on systems that has separate IPv4/v6 socket layer (i.e. IPv4 packet
        does not get routed to AF_INET6 socket) rsync --daemon would accept
        IPv6 sessions only.  open_socket_in() tries to deal with the
        situation, but it was not enough.  here's the patch.

        (it is required on all *BSDs to accept both IPv4 and IPv6 connections
        with --daemon mode)

itojun


---
? configure.lineno
? lib/dummy
Index: socket.c
===================================================================
RCS file: /cvsroot/apps/rsync/socket.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 socket.c
--- socket.c    4 Mar 2003 10:29:09 -0000       1.1.1.1
+++ socket.c    4 Mar 2003 10:55:34 -0000
@@ -290,59 +290,30 @@
  * @param bind_address Local address to bind, or NULL to allow it to
  * default.
  **/
-static int open_socket_in(int type, int port, const char *bind_address,
-                         int af_hint)
+static int open_socket_in(struct addrinfo *resp)
 {
        int one=1;
        int s;
-       struct addrinfo hints, *all_ai, *resp;
-       char portbuf[10];
-       int error;
-
-       memset(&hints, 0, sizeof(hints));
-       hints.ai_family = af_hint;
-       hints.ai_socktype = type;
-       hints.ai_flags = AI_PASSIVE;
-       snprintf(portbuf, sizeof(portbuf), "%d", port);
-       error = getaddrinfo(bind_address, portbuf, &hints, &all_ai);
-       if (error) {
-               rprintf(FERROR, RSYNC_NAME ": getaddrinfo: bind address %s: %s\n",
-                       bind_address, gai_strerror(error));
-               return -1;
-       }
 
        /* We may not be able to create the socket, if for example the
         * machine knows about IPv6 in the C library, but not in the
         * kernel. */
-       for (resp = all_ai; resp; resp = resp->ai_next) {
-               s = socket(resp->ai_family, resp->ai_socktype,
-                          resp->ai_protocol);
+       s = socket(resp->ai_family, resp->ai_socktype,
+                  resp->ai_protocol);
 
-               if (s == -1) 
-                       /* See if there's another address that will work... */
-                       continue;
-               
-               setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
-                          (char *)&one, sizeof one);
-               
-               /* now we've got a socket - we need to bind it */
-               if (bind(s, all_ai->ai_addr, all_ai->ai_addrlen) < 0) {
-                       /* Nope, try another */
-                       close(s);
-                       continue;
-               }
-
-               freeaddrinfo(all_ai);
-               return s;
+       if (s == -1) 
+               return -1;
+       
+       setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
+                  (char *)&one, sizeof one);
+       
+       /* now we've got a socket - we need to bind it */
+       if (bind(s, resp->ai_addr, resp->ai_addrlen) < 0) {
+               close(s);
+               return -1;
        }
 
-       rprintf(FERROR, RSYNC_NAME ": open inbound socket on port %d failed: "
-               "%s\n",
-               port, 
-               strerror(errno));
-
-       freeaddrinfo(all_ai);
-       return -1; 
+       return s;
 }
 
 
@@ -371,24 +342,52 @@
        return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0);
 }
 
+#define        MAXSOCK 20
 
 void start_accept_loop(int port, int (*fn)(int ))
 {
-       int s;
+       int s[MAXSOCK];
+       int nsock = 0;
+       int maxsock = -1;
        extern char *bind_address;
        extern int default_af_hint;
+       struct addrinfo hints, *res, *res0;
+       char portstr[NI_MAXSERV];
+       int i;
 
-       /* open an incoming socket */
-       s = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint);
-       if (s == -1)
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = default_af_hint;
+       hints.ai_socktype = SOCK_STREAM;
+       hints.ai_flags = AI_PASSIVE;
+       snprintf(portstr, sizeof(portstr), "%d", port);
+       if (getaddrinfo(bind_address, portstr, &hints, &res0) != 0)
                exit_cleanup(RERR_SOCKETIO);
 
