#![warn(rust_2018_idioms)]
#![allow(dead_code)]
#[allow(unused_macros)]
macro_rules! ready {
($e:expr $(,)?) => {
match $e {
std::task::Poll::Ready(t) => t,
std::task::Poll::Pending => return std::task::Poll::Pending,
}
};
}
#[cfg(unix)]
use std::os::unix::io::AsRawFd;
#[cfg(windows)]
use std::os::windows::io::AsRawSocket;
use std::sync::atomic::AtomicU64;
use std::{
net::{IpAddr, Ipv6Addr, SocketAddr},
sync::atomic::{AtomicUsize, Ordering},
time::{Duration, Instant},
};
use tracing::warn;
#[cfg(unix)]
mod cmsg;
#[cfg(unix)]
#[path = "unix.rs"]
mod imp;
#[cfg(windows)]
#[path = "windows.rs"]
mod imp;
#[cfg(not(any(unix, windows)))]
#[path = "fallback.rs"]
mod imp;
mod proto;
mod runtime;
pub use imp::UdpSocketState;
pub use proto::{EcnCodepoint, Transmit};
#[cfg(not(feature = "metal-io"))]
pub use runtime::AsyncUdpSocket;
pub use runtime::UdpSocket;
pub const BATCH_SIZE: usize = imp::BATCH_SIZE;
#[derive(Debug)]
pub struct Capabilities {
max_gso_segments: AtomicUsize,
gro_segments: usize,
}
impl Capabilities {
pub fn new() -> Self {
imp::capabilities()
}
#[inline]
pub fn max_gso_segments(&self) -> usize {
self.max_gso_segments.load(Ordering::Relaxed)
}
#[inline]
pub fn gro_segments(&self) -> usize {
self.gro_segments
}
}
impl Default for Capabilities {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Copy, Clone)]
pub struct RecvMeta {
pub addr: SocketAddr,
pub len: usize,
pub stride: usize,
pub ecn: Option<EcnCodepoint>,
pub dst_ip: Option<IpAddr>,
}
impl Default for RecvMeta {
fn default() -> Self {
Self {
addr: SocketAddr::new(Ipv6Addr::UNSPECIFIED.into(), 0),
len: 0,
stride: 0,
ecn: None,
dst_ip: None,
}
}
}
const IO_ERROR_LOG_INTERVAL: Duration = std::time::Duration::from_secs(60);
fn log_sendmsg_error(
epoch: &Instant,
last_send_error: &AtomicU64,
err: impl core::fmt::Debug,
transmit: &Transmit,
) {
let d = last_send_error.load(Ordering::Relaxed);
let last = epoch.checked_add(Duration::from_nanos(d)).unwrap();
let now = Instant::now();
let interval = now.saturating_duration_since(last);
if interval > IO_ERROR_LOG_INTERVAL {
last_send_error.store(interval.as_nanos() as u64, Ordering::Relaxed);
warn!(
"sendmsg error: {:?}, Transmit: {{ destination: {:?}, src_ip: {:?}, enc: {:?}, len: {:?}, segment_size: {:?} }}",
err, transmit.destination, transmit.src_ip, transmit.ecn, transmit.contents.len(), transmit.segment_size);
}
}
pub struct UdpSockRef<'a>(socket2::SockRef<'a>);
#[cfg(unix)]
impl<'s, S> From<&'s S> for UdpSockRef<'s>
where
S: AsRawFd,
{
fn from(socket: &'s S) -> Self {
Self(socket.into())
}
}
#[cfg(windows)]
impl<'s, S> From<&'s S> for UdpSockRef<'s>
where
S: AsRawSocket,
{
fn from(socket: &'s S) -> Self {
Self(socket.into())
}
}