Skip to main content

ax_net/
options.rs

1//! Socket option data structures and dispatch traits.
2//!
3//! This module defines Linux-compatible option payloads plus the `Configurable`
4//! trait used by each socket implementation to handle getsockopt/setsockopt.
5//! The goal is to keep the syscall layer protocol-neutral: it builds one option
6//! request enum, then the concrete socket decides which values it supports.
7//!
8//! # Compatibility Boundary
9//!
10//! Option structs model Linux-visible ABI state, but not every field maps to a
11//! smoltcp feature. Unsupported or synthetic fields should be filled
12//! conservatively in the socket implementation, with defaults documented near
13//! the protocol that reports them.
14
15use alloc::{boxed::Box, sync::Arc};
16use core::{any::Any, fmt, time::Duration};
17
18use enum_dispatch::enum_dispatch;
19
20use crate::{InterfaceId, NetError, NetResult};
21
22/// Linux-like TCP connection state reported by TCP_INFO.
23#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
24pub enum TcpState {
25    /// No active TCP connection.
26    #[default]
27    Closed,
28    /// Passive listener.
29    Listen,
30    /// SYN sent, waiting for a matching SYN+ACK.
31    SynSent,
32    /// SYN received, waiting for the final ACK.
33    SynReceived,
34    /// Fully established connection.
35    Established,
36    /// Local endpoint has closed and sent FIN.
37    FinWait1,
38    /// Local FIN has been acknowledged.
39    FinWait2,
40    /// Remote endpoint has closed first.
41    CloseWait,
42    /// Both endpoints have closed simultaneously.
43    Closing,
44    /// Waiting for ACK of the local FIN after remote close.
45    LastAck,
46    /// Waiting for delayed packets to expire.
47    TimeWait,
48}
49
50bitflags::bitflags! {
51    /// Negotiated TCP options reported by TCP_INFO.
52    #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
53    pub struct TcpInfoOptions: u8 {
54        /// TCP timestamps are enabled.
55        const TIMESTAMPS = 1 << 0;
56        /// Selective ACK is enabled.
57        const SACK = 1 << 1;
58        /// Window scaling is enabled.
59        const WSCALE = 1 << 2;
60        /// Explicit congestion notification is enabled.
61        const ECN = 1 << 3;
62        /// ECN has been seen on the connection.
63        const ECN_SEEN = 1 << 4;
64        /// SYN data was used by the connection.
65        const SYN_DATA = 1 << 5;
66    }
67}
68
69/// Transport-independent TCP_INFO snapshot.
70#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
71pub struct TcpInfo {
72    /// Current TCP state.
73    pub state: TcpState,
74    /// Congestion-avoidance state. Zero means open.
75    pub ca_state: u8,
76    /// Number of unacknowledged retransmits.
77    pub retransmits: u8,
78    /// Number of pending keepalive or zero-window probes.
79    pub probes: u8,
80    /// Exponential backoff counter.
81    pub backoff: u8,
82    /// Negotiated TCP options.
83    pub options: TcpInfoOptions,
84    /// Send window scale.
85    pub snd_wscale: u8,
86    /// Receive window scale.
87    pub rcv_wscale: u8,
88    /// Retransmission timeout in microseconds.
89    pub rto_micros: u32,
90    /// Delayed ACK timeout in microseconds.
91    pub ato_micros: u32,
92    /// Send maximum segment size.
93    pub snd_mss: u32,
94    /// Receive maximum segment size.
95    pub rcv_mss: u32,
96    /// Bytes currently queued for transmit.
97    pub notsent_bytes: u32,
98    /// Advertised path MTU.
99    pub pmtu: u32,
100    /// Advertised maximum segment size.
101    pub advmss: u32,
102    /// Current send congestion window, in segments.
103    pub snd_cwnd: u32,
104    /// Packet reordering tolerance.
105    pub reordering: u32,
106    /// Available receive buffer space.
107    pub rcv_space: u32,
108    /// Current send window estimate.
109    pub snd_wnd: u32,
110    /// Current receive window estimate.
111    pub rcv_wnd: u32,
112}
113
114/// TCP congestion-control algorithms exposed by the transport backend.
115#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
116pub enum TcpCongestionControl {
117    /// The transport does not apply congestion-window control.
118    #[default]
119    None,
120}
121
122macro_rules! define_options {
123    ($($name:ident($value:ty),)*) => {
124        /// Operation to get a socket option.
125        ///
126        /// See [`Configurable::get_option`].
127        #[allow(missing_docs)]
128        pub enum GetSocketOption<'a> {
129            $(
130                $name(&'a mut $value),
131            )*
132        }
133
134        /// Operation to set a socket option.
135        ///
136        /// See [`Configurable::set_option`].
137        #[allow(missing_docs)]
138        #[derive(Clone, Copy)]
139        pub enum SetSocketOption<'a> {
140            $(
141                $name(&'a $value),
142            )*
143        }
144    };
145}
146
147/// Transport-owned Unix credentials plus an optional OS identity generation.
148///
149/// `pid`, `uid`, and `gid` are ABI-compatible fallback values. OS layers with
150/// PID namespaces can attach their generation object opaquely so queued
151/// messages and peer sockets do not depend on a reusable numeric PID.
152#[derive(Default, Clone)]
153pub struct UnixCredentials {
154    /// Process ID.
155    pub pid: u32,
156    /// User ID.
157    pub uid: u32,
158    /// Group ID.
159    pub gid: u32,
160    identity: Option<Arc<dyn Any + Send + Sync>>,
161}
162impl UnixCredentials {
163    /// Create a new `UnixCredentials` with the given PID and default UID/GID.
164    pub fn new(pid: u32) -> Self {
165        UnixCredentials {
166            pid,
167            uid: 0,
168            gid: 0,
169            identity: None,
170        }
171    }
172
173    /// Creates credentials with explicit numeric fallback values.
174    pub fn from_parts(pid: u32, uid: u32, gid: u32) -> Self {
175        Self {
176            pid,
177            uid,
178            gid,
179            identity: None,
180        }
181    }
182
183    /// Attaches an OS-specific stable process generation.
184    pub fn with_identity<T>(mut self, identity: Arc<T>) -> Self
185    where
186        T: Any + Send + Sync,
187    {
188        self.identity = Some(identity);
189        self
190    }
191
192    /// Borrows the attached process generation when it has the requested type.
193    pub fn identity<T: Any + Send + Sync>(&self) -> Option<&T> {
194        self.identity.as_deref()?.downcast_ref()
195    }
196}
197
198impl fmt::Debug for UnixCredentials {
199    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
200        formatter
201            .debug_struct("UnixCredentials")
202            .field("pid", &self.pid)
203            .field("uid", &self.uid)
204            .field("gid", &self.gid)
205            .field("has_identity", &self.identity.is_some())
206            .finish()
207    }
208}
209
210impl PartialEq for UnixCredentials {
211    fn eq(&self, other: &Self) -> bool {
212        self.pid == other.pid && self.uid == other.uid && self.gid == other.gid
213    }
214}
215
216impl Eq for UnixCredentials {}
217
218impl From<u32> for UnixCredentials {
219    fn from(pid: u32) -> Self {
220        Self::new(pid)
221    }
222}
223
224define_options! {
225    // ---- Socket level options (SO_*) ----
226    ReuseAddress(bool),
227    ReusePort(bool),
228    Error(i32),
229    DontRoute(bool),
230    SendBuffer(usize),
231    ReceiveBuffer(usize),
232    KeepAlive(bool),
233    SendTimeout(Duration),
234    ReceiveTimeout(Duration),
235    SendBufferForce(usize),
236    PassCredentials(bool),
237    ReceiveTimestamp(bool),
238    PeerCredentials(UnixCredentials),
239    SocketType(i32),
240    SocketProtocol(i32),
241    SocketDomain(i32),
242    BindToDevice(Option<InterfaceId>),
243    Priority(i32),
244
245    // --- TCP level options (TCP_*) ----
246    NoDelay(bool),
247    MaxSegment(usize),
248    TcpKeepIdle(u32),
249    TcpKeepInterval(u32),
250    TcpKeepCount(u32),
251    TcpUserTimeout(u32),
252    TcpInfo(TcpInfo),
253    TcpCongestionControl(TcpCongestionControl),
254
255    // ---- IP level options (IP_*) ----
256    Ttl(u8),
257    IpTos(u8),
258    RecvTtl(bool),
259    RecvTos(bool),
260    RecvTrafficClass(bool),
261    RecvErr(bool),
262    IpMtuDiscover(u8),
263
264    // ---- Extra options ----
265    NonBlocking(bool),
266}
267
268/// Trait for configurable socket-like objects.
269#[enum_dispatch]
270pub trait Configurable {
271    /// Get a socket option, returns `true` if the socket supports the option.
272    fn get_option_inner(&self, opt: &mut GetSocketOption) -> NetResult<bool>;
273    /// Set a socket option, returns `true` if the socket supports the option.
274    fn set_option_inner(&self, opt: SetSocketOption) -> NetResult<bool>;
275
276    /// Get a socket option. Dispatches to [`Configurable::get_option_inner`].
277    fn get_option(&self, mut opt: GetSocketOption) -> NetResult {
278        self.get_option_inner(&mut opt).and_then(|supported| {
279            if !supported {
280                Err(NetError::ProtocolOptionUnsupported)
281            } else {
282                Ok(())
283            }
284        })
285    }
286    /// Set a socket option. Dispatches to [`Configurable::set_option_inner`].
287    fn set_option(&self, opt: SetSocketOption) -> NetResult {
288        self.set_option_inner(opt).and_then(|supported| {
289            if !supported {
290                Err(NetError::ProtocolOptionUnsupported)
291            } else {
292                Ok(())
293            }
294        })
295    }
296}
297
298impl<T: Configurable + ?Sized> Configurable for Box<T> {
299    fn get_option_inner(&self, opt: &mut GetSocketOption) -> NetResult<bool> {
300        self.as_ref().get_option_inner(opt)
301    }
302
303    fn set_option_inner(&self, opt: SetSocketOption) -> NetResult<bool> {
304        self.as_ref().set_option_inner(opt)
305    }
306}