quic: upload improvements
No binary (build failed)
—
(log yok)
| @@ -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) | |
| @@ -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) | |
| @@ -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) | |
| @@ -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 \ | |
| @@ -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; | |
| @@ -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 | |
| @@ -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); | |
| @@ -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 */ | |
| @@ -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; | |
| } | |
| @@ -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; | |
| @@ -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; | |
| @@ -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; | |
| @@ -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, | |