advanced sockets in unix / linux references: internetworking with tcp/ip (comer) (linux / posix...

31
Advanced Sockets in UNIX / Linux References: Internetworking with TCP/IP (Comer) (Linux / POSIX Sockets Version) UNIX Network Programming Vol. 1, 2ed. (Stevens) Linux Sockets Programming (Walton)

Upload: marian-manning

Post on 16-Dec-2015

240 views

Category:

Documents


2 download

TRANSCRIPT

Advanced Socketsin UNIX / Linux

References:Internetworking with TCP/IP (Comer)

(Linux / POSIX Sockets Version)

UNIX Network Programming Vol. 1, 2ed.(Stevens)Linux Sockets Programming (Walton)

cs423-cotter 2

Addressing Support

• getsockname (socket, name, namelen)– return value = 0 on success, SOCKET_ERROR on failure

– socket = SOCKET

– name = struct sockaddr *

– namelen = socklen_t * sizeof(sockaddr)

cs423-cotter 3

Addressing Support• getpeername(socket, remaddr, addrlen)

– return value = 0 on success, SOCKET_ERROR on failure

– socket = SOCKET

– remaddr = struct sockaddr *

– addrlen = socklen_t *sizeof(sockaddr)

Getaddrinfo

• Combines:– gethostbyname () – (getipnodebyname() )

– gethostbyaddr() – (getipnodebyaddr()

– getservbyname()

– getservbytport()

• Designed to support IP v4, IP v6• Can return a linked list of addr structures that can

be used by bind (), connect (), etc. – Sorts list by relevance.

4cs423-cotter

Getaddrinfo

• int getaddrinfo ( char *host, char *service, struct addrinfo *hints, struct addrinfo **res);

– struct addrinfo {int ai_flags;

int ai_family;

int socktype;

int ai_protocol;

size_t ai_addrlen;

struct sockaddr * ai_addr;

char * ai_cannonname;

struct addrinfo * ai_next;

}

5cs423-cotter

Send / recv Options

Flag Description RECV SEND

MSG_DONTROUTEMSG_DONTWAITMSG_PEEKMSG_WAITALLMSG_OOB

Bypass routing table lookupOnly this operation is nonblocking

Peek at incoming messageWait for all the data

Send or receive out-of-band data

****

**

*

recv (s, buf, sizeof(buf), flags);

Out-of-band / Urgent Data

• Objective is to pass urgent data as part of a TCP packet that may also include regular (inband) data.

• TCP urgent pointer references a single byte in TCP data. That single byte is what gets returned as urgent (OOB) data.

• Sending OOB data:

• send (s, buf, strlen(buf), MSG_OOB);• sendto (s, buf, strlen(buf), MSG_OOB, (struct sockaddr FAR *)&sin,sizeof(sin));

Receiving OOB data - SIGURG

signal (SIGURG, myUrgHandlr) //Identify signal Handler

static void myUrgHandlr(int signo) { //signal handler

int n;

char buf[BUFSIZE];

n = recv(ss,buf,sizeof buf,MSG_OOB);

buf[n] = '\0'; // null terminator for buffer

printf("Urgent Data: '%s' (%d)\n", buf,n);

// reset the signal handler.

signal(SIGURG,sigurg);

}

Receiving OOB data - 2

int main(int argc, char *argv[]) {char *service = "6543"; /* service name or port number */struct sockaddr_in fsin; /* the address of a client */unsigned int alen; /* length of client's address*/int z;char buf[BUFSIZE];switch (argc) {

case 1:break;

case 2:service = argv[1];break;

default:errexit("usage: TCPechod [port]\n");

}s = passiveTCP(service, QLEN);

Receiving OOB data - 3

/*--------------- * Catch SIGURG: *--------------*/ signal(SIGURG,sigurg);

ss = accept(s, (struct sockaddr *)&fsin, &alen); /*Establish ownership so that we can catch SIGURG: */

z = fcntl(ss,F_SETOWN,getpid()); if ( z == -1 )

errexit("fcntl fail: %s\n", strerror(errno)); else

printf("We own the socket\n");

Receiving OOB data - 4

while (1) {

z = recv(ss,buf,sizeof buf,0);

if ( z == -1 )

errexit("recv fail: %s\n", strerror(errno));

if ( z == 0 )

break;

buf[z] = 0;

printf("rcv '%s' (%d)\n", buf, z);

}

close(s);

return 0;

}

cs423-cotter 12

Smart Select

• Some programs may require more than 1 thread (or process), but may be able to support more than 1 client per thread.

• Select can be combined with multi-tasking to provide appropriate levels of client support.

cs423-cotter 13

Smart-select-server.cint main(int argc, char *argv[]){

::if ( bind(sd, (struct sockaddr*)&addr, sizeof(addr)) == 0){

listen(sd, 15); for (;;) {

if ( NumChildren < MAXPROCESSES ){ int pid;

if ( (pid = fork()) == 0 )servlet(sd);

else if ( pid > 0 )NumChildren++;

elseperror("fork()");

}else

sleep(1); }

}else

perror("bind()");return 0;

}

14

Smart-select-server.cSmart-select-server.c

void servlet(int server){

fd_set set, rset;int maxfd = server;int ceiling=0;FD_ZERO(&set);FD_ZERO(&rset);FD_SET(server, &set);for (;;) {

memcpy (&rset, &set, sizeof (fd_set));struct timeval timeout={2,0}; // 2 seconds

if ( select(maxfd+1, &rset, 0, 0, &timeout) > 0 ) { //---If new connection, connect and add to list---

if ( FD_ISSET(server, &rset) ) { if ( ceiling < MAXCONNECTIONS ) {

int client = accept(server, 0, 0); if ( maxfd < client )

maxfd = client; FD_SET(client, &set);

ceiling++;printf("select process #%d: %d connected\n",

getpid(), ceiling); }

}

15

Smart-select-server.cSmart-select-server.celse {

int i;for ( i = 0; i < maxfd+1; i++ ) {

if ( FD_ISSET(i, &rset) ) {char buffer[1024];int bytes;bytes = recv(i, buffer, sizeof(buffer), 0);if ( bytes < 0 )// check if channel closed {

close(i);FD_CLR(i, &set);ceiling--;printf("select process #%d: %d connected\

n",getpid(), ceiling);

}else //process the request

send(i, buffer, bytes, 0);}

}// end of for}//end of else

}//end of if}//end of forexit(0);

}

cs423-cotter 16

Poll Function

• int poll (struct pollfd *fdarray, unsigned long nfds, int timeout)

– Return: count of ready fds, -1 on error, 0 on timeout

• timeout: -1 wait forever, 0 no block, >0 wait for specified milliseconds.

• struct pollfd {

int fd; //descriptor to check

short events; //events of interest on fd

short revents; //events that occurred on fd

}

cs423-cotter 17

Poll Events

Constant In to events

From revents

Description

POLLIN * * Normal or priority data can be read

POLLRDNORM * * Normal data can be read

POLLRDBAND * * Priority band data can be read

POLLPRI * * High Priority data can be read

POLLOUT * * Normal data can be written

POLLWRNORM * * Normal data can be written

POLLWRBAND * * Priority data can be written

POLLERR * An error has occurred

POLLHUP * Hangup has occurred

POLLNVAL * Descriptor is not an open file

cs423-cotter 18

TCPpollechod.c#include <sys/types.h>,<sys/socket.h>,<sys/time.h>,<netinet/in.h><unistd.h>,<string.h>,<stdio.h>,<asm/poll.h>,<asm/errno.h>

#define QLEN 5 // maximum connection queue length#define BUFSIZE 4096#define MAX_OPEN 16#define INFTIM -1

int main(int argc, char *argv[]){

char *service = "9877"; // service name or port numberstruct sockaddr_in fsin; // the from address of a clientint msock, connfd, sockfd; // master server socketstruct pollfd client[MAX_OPEN];unsigned int alen; // from-address lengthint fd, nfds, maxi, nready, i, n;socklen_t clilen;char line[BUFSIZE];

cs423-cotter 19

TCPpollechod.cswitch (argc) {

case 1:break;

case 2:service = argv[1];break;

default:errexit("usage: TCPmechod [port]\n");

}msock = passiveTCP(service, QLEN);

//Now we need to set up the polling process.client[0].fd = msock;client[0].events = POLLRDNORM;for (i=1; i < MAX_OPEN; i++)

client[i].fd = -1; // -1 indicates available entrymaxi = 0;

cs423-cotter 20

TCPpollechod.cwhile (1) {

nready = poll(client, maxi +1, INFTIM);if (client[0].revents & POLLRDNORM)//new connect rqst?{

clilen = sizeof(fsin);connfd = accept(msock, (struct sockaddr *)

&fsin, &clilen);for (i = 1; i < MAX_OPEN; i++)

if (client[i].fd < 0) {client[i].fd = connfd;//save descriptorbreak;

}if (i == MAX_OPEN)

errexit("too many clients");client[i].events = POLLRDNORM;if (i > maxi)

maxi = i; // max index in client[] array if (--nready <= 0)

continue; // no more readable descriptors}

cs423-cotter 21

TCPpollechod.cfor (i = 1; i <= maxi; i++) // check all clients for data {

if ( (sockfd = client[i].fd) < 0)continue;

if (client[i].revents & (POLLRDNORM | POLLERR)) {

if ( (n = read(sockfd, line, BUFSIZE)) < 0) {if (errno == ENOTCONN) { //connection reset

close(sockfd);client[i].fd = -1;

} elseerrexit("readline error");

} else if (n == 0) { // connection closed by client

close(sockfd);client[i].fd = -1;

} else {printf ("Got %d char from client %d\n", n, i);write(sockfd, line, n);

}if (--nready <= 0)

break; // no more readable descriptors }

}} }

cs423-cotter 22

IO control command

• ioctlsocket(socket, cmd, argp)– return value = 0 on success, SOCKET_ERROR on

failure

– cmd = socket command requested (long)• FIONBIO (Set socket to non-blocking mode)

• FIONREAD (Determine the amount of pending data to be read)

• SIOCATMARK (Determine whether all OOB data has been read)

– argp = pointer to return value (u_long *)

cs423-cotter 23

Windows Non-Blocking

if (ioctlsocket(sock, FIONBIO, &bflag)== SOCKET_ERROR) errexit("Can't set socket to be nonblocking %d\n",GetLastError());

::timer = clock(); // set the timerrcfm_ok = false;while ( clock() - timer < TIMEOUT){

cc = recvfrom(sock, buf, BUFSIZE, 0, (sockaddr *)&clt_addr, &alen);if ( cc>=0) //Should also test for error return!!{

rcfm_ok = true;break;

}}

cs423-cotter 24

Windows Non-Blocking

• The clock() function (part of time.h) counts in terms of milliseconds. (Independent of the hardware timer. The hardware timer might not be as precise. I think the Windows timer is on the range of 15 ms. ) In this example, we set the TIMEOUT value to 500 miliseconds (well within our level of precision). This allows us to wait for a predetermined amount of time (in this case 500 ms) until we give up on getting an answer.

cs423-cotter 25

Linux Non-Blockingsave_file_flags = fcntl(sock, F_GETFL);save_file_flags |= O_NONBLOCK;fcntl(sock, F_SETFL, save_file_flags);:while ( delay < TIMEOUT){

cc = recvfrom(sock, buf, BUFSIZE, 0, (sockaddr *)&clt_addr, (socklen_t*) &alen);if (cc < 0){

if (errno == EAGAIN) // we "nonblocked" out of the function{

gettimeofday(&mytime, &myzone);endsec = mytime.tv_sec;endus = mytime.tv_usec;delay = endus - startus;

}else //we had a real problem with recvfrom

errexit ("recvfrom failed");}else //We got some data. Go process it.{

rcfm_ok = true;break;

}} // end of delay while

