1 advanced i/o computer network programming. 2 regarding project1 –use rcs to store different...

28
1 Advanced I/O Computer Network Programming

Post on 20-Dec-2015

213 views

Category:

Documents


0 download

TRANSCRIPT

1

Advanced I/O

Computer Network Programming

2

Regarding Project1 – Use RCS to store different revisions of your programs

– this is a requirement!

– you will loose points if you don’t conform!

– Your programs should be able to compile and run on SunOS 5.5.

– We will do out tests on SunOS 5.5

– Don’t waste time in trying to reduce the time that your programs spends in transferring files.

– There will tiny bonus or may be not at all.

– Project 2 will be assigned soon, so that you can have larger window of time to work.

– Probably on Friday.

3

Memory Allignment

The data from memory is read usually in chunks of 2, 4, 8 bytes.

We have to allign the data types in multiple of their size. Meaning that:

short should start at even memory addresseslong should start at memory addresses divisable by 4. char can start at any memory addressstrings and char arrays can start at any memory address.

If you try to retrieve an integer value from a memory address which is not multiple of 4, you will most likely get a segmentationfault error: core dump!

4

Compiler aligns the fields of a structure

struct foo { char bytes[17]; /* 17 bytes */ int numbers[33]; /* 33 * 4 bytes */ }

} X; /* 149 bytes */

The allocated amount of memory for varible X is not 149, but it is 152 bytes.

The reason is that integers should start at word (4 bytes) boundaries and compiler inserts 3 padding bytes after thebytes array (after first 17 bytes). Then starts the integers.

5

Lets see some alignment problems

unsigned int x;unsigned char *buf;

buf = (unsigned char *) malloc (1024);x = *((unsigned int *)buf + 2); /* you may get a segmentation fault on some machines */x = *((unsigned int *)buf + 4); /* this is OK */

/* to prevent segmentation fault you may use memcpy ınstead of direct assignment using type casting */memcpy ((void*) &x, (void *) buf + 2, sizeof(unsigned int)); /* this is OK - copies 4 bytes starting at address buf + 2 */

For project you may encounter similar aligment problem. So use memcpy when you areaccessing the header fields of the message that I defined: [len(2), seqno(4)][data(N)]

I should have defined the header in an other format like following:[seqno(4 bytes), len(4 bytes)] [data(N)]

6

unsighned int x;unsigned short y;char *buf;struct header {

unsigned int seqno;unsigned short len;

} *hptr;buf = (char *) malloc (1024);If I would have defined the header in the following format

[seqno(4 bytes), len(4 bytes)] [data(N)]than you could access the fields of the hader also like following (so my header definition isnot very efficient)

hptr = (struct header *)buf;x = hptr->seqno;y = hptr->len;

or hptr->seqno = 1000;

Again you can use memcpy for this case also. y = *((unsigned short *)buf + 4);

7

Lets look to the header definitions of well-known protocols

struct ip { u_char ip_v:4, /* half byte - version */ ip_hl:4; /* half byte - header length */ u_char ip_tos; /* 1 byte - type of service */ short ip_len; /* 2 bytes - total length */ u_short ip_id; /* 2 bytes - identification */ short ip_off; /* 2 bytes - fragment offset field */ u_char ip_ttl; /* 1 byte - time to live */ u_char ip_p; /* 1 byte - protocol */ u_short ip_sum; /* 2 byte - checksum */ struct in_addr ip_src, /* 4 bytes - source address */

ip_dst; /* 4 bytes - dest address */};

If you look carefully, each fied is alligned according to its size.char can present at any address, short can present at even addresses and int can present at addresses

multiples of 4.

IP Protocol Header

uchar *buffer; struct ip * hptr;/* assume buffer contains an IP datagram. Then you can access the header fields of the IPdatagram as follows */hptr = (struct ip *)buffer;printf (“ %d %d “, ntohl(hptr->ip_src), ntohs(hptr->ip_len));…..

8

Lets look to the header definitions of well-known protocols

struct tcphdr { u_short th_sport; /* 2 bytes - source port */ u_short th_dport; /* 2 bytes - destination port */ tcp_seq th_seq; /* 4 bytes- sequence number */ tcp_seq th_ack; /* 4 bytes - acknowledgement number */ u_int th_off:4, /* half byte - data offset */ th_x2:4; /* half byte - (unused) */ u_char th_flags; /* 1 byte */ u_short th_win; /* 2 bytes - window */ u_short th_sum; /* 2 bytes - checksum */ u_short th_urp; /* 2 bytes - urgent pointer */};

If you look carefully, each fied is alligned according to its size.char can present at any address, short can present at even

addresses and int can present at addresses multiples of 4.

TCP Protocol Header

9

One more thing

uchar bufarray[1024]; /* array may start at any address, odd, even,…. */uchar *bufdynamic;bufdymamic = (char *)malloc(1024); /* dynamic memory allocation gives a address pointer

which is multiple of 8 - aligned*//* Hence it is safer to allocate memory using malloc if you would access the fields ofa header or an other structure that is mapped to the buffer */

/* If you use memcpy, both are OK, but this is less efficient */

