[distcc] [patch] Fix bug in dcc_connect_by_addr in distcc-2.18.3

Daniel Kegel dank at kegel.com
Tue Oct 4 23:33:39 GMT 2005


dcc_connect_by_addr does not check for the result
of the connect properly.   Once the fd is writable, you
have to retrieve the connect's completion status using getsockopt
SO_ERROR.  I noticed this when I modified lsdistcc to use dcc_connect_by_addr,
and it started returning a much larger list of servers than it should have!
I don't know under what circumstances this bug would have been
triggered in distcc, but it's worth fixing anyway.

The following patch seems to solve the problem.
I'm using the nonblocking connect code in
http://kegel.com/dkftpbench/dkftpbench-0.45/ftp_client_pipe.cc
as an example.

--- distcc-2.18.3/src/clinet.c  2004-11-21 10:36:23.000000000 -0800
+++ distcc-2.18.3.new/src/clinet.c  2005-10-04 16:29:58.000000000 -0700
@@ -87,6 +87,7 @@
      int ret;
      char *s;
      int failed;
+    int connecterr;

      dcc_sockaddr_to_string(sa, salen, &s);

@@ -105,17 +106,39 @@
          failed = connect(fd, sa, salen);
      while (failed == -1 && errno == EINTR);

-    if (failed == -1 && errno != EINPROGRESS) {
-        rs_log(RS_LOG_ERR|RS_LOG_NONAME,
-               "failed to connect to %s: %s", s, strerror(errno));
-        ret = EXIT_CONNECT_FAILED;
-        goto out_failed;
-    }
+    do {
+       socklen_t len;

-    if ((ret = dcc_select_for_write(fd, dcc_connect_timeout))) {
-        rs_log(RS_LOG_ERR|RS_LOG_NONAME,
-               "timeout while connecting to %s", s);
-        goto out_failed;
+       if (failed == -1 && errno != EINPROGRESS) {
+           rs_log(RS_LOG_ERR|RS_LOG_NONAME,
+                  "failed to connect to %s: %s", s, strerror(errno));
+           ret = EXIT_CONNECT_FAILED;
+           goto out_failed;
+       }
+
+       if ((ret = dcc_select_for_write(fd, dcc_connect_timeout))) {
+           rs_log(RS_LOG_ERR|RS_LOG_NONAME,
+                  "timeout while connecting to %s", s);
+           goto out_failed;
+       }
+
+       connecterr = -1;
+       len = sizeof(connecterr);
+       if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *)&connecterr, &len) < 0) {
+               rs_log_error("getsockopt SO_ERROR failed?!");
+               ret = EXIT_CONNECT_FAILED;
+               goto out_failed;
+       }
+
+       /* looping is unlikely, but I believe I needed this in dkftpbench */
+       /* fixme: should reduce timeout on each time around this loop */
+    } while (connecterr == EINPROGRESS);
+
+    if (connecterr) {
+       rs_log(RS_LOG_ERR|RS_LOG_NONAME,
+                "nonblocking connect to %s failed: %s", s, strerror(connecterr));
+       ret = EXIT_CONNECT_FAILED;
+       goto out_failed;
      }

      *p_fd = fd;


More information about the distcc mailing list