Socket Options

 
Let's look at socket options:
 
     #include <sys/types.h>
     #include <sys/socket.h>
 
     int getsockopt(int s, int level, int optname, char *optval,
          int *optlen);
     int setsockopt(int s, int level, int optname,
          const char *optval, int optlen);
 
Example:
 
    int     one = 1;
    if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&one, sizeof(one)) < 0)
            printf("error...");
 
  - When manipulating socket options, the  level  at  which  the
    option resides and the name of the option must be specified.
 
  - To manipulate options at the "socket" level, level is speci-
    fied  as  SOL_SOCKET.   To  manipulate  options at any other
    level, level is the protocol number  of  the  protocol  that
    controls  the  option.   For  example,  to  indicate that an
    option is to be interpreted by the TCP  protocol,  level  is
    set to the TCP protocol number (see getprotobyname(3N)).
 
  - The parameters optval and optlen are used to  access  option
    values  for setsockopt().  For getsockopt(), they identify a
    buffer in which the value(s) for the requested option(s) are
    to  be returned.
 
  - Most socket-level options take an int for optval.  For  set-
    sockopt(), the optval parameter should be non-zero to enable
    a boolean option, or zero if the option is to  be  disabled.
 
  - SO_LINGER  uses a struct linger parameter that specifies the
    desired state of the option and  the  linger  interval  (see
    below).  struct linger is defined in .  struct
    linger contains the following members:
 
     l_onoff             on = 1/off = 0
     l_linger            linger time, in seconds
 
  - The following options are recognized at  the  socket  level.
 
     SO_REUSEADDR        enable/disable local address reuse
 
     SO_KEEPALIVE        enable/disable   keep   connections
                         alive
 
     SO_DONTROUTE        enable/disable routing  bypass  for
                         outgoing messages
                         It indicates that outgoing messages
                         should bypass the  standard routing
                         facilities.   Instead, messages are
                         directed to the appropriate network
                         interface according to the network
                         portion of the destination address.
 
     SO_LINGER           linger on close if data is present
 
     SO_BROADCAST        enable/disable    permission     to
                         transmit broadcast messages
 
     SO_OOBINLINE        enable/disable  reception  of  out-
                         of-band data in band.  When set,
                         OOB data is treated like normal data.
 
     SO_SNDBUF           set buffer size for output
 
     SO_RCVBUF           set buffer size for input
 
     SO_TYPE             get the type  of  the  socket  (get
                         only)
 
  - SO_LINGER controls the action taken when unsent messages are
    queued  on  a  socket  and  a close(2) is performed.  If the
    socket promises reliable delivery of data and  SO_LINGER  is
    set,  the  system  will  block  the  process  on the close()
    attempt until it is able to transmit the data  or  until  it
    decides  it  is unable to deliver the information (a timeout
    period, termed the linger interval, is specified in the set-
    sockopt()  call  when SO_LINGER is requested).  If SO_LINGER
    is disabled and a close() is issued, the system will process
    the  close() in a manner that allows the process to continue
    as quickly as possible.
 
  - The option SO_BROADCAST requests permission to  send  broad-
    cast  datagrams  on the socket.  With protocols that support
    out-of-band data,  the  SO_OOBINLINE  option  requests  that
    out-of-band data be placed in the normal data input queue as
    received; it will then be accessible with recv()  or  read()
    calls without the special MSG_OOB flag.

 

Select

 

The select call lets you look for data on a number of file descriptors

(including sockets) simultaneously.

 

     #include <sys/time.h>

 

     int select(int  nfds,  fd_set  *readfds,  fd_set  *writefds,

     fd_set *errorfds, struct timeval *timeout);

 

     void FD_SET(int fd, fd_set *fdset);

 

     void FD_CLR(int fd, fd_set *fdset);

 

     int FD_ISSET(int fd, fd_set *fdset);

 

     void FD_ZERO(fd_set *fdset);

 

     The select() function indicates which of the specified  file

     descriptors  is ready for reading, ready for writing, or has

     an error condition pending.  If the specified  condition  is

     false  for  all  of the specified file descriptors, select()

     blocks, up to the  specified  timeout  interval,  until  the

     specified  condition  is true for at least one of the speci-

     fied file descriptors.

 

    The nfds argument specifies the range of file descriptors to

    be  tested.  The select() function tests file descriptors in

    the range of 0 to nfds-1.

 

