1#![warn(unreachable_pub)]
3#![warn(clippy::use_self)]
4
5#[cfg(unix)]
6use std::os::unix::io::AsFd;
7#[cfg(windows)]
8use std::os::windows::io::AsSocket;
9use std::{
10 sync::Mutex,
11 time::{Duration, Instant},
12};
13
14use scionnet::{IpAddr, Ipv6Addr, SocketAddr};
15
16use bytes::Bytes;
17use tracing::warn;
18
19#[cfg(unix)]
20mod cmsg;
21#[cfg(unix)]
22#[path = "unix.rs"]
23mod imp;
24
25#[cfg(windows)]
26#[path = "windows.rs"]
27mod imp;
28
29#[cfg(not(any(unix, windows)))]
31#[path = "fallback.rs"]
32mod imp;
33
34pub use imp::UdpSocketState;
35
36pub const BATCH_SIZE: usize = imp::BATCH_SIZE;
38
39#[derive(Debug, Copy, Clone)]
45pub struct RecvMeta {
46 pub addr: SocketAddr,
48 pub len: usize,
50 pub stride: usize,
60 pub ecn: Option<EcnCodepoint>,
62 pub dst_ip: Option<IpAddr>,
64}
65
66impl Default for RecvMeta {
67 fn default() -> Self {
69 Self {
70 addr: SocketAddr::new_ip(Ipv6Addr::UNSPECIFIED.into(), 0),
71 len: 0,
72 stride: 0,
73 ecn: None,
74 dst_ip: None,
75 }
76 }
77}
78
79#[derive(Debug, Clone)]
81pub struct Transmit {
82 pub destination: SocketAddr,
84 pub ecn: Option<EcnCodepoint>,
86 pub contents: Bytes,
88 pub segment_size: Option<usize>,
91 pub src_ip: Option<IpAddr>,
93}
94
95const IO_ERROR_LOG_INTERVAL: Duration = std::time::Duration::from_secs(60);
97
98fn log_sendmsg_error(
103 last_send_error: &Mutex<Instant>,
104 err: impl core::fmt::Debug,
105 transmit: &Transmit,
106) {
107 let now = Instant::now();
108 let last_send_error = &mut *last_send_error.lock().expect("poisend lock");
109 if now.saturating_duration_since(*last_send_error) > IO_ERROR_LOG_INTERVAL {
110 *last_send_error = now;
111 warn!(
112 "sendmsg error: {:?}, Transmit: {{ destination: {:?}, src_ip: {:?}, enc: {:?}, len: {:?}, segment_size: {:?} }}",
113 err, transmit.destination, transmit.src_ip, transmit.ecn, transmit.contents.len(), transmit.segment_size);
114 }
115}
116
117pub struct UdpSockRef<'a>(socket2::SockRef<'a>);
123
124#[cfg(unix)]
125impl<'s, S> From<&'s S> for UdpSockRef<'s>
126where
127 S: AsFd,
128{
129 fn from(socket: &'s S) -> Self {
130 Self(socket.into())
131 }
132}
133
134#[cfg(windows)]
135impl<'s, S> From<&'s S> for UdpSockRef<'s>
136where
137 S: AsSocket,
138{
139 fn from(socket: &'s S) -> Self {
140 Self(socket.into())
141 }
142}
143
144#[repr(u8)]
146#[derive(Debug, Copy, Clone, Eq, PartialEq)]
147pub enum EcnCodepoint {
148 #[doc(hidden)]
149 Ect0 = 0b10,
150 #[doc(hidden)]
151 Ect1 = 0b01,
152 #[doc(hidden)]
153 Ce = 0b11,
154}
155
156impl EcnCodepoint {
157 pub fn from_bits(x: u8) -> Option<Self> {
159 use self::EcnCodepoint::*;
160 Some(match x & 0b11 {
161 0b10 => Ect0,
162 0b01 => Ect1,
163 0b11 => Ce,
164 _ => {
165 return None;
166 }
167 })
168 }
169}