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 19, 2023
1 parent 046a228 commit 3e81595
Show file tree
Hide file tree
Showing 7 changed files with 416 additions and 47 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 traits for native types for control messages
Expand Down
112 changes: 112 additions & 0 deletions quinn-udp/src/cmsg/windows.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
use std::ffi::{c_int, c_uchar};

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 control_len(&self) -> usize {
self.Control.len as _
}

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

fn cmsg_firsthdr(&self) -> *mut Self::ControlMessage {
unsafe { self::wsa2::cmsg_firsthdr(self) }
}

fn cmsg_nxthdr(&self, cmsg: &Self::ControlMessage) -> *mut Self::ControlMessage {
unsafe { self::wsa2::cmsg_nxthdr(self, cmsg) }
}
}

/// 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 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 _
}

fn cmsg_space(length: usize) -> usize {
self::wsa2::cmsg_space(length)
}

fn cmsg_len(length: usize) -> usize {
self::wsa2::cmsg_len(length)
}

fn cmsg_data(&self) -> *mut c_uchar {
unsafe { self::wsa2::cmsg_data(self) }
}
}

mod wsa2 {
use std::{mem, ptr};

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

// Helpers functions 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)
}

pub(crate) unsafe fn cmsg_firsthdr(msg: *const WinSock::WSAMSG) -> *mut WinSock::CMSGHDR {
if (*msg).Control.len as usize >= mem::size_of::<WinSock::CMSGHDR>() {
(*msg).Control.buf as *mut WinSock::CMSGHDR
} else {
ptr::null_mut::<WinSock::CMSGHDR>()
}
}

pub(crate) unsafe fn cmsg_nxthdr(
hdr: &WinSock::WSAMSG,
cmsg: *const WinSock::CMSGHDR,
) -> *mut WinSock::CMSGHDR {
if cmsg.is_null() {
return cmsg_firsthdr(hdr);
}
let next = (cmsg as usize + cmsghdr_align((*cmsg).cmsg_len)) as *mut WinSock::CMSGHDR;
let max = hdr.Control.buf as usize + hdr.Control.len as usize;
if (next.offset(1)) as usize > max {
ptr::null_mut()
} else {
next
}
}

pub(crate) unsafe fn cmsg_data(cmsg: *const WinSock::CMSGHDR) -> *mut u8 {
(cmsg as usize + cmsgdata_align(mem::size_of::<WinSock::CMSGHDR>())) as *mut u8
}

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

pub(crate) fn cmsg_len(length: usize) -> usize {
cmsgdata_align(mem::size_of::<WinSock::CMSGHDR>()) + length
}
}
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 3e81595

Please sign in to comment.