]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
REORG: sock: move get_old_sockets() from haproxy.c
authorWilly Tarreau <w@1wt.eu>
Fri, 28 Aug 2020 16:42:45 +0000 (18:42 +0200)
committerWilly Tarreau <w@1wt.eu>
Fri, 28 Aug 2020 17:24:55 +0000 (19:24 +0200)
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.

include/haproxy/sock.h
src/haproxy.c
src/sock.c

index e405bb30c4da83c38e7461c228dcbf356266c4d7..c106ffde486b135c2cabfcd4da0fea0372664500 100644 (file)
@@ -35,6 +35,7 @@ extern struct xfer_sock_list *xfer_sock_list;
 int sock_create_server_socket(struct connection *conn);
 int sock_get_src(int fd, struct sockaddr *sa, socklen_t salen, int dir);
 int sock_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir);
+int sock_get_old_sockets(const char *unixsocket);
 int sock_find_compatible_fd(const struct listener *l);
 
 #endif /* _HAPROXY_SOCK_H */
index 7eb5c0e9a46f142778308c63c51d3126360dec00..8f41cf57967160af79fe15ed1f3dfd48f8d18dd6 100644 (file)
@@ -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 @@ next_dir_entry:
        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 @@ int main(int argc, char **argv)
 
        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);
index 5bb6e13d5ba9e1eed7c5613bdaaa040c3242ef04..b8a729ba62b2897052e3fa650e9b891d5743ac27 100644 (file)
@@ -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 @@ int sock_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir)
                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