-       /* ready to listen */
-       if (listen(s, 5) == -1) {
-               close(s);
-               exit_cleanup(RERR_SOCKETIO);
+       /* open an incoming socket */
+       for (res = res0; res; res = res->ai_next) {
+               if (nsock >= sizeof(s) / sizeof(s[0]))
+                       break;
+               s[nsock] = open_socket_in(res);
+               if (s[nsock] == -1)
+                       continue;
+               if (s[nsock] >= FD_SETSIZE) {
+                       close(s[nsock]);
+                       continue;
+               }
+
+               /* ready to listen */
+               if (listen(s[nsock], 5) == -1) {
+                       close(s[nsock]);
+                       continue;
+               }
+
+               if (s[nsock] > maxsock)
+                       maxsock = s[nsock];
+               nsock++;
        }
 
+       if (nsock == 0)
+               exit_cleanup(RERR_SOCKETIO);
 
        /* now accept incoming connections - forking a new process
           for each incoming connection */
@@ -405,46 +404,51 @@
                log_close();
 
                FD_ZERO(&fds);
-               FD_SET(s, &fds);
+               for (i = 0; i < nsock; i++)
+                       FD_SET(s[i], &fds);
 
-               if (select(s+1, &fds, NULL, NULL, NULL) != 1) {
+               if (select(maxsock + 1, &fds, NULL, NULL, NULL) < 0)
                        continue;
-               }
 
-               if(!FD_ISSET(s, &fds)) continue;
+               for (i = 0; i < nsock; i++) {
+                       if (!FD_ISSET(s[i], &fds))
+                               continue;
 
-               fd = accept(s,(struct sockaddr *)&addr,&addrlen);
+                       fd = accept(s[i], (struct sockaddr *)&addr, &addrlen);
 
-               if (fd == -1) continue;
+                       if (fd == -1)
+                               continue;
 
-               signal(SIGCHLD, SIG_IGN);
+                       signal(SIGCHLD, SIG_IGN);
 
-               /* we shouldn't have any children left hanging around
-                  but I have had reports that on Digital Unix zombies
-                  are produced, so this ensures that they are reaped */
+                       /* we shouldn't have any children left hanging around
+                          but I have had reports that on Digital Unix zombies
+                          are produced, so this ensures that they are reaped */
 #ifdef WNOHANG
-                while (waitpid(-1, NULL, WNOHANG) > 0);
+                       while (waitpid(-1, NULL, WNOHANG) > 0);
 #endif
 
-               if ((pid = fork()) == 0) {
-                       close(s);
-                       /* open log file in child before possibly giving
-                          up privileges  */
-                       log_open();
-                       _exit(fn(fd));
-               } else if (pid < 0) {
-                       rprintf(FERROR,
-                               RSYNC_NAME
-                               ": could not create child server process: %s\n",
-                               strerror(errno));
-                       close(fd);
-                       /* This might have happened because we're
-                        * overloaded.  Sleep briefly before trying to
-                        * accept again. */
-                       sleep(2);
-               } else {
-                       /* Parent doesn't need this fd anymore. */
-                       close(fd);
+                       if ((pid = fork()) == 0) {
+                               for (i = 0; i < nsock; i++)
+                                       close(s[i]);
+                               /* open log file in child before possibly giving
+                                  up privileges  */
+                               log_open();
+                               _exit(fn(fd));
+                       } else if (pid < 0) {
+                               rprintf(FERROR,
+                                       RSYNC_NAME
+                                       ": could not create child server process: 
%s\n",
+                                       strerror(errno));
+                               close(fd);
+                               /* This might have happened because we're
+                                * overloaded.  Sleep briefly before trying to
+                                * accept again. */
+                               sleep(2);
+                       } else {
+                               /* Parent doesn't need this fd anymore. */
+                               close(fd);
+                       }
                }
        }
 }
-- 
To unsubscribe or change options: http://lists.samba.org/mailman/listinfo/rsync
Before posting, read: http://www.tuxedo.org/~esr/faqs/smart-questions.html

Reply via email to