Select on socket

Select on socket

Post by Frank Lang » Sat, 24 May 1997 04:00:00



This is a multi-part message in MIME format.

--------------4BA539A9338E9DD41688A0DF
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

I have some problems with select call on a TCP/IP socket.

I built a testprogram where a client (connect) and
a server (listen) task always sends or reads data
when the read/write selectmask becomes ready.

For some reasons within a wide area network using
routers, I set the SO_RCVBUF option to 1024.

Now I got the following problem:

On the client side, the select call with an empty writemask,
will never return, although the server has sent data.
If the writemask not empty everything works well.
With a SO_RCVBUF option greater than 3147 there is also no problem
with an empty writemask.

On the server side I had no problem.

Enclosed you will find my testprogram

==============================================================================
Philips Automation Projects               Phone:  +49 561 501 1303
Miramstr. 87                              Fax:    +49 561 501 1688
34123 Kassel                              Email:
fr...@ap-kas.ie.philips.com
Germany
==============================================================================

--------------4BA539A9338E9DD41688A0DF
Content-Type: text/plain; charset=us-ascii; name="csfd.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="csfd.c"

/* Testprogramm for TCP/IP Full Duplex
 *
 * F. Lange, Philips Kassel - PAP
 *
 * Compile: Sorix: cc -DSORIX csfd.c -g -o csfd -lsocket -lnsl
 *          Linux: cc csfd.c -g -o csfd
 *
 * Start: server: csfd server slen=1200 tcprlen=1024
 *        client: csfd host=<server> slen=1200 tcprlen=1024 clnosend
 *
 */

#define MAXFD 128

#include <stdio.h>
#include <sys/time.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#ifdef SORIX
#include <sys/select.h>
#endif

/* TCP/IP Linger structure */
static int Linger[2] = { 1, 0 };
int Li_socket = 0, Cl_socket = 0;
int MY_port  = 5555;
int MY_debug = 0;

char Host[128];
int  Serverflag = 0;  /* 0 = Client 1 = Server */

#define HEAD_ID 0x11223344L

#define OUTLEN 8215

char *Outbuff, *Inbuff;

int  TcpSendBufLen = 0;     /* sollte 1024 sein, wegen NRE Problem ?! */
int  TcpRecvBufLen = 0;
int  ClientDoSend = 1;

int  Outlen = OUTLEN;

int  dlen;
char *dptr;
char *rdptr;
int  rlen;

int  Sleep  = 0;

fd_set InputMask;
fd_set OutputMask;
fd_set RselectMask;
fd_set WselectMask;

void sigisr();

main (argc, argv)
int argc;
char *argv[];
{
  int argi = argc;
  int i1;
  int status;

  while (--argi){
          if (strncmp(argv[argi], "debug=", 6) == 0) {
              i1 = 6;
              MY_debug = atoi(&argv[argi][i1]);
          }
          if (strncmp(argv[argi], "slen=", 5) == 0) {
              i1 = 5;
              Outlen = atoi (&argv[argi][i1]);
          }
          if (strncmp(argv[argi], "tcpslen=", 8) == 0) {
              i1 = 8;
              TcpSendBufLen = atoi (&argv[argi][i1]);
          }
          if (strncmp(argv[argi], "tcprlen=", 8) == 0) {
              i1 = 8;
              TcpRecvBufLen = atoi (&argv[argi][i1]);
          }
          if (strncmp(argv[argi], "port=", 5) == 0) {
              i1 = 5;
              MY_port = (u_short) atoi (&argv[argi][i1]);
          }
          if (strncmp(argv[argi], "sleep=", 6) == 0) {
              i1 = 6;
              Sleep = atoi (&argv[argi][i1]);
          }
          if (strncmp(argv[argi], "host=", 5) == 0) {
              i1 = 5;
              strcpy (Host, &argv[argi][i1]);
          }
          if (strncmp(argv[argi], "clnosend", 8) == 0) {
              ClientDoSend = 0;
          }
          if (strncmp(argv[argi], "server", 6) == 0) {
              Serverflag = 1;
          }

  }
  if (MY_debug) {
     printf ("TCP-Port = %hd \n", MY_port);
     printf ("Host     = %s \n", Host);
     printf ("Outlen   = %d \n", Outlen);
  }

  Outbuff = (char *) malloc (Outlen);
  Inbuff  = (char *) malloc (Outlen);

  *(u_long *)Outbuff = HEAD_ID;

  dlen = Outlen;
  dptr = Outbuff;

  rdptr = Inbuff;
  rlen = 0;

  signal (SIGPIPE, sigisr);

  FD_ZERO (&InputMask);
  FD_ZERO (&OutputMask);

  if (Serverflag) {
      Li_socket = TCP_server_create (MY_port);
      if (Li_socket < 0) {
          exit (1);
      }
      FD_SET (Li_socket, &InputMask);
  }
  else {
      Cl_socket = TCP_client_create (MY_port);
      if (Cl_socket < 0) {
          exit (1);
      }
      status = TCP_connect (Host, MY_port, Cl_socket);
      if (status)
          exit (1);
      if (fcntl (Cl_socket, F_SETFL, O_NDELAY)) {
          fprintf (stderr, "set O_NDELAY failed with errno = %d\n", errno);
          exit (1);
      }
      FD_SET (Cl_socket, &InputMask);
      if (ClientDoSend)
          FD_SET (Cl_socket, &OutputMask);
  }

  do_select();

  exit(0);

}

