#include "curl_setup.h"
+#ifdef HAVE_NETINET_UDP_H
+#include <netinet/udp.h>
+#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
return vquic_flush(cf, data, qctx);
}
+#if defined(HAVE_SENDMMSG) || defined(HAVE_SENDMSG)
+static size_t msghdr_get_udp_gro(struct msghdr *msg)
+{
+ uint16_t gso_size = 0;
+#ifdef UDP_GRO
+ struct cmsghdr *cmsg;
+
+ /* Workaround musl CMSG_NXTHDR issue */
+#ifndef __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)) {
+#ifndef __GLIBC__
+#pragma clang diagnostic pop
+#endif
+ if(cmsg->cmsg_level == SOL_UDP && cmsg->cmsg_type == UDP_GRO) {
+ memcpy(&gso_size, CMSG_DATA(cmsg), sizeof(gso_size));
+
+ break;
+ }
+ }
+#endif
+ (void)msg;
+
+ return gso_size;
+}
+#endif
+
#ifdef HAVE_SENDMMSG
static CURLcode recvmmsg_packets(struct Curl_cfilter *cf,
struct Curl_easy *data,
#define MMSG_NUM 64
struct iovec msg_iov[MMSG_NUM];
struct mmsghdr mmsg[MMSG_NUM];
+ uint8_t msg_ctrl[MMSG_NUM * CMSG_SPACE(sizeof(uint16_t))];
uint8_t bufs[MMSG_NUM][2*1024];
struct sockaddr_storage remote_addr[MMSG_NUM];
size_t total_nread, pkts;
int mcount, i, n;
char errstr[STRERROR_LEN];
CURLcode result = CURLE_OK;
+ size_t gso_size;
+ size_t pktlen;
+ size_t offset, to;
DEBUGASSERT(max_pkts > 0);
pkts = 0;
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];
+ mmsg[i].msg_hdr.msg_controllen = CMSG_SPACE(sizeof(uint16_t));
}
while((mcount = recvmmsg(qctx->sockfd, mmsg, n, 0, NULL)) == -1 &&
}
CURL_TRC_CF(data, cf, "recvmmsg() -> %d packets", mcount);
- pkts += mcount;
for(i = 0; i < mcount; ++i) {
total_nread += mmsg[i].msg_len;
- result = recv_cb(bufs[i], mmsg[i].msg_len,
- mmsg[i].msg_hdr.msg_name, mmsg[i].msg_hdr.msg_namelen,
- 0, userp);
- if(result)
- goto out;
+
+ gso_size = msghdr_get_udp_gro(&mmsg[i].msg_hdr);
+ if(gso_size == 0) {
+ gso_size = mmsg[i].msg_len;
+ }
+
+ for(offset = 0; offset < mmsg[i].msg_len; offset = to) {
+ ++pkts;
+
+ to = offset + gso_size;
+ if(to > mmsg[i].msg_len) {
+ pktlen = mmsg[i].msg_len - offset;
+ }
+ else {
+ pktlen = gso_size;
+ }
+
+ result = recv_cb(bufs[i] + offset, pktlen, mmsg[i].msg_hdr.msg_name,
+ mmsg[i].msg_hdr.msg_namelen, 0, userp);
+ if(result)
+ goto out;
+ }
}
}
ssize_t nread;
char errstr[STRERROR_LEN];
CURLcode result = CURLE_OK;
+ uint8_t msg_ctrl[CMSG_SPACE(sizeof(uint16_t))];
+ size_t gso_size;
+ size_t pktlen;
+ size_t offset, to;
msg_iov.iov_base = buf;
msg_iov.iov_len = (int)sizeof(buf);
memset(&msg, 0, sizeof(msg));
msg.msg_iov = &msg_iov;
msg.msg_iovlen = 1;
+ msg.msg_control = msg_ctrl;
DEBUGASSERT(max_pkts > 0);
for(pkts = 0, total_nread = 0; pkts < max_pkts;) {
msg.msg_name = &remote_addr;
msg.msg_namelen = sizeof(remote_addr);
+ msg.msg_controllen = sizeof(msg_ctrl);
while((nread = recvmsg(qctx->sockfd, &msg, 0)) == -1 &&
SOCKERRNO == EINTR)
;
goto out;
}
- ++pkts;
total_nread += (size_t)nread;
- result = recv_cb(buf, (size_t)nread, msg.msg_name, msg.msg_namelen,
- 0, userp);
- if(result)
- goto out;
+
+ gso_size = msghdr_get_udp_gro(&msg);
+ if(gso_size == 0) {
+ gso_size = (size_t)nread;
+ }
+
+ for(offset = 0; offset < (size_t)nread; offset = to) {
+ ++pkts;
+
+ to = offset + gso_size;
+ if(to > (size_t)nread) {
+ pktlen = (size_t)nread - offset;
+ }
+ else {
+ pktlen = gso_size;
+ }
+
+ result =
+ recv_cb(buf + offset, pktlen, msg.msg_name, msg.msg_namelen, 0, userp);
+ if(result)
+ goto out;
+ }
}
out: