Skip to main content

redis/io/
tcp.rs

1use std::{io, net::TcpStream};
2
3use std::time::Duration;
4
5#[cfg(not(target_family = "wasm"))]
6pub use socket2;
7
8/// Settings for a TCP stream.
9#[derive(Clone, Debug)]
10pub struct TcpSettings {
11    nodelay: bool,
12    #[cfg(not(target_family = "wasm"))]
13    keepalive: Option<socket2::TcpKeepalive>,
14    linger_time: Option<Duration>,
15    #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
16    user_timeout: Option<Duration>,
17}
18
19impl TcpSettings {
20    /// Returns the value of the `TCP_NODELAY` option on this socket.
21    pub fn nodelay(&self) -> bool {
22        self.nodelay
23    }
24
25    /// Returns parameters configuring TCP keepalive probes for this socket.
26    #[cfg(not(target_family = "wasm"))]
27    pub fn keepalive(&self) -> Option<&socket2::TcpKeepalive> {
28        self.keepalive.as_ref()
29    }
30
31    /// Returns the value of the `TCP_USER_TIMEOUT` option on this socket.
32    #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
33    pub fn user_timeout(&self) -> Option<Duration> {
34        self.user_timeout
35    }
36
37    /// Sets the value of the `TCP_NODELAY` option on this socket.
38    pub fn set_nodelay(self, nodelay: bool) -> Self {
39        Self { nodelay, ..self }
40    }
41
42    /// Set parameters configuring TCP keepalive probes for this socket.
43    ///
44    /// Default values are system-specific
45    #[cfg(not(target_family = "wasm"))]
46    pub fn set_keepalive(self, keepalive: socket2::TcpKeepalive) -> Self {
47        Self {
48            keepalive: Some(keepalive),
49            ..self
50        }
51    }
52
53    /// Set the SO_LINGER time on this socket.
54    ///
55    /// By default, lingering is disabled and sockets will remain in the background
56    /// after being closed. Setting linger to `Duration::ZERO` will disable lingering
57    /// and cause sockets to no longer wait in the TIME-WAIT state (at the cost of causing
58    /// unusual behavior if connecting to non-local-hosts where packets may be ordered).
59    /// Setting linger to a non-zero value will cause close/shutdown to wait for
60    /// reordered packets. This option may not do anything depending on your operating
61    /// system and its configuration; please consult your friendly neighborhood netadmin.
62    /// For more information, see the socket(7) man page.
63    pub fn set_linger_time(self, linger: Duration) -> Self {
64        Self {
65            linger_time: Some(linger),
66            ..self
67        }
68    }
69
70    /// Set the value of the `TCP_USER_TIMEOUT` option on this socket.
71    #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
72    pub fn set_user_timeout(self, user_timeout: Duration) -> Self {
73        Self {
74            user_timeout: Some(user_timeout),
75            ..self
76        }
77    }
78}
79
80#[allow(clippy::derivable_impls)]
81impl Default for TcpSettings {
82    fn default() -> Self {
83        Self {
84            nodelay: false,
85            #[cfg(not(target_family = "wasm"))]
86            keepalive: None,
87            linger_time: None,
88            #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
89            user_timeout: None,
90        }
91    }
92}
93
94pub(crate) fn stream_with_settings(
95    socket: TcpStream,
96    settings: &TcpSettings,
97) -> io::Result<TcpStream> {
98    socket.set_nodelay(settings.nodelay)?;
99    #[cfg(not(target_family = "wasm"))]
100    {
101        let socket2: socket2::Socket = socket.into();
102        if let Some(keepalive) = &settings.keepalive {
103            socket2.set_tcp_keepalive(keepalive)?;
104        }
105        if let Some(linger) = &settings.linger_time {
106            socket2.set_linger(Some(*linger))?;
107        }
108        #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
109        socket2.set_tcp_user_timeout(settings.user_timeout)?;
110        Ok(socket2.into())
111    }
112    #[cfg(target_family = "wasm")]
113    {
114        Ok(socket)
115    }
116}