There are two ways to allocate memory for a buffer:- use char array- use malloc

and there is a difference between these two in terms of memoryalignment:

10

One more thing continuedIf you want your static buffer (char array) to start at a correctlyaligned memory address then use union

(this will force the compiler not start the array at an arbitrary address but at an aligned address)

struct hdr {int x;int y;

} *h;union aligned_buf {

struct hdr h;char data[1024];

} mybuffer;

/* by this definition compiler makes sure that the start address of mybuffer is word (4 bytes) aligned. / * then you can safely cast a struct hdr pointer to point to mybuffer.data and access its members */h = (struct hdr *)mybuffer.data;h->x = ….h->y = ….

11

Outline for todays Class• How we can set timeout on an I/O operation

• select, alarm, socket options.

• New I/O functions• recv, send, recvmsg, sendmsg, readv, writev

• How to determine the amount of data in socket recv buffer

• How to use the standard I/O library with sockets.

• independency from operating system

12

Timeouts– Sometimes we want to set timout on I/O

operations and also on connect() function, so that they don’t block forever or for a long time.

– 3 ways to set a timeout• call alarm() function which generates SIGALRM

signal when timer expires.

• Call select() and block on select until specified timeout value or until data is available.

• Set socket options SO_RCVTIMEO and SO_SNDTIMEO

– not all systems support this

13

connect() with timeout using alarm()static void connect_alarm(int);int connect_timeo(int sockfd, const SA *saptr, socklen_t salen, int nsec){ Sigfunc *sigfunc; int n;

sigfunc = Signal(SIGALRM, connect_alarm); /* set the alarm clock for the process*/ if (alarm(nsec) != 0) err_msg("connect_timeo: alarm was already set");

if ( (n = connect(sockfd, (struct sockaddr *) saptr, salen)) < 0) { close(sockfd); if (errno == EINTR) errno = ETIMEDOUT; } alarm(0); /* turn off the alarm */ Signal(SIGALRM, sigfunc); /* restore previous signal handler */ return(n);}

/* our SIGALRM signal handler */static voidconnect_alarm(int signo){ return; /* just interrupt the connect() */}

SIGALRM signal makes the connect returnafter specified amount of time if connectioncould not be established.

14

UDP echo client with timeout using alarm()static void sig_alrm(int);void dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen){ int n; char sendline[MAXLINE], recvline[MAXLINE + 1]; Signal(SIGALRM, sig_alrm); while (Fgets(sendline, MAXLINE, fp) != NULL) { Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen); alarm(5); /* set timer for 5 seconds */ if ( (n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL)) < 0) { if (errno == EINTR) fprintf(stderr, "socket timeout\n"); else err_sys("recvfrom error"); } else { alarm(0); /* clear the timer */ recvline[n] = 0; /* null terminate */ Fputs(recvline, stdout); } }}

static void sig_alrm(int signo){ /* just interrupt the recvfrom() */ return; }

15

void dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen){ int n; char sendline[MAXLINE], recvline[MAXLINE + 1];

while (Fgets(sendline, MAXLINE, fp) != NULL) {

Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);

if (readable_timeo(sockfd, 5) == 0) { fprintf(stderr, "socket timeout\n"); } else { n = Recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL); recvline[n] = 0; /* null terminate */ Fputs(recvline, stdout); } }}

intreadable_timeo(int fd, int sec){ fd_set rset; struct timeval tv;

FD_ZERO(&rset); FD_SET(fd, &rset);

tv.tv_sec = sec; tv.tv_usec = 0;

return(select (fd+1, &rset, NULL, NULL, &tv)); /* > 0 if descriptor is readable */}

UDP echo client with timeout using select()

16

void dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen){ int n; char sendline[MAXLINE], recvline[MAXLINE + 1]; struct timeval tv;

tv.tv_sec = 5; tv.tv_usec = 0; /* set timeout value to 5 seconds */ Setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); while (Fgets(sendline, MAXLINE, fp) != NULL) { Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen); n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL); if (n < 0) { if (errno == EWOULDBLOCK) { fprintf(stderr, "socket timeout\n"); continue; } else err_sys("recvfrom error"); } recvline[n] = 0; /* null terminate */ Fputs(recvline, stdout); }}

UDP echo client with timeout using socket option

17

New Socket I/O functions

• recv(), send()• ssize_t recv(int sd, void *buf, size_t nbytes, int flags);

• ssize_t send(int sd, void *buf, size_t nbytes, int flags);

– similar to read and write functions exept they take flags argument:

– Flags could be: » zero» MSG_DONTROUTE, MSG_DONTWAIT, MSG_OOB,

MSG_PEEK, MSG_WAITALL

18

New Socket I/O functions• readv and writev functions

• similar to read and write but allows to read into or write from multiple buffers with a single function call.

• ssize_t readv (int fd, const struct iovec *iov, int iovcnt);

• ssize_t writev (int fd, const struct iovec *iov, int iovcnt);– returns the number of bytes read or written, -1 on error.

struct iovec {void *iov_base; size_t iov_len;

}

• can be used with any descriptor

• for UDP, all buffers are sent in one UDP datagram

