From: Fabian Keil Date: Tue, 19 May 2009 17:18:52 +0000 (+0000) Subject: In connect_to(), try multiple addresses if possible and necessary. X-Git-Tag: v_3_0_13~92 X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=commitdiff_plain;h=38be442c986a8399271ae0a5101f734d1936e842 In connect_to(), try multiple addresses if possible and necessary. Closes #2790891. Problem reported and patch provided by Petr Pisar. --- diff --git a/jbsockets.c b/jbsockets.c index d6e55d46..19303ee5 100644 --- a/jbsockets.c +++ b/jbsockets.c @@ -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);