Skip to content

Commit

Permalink
refactor(s2n-quic-platform): move pktinfo checks to separate modules
Browse files Browse the repository at this point in the history
  • Loading branch information
camshaft committed Feb 16, 2024
1 parent 311ece3 commit d8b061b
Show file tree
Hide file tree
Showing 15 changed files with 952 additions and 568 deletions.
5 changes: 5 additions & 0 deletions quic/s2n-quic-platform/src/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ type c_int = std::os::raw::c_int;

pub mod gro;
pub mod gso;
pub mod pktinfo;
pub mod pktinfo_v4;
pub mod pktinfo_v6;
pub mod tos;
pub mod tos_v4;
pub mod tos_v6;

pub use gso::Gso;
4 changes: 4 additions & 0 deletions quic/s2n-quic-platform/src/features/pktinfo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

pub const IS_SUPPORTED: bool = super::pktinfo_v4::IS_SUPPORTED || super::pktinfo_v6::IS_SUPPORTED;
105 changes: 105 additions & 0 deletions quic/s2n-quic-platform/src/features/pktinfo_v4.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use super::c_int;
use s2n_quic_core::inet::IpV4Address;

#[cfg(s2n_quic_platform_pktinfo)]
mod pktinfo_enabled {
use super::*;
use crate::message::cmsg;
use libc::{IPPROTO_IP, IP_PKTINFO};

pub const LEVEL: Option<c_int> = Some(IPPROTO_IP as _);
pub const TYPE: Option<c_int> = Some(IP_PKTINFO as _);
pub const SOCKOPT: Option<(c_int, c_int)> = Some((IPPROTO_IP as _, IP_PKTINFO as _));
pub const CMSG_SPACE: usize = crate::message::cmsg::size_of_cmsg::<Cmsg>();

pub type Cmsg = libc::in_pktinfo;

#[inline]
pub const fn is_match(level: c_int, ty: c_int) -> bool {
level == IPPROTO_IP as c_int && ty == IP_PKTINFO as c_int
}

/// # Safety
///
/// * The provided bytes must be aligned to `cmsghdr`
#[inline]
pub unsafe fn decode(bytes: &[u8]) -> Option<(IpV4Address, u32)> {
let pkt_info = cmsg::decode::value_from_bytes::<Cmsg>(bytes)?;

// read from both fields in case only one is set and not the other
//
// from https://man7.org/linux/man-pages/man7/ip.7.html:
//
// > ipi_spec_dst is the local address
// > of the packet and ipi_addr is the destination address in
// > the packet header.
let local_address = match (pkt_info.ipi_addr.s_addr, pkt_info.ipi_spec_dst.s_addr) {
(0, v) => v.to_ne_bytes(),
(v, _) => v.to_ne_bytes(),
};

let address = IpV4Address::new(local_address);
let interface = pkt_info.ipi_ifindex as _;

Some((address, interface))
}

#[inline]
pub fn encode(addr: &IpV4Address, local_interface: Option<u32>) -> Cmsg {
let mut pkt_info = unsafe { core::mem::zeroed::<Cmsg>() };
pkt_info.ipi_spec_dst.s_addr = u32::from_ne_bytes((*addr).into());
if let Some(interface) = local_interface {
pkt_info.ipi_ifindex = interface as _;
}
pkt_info
}
}

#[cfg(any(not(s2n_quic_platform_pktinfo), test))]
mod pktinfo_disabled {
#![cfg_attr(test, allow(dead_code))]
use super::*;

pub const LEVEL: Option<c_int> = None;
pub const TYPE: Option<c_int> = None;
pub const SOCKOPT: Option<(c_int, c_int)> = None;
pub const CMSG_SPACE: usize = 0;

pub type Cmsg = c_int;

#[inline]
pub const fn is_match(level: c_int, ty: c_int) -> bool {
let _ = level;
let _ = ty;
false
}

/// # Safety
///
/// * The provided bytes must be aligned to `cmsghdr`
pub unsafe fn decode(bytes: &[u8]) -> Option<(IpV4Address, u32)> {
let _ = bytes;
None
}

#[inline]
pub fn encode(addr: &IpV4Address, local_interface: Option<u32>) -> Cmsg {
let _ = addr;
let _ = local_interface;
unimplemented!("this platform does not support pktinfo")
}
}

mod pktinfo_impl {
#[cfg(not(s2n_quic_platform_pktinfo))]
pub use super::pktinfo_disabled::*;
#[cfg(s2n_quic_platform_pktinfo)]
pub use super::pktinfo_enabled::*;
}

