Mail Archives: cygwin/2003/06/06/17:25:35
--------------090005080803070301010304
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit
It looks like poll() is implemented on top of select() in cygwin.
This is fine unless you try to use it in a program with
more than 1024 fd's or so. Here's the result of running a test app
that goes beyond that limit:
Program received signal SIGSEGV, Segmentation fault.
0x6106fe3a in select () from /usr/bin/cygwin1.dll
(gdb) bt
#0 0x6106fe3a in select () from /usr/bin/cygwin1.dll
#1 0x61610790 in ?? ()
#2 0x6106ca1d in select () from /usr/bin/cygwin1.dll
#3 0x6106c223 in select () from /usr/bin/cygwin1.dll
#4 0x61059e7d in poll () from /usr/bin/cygwin1.dll
#5 0x004012d3 in count_connects (ipadr=16777343, portnum=80, want=1200) at pollbug.c:120
#6 0x0040175d in main (argc=2, argv=0xa0418c8) at pollbug.c:211
And here's the test code. To reproduce the bug, just run with argument 1500 or so.
- Dan
--------------090005080803070301010304
Content-Type: text/x-csrc;
name="pollbug.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="pollbug.c"
/*--------------------------------------------------------------------------
Copyright 1999,2000, Dan Kegel http://www.kegel.com/
See the file COPYING
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------
Program to measure limits on network sockets, file descriptors, etc.
--------------------------------------------------------------------------*/
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/resource.h>
#include <time.h>
#include <unistd.h>
#ifndef AF_LOCAL
#define AF_LOCAL AF_UNIX
#endif
#define MAX_TEST 100000
int fds[MAX_TEST];
/*----------------------------------------------------------------------
Portable function to set a socket into nonblocking mode.
----------------------------------------------------------------------*/
static int setNonblocking(int fd)
{
int flags;
/* Caution: O_NONBLOCK is defined but broken on SunOS 4.1.x and AIX 3.2.5. */
#if defined(O_NONBLOCK)
if (-1 == (flags = fcntl(fd, F_GETFL, 0)))
flags = 0;
return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
#else
flags = 1;
return ioctl(fd, FIOBIO, &flags);
#endif
}
static int count_connects(int ipadr, int portnum, int want)
{
int i;
int maxfd;
int nopen;
struct pollfd pfds[MAX_TEST];
int nok;
int nrej;
time_t end;
#ifdef VERBOSE
printf("Starting connections until we can't start any more; will print what stops us to stderr.\n");
#endif
for (i = 0; i < want; i++) {
struct sockaddr_in srv_addr;
int err;
fds[i] = socket(AF_INET, SOCK_STREAM, 0);
if (fds[i] < 0) {
#ifdef VERBOSE
perror("socket");
#endif
break;
}
setNonblocking(fds[i]); /* else connect will wait until resources avail */
memset((char *) &srv_addr, 0, sizeof(srv_addr));
srv_addr.sin_family = AF_INET;
srv_addr.sin_addr.s_addr = ipadr;
srv_addr.sin_port = htons(portnum);
err = connect(fds[i], (struct sockaddr *) &srv_addr, sizeof(srv_addr));
if ((err != 0) && (errno != EINPROGRESS)) {
#ifdef VERBOSE
perror("connect");
#endif
break;
}
pfds[i].fd = fds[i];
pfds[i].events = POLLOUT;
}
maxfd = i;
#ifdef VERBOSE
printf("%d connections in progress...\n", maxfd);
#endif
/* Now sit until they all connect or fail, or until five seconds
* pass, whichever comes first.
*/
end = time(0) + 6;
for (nrej=nok=0, nopen=maxfd; nopen; ) {
int nready;
if ((end - time(0)) < 0)
break;
nready = poll(pfds, maxfd, 1000);
if (nready < 0) {
perror("poll");
exit(1);
}
for (i=0; i<maxfd; i++) {
if ((pfds[i].fd == -1) || !pfds[i].revents)
continue;
/* question: if a connect fails, will it show up first
* as a POLLERR, POLLHUP, or POLLOUT?
*/
if (pfds[i].revents & (POLLHUP|POLLERR)) {
/* connect failed? */
close(pfds[i].fd);
nrej++;
} else if (pfds[i].revents & POLLOUT) {
/* check to see if connect succeeded */
int connecterr = -1;
socklen_t len = sizeof(connecterr);
if (getsockopt(pfds[i].fd, SOL_SOCKET, SO_ERROR, (char *)&connecterr, &len) < 0) {
perror("getsockopt");
exit(1);
}
if (!connecterr) {
nok++;
/* keep socket open */
} else if (connecterr == ECONNREFUSED) {
close(pfds[i].fd);
nrej++;
}
} else {
printf("bad poll result: pfds[%d].fd %d, .revents %x\n", i, pfds[i].fd, pfds[i].revents);
exit(1);
}
pfds[i].fd = -1;
nopen--;
}
}
/* Close 'em (might close a few extra, but that's ok) */
for (i = 0; i < maxfd; i++)
close(fds[i]);
#ifdef VERBOSE
printf("%d connections accepted, %d rejected, %d pending\n", nok, nrej, nopen);
#endif
return nok + nrej + nopen;
}
int main(int argc, char **argv)
{
const char *ipadrstr;
int ipadr;
int portnum;
int want;
if (argc < 2) {
printf("Usage: %s num_wanted [ipadr portnum]\n\
Tries to open the specified number of sockets in various ways.\n\
", argv[0]);
exit(1);
}
want = atoi(argv[1]);
if (want < 1 || want > MAX_TEST) {
printf("Sorry, want must be between 1 and %d\n", MAX_TEST);
exit(1);
}
if (argc < 3)
ipadrstr = "127.0.0.1";
else
ipadrstr = argv[2];
ipadr = inet_addr(ipadrstr);
if (ipadr == -1) {
printf("Bad ip address %s.\n", ipadrstr);
exit(1);
}
if (argc < 4)
portnum = 80;
else {
const char *portnumstr;
portnumstr = argv[3];
portnum = atoi(portnumstr);
if ((portnum <= 0) || (portnum > 65535)) {
printf("Bad port number '%s'. Must be number between 1 and 65535.\n", portnumstr);
exit(1);
}
}
printf("Can start %d nonblocking connect()'s\n", count_connects(ipadr, portnum, want));
return 0;
}
--------------090005080803070301010304
Content-Type: text/plain; charset=us-ascii
--
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
Problem reports: http://cygwin.com/problems.html
Documentation: http://cygwin.com/docs.html
FAQ: http://cygwin.com/faq/
--------------090005080803070301010304--
- Raw text -