mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2024-12-19 01:54:37 +00:00
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.
This commit is contained in:
parent
37bafdcbb1
commit
429617459d
@ -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 */
|
||||
|
241
src/haproxy.c
241
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 @@ 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);
|
||||
|
262
src/sock.c
262
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 @@ 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
|
||||
|
Loading…
Reference in New Issue
Block a user