Skip to main content

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    /// Whether to allow port reuse (`SO_REUSEPORT`) where supported.
46    pub reuseport: Option<bool>,
47    /// Allow broadcast (`SO_BROADCAST`).
48    pub broadcast: Option<bool>,
49    /// Time to live value.
50    pub ttl: Option<u32>,
51    /// Hop limit value.
52    pub hoplimit: Option<u32>,
53    /// Read timeout for the socket.
54    pub read_timeout: Option<Duration>,
55    /// Write timeout for the socket.
56    pub write_timeout: Option<Duration>,
57    /// Optional receive buffer size in bytes.
58    pub recv_buffer_size: Option<usize>,
59    /// Optional send buffer size in bytes.
60    pub send_buffer_size: Option<usize>,
61    /// Optional IPv4 TOS / DSCP field value.
62    pub tos: Option<u32>,
63    /// Optional IPv6 traffic class value (`IPV6_TCLASS`) where supported.
64    pub tclass_v6: Option<u32>,
65    /// Enable receiving packet info ancillary data (`IP_PKTINFO` / `IPV6_RECVPKTINFO`) where supported.
66    pub recv_pktinfo: Option<bool>,
67    /// Whether to force IPv6-only behavior on dual-stack sockets.
68    pub only_v6: Option<bool>,
69    /// Bind to a specific interface (Linux only).
70    pub bind_device: Option<String>,
71}
72
73impl Default for UdpConfig {
74    fn default() -> Self {
75        Self {
76            socket_family: SocketFamily::IPV4,
77            socket_type: UdpSocketType::Dgram,
78            bind_addr: None,
79            reuseaddr: None,
80            reuseport: None,
81            broadcast: None,
82            ttl: None,
83            hoplimit: None,
84            read_timeout: None,
85            write_timeout: None,
86            recv_buffer_size: None,
87            send_buffer_size: None,
88            tos: None,
89            tclass_v6: None,
90            recv_pktinfo: None,
91            only_v6: None,
92            bind_device: None,
93        }
94    }
95}
96
97impl UdpConfig {
98    /// Create a new UDP configuration with default values.
99    pub fn new() -> Self {
100        Self::default()
101    }
102
103    /// Create a new UDP configuration for a specific socket family.
104    pub fn new_with_family(socket_family: SocketFamily) -> Self {
105        Self {
106            socket_family,
107            ..Self::default()
108        }
109    }
110
111    /// Set the socket family.
112    pub fn with_socket_family(mut self, socket_family: SocketFamily) -> Self {
113        self.socket_family = socket_family;
114        self
115    }
116
117    /// Set the bind address.
118    pub fn with_bind_addr(mut self, addr: SocketAddr) -> Self {
119        self.bind_addr = Some(addr);
120        self
121    }
122
123    /// Set the bind address.
124    pub fn with_bind(self, addr: SocketAddr) -> Self {
125        self.with_bind_addr(addr)
126    }
127
128    /// Enable address reuse.
129    pub fn with_reuseaddr(mut self, on: bool) -> Self {
130        self.reuseaddr = Some(on);
131        self
132    }
133
134    /// Enable port reuse.
135    pub fn with_reuseport(mut self, on: bool) -> Self {
136        self.reuseport = Some(on);
137        self
138    }
139
140    /// Allow broadcast.
141    pub fn with_broadcast(mut self, on: bool) -> Self {
142        self.broadcast = Some(on);
143        self
144    }
145
146    /// Set the time to live value.
147    pub fn with_ttl(mut self, ttl: u32) -> Self {
148        self.ttl = Some(ttl);
149        self
150    }
151
152    /// Set the hop limit value.
153    pub fn with_hoplimit(mut self, hops: u32) -> Self {
154        self.hoplimit = Some(hops);
155        self
156    }
157
158    /// Set the hop limit value.
159    pub fn with_hop_limit(self, hops: u32) -> Self {
160        self.with_hoplimit(hops)
161    }
162
163    /// Set the read timeout.
164    pub fn with_read_timeout(mut self, timeout: Duration) -> Self {
165        self.read_timeout = Some(timeout);
166        self
167    }
168
169    /// Set the write timeout.
170    pub fn with_write_timeout(mut self, timeout: Duration) -> Self {
171        self.write_timeout = Some(timeout);
172        self
173    }
174
175    /// Set the receive buffer size.
176    pub fn with_recv_buffer_size(mut self, size: usize) -> Self {
177        self.recv_buffer_size = Some(size);
178        self
179    }
180
181    /// Set the send buffer size.
182    pub fn with_send_buffer_size(mut self, size: usize) -> Self {
183        self.send_buffer_size = Some(size);
184        self
185    }
186
187    /// Set the IPv4 TOS / DSCP field value.
188    pub fn with_tos(mut self, tos: u32) -> Self {
189        self.tos = Some(tos);
190        self
191    }
192
193    /// Set the IPv6 traffic class value.
194    pub fn with_tclass_v6(mut self, tclass: u32) -> Self {
195        self.tclass_v6 = Some(tclass);
196        self
197    }
198
199    /// Enable packet-info ancillary data receiving.
200    pub fn with_recv_pktinfo(mut self, on: bool) -> Self {
201        self.recv_pktinfo = Some(on);
202        self
203    }
204
205    /// Set whether the socket is IPv6 only.
206    pub fn with_only_v6(mut self, only_v6: bool) -> Self {
207        self.only_v6 = Some(only_v6);
208        self
209    }
210
211    /// Bind to a specific interface (Linux only).
212    pub fn with_bind_device(mut self, iface: impl Into<String>) -> Self {
213        self.bind_device = Some(iface.into());
214        self
215    }
216}
217
218#[cfg(test)]
219mod tests {
220    use super::*;
221
222    #[test]
223    fn udp_config_default_values() {
224        let cfg = UdpConfig::default();
225        assert!(cfg.bind_addr.is_none());
226        assert!(cfg.reuseaddr.is_none());
227        assert!(cfg.reuseport.is_none());
228        assert!(cfg.broadcast.is_none());
229        assert!(cfg.ttl.is_none());
230        assert!(cfg.recv_buffer_size.is_none());
231        assert!(cfg.send_buffer_size.is_none());
232        assert!(cfg.tos.is_none());
233        assert!(cfg.tclass_v6.is_none());
234        assert!(cfg.recv_pktinfo.is_none());
235        assert!(cfg.only_v6.is_none());
236        assert!(cfg.bind_device.is_none());
237    }
238
239    #[test]
240    fn udp_config_with_family_builder() {
241        let cfg =
242            UdpConfig::new_with_family(SocketFamily::IPV6).with_bind("[::1]:0".parse().unwrap());
243        assert_eq!(cfg.socket_family, SocketFamily::IPV6);
244        assert!(cfg.bind_addr.is_some());
245    }
246}