Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 31 Jul 2011 11:50:27 +0200
From:      "Christoph P.U. Kukulies" <kuku@kukulies.org>
To:        "freebsd-questions@freebsd.org" <freebsd-questions@freebsd.org>
Subject:   invalid argument in select() when peer socket is in FD_SET
Message-ID:  <4E352563.2070808@kukulies.org>

Next in thread | Raw E-Mail | Index | Archive | Help
I have written a  small to test TCP/IP roundtrip times of the packets in 
a proprietary protocol and while
compiling and running this server on different platforms (Windows 
7/cygwin, UbuntuLinux, FreeBSD 8.0 Release), I found
that the server produces an error when the listening socket (on which 
the accpet() is performed) is member of the select()
fd_set.

On the other platforms the program works without error, just under 
FreeBSD I'm getting this "invalid argument" error.

Comments appreciated (despite comments about the error checking logic :)

Here is the code:
// testsrv.c
//  gcc -o testsrv testsrv.c
//

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>

#include <sys/select.h>

#define USEDBUFSIZ 60
#define MAX_HOSTNAME 256
#define MAXFDS 256
#define CLRBUF  memset(buf,0,sizeof(buf))
#define max(a,b)        (((a) > (b)) ? (a) : (b))
static unsigned char buf[256];
int             array_of_fds[MAXFDS];
static fd_set   clientfds;
#define SOCKET int
void           *memset(void *, int, size_t);
int             enter      (int);
int             remov      (int);
int             invalidip  (char *);
void            exit      (int);
int             getv       (int, unsigned char *, int);
int             getfds     ();

