Sockets and UDP. The second assignment at DAB

Relevanta dokument
Datasäkerhet och integritet

Michael Q. Jones & Matt B. Pedersen University of Nevada Las Vegas

Support Manual HoistLocatel Electronic Locks

Beijer Electronics AB 2000, MA00336A,

Isolda Purchase - EDI

Problem som kan uppkomma vid registrering av ansökan

Styrteknik: Binära tal, talsystem och koder D3:1

Schenker Privpak AB Telefon VAT Nr. SE Schenker ABs ansvarsbestämmelser, identiska med Box 905 Faxnr Säte: Borås

Writing with context. Att skriva med sammanhang

Schenker Privpak AB Telefon VAT Nr. SE Schenker ABs ansvarsbestämmelser, identiska med Box 905 Faxnr Säte: Borås

FÖRBERED UNDERLAG FÖR BEDÖMNING SÅ HÄR

6 th Grade English October 6-10, 2014

Preschool Kindergarten

Module 1: Functions, Limits, Continuity

2.1 Installation of driver using Internet Installation of driver from disk... 3

Isometries of the plane


Recitation 4. 2-D arrays. Exceptions

Viktig information för transmittrar med option /A1 Gold-Plated Diaphragm

Information technology Open Document Format for Office Applications (OpenDocument) v1.0 (ISO/IEC 26300:2006, IDT) SWEDISH STANDARDS INSTITUTE

Lösenordsportalen Hosted by UNIT4 For instructions in English, see further down in this document

Övning 5 ETS052 Datorkommuniktion Routing och Networking

Webbregistrering pa kurs och termin

Övning 4 EITF25 & EITF Protokoll. October 29, 2016

Support for Artist Residencies

Module 6: Integrals and applications

INSTALLATION INSTRUCTIONS

Materialplanering och styrning på grundnivå. 7,5 högskolepoäng

FANNY AHLFORS AUTHORIZED ACCOUNTING CONSULTANT,

Quick-guide to Min ansökan

Chapter 2: Random Variables

Make a speech. How to make the perfect speech. söndag 6 oktober 13

Webbreg öppen: 26/ /

Workplan Food. Spring term 2016 Year 7. Name:

Vässa kraven och förbättra samarbetet med hjälp av Behaviour Driven Development Anna Fallqvist Eriksson

This exam consists of four problems. The maximum sum of points is 20. The marks 3, 4 and 5 require a minimum

GU / Chalmers Campus Lindholmen Tentamen Programutveckling LEU 482 / TIG167

Application Note SW

Lehigh Valley Hospital Schuylkill Portal User Q&A

Övning 3 ETS052 Datorkommuniktion IP, TCP och

Om oss DET PERFEKTA KOMPLEMENTET THE PERFECT COMPLETION 04 EN BINZ ÄR PRECIS SÅ BRA SOM DU FÖRVÄNTAR DIG A BINZ IS JUST AS GOOD AS YOU THINK 05

Installation Instructions

DVG C01 TENTAMEN I PROGRAMSPRÅK PROGRAMMING LANGUAGES EXAMINATION :15-13: 15

Integritetspolicy på svenska Integrity policy in English... 5

Boiler with heatpump / Värmepumpsberedare

Installation av F13 Bråvalla

Schenker Privpak AB Telefon VAT Nr. SE Schenker ABs ansvarsbestämmelser, identiska med Box 905 Faxnr Säte: Borås

Questionnaire for visa applicants Appendix A

Biblioteket.se. A library project, not a web project. Daniel Andersson. Biblioteket.se. New Communication Channels in Libraries Budapest Nov 19, 2007

1. Unpack content of zip-file to temporary folder and double click Setup

12.6 Heat equation, Wave equation

Alias 1.0 Rollbaserad inloggning

Föreläsning 4 IS1300 Inbyggda system

Adding active and blended learning to an introductory mechanics course

1.1 Invoicing Requirements

VHDL Basics. Component model Code model Entity Architecture Identifiers and objects Operations for relations. Bengt Oelmann -- copyright

EXPERT SURVEY OF THE NEWS MEDIA

Chapter 1 : Who do you think you are?

Libers språklåda i engelska Grab n go lessons

LUNDS TEKNISKA HÖGSKOLA Institutionen för Elektro- och Informationsteknik

Övning 5 EITF25 & EITF Routing och Networking. December 5, 2017

F ξ (x) = f(y, x)dydx = 1. We say that a random variable ξ has a distribution F (x), if. F (x) =

Health café. Self help groups. Learning café. Focus on support to people with chronic diseases and their families

1. Compute the following matrix: (2 p) 2. Compute the determinant of the following matrix: (2 p)

Quick Start Guide Snabbguide

Översättning av galleriet. Hjälp till den som vill...

The Finite Element Method, FHL064

Rastercell. Digital Rastrering. AM & FM Raster. Rastercell. AM & FM Raster. Sasan Gooran (VT 2007) Rastrering. Rastercell. Konventionellt, AM

A metadata registry for Japanese construction field

Får endast utföras av behörig personal. May only be carried out by authorized electrician

EXTERNAL ASSESSMENT SAMPLE TASKS SWEDISH BREAKTHROUGH LSPSWEB/0Y09

Kursutvärderare: IT-kansliet/Christina Waller. General opinions: 1. What is your general feeling about the course? Antal svar: 17 Medelvärde: 2.

Very formal, recipient has a special title that must be used in place of their name

- den bredaste guiden om Mallorca på svenska! -

LARS. Ett e-bokningssystem för skoldatorer.

State Examinations Commission

Algoritmer och Komplexitet ht 08. Övning 6. NP-problem

SVENSK STANDARD SS :2010

INTERAKTIVA UTBILDNINGAR. UPPDRAG: Trafikutbildning åt Örebro kommun. KUND: Agresso Unit4

WhatsApp finns för dessa plattformar:

Custom-made software solutions for increased transport quality and creation of cargo specific lashing protocols.

Sri Lanka Association for Artificial Intelligence

Kurskod: TAMS11 Provkod: TENB 28 August 2014, 08:00-12:00. English Version

