#![allow(unused_variables, unused_macros, unused_mut, clippy::let_and_return)]
use crate::socket::stats;
use core::ops::ControlFlow;
use socket2::{Domain, Protocol, Socket, Type};
use std::io;
macro_rules! libc {
($fn: ident ( $($arg: expr),* $(,)* ) ) => {{
let res = unsafe { libc::$fn($($arg, )*) };
if res < 0 {
Err(std::io::Error::last_os_error())
} else {
Ok(res)
}
}};
}
#[cfg(s2n_quic_platform_socket_mmsg)]
pub mod mmsg;
#[cfg(s2n_quic_platform_socket_msg)]
pub mod msg;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[allow(dead_code)] pub enum SocketType {
Blocking,
NonBlocking,
}
pub trait SocketEvents {
fn on_complete(&mut self, count: usize) -> ControlFlow<(), ()>;
fn on_error(&mut self, error: io::Error) -> ControlFlow<(), ()>;
}
#[cfg(unix)]
pub trait UnixMessage: crate::message::Message {
fn send<E: SocketEvents>(
fd: std::os::unix::io::RawFd,
entries: &mut [Self],
events: &mut E,
stats: &stats::Sender,
);
fn recv<E: SocketEvents>(
fd: std::os::unix::io::RawFd,
ty: SocketType,
entries: &mut [Self],
events: &mut E,
stats: &stats::Sender,
);
}
pub fn udp_socket(addr: std::net::SocketAddr, only_v6: bool) -> io::Result<Socket> {
let domain = Domain::for_address(addr);
let socket_type = Type::DGRAM;
let protocol = Some(Protocol::UDP);
let socket = Socket::new(domain, socket_type, protocol)?;
let _ = socket.set_only_v6(only_v6);
Ok(socket)
}
pub fn bind_udp<A: std::net::ToSocketAddrs>(
addr: A,
reuse_address: bool,
reuse_port: bool,
only_v6: bool,
) -> io::Result<Socket> {
let addr = addr.to_socket_addrs()?.next().ok_or_else(|| {
std::io::Error::new(
io::ErrorKind::InvalidInput,
"the provided bind address was empty",
)
})?;
debug_assert!(!(reuse_port && addr.port() == 0));
let socket = udp_socket(addr, only_v6)?;
socket.set_reuse_address(reuse_address)?;
#[cfg(unix)]
socket.set_reuse_port(reuse_port)?;
let _ = reuse_port;
socket.bind(&addr.into())?;
Ok(socket)
}
#[cfg(feature = "xdp")]
pub fn bind_to_interface<F: std::os::unix::io::AsRawFd>(
socket: &F,
ifname: &std::ffi::CStr,
) -> io::Result<()> {
libc!(setsockopt(
socket.as_raw_fd(),
libc::SOL_SOCKET,
libc::SO_BINDTODEVICE,
ifname as *const _ as *const _,
libc::IF_NAMESIZE as _
))?;
Ok(())
}
pub fn configure_mtu_disc(tx_socket: &Socket) -> bool {
let mut success = false;
#[cfg(s2n_quic_platform_mtu_disc)]
{
use std::os::unix::io::AsRawFd;
success |= libc!(setsockopt(
tx_socket.as_raw_fd(),
libc::IPPROTO_IP,
libc::IP_MTU_DISCOVER,
&libc::IP_PMTUDISC_PROBE as *const _ as _,
core::mem::size_of_val(&libc::IP_PMTUDISC_PROBE) as _,
))
.is_ok();
success |= libc!(setsockopt(
tx_socket.as_raw_fd(),
libc::IPPROTO_IPV6,
libc::IPV6_MTU_DISCOVER,
&libc::IP_PMTUDISC_PROBE as *const _ as _,
core::mem::size_of_val(&libc::IP_PMTUDISC_PROBE) as _,
))
.is_ok();
}
success
}
pub fn configure_tos(rx_socket: &Socket) -> bool {
let mut success = false;
#[cfg(unix)]
{
use std::os::unix::io::AsRawFd;
let enabled: libc::c_int = 1;
if let Some((level, ty)) = crate::features::tos_v4::SOCKOPT {
success |= libc!(setsockopt(
rx_socket.as_raw_fd(),
level,
ty,
&enabled as *const _ as _,
core::mem::size_of_val(&enabled) as _,
))
.is_ok();
}
if let Some((level, ty)) = crate::features::tos_v6::SOCKOPT {
success |= libc!(setsockopt(
rx_socket.as_raw_fd(),
level,
ty,
&enabled as *const _ as _,
core::mem::size_of_val(&enabled) as _,
))
.is_ok();
}
}
success
}
pub fn configure_pktinfo(rx_socket: &Socket) -> bool {
let mut success = false;
#[cfg(unix)]
{
use std::os::unix::io::AsRawFd;
let enabled: libc::c_int = 1;
if let Some((level, ty)) = crate::features::pktinfo_v4::SOCKOPT {
success |= libc!(setsockopt(
rx_socket.as_raw_fd(),
level,
ty,
&enabled as *const _ as _,
core::mem::size_of_val(&enabled) as _,
))
.is_ok();
}
if let Some((level, ty)) = crate::features::pktinfo_v6::SOCKOPT {
success |= libc!(setsockopt(
rx_socket.as_raw_fd(),
level,
ty,
&enabled as *const _ as _,
core::mem::size_of_val(&enabled) as _,
))
.is_ok();
}
}
success
}
pub fn configure_gro(rx_socket: &Socket) -> bool {
let mut success = false;
#[cfg(unix)]
if let Some((level, ty)) = crate::features::gro::SOCKOPT {
use std::os::unix::io::AsRawFd;
let enabled: libc::c_int = 1;
success |= libc!(setsockopt(
rx_socket.as_raw_fd(),
level as _,
ty as _,
&enabled as *const _ as _,
core::mem::size_of_val(&enabled) as _
))
.is_ok();
}
success
}