nex_socket/udp/
config.rs

1use std::{net::SocketAddr, time::Duration};
2
3use socket2::Type as SockType;
4
5use crate::SocketFamily;
6
7/// UDP socket type, either DGRAM or RAW.
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum UdpSocketType {
10    Dgram,
11    Raw,
12}
13
14impl UdpSocketType {
15    /// Returns true if the socket type is DGRAM.
16    pub fn is_dgram(&self) -> bool {
17        matches!(self, UdpSocketType::Dgram)
18    }
19
20    /// Returns true if the socket type is RAW.
21    pub fn is_raw(&self) -> bool {
22        matches!(self, UdpSocketType::Raw)
23    }
24
25    /// Converts the UDP socket type to a `socket2::Type`.
26    pub(crate) fn to_sock_type(&self) -> SockType {
27        match self {
28            UdpSocketType::Dgram => SockType::DGRAM,
29            UdpSocketType::Raw => SockType::RAW,
30        }
31    }
32}
33
34/// Configuration options for a UDP socket.
35#[derive(Debug, Clone)]
36pub struct UdpConfig {
37    /// The socket family.
38    pub socket_family: SocketFamily,
39    /// The socket type (DGRAM or RAW).
40    pub socket_type: UdpSocketType,
41    /// Address to bind. If `None`, the operating system chooses the address.
42    pub bind_addr: Option<SocketAddr>,
43    /// Enable address reuse (`SO_REUSEADDR`).
44    pub reuseaddr: Option<bool>,
45    /// Allow broadcast (`SO_BROADCAST`).
46    pub broadcast: Option<bool>,
47    /// Time to live value.
48    pub ttl: Option<u32>,
49    /// Hop limit value.
50    pub hoplimit: Option<u32>,
51    /// Read timeout for the socket.
52    pub read_timeout: Option<Duration>,
53    /// Write timeout for the socket.
54    pub write_timeout: Option<Duration>,
55    /// Bind to a specific interface (Linux only).
56    pub bind_device: Option<String>,
57}
58
59impl Default for UdpConfig {
60    fn default() -> Self {
61        Self {
62            socket_family: SocketFamily::IPV4,
63            socket_type: UdpSocketType::Dgram,
64            bind_addr: None,
65            reuseaddr: None,
66            broadcast: None,
67            ttl: None,
68            hoplimit: None,
69            read_timeout: None,
70            write_timeout: None,
71            bind_device: None,
72        }
73    }
74}
75
76impl UdpConfig {
77    /// Create a new UDP configuration with default values.
78    pub fn new() -> Self {
79        Self::default()
80    }
81
82    /// Set the bind address.
83    pub fn with_bind_addr(mut self, addr: SocketAddr) -> Self {
84        self.bind_addr = Some(addr);
85        self
86    }
87
88    /// Enable address reuse.
89    pub fn with_reuseaddr(mut self, on: bool) -> Self {
90        self.reuseaddr = Some(on);
91        self
92    }
93
94    /// Allow broadcast.
95    pub fn with_broadcast(mut self, on: bool) -> Self {
96        self.broadcast = Some(on);
97        self
98    }
99
100    /// Set the time to live value.
101    pub fn with_ttl(mut self, ttl: u32) -> Self {
102        self.ttl = Some(ttl);
103        self
104    }
105
106    /// Set the hop limit value.
107    pub fn with_hoplimit(mut self, hops: u32) -> Self {
108        self.hoplimit = Some(hops);
109        self
110    }
111
112    /// Set the read timeout.
113    pub fn with_read_timeout(mut self, timeout: Duration) -> Self {
114        self.read_timeout = Some(timeout);
115        self
116    }
117
118    /// Set the write timeout.
119    pub fn with_write_timeout(mut self, timeout: Duration) -> Self {
120        self.write_timeout = Some(timeout);
121        self
122    }
123
124    /// Bind to a specific interface (Linux only).
125    pub fn with_bind_device(mut self, iface: impl Into<String>) -> Self {
126        self.bind_device = Some(iface.into());
127        self
128    }
129}
130
131#[cfg(test)]
132mod tests {
133    use super::*;
134
135    #[test]
136    fn udp_config_default_values() {
137        let cfg = UdpConfig::default();
138        assert!(cfg.bind_addr.is_none());
139        assert!(cfg.reuseaddr.is_none());
140        assert!(cfg.broadcast.is_none());
141        assert!(cfg.ttl.is_none());
142        assert!(cfg.bind_device.is_none());
143    }
144}