Skip to content

Commit

Permalink
udp: add support for ECN on Windows
Browse files Browse the repository at this point in the history
  • Loading branch information
stormshield-damiend committed Dec 21, 2023
1 parent e796eb2 commit 4cdb5ce
Show file tree
Hide file tree
Showing 7 changed files with 355 additions and 34 deletions.
1 change: 1 addition & 0 deletions quinn-proto/src/connection/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1209,6 +1209,7 @@ impl Connection {
/// Retrieving the local IP address is currently supported on the following
/// platforms:
/// - Linux
/// - Windows
///
/// On all non-supported platforms the local IP address will not be available,
/// and the method will return `None`.
Expand Down
3 changes: 2 additions & 1 deletion quinn-udp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@ socket2 = "0.5"
tracing = "0.1.10"

[target.'cfg(windows)'.dependencies]
windows-sys = { version = "0.52.0", features = ["Win32_Networking_WinSock"] }
windows-sys = { version = "0.52.0", features = ["Win32_Foundation", "Win32_System_IO", "Win32_Networking_WinSock"] }
once_cell = "1.19.0"
4 changes: 4 additions & 0 deletions quinn-udp/src/cmsg/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ use std::{
#[path = "unix.rs"]
mod imp;

#[cfg(windows)]
#[path = "windows.rs"]
mod imp;

pub(crate) use imp::Aligned;

/// Helper to encode a series of control messages (native "cmsgs") to a buffer for use in `sendmsg`
Expand Down
84 changes: 84 additions & 0 deletions quinn-udp/src/cmsg/windows.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use std::{
ffi::{c_int, c_uchar},
mem, ptr,
};

use windows_sys::Win32::Networking::WinSock;

use super::{CMsgHdr, MsgHdr};

#[derive(Copy, Clone)]
#[repr(align(8))] // Conservative bound for align_of<WinSock::CMSGHDR>
pub(crate) struct Aligned<T>(pub(crate) T);

/// Helpers for [`WinSock::WSAMSG`]
// https://learn.microsoft.com/en-us/windows/win32/api/ws2def/ns-ws2def-wsamsg
// https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/Networking/WinSock/struct.WSAMSG.html
impl MsgHdr for WinSock::WSAMSG {
type ControlMessage = WinSock::CMSGHDR;

fn cmsg_first_hdr(&self) -> *mut Self::ControlMessage {
if self.Control.len as usize >= mem::size_of::<WinSock::CMSGHDR>() {
self.Control.buf as *mut WinSock::CMSGHDR
} else {
ptr::null_mut::<WinSock::CMSGHDR>()
}
}

fn cmsg_nxt_hdr(&self, cmsg: &Self::ControlMessage) -> *mut Self::ControlMessage {
let next =
(cmsg as *const _ as usize + cmsghdr_align((*cmsg).cmsg_len)) as *mut WinSock::CMSGHDR;
let max = self.Control.buf as usize + self.Control.len as usize;
if unsafe { next.offset(1) } as usize > max {
ptr::null_mut()
} else {
next
}
}

fn set_control_len(&mut self, len: usize) {
self.Control.len = len as _;
}

fn control_len(&self) -> usize {
self.Control.len as _
}
}

/// Helpers for [`WinSock::CMSGHDR`]
// https://learn.microsoft.com/en-us/windows/win32/api/ws2def/ns-ws2def-wsacmsghdr
// https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/Networking/WinSock/struct.CMSGHDR.html
impl CMsgHdr for WinSock::CMSGHDR {
fn cmsg_len(length: usize) -> usize {
cmsgdata_align(mem::size_of::<WinSock::CMSGHDR>()) + length
}

fn cmsg_space(length: usize) -> usize {
cmsgdata_align(mem::size_of::<WinSock::CMSGHDR>() + cmsghdr_align(length))
}

fn cmsg_data(&self) -> *mut c_uchar {
(self as *const _ as usize + cmsgdata_align(mem::size_of::<WinSock::CMSGHDR>()))
as *mut c_uchar
}

fn set(&mut self, level: c_int, ty: c_int, len: usize) {
self.cmsg_level = level as _;
self.cmsg_type = ty as _;
self.cmsg_len = len as _;
}

fn len(&self) -> usize {
self.cmsg_len as _
}
}

// Helpers functions for `WinSock::WSAMSG` and `WinSock::CMSGHDR` are based on C macros from
// https://github.com/microsoft/win32metadata/blob/main/generation/WinSDK/RecompiledIdlHeaders/shared/ws2def.h#L741
fn cmsghdr_align(length: usize) -> usize {
(length + mem::align_of::<WinSock::CMSGHDR>() - 1) & !(mem::align_of::<WinSock::CMSGHDR>() - 1)
}

fn cmsgdata_align(length: usize) -> usize {
(length + mem::align_of::<usize>() - 1) & !(mem::align_of::<usize>() - 1)
}
3 changes: 2 additions & 1 deletion quinn-udp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ use std::{
use bytes::Bytes;
use tracing::warn;

#[cfg(unix)]
#[cfg(any(unix, windows))]
mod cmsg;

#[cfg(unix)]
#[path = "unix.rs"]
mod imp;
Expand Down
Loading

0 comments on commit 4cdb5ce

Please sign in to comment.