diff --git a/quinn-udp/src/windows.rs b/quinn-udp/src/windows.rs index c003cf80c..6d4e5cc76 100644 --- a/quinn-udp/src/windows.rs +++ b/quinn-udp/src/windows.rs @@ -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, + 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 = LazyLock::new(|| { wsa_recvmsg_ptr }); -static MAX_GSO_SEGMENTS: LazyLock = 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 = LazyLock::new(|| { Ok(()) => 512, Err(_) => 1, } -}); +}