Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 08 Feb 2003 00:29:56 +0900
From:      Hajimu UMEMOTO <ume@FreeBSD.org>
To:        David Rhodus <david@uky.edu>
Cc:        "Sean Winn" <sean@gothic.net.au>, FreeBSD users <FreeBSD-current@FreeBSD.ORG>, obraun@FreeBSD.org
Subject:   Re: rsync --daemon problems
Message-ID:  <ygelm0sm7m3.wl%ume@mahoroba.org>
In-Reply-To: <BC6793A7-3A33-11D7-B375-00039380DD2C@uky.edu>
References:  <007e01c2ce2f$8c403c80$f400a8c0@private.gothic.net.au> <BC6793A7-3A33-11D7-B375-00039380DD2C@uky.edu>

next in thread | previous in thread | raw e-mail | index | archive | help
--Multipart_Sat_Feb__8_00:29:56_2003-1
Content-Type: text/plain; charset=US-ASCII

Hi,

>>>>> On Thu, 6 Feb 2003 19:33:10 -0500
>>>>> David Rhodus <david@uky.edu> said:

david> On one machine that rsync start's on, I get this from netstat.
david> tcp6       0      0  *.873                  *.*                    
david> LISTEN

It seems the daemon mode of rsync depends on an IPv4-mapped IPv6
address.  Since an IPv4-mapped IPv6 address is off by default on
5-CURRENT, rsync doesn't listen on IPv4.
Further, rsync has a bug that it always listen on 1st entry's address
of the result of getaddrinfo() call.
Please try attached patch.  With this patch, rsync listen on both an
IPv4 and an IPv6.

Sincerely,


--Multipart_Sat_Feb__8_00:29:56_2003-1
Content-Type: text/x-patch; charset=US-ASCII
Content-Disposition: attachment; filename="patch-socket.c"
Content-Transfer-Encoding: 7bit

Index: socket.c
diff -u socket.c.orig socket.c
--- socket.c.orig	Mon Jan 27 12:35:09 2003
+++ socket.c	Sat Feb  8 00:06:59 2003
@@ -292,11 +292,11 @@
  * @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(int type, int port, const char *bind_address,
+			   int af_hint)
 {
 	int one=1;
-	int s;
+	int *s, *socks, maxs;
 	struct addrinfo hints, *all_ai, *resp;
 	char portbuf[10];
 	int error;
@@ -310,41 +310,65 @@
 	if (error) {
 		rprintf(FERROR, RSYNC_NAME ": getaddrinfo: bind address %s: %s\n",
 			bind_address, gai_strerror(error));
-		return -1;
+		return NULL;
+	}
+
+	/* Count max number of sockets we may open */
+	for (maxs = 0, resp = all_ai; resp; resp = resp->ai_next, maxs++)
+		;
+	socks = malloc((maxs + 1) * sizeof(int));
+	if (!socks) {
+		rprintf(FERROR,
+			RSYNC_NAME "couldn't allocate memory for sockets");
+		return NULL;
 	}
 
 	/* 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. */
+	*socks = 0;   /* num of sockets counter at start of array */
+	s = socks + 1;
 	for (resp = all_ai; resp; resp = resp->ai_next) {
-		s = socket(resp->ai_family, resp->ai_socktype,
+		*s = socket(resp->ai_family, resp->ai_socktype,
 			   resp->ai_protocol);
 
-		if (s == -1) 
+		if (*s == -1) 
 			/* See if there's another address that will work... */
 			continue;
 		
-		setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
+		setsockopt(*s, SOL_SOCKET, SO_REUSEADDR,
 			   (char *)&one, sizeof one);
 		
+#ifdef IPV6_V6ONLY
+		if (resp->ai_family == AF_INET6)
+			setsockopt(*s, IPPROTO_IPV6, IPV6_V6ONLY,
+				   (char *)&one, sizeof one);
+#endif
+
 		/* now we've got a socket - we need to bind it */
-		if (bind(s, all_ai->ai_addr, all_ai->ai_addrlen) < 0) {
+		if (bind(*s, resp->ai_addr, resp->ai_addrlen) < 0) {
 			/* Nope, try another */
-			close(s);
+			close(*s);
 			continue;
 		}
 
-		freeaddrinfo(all_ai);
-		return s;
+		(*socks)++;
+		s++;
 	}
 
-	rprintf(FERROR, RSYNC_NAME ": open inbound socket on port %d failed: "
-		"%s\n",
-		port, 
-		strerror(errno));
+	if (all_ai)
+		freeaddrinfo(all_ai);
 
-	freeaddrinfo(all_ai);
-	return -1; 
+	if (*socks == 0) {
+		rprintf(FERROR,
+			RSYNC_NAME ": open inbound socket on port %d failed: "
+			"%s\n",
+			port, 
+			strerror(errno));
+		free(socks);
+		return NULL;
+	}
+	return socks;
 }
 
 
@@ -376,19 +400,29 @@
 
 void start_accept_loop(int port, int (*fn)(int, int))
 {
-	int s;
+	fd_set deffds;
+	int *s, maxfd, i, j;
 	extern char *bind_address;
 	extern int default_af_hint;
 
 	/* open an incoming socket */
 	s = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint);
-	if (s == -1)
+	if (s == NULL)
 		exit_cleanup(RERR_SOCKETIO);
 
 	/* ready to listen */
-	if (listen(s, 5) == -1) {
-		close(s);
-		exit_cleanup(RERR_SOCKETIO);
+	FD_ZERO(&deffds);
+	maxfd = -1;
+	for (i = 1; i <= *s; i++) {
+		if (listen(s[i], 5) == -1) {
+			for (j = 1; j <= i; j++)
+				close(s[j]);
+			free(s);
+			exit_cleanup(RERR_SOCKETIO);
+		}
+		FD_SET(s[i], &deffds);
+		if (maxfd < s[i])
+			maxfd = s[i];
 	}
 
 
@@ -406,16 +440,20 @@
 		   forever */
 		log_close();
 
-		FD_ZERO(&fds);
-		FD_SET(s, &fds);
+		FD_COPY(&deffds, &fds);
 
-		if (select(s+1, &fds, NULL, NULL, NULL) != 1) {
+		if (select(maxfd + 1, &fds, NULL, NULL, NULL) != 1) {
 			continue;
 		}
 
-		if(!FD_ISSET(s, &fds)) continue;
-
-		fd = accept(s,(struct sockaddr *)&addr,&addrlen);
+		fd = -1;
+		for (i = 1; i <= *s; i++) {
+			if (FD_ISSET(s[i], &fds)) {
+				fd = accept(s[i], (struct sockaddr *)&addr,
+					    &addrlen);
+				break;
+			}
+		}
 
 		if (fd == -1) continue;
 
@@ -430,7 +468,7 @@
 
 		if ((pid = fork()) == 0) {
 			int ret;
-			close(s);
+			close(s[i]);
 			/* open log file in child before possibly giving
 			   up privileges  */
 			log_open();
@@ -452,6 +490,7 @@
 			close(fd);
 		}
 	}
+	free(s);
 }
 
 

--Multipart_Sat_Feb__8_00:29:56_2003-1
Content-Type: text/plain; charset=US-ASCII

--
Hajimu UMEMOTO @ Internet Mutual Aid Society Yokohama, Japan
ume@mahoroba.org  ume@bisd.hitachi.co.jp  ume@{,jp.}FreeBSD.org
http://www.imasy.org/~ume/

--Multipart_Sat_Feb__8_00:29:56_2003-1--

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?ygelm0sm7m3.wl%ume>