diff --git a/tonic/src/transport/server/mod.rs b/tonic/src/transport/server/mod.rs index 850cf2d02..d63f94647 100644 --- a/tonic/src/transport/server/mod.rs +++ b/tonic/src/transport/server/mod.rs @@ -98,6 +98,8 @@ pub struct Server { init_connection_window_size: Option, max_concurrent_streams: Option, tcp_keepalive: Option, + tcp_keepalive_interval: Option, + tcp_keepalive_retries: Option, tcp_nodelay: bool, http2_keepalive_interval: Option, http2_keepalive_timeout: Duration, @@ -124,6 +126,8 @@ impl Default for Server { init_connection_window_size: None, max_concurrent_streams: None, tcp_keepalive: None, + tcp_keepalive_interval: None, + tcp_keepalive_retries: None, tcp_nodelay: true, http2_keepalive_interval: None, http2_keepalive_timeout: DEFAULT_HTTP2_KEEPALIVE_TIMEOUT, @@ -367,6 +371,43 @@ impl Server { } } + /// Set the value of `TCP_KEEPINTVL` option for accepted connections. + /// + /// This option specifies the time interval between subsequent keepalive probes. + /// This setting only takes effect if [`tcp_keepalive`](Self::tcp_keepalive) is also set. + /// + /// Important: This setting is ignored when using `serve_with_incoming`. + /// + /// Default is `None` (system default). + /// + /// Note: This option is only available on some platforms (Linux, macOS, Windows, etc.). + #[must_use] + pub fn tcp_keepalive_interval(self, tcp_keepalive_interval: Option) -> Self { + Server { + tcp_keepalive_interval, + ..self + } + } + + /// Set the value of `TCP_KEEPCNT` option for accepted connections. + /// + /// This option specifies the maximum number of keepalive probes that should be sent + /// before dropping the connection. + /// This setting only takes effect if [`tcp_keepalive`](Self::tcp_keepalive) is also set. + /// + /// Important: This setting is ignored when using `serve_with_incoming`. + /// + /// Default is `None` (system default). + /// + /// Note: This option is only available on some platforms (Linux, macOS, Windows, etc.). + #[must_use] + pub fn tcp_keepalive_retries(self, tcp_keepalive_retries: Option) -> Self { + Server { + tcp_keepalive_retries, + ..self + } + } + /// Set the value of `TCP_NODELAY` option for accepted connections. Enabled by default. /// /// Important: This setting is ignored when using `serve_with_incoming`. @@ -561,6 +602,8 @@ impl Server { init_connection_window_size: self.init_connection_window_size, max_concurrent_streams: self.max_concurrent_streams, tcp_keepalive: self.tcp_keepalive, + tcp_keepalive_interval: self.tcp_keepalive_interval, + tcp_keepalive_retries: self.tcp_keepalive_retries, tcp_nodelay: self.tcp_nodelay, http2_keepalive_interval: self.http2_keepalive_interval, http2_keepalive_timeout: self.http2_keepalive_timeout, @@ -578,7 +621,9 @@ impl Server { Ok(TcpIncoming::bind(addr) .map_err(super::Error::from_source)? .with_nodelay(Some(self.tcp_nodelay)) - .with_keepalive(self.tcp_keepalive)) + .with_keepalive(self.tcp_keepalive) + .with_keepalive_interval(self.tcp_keepalive_interval) + .with_keepalive_retries(self.tcp_keepalive_retries)) } /// Serve the service. @@ -1180,23 +1225,39 @@ mod tests { #[test] fn server_tcp_defaults() { const EXAMPLE_TCP_KEEPALIVE: Duration = Duration::from_secs(10); + const EXAMPLE_TCP_KEEPALIVE_INTERVAL: Duration = Duration::from_secs(5); + const EXAMPLE_TCP_KEEPALIVE_RETRIES: u32 = 3; // Using ::builder() or ::default() should do the same thing let server_via_builder = Server::builder(); assert!(server_via_builder.tcp_nodelay); assert_eq!(server_via_builder.tcp_keepalive, None); + assert_eq!(server_via_builder.tcp_keepalive_interval, None); + assert_eq!(server_via_builder.tcp_keepalive_retries, None); let server_via_default = Server::default(); assert!(server_via_default.tcp_nodelay); assert_eq!(server_via_default.tcp_keepalive, None); + assert_eq!(server_via_default.tcp_keepalive_interval, None); + assert_eq!(server_via_default.tcp_keepalive_retries, None); // overriding should be possible let server_via_builder = Server::builder() .tcp_nodelay(false) - .tcp_keepalive(Some(EXAMPLE_TCP_KEEPALIVE)); + .tcp_keepalive(Some(EXAMPLE_TCP_KEEPALIVE)) + .tcp_keepalive_interval(Some(EXAMPLE_TCP_KEEPALIVE_INTERVAL)) + .tcp_keepalive_retries(Some(EXAMPLE_TCP_KEEPALIVE_RETRIES)); assert!(!server_via_builder.tcp_nodelay); assert_eq!( server_via_builder.tcp_keepalive, Some(EXAMPLE_TCP_KEEPALIVE) ); + assert_eq!( + server_via_builder.tcp_keepalive_interval, + Some(EXAMPLE_TCP_KEEPALIVE_INTERVAL) + ); + assert_eq!( + server_via_builder.tcp_keepalive_retries, + Some(EXAMPLE_TCP_KEEPALIVE_RETRIES) + ); } }