In connect_to(), try multiple addresses if possible and necessary.
authorFabian Keil <fk@fabiankeil.de>
Tue, 19 May 2009 17:18:52 +0000 (17:18 +0000)
committerFabian Keil <fk@fabiankeil.de>
Tue, 19 May 2009 17:18:52 +0000 (17:18 +0000)
Closes #2790891. Problem reported and patch provided by Petr Pisar.

jbsockets.c

index d6e55d4..19303ee 100644 (file)
@@ -1,4 +1,4 @@
-const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.55 2009/05/10 10:12:30 fabiankeil Exp $";
+const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.56 2009/05/16 13:27:20 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/jbsockets.c,v $
@@ -222,7 +222,7 @@ jb_socket connect_to(const char *host, int portnum, struct client_state *csp)
       }
 #endif /* def TCP_NODELAY */
 
-#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
+#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) 
       if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
       {
          flags |= O_NDELAY;
@@ -276,13 +276,34 @@ jb_socket connect_to(const char *host, int portnum, struct client_state *csp)
       tv->tv_usec = 0;
 
       /* MS Windows uses int, not SOCKET, for the 1st arg of select(). Wierd! */
-      if (select((int)fd + 1, NULL, &wfds, NULL, tv) <= 0)
+      if (select((int)fd + 1, NULL, &wfds, NULL, tv) > 0 &&
+            FD_ISSET(fd, &wfds))
       {
-         close_socket(fd);
-         continue;
+         /* See Linux connect(2) man page for more info about connecting on
+          * non-blocking socket. */
+         int socket_in_error;
+         socklen_t optlen = sizeof(socket_in_error);
+         if (!getsockopt(fd, SOL_SOCKET, SO_ERROR, &socket_in_error, &optlen))
+         {
+            if (!socket_in_error)
+            {
+               break; /* for; Connection established; don't try other addresses */
+            }
+            log_error(LOG_LEVEL_INFO, "Could not connect to TCP/[%s]:%s: %s",
+                  csp->http->host_ip_addr_str, service,
+                  strerror(socket_in_error));
+         }
+         else
+         {
+            log_error(LOG_LEVEL_ERROR,
+                  "Could not get state of TCP connection to [%s]:%s: %s;"
+                  " dropping connection",
+                  csp->http->host_ip_addr_str, service, strerror(errno));
+         }
       }
 
-      break; /* for; Connection established; don't try other addresses */
+      /* Connection failed, try next address */
+      close_socket(fd);
    }
 
    freeaddrinfo(result);
@@ -292,15 +313,8 @@ jb_socket connect_to(const char *host, int portnum, struct client_state *csp)
          "Could not connect to TCP/[%s]:%s", host, service);
       return(JB_INVALID_SOCKET);
    }
-   /*
-    * XXX: Current connection verification (EINPROGRESS && select()
-    * for writing) is not sufficient. E.g. on Linux-2.6.27 with glibc-2.6
-    * select returns socket ready for writing, however subsequential
-    * write(2) fails with ENOCONNECT. Read Linux connect(2) man page
-    * about non-blocking sockets.
-    * Thus we can't log here that the socket is connected.
-    */
-   /* log_error(LOG_LEVEL_INFO, "Connected to TCP/[%s]:%s", host, service); */
+   log_error(LOG_LEVEL_INFO, "Connected to TCP/%s[%s]:%s", host,
+         csp->http->host_ip_addr_str, service);
 
    return(fd);