#include <haproxy/api.h>
#include <haproxy/connection-t.h>
#include <haproxy/listener-t.h>
+#include <haproxy/quic_conn-t.h>
#include <haproxy/quic_sock-t.h>
int quic_session_accept(struct connection *cli_conn);
int qc_snd_buf(struct quic_conn *qc, const struct buffer *buf, size_t count,
int flags);
+/* Set default value for <qc> socket as uninitialized. */
+static inline void qc_init_fd(struct quic_conn *qc)
+{
+ qc->fd = -1;
+}
+
+/* Returns true if <qc> socket is initialized else false. */
+static inline char qc_test_fd(struct quic_conn *qc)
+{
+ /* quic-conn socket should not be accessed once it has been released. */
+ BUG_ON(qc->fd == DEAD_FD_MAGIC);
+ return qc->fd >= 0;
+}
+
+void qc_alloc_fd(struct quic_conn *qc, const struct sockaddr_storage *src,
+ const struct sockaddr_storage *dst);
+void qc_release_fd(struct quic_conn *qc);
+
void quic_accept_push_qc(struct quic_conn *qc);
#endif /* USE_QUIC */
goto err;
}
+ if ((global.tune.options & GTUNE_QUIC_SOCK_PER_CONN) &&
+ is_addr(local_addr)) {
+ TRACE_USER("Allocate a socket for QUIC connection", QUIC_EV_CONN_INIT, qc);
+ qc_alloc_fd(qc, local_addr, peer_addr);
+ }
+ else {
+ qc_init_fd(qc);
+ }
+
/* insert the allocated CID in the receiver datagram handler tree */
if (server)
ebmb_insert(&quic_dghdlrs[tid].cids, &icid->node, icid->cid.len);
/* We must not free the quic-conn if the MUX is still allocated. */
BUG_ON(qc->mux_state == QC_MUX_READY);
+ /* Close quic-conn socket fd. */
+ qc_release_fd(qc);
+
/* in the unlikely (but possible) case the connection was just added to
* the accept_list we must delete it from there.
*/
#include <haproxy/global-t.h>
#include <haproxy/list.h>
#include <haproxy/listener.h>
+#include <haproxy/log.h>
#include <haproxy/pool.h>
#include <haproxy/proto_quic.h>
#include <haproxy/proxy-t.h>
return 0;
}
+/* Allocate a socket file-descriptor specific for QUIC connection <qc>.
+ * Endpoint addresses are specified by the two following arguments : <src> is
+ * the local address and <dst> is the remote one.
+ *
+ * Return the socket FD or a negative error code. On error, socket is marked as
+ * uninitialized.
+ */
+void qc_alloc_fd(struct quic_conn *qc, const struct sockaddr_storage *src,
+ const struct sockaddr_storage *dst)
+{
+ struct proxy *p = qc->li->bind_conf->frontend;
+ int fd = -1;
+ int ret;
+
+ /* Must not happen. */
+ BUG_ON(src->ss_family != dst->ss_family);
+
+ qc_init_fd(qc);
+
+ fd = socket(src->ss_family, SOCK_DGRAM, 0);
+ if (fd < 0)
+ goto err;
+
+ if (fd >= global.maxsock) {
+ send_log(p, LOG_EMERG,
+ "Proxy %s reached the configured maximum connection limit. Please check the global 'maxconn' value.\n",
+ p->id);
+ goto err;
+ }
+
+ ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
+ if (ret < 0)
+ goto err;
+
+ switch (src->ss_family) {
+ case AF_INET:
+#if defined(IP_PKTINFO)
+ ret = setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
+#elif defined(IP_RECVDSTADDR)
+ ret = setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &one, sizeof(one));
+#endif /* IP_PKTINFO || IP_RECVDSTADDR */
+ break;
+ case AF_INET6:
+#ifdef IPV6_RECVPKTINFO
+ ret = setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
+#endif
+ break;
+ }
+ if (ret < 0)
+ goto err;
+
+ ret = bind(fd, (struct sockaddr *)src, get_addr_len(src));
+ if (ret < 0)
+ goto err;
+
+ ret = connect(fd, (struct sockaddr *)dst, get_addr_len(dst));
+ if (ret < 0)
+ goto err;
+
+ qc->fd = fd;
+ fd_set_nonblock(fd);
+
+ return;
+
+ err:
+ if (fd >= 0)
+ close(fd);
+}
+
+/* Release socket file-descriptor specific for QUIC connection <qc>. */
+void qc_release_fd(struct quic_conn *qc)
+{
+ if (qc_test_fd(qc))
+ qc->fd = DEAD_FD_MAGIC;
+}
/*********************** QUIC accept queue management ***********************/
/* per-thread accept queues */