From owner-freebsd-questions@FreeBSD.ORG Sun Jul 31 10:07:37 2011 Return-Path: Delivered-To: freebsd-questions@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 3CF85106566B for ; Sun, 31 Jul 2011 10:07:37 +0000 (UTC) (envelope-from kuku@kukulies.org) Received: from kukulies.org (mail.kukulies.org [78.47.239.221]) by mx1.freebsd.org (Postfix) with ESMTP id D4B9E8FC12 for ; Sun, 31 Jul 2011 10:07:36 +0000 (UTC) Received: by kukulies.org (Postfix, from userid 5001) id A41B21AC003; Sun, 31 Jul 2011 11:50:38 +0200 (CEST) Received: from [192.168.2.102] (pC19EB8FB.dip.t-dialin.net [193.158.184.251]) by kukulies.org (Postfix) with ESMTPSA id B58791AC002 for ; Sun, 31 Jul 2011 11:50:35 +0200 (CEST) Message-ID: <4E352563.2070808@kukulies.org> Date: Sun, 31 Jul 2011 11:50:27 +0200 From: "Christoph P.U. Kukulies" User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:5.0) Gecko/20110624 Thunderbird/5.0 MIME-Version: 1.0 To: "freebsd-questions@freebsd.org" Content-Type: text/plain; charset=ISO-8859-15; format=flowed Content-Transfer-Encoding: 7bit Subject: invalid argument in select() when peer socket is in FD_SET X-BeenThere: freebsd-questions@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: User questions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 31 Jul 2011 10:07:37 -0000 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 #include #include #include #include #include #include #include #include #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; }