do_select()
{
  int nfound, sock;

  while (1) {

      RselectMask = InputMask;
      WselectMask = OutputMask;
      errno = 0;
      nfound=select (MAXFD, &RselectMask, &WselectMask, NULL, NULL);

      if (nfound <= 0) {
          printf ("nfound = %d errno = %d\n", nfound, errno);
          return;
      }
      if (errno == EINTR) continue;

      while ((sock = fd_ffs(&RselectMask)) > 0)
      {
        serv_read (sock);
        FD_CLR (sock, &RselectMask);    /* reset socket no. from read mask */
      }
      while ((sock = fd_ffs(&WselectMask)) > 0)
      {
        serv_write (sock);
        FD_CLR (sock, &WselectMask);    /* reset socket no. from read mask */
        sleep (Sleep);
      }
  }

}

serv_read(iosock)
int iosock;
{
  int len;
  int newsock;
  int fini = 0;

  if (iosock == Li_socket) {
      /* new connection */
      newsock = TCP_accept (Li_socket);

      if (newsock) {
          FD_SET(newsock, &InputMask);
          FD_SET(newsock, &OutputMask);
          if (fcntl (newsock, F_SETFL, O_NDELAY)) {
              fprintf (stderr, "servio: O_NDELAY failed errno = %d\n", errno);
          }
      }
      return;
  }

  while (!fini) {
      errno = 0;
      len = read (iosock , rdptr, Outlen - rlen);

      if (len > 0) {
          printf ("receive len = %d headid = %lx \n", len, *(u_long *)Inbuff);
          rlen += len;
          rdptr += len;
          if (rlen == Outlen) {
              printf ("we got everything - rlen = %d\n", rlen);
              rlen = 0; fini = 1;
              rdptr = Inbuff;
              if ( *(u_long *)Inbuff != HEAD_ID) {
                  printf ("got corrupted message Header\n");
              }
              else {
                  printf ("header OK %lx \n", *(u_long *)Inbuff);
                  *(u_long *)Inbuff = 0L;
              }
          }
      }
      else if (len == 0 ||
               ((errno != 0)           &&
                (errno != EWOULDBLOCK) &&
                (errno != EINTR))) {
                printf ("read len = %d errno = %d\n", len, errno);
#ifdef SORIX
                so_close (iosock);
#else
                close (iosock);
#endif
                FD_CLR (iosock, &InputMask);
                return;
      }

      if (errno == EWOULDBLOCK) {
          printf ("read would block \n");
          return;
      }
   }

}  

serv_write (iosock)
int iosock;
{
  int len, status;
  int loopcount = 0;
  int i;

      errno = 0;
      do{
          if (errno) printf ("errno = %d\n");
          len = write (iosock, dptr, dlen);
      }while ((len == -1) && (errno == EINTR));

      switch (len) {
          case 0:
              printf ("send len = 0\n");
              FD_CLR (iosock, &OutputMask);
              exit (0);
          case -1:
              if (errno == EWOULDBLOCK) {
                  printf ("send would block dlen = %d\n", dlen);
                  break;
              }
              else {
                  printf ("len = -1 errno = %d\n", errno);
                  break ;
              }
              break;
          default:
              if (len == dlen) {
                  printf ("      <<<< everything sent - len = %d  >>>>\n", len);
                  dlen = Outlen;
                  dptr = Outbuff;
              }
              else {
                  printf ("more to send - len = %d dlen = %d\n", len, dlen);
                  dlen -= len;
                  dptr += len;
              }
              break;
      }

}

