delorie.com/archives/browse.cgi   search  
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 -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019