19

New Socket I/O functions• recvmsg() and sendmsg() functions

– ssize_t recvmsg(int sd, struct msghdr *msg, int flags);

– ssize_t sendmsg(int sd, struct msghdr *msg, int flags); struct msghdr { void *msg_name; /* optional address */ size_t msg_namelen; /* size of address */ struct iovec *msg_iov; /* scatter/gather array of buffers*/ int msg_iovlen; /* number of elements in msg_iov */ void *msg_control; /* ancillary data (control data) */ size_t msg_controllen; /* ancillary data buffer len */ int msg_flags; /* flags on received message */};

These socket I/O functions are most generic, they can do all the things the other socket I/O functions can do.

Two flags of special importance: MSG_BCAST, MSG_MCAST

20

msghdr structure

msg_namemsg_namelenmsg_iovmsg_iovlenmsg_controlmsg_controllenmsg_flags

sockaddrstructure

(variable length)

iov_baseiov_leniov_baseiov_leniov_baseiov_len

Variable size buffer

buffer

buffer

control msg structure

(variabe length)

(can contain an IP address (IPv4 or IPv5)

(can return control information, forexample the IP destination address for a receivd UDP datagram with recvmsg function)

DATA is stored in thesebuffers (before sending or afterreceiving)

21

Ancillary data can be originated form kernel or from sending process.

Protocol cmg_level cmg_type descriptonIPv4 IPPROTO_IP IP_RECVDSTADDR recv dest address with UDP dataUnix SOL_SOCKET SCM_RIGHTS send/recv descriptorDomain SCM_CREDS send/recv user credentials

Ancillary Data

cmgg_lencmgg_levelcmgg_type

data

cmg_hdrcmg_len

Control message format

Ancillary data should be carried using the control message structure

Data could be IP address, descriptor, credentials, etc.

22

How much data is queued in the socket recv buffer

– Sometimes, we would like to learn how much data is queued to be read on a socket.

– 3 techniques• use non-blocking I/O ( we will see this later)

• call recv with MSG_PEEK and MSG_DONTWAIT flags– for UDP, returns the size of the first UDP datagram queued

(there may be more than one UDP datagram)– for TCP, returns the all data queued in the recv buffer

• use ioctl() function with FIONREAD command. – Returns the amount of all the buffered data in the socket received

buffer

23

Standard I/O and sockets– read, write, send, recv are not ANSI C functions

and therefore can only be used in UNIX systems– It is also possible to use the standard I/O library

functions with sockets. Standard I/O library ispart of ANSI C

» the code could be more easily ported to non-Unix systems

– Standard I/O library uses buffers and is stream based

– the data to be output is stored in those buffers until the buffer is full. Then the output operation to device takes place

24

Things to consider

– A standard I/O stream can be created from any descriptor (including sockets) by calling fdopen function.

• The inverse is done using fileno function: given a I/O stream, get the corresponding integer descriptor.

– Sockets are full duplex. – Standard I/O streams can also be full duplex but it

requires careful attention when doing input and output on the stream at the same time.

– Solution: open two I/O streams for socket: one for reading, and one for writing.

25

Str_echo function using Standard I/O

void str_echo(int sockfd){ char line[MAXLINE]; FILE *fpin, *fpout;

/* convert the socket descriptor into input and output stream */ fpin = fdopen(sockfd, "r"); fpout = fdopen(sockfd, "w"); for ( ; ; ) { /* read a line from the socket */ if (fgets(line, MAXLINE, fpin) == NULL) return; /* connection closed by other end */ /* write a line to the socket */ fputs(line, fpout); }}

fgets and fputs are part of the standard I/O library (stdio.h)read and write, etc. are not part of the standard I/O library

26

Problem with this Solution– Standard I/O uses buffered I/O unless otherwise

specified. – Hence when the echo server sends back the lines using

fputs, they are actually buffered in the I/O library and transmitted only when the buffer is full

– User will not be able to see the echoed lines and the server terminates upon which the buffer is flushed.

stream buffer (8192 bytes)

Socket

Standard I/O library

Kernel

Application fputs(line, MAXLINE, fpout)

The lines are buffered until the buffer is full, then they are sent to the socket

Transport layer start transmitting the dataimmediately (if possible)using TCP or UDP

27

Standard I/O library buffering

• 3 types of buffering is done by the standard I/O library

• Fully buffered: I/O takes place when the buffer is full, or the process calls explicitly fflush() function, or the process terminates by calling exit.

• Line buffered: I/O takes place only when new line (\n) is encountered on the steam, or when the process calls fflush(), terminates by calling exit.

• Unbuffered I/O. I/O takes place immediately when the standard I/O output function is called.

28

– Force the output stream to be line buffered by calling setvbuf function

– Call fflush function after each call to standard I/O output function fputs.

Solution to our Problem

What does Unix do• Standard input and output is fully buffered, unless they referto a terminal device in which case they are line buffered

/dev/console, /dev/ttya, /dev/ttyp0, /dev/ptyp0,….are

examples of terminal devices • All other streams are fully buffered, unless the stream refersto a terminal device in which case they are again line buffered.