$OpenBSD: patch-socket_c,v 1.2 2003/12/04 17:54:17 espie Exp $
--- socket.c.orig	2003-01-27 04:35:09.000000000 +0100
+++ socket.c	2003-12-04 09:44:06.000000000 +0100
@@ -292,11 +292,11 @@ int open_socket_out_wrapped (char *host,
  * @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 @@ static int open_socket_in(int type, int 
 	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 = new_array(int, maxs + 1);
+	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 @@ int is_a_socket(int fd)
 
 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 @@ void start_accept_loop(int port, int (*f
 		   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 @@ void start_accept_loop(int port, int (*f
 
 		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 @@ void start_accept_loop(int port, int (*f
 			close(fd);
 		}
 	}
+	free(s);
 }
 
 
