diff --git a/include/haproxy/global-t.h b/include/haproxy/global-t.h index 0cdb361ae..2e9b61b24 100644 --- a/include/haproxy/global-t.h +++ b/include/haproxy/global-t.h @@ -78,6 +78,7 @@ #define GTUNE_DISABLE_H2_WEBSOCKET (1<<21) #define GTUNE_DISABLE_ACTIVE_CLOSE (1<<22) #define GTUNE_QUICK_EXIT (1<<23) +#define GTUNE_QUIC_SOCK_PER_CONN (1<<24) /* SSL server verify mode */ enum { diff --git a/src/proto_quic.c b/src/proto_quic.c index 7267b67e7..003e510b6 100644 --- a/src/proto_quic.c +++ b/src/proto_quic.c @@ -570,6 +570,40 @@ static int quic_alloc_rxbufs_listener(struct listener *l) return 0; } +/* Check if platform supports the required feature set for quic-conn owned + * socket. listener must already be binded; a dummy socket will be opened + * on the same address as one of the support test. + * + * Returns true if platform is deemed compatible else false. + */ +static int quic_test_sock_per_conn_support(struct listener *l) +{ + const struct receiver *rx = &l->rx; + int ret = 1, fdtest; + + /* Check if platform support multiple UDP sockets bind on the same + * local address. Create a dummy socket and bind it on the same address + * as listener. If bind system call fails, deactivate socket per + * connection. All other errors are not taken into account. + */ + if (ret) { + fdtest = socket(rx->proto->fam->sock_domain, + rx->proto->sock_type, rx->proto->sock_prot); + if (fdtest > 0) { + if (setsockopt(fdtest, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) && + bind(fdtest, (struct sockaddr *)&rx->addr, rx->proto->fam->sock_addrlen) < 0) { + ha_alert("Your platform does not seem to support multiple UDP sockets binded on the same address. " + "QUIC connections will use listener socket.\n"); + ret = 0; + } + + close(fdtest); + } + } + + return ret; +} + /* This function tries to bind a QUIC4/6 listener. It may return a warning or * an error message in if the message is at most bytes long * (including '\0'). Note that may be NULL if is also zero. @@ -626,6 +660,11 @@ static int quic_bind_listener(struct listener *listener, char *errmsg, int errle goto udp_return; } + if (global.tune.options & GTUNE_QUIC_SOCK_PER_CONN) { + if (!quic_test_sock_per_conn_support(listener)) + global.tune.options &= ~GTUNE_QUIC_SOCK_PER_CONN; + } + listener_set_state(listener, LI_LISTEN); udp_return: