← Commit list

f2c03b1c40

Stefan Eissing
Stefan Eissing
2026-08-26
SUCCESS Duration: 426s

Subject

quic: upload improvements

Binary

No binary (build failed)

Architecture & Compiler Flags

Architecture: x86_64-linux-gnu Compiler: gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0

—

Build Log

(log yok)

Commit Diff GitHub →

CMake/unix-cache.cmake+1 -0
@@ -202,6 +202,7 @@ else()
set(HAVE_NETINET_IN6_H 0)
endif()
set(HAVE_NETINET_IN_H 1)
+set(HAVE_NETINET_IP_H 1)
set(HAVE_NETINET_TCP_H 1)
set(HAVE_NETINET_UDP_H 1)
set(HAVE_NET_IF_H 1)
CMake/win32-cache.cmake+1 -0
@@ -112,6 +112,7 @@ set(HAVE_MEMRCHR 0)
set(HAVE_NETDB_H 0)
set(HAVE_NETINET_IN6_H 0)
set(HAVE_NETINET_IN_H 0)
+set(HAVE_NETINET_IP_H 0)
set(HAVE_NETINET_TCP_H 0)
set(HAVE_NETINET_UDP_H 0)
set(HAVE_NET_IF_H 0)
CMakeLists.txt+1 -0
@@ -1567,6 +1567,7 @@ check_include_file_concat_curl("net/if.h" HAVE_NET_IF_H) # sys/select.h
check_include_file_concat_curl("netdb.h" HAVE_NETDB_H)
check_include_file_concat_curl("netinet/in.h" HAVE_NETINET_IN_H)
check_include_file("netinet/in6.h" HAVE_NETINET_IN6_H)
+check_include_file("netinet/ip.h" HAVE_NETINET_IP_H)
check_include_file_concat_curl("netinet/tcp.h" HAVE_NETINET_TCP_H) # sys/types.h (e.g. Cygwin) netinet/in.h
check_include_file_concat_curl("netinet/udp.h" HAVE_NETINET_UDP_H) # sys/types.h (e.g. Cygwin)
check_include_file("poll.h" HAVE_POLL_H)
configure.ac+1 -0
@@ -4035,6 +4035,7 @@ AC_CHECK_HEADERS(
linux/tcp.h \
netinet/tcp.h \
netinet/udp.h \
+ netinet/ip.h \
netdb.h \
sys/sockio.h \
sys/param.h \
lib/cf-socket.c+47 -0
@@ -37,6 +37,9 @@
#ifdef HAVE_NETINET_UDP_H
#include <netinet/udp.h>
#endif
+#ifdef HAVE_NETINET_IP_H
+#include <netinet/ip.h>
+#endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
@@ -1944,6 +1947,48 @@ static void linux_quic_gro(struct cf_socket_ctx *ctx)
#define linux_quic_gro(x)
#endif
+#if (defined(__linux__) || defined(__APPLE__)) && defined(IP_RECVTOS)
+static void linux_quic_ecn(struct cf_socket_ctx *ctx)
+{
+ unsigned int tos = 1;
+ switch(ctx->addr.family) {
+ case AF_INET:
+ (void)setsockopt(ctx->sock, IPPROTO_IP, IP_RECVTOS, &tos, sizeof(tos));
+ break;
+#ifdef IPV6_RECVTCLASS
+ case AF_INET6:
+ (void)setsockopt(ctx->sock, IPPROTO_IPV6, IPV6_RECVTCLASS,
+ &tos, sizeof(tos));
+ break;
+#endif
+ }
+}
+#else
+#define linux_quic_ecn(x)
+#endif
+
+#if (defined(__linux__) || defined(__APPLE__)) && defined(IP_DONTFRAG)
+static void linux_ip_dontfrag(struct cf_socket_ctx *ctx)
+{
+ int val = 1;
+
+ switch(ctx->addr.family) {
+ case AF_INET:
+ (void)setsockopt(ctx->sock, IPPROTO_IP, IP_DONTFRAG, &val, sizeof(val));
+ break;
+#ifdef IPV6_DONTFRAG
+ case AF_INET6:
+ (void)setsockopt(ctx->sock, IPPROTO_IPV6, IPV6_DONTFRAG,
+ &val, sizeof(val));
+ break;
+#endif
+ }
+}
+#else
+#define linux_ip_dontfrag(x)
+#endif
+
+
static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
@@ -1973,7 +2018,9 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
* non-blocking socket created by cf_socket_open() to it. Thus, we
* do not need to call curlx_nonblock() in cf_udp_setup_quic() anymore.
*/
+ linux_quic_ecn(ctx);
linux_quic_mtu(ctx);
+ linux_ip_dontfrag(ctx);
linux_quic_gro(ctx);
return CURLE_OK;
lib/curl_config-cmake.h.in+3 -0
@@ -424,6 +424,9 @@
/* Define to 1 if you have the <netinet/udp.h> header file. */
#cmakedefine HAVE_NETINET_UDP_H 1
+/* Define to 1 if you have the <netinet/ip.h> header file. */
+#cmakedefine HAVE_NETINET_IP_H 1
+
/* Define to 1 if you have the <linux/tcp.h> header file. */
#cmakedefine HAVE_LINUX_TCP_H 1
lib/vquic/cf-ngtcp2-cmn.c+4 -3
@@ -1640,7 +1640,7 @@ struct cf_ngtcp2_recv_ctx {
static CURLcode cf_ngtcp2_recv_pkts(const unsigned char *buf, size_t buflen,
size_t gso_size,
struct sockaddr_storage *remote_addr,
- socklen_t remote_addrlen, int ecn,
+ socklen_t remote_addrlen, uint8_t ecn,
void *userp)
{
struct cf_ngtcp2_recv_ctx *rctx = userp;
@@ -1658,7 +1658,7 @@ static CURLcode cf_ngtcp2_recv_pkts(const unsigned char *buf, size_t buflen,
if(ecn)
CURL_TRC_CF(pktx->data, pktx->cf, "vquic_recv(len=%zu, gso=%zu, ecn=%x)",
- buflen, gso_size, (unsigned int)ecn);
+ buflen, gso_size, (unsigned)ecn);
ngtcp2_addr_init(&path.local, (struct sockaddr *)&ctx->q.local_addr,
ctx->q.local_addrlen);
ngtcp2_addr_init(&path.remote, (struct sockaddr *)remote_addr,
@@ -1890,11 +1890,12 @@ CURLcode Curl_cf_ngtcp2_h3_stream_setup(struct Curl_cfilter *cf,
stream->id = -1;
stream->rx_offset = 0;
stream->rx_offset_max = H3_STREAM_WINDOW_SIZE_INITIAL;
+ stream->tx_in_flight_ideal = H3_STREAM_SEND_BUF_INITIAL;
/* on send, we control how much we put into the buffer */
Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp,
H3_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE);
- stream->sendbuf_len_in_flight = 0;
+ stream->tx_in_flight_size = 0;
stream->window_size_max = H3_STREAM_WINDOW_SIZE_INITIAL;
Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
lib/vquic/cf-ngtcp2-cmn.h+5 -1
@@ -93,6 +93,9 @@ struct cf_quic_ctx;
#define H3_STREAM_SEND_BUFFER_MAX (10 * 1024 * 1024)
#define H3_STREAM_SEND_CHUNKS \
(H3_STREAM_SEND_BUFFER_MAX / H3_STREAM_CHUNK_SIZE)
+/* How much data we initially want to buffer un-acked */
+#define H3_STREAM_SEND_BUF_INITIAL (32 * 1024)
+
#define QUIC_TUNNEL_INGRESS_PKT_LIMIT 1000
@@ -165,13 +168,14 @@ struct h3_stream_ctx {
int64_t id; /* HTTP/3 stream identifier */
struct bufq sendbuf; /* h3 request body */
struct h1_req_parser h1; /* h1 request parsing */
- size_t sendbuf_len_in_flight; /* sendbuf amount "in flight" */
uint64_t error3; /* HTTP/3 stream error code */
curl_off_t upload_left; /* number of request bytes left to upload */
curl_off_t rx_total; /* total number of bytes received */
uint64_t rx_offset; /* current receive offset */
uint64_t rx_offset_max; /* allowed receive offset */
uint64_t window_size_max; /* max flow control window set for stream */
+ size_t tx_in_flight_size; /* sendbuf data "in flight" */
+ size_t tx_in_flight_ideal; /* ideal amount of un-acked send data */
int status_code; /* HTTP status code */
CURLcode xfer_result; /* result from xfer_resp_write(_hd) */
BIT(resp_hds_complete); /* we have a complete, final response */
lib/vquic/cf-ngtcp2-proxy.c+9 -9
@@ -214,15 +214,15 @@ static int cb_h3_proxy_acked_req_body(nghttp3_conn *conn, int64_t stream_id,
/* The server acknowledged `datalen` of bytes from our request body.
* This is a delta. We have kept this data in `sendbuf` for
* re-transmissions and can free it now. */
- if(datalen >= (uint64_t)stream->sendbuf_len_in_flight)
- skiplen = stream->sendbuf_len_in_flight;
+ if(datalen >= (uint64_t)stream->tx_in_flight_size)
+ skiplen = stream->tx_in_flight_size;
else
skiplen = (size_t)datalen;
Curl_bufq_skip(&stream->sendbuf, skiplen);
- stream->sendbuf_len_in_flight -= skiplen;
+ stream->tx_in_flight_size -= skiplen;
/* Resume upload processing if we have more data to send */
- if(stream->sendbuf_len_in_flight < Curl_bufq_len(&stream->sendbuf)) {
+ if(stream->tx_in_flight_size < Curl_bufq_len(&stream->sendbuf)) {
int rv = nghttp3_conn_resume_stream(conn, stream_id);
if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
return NGHTTP3_ERR_CALLBACK_FAILURE;
@@ -568,21 +568,21 @@ static nghttp3_ssize cb_h3_tunnel_read_data(nghttp3_conn *conn,
/* nghttp3 keeps references to the sendbuf data until it is ACKed
* by the server (see `cb_h3_proxy_acked_req_body()` for updates).
- * `sendbuf_len_in_flight` is the amount of bytes in `sendbuf`
+ * `tx_in_flight_size` is the amount of bytes in `sendbuf`
* that we have already passed to nghttp3, but which have not been
* ACKed yet.
- * Any amount beyond `sendbuf_len_in_flight` we need still to pass
+ * Any amount beyond `tx_in_flight_size` we need still to pass
* to nghttp3. Do that now, if we can. */
- if(stream->sendbuf_len_in_flight < Curl_bufq_len(&stream->sendbuf)) {
+ if(stream->tx_in_flight_size < Curl_bufq_len(&stream->sendbuf)) {
nvecs = 0;
while(nvecs < veccnt) {
if(!Curl_bufq_peek_at(&stream->sendbuf,
- stream->sendbuf_len_in_flight,
+ stream->tx_in_flight_size,
&buf_base,
&vec[nvecs].len))
break;
vec[nvecs].base = (uint8_t *)(uintptr_t)buf_base;
- stream->sendbuf_len_in_flight += vec[nvecs].len;
+ stream->tx_in_flight_size += vec[nvecs].len;
nwritten += vec[nvecs].len;
++nvecs;
}
lib/vquic/cf-ngtcp2.c+38 -11
@@ -78,7 +78,8 @@ static CURLcode cf_ngtcp2_adjust_pollset(struct Curl_cfilter *cf,
c_exhaust = want_send && (!ngtcp2_conn_get_cwnd_left(ctx->qconn) ||
!ngtcp2_conn_get_max_data_left(ctx->qconn));
s_exhaust = want_send && stream && stream->id >= 0 &&
- stream->quic_flow_blocked;
+ (stream->quic_flow_blocked ||
+ stream->tx_in_flight_size >= stream->tx_in_flight_ideal);
want_recv = (want_recv || c_exhaust || s_exhaust);
want_send = (!s_exhaust && want_send) ||
!Curl_bufq_is_empty(&ctx->q.sendbuf);
@@ -577,15 +578,15 @@ static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id,
/* The server acknowledged `datalen` of bytes from our request body.
* This is a delta. We have kept this data in `sendbuf` for
* re-transmissions and can free it now. */
- if(datalen >= (uint64_t)stream->sendbuf_len_in_flight)
- skiplen = stream->sendbuf_len_in_flight;
+ if(datalen >= (uint64_t)stream->tx_in_flight_size)
+ skiplen = stream->tx_in_flight_size;
else
skiplen = (size_t)datalen;
Curl_bufq_skip(&stream->sendbuf, skiplen);
- stream->sendbuf_len_in_flight -= skiplen;
+ stream->tx_in_flight_size -= skiplen;
/* Resume upload processing if we have more data to send */
- if(stream->sendbuf_len_in_flight < Curl_bufq_len(&stream->sendbuf)) {
+ if(stream->tx_in_flight_size < Curl_bufq_len(&stream->sendbuf)) {
int rv = nghttp3_conn_resume_stream(conn, stream_id);
if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
return NGHTTP3_ERR_CALLBACK_FAILURE;
@@ -615,19 +616,19 @@ static nghttp3_ssize cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id,
return NGHTTP3_ERR_CALLBACK_FAILURE;
/* nghttp3 keeps references to the sendbuf data until it is ACKed
* by the server (see `cb_h3_acked_req_body()` for updates).
- * `sendbuf_len_in_flight` is the amount of bytes in `sendbuf`
+ * `tx_in_flight_size` is the amount of bytes in `sendbuf`
* that we have already passed to nghttp3, but which have not been
* ACKed yet.
- * Any amount beyond `sendbuf_len_in_flight` we need still to pass
+ * Any amount beyond `tx_in_flight_size` we need still to pass
* to nghttp3. Do that now, if we can. */
- if(stream->sendbuf_len_in_flight < Curl_bufq_len(&stream->sendbuf)) {
+ if(stream->tx_in_flight_size < Curl_bufq_len(&stream->sendbuf)) {
nvecs = 0;
while(nvecs < veccnt &&
Curl_bufq_peek_at(&stream->sendbuf,
- stream->sendbuf_len_in_flight,
+ stream->tx_in_flight_size,
CURL_UNCONST(&vec[nvecs].base),
&vec[nvecs].len)) {
- stream->sendbuf_len_in_flight += vec[nvecs].len;
+ stream->tx_in_flight_size += vec[nvecs].len;
nwritten += vec[nvecs].len;
++nvecs;
}
@@ -862,6 +863,10 @@ static CURLcode cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
result = CURLE_SEND_ERROR;
goto out;
}
+ else if(stream->tx_in_flight_size >= stream->tx_in_flight_ideal) {
+ result = CURLE_AGAIN;
+ goto out;
+ }
else {
result = Curl_bufq_write(&stream->sendbuf, buf, len, pnwritten);
CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send, add to "
@@ -878,6 +883,28 @@ static CURLcode cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
DEBUGASSERT(!result);
result = Curl_cf_ngtcp2_progress_egress(cf, data, &pktx);
+ if(*pnwritten > 0) {
+ const size_t delta = (2 * 1024);
+ if(stream->tx_in_flight_size > (stream->tx_in_flight_ideal + delta)) {
+ /* ngtcp2 keeps more in flight than we try to provide for,
+ * increase our "ideal" tx buffer length */
+ stream->tx_in_flight_ideal += delta;
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send(%zu), added %zu, "
+ "inflight=%zu, increase tx_win=%zu",
+ stream->id, len, *pnwritten,
+ stream->tx_in_flight_size, stream->tx_in_flight_ideal);
+ }
+ else if((stream->tx_in_flight_size + delta) < stream->tx_in_flight_ideal) {
+ /* ngtcp2 keeps less in flight than we try to provide for,
+ * decrease our "ideal" tx buffer length */
+ stream->tx_in_flight_ideal -= delta;
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send(%zu), added %zu, "
+ "inflight=%zu, reduce tx_win=%zu",
+ stream->id, len, *pnwritten,
+ stream->tx_in_flight_size, stream->tx_in_flight_ideal);
+ }
+ }
+
out:
result = Curl_1st_fatal(result,
Curl_cf_ngtcp2_cmn_set_expiry(cf, data, &pktx));
@@ -925,7 +952,7 @@ static CURLcode cf_ngtcp2_cntrl(struct Curl_cfilter *cf,
if(stream && !stream->send_closed) {
stream->send_closed = TRUE;
stream->upload_left = Curl_bufq_len(&stream->sendbuf) -
- stream->sendbuf_len_in_flight;
+ stream->tx_in_flight_size;
(void)nghttp3_conn_resume_stream(ctx->h3conn, stream->id);
}
break;
lib/vquic/cf-quiche.c+1 -1
@@ -652,7 +652,7 @@ struct recv_ctx {
static CURLcode cf_quiche_recv_pkts(const unsigned char *buf, size_t buflen,
size_t gso_size,
struct sockaddr_storage *remote_addr,
- socklen_t remote_addrlen, int ecn,
+ socklen_t remote_addrlen, uint8_t ecn,
void *userp)
{
struct recv_ctx *r = userp;
lib/vquic/vquic.c+86 -12
@@ -33,6 +33,9 @@
#ifdef HAVE_NETINET_UDP_H
#include <netinet/udp.h>
#endif
+#ifdef HAVE_NETINET_IP_H
+#include <netinet/ip.h>
+#endif
#ifdef USE_NGHTTP3
#include <nghttp3/nghttp3.h>
@@ -66,6 +69,8 @@
#define NW_SEND_CHUNKS 1
#ifdef HAVE_APPLE_MSG_X
+
+/* this is `struct msghdr` with an additional field at the end */
struct msghdr_x {
void *msg_name; /* optional address */
socklen_t msg_namelen; /* size of address */
@@ -552,14 +557,72 @@ static size_t vquic_msghdr_get_udp_gro(struct msghdr *msg)
break;
}
}
-#endif
+#endif /* linux && UDP_GRO */
(void)msg;
return (size_t)gso_size;
}
+#endif /* (HAVE_SENDMMSG || HAVE_SENDMSG) && !HAVE_APPLE_MSG_X */
+
+#if (defined(HAVE_SENDMMSG) || defined(HAVE_SENDMSG) || \
+ defined(HAVE_APPLE_MSG_X)) && \
+ (defined(IP_RECVTOS) || defined(IP_TOS)) && defined(IPTOS_ECN_MASK)
+static uint8_t vquic_msghdr_get_ecn(struct msghdr *msg, int family)
+{
+ struct cmsghdr *cmsg;
+ switch(family) {
+ case AF_INET:
+ /* Workaround musl CMSG_NXTHDR issue */
+#if defined(__clang__) && !defined(__GLIBC__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wsign-compare"
+#pragma clang diagnostic ignored "-Wcast-align"
+#endif
+ for(cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+#if defined(__clang__) && !defined(__GLIBC__)
+#pragma clang diagnostic pop
#endif
+ if(cmsg->cmsg_level == IPPROTO_IP &&
+#ifdef __APPLE__
+ cmsg->cmsg_type == IP_RECVTOS
+#else
+ cmsg->cmsg_type == IP_TOS
+#endif
+ && cmsg->cmsg_len) {
+ return *(uint8_t *)(CMSG_DATA(cmsg)) & IPTOS_ECN_MASK;
+ }
+ }
+ break;
+ case AF_INET6:
+ /* Workaround musl CMSG_NXTHDR issue */
+#if defined(__clang__) && !defined(__GLIBC__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wsign-compare"
+#pragma clang diagnostic ignored "-Wcast-align"
+#endif
+ for(cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+#if defined(__clang__) && !defined(__GLIBC__)
+#pragma clang diagnostic pop
+#endif
+ if(cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_TCLASS &&
+ cmsg->cmsg_len) {
+ unsigned int tos;
+
+ memcpy(&tos, CMSG_DATA(cmsg), sizeof(int));
+
+ return (uint8_t)(tos & IPTOS_ECN_MASK);
+ }
+ }
+ break;
+ }
+ return 0;
+}
+#else
+#define vquic_msghdr_get_ecn(a,b) 0
+#endif /* HAVE_SENDMMSG || HAVE_SENDMSG || HAVE_APPLE_MSG_X ... */
#ifdef HAVE_SENDMMSG
+
static CURLcode recvmmsg_packets(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct cf_quic_ctx *qctx,
@@ -569,14 +632,16 @@ static CURLcode recvmmsg_packets(struct Curl_cfilter *cf,
#if defined(__linux__) && defined(UDP_GRO)
#define MMSG_NUM 16
#define UDP_GRO_CNT_MAX 64
+#define CMSG_PER_MSG_SIZE (2 * CMSG_SPACE(sizeof(int)))
#else
#define MMSG_NUM 64
#define UDP_GRO_CNT_MAX 1
+#define CMSG_PER_MSG_SIZE CMSG_SPACE(sizeof(int))
#endif
#define MSG_BUF_SIZE (UDP_GRO_CNT_MAX * 1500)
struct iovec msg_iov[MMSG_NUM];
struct mmsghdr mmsg[MMSG_NUM];
- uint8_t msg_ctrl[MMSG_NUM * CMSG_SPACE(sizeof(int))];
+ uint8_t msg_ctrl[MMSG_NUM * CMSG_PER_MSG_SIZE];
struct sockaddr_storage remote_addr[MMSG_NUM];
size_t total_nread = 0, pkts = 0;
#ifdef CURLVERBOSE
@@ -588,6 +653,7 @@ static CURLcode recvmmsg_packets(struct Curl_cfilter *cf,
size_t gso_size;
char *sockbuf = NULL;
uint8_t (*bufs)[MSG_BUF_SIZE] = NULL;
+ uint8_t ecn = 0;
DEBUGASSERT(max_pkts > 0);
result = Curl_multi_xfer_sockbuf_borrow(data, MMSG_NUM * MSG_BUF_SIZE,
@@ -607,8 +673,8 @@ static CURLcode recvmmsg_packets(struct Curl_cfilter *cf,
mmsg[i].msg_hdr.msg_iovlen = 1;
mmsg[i].msg_hdr.msg_name = &remote_addr[i];
mmsg[i].msg_hdr.msg_namelen = sizeof(remote_addr[i]);
- mmsg[i].msg_hdr.msg_control = &msg_ctrl[i * CMSG_SPACE(sizeof(int))];
- mmsg[i].msg_hdr.msg_controllen = CMSG_SPACE(sizeof(int));
+ mmsg[i].msg_hdr.msg_control = &msg_ctrl[i * CMSG_PER_MSG_SIZE];
+ mmsg[i].msg_hdr.msg_controllen = CMSG_PER_MSG_SIZE;
}
while((mcount = recvmmsg(qctx->sockfd, mmsg, n, 0, NULL)) == -1 &&
@@ -643,13 +709,14 @@ static CURLcode recvmmsg_packets(struct Curl_cfilter *cf,
}
total_nread += mmsg[i].msg_len;
+ ecn = vquic_msghdr_get_ecn(&mmsg[i].msg_hdr, remote_addr[i].ss_family);
gso_size = vquic_msghdr_get_udp_gro(&mmsg[i].msg_hdr);
if(gso_size == 0)
gso_size = mmsg[i].msg_len;
result = recv_cb(bufs[i], mmsg[i].msg_len, gso_size,
mmsg[i].msg_hdr.msg_name,
- mmsg[i].msg_hdr.msg_namelen, 0, userp);
+ mmsg[i].msg_hdr.msg_namelen, ecn, userp);
if(result)
goto out;
pkts += (mmsg[i].msg_len + gso_size - 1) / gso_size;
@@ -676,9 +743,10 @@ static CURLcode recvmsg_x_packets(struct Curl_cfilter *cf,
{
#define MSG_X_NUM 64
#define MSG_BUF_SIZE (2048)
+#define CMSG_PER_MSG_SIZE CMSG_SPACE(sizeof(int))
struct iovec msg_iov[MSG_X_NUM];
struct msghdr_x mmsg[MSG_X_NUM];
- uint8_t msg_ctrl[MSG_X_NUM * CMSG_SPACE(sizeof(int))];
+ uint8_t msg_ctrl[MSG_X_NUM * CMSG_PER_MSG_SIZE];
struct sockaddr_storage remote_addr[MSG_X_NUM];
size_t total_nread = 0, pkts = 0;
#ifdef CURLVERBOSE
@@ -690,6 +758,7 @@ static CURLcode recvmsg_x_packets(struct Curl_cfilter *cf,
size_t gso_size;
char *sockbuf = NULL;
uint8_t (*bufs)[MSG_BUF_SIZE] = NULL;
+ uint8_t ecn = 0;
DEBUGASSERT(max_pkts > 0);
result = Curl_multi_xfer_sockbuf_borrow(data, MSG_X_NUM * MSG_BUF_SIZE,
@@ -709,8 +778,8 @@ static CURLcode recvmsg_x_packets(struct Curl_cfilter *cf,
mmsg[i].msg_iovlen = 1;
mmsg[i].msg_name = &remote_addr[i];
mmsg[i].msg_namelen = sizeof(remote_addr[i]);
- mmsg[i].msg_control = &msg_ctrl[i * CMSG_SPACE(sizeof(int))];
- mmsg[i].msg_controllen = CMSG_SPACE(sizeof(int));
+ mmsg[i].msg_control = &msg_ctrl[i * CMSG_PER_MSG_SIZE];
+ mmsg[i].msg_controllen = CMSG_PER_MSG_SIZE;
}
#if defined(CURL_HAVE_DIAG) && defined(__APPLE__)
@@ -751,11 +820,13 @@ static CURLcode recvmsg_x_packets(struct Curl_cfilter *cf,
continue;
}
total_nread += mmsg[i].msg_datalen;
+ ecn = vquic_msghdr_get_ecn((struct msghdr *)&mmsg[i],
+ remote_addr[i].ss_family);
gso_size = mmsg[i].msg_datalen;
result = recv_cb(bufs[i], mmsg[i].msg_datalen, gso_size,
mmsg[i].msg_name,
- mmsg[i].msg_namelen, 0, userp);
+ mmsg[i].msg_namelen, ecn, userp);
if(result)
goto out;
pkts += (mmsg[i].msg_datalen + gso_size - 1) / gso_size;
@@ -778,6 +849,7 @@ static CURLcode recvmsg_packets(struct Curl_cfilter *cf,
size_t max_pkts,
Curl_vquic_recv_pkts_cb *recv_cb, void *userp)
{
+#define CMSG_PER_MSG_SIZE CMSG_SPACE(sizeof(int))
struct iovec msg_iov;
struct msghdr msg;
uint8_t buf[64 * 1024];
@@ -787,8 +859,9 @@ static CURLcode recvmsg_packets(struct Curl_cfilter *cf,
size_t nread;
char errstr[STRERROR_LEN];
CURLcode result = CURLE_OK;
- uint8_t msg_ctrl[CMSG_SPACE(sizeof(int))];
+ uint8_t msg_ctrl[CMSG_PER_MSG_SIZE];
size_t gso_size;
+ uint8_t ecn = 0;
DEBUGASSERT(max_pkts > 0);
for(pkts = 0, total_nread = 0, calls = 0; pkts < max_pkts;) {
@@ -802,7 +875,7 @@ static CURLcode recvmsg_packets(struct Curl_cfilter *cf,
msg.msg_control = msg_ctrl;
msg.msg_name = &remote_addr;
msg.msg_namelen = sizeof(remote_addr);
- msg.msg_controllen = sizeof(msg_ctrl);
+ msg.msg_controllen = CMSG_PER_MSG_SIZE;
while((rc = recvmsg(qctx->sockfd, &msg, 0)) == -1 &&
(SOCKERRNO == SOCKEINTR || SOCKERRNO == SOCKEMSGSIZE))
@@ -835,12 +908,13 @@ static CURLcode recvmsg_packets(struct Curl_cfilter *cf,
continue;
}
+ ecn = vquic_msghdr_get_ecn(&msg, remote_addr.ss_family);
gso_size = vquic_msghdr_get_udp_gro(&msg);
if(gso_size == 0)
gso_size = nread;
result = recv_cb(buf, nread, gso_size,
- msg.msg_name, msg.msg_namelen, 0, userp);
+ msg.msg_name, msg.msg_namelen, ecn, userp);
if(result)
goto out;
pkts += (nread + gso_size - 1) / gso_size;
lib/vquic/vquic_int.h+1 -1
@@ -105,7 +105,7 @@ typedef CURLcode Curl_vquic_recv_pkts_cb(const unsigned char *buf,
size_t buflen,
size_t gso_size,
struct sockaddr_storage *remote_addr,
- socklen_t remote_addrlen, int ecn,
+ socklen_t remote_addrlen, uint8_t ecn,
void *userp);
CURLcode Curl_vquic_recv_packets(struct Curl_cfilter *cf,