Mail Archives: cygwin/2014/04/23/10:26:03
X-Recipient: | archive-cygwin AT delorie DOT com
|
DomainKey-Signature: | a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id
|
| :list-unsubscribe:list-subscribe:list-archive:list-post
|
| :list-help:sender:content-type:date:from:message-id:mime-version
|
| :subject:to:content-transfer-encoding; q=dns; s=default; b=pewHx
|
| w7+jalZGlYG11qsc0hOw4njEGIpmLGdzedT7V2UO42nMTkHjUgL3M135AAwWLqTG
|
| ipmJSnlINXOv9snQdgndzXv49KaWnYzJH0nUu3H1ypklg4wgpXrq6z4LIqpgBe4b
|
| hJe03Kf+1vzrIWM6BsRWQD2M/iGIvGB2XlQu88=
|
DKIM-Signature: | v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id
|
| :list-unsubscribe:list-subscribe:list-archive:list-post
|
| :list-help:sender:content-type:date:from:message-id:mime-version
|
| :subject:to:content-transfer-encoding; s=default; bh=lbg1DkzOl2k
|
| nQznjW6y9hGmppU0=; b=GXmaSeoQfTW/SQ+zhHz+yIBd5mJjVzKgmLMo17wXSLg
|
| Qz+CnLRXCXD5o6tFEkCN6bx8lDlAKiQTI6BkY6shvEy1u/edULrWU7WvyCuVHdhf
|
| Sh94TR0YcmjBr2j/gvYxVbpoc3io9YyiH5gNOY678vS+e5lwTZW5eZWhvUImeqag
|
| =
|
Mailing-List: | contact cygwin-help AT cygwin DOT com; run by ezmlm
|
List-Id: | <cygwin.cygwin.com>
|
List-Subscribe: | <mailto:cygwin-subscribe AT cygwin DOT com>
|
List-Archive: | <http://sourceware.org/ml/cygwin/>
|
List-Post: | <mailto:cygwin AT cygwin DOT com>
|
List-Help: | <mailto:cygwin-help AT cygwin DOT com>, <http://sourceware.org/ml/#faqs>
|
Sender: | cygwin-owner AT cygwin DOT com
|
Mail-Followup-To: | cygwin AT cygwin DOT com
|
Delivered-To: | mailing list cygwin AT cygwin DOT com
|
Authentication-Results: | sourceware.org; auth=none
|
X-Virus-Found: | No
|
X-Spam-SWARE-Status: | No, score=0.7 required=5.0 tests=AWL,BAYES_40,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM,RCVD_IN_DNSWL_NONE,SPF_PASS autolearn=no version=3.3.2
|
X-HELO: | mout.gmx.net
|
Date: | Wed, 23 Apr 2014 16:25:40 +0200
|
From: | "qq qq" <miska0000 AT gmx DOT com>
|
Message-ID: | <20140423142541.156360@gmx.com>
|
MIME-Version: | 1.0
|
Subject: | Dup'd sockets lose error information
|
To: | cygwin AT cygwin DOT com
|
x-registered: | 0
|
The following code is a simplified app that was used to test-connect to local ports 55000+ (none of which were actually listening) and received false-positive "connected" results because Cygwin's dup()
for socket causes SO_ERROR to be lost. Â Since FD_SETSIZE is only 64 on Cygwin, the app uses dup()'s to lower the descriptors as it checks them for completion. Â There is no such problem on Linux.
Also, strangely that Cygwin does not accept sin_addr as 0 to connect locally (and either localhost or local host IP must be stuffed in there, otherwise resulting in the "Cannot assign requested address" error).
$ cat connect.c
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>
#ifndef MAX_SOCK
#define MAX_SOCK 100
#endif
#ifdef LINUX
#undef  FD_SETSIZE
#define FD_SETSIZE 16
#endif
int main()
{
 static struct {
   struct sockaddr_in sin;
   int         sock;
 } s[MAX_SOCK];
 int i;
Â
 for (i = 0;  i < MAX_SOCK;  ++i) {
   s[i].sock = socket(AF_INET, SOCK_STREAM, 0);
   fcntl(s[i].sock, F_SETFL, O_NONBLOCK);
   memset(&s[i].sin, 0, sizeof(s[i].sin));
   s[i].sin.sin_family = AF_INET;
#ifdef BUG2
   s[i].sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
#endif
   s[i].sin.sin_port = htons(55000 + i);
   connect(s[i].sock, (struct sockaddr*) &s[i].sin, sizeof(s[i].sin));
   printf("connecting #%d(%d) to :%hu\n", i, s[i].sock, ntohs(s[i].sin.sin_port));
 }
 for (;;) {
   fd_set wfds, efds;
   int m = 0, v = 0;
   for (i = 0;  i < MAX_SOCK;  ++i) {
     if (s[i].sock < 0)
       continue;
     if (s[i].sock >= FD_SETSIZE) {
       int fd = dup(s[i].sock);
       if (fd < 0)
         continue;
       if (fd >= FD_SETSIZE) {
         close(fd);
         continue;
       }
       close(s[i].sock);
       printf("%d -> %d\n", s[i].sock, fd);
       s[i].sock = fd;
     }
     if (!m) {
       FD_ZERO(&wfds);
       FD_ZERO(&efds);
     }
    Â
     FD_SET(s[i].sock, &wfds);
     FD_SET(s[i].sock, &efds);
     ++m;
     if (v < s[i].sock)
       v = s[i].sock;
   }
   if (!m)
     break;
   if (select(v + 1, 0, &wfds, &efds, 0) < 0) {
     perror("select");
     return 1;
   }
   for (i = 0;  i < MAX_SOCK;  ++i) {
     int err;
     socklen_t len;
    Â
     if (s[i].sock < 0  ||  FD_SETSIZE <= s[i].sock)
       continue;
      Â
     if (FD_ISSET(s[i].sock, &efds))
       v = 1;
     else if (FD_ISSET(s[i].sock, &wfds))
       v = 0;
     else
       continue;
      Â
     len = sizeof(err);
     if (getsockopt(s[i].sock, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
       perror("getsockopt");
       return 1;
     }
     if (!err)
       printf("#%d connected to :%hu%s\n", i, ntohs(s[i].sin.sin_port), v ? " w/exception" : "!");
     else
       printf("#%d to :%hu: %s\n", i, ntohs(s[i].sin.sin_port), strerror(err));
     close(s[i].sock);
     s[i].sock = -1;
   }
 }
 return 0;
}
Linux:
$ gcc -Wall -DLINUX connect.c
$ ./a.out
(shows all connection refused with or without -DBUG2 given to the compiler)
Cygwin:
$ gcc -Wall -DBUG2 connect.c
$ ./a.exe
(only shows "connection refused" for fds less than FD_SETSIZE==64, others will be "successfully connected")
$ gcc -Wall connect.c
(shows "cannot assign requested address" errors for fds < 64, all others "successfully connected")
Keep in mind the socket fds are offset by 3 open descriptors used by stdio.
Setting MAX_SOCK to 2 and FD_SETSIZE to 1 on Cygwin clearly shows that it's the dup() call that messes up the socket error state:
the first socket will get the proper "connection refused", and the other -- will be erroneously reported back as "connected" (no error returned).
--
Problem reports: http://cygwin.com/problems.html
FAQ: http://cygwin.com/faq/
Documentation: http://cygwin.com/docs.html
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
- Raw text -