Skip to main content

nex_socket/tcp/
config.rs

1use socket2::Type as SockType;
2use std::net::SocketAddr;
3use std::time::Duration;
4
5use crate::SocketFamily;
6
7/// TCP socket type, either STREAM or RAW.
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum TcpSocketType {
10    Stream,
11    Raw,
12}
13
14impl TcpSocketType {
15    /// Returns true if the socket type is STREAM.
16    pub fn is_stream(&self) -> bool {
17        matches!(self, TcpSocketType::Stream)
18    }
19
20    /// Returns true if the socket type is RAW.
21    pub fn is_raw(&self) -> bool {
22        matches!(self, TcpSocketType::Raw)
23    }
24
25    /// Converts the TCP socket type to a `socket2::Type`.
26    pub(crate) fn to_sock_type(&self) -> SockType {
27        match self {
28            TcpSocketType::Stream => SockType::STREAM,
29            TcpSocketType::Raw => SockType::RAW,
30        }
31    }
32}
33
34/// Configuration options for a TCP socket.
35#[derive(Debug, Clone)]
36pub struct TcpConfig {
37    /// The socket family, either IPv4 or IPv6.
38    pub socket_family: SocketFamily,
39    /// The type of TCP socket, either STREAM or RAW.
40    pub socket_type: TcpSocketType,
41    /// Optional address to bind the socket to.
42    pub bind_addr: Option<SocketAddr>,
43    /// Whether the socket should be non-blocking.
44    pub nonblocking: bool,
45    /// Whether to allow address reuse.
46    pub reuseaddr: Option<bool>,
47    /// Whether to allow port reuse (`SO_REUSEPORT`) where supported.
48    pub reuseport: Option<bool>,
49    /// Whether to disable Nagle's algorithm (TCP_NODELAY).
50    pub nodelay: Option<bool>,
51    /// Optional linger duration for the socket.
52    pub linger: Option<Duration>,
53    /// Optional Time-To-Live (TTL) for the socket.
54    pub ttl: Option<u32>,
55    /// Optional Hop Limit for the socket (IPv6).
56    pub hoplimit: Option<u32>,
57    /// Optional read timeout for the socket.
58    pub read_timeout: Option<Duration>,
59    /// Optional write timeout for the socket.
60    pub write_timeout: Option<Duration>,
61    /// Optional receive buffer size in bytes.
62    pub recv_buffer_size: Option<usize>,
63    /// Optional send buffer size in bytes.
64    pub send_buffer_size: Option<usize>,
65    /// Optional IPv4 TOS / DSCP field value.
66    pub tos: Option<u32>,
67    /// Optional IPv6 traffic class value (`IPV6_TCLASS`) where supported.
68    pub tclass_v6: Option<u32>,
69    /// Whether to force IPv6-only behavior on dual-stack sockets.
70    pub only_v6: Option<bool>,
71    /// Optional device to bind the socket to.
72    pub bind_device: Option<String>,
73    /// Whether to enable TCP keepalive.
74    pub keepalive: Option<bool>,
75}
76
77impl TcpConfig {
78    /// Create a STREAM socket for the specified family.
79    pub fn new(socket_family: SocketFamily) -> Self {
80        match socket_family {
81            SocketFamily::IPV4 => Self::v4_stream(),
82            SocketFamily::IPV6 => Self::v6_stream(),
83        }
84    }
85
86    /// Create a STREAM socket for IPv4.
87    pub fn v4_stream() -> Self {
88        Self {
89            socket_family: SocketFamily::IPV4,
90            socket_type: TcpSocketType::Stream,
91            bind_addr: None,
92            nonblocking: false,
93            reuseaddr: None,
94            reuseport: None,
95            nodelay: None,
96            linger: None,
97            ttl: None,
98            hoplimit: None,
99            read_timeout: None,
100            write_timeout: None,
101            recv_buffer_size: None,
102            send_buffer_size: None,
103            tos: None,
104            tclass_v6: None,
105            only_v6: None,
106            bind_device: None,
107            keepalive: None,
108        }
109    }
110
111    /// Create a RAW socket. Requires administrator privileges.
112    pub fn raw_v4() -> Self {
113        Self {
114            socket_family: SocketFamily::IPV4,
115            socket_type: TcpSocketType::Raw,
116            ..Self::v4_stream()
117        }
118    }
119
120    /// Create a STREAM socket for IPv6.
121    pub fn v6_stream() -> Self {
122        Self {
123            socket_family: SocketFamily::IPV6,
124            socket_type: TcpSocketType::Stream,
125            ..Self::v4_stream()
126        }
127    }
128
129    /// Create a RAW socket for IPv6. Requires administrator privileges.
130    pub fn raw_v6() -> Self {
131        Self {
132            socket_family: SocketFamily::IPV6,
133            socket_type: TcpSocketType::Raw,
134            ..Self::v4_stream()
135        }
136    }
137
138    // --- chainable modifiers ---
139
140    pub fn with_bind(mut self, addr: SocketAddr) -> Self {
141        self.bind_addr = Some(addr);
142        self
143    }
144
145    pub fn with_bind_addr(self, addr: SocketAddr) -> Self {
146        self.with_bind(addr)
147    }
148
149    pub fn with_nonblocking(mut self, flag: bool) -> Self {
150        self.nonblocking = flag;
151        self
152    }
153
154    pub fn with_reuseaddr(mut self, flag: bool) -> Self {
155        self.reuseaddr = Some(flag);
156        self
157    }
158
159    pub fn with_reuseport(mut self, flag: bool) -> Self {
160        self.reuseport = Some(flag);
161        self
162    }
163
164    pub fn with_nodelay(mut self, flag: bool) -> Self {
165        self.nodelay = Some(flag);
166        self
167    }
168
169    pub fn with_linger(mut self, dur: Duration) -> Self {
170        self.linger = Some(dur);
171        self
172    }
173
174    pub fn with_ttl(mut self, ttl: u32) -> Self {
175        self.ttl = Some(ttl);
176        self
177    }
178
179    pub fn with_hoplimit(mut self, hops: u32) -> Self {
180        self.hoplimit = Some(hops);
181        self
182    }
183
184    pub fn with_hop_limit(self, hops: u32) -> Self {
185        self.with_hoplimit(hops)
186    }
187
188    pub fn with_keepalive(mut self, on: bool) -> Self {
189        self.keepalive = Some(on);
190        self
191    }
192
193    pub fn with_read_timeout(mut self, timeout: Duration) -> Self {
194        self.read_timeout = Some(timeout);
195        self
196    }
197
198    pub fn with_write_timeout(mut self, timeout: Duration) -> Self {
199        self.write_timeout = Some(timeout);
200        self
201    }
202
203    pub fn with_recv_buffer_size(mut self, size: usize) -> Self {
204        self.recv_buffer_size = Some(size);
205        self
206    }
207
208    pub fn with_send_buffer_size(mut self, size: usize) -> Self {
209        self.send_buffer_size = Some(size);
210        self
211    }
212
213    pub fn with_tos(mut self, tos: u32) -> Self {
214        self.tos = Some(tos);
215        self
216    }
217
218    pub fn with_tclass_v6(mut self, tclass: u32) -> Self {
219        self.tclass_v6 = Some(tclass);
220        self
221    }
222
223    pub fn with_only_v6(mut self, only_v6: bool) -> Self {
224        self.only_v6 = Some(only_v6);
225        self
226    }
227
228    pub fn with_bind_device(mut self, iface: impl Into<String>) -> Self {
229        self.bind_device = Some(iface.into());
230        self
231    }
232}
233
234#[cfg(test)]
235mod tests {
236    use super::*;
237
238    #[test]
239    fn tcp_config_builders() {
240        let addr: SocketAddr = "127.0.0.1:80".parse().unwrap();
241        let cfg = TcpConfig::new(SocketFamily::IPV4)
242            .with_bind_addr(addr)
243            .with_nonblocking(true)
244            .with_reuseaddr(true)
245            .with_reuseport(true)
246            .with_nodelay(true)
247            .with_ttl(10)
248            .with_recv_buffer_size(8192)
249            .with_send_buffer_size(8192)
250            .with_tos(0x10)
251            .with_tclass_v6(0x20);
252
253        assert_eq!(cfg.socket_family, SocketFamily::IPV4);
254        assert_eq!(cfg.socket_type, TcpSocketType::Stream);
255        assert_eq!(cfg.bind_addr, Some(addr));
256        assert!(cfg.nonblocking);
257        assert_eq!(cfg.reuseaddr, Some(true));
258        assert_eq!(cfg.reuseport, Some(true));
259        assert_eq!(cfg.nodelay, Some(true));
260        assert_eq!(cfg.ttl, Some(10));
261        assert_eq!(cfg.recv_buffer_size, Some(8192));
262        assert_eq!(cfg.send_buffer_size, Some(8192));
263        assert_eq!(cfg.tos, Some(0x10));
264        assert_eq!(cfg.tclass_v6, Some(0x20));
265    }
266
267    #[test]
268    fn new_with_ipv6_family_creates_v6_stream() {
269        let cfg = TcpConfig::new(SocketFamily::IPV6);
270        assert_eq!(cfg.socket_family, SocketFamily::IPV6);
271        assert_eq!(cfg.socket_type, TcpSocketType::Stream);
272    }
273}