REORG: sock: move get_old_sockets() from haproxy.c

The new function was called sock_get_old_sockets() and was left as-is
except a minimum amount of style lifting to make it more readable. It
will never be awesome anyway since it's used very early in the boot
sequence and needs to perform socket I/O without any external help.
diff --git a/src/haproxy.c b/src/haproxy.c
index 7eb5c0e..8f41cf5 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -39,7 +39,6 @@
 #include <netinet/tcp.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
-#include <net/if.h>
 #include <netdb.h>
 #include <fcntl.h>
 #include <errno.h>
@@ -1124,244 +1123,6 @@
 	free(err);
 }
 
-/* Retrieves old sockets from worker process running the CLI at address
- * <unixsocket>. Fills xfer_sock_list with what is found. Returns 0 on
- * success, -1 on failure.
- */
-static int get_old_sockets(const char *unixsocket)
-{
-	char *cmsgbuf = NULL, *tmpbuf = NULL;
-	int *tmpfd = NULL;
-	struct sockaddr_un addr;
-	struct cmsghdr *cmsg;
-	struct msghdr msghdr;
-	struct iovec iov;
-	struct xfer_sock_list *xfer_sock = NULL;
-	struct timeval tv = { .tv_sec = 1, .tv_usec = 0 };
-	int sock = -1;
-	int ret = -1;
-	int ret2 = -1;
-	int fd_nb;
-	int got_fd = 0;
-	int i = 0;
-	size_t maxoff = 0, curoff = 0;
-
-	memset(&msghdr, 0, sizeof(msghdr));
-	cmsgbuf = malloc(CMSG_SPACE(sizeof(int)) * MAX_SEND_FD);
-	if (!cmsgbuf) {
-		ha_warning("Failed to allocate memory to send sockets\n");
-		goto out;
-	}
-	sock = socket(PF_UNIX, SOCK_STREAM, 0);
-	if (sock < 0) {
-		ha_warning("Failed to connect to the old process socket '%s'\n",
-			   unixsocket);
-		goto out;
-	}
-	strncpy(addr.sun_path, unixsocket, sizeof(addr.sun_path) - 1);
-	addr.sun_path[sizeof(addr.sun_path) - 1] = 0;
-	addr.sun_family = PF_UNIX;
-	ret = connect(sock, (struct sockaddr *)&addr, sizeof(addr));
-	if (ret < 0) {
-		ha_warning("Failed to connect to the old process socket '%s'\n",
-			   unixsocket);
-		goto out;
-	}
-	setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv));
-	iov.iov_base = &fd_nb;
-	iov.iov_len = sizeof(fd_nb);
-	msghdr.msg_iov = &iov;
-	msghdr.msg_iovlen = 1;
-	send(sock, "_getsocks\n", strlen("_getsocks\n"), 0);
-	/* First, get the number of file descriptors to be received */
-	if (recvmsg(sock, &msghdr, MSG_WAITALL) != sizeof(fd_nb)) {
-		ha_warning("Failed to get the number of sockets to be transferred !\n");
-		goto out;
-	}
-	if (fd_nb == 0) {
-		ret2 = 0;
-		goto out;
-	}
-	tmpbuf = malloc(fd_nb * (1 + MAXPATHLEN + 1 + IFNAMSIZ + sizeof(int)));
-	if (tmpbuf == NULL) {
-		ha_warning("Failed to allocate memory while receiving sockets\n");
-		goto out;
-	}
-	tmpfd = malloc(fd_nb * sizeof(int));
-	if (tmpfd == NULL) {
-		ha_warning("Failed to allocate memory while receiving sockets\n");
-		goto out;
-	}
-	msghdr.msg_control = cmsgbuf;
-	msghdr.msg_controllen = CMSG_SPACE(sizeof(int)) * MAX_SEND_FD;
-	iov.iov_len = MAX_SEND_FD * (1 + MAXPATHLEN + 1 + IFNAMSIZ + sizeof(int));
-	do {
-		int ret3;
-
-		iov.iov_base = tmpbuf + curoff;
-		ret = recvmsg(sock, &msghdr, 0);
-		if (ret == -1 && errno == EINTR)
-			continue;
-		if (ret <= 0)
-			break;
-		/* Send an ack to let the sender know we got the sockets
-		 * and it can send some more
-		 */
-		do {
-			ret3 = send(sock, &got_fd, sizeof(got_fd), 0);
-		} while (ret3 == -1 && errno == EINTR);
-		for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg != NULL;
-		    cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
-			if (cmsg->cmsg_level == SOL_SOCKET &&
-			    cmsg->cmsg_type == SCM_RIGHTS) {
-				size_t totlen = cmsg->cmsg_len -
-				    CMSG_LEN(0);
-				if (totlen / sizeof(int) + got_fd > fd_nb) {
-					ha_warning("Got to many sockets !\n");
-					goto out;
-				}
-				/*
-				 * Be paranoid and use memcpy() to avoid any
-				 * potential alignment issue.
-				 */
-				memcpy(&tmpfd[got_fd], CMSG_DATA(cmsg), totlen);
-				got_fd += totlen / sizeof(int);
-			}
-		}
-		curoff += ret;
-	} while (got_fd < fd_nb);
-
-	if (got_fd != fd_nb) {
-		ha_warning("We didn't get the expected number of sockets (expecting %d got %d)\n",
-			   fd_nb, got_fd);
-		goto out;
-	}
-	maxoff = curoff;
-	curoff = 0;
-	for (i = 0; i < got_fd; i++) {
-		int fd = tmpfd[i];
-		socklen_t socklen;
-		int len;
-
-		xfer_sock = calloc(1, sizeof(*xfer_sock));
-		if (!xfer_sock) {
-			ha_warning("Failed to allocate memory in get_old_sockets() !\n");
-			break;
-		}
-		xfer_sock->fd = -1;
-
-		socklen = sizeof(xfer_sock->addr);
-		if (getsockname(fd, (struct sockaddr *)&xfer_sock->addr, &socklen) != 0) {
-			ha_warning("Failed to get socket address\n");
-			free(xfer_sock);
-			xfer_sock = NULL;
-			continue;
-		}
-		if (curoff >= maxoff) {
-			ha_warning("Inconsistency while transferring sockets\n");
-			goto out;
-		}
-		len = tmpbuf[curoff++];
-		if (len > 0) {
-			/* We have a namespace */
-			if (curoff + len > maxoff) {
-				ha_warning("Inconsistency while transferring sockets\n");
-				goto out;
-			}
-			xfer_sock->namespace = malloc(len + 1);
-			if (!xfer_sock->namespace) {
-				ha_warning("Failed to allocate memory while transferring sockets\n");
-				goto out;
-			}
-			memcpy(xfer_sock->namespace, &tmpbuf[curoff], len);
-			xfer_sock->namespace[len] = 0;
-			xfer_sock->ns_namelen = len;
-			curoff += len;
-		}
-		if (curoff >= maxoff) {
-			ha_warning("Inconsistency while transferring sockets\n");
-			goto out;
-		}
-		len = tmpbuf[curoff++];
-		if (len > 0) {
-			/* We have an interface */
-			if (curoff + len > maxoff) {
-				ha_warning("Inconsistency while transferring sockets\n");
-				goto out;
-			}
-			xfer_sock->iface = malloc(len + 1);
-			if (!xfer_sock->iface) {
-				ha_warning("Failed to allocate memory while transferring sockets\n");
-				goto out;
-			}
-			memcpy(xfer_sock->iface, &tmpbuf[curoff], len);
-			xfer_sock->iface[len] = 0;
-			xfer_sock->if_namelen = len;
-			curoff += len;
-		}
-		if (curoff + sizeof(int) > maxoff) {
-			ha_warning("Inconsistency while transferring sockets\n");
-			goto out;
-		}
-
-		/* we used to have 32 bits of listener options here but we don't
-		 * use them anymore.
-		 */
-		curoff += sizeof(int);
-
-		/* determine the foreign status directly from the socket itself */
-		if (sock_inet_is_foreign(fd, xfer_sock->addr.ss_family))
-			xfer_sock->options |= LI_O_FOREIGN;
-
-		/* keep only the v6only flag depending on what's currently
-		 * active on the socket, and always drop the v4v6 one.
-		 */
-#if defined(IPV6_V6ONLY)
-		{
-			int val = 0;
-			socklen_t len = sizeof(val);
-
-			if (xfer_sock->addr.ss_family == AF_INET6 &&
-			    getsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, &len) == 0 &&
-			    val > 0)
-				xfer_sock->options |= LI_O_V6ONLY;
-		}
-#endif
-
-		xfer_sock->fd = fd;
-		if (xfer_sock_list)
-			xfer_sock_list->prev = xfer_sock;
-		xfer_sock->next = xfer_sock_list;
-		xfer_sock->prev = NULL;
-		xfer_sock_list = xfer_sock;
-		xfer_sock = NULL;
-	}
-
-	ret2 = 0;
-out:
-	/* If we failed midway make sure to close the remaining
-	 * file descriptors
-	 */
-	if (tmpfd != NULL && i < got_fd) {
-		for (; i < got_fd; i++) {
-			close(tmpfd[i]);
-		}
-	}
-	free(tmpbuf);
-	free(tmpfd);
-	free(cmsgbuf);
-	if (sock != -1)
-		close(sock);
-	if (xfer_sock) {
-		free(xfer_sock->namespace);
-		free(xfer_sock->iface);
-		if (xfer_sock->fd != -1)
-			close(xfer_sock->fd);
-		free(xfer_sock);
-	}
-	return (ret2);
-}
-
 /*
  * copy and cleanup the current argv
  * Remove the -sf /-st / -x parameters
@@ -3281,7 +3042,7 @@
 
 	if (old_unixsocket) {
 		if (strcmp("/dev/null", old_unixsocket) != 0) {
-			if (get_old_sockets(old_unixsocket) != 0) {
+			if (sock_get_old_sockets(old_unixsocket) != 0) {
 				ha_alert("Failed to get the sockets from the old process!\n");
 				if (!(global.mode & MODE_MWORKER))
 					exit(1);
diff --git a/src/sock.c b/src/sock.c
index 5bb6e13..b8a729b 100644
--- a/src/sock.c
+++ b/src/sock.c
@@ -22,6 +22,8 @@
 #include <sys/socket.h>
 #include <sys/types.h>
 
+#include <net/if.h>
+
 #include <haproxy/api.h>
 #include <haproxy/connection.h>
 #include <haproxy/listener-t.h>
@@ -81,6 +83,266 @@
 		return getsockname(fd, sa, &salen);
 }
 
+/* Try to retrieve exported sockets from worker at CLI <unixsocket>. These
+ * ones will be placed into the xfer_sock_list for later use by function
+ * sock_find_compatible_fd(). Returns 0 on success, -1 on failure.
+ */
+int sock_get_old_sockets(const char *unixsocket)
+{
+	char *cmsgbuf = NULL, *tmpbuf = NULL;
+	int *tmpfd = NULL;
+	struct sockaddr_un addr;
+	struct cmsghdr *cmsg;
+	struct msghdr msghdr;
+	struct iovec iov;
+	struct xfer_sock_list *xfer_sock = NULL;
+	struct timeval tv = { .tv_sec = 1, .tv_usec = 0 };
+	int sock = -1;
+	int ret = -1;
+	int ret2 = -1;
+	int fd_nb;
+	int got_fd = 0;
+	int cur_fd = 0;
+	size_t maxoff = 0, curoff = 0;
+
+	memset(&msghdr, 0, sizeof(msghdr));
+	cmsgbuf = malloc(CMSG_SPACE(sizeof(int)) * MAX_SEND_FD);
+	if (!cmsgbuf) {
+		ha_warning("Failed to allocate memory to send sockets\n");
+		goto out;
+	}
+
+	sock = socket(PF_UNIX, SOCK_STREAM, 0);
+	if (sock < 0) {
+		ha_warning("Failed to connect to the old process socket '%s'\n", unixsocket);
+		goto out;
+	}
+
+	strncpy(addr.sun_path, unixsocket, sizeof(addr.sun_path) - 1);
+	addr.sun_path[sizeof(addr.sun_path) - 1] = 0;
+	addr.sun_family = PF_UNIX;
+
+	ret = connect(sock, (struct sockaddr *)&addr, sizeof(addr));
+	if (ret < 0) {
+		ha_warning("Failed to connect to the old process socket '%s'\n", unixsocket);
+		goto out;
+	}
+
+	setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv));
+	iov.iov_base = &fd_nb;
+	iov.iov_len = sizeof(fd_nb);
+	msghdr.msg_iov = &iov;
+	msghdr.msg_iovlen = 1;
+
+	if (send(sock, "_getsocks\n", strlen("_getsocks\n"), 0) != strlen("_getsocks\n")) {
+		ha_warning("Failed to get the number of sockets to be transferred !\n");
+		goto out;
+	}
+
+	/* First, get the number of file descriptors to be received */
+	if (recvmsg(sock, &msghdr, MSG_WAITALL) != sizeof(fd_nb)) {
+		ha_warning("Failed to get the number of sockets to be transferred !\n");
+		goto out;
+	}
+
+	if (fd_nb == 0) {
+		ret2 = 0;
+		goto out;
+	}
+
+	tmpbuf = malloc(fd_nb * (1 + MAXPATHLEN + 1 + IFNAMSIZ + sizeof(int)));
+	if (tmpbuf == NULL) {
+		ha_warning("Failed to allocate memory while receiving sockets\n");
+		goto out;
+	}
+
+	tmpfd = malloc(fd_nb * sizeof(int));
+	if (tmpfd == NULL) {
+		ha_warning("Failed to allocate memory while receiving sockets\n");
+		goto out;
+	}
+
+	msghdr.msg_control = cmsgbuf;
+	msghdr.msg_controllen = CMSG_SPACE(sizeof(int)) * MAX_SEND_FD;
+	iov.iov_len = MAX_SEND_FD * (1 + MAXPATHLEN + 1 + IFNAMSIZ + sizeof(int));
+
+	do {
+		int ret3;
+
+		iov.iov_base = tmpbuf + curoff;
+
+		ret = recvmsg(sock, &msghdr, 0);
+
+		if (ret == -1 && errno == EINTR)
+			continue;
+
+		if (ret <= 0)
+			break;
+
+		/* Send an ack to let the sender know we got the sockets
+		 * and it can send some more
+		 */
+		do {
+			ret3 = send(sock, &got_fd, sizeof(got_fd), 0);
+		} while (ret3 == -1 && errno == EINTR);
+
+		for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg != NULL; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
+			if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
+				size_t totlen = cmsg->cmsg_len - CMSG_LEN(0);
+
+				if (totlen / sizeof(int) + got_fd > fd_nb) {
+					ha_warning("Got to many sockets !\n");
+					goto out;
+				}
+
+				/*
+				 * Be paranoid and use memcpy() to avoid any
+				 * potential alignment issue.
+				 */
+				memcpy(&tmpfd[got_fd], CMSG_DATA(cmsg), totlen);
+				got_fd += totlen / sizeof(int);
+			}
+		}
+		curoff += ret;
+	} while (got_fd < fd_nb);
+
+	if (got_fd != fd_nb) {
+		ha_warning("We didn't get the expected number of sockets (expecting %d got %d)\n",
+			   fd_nb, got_fd);
+		goto out;
+	}
+
+	maxoff = curoff;
+	curoff = 0;
+
+	for (cur_fd = 0; cur_fd < got_fd; cur_fd++) {
+		int fd = tmpfd[cur_fd];
+		socklen_t socklen;
+		int val;
+		int len;
+
+		xfer_sock = calloc(1, sizeof(*xfer_sock));
+		if (!xfer_sock) {
+			ha_warning("Failed to allocate memory in get_old_sockets() !\n");
+			break;
+		}
+		xfer_sock->fd = -1;
+
+		socklen = sizeof(xfer_sock->addr);
+		if (getsockname(fd, (struct sockaddr *)&xfer_sock->addr, &socklen) != 0) {
+			ha_warning("Failed to get socket address\n");
+			free(xfer_sock);
+			xfer_sock = NULL;
+			continue;
+		}
+
+		if (curoff >= maxoff) {
+			ha_warning("Inconsistency while transferring sockets\n");
+			goto out;
+		}
+
+		len = tmpbuf[curoff++];
+		if (len > 0) {
+			/* We have a namespace */
+			if (curoff + len > maxoff) {
+				ha_warning("Inconsistency while transferring sockets\n");
+				goto out;
+			}
+			xfer_sock->namespace = malloc(len + 1);
+			if (!xfer_sock->namespace) {
+				ha_warning("Failed to allocate memory while transferring sockets\n");
+				goto out;
+			}
+			memcpy(xfer_sock->namespace, &tmpbuf[curoff], len);
+			xfer_sock->namespace[len] = 0;
+			xfer_sock->ns_namelen = len;
+			curoff += len;
+		}
+
+		if (curoff >= maxoff) {
+			ha_warning("Inconsistency while transferring sockets\n");
+			goto out;
+		}
+
+		len = tmpbuf[curoff++];
+		if (len > 0) {
+			/* We have an interface */
+			if (curoff + len > maxoff) {
+				ha_warning("Inconsistency while transferring sockets\n");
+				goto out;
+			}
+			xfer_sock->iface = malloc(len + 1);
+			if (!xfer_sock->iface) {
+				ha_warning("Failed to allocate memory while transferring sockets\n");
+				goto out;
+			}
+			memcpy(xfer_sock->iface, &tmpbuf[curoff], len);
+			xfer_sock->iface[len] = 0;
+			xfer_sock->if_namelen = len;
+			curoff += len;
+		}
+
+		if (curoff + sizeof(int) > maxoff) {
+			ha_warning("Inconsistency while transferring sockets\n");
+			goto out;
+		}
+
+		/* we used to have 32 bits of listener options here but we don't
+		 * use them anymore.
+		 */
+		curoff += sizeof(int);
+
+		/* determine the foreign status directly from the socket itself */
+		if (sock_inet_is_foreign(fd, xfer_sock->addr.ss_family))
+			xfer_sock->options |= LI_O_FOREIGN;
+
+#if defined(IPV6_V6ONLY)
+		/* keep only the v6only flag depending on what's currently
+		 * active on the socket, and always drop the v4v6 one.
+		 */
+		socklen = sizeof(val);
+		if (xfer_sock->addr.ss_family == AF_INET6 &&
+		    getsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, &socklen) == 0 && val > 0)
+			xfer_sock->options |= LI_O_V6ONLY;
+#endif
+
+		xfer_sock->fd = fd;
+		if (xfer_sock_list)
+			xfer_sock_list->prev = xfer_sock;
+		xfer_sock->next = xfer_sock_list;
+		xfer_sock->prev = NULL;
+		xfer_sock_list = xfer_sock;
+		xfer_sock = NULL;
+	}
+
+	ret2 = 0;
+out:
+	/* If we failed midway make sure to close the remaining
+	 * file descriptors
+	 */
+	if (tmpfd != NULL && cur_fd < got_fd) {
+		for (; cur_fd < got_fd; cur_fd++) {
+			close(tmpfd[cur_fd]);
+		}
+	}
+
+	free(tmpbuf);
+	free(tmpfd);
+	free(cmsgbuf);
+
+	if (sock != -1)
+		close(sock);
+
+	if (xfer_sock) {
+		free(xfer_sock->namespace);
+		free(xfer_sock->iface);
+		if (xfer_sock->fd != -1)
+			close(xfer_sock->fd);
+		free(xfer_sock);
+	}
+	return (ret2);
+}
+
 /* When binding the listeners, check if a socket has been sent to us by the
  * previous process that we could reuse, instead of creating a new one. Note
  * that some address family-specific options are checked on the listener and