Advanced Sockets in UNIX / Linux References: Internetworking with TCP/IP (Comer) (Linux / POSIX...
-
Upload
marian-manning -
Category
Documents
-
view
240 -
download
2
Transcript of Advanced Sockets in UNIX / Linux References: Internetworking with TCP/IP (Comer) (Linux / POSIX...
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() */
}