TCP_server_create (port)
u_short port;
{

  int li_socket;
  struct sockaddr_in sin;
  int on;
  int i;

  memset ((char *)&sin,0, sizeof(sin));  /* init sin with 0 */

  sin.sin_addr.s_addr = htonl(INADDR_ANY);
  sin.sin_family      = AF_INET;
  sin.sin_port        = htons(port);

  /* get socket */

  li_socket = socket (AF_INET, SOCK_STREAM, 0);
  if (li_socket < 0) {
      fprintf (stderr, "TCP socket failed errno = %d\n", errno);
      return -1;
  }
  on = 1;

  setsockopt (li_socket, SOL_SOCKET, SO_KEEPALIVE, (char *) &on,
              sizeof (on));
  setsockopt (li_socket, SOL_SOCKET, SO_LINGER,
              (char *)Linger, sizeof(Linger));

  /* nessecary for fast restart of server */
  setsockopt (li_socket, SOL_SOCKET, SO_REUSEADDR, (char *) &on,
              sizeof (on));

  /* bind socket */

  i = 20;
  while (bind(li_socket, (struct sockaddr *) &sin, sizeof (sin)))
  {
      if (--i == 0) {
            fprintf (stderr,"Binding TCP socket failed errno = %d\n", errno);
#ifdef SORIX
            so_close (li_socket);
#else
            close (li_socket);
#endif
            return -1;
      }
  }

  /* set socket to "no wait" */
  if (fcntl (li_socket, F_SETFL, O_NDELAY)) {
      fprintf (stderr, "set O_NDELAY failed with errno = %d\n", errno);
  }

  /* listen */
  if (listen (li_socket, 5)) {
      fprintf (stderr,"TCP Listen failed errno = %d\n", errno);
#ifdef SORIX
      so_close (li_socket);
#else
      close (li_socket);
#endif
      return -1;
  }

  return (li_socket);

}

TCP_client_create (port)
u_short port;
{
  int err;
  int cl_socket;
  int on;

  /* get socket */

  cl_socket = socket (AF_INET, SOCK_STREAM, 0);
  if (cl_socket < 0) {
      fprintf (stderr, "TCP socket failed errno = %d\n", errno);
      return -1;
  }

  on = 1;

  setsockopt (cl_socket, SOL_SOCKET, SO_KEEPALIVE, (char *) &on,
              sizeof (on));
  setsockopt (cl_socket, SOL_SOCKET, SO_LINGER,
              (char *)Linger, sizeof(Linger));

  /* nessecary for fast restart of server */
  setsockopt (cl_socket, SOL_SOCKET, SO_REUSEADDR, (char *) &on,
              sizeof (on));

  if (TcpSendBufLen) {
    on = TcpSendBufLen;

    err = setsockopt (cl_socket, SOL_SOCKET, SO_SNDBUF,
                     (char *) &on, sizeof (on));
    if (err) {
        fprintf (stderr, "set SO_SNDBUF failed with errno = %d\n", errno);
    }
  }

  if (TcpRecvBufLen) {
    on = TcpRecvBufLen;
    err = setsockopt (cl_socket, SOL_SOCKET, SO_RCVBUF,
                     (char *) &on, sizeof (on));
    if (err) {
        fprintf (stderr, "set SO_RCVBUF failed with errno = %d\n", errno);
    }
  }

  return (cl_socket);

}

get_myinet_addr (inet)
long *inet;
{
  char   name[34];

  struct hostent   *host_ptr,
                   *gethostbyname();

  if ( gethostname ( name, 34 ) == -1 ) {
      return (-1);
  }

  if (( host_ptr = gethostbyname ( name )) != (struct hostent *) 0 ) {
      *inet = *((long *) host_ptr->h_addr);
      return (0);
  }
  else {
    return (-1);
  }

}

TCP_connect (host, port, sock)
char    *host;
u_short port;
int     sock;
{
    struct sockaddr_in sin;
    struct hostent *hp;
    int    i, servlen;

    memset((char *)&sin,0,sizeof(sin));

    hp = gethostbyname (host);
    if (hp == NULL) {
       fprintf (stderr, "%s: unknown host\n", host);
       return (-1);
    }

    memcpy ((char *)&sin.sin_addr, hp->h_addr, hp->h_length);
    sin.sin_family      = AF_INET;
    sin.sin_port        = htons(port);

    servlen = sizeof (sin);

    if (connect(sock, (struct sockaddr *)&sin, servlen) < 0 ) {
        fprintf (stderr, "connect error: errno = %d\n", errno);
        return (-1);
    }

    return (0);

}

