"rsync --daemon" and IPv4/v6 dual stack
Jun-ichiro itojun Hagino
itojun at iijlab.net
Wed Mar 5 10:38:45 EST 2003
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);
+ }
}
}
}
More information about the rsync
mailing list