pub use pktinfo_impl::*;

pub const IS_SUPPORTED: bool = cfg!(s2n_quic_platform_pktinfo);
94 changes: 94 additions & 0 deletions quic/s2n-quic-platform/src/features/pktinfo_v6.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use super::c_int;
use s2n_quic_core::inet::IpV6Address;

#[cfg(s2n_quic_platform_pktinfo)]
mod pktinfo_enabled {
use super::*;
use crate::message::cmsg;
use libc::{IPPROTO_IPV6, IPV6_PKTINFO, IPV6_RECVPKTINFO};

pub const LEVEL: Option<c_int> = Some(IPPROTO_IPV6 as _);
pub const TYPE: Option<c_int> = Some(IPV6_PKTINFO as _);
pub const SOCKOPT: Option<(c_int, c_int)> = Some((IPPROTO_IPV6 as _, IPV6_RECVPKTINFO));
pub const CMSG_SPACE: usize = crate::message::cmsg::size_of_cmsg::<Cmsg>();

pub type Cmsg = libc::in6_pktinfo;

#[inline]
pub const fn is_match(level: c_int, ty: c_int) -> bool {
level == IPPROTO_IPV6 as c_int && ty == IPV6_PKTINFO as c_int
}

/// # Safety
///
/// * The provided bytes must be aligned to `cmsghdr`
pub unsafe fn decode(bytes: &[u8]) -> Option<(IpV6Address, u32)> {
let pkt_info = cmsg::decode::value_from_bytes::<Cmsg>(bytes)?;

let local_address = pkt_info.ipi6_addr.s6_addr;

let address = IpV6Address::new(local_address);
let interface = pkt_info.ipi6_ifindex as _;

Some((address, interface))
}

#[inline]
pub fn encode(addr: &IpV6Address, local_interface: Option<u32>) -> Cmsg {
let mut pkt_info = unsafe { core::mem::zeroed::<Cmsg>() };
pkt_info.ipi6_addr.s6_addr = (*addr).into();
if let Some(interface) = local_interface {
pkt_info.ipi6_ifindex = interface as _;
}
pkt_info
}
}

#[cfg(any(not(s2n_quic_platform_pktinfo), test))]
mod pktinfo_disabled {
#![cfg_attr(test, allow(dead_code))]
use super::*;

pub const LEVEL: Option<c_int> = None;
pub const TYPE: Option<c_int> = None;
pub const SOCKOPT: Option<(c_int, c_int)> = None;
pub const CMSG_SPACE: usize = 0;

pub type Cmsg = c_int;

#[inline]
pub const fn is_match(level: c_int, ty: c_int) -> bool {
let _ = level;
let _ = ty;
false
}

/// # Safety
///
/// * The provided bytes must be aligned to `cmsghdr`
pub unsafe fn decode(bytes: &[u8]) -> Option<(IpV6Address, u32)> {
let _ = bytes;
None
}

#[inline]
pub fn encode(addr: &IpV6Address, local_interface: Option<u32>) -> Cmsg {
let _ = addr;
let _ = local_interface;
unimplemented!("this platform does not support pktinfo")
}
}

mod pktinfo_impl {
#[cfg(not(s2n_quic_platform_pktinfo))]
pub use super::pktinfo_disabled::*;
#[cfg(s2n_quic_platform_pktinfo)]
pub use super::pktinfo_enabled::*;
}

pub use pktinfo_impl::*;

pub const IS_SUPPORTED: bool = cfg!(s2n_quic_platform_pktinfo);
23 changes: 23 additions & 0 deletions quic/s2n-quic-platform/src/features/tos.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use super::c_int;
use s2n_quic_core::inet::ExplicitCongestionNotification;

pub const IS_SUPPORTED: bool = super::tos_v4::IS_SUPPORTED || super::tos_v6::IS_SUPPORTED;

#[inline]
pub const fn is_match(level: c_int, ty: c_int) -> bool {
super::tos_v4::is_match(level, ty) || super::tos_v6::is_match(level, ty)
}

#[inline]
pub fn decode(bytes: &[u8]) -> Option<ExplicitCongestionNotification> {
let value = match bytes.len() {
1 => bytes[0],
4 => u32::from_ne_bytes(bytes.try_into().unwrap()) as u8,
_ => return None,
};

Some(ExplicitCongestionNotification::new(value))
}
Loading

0 comments on commit d8b061b

Please sign in to comment.