int
main(int argc, char **argv)
{
     int             nfds;
     static fd_set   readfds;
     SOCKET          ListenSocket, newsockfd;
     struct sockaddr_in cli_addr;
     struct sockaddr_in service;
     struct hostent *thisHost;
     int             bOptVal = 0;
     int             bOptLen = sizeof(int);
     char            hostname[256];
     char           *host_addr;
     struct in_addr  addr = {0};
     char           *ip;
     u_short         port;
     int             iResult = 0;
     int             i     , n, m, clilen, dummy, connect = 0;
     struct timeval  tv;
     //---------------------------------------
         //Create a listening socket
         ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     if (ListenSocket == -1) {
         perror("socket creation");
         return 1;
     } else
         printf("ListenSocket=%d\n", ListenSocket);
     //---------------------------------------
         //Bind the socket to the local IP address
         // and port 3210
         port = 3210;
     if (gethostname(hostname, 256))
         perror("gethostname failed\n"), exit(3);
     printf("%s\n", hostname), fflush(stdout);
     thisHost = gethostbyname(hostname);
     ip = inet_ntoa(*(struct in_addr *)(*thisHost->h_addr_list));


     if (argc == 2) {
         host_addr = argv[1];
         service.sin_addr.s_addr = inet_addr(host_addr);
         thisHost = gethostbyaddr((const char *)&service.sin_addr.s_addr,
                                  sizeof(service.sin_addr.s_addr), AF_INET);
         if (thisHost == 0)
             printf("host unknown\n"), exit(3);
         if (invalidip(host_addr))
             printf("invalid IP\n"), exit(4);
     } else {
         service.sin_addr.s_addr = inet_addr(ip);
     }
     service.sin_port = htons(port);
     service.sin_family = AF_INET;

     iResult = bind(ListenSocket, (struct sockaddr *)&service, 
sizeof(service));
     if (iResult == -1) {
         perror("bind");
         shutdown(ListenSocket, SHUT_RDWR);
         return 1;
     }
     listen(ListenSocket, SOMAXCONN);
     printf("SOMAXCONN=%d %d\n", SOMAXCONN, FD_SETSIZE);
     /* all sockets are put into an own array_of_fs */
     /* in the while() loop below the FD_SET id used by looping through 
the */
     /* array_of_fds to fill the readfds array in the select() */

     enter(ListenSocket);

     /*
      * Wait for connect
      */
     tv.tv_sec = 0;
     tv.tv_usec = 5000000;       /* 5 seconds */

     printf("Server %s listening on port %d\n", thisHost->h_name, port);
     memset((void *)array_of_fds, 0, (size_t) MAXFDS * 
sizeof(*array_of_fds));
     nfds = ListenSocket + 1;
     while (1) {
         FD_ZERO(&readfds);
         FD_SET(ListenSocket, &readfds);
         for (i = 0; i < MAXFDS; i++) {
             if (array_of_fds[i]) {
                 nfds = max(nfds, array_of_fds[i]) + 1;
                 FD_SET(array_of_fds[i], &readfds);
             }
         }
         n = select(nfds, &readfds,
                    (fd_set *) NULL,     /* not interested in write */
                    (fd_set *) NULL,     /* ...or exceptions */
&tv);        /* timeout */

         switch (n) {

         case 1:
             clilen = sizeof(cli_addr);
             /* first test if a new client has connected */
             if (FD_ISSET(ListenSocket, &readfds)) {
                 newsockfd = accept(ListenSocket,
                             (struct sockaddr *)&cli_addr, &clilen);
                 if (enter(newsockfd)) /* socket of new connection is 
entered*/
                     printf("\n%d.connect! ", ++connect), fflush(stdout);
                 else
                     printf("too many connections"), exit(1);
                 sprintf(buf, "ENTERED %d of %d", 1, 10);
                 send(newsockfd, buf, USEDBUFSIZ, 0); /* send to the 
client*/
             } else {

                 for (i = 0; i < MAXFDS; i++) {
                     int             s;
                     if (FD_ISSET((s = array_of_fds[i]), &readfds)) {

                         m = getv(s, buf, USEDBUFSIZ);
                         if (m <= 0) {
                             shutdown(s, SHUT_RDWR);
                             if (remov(s) == -1)
                                 printf("error on remove(s)\n", s), 
fflush(stdout
);
                             goto done;
                         } else {
                             printf("*");
                             fflush(stdout);

                             CLRBUF;
                             /* now send some data to the client */
                             sprintf(buf, "XX-123456789-XX-xx       : 
0x0600, 0x9
9999999, \"NNNNN\"");
                             m = send(s, buf, USEDBUFSIZ, 0);
                             if (m < 0 || m != USEDBUFSIZ) {
                                 perror("cannot send\n");
                             }
                             CLRBUF;
                             sprintf(buf, "END");
                             m = send(s, buf, USEDBUFSIZ, 0);
                             if (m < 0 || m != USEDBUFSIZ) {
                                 perror("cannot send\n");
                             }
                         }       /* else */
                     }           /* if FD_ISSET */
                 }               /* for */
                 break;

         case 0:
                 break;

         case -1:
                 perror("select");
                 exit(2);

         default:
                 printf("more than one descriptor ready!\n");
                 fflush(stdout);
                 exit(4);
                 break;
             }                   /* switch */
         }                       /* while */

     }

done:
     shutdown(ListenSocket, SHUT_RDWR);
     return 0;

}                               /* main */
int
getv(int fd, unsigned char *buf, int count)
{
     int             m     , got = 0;
     int             i = 0;
     while (got < count) {
         m = recv(fd, buf + got, count - got, 0);
         if (m == count)
             return m;
         if (m > 0)
             got = got + m;
         if (m == 0)
             return (0);
         if (m < 0) {
             return -1;
         }
     }
     return -1;
}
int
enter(int i)
{
     int             k = 0;
     while (array_of_fds[k++]);

     if (k > MAXFDS - 1)
         return -1;
     k--;
     array_of_fds[k] = i;
     return i;
}

int
remov(s)
{
     int             k;
     for (k = 0; k < MAXFDS; k++)
         if (array_of_fds[k] == s) {
             array_of_fds[k] = 0;
             return k;
         }
     return -1;
}

/*
  * this code taken from code for validating IPv4 address taken from article
  * in http://bytes.com/topic/c/answers/212174-code-validating-ipv4-address
  */
#define INVALID -1
#define VALID 0


int
invalidip(char *ipadd)
{
     unsigned        b1, b2, b3, b4;
     unsigned char   c;
     if (sscanf(ipadd, "%3u.%3u.%3u.%3u%c", &b1, &b2, &b3, &b4, &c) != 4)
         return INVALID;

     if ((b1 | b2 | b3 | b4) > 255)
         return INVALID;
     if (strspn(ipadd, "0123456789.") < strlen(ipadd))
         return INVALID;

     return VALID;
}





Want to link to this message? Use this URL: <http://docs.FreeBSD.org/cgi/mid.cgi?4E352563.2070808>