redis/io/
tcp.rs

1use std::{io, net::TcpStream};
2
3#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
4use std::time::Duration;
5
6#[cfg(not(target_family = "wasm"))]
7pub use socket2;
8
9/// Settings for a TCP stream.
10#[derive(Clone, Debug)]
11pub struct TcpSettings {
12    nodelay: bool,
13    #[cfg(not(target_family = "wasm"))]
14    keepalive: Option<socket2::TcpKeepalive>,
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 value of the `TCP_USER_TIMEOUT` option on this socket.
54    #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
55    pub fn set_user_timeout(self, user_timeout: Duration) -> Self {
56        Self {
57            user_timeout: Some(user_timeout),
58            ..self
59        }
60    }
61}
62
63#[allow(clippy::derivable_impls)]
64impl Default for TcpSettings {
65    fn default() -> Self {
66        Self {
67            nodelay: false,
68            #[cfg(not(target_family = "wasm"))]
69            keepalive: None,
70            #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
71            user_timeout: None,
72        }
73    }
74}
75
76pub(crate) fn stream_with_settings(
77    socket: TcpStream,
78    settings: &TcpSettings,
79) -> io::Result<TcpStream> {
80    socket.set_nodelay(settings.nodelay)?;
81    #[cfg(not(target_family = "wasm"))]
82    {
83        let socket2: socket2::Socket = socket.into();
84        if let Some(keepalive) = &settings.keepalive {
85            socket2.set_tcp_keepalive(keepalive)?;
86        }
87        #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
88        socket2.set_tcp_user_timeout(settings.user_timeout)?;
89        Ok(socket2.into())
90    }
91    #[cfg(target_family = "wasm")]
92    {
93        Ok(socket)
94    }
95}