fix: evaluate max_gso_segments for every socket on Windows

This follows the behaviour we have for UNIX-based systems. Support for
GSO varies depending on the network driver which may change at runtime
when e.g. a device switches between Ethernet and WiFi or gets plugged
into a docking station.

Resolves: #2491
This commit is contained in:
Thomas Eizinger
2026-03-10 15:53:33 +11:00
committed by Dirkjan Ochtman
parent c67e9d8930
commit 41bf1db60d
+10 -11
View File
@@ -4,7 +4,10 @@ use std::{
net::{IpAddr, Ipv4Addr},
os::windows::io::AsRawSocket,
ptr,
sync::{LazyLock, Mutex},
sync::{
LazyLock, Mutex,
atomic::{AtomicUsize, Ordering},
},
time::Instant,
};
@@ -24,6 +27,7 @@ use crate::{
#[derive(Debug)]
pub struct UdpSocketState {
last_send_error: Mutex<Instant>,
max_gso_segments: AtomicUsize,
/// Whether the underlying Winsock provider supports IPv4 ECN socket options/control messages.
///
@@ -153,6 +157,7 @@ impl UdpSocketState {
let now = Instant::now();
Ok(Self {
last_send_error: Mutex::new(now.checked_sub(2 * IO_ERROR_LOG_INTERVAL).unwrap_or(now)),
max_gso_segments: AtomicUsize::new(max_gso_segments(&*socket.0)),
ecn_v4_supported,
ecn_v6_supported,
})
@@ -332,7 +337,7 @@ impl UdpSocketState {
/// while using GSO.
#[inline]
pub fn max_gso_segments(&self) -> usize {
*MAX_GSO_SEGMENTS
self.max_gso_segments.load(Ordering::Relaxed)
}
/// The number of segments to read when GRO is enabled. Used as a factor to
@@ -552,16 +557,10 @@ static WSARECVMSG_PTR: LazyLock<WinSock::LPFN_WSARECVMSG> = LazyLock::new(|| {
wsa_recvmsg_ptr
});
static MAX_GSO_SEGMENTS: LazyLock<usize> = LazyLock::new(|| {
let socket = match std::net::UdpSocket::bind("[::]:0")
.or_else(|_| std::net::UdpSocket::bind((Ipv4Addr::LOCALHOST, 0)))
{
Ok(socket) => socket,
Err(_) => return 1,
};
fn max_gso_segments(socket: &impl AsRawSocket) -> usize {
const GSO_SIZE: c_uint = 1500;
match set_socket_option(
&socket,
socket,
WinSock::IPPROTO_UDP,
WinSock::UDP_SEND_MSG_SIZE,
GSO_SIZE,
@@ -570,4 +569,4 @@ static MAX_GSO_SEGMENTS: LazyLock<usize> = LazyLock::new(|| {
Ok(()) => 512,
Err(_) => 1,
}
});
}