cs423-cotter 26

Linux Non-Blocking

• In this example, we first set the socket to be non-blocking. The form of that function is conceptually the same as for Windows, but it uses a different command.

• This program uses the gettimeofday command to check for the time. It returns a value that is precise to microseconds, although its accuracy is limited by the system timer for the OS / hardware. (typically 15 ms).

• If the socket is non-blocking, we will get an error return from recvfrom (-1). To tell the difference between a real error and a non-blocking return, we need to check the value of the global variable “ errno”. If it is equal to EAGAIN, then we left recvfrom because it was non-blocking. We test the time here to see how long we have been doing this loop.

• If we actually got some data, we would have cc > 0. That sends us to the last “else” loop which breaks us out of the loop. Otherwise we go back to the recvfrom and repeat until we run out of time.

cs423-cotter 27

Socket Option commands

• getsockopt, setsockopt (socket, level, optname, optval, optlen)– return value = 0 on success, SOCKET_ERROR on failure– level = (Where option is interpreted)

• SOL_SOCKET IPPROTO_IPV6• IPPROTO_TCP IPPROTO_ICMPV6• IPPROTO_IP

– opt = option selected• SO_BROADCAST SO_RCVBUF• SO_KEEPALIVE SO_RCVTIMEO• SO_OOBINLINE …

