From 24360415577b320c954687c65003a6758be1eab1 Mon Sep 17 00:00:00 2001
From: Max Inden <mail@max-inden.de>
Date: Mon, 16 Dec 2024 11:40:13 +0100
Subject: [PATCH] fix(udp): make GRO (i.e. URO) optional, off by default

We have multiple bug reports for URO on Windows, including non-ARM. See:

- https://github.com/quinn-rs/quinn/issues/2041
- https://bugzilla.mozilla.org/show_bug.cgi?id=1916558

Instead of enabling GRO on Windows by default, this commit changes the default
to off, adding a `set_gro` to optionally enable it.
---
 quinn-udp/src/windows.rs | 34 +++++++++++++++++++++++-----------
 1 file changed, 23 insertions(+), 11 deletions(-)

diff --git a/quinn-udp/src/windows.rs b/quinn-udp/src/windows.rs
index 223ab0fdf6..0af3c5021e 100644
--- a/quinn-udp/src/windows.rs
+++ b/quinn-udp/src/windows.rs
@@ -107,23 +107,35 @@ impl UdpSocketState {
             )?;
         }
 
-        // Opportunistically try to enable GRO
-        _ = set_socket_option(
-            &*socket.0,
-            WinSock::IPPROTO_UDP,
-            WinSock::UDP_RECV_MAX_COALESCED_SIZE,
-            // u32 per
-            // https://learn.microsoft.com/en-us/windows/win32/winsock/ipproto-udp-socket-options.
-            // Choice of 2^16 - 1 inspired by msquic.
-            u16::MAX as u32,
-        );
-
         let now = Instant::now();
         Ok(Self {
             last_send_error: Mutex::new(now.checked_sub(2 * IO_ERROR_LOG_INTERVAL).unwrap_or(now)),
         })
     }
 
+    /// Enable or disable receive offloading.
+    ///
+    /// Also referred to as UDP Receive Segment Coalescing Offload (URO) on Windows.
+    ///
+    /// <https://learn.microsoft.com/en-us/windows-hardware/drivers/network/udp-rsc-offload>
+    ///
+    /// Disabled by default due to <https://github.com/quinn-rs/quinn/issues/2041>.
+    pub fn set_gro(&self, enable: bool) -> io::Result<()> {
+        set_socket_option(
+            &*socket.0,
+            WinSock::IPPROTO_UDP,
+            WinSock::UDP_RECV_MAX_COALESCED_SIZE,
+            if enable {
+                // u32 per
+                // https://learn.microsoft.com/en-us/windows/win32/winsock/ipproto-udp-socket-options.
+                // Choice of 2^16 - 1 inspired by msquic.
+                u16::MAX as u32
+            } else {
+                0
+            },
+        )
+    }
+
     /// Sends a [`Transmit`] on the given socket.
     ///
     /// This function will only ever return errors of kind [`io::ErrorKind::WouldBlock`].