]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
apple-fast-udp: fix sendmsg_x partial results master
authorStefan Eissing <stefan@eissing.org>
Wed, 29 Jul 2026 11:11:20 +0000 (13:11 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 30 Jul 2026 20:55:04 +0000 (22:55 +0200)
When sending with sendmsg_x(), fix handling of last gso chunk being
smaller. Handle partial results correctly. Ignore SOCKEMSGSIZE by
reporting success which drops PMTUD probes into the void.

Closes #22429

lib/vquic/vquic.c

index 384935f87a78e0c6fa8107b3968b1c9e1dfc15d3..3844f4e88a591a692497927a82622fcfc8d27fae 100644 (file)
@@ -179,16 +179,18 @@ static CURLcode do_sendmsg(struct Curl_cfilter *cf,
     return CURLE_OK;
   if(!gsolen || (pktlen < gsolen))
     gsolen = pktlen;
-  n = pktlen / gsolen;
+  n = (pktlen + gsolen - 1) / gsolen;
   while(i < n) {
-    size_t j, batch = CURLMIN(n - i, MSG_X_SNUM);
+    size_t j, batch = CURLMIN(n - i, MSG_X_SNUM), pkts_sent = 0;
 
     for(j = 0; j < batch; ++j) {
-      msg_iov[j].iov_base = CURL_UNCONST(&pkt[(i + j) * gsolen]);
-      msg_iov[j].iov_len = gsolen;
+      const size_t offset = (i + j) * gsolen;
+      msg_iov[j].iov_base = CURL_UNCONST(pkt + offset);
+      msg_iov[j].iov_len = CURLMIN(gsolen, pktlen - offset);
       memset(&mmsg[j], 0, sizeof(mmsg[j]));
       mmsg[j].msg_iov = &msg_iov[j];
       mmsg[j].msg_iovlen = 1;
+      mmsg[j].msg_datalen = msg_iov[j].iov_len;
     }
 
 #if defined(CURL_HAVE_DIAG) && defined(__APPLE__)
@@ -196,27 +198,43 @@ static CURLcode do_sendmsg(struct Curl_cfilter *cf,
 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
 #endif
     while((rc = syscall(SYS_sendmsg_x, qctx->sockfd, &mmsg, batch, 0)) == -1 &&
-          (SOCKERRNO == SOCKEINTR || SOCKERRNO == SOCKEMSGSIZE))
+          (SOCKERRNO == SOCKEINTR))
       ;
 #if defined(CURL_HAVE_DIAG) && defined(__APPLE__)
 #pragma GCC diagnostic pop
 #endif
 
-    if(rc == -1) {
+    if(rc < 0) {
       if(SOCK_EAGAIN(SOCKERRNO)) {
         CURL_TRC_CF(data, cf, "egress, sendmsg_x -> EAGAIN");
         result = sent ? CURLE_OK : CURLE_AGAIN;
         goto out;
       }
-      curlx_strerror(SOCKERRNO, errstr, sizeof(errstr));
-      failf(data, "QUIC: sendmsg_x() unexpectedly returned %d (errno=%d; %s)",
-            rc, SOCKERRNO, errstr);
-      result = CURLE_RECV_ERROR;
-      goto out;
+      if(SOCKERRNO != SOCKEMSGSIZE) {
+        curlx_strerror(SOCKERRNO, errstr, sizeof(errstr));
+        failf(data, "QUIC: sendmsg_x() returned %d (errno=%d; %s)",
+              rc, SOCKERRNO, errstr);
+        result = CURLE_SEND_ERROR;
+        goto out;
+      }
+      /* Error was SOCKEMSGSIZE. Network stack does not accept the packet
+       * length(s). This might be a PMTUD. Just drop it into the void
+       * and fall through to the success handling. */
+      pkts_sent = batch;
     }
+    else
+      pkts_sent = CURLMIN((size_t)rc, batch);
+
     VERBOSE(++calls);
-    i += batch;
-    sent += (batch * gsolen);
+    if(!pkts_sent) {  /* no packets of the current batch were sent */
+      result = sent ? CURLE_OK : CURLE_AGAIN;
+      goto out;
+    }
+    i += pkts_sent; /* Some have been sent */
+    for(j = 0; j < pkts_sent; ++j)
+      sent += msg_iov[j].iov_len;
+    if(pkts_sent < batch)
+      goto out; /* but not all of them */
   }
 
 out: