1use std::{io, net::TcpStream};
2
3use std::time::Duration;
4
5#[cfg(not(target_family = "wasm"))]
6pub use socket2;
7
8#[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 pub fn nodelay(&self) -> bool {
22 self.nodelay
23 }
24
25 #[cfg(not(target_family = "wasm"))]
27 pub fn keepalive(&self) -> Option<&socket2::TcpKeepalive> {
28 self.keepalive.as_ref()
29 }
30
31 #[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 pub fn set_nodelay(self, nodelay: bool) -> Self {
39 Self { nodelay, ..self }
40 }
41
42 #[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 pub fn set_linger_time(self, linger: Duration) -> Self {
64 Self {
65 linger_time: Some(linger),
66 ..self
67 }
68 }
69
70 #[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}