OFFERT Innovativ Upphandling av Innovativ Teknik

CVUSD Online Education. Summer School 2010

Avancerad SSL-programmering I

Swedish adaptation of ISO TC 211 Quality principles. Erik Stenborg

Förändrade förväntningar

PORTSECURITY IN SÖLVESBORG

Hur fattar samhället beslut när forskarna är oeniga?

8 < x 1 + x 2 x 3 = 1, x 1 +2x 2 + x 4 = 0, x 1 +2x 3 + x 4 = 2. x 1 2x 12 1A är inverterbar, och bestäm i så fall dess invers.

How to format the different elements of a page in the CMS :

Methods to increase work-related activities within the curricula. S Nyberg and Pr U Edlund KTH SoTL 2017

Day 1: European Cooperation Day 2017

SWESIAQ Swedish Chapter of International Society of Indoor Air Quality and Climate

x 2 2(x + 2), f(x) = by utilizing the guidance given by asymptotes and stationary points. γ : 8xy x 2 y 3 = 12 x + 3

Taking Flight! Migrating to SAS 9.2!

The Swedish National Patient Overview (NPO)

Solutions to exam in SF1811 Optimization, June 3, 2014

Unit course plan English class 8C

Transkript:

Sockets and UDP The second assignment at DAB728 2006-11-30 Jonas Lundberg/Ola Flygt Matematiska och systemtekniska institutionen, MSI Växjö universitet (email: Ola.Flygt@msi.vxu.se) This assignment should be nished and handed in before December 20. Introduction The aim of this second assignment is to introduce the fundamentals of network programming using C. We start by introducing the concepts: application, port, endpoint, client-server model and socket. Our presentation of the various network related system calls is based on a simple implementation of an UDP echo client/server. The idea is to discuss the various calls as we come across them. We only give a short description of the system calls, further information can be found in the manual pages.

Applications, Ports and Endpoints TCP/IP is the name of a collection of protocols that, put together, makes it possible for two or more machines to communicate across a network. The precise functionality of each one of these protocols are specied in dierent RFCs (Request For Comment). The RFCs doesn't describe how the various protocols should be implemented (although some advice is given); they only specify the functionality. As a result, the software that constitutes the implementation of the TCP/IP protocols might vary among dierent manufacturers. The software implementation is in most cases a part of the operating system. That is the case for the UNIX machines here at MSI. We consider the TCP/IP protocols as a service provided by the operating system. Like any other services provided by the operating system, a user can only access them through various system calls. In order to separate the network related software that uses these system calls from the software that is a part of the operating system, we refer to them as applications. An application is therefore a program that uses the system calls provided by the operating system. There are several standard applications (e.g. TELNET and FTP) whose functionality also is specied by RFCs. In assignment 4 we will take a closer look (and implement) one them: The Trivial File Transfer Protocol (TFTP). In this assignment, and the next, we will prepare ourselves by implementing a few simple applications. In order to understand the term port in a networking context we must rst realize that communication across a network primarily takes part between applications, and not between machines. For example, if you at home use TELNET to contact a computer here at the university, then the communication is primarily between the TELNET application at home and the TELNET application at the university. It is quite possible to have a second communication channel open between the two machines that uses a dierent application (e.g. FTP). As a result, when we connect, we must not only specify what machine we want to contact, we must also specify what kind of application in the foreign machine we intend to use. This is where the port number comes into play. The port identies a single application. The application identication by ports has two parts; rst, by using a specic port number a user can determine what application on the foreign machine to contact. Secondly, the port number is necessary at the receiving end since it tells the machine how to handle incoming trac. That is, which of all the possible applications that should be used to interpret the incoming packet. (The process of identifying what protocols and applications to use, when a packet is received, is called demultiplexing.) The port number is a 16-bit integer ranging from 1 to 65535. All the numbers below 1024 are reserved for the standard applications. In the following table we list some of the standard applications and their corresponding port number. Application Port =========== ==== FTP 21 TELNET 23 SMTP 25 TFTP 69 HTTP 80 Every packet that travels across the Internet contains two port numbers. One that species the application at the receiving end (destination port) and one that species the application at the transmitting end (source port). The latter is necessary if a response is expected (which usually is the case). The port numbers are elds in the TCP or UDP header. Besides the port number, every packet also includes two IP addresses that uniquely identies the communicating machines. Since both port number and IP address are necessary to identify a unique application at a unique machine, both must be included in every packet that enters the Internet. The combination (IP address, port number) is called an endpoint. We can summarize the discussion above as: All communication across the Internet takes part between two endpoints. Each endpoint is speci- ed by an IP address and a port number. 1

The Client-Server model The client-server model of communication across a network separates the participating applications into two categories depending on whether the application is passively waiting for contact (the server) or if it actively initiates a contact (the client). Hence, it is the direction of initiative to make contact that determines whether an application should be considered as a client or a server. The client-server model is by far the most common way to organize the interacting parts in a distributed environment. Most of the applications we use daily are client applications. Whenever we use FTP to fetch a le or a document or when we use a web browser to read a HTML document, we are the one that initiates contact and thus, we act as a client in the communication process. The software that constitutes the client application is in principle simple compared to a server. It supports means to get in contact usually followed by one or more request/response cycles. In practice however; although the principles are straight forward, the amount of services and the exibility that users today demand from a client makes the design of a client a rather extensive project. Think of a web browser. The server on the other hand must constantly be prepared to accept a call and handle various request from dierent clients. Furthermore, the server must be able to handle several clients at the same time. In most application it is not acceptable that a single client blocks a server. For example, it is unacceptable that a client that uses FTP to communicate with a server blocks the server for other clients while it is connected. A server must therefore be able to communicate with many clients concurrently. We will look closer at dierent techniques to implement concurrency in assignment 3. A server should also be a somewhat robust construction that is capable of handle erroneous connections from a client. If a client crashes during a connection it is frustrating. However, the amount of work required for the user to make a new connection is most often not overwhelming. If, on the other hand, a server crashes, many users might be suering and it might take a while to get the server restarted again. For example, if the le server luc here at MSI stopped working, none of the students would be able to reach any of their les until the system administrator (Niklas Brandt) was contacted and had gured out how to restart the server. Finally, server software should also include some means to handle illegal intrusions and malicious use of the system's resources. Put together, the server software is usually much more complicated than the client software. 2

