summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWilly Tarreau <w@1wt.eu>2020-09-01 16:12:50 +0200
committerWilly Tarreau <w@1wt.eu>2020-09-02 18:53:56 +0200
commit400fbfa21c3a406c5c1930783145eb3c19a775ec (patch)
tree26e58c1e6cdf7e25d4d4d5ee0c57c34fa5e228c3
parent1625fa0ed93947c65f8f92e76556c1ea9efb73b5 (diff)
downloadhaproxy-400fbfa21c3a406c5c1930783145eb3c19a775ec.tar.gz
MEDIUM: tcp: make use of sock_inet_bind_receiver()
This removes all the AF_INET-specific code from tcp_bind_listener() and now simply relies on sock_inet_bind_listener() to do the same job. The function was now roughly cut in half and its error path significantly simplified.
-rw-r--r--src/proto_tcp.c136
1 files changed, 15 insertions, 121 deletions
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index 02a458349..9e8e5a403 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -556,11 +556,10 @@ int tcp_connect_server(struct connection *conn, int flags)
*/
int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen)
{
- __label__ tcp_return, tcp_close_return;
int fd, err;
- int ext, ready;
+ int ready;
socklen_t ready_len;
- const char *msg = NULL;
+ char *msg = NULL;
/* ensure we never return garbage */
if (errlen)
@@ -569,62 +568,16 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen)
if (listener->state != LI_ASSIGNED)
return ERR_NONE; /* already bound */
- err = ERR_NONE;
-
- if (listener->rx.options & RX_O_BOUND)
- goto bound;
-
- if (listener->options & LI_O_FOREIGN)
- listener->rx.options |= RX_O_FOREIGN;
-
- if (listener->rx.addr.ss_family == AF_INET6) {
- /* Prepare to match the v6only option against what we really want. Note
- * that sadly the two options are not exclusive to each other and that
- * v6only is stronger than v4v6.
- */
- if ((listener->options & LI_O_V6ONLY) ||
- (sock_inet6_v6only_default && !(listener->options & LI_O_V4V6)))
- listener->rx.options |= RX_O_V6ONLY;
+ err = sock_inet_bind_receiver(&listener->rx,
+ listener->rx.proto->accept, listener,
+ listener->bind_conf->bind_thread, &msg);
+ if (err != ERR_NONE) {
+ snprintf(errmsg, errlen, "%s", msg);
+ free(msg); msg = NULL;
+ return err;
}
- if (listener->rx.fd == -1)
- listener->rx.fd = sock_find_compatible_fd(&listener->rx);
-
- /* if the listener already has an fd assigned, then we were offered the
- * fd by an external process (most likely the parent), and we don't want
- * to create a new socket. However we still want to set a few flags on
- * the socket.
- */
fd = listener->rx.fd;
- ext = (fd >= 0);
-
- if (!ext) {
- fd = my_socketat(listener->rx.netns, listener->rx.addr.ss_family, SOCK_STREAM, IPPROTO_TCP);
-
- if (fd == -1) {
- err |= ERR_RETRYABLE | ERR_ALERT;
- msg = "cannot create listening socket";
- goto tcp_return;
- }
- }
-
- if (fd >= global.maxsock) {
- err |= ERR_FATAL | ERR_ABORT | ERR_ALERT;
- msg = "not enough free sockets (raise '-n' parameter)";
- goto tcp_close_return;
- }
-
- if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
- err |= ERR_FATAL | ERR_ALERT;
- msg = "cannot make socket non-blocking";
- goto tcp_close_return;
- }
-
- if (!ext && setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) {
- /* not fatal but should be reported */
- msg = "cannot do so_reuseaddr";
- err |= ERR_ALERT;
- }
if (listener->options & LI_O_NOLINGER)
setsockopt(fd, SOL_SOCKET, SO_LINGER, &nolinger, sizeof(struct linger));
@@ -640,41 +593,6 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen)
}
}
-#ifdef SO_REUSEPORT
- /* OpenBSD and Linux 3.9 support this. As it's present in old libc versions of
- * Linux, it might return an error that we will silently ignore.
- */
- if (!ext && (global.tune.options & GTUNE_USE_REUSEPORT))
- setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
-#endif
-
- if (!ext && (listener->options & LI_O_FOREIGN)) {
- switch (listener->rx.addr.ss_family) {
- case AF_INET:
- if (!sock_inet4_make_foreign(fd)) {
- msg = "cannot make listening socket transparent";
- err |= ERR_ALERT;
- }
- break;
- case AF_INET6:
- if (!sock_inet6_make_foreign(fd)) {
- msg = "cannot make listening socket transparent";
- err |= ERR_ALERT;
- }
- break;
- }
- }
-
-#ifdef SO_BINDTODEVICE
- /* Note: this might fail if not CAP_NET_RAW */
- if (!ext && listener->rx.interface) {
- if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
- listener->rx.interface, strlen(listener->rx.interface) + 1) == -1) {
- msg = "cannot bind listener to device";
- err |= ERR_WARN;
- }
- }
-#endif
#if defined(TCP_MAXSEG)
if (listener->maxseg > 0) {
if (setsockopt(fd, IPPROTO_TCP, TCP_MAXSEG,
@@ -682,7 +600,8 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen)
msg = "cannot set MSS";
err |= ERR_WARN;
}
- } else if (ext) {
+ } else {
+ /* we may want to try to restore the default MSS if the socket was inherited */
int tmpmaxseg = -1;
int defaultmss;
socklen_t len = sizeof(tmpmaxseg);
@@ -749,27 +668,12 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen)
}
}
#endif
-#if defined(IPV6_V6ONLY)
- if (!ext && listener->options & LI_O_V6ONLY)
- setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
- else if (!ext && listener->options & LI_O_V4V6)
- setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero));
-#endif
-
- if (!ext && bind(fd, (struct sockaddr *)&listener->rx.addr, listener->rx.proto->sock_addrlen) == -1) {
- err |= ERR_RETRYABLE | ERR_ALERT;
- msg = "cannot bind socket";
- goto tcp_close_return;
- }
- listener->rx.options |= RX_O_BOUND;
-
- bound:
ready = 0;
ready_len = sizeof(ready);
if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &ready, &ready_len) == -1)
ready = 0;
- if (!(ext && ready) && /* only listen if not already done by external process */
+ if (!ready && /* only listen if not already done by external process */
listen(fd, listener_backlog(listener)) == -1) {
err |= ERR_RETRYABLE | ERR_ALERT;
msg = "cannot listen to socket";
@@ -784,17 +688,11 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen)
#endif
/* the socket is ready */
- listener->rx.fd = fd;
listener->state = LI_LISTEN;
+ return err;
- fd_insert(fd, listener, listener->rx.proto->accept,
- thread_mask(listener->bind_conf->bind_thread) & all_threads_mask);
-
- /* for now, all regularly bound TCP listeners are exportable */
- if (!(listener->rx.options & RX_O_INHERITED))
- fdtab[fd].exported = 1;
-
- tcp_return:
+ tcp_close_return:
+ close(fd);
if (msg && errlen) {
char pn[INET6_ADDRSTRLEN];
@@ -802,10 +700,6 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen)
snprintf(errmsg, errlen, "%s [%s:%d]", msg, pn, get_host_port(&listener->rx.addr));
}
return err;
-
- tcp_close_return:
- close(fd);
- goto tcp_return;
}
/* Add <listener> to the list of tcpv4 listeners, on port <port>. The