– optval = address for value returned (void *)– optlen = length of option field (int *)

cs423-cotter 28

Bcast_1.cBasic client preamble………

setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));signal(SIGALRM, recvfrom_alarm);while (fgets(sendline, MAXLINE, stdin) != NULL) {

servlen = sizeof(sin); sendto(s,sendline,strlen(sendline),0,&sin,servlen);

alarm(5); for ( ; ; ) {

len = servlen; n = recvfrom(s,recvline,MAXLINE,0,&reply_addr,&len); if (n < 0) {

if (errno == EINTR)break; // waited long enough for replies

elseerrexit("recvfrom error");

}

cs423-cotter 29

Bcast_1.c

else {// Reformat info and print time and source IDrecvline[n] = 0; /* null terminate */now = ntohl((unsigned long)now);//put in host ordernow -= UNIXEPOCH; // convert UCT to UNIX epochprintf("%s", ctime(&now));sadr = (struct sockaddr_in *)&reply_addr;printf("from %s: %s",inet_ntoa(sadr->sin_addr),

ctime(&now));}

}}

}

cs423-cotter 30

Bcast_1.cint errexit(const char *format, ...){

va_list args;

va_start(args, format);vfprintf(stderr, format, args);va_end(args);exit(1);

}

static void recvfrom_alarm(int signo){

printf("Alarm was triggered\n");/* just interrupt the recvfrom() */

}

cs423-cotter 31

Summary

• Many other socket capabilities beyond basic client / server– Other library commands

– Other ways to use select( )

– Poll( ) function

– Broadcast capability

– Etc.