Example:

 

   #define MAXCONNECTS 30

 

   fd_set readfds;

 

   struct {

      int connected;

      int fd;

   } recvfd[MAXCONNECTS];

 

  . . .

 

   for (i = 0; i < MAXCONNECTS; i++) {

      recvfd[i].connected = 0;

   }

 

   . . .

 

   /*

    *  Get a socket into TCP/IP.

    */

   if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {

      perror("socket failed");

      exit(1);

   }

 

   . . .

 

   while (1) {

      FD_ZERO(&readfds);

      FD_SET(socket_fd, &readfds);

      biggest = socket_fd;

      for (i = 0; i < MAXCONNECTS; i++) {

         if (recvfd[i].connected) {

            FD_SET(recvfd[i].fd, &readfds);

            if (recvfd[i].fd > biggest) {

               biggest = recvfd[i].fd;

            }

         }

      }

      if ((select(biggest + 1, &readfds, (fd_set *) 0, (fd_set *) 0, (struct timeval *)0) < 1)) {

           perror("select");

           exit(1);

      }

      if (FD_ISSET(socket_fd, &readfds)) {

           printf("got something on socket_fd\n");

           if ((newconn = accept(socket_fd, (struct sockaddr *)&client_addr,

                          &length)) < 0) {

              perror("could not accept call");

              exit(1);

           }

           for (i = 0; i < MAXCONNECTS; i++) {

              if (recvfd[i].connected == 0)

                 break;

           }

           if (i == MAXCONNECTS) {

              sprintf(buf, "Too many connections, try again later\n");

              write(newconn, buf, strlen(buf) + 1);

              close(newconn);

              continue;

           }

           sprintf(buf, "Welcome to the multiplexing server\n");

           write(newconn, buf, strlen(buf) + 1);

 

           recvfd[i].connected = 1;

           recvfd[i].fd = newconn;

      }

      for (i = 0; i < MAXCONNECTS; i++) {

          if (recvfd[i].connected && FD_ISSET(recvfd[i].fd, &readfds)) {

             /*

* process data from recvfd[i].fd

              */

          }

      }

      continue;

   }

 

 

 

Protocols

 
 
The telnet command is a very good command to test protocols.  It takes
an optional port number, and sends ASCII data to the server on that port.
 
Now let's look at some protocols:
 
 
The Simple Mail Transfer Protocol
 
  The client connects to the server.  The server is listeneing on port
  25.
 
  After opening, you send the string "HELO" followed by your domain
  name.
 
  Example:  HELO  cs.nyu.edu
 
   The first step in the procedure is the MAIL command.  The
   contains the source mailbox.
 
     MAIL  FROM:
 
  Example: MAIL FROM: padovano@cs.nyu.edu
 
  This command tells the SMTP-receiver that a new mail
  transaction is starting and to reset all its state tables and
  buffers, including any recipients or mail data.  It gives the
  reverse-path which can be used to report errors.  If accepted,
  the receiver-SMTP returns a 250 OK reply.
 
  The second step in the procedure is the RCPT command.
 
     RCPT  TO:
 
  Example:  RCPT  TO: bill.clinton@whitehouse.gov
 
  This command gives a forward-path identifying one recipient.
  If accepted, the receiver-SMTP returns a 250 OK reply, and
  stores the forward-path.  If the recipient is unknown the
  receiver-SMTP returns a 550 Failure reply.  This second step of
  the procedure can be repeated any number of times.
 
  The third step in the procedure is the DATA command.
 
     DATA
 
  If accepted, the receiver-SMTP returns a 354 Intermediate reply
  and considers all succeeding lines to be the message text.
  When the end of text is received and stored the SMTP-receiver
  sends a 250 OK reply.
 
  The data is ended with a "." on a single line, and should contain
  mail headers.
 
  S: MAIL FROM: padovano@cs.nuy.edu
  R: 250 ok
  S: RCPT TO: bill.clinton@whitehouse.gov
  R: 250 ok
  S: DATA
  R: 354 send the mail data, end with .
  S: From: padovano@cs.nuy.edu
  S: To: bill.clinton@whitehouse.gov
  S: Subject: Good job
  S:
  S:   Just a quick note to say you're doing a fine job.
  S:   Keep up the good work.
  S: .
  R: 250 ok
 
  End the sessions with QUIT
 
  Example:  QUIT