TCP_accept (sock)
int sock;
{
  struct sockaddr_in from;
  int    fromlen;
  int    err, opt;

  int newsock;

  fromlen = sizeof (struct sockaddr_in);
  newsock = accept(sock, (struct sockaddr *)&from, &fromlen);

  if (newsock) {
      if (TcpSendBufLen) {
        opt = TcpSendBufLen;
        err = setsockopt (newsock, SOL_SOCKET, SO_SNDBUF,
                         (char *) &opt, sizeof (opt));
        if (err) {
            fprintf (stderr, "set SO_SNDBUF in TCP_accept failed with errno = %d\n", errno);
        }
      }
      if (TcpRecvBufLen) {
        opt = TcpRecvBufLen;
        err = setsockopt (newsock, SOL_SOCKET, SO_RCVBUF,
                         (char *) &opt, sizeof (opt));
        if (err) {
            fprintf (stderr, "set SO_RCVBUF in TCP_accept failed with errno = %d\n", errno);
        }
      }
  }

  return (newsock);

}

#define ANYSET(p) ((p)->fds_bits[0] || (p)->fds_bits[1] || \
                   (p)->fds_bits[2] || (p)->fds_bits[3])

/*fg*****************************************************************
 *   fd_ffs                                                         *
 ********************************************************************/

/*******************************************************************
   *
   * Author     :  F. Lange, Philips UB EWI Kassel, Dep. PAE
   *
   * Purpose    :  Find the first bit set in the bitmap passed
   *               and returns the index of that bit.
   *               Returns -1 if no bit found.
   *
   * History    :
   *
   */

int fd_ffs (blkmsk)
fd_set *blkmsk;
/*
end*/
{
    int bit, j;

    if (!(ANYSET(blkmsk)))
        return (0);

    j=bit=0;

    while ((bit == 0) && (j <MAXFD)) {
        if (FD_ISSET (j, blkmsk))
            bit = j;
        else
            j++;
    }
    if (bit)
        return (bit);
    else
        return (-1);   /* no free entry */

}

void sigisr(sig)
int sig;
{
  printf ("got SIGPIPE signal\n");
exit (1);
  signal (sig, SIG_IGN);

}

--------------4BA539A9338E9DD41688A0DF--
 
 
 

1. select() doesn't return on socket descriptor

Has anyone else had the problem of select() not returning for a
socket descriptor in the fd_set ?  It works fine on Solaris and IRIX,
but not on Linux.

Here is a code snipit.  If you see an obvious problem , let me know.
Thanks!

  sd = advertizeself(lan_name);

  if(listen(sd, 5) < 0) {
    perror("listen");
    exit(1);
  }

  /* setup for multiplexed I/O  */
  FD_ZERO(&readset);

  while (1) {
    FD_SET(sd, &readset);
    for (i = 0; i < sd_count; i++) FD_SET(sd_list[i], &readset);

    nready = select(FD_SETSIZE, &readset, NULL, NULL, NULL);

      if (FD_ISSET(sd, &readset)) {
         /* connect request */
         if ((new_sd = attachhost(sd)) < 0) {
            printf("\tNo free ports: connection request denied.\n\n");
         } else {
           printf("\tAccepted connection.\n\n");
            sd_list[sd_count] = new_sd;
            sd_count++;
         }
      } else {
         for (i = 0; i < sd_count; i++) {
            if (FD_ISSET(sd_list[i], &readset)) {
               /* read request */
               pkt = recvpkt( sd_list[i] );
               /* relay request / broadcast packet */
               /* this part isn't finished yet
            }
         }
      }
   }

--

--

Systems Staff, CSci Dept
University of Minnesota         URL:    http://www.cs.umn.edu/~bentlema/

2. ppp event over pf_netlink (simulation)

3. Selecting between sockets & memory

4. PPP->Kernel compile problem

5. HELP!Blocking select times out on a valid socket!

6. directories

7. select seems to hang on a tcp socket

8. Locales not loading at startup...

9. Select in non-blocking sockets

10. a basic problem about socket and select

11. Why does Sockets select() block ???

12. Q: select() returns upon socket connection, or STDIN, but not both

13. select(), getsockopt(), and bsd sockets.