From: newsham AT lava DOT net (Tim Newsham) Subject: another socket bug 28 Apr 1998 04:59:07 -0700 Message-ID: Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit To: gnu-win32 AT cygnus DOT com Hi, It looks like another cygwin bug. The following is a test program which behaves incorrectly in cygwin. I ran it in cygwin beta 19.1 as: remote% nc -l -p 3333 cygwin$ ./testcase The program connects from cyginw to remote, then it sequentially tries to connect to a few ports (notice how slow the connection attempts are; winsock seems to be very slow at reacting to RST's after SYN's). After some time a signal handler is invoked which warps the program back out to main. At this point a write to the original connected socket will fail with EINPROGRESS (sometimes. it appears this is a race). This should not happen! My best guess is that the signal handler warped out of the cygwin connect() function and cygwin was left in a weird state in which future operations fail. EINPROGRESS is not even a valid error response for write(). The error can also be observed when sigsetjmp/siglongjmp is not used but socket operations are performed directly from the signal handler. fix: not sure. perhaps some parts of the code need to be protected from interruption by signals. Tim N. ---- test case ---- /* * Connect to REMOTE port 3333 (I use nc -l -p 3333 on remote host for testing) * then attempt to connect to ports on REMOTE until timeout * after TIMEOUT, try to write to REMOTE. * * Error: write() to REMOTE at end (after jumping from signal handler) * results in error with errno = 119 sometimes (EINPROGRESS). This should * not happen. The same thing is observed if the write is done directly * from the signal handler. * * Synopsis: Jumping out of some calls leaves the system in a weird state? */ #include #include #include #include #include #include #include #define REMOTE "10.200.200.3" static sigjmp_buf jmpbuf; static void jumper(int sig) { siglongjmp(jmpbuf, 1); } int connect_sock(int addr, int port) { struct sockaddr_in ad; int s; s = socket(AF_INET, SOCK_STREAM, 0); if(s == -1) { perror("socket"); exit(1); } memset(&ad, 0, sizeof ad); ad.sin_family = AF_INET; ad.sin_addr.s_addr = addr; ad.sin_port = htons(port); if(connect(s, (struct sockaddr *)&ad, sizeof ad) == -1) { close(s); return -1; } return s; } int set_nonblock(int fd, int flag) { return ioctl(fd, FIONBIO, &flag); } int main() { int s, sx, port, addr, res; char c; signal(SIGALRM, jumper); sx = connect_sock(inet_addr("10.200.200.3"), 3333); printf("sx is %d\n", sx); addr = inet_addr("10.200.200.3"); alarm(5); if(sigsetjmp(jmpbuf, 1) == 0) { for(port = 1; port < 40; port++) { printf("try %d\n", port); s = connect_sock(addr, port); if(s == -1) continue; printf("%d connected\n", port); set_nonblock(s, 1); write(s, "test", 4); read(s, &c, 1); close(s); } } else { printf("timeout\n"); } res = write(sx, "test", 4); if(res == -1) printf("error: %s\n", strerror(errno)); else printf("res %d\n", res); return 0; } - For help on using this list (especially unsubscribing), send a message to "gnu-win32-request AT cygnus DOT com" with one line of text: "help".