Skip to content

Commit d278529

Browse files
Add support for tcp keepalive through socket2
Not fully implemented, probably should be using a custom structure for `TcpKeepalive` to avoid exposing `socket2` publicly. In that case, should we have the same feature flag as the `socket2` library? Or should we allow each setting and just warn when one is not available for the given platform ?
1 parent 414c515 commit d278529

File tree

4 files changed

+50
-0
lines changed

4 files changed

+50
-0
lines changed

Cargo.lock

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ gzip = ["dep:flate2"]
3131
brotli = ["dep:brotli-decompressor"]
3232
charset = ["dep:encoding_rs"]
3333
json = ["dep:serde", "dep:serde_json", "cookie_store?/serde_json"]
34+
keepalive = ["dep:socket2", "socket2/all"]
3435

3536
######## UNSTABLE FEATURES.
3637
# Might be removed or changed in a minor version.
@@ -90,6 +91,7 @@ encoding_rs = { version = "0.8.34", optional = true }
9091

9192
serde = { version = "1.0.138", optional = true, default-features = false, features = ["std"] }
9293
serde_json = { version = "1.0.120", optional = true, default-features = false, features = ["std"] }
94+
socket2 = { version = "0.5.8", optional = true }
9395

9496
[dev-dependencies]
9597
env_logger = "0.11.6"

src/config.rs

+21
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ pub struct Config {
156156
max_idle_connections: usize,
157157
max_idle_connections_per_host: usize,
158158
max_idle_age: Duration,
159+
#[cfg(feature = "keepalive")]
160+
tcp_keepalive: Option<socket2::TcpKeepalive>,
159161

160162
// Chain built for middleware.
161163
pub(crate) middleware: MiddlewareChain,
@@ -394,6 +396,12 @@ impl Config {
394396
pub fn max_idle_age(&self) -> Duration {
395397
self.max_idle_age
396398
}
399+
400+
#[cfg(feature = "keepalive")]
401+
/// TCP Keepalive configuration
402+
pub fn tcp_keepalive(&self) -> &Option<socket2::TcpKeepalive> {
403+
&self.tcp_keepalive
404+
}
397405
}
398406

399407
/// Builder of [`Config`]
@@ -712,6 +720,17 @@ impl<Scope: private::ConfigScope> ConfigBuilder<Scope> {
712720
self.config().timeouts.recv_body = v;
713721
self
714722
}
723+
724+
/// Configuration of TCP keepalive
725+
///
726+
/// If `None`, keepalive is not configured for the connections
727+
///
728+
/// Defaults to `None`
729+
#[cfg(feature = "keepalive")]
730+
pub fn tcp_keepalive(mut self, v: Option<socket2::TcpKeepalive>) -> Self {
731+
self.config().tcp_keepalive = v;
732+
self
733+
}
715734
}
716735

717736
/// Possible config values for headers.
@@ -849,6 +868,8 @@ impl Default for Config {
849868
max_idle_connections_per_host: 3,
850869
max_idle_age: Duration::from_secs(15),
851870
middleware: MiddlewareChain::default(),
871+
#[cfg(feature = "keepalive")]
872+
tcp_keepalive: None,
852873
force_send_body: false,
853874
}
854875
}

src/unversioned/transport/tcp.rs

+16
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ impl<In: Transport> Connector<In> for TcpConnector {
3333

3434
let config = &details.config;
3535
let stream = try_connect(&details.addrs, details.timeout, config)?;
36+
#[cfg(feature = "keepalive")]
37+
let stream = set_keepalive(stream, details.config.tcp_keepalive().as_ref())?;
3638

3739
let buffers = LazyBuffers::new(config.input_buffer_size(), config.output_buffer_size());
3840
let transport = TcpTransport::new(stream, buffers);
@@ -41,6 +43,20 @@ impl<In: Transport> Connector<In> for TcpConnector {
4143
}
4244
}
4345

46+
#[cfg(feature = "keepalive")]
47+
fn set_keepalive(
48+
stream: TcpStream,
49+
keepalive: Option<&socket2::TcpKeepalive>,
50+
) -> Result<TcpStream, crate::Error> {
51+
use socket2::Socket;
52+
let socket: Socket = stream.into();
53+
if let Some(keepalive) = keepalive {
54+
socket.set_keepalive(true)?;
55+
socket.set_tcp_keepalive(keepalive)?;
56+
}
57+
Ok(socket.into())
58+
}
59+
4460
fn try_connect(
4561
addrs: &ResolvedSocketAddrs,
4662
timeout: NextTimeout,

0 commit comments

Comments
 (0)