Introduction to Sockets We have earlier mentioned that the implementation of the TCP/IP protocols in most cases is a part of the operating system and that a user can only access these parts by certain system calls. The set of system calls can be considered as an interface between the applications and the operating system. Each system call is designed to perform a specic task. It is common to view the system calls as services provided by the operating system. The set of all system calls is referred to as the Application Program Interface (API) and they can be considered as a set of tools that a programmer can use to build applications. In Figure 1 we show the position of the API in a schematic picture. A1 A2 A3 A4 API UDP TCP IP Ethernet Internet Figur 1: A schematic picture showing four applications using the services provided by the operating system. The network API that we shall take a closer look at is the BSD UNIX Socket Interface that was developed at the University of California at Berkeley during the 1980s. It is by far the most commonly used interface for UNIX machines but one should be aware that other interfaces exist (e.g. TLI used by System V). Microsoft has developed an interface of their own (Winsock) that is similar to BSD. However, applications developed using the BSD socket interface on UNIX machines are in general not portable to Windows machines without some modications, and vice versa. Before we start to look at the various network related system calls that constitutes the BSD socket API, we must rst take a closer look at the so called socket. The traditional UNIX way to handle external units (e.g. disks, printers and modems) is to consider them as les that we can manipulate through le descriptors and system calls like open, read, write, and close. Whenever we want to access an external unit we start by calling open which generates a le descriptor through which we later can access the le associated with the unit. The le descriptor is an index to a table (the open le table) that contains pointers to the data structures that represent the various les that are open at the moment. When the people at Berkeley made the rst implementations of the TCP/IP protocols they wanted a design that, as far as possible, imitated the system with le descriptors. The ideal would be if we could send a UDP package the following way: fd = open(``/dev/udp'', O_RDWR,0); write(fd, buffert, strlen(buffert)); That is, in a way that is analogous to the way we open and write to an ordinary le in UNIX. The le /dev/udp represents the connection and contains endpoint information. However, that didn't work for several reasons. One problem is to handle servers that should be able to accept 3

calls from unknown clients. In the above model that would mean opening and reading from an unknown device le. The solution they came up with was the socket. A socket is an internal data structure that on creation (by a system call socket to be described later) only contains information regarding what transport protocol to be used. Additional information (endpoint information of the communicating applications) is added later on using the system calls bind and connect. A socket is a close relative to the le descriptors since both of them can be considered as communication channels or pipes through which communication between a process and an external unit takes place. In the socket case, the external unit represents a process at a (possibly foreign) machine. It is also treated in a way that is similar to le descriptors by the operating system. Once a socket has been created it can be used by a server waiting for an Open File Table 0 1 2 Socket Data Structure family: PF_INET service: SOCK_DGRAM local!p: remote IP: local port: remote port: n More fields with options Figur 2: Conceptual operating system data structures after a call to socket. incoming call (a passive socket where only the endpoint information of the server is stored in the socket), or by a client to initiate a connection (an active socket where the endpoint information of both parties is stored in the socket). In the next section we will show how to use sockets. A Simple Echo Client In this section some of the most common system calls related to network programming will be presented. We start with a simple application and discuss the various calls as we come across them. The rst example is a so called echo client. All it does is to send and receive a UDP package to a specic endpoint that is passed as a parameter in the program call. After it has received the package it checks if the sent and received packages are identical. The program doesn't work properly on its own, it requires a second application (an echo server) that mirrors (or echos) every packet it receives. The echo server will be presented in the next section. /* udp_echo_client.c A simple echo client with no error handling */ #include <stdio.h> #include <stdlib.h> /* atoi */ #include <string.h> /* strcpy, strcmp */ #include <unistd.h> /* read, write, close */ #include <sys/types.h> /* socket, connect, bind */ #include <sys/socket.h> /* socket, connect, bind */ #include <netinet/in.h> /* htons */ #include <netdb.h> /* hostent, gethostbyname */ #define BUFSIZE 1024 #define MYPORT 0 /* Zero means auto-choice */ #define MSG "An Echo Message!" /* Echo-message */ 4

