tokio_listener/
tcp_keepalive_params.rs1use std::{fmt::Display, str::FromStr, time::Duration};
2
3#[cfg(feature = "socket_options")]
4#[cfg_attr(docsrs_alt, doc(cfg(feature = "socket_options")))]
5#[cfg_attr(
28 feature = "serde",
29 derive(serde_with::DeserializeFromStr, serde_with::SerializeDisplay)
30)]
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
32pub struct TcpKeepaliveParams {
33 pub timeout_ms: Option<u32>,
35 pub count: Option<u32>,
37 pub interval_ms: Option<u32>,
39}
40#[cfg(feature = "socket_options")]
41impl Display for TcpKeepaliveParams {
42 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43 if let Some(x) = self.timeout_ms {
44 x.fmt(f)?;
45 }
46 ':'.fmt(f)?;
47 if let Some(x) = self.count {
48 x.fmt(f)?;
49 }
50 ':'.fmt(f)?;
51 if let Some(x) = self.interval_ms {
52 x.fmt(f)?;
53 }
54 Ok(())
55 }
56}
57#[cfg(feature = "socket_options")]
58impl FromStr for TcpKeepaliveParams {
59 type Err = &'static str;
60
61 #[allow(clippy::get_first)]
62 fn from_str(input_string: &str) -> Result<Self, Self::Err> {
63 let input_chunks: Vec<&str> = input_string.split(':').collect();
64 if input_chunks.len() > 3 {
65 return Err("Too many colon-separated chunks");
66 }
67 let timeout_chunk = input_chunks.get(0).unwrap_or(&"").trim();
68 let ping_count_chunk = input_chunks.get(1).unwrap_or(&"").trim();
69 let interval_chunk = input_chunks.get(2).unwrap_or(&"").trim();
70
71 let mut ka_params = TcpKeepaliveParams::default();
72
73 if !timeout_chunk.is_empty() {
74 ka_params.timeout_ms = Some(
75 timeout_chunk
76 .parse()
77 .map_err(|_| "failed to parse timeout as a number")?,
78 );
79 }
80 if !ping_count_chunk.is_empty() {
81 ka_params.count = Some(
82 ping_count_chunk
83 .parse()
84 .map_err(|_| "failed to parse count as a number")?,
85 );
86 }
87 if !interval_chunk.is_empty() {
88 ka_params.interval_ms = Some(
89 interval_chunk
90 .parse()
91 .map_err(|_| "failed to parse interval as a number")?,
92 );
93 }
94
95 Ok(ka_params)
96 }
97}
98#[cfg(feature = "socket_options")]
99impl TcpKeepaliveParams {
100 #[must_use]
104 pub fn to_socket2(&self) -> socket2::TcpKeepalive {
105 let mut k = socket2::TcpKeepalive::new();
106
107 if let Some(x) = self.timeout_ms {
108 k = k.with_time(Duration::from_millis(u64::from(x)));
109 }
110
111 #[cfg(any(
112 target_os = "android",
113 target_os = "dragonfly",
114 target_os = "freebsd",
115 target_os = "fuchsia",
116 target_os = "illumos",
117 target_os = "ios",
118 target_os = "linux",
119 target_os = "macos",
120 target_os = "netbsd",
121 target_os = "tvos",
122 target_os = "watchos",
123 ))]
124 if let Some(x) = self.count {
125 k = k.with_retries(x);
126 }
127
128 #[cfg(any(
129 target_os = "android",
130 target_os = "dragonfly",
131 target_os = "freebsd",
132 target_os = "fuchsia",
133 target_os = "illumos",
134 target_os = "ios",
135 target_os = "linux",
136 target_os = "macos",
137 target_os = "netbsd",
138 target_os = "tvos",
139 target_os = "watchos",
140 target_os = "windows",
141 ))]
142 if let Some(x) = self.interval_ms {
143 k = k.with_interval(Duration::from_millis(u64::from(x)));
144 }
145
146 k
147 }
148}