void main(int argc, char *argv[]) { int sockfd, numbytes; char buf[bufsize]; struct sockaddr_in myaddr; /* local endpoint */ struct sockaddr_in theiraddr; /* remote endpoint */ struct hostent *he; if (argc!= 3) { fprintf(stderr,"usage: %s server_name port\n",argv[0]); exit(1); /* Create socket */ sockfd = socket(pf_inet, SOCK_DGRAM, 0); /* Define local endpoint */ myaddr.sin_family = AF_INET; myaddr.sin_port = htons(myport); myaddr.sin_addr.s_addr = INADDR_ANY; memset(&(myaddr.sin_zero),0, 8); /* Add myaddr-info to socket */ bind(sockfd, (struct sockaddr *)&myaddr, sizeof(struct sockaddr)); /* get the server info */ he=gethostbyname(argv[1]); /* Define remote endpoint */ theiraddr.sin_family = AF_INET; theiraddr.sin_port = htons(atoi(argv[2])); theiraddr.sin_addr = *((struct in_addr *)he->h_addr_list[0]); memset(&(theiraddr.sin_zero),0, 8); /* Add theiraddr-info to socket */ connect(sockfd, (struct sockaddr *)&theiraddr,sizeof(struct sockaddr)); /* Send and receive message */ strcpy(buf,msg); /* Copy MSG to buf */ write(sockfd, buf, strlen(buf)); /* Send message */ numbytes=read(sockfd,buf,bufsize); /* Receive message */ buf[numbytes] = '\0'; /* Compare sent and received message */ if (strcmp(buf,msg) == 0) printf("%d bytes sent and received\n", strlen(buf)); else printf("sent and received msg not equal!\n"); close(sockfd); In what follows we will discuss the various parts of the example above as well as explaining the synopsis and purpose of the dierent system calls and data structures. We only give an introduction suited for our type of applications (applications based on TCP/IP). Remember that the socket interface is designed to be very exible and that it can handle several dierent types of networking protocols. This exibility is one reason why we have to cast one type of data structure into another all the time. Additional information can be found in the man pages. The socket call SYNOPSIS 5

#include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, int protocol) DESCRIPTION The call ``socket'' creates a socket and adds information to the socket about what protocols to be used during the communication. The domain parameter specifies a communication domain within which communication will take place; this selects the protocol family which should be used. These families are defined in <sys/socket.h>. The two most common families are PF_UNIX and PF_INET. The PF_UNIX protocol family can be used for IPC between processes on the same machine. The PF_INET protocol family uses the IP version 4 Internet protocols. The PF_INET type option is what we will use throughout this course. The second parameter type indicates what kind of transport to be used. The two most common types are SOCK_STREAM and SOCK_DGRAM. The SOCK_DGRAM option indicates that data will be sent and received in packets called datagrams whereas the SOCK_STREAM option indicates that data will be transported as a stream of characters. Using the TCP/IP transport protocols (i.e. the PF_INET domain option) the SOCK_STREAM options equals choosing TCP and SOCK_DGRAM is equivalent to UDP. The protocol option will not be used throughout this course. You can safely put it to zero. RETURN VALUES A -1 is returned and errno is set if an error occurs. Otherwise the return value is a descriptor referencing the socket. The struct sockaddr_in Endpoint Data Structure Each protocol family that uses sockets denes their own exact representation of its endpoint addresses by providing a corresponding data structure. The TCP/IP protocols uses a data structure named sockaddr_in that is provided by the BSD interface to store the endpoint information. struct sockaddr_in { u_char sin_len; /* total length */ u_short sin_family; /* type of address */ u_short sin_port; /* port in network byte order */ struct in_addr sin_addr; /* IP address in binary */ char sin_zero[8]; /* unused (set to zero) */ ; where the address structure in_addr is dened as: struct in_addr { unsigned long s_addr; ; In the program udp_echo_client.c, under the section entitled Define local endpoint we simply add information to the variable myaddr that stores the local endpoint information. There are a few things to notice here; We don't add any information to the sin_len eld. This will be taken care of later on when we use the bind system call. The port number (myaddr.sin_port) should be given in Network Byte Order. This refers to the representation of objects such as integers within a word. Some computers are big endian whereas others are little endian. A big endian machine stores the most signicant byte in leftmost position. A little endian machine works the other way around. In order for the system calls provided by BSD to work we have to pass arguments in Network Byte Order which is big endian. There are a number of conversion functions provided that handles the byte ordering: 6

SYNOPSIS #include <netinet/in.h> unsigned long int htonl(unsigned long int hostlong); unsigned short int htons(unsigned short int hostshort); unsigned long int ntohl(unsigned long int netlong); unsigned short int ntohs(unsigned short int netshort); DESCRIPTION The htonl(): converts long integer to network byte order. The htons(): converts short integer to network byte order. The ntohl(): converts long integer to host byte order. The ntohs(): converts short integer to host byte order. These conversion functions should always be used in order to make the applications portable between dierent types of machines. The parameter MYPORT is set to zero. This means that a random available port is chosen by the computer. The eld myaddr.sin_addr.s_addr is set to INADDR_ANY. This means that the machine's own IP address is used. You could just as well add it explicitly as: myaddr.sin_addr.s_addr = inet_addr(``194.47.74.214''); where inet_addr() is a function that converts dotted decimal notation to a 32-bit binary representation. Finally, the assignment memset(&(myaddr.sin_zero),0, 8) adds zeros to the unused eld sin_zero. Further down the program we repeat the same assignment procedure for the data structure (theiraddr) that stores the remote endpoint information. This time we can no longer use the port number auto-choice function (MYPORT 0) and the auto-ll function INADDR_ANY. Instead we must explicitly assign the server port number and the server IP address. Notice also that we rst use the call gethostbyname() (introduced in assignment 1) to gather information about the server. The assignment of the eld theiraddr.sin_addr is ugly but it works! The bind call SYNOPSIS #include <sys/types.h> #include <sys/socket.h> int bind(int sockfd, struct sockaddr *local_addr, int addrlen); DESCRIPTION bind assigns the socket with socket descriptor sockfd the local endpoint information. RETURN VALUE On success, zero is returned. On error, -1 is returned, and errno is set appropriately. Notice that the bind call is designed to use the general address data structure struct sockaddr and that we in the program udp_echo_client.c have to cast the struct sockaddr_in in use into that form. The connect call SYNOPSIS #include <sys/types.h> #include <sys/socket.h> 7

int connect(int sockfd, struct sockaddr *remote_addr, int addrlen); DESCRIPTION The parameter sockfd is a socket. If the socket is of type SOCK_DGRAM (i.e. we use UDP as transport protocol), this call specifies the remote endpoint information; this address is that to which datagrams are to be sent, and the only address from which datagrams are to be received. If the socket is of type SOCK_STREAM (i.e. we use TCP as transport protocol), this call (besides specifying the remote endpoint) also attempts to make a connection to the remote host. The remote endpoint is specified by remote_addr. RETURN VALUE If the connection or binding succeeds, zero is returned. On error, -1 is returned, and errno is set appropriately. This call works similar to bind. We have to cast the struct sockaddr_in in use into a struct sockaddr. The write and read call Once the socket has both endpoints specied, reading and writing to the remote host works exactly the same way as reading and writing to an ordinary external unit in UNIX. That is, we can use the functions read() and write(). SYNOPSIS #include <unistd.h> int read(int fd, void *buf, int count); int write(int fd, const void *buf, int count); DESCRIPTION read() attempts to read up to count bytes from file descriptor fd into the buffer starting at buf. write() writes up to count bytes to the file referenced by the file descriptor fd from the buffer starting at buf. RETURN VALUE On success, the number of bytes read by read() is returned (zero indicates end of file), and the file position is advanced by this number. On error, -1 is returned, and errno is set appropriately. On success, the number of bytes written by write() are returned. On error, -1 is returned, and errno is set appropriately. 8

A Simple Echo Server The echo client presented in the last section requires an echo server that mirrors every packet it receives. Before we present the C code for the server, let us view a schematic picture of the two cooperating processes. There is one principal dierence between a client and a server. The client Echo Client Echo Server socket() bind() socket() connect() bind() write() read() echo request echo response recvfrom() sendto() return to listening state close() close() Figur 3: Schematic structure of the system calls during a echo session. requires that both endpoints are specied before the exchange of packets starts. This implies that both bind() and connect() must be called before the rst transmission in order to assign the socket the required information. An application where both endpoints are xed in the socket is called a connection-oriented application. The server on the other hand can't have both endpoints xed if we want the server to be able to mirror echo requests from dierent clients. That is the reason why we don't nd a connect() call on the server side in gure 3. Applications where only one endpoint in the socket is xed are called connectionless applications. Since the echo server is connectionless we can not use the simple calls read() and write() to receive and transmit the packets. Instead we use the calls recvfrom() and sendto() that are designed for connectionless applications. Notice also that the call recvfrom() blocks the server until an incoming packet is received, just like an ordinary read() would. A server that is blocked and waiting for an incoming call is said to be listening. Furthermore, since we want the server to be able to handle many clients we use an eternal loop that returns to the listening state as soon as a client request is handled. /* udp_echo_server.c A simple echo server with no error handling */ #include <stdio.h> #include <stdlib.h> /* atoi */ #include <string.h> /* strcpy */ #include <errno.h> /* perror */ #include <string.h> /* strcpy */ #include <unistd.h> /* read, write, close */ #include <sys/types.h> /* socket, bind, htons, inet_ntoa */ #include <sys/socket.h> /* socket, bind, inet_ntoa */ #include <netinet/in.h> /* htons, ntohs, inet_ntoa */ #include <inttypes.h> /* htons, ntohs */ #include <arpa/inet.h> /* inet_ntoa */ 9

#define BUFSIZE 1024 #define MYPORT 4950 /* the "well-known" port */ void main() { int sockfd; struct sockaddr_in myaddr; /* local endpoint */ struct sockaddr_in theiraddr; /* remote endpoint */ char buf[bufsize]; /* Create socket */ sockfd = socket(pf_inet, SOCK_DGRAM, 0); /* Defining myaddr */ myaddr.sin_family = AF_INET; myaddr.sin_port = htons(myport); myaddr.sin_addr.s_addr = INADDR_ANY; memset(&(myaddr.sin_zero),0, 8); /* Add myaddr-info to socket */ bind(sockfd, (struct sockaddr *)&myaddr, sizeof(struct sockaddr)); printf("listening at port %d\n", ntohs(myaddr.sin_port)); while(1) { /* Main receive-send loop */ int addrlen = sizeof(struct sockaddr); int numbytes; numbytes=recvfrom(sockfd,buf,bufsize,0, /* Receive message */ (struct sockaddr *)&theiraddr,&addrlen); buf[numbytes] = '\0'; numbytes=sendto(sockfd, buf, strlen(buf), 0, /* Send message */ (struct sockaddr *)&theiraddr,addrlen); printf("udp echo request from %s",inet_ntoa(theiraddr.sin_addr)); printf(" using port %d\n", ntohs(theiraddr.sin_port)); Many things in the program udp_echo_server.c are just the same as in the previously presented program udp_echo_client.c and we refer to that program for explanations. However, a few things are dierent and worth commenting. First, a server requires a well-known port. We can not have a randomly chosen port that vary between dierent values every time we start the server. In that case no client would be able to make contact since it has no way of knowing the remote endpoint of the server. Secondly, since the server is a connectionless application we must add the remote endpoint information every time we transmit a packet. In the above server we do so by passing a struct theiraddr storing the remote endpoint information to the transmitting function sendto(). The struct theiraddr is assigned the remote endpoint information in the call recvfrom(). That is, besides receiving a buer that contains received data, the function recvfrom() also stores the endpoint information of the received packet in the struct theiraddr that is passed as a parameter. Notice also that both sendto() and recvfrom() are designed to use the general address data structure struct sockaddr (just like bind() and connect()) and that we have to cast the struct sockaddr_in in use into that form. The functions sendto() and recvfrom() have the following synopsis: SYNOPSIS #include <sys/types.h> #include <sys/socket.h> int sendto(int sockfd, const void *msg, int msglen, unsigned int flags, 10

const struct sockaddr *target, int targetlen); int recvfrom(int sockfd, void *buf, int buflen, unsigned int flags, struct sockaddr *from, int *fromlen); DESCRIPTION sendto() is used to transmit a message to another socket. The parameter sockfd refers to a socket storing local endpoint information. The call may be used to transmit data on a socket whether or not it is connection-oriented. The endpoint information of the target is given by target with targetlen specifying its size. The length of the message is given by msglen. The flags parameter can be put to zero. The recvfrom() call is used to receive messages from a socket. The parameter sockfd refers to a socket storing local endpoint information. The call may be used to receive data on a socket whether or not it is connection-oriented. If from is not NULL, and the socket is not connection-oriented, the source endpoint information of the message is filled in. Fromlen is a value-result parameter, initialized to the size of the buffer associated with from, and modified on return to indicate the actual size of the address stored there. The maximum size of buf is given by buflen. The flags parameter can be put to zero. RETURN VALUES The call sendto() return the number of characters sent. On error, -1 is returned, and errno is set appropriately. The call recvfrom() return the number of bytes received. On error, -1 is returned, and errno is set appropriately. Error handling None of the two programs udp_echo_server.c and udp_echo_client.c has any error handling. If an error occurs during execution, no detailed information will be shown to tell us what went wrong. A program should always include some error handling! This is especially important when dealing with network programming since many dierent errors might occur while communicating with a foreign host. The traditional C way to handle errors due to mis-happenings in a system call is to use the routine perror(). The routine perror() produces a message on the standard error output, describing the last error encountered during a call to a system or library function. #include <stdio.h> #include <errno.h> void perror(const char *s); The argument string s is printed rst, then a colon and a blank, then the message and a newline. To be of most use, the argument string should include the name of the function that incurred the error. When a system call fails, it usually returns -1 and sets the variable errno to a value describing what went wrong. The function perror() serves to translate this error code into human-readable form. For example, the bind calls shown in the previous client and server examples ought to be replaced by: if (bind(sockfd, (struct sockaddr *)myaddr,sizeof(struct sockaddr)) == -1) { perror("bind"); exit(1); In case of an error when using the call bind, we now get a message saying that an error occurred while calling bind() (i.e. pointing out where the error occurred). We also get information about why it happened. After that, the program exits. 11

UDP: A Short Introduction UDP (User Datagram Protocol) is a simple datagram-oriented transport protocol within the TCP/IP protocol suite. UDP provides no reliability. It sends the datagram that the applications writes to the IP layer, but there is no guarantee that they ever reach their destination. If UDP is used and a reliable delivery is required, packet sequence checking and error notication must be written into the applications. A common method to implement error notication is presented in the next section. Given the lack of reliability of UDP, we are tempted to think that we should avoid UDP and always use a reliable protocol such as TCP. After assignment 3 where we use TCP we will return to this topic and discuss what kind of applications can utilize UDP. Figure 4 shows a UDP/IP/Ethernet packet and the UDP header. The top of the gure shows that Ethernet Frame IP Datagram UDP Datagram Ethernet header IP header UDP header UDP Data Ethernet tail UDP Header 16-bit source port 16-bit UDP length 16-bit destination port 16-bit UDP checksum Data (if any) Figur 4: Schematic structure of a packet using UDP (above) and the UDP header (below). UDP is encapsulated in an IP frame. We can think of IP as the protocol that is responsible for transport from one machine to another across the Internet whereas UDP is responsible for locating the target application. It is therefore no surprise that the UDP header (Figure 4, bottom) includes port information. Both the port number identifying the source application as well as the destination application is included in the UDP header. The UDP length eld is the length of the UDP header and the UDP data in bytes. The minimum value for this eld is 8 bytes. The UDP checksum uses a 16-bit Cyclic Redundancy Check technique to help the receiving end to detect errors. The checksum covers both the UDP header and the UDP data. An Acknowledgment/Retransmission Scheme for Fetch We have earlier mentioned briey that if UDP is used and a reliable delivery is required, error notication must be implemented into the applications. One often used technique to implement error notication is called Positive Acknowledgment With Retransmissions. The technique requires a recipient to communicate with the source, sending back an acknowledgment (ACK) message as it receives data. The sender sends a packet and then waits for an acknowledgment before sending the next packet. The sender also starts a timer when it sends a packet and retransmits if the timer expires before an acknowledgment arrives. In the last exercise in this assignment you are asked to implement fetch, a client-server pair where (similar to the last exercise in assignment 1) the client reads a le from a predened server side directory. In what follows we give a short (but hopefully sucient) description of the Acknowledge/Retransmit scheme you are supposed to use. It is a simplied version of the TFTP scheme (RFC 1350) you will use in assignment 4. 12

Overview Any transfer begins with a request to read a le, which also serves to request a connection. If the server grants the request, the connection is opened and the le is sent in xed length blocks of 512 bytes. Each data packet contains one block of data, and must be acknowledged by an acknowledgment packet before the next packet can be sent. A data packet of less than 512 bytes signals termination of a transfer. If a packet gets lost in the network, the intended recipient will timeout and may retransmit his last packet (which may be data or an acknowledgment), thus causing the sender of the lost packet to retransmit that lost packet. The sender has to keep just one packet on hand for retransmission, since the lock step acknowledgment guarantees that all older packets have been received. Notice that both machines involved in a transfer are considered senders and receivers. One sends data and receives acknowledgments, the other receives data and sends acknowledgments. In Figure 5 (left) we show a successful set of transmissions. Each diagonal line represents the transfer of one packet across the network. The fetch header consists of a 2 byte opcode eld which indicates the packet's type (e.g. RRQ, DATA or ACK). These opcodes and the formats of the various types of packets are dsicussed in the next section. Client Site Server Site Client Site Server Site Send RRQ Send ACK(X) Recv. DATA(1) Send ACK(1) Receive RRQ Send DATA(1) Retransmission time DATA lost Receive ACK(X) Send DATA(X+1) Receive ACK(1) Send DATA(2) Time expires Recc. DATA(2) Retransmit ACK(X) Send ACK(2) Receive ACK(2) Receive ACK(X) Send DATA(X+1) Receive DATA(X+1) Figur 5: Schematic picture of a succesful transmission of two packets (left) and a retransmission after a packet is lost (right). In Figure 5 (right) a packet is lost and hence no data is returned before the timer expires. This forces the client to retransmit the packet. Usually the number of retransmissions is limited (e.g. no more than 5 retransmissions) in order to prevent an application to get caught in a innite loop of retransmissions if the recipient part goes down or some other problem arises. All errors cause termination of the connection. Timeouts are therefore also used to detect such termination. If one side goes down the other side retransmits the last packet ve times and then terminates. The Fetch Protocol A transfer is established by sending a read request (RRQ), and receiving a positive reply - the rst data packet DATA(1). (See Figure 6 for an account of the three types of packages supported by the fetch protocol.) The client responds to the arrival of the data packet with an ACK(1). Data is transferred in DATA packets depicted in Figure 6. DATA packets (opcode = 2) have a block number and data eld. The block numbers on data packets begin with one and increase by one for each new block of data. This restriction allows the program to use a single number to 13

discriminate between new packets and duplicates. The data eld is from zero to 512 bytes long. If it is 512 bytes long, the block is not the last block of data; if it is from zero to 511 bytes long, it signals the end of the transfer. opcode operation 1 Read request (RRQ) 2 Data (DATA) 3 Acknowledgment (ACK) 2 bytes string --------------------- Opcode Filename RRQ packet --------------------- 2 bytes 2 bytes n bytes ---------------------------------- Opcode Block # Data DATA packet ---------------------------------- 2 bytes 2 bytes --------------------- Opcode Block # ACK packet --------------------- Figure 6: The three types of opcodes and packets supported by the fetch protocol. The following example demonstrates a correct use of the block number. Somewhere in the network, the data packet is duplicated, and as a result two data packets with the same block number X are returned to the client. When the rst packet arrives the client responds with an ACK(X). When the second data packet arrives, the client must, by checking the block number, recognize it as a duplicate and reject it. However, there is no reason to terminate the connection. The client just resets the timer and continues to wait for DATA(X+1). All packets other than duplicate ACK's and those used for termination are acknowledged unless a timeout occurs. Sending a DATA packet is an acknowledgment for the ACK packet of the previous DATA packet. The DATA packets are acknowledged by ACK packets, while a RRQ packet is acknowledged by the rst DATA packet. Figure 6 depicts an ACK packet; the opcode is 3. The block number in an ACK echoes the block number of the DATA packet being acknowledged. In Figure 6 you can also see that a RRQ packet contains an opcode (1) and the name of the le to be fetched. Once a packet has been received we must parse it in order to get the information (opcode, block number, requested le etc). The following function reads two bytes at a given address and converts it to an unsigned short in host byte order: unsigned short GetShortAt(char *addr) { return ntohs(*((unsigned short*) addr)); (Its a beauty, isn't it?). We can now, for example, parse a read request (RRQ) for opcode and requested le as: opcode = GetShortAt(buf); strcpy(reqfile,buf+2); We leave you with the problem of writing the corresponding function PutShortAt(char* buf, short val). Timeout and retransmission occur when a packet is lost (or severely delayed). The general strategy is the following: Assume that a host has transmitted a packet X, started the timer and is waiting for a response. If the response is lost (or severely delayed) the time expires. The host then retransmits packet X to notify the other side that a packet is lost. The maximum number 14

of retransmissions is set to 5 in order to prevent an innite loop if the recipient (or some other machine along the way) goes down. Usually the timeout time is increased for every retransmission to avoid congestion in cases where an overloaded router or recipient is the reason behind the problem. We expect you to use the following retransmission times (in seconds): Time before retransmission: [1, 2, 4, 8, 16] The end of a transfer is marked by a DATA packet that contains between 0 and 511 bytes of data (i.e., Datagram length < 512). This packet is acknowledged by an ACK packet like all other DATA packets. The client acknowledging the nal DATA packet may terminate its side of the connection on sending the nal ACK. The server sending the last DATA must retransmit it until the packet is acknowledged or the server times out. If the response is an ACK, the transmission was completed successfully. If the server times out and is not prepared to retransmit any more, the transfer may still have been completed successfully. Implement a timer with select() In the previous section we found out that a timer is needed if we want to implement Positive Acknowledgment with Retransmissions. In this section we show how we can use the system call select() to implement a timer. The select() will also be used in Assignment 3 to implement a server that can handle concurrent connections. The select() function indicates which of the specied le descriptors is ready for reading, ready for writing, or has an error condition pending. If the specied condition is false for all of the specied le descriptors, select() blocks, up to the specied timeout interval, until the specied condition is true for at least one of the specied le descriptors. That is; select() blocks until something happens with the set of le descriptors that select monitors, or until the time limit (specied in the parameter timeout) expires. #include <sys/time.h> int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout); The nfds argument species the range of le descriptors to be tested. The select() function tests le descriptors in the range of 0 to nfds-1. The arguments readfs, writefs and errorfds is dierent sets of le descriptors, each of type fd_set. These three sets of le descriptors specify which descriptors we are interested in and for which condition (readable, writable, or exception condition). There is a set of functions designed to manipulate this type of le descriptor sets: #include <sys/time.h> #include <sys/types.h> void FD_ZERO(fd_set *fdset); // remove all descriptors from fdset void FD_SET(int fd, fd_set *fdset); // add descriptor fd to fdset void FD_CLR(int fd, fd_set *fdset); // remove descriptor fd from fdset int FD_ISSET(int fd, fd_set *fdset); // test if fd in fdset is activated The maximum number of le descriptors in an fd_set is given by a the constant FD_SETSIZE. The last argument in the select call, timeout, determines the maximum amount of time that select() is allowed to block. The timeout value is given using a struct timeval also dened in <sys/time.h>: struct timeval { int tv_sec; /* seconds */ long tv_usec; /* microseconds */ ; In the example that follows we illustrate how select() can be used to implement a timer. The example shows a modication of the client udp_echo_client.c presented earlier. Some parts have been left out in order to make the example more readable. The major dierence is that after the message has been sent by write(), the program only waits for 1.5 seconds for a response from the server. If no response is received within that time, the program skips the read() part and exits. 15

void main(int argc, char *argv[]) { /* Various other declarations */ int sockfd, numbytes, result; fd_set fdset; struct timeval timeout; /* Create socket and endpoint information */ /* => socket (), bind(), connect() */ /* Look att udp_echo_client.c for details */ /* Prepare fdset */ FD_ZERO(&fdset); /* Clears fdset */ FD_SET(sockfd,&fdset); /* Add sockfd to fdset */ /* Set time to wait */ timeout.tv_sec = 1; /* Set time to wait */ timeout.tv_usec = 500000; /* Send and receive message */ write(sockfd, buf, strlen(buf)); result = select(fd_setsize, &fdset, NULL, NULL, &timeout); /* Start timer */ switch (result) { case -1: /* result = -1 ==> Error in select() */ perror("select"); exit(-1); case 0: /* result = 0 ==> Timer expired */ printf("timeout: No respons within 1.5 seconds\n"); break; default: /* Event occured before timer expired */ numbytes=read(sockfd,buf,bufsize); buf[numbytes] = '\0'; /* Compare sent and received message */ /* End of switch */ close(sockfd); There are a few things to notice about the select call: result = select(fd_setsize, &fdset, NULL, NULL, &timeout); Most important; the call select() blocks the execution. This means that the program stops there until one of the three cases in the switch statement occurs. The value of result determines which. We have put the arguments writefds and errorfds to NULL. This implies that we are only interested in events related to reading. In our case this means that we are waiting for reading on the socket descriptor sockfd, the only le descriptor in fdset. The reason why we introduced select in this section was that we needed a timer in the fetch exercise 7. In that case we don't skip the read call and terminate if the timer expires. Instead we retransmit the previous packet until we get a response. Notice also that select changes the value of fdset after each call and that the original value must be restored before the next call to select. 16

Exercises The names of the les you send in are supposed to be the ones stated in the assignment question. If you want to rename the les you should also hand in a makefile that reects these changes. If you are not familiar with makeles and how to create one, you can search Google using the keywords makefile tutorial. One of the results from this search is the URL http://www.eng.hawaii.edu/tutor/make/. This is useful for the tutor but also to you, since when compiling using a makele you need not remember the exact syntax and one or more compilations can be done as the result of one invocation. This is strongly advised. 1. The C code of the two example programs presented earlier (udp_echo_client.c and udp_echo_server.c) can be found on the home page of this course. Download them and make them work. Remember to compile each program according to: gcc -o server udp_echo_server.c -lsocket -lnsl -Wall 2. None of the two programs in exercise 1 have any error handling. Modify them in such a way that all system calls handles errors using perror(). At the same time; build a library udp.h that includes functions Socket(), Bind(),..., Recvfrom(). The various functions should be dened in a le named udp_def.c such that the following program is equivalent to udp_echo_client.c. The corresponding header le udp.h can be found at the home page of this course. /* udp_echo_clnt.c : An echo-client using udp.h */ #include <stdio.h> #include <unistd.h> /* close */ #include <stdlib.h> /* atoi */ #include <string.h> /* strcpy */ #include "udp.h" #define BUFSIZE 2000 #define MYPORT 0 /* Zero means auto-choice */ #define MSG "Our Echo Message!" void main(int argc, char *argv[]) { int sockfd; struct sockaddr_in myaddr; struct sockaddr_in theiraddr; char buf[bufsize] = MSG; if (argc!= 3) { fprintf(stderr,"usage: %s server_name port\n",argv[0]); exit(1); sockfd = Socket("udp"); GetMyAddress(MYPORT, &myaddr); Bind(sockfd, &myaddr); GetTheirAddress(atoi(argv[2]), argv[1], &theiraddr); Connect(sockfd, &theiraddr); Write(sockfd, buf, strlen(buf)); Read(sockfd, buf, BUFSIZE); if (strncmp(buf,msg,strlen(msg)) == 0) printf("%d bytes sent and received\n", strlen(buf)); else fprintf(stderr,"%s: sent and received msg not equal!\n",argv[0]); close(sockfd); 17

For example, the function Socket() might look like: int Socket(const char *transport) { int sockfd; if (strncmp(transport,"udp",3) == 0) sockfd = socket(pf_inet, SOCK_DGRAM, 0); else if (strncmp(transport,"tcp",3) == 0) sockfd = socket(pf_inet, SOCK_STREAM, 0); else { printf("%s : Unknown transport protocol in Socket\n",transport); exit(1); if (sockfd == -1) { perror("socket"); exit(1); return sockfd; You should also implement the program udp_echo_clnt.c and the corresponding server udp_echo_srv.c. In what follows, use these two programs as starting points. 3. Use TELNET or SSH to login at a dierent machine than the one you are using at the moment and start udp_echo_srv.c. Then try to contact it with your client. Use the program snoka presented in assignment 1 to monitor the trac. A snoka session should be handed in. 4. Modify udp_echo_clnt.c so that you can easily change the size (measured in bytes) of the data transmitted. (We suggest that you read the size from the terminal when starting the client program.) Then try to nd the upper limit for a single packet. What happens when a packet is transmitted that is larger than the upper limit? What determines the upper limit? The C code of the modied udp_echo_clnt.c together with the corresponding server, header, and denition les should be handed in. We also want thorough answers to the above questions based on facts from various executions and snoka sessions. 5. Simple fetch: In assignment 1 you made a program fetch that fetches les from a predened directory and saves them in the local directory. In this exercise you should make a client-server pair (fetch.c and fetchserver.c that uses fetch.h and fetch_def.c) that fetches a le from a remote machine. It should work like: prompt> fetch avari.msi.vxu.se 5350 rfc1350.txt 24599 bytes read and saved where avari.msi.vxu.se is the remote machine, 5350 is the port that fetchserver is listening to, and rfc1350.txt is the le to fetch. The maximum data size in each packet must not exceed 512 bytes. This exercise is just a preparation for the last exercise. However, we recommend it as a starting point. 6. Your program should be able to send any le. That includes large and small les and both text and binary les, e.g., images. Modify your program to handle this problem and describe the changes you have to make. 7. Describe (in text and simple pictures) what happens in fetch when using timeouts and retransmissions if an acknowledgement (ACK) is delayed for a period of time long enough for a single retransmission to occur. 8. fetch with error notication : Add timeouts and retransmissions to the fetch server according to the description given earlier in this text. Be careful, this is rather tricky. We strongly suggest that you start with a single acknowledged data packet. The C code of fetch.c, fetchserver.c, fetch.h, and fetch_def.c should be handed in together with a snoka session showing the resulting packet exchange between the client and the server in a case where only a single data packet is transmitted. 18

Handing in Some points to consider before you hand in your solutions: Make sure your fetch program can send both text les and binary les of arbitrary length, i.e., larger than 512 bytes. Verify that the le that was sent contains the exact same content as the original le. Use the Unix command cmp to do this. Preferably the fetch program will read from a directory relative to the directory from which the program was started (data/"), and not an absolute path ("/home/user/data/"). Please include the names of all group members in the email. Package the les in a well-known archive format (e.g., zip, gz). What to hand in 1. Exercise 4: udp_echo_clnt.c, udp_echo_srv.c, udp.h, and udp_def.c 2. Exercise 8: fetch.c, fetchserver.c, fetch.h, and fetch_def.c 3. A document containing the snoka session from exercises 3 and 7, and the answers from excersises 4, 6 and 7. 19