From b4c05f4f81152f430bb196a5b1956e1e36a6fcff Mon Sep 17 00:00:00 2001 From: Paul Hemberger Date: Fri, 24 Mar 2023 11:46:20 -0400 Subject: [PATCH 1/4] wire through knob for TCP user timeout --- tokio-postgres/Cargo.toml | 2 +- tokio-postgres/src/cancel_query.rs | 1 + tokio-postgres/src/client.rs | 1 + tokio-postgres/src/config.rs | 14 ++++++++++++++ tokio-postgres/src/connect.rs | 2 ++ tokio-postgres/src/connect_socket.rs | 12 +++++++++++- 6 files changed, 30 insertions(+), 2 deletions(-) diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 68737f738..807698f88 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -55,7 +55,7 @@ pin-project-lite = "0.2" phf = "0.11" postgres-protocol = { version = "0.6.4", path = "../postgres-protocol" } postgres-types = { version = "0.2.4", path = "../postgres-types" } -socket2 = "0.4" +socket2 = { version = "0.4", features = ["all"] } tokio = { version = "1.0", features = ["io-util"] } tokio-util = { version = "0.7", features = ["codec"] } diff --git a/tokio-postgres/src/cancel_query.rs b/tokio-postgres/src/cancel_query.rs index b02729f85..022278804 100644 --- a/tokio-postgres/src/cancel_query.rs +++ b/tokio-postgres/src/cancel_query.rs @@ -38,6 +38,7 @@ where &config.host, config.port, config.connect_timeout, + config.user_timeout, config.keepalive.as_ref(), ) .await?; diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index 5d0d2c536..9760ee55b 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -156,6 +156,7 @@ pub(crate) struct SocketConfig { pub host: Host, pub port: u16, pub connect_timeout: Option, + pub user_timeout: Option, pub keepalive: Option, } diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index 5b364ec06..5930fbd9e 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -160,6 +160,7 @@ pub struct Config { pub(crate) host: Vec, pub(crate) port: Vec, pub(crate) connect_timeout: Option, + pub(crate) user_timeout: Option, pub(crate) keepalives: bool, pub(crate) keepalive_config: KeepaliveConfig, pub(crate) target_session_attrs: TargetSessionAttrs, @@ -190,6 +191,7 @@ impl Config { host: vec![], port: vec![], connect_timeout: None, + user_timeout: None, keepalives: true, keepalive_config, target_session_attrs: TargetSessionAttrs::Any, @@ -340,6 +342,18 @@ impl Config { self.connect_timeout.as_ref() } + /// Sets the TCP user timeout. + pub fn user_timeout(&mut self, user_timeout: Duration) -> &mut Config { + self.user_timeout = Some(user_timeout); + self + } + + /// Gets the TCP user timeout, if one has been set with the + /// `user_timeout` method. + pub fn get_user_timeout(&self) -> Option<&Duration> { + self.user_timeout.as_ref() + } + /// Controls the use of TCP keepalive. /// /// This is ignored for Unix domain socket connections. Defaults to `true`. diff --git a/tokio-postgres/src/connect.rs b/tokio-postgres/src/connect.rs index 97a00c812..0006be154 100644 --- a/tokio-postgres/src/connect.rs +++ b/tokio-postgres/src/connect.rs @@ -65,6 +65,7 @@ where host, port, config.connect_timeout, + config.user_timeout, if config.keepalives { Some(&config.keepalive_config) } else { @@ -118,6 +119,7 @@ where host: host.clone(), port, connect_timeout: config.connect_timeout, + user_timeout: config.user_timeout, keepalive: if config.keepalives { Some(config.keepalive_config.clone()) } else { diff --git a/tokio-postgres/src/connect_socket.rs b/tokio-postgres/src/connect_socket.rs index 19d01d87a..3380ccae9 100644 --- a/tokio-postgres/src/connect_socket.rs +++ b/tokio-postgres/src/connect_socket.rs @@ -14,6 +14,7 @@ pub(crate) async fn connect_socket( host: &Host, port: u16, connect_timeout: Option, + user_timeout: Option, keepalive_config: Option<&KeepaliveConfig>, ) -> Result { match host { @@ -35,8 +36,17 @@ pub(crate) async fn connect_socket( }; stream.set_nodelay(true).map_err(Error::connect)?; + + let sock_ref = SockRef::from(&stream); + #[cfg(target_os = "linux")] + { + sock_ref + .set_tcp_user_timeout(user_timeout) + .map_err(Error::timeout)?; + } + if let Some(keepalive_config) = keepalive_config { - SockRef::from(&stream) + sock_ref .set_tcp_keepalive(&TcpKeepalive::from(keepalive_config)) .map_err(Error::connect)?; } From ee5a139028f9f470f4adae61d80e0404fe310ab2 Mon Sep 17 00:00:00 2001 From: Paul Hemberger Date: Fri, 24 Mar 2023 13:11:18 -0400 Subject: [PATCH 2/4] add in to param parsing; update doc --- tokio-postgres/src/cancel_query.rs | 2 +- tokio-postgres/src/client.rs | 2 +- tokio-postgres/src/config.rs | 28 ++++++++++++++++++++++------ tokio-postgres/src/connect.rs | 4 ++-- tokio-postgres/src/connect_socket.rs | 4 ++-- 5 files changed, 28 insertions(+), 12 deletions(-) diff --git a/tokio-postgres/src/cancel_query.rs b/tokio-postgres/src/cancel_query.rs index 022278804..d869b5824 100644 --- a/tokio-postgres/src/cancel_query.rs +++ b/tokio-postgres/src/cancel_query.rs @@ -38,7 +38,7 @@ where &config.host, config.port, config.connect_timeout, - config.user_timeout, + config.tcp_user_timeout, config.keepalive.as_ref(), ) .await?; diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index 9760ee55b..8b7df4e87 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -156,7 +156,7 @@ pub(crate) struct SocketConfig { pub host: Host, pub port: u16, pub connect_timeout: Option, - pub user_timeout: Option, + pub tcp_user_timeout: Option, pub keepalive: Option, } diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index 5930fbd9e..fd848153f 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -96,6 +96,9 @@ pub enum Host { /// omitted or the empty string. /// * `connect_timeout` - The time limit in seconds applied to each socket-level connection attempt. Note that hostnames /// can resolve to multiple IP addresses, and this limit is applied to each address. Defaults to no timeout. +/// * `tcp_user_timeout` - The time limit that transmitted data may remain unacknowledged before a connection is forcibly closed. +/// This is ignored for Unix domain socket connections. It is only supported on systems where TCP_USER_TIMEOUT is available +/// and will default to the system default; on other systems, it has no effect. /// * `keepalives` - Controls the use of TCP keepalive. A value of 0 disables keepalive and nonzero integers enable it. /// This option is ignored when connecting with Unix sockets. Defaults to on. /// * `keepalives_idle` - The number of seconds of inactivity after which a keepalive message is sent to the server. @@ -160,7 +163,7 @@ pub struct Config { pub(crate) host: Vec, pub(crate) port: Vec, pub(crate) connect_timeout: Option, - pub(crate) user_timeout: Option, + pub(crate) tcp_user_timeout: Option, pub(crate) keepalives: bool, pub(crate) keepalive_config: KeepaliveConfig, pub(crate) target_session_attrs: TargetSessionAttrs, @@ -191,7 +194,7 @@ impl Config { host: vec![], port: vec![], connect_timeout: None, - user_timeout: None, + tcp_user_timeout: None, keepalives: true, keepalive_config, target_session_attrs: TargetSessionAttrs::Any, @@ -343,15 +346,19 @@ impl Config { } /// Sets the TCP user timeout. - pub fn user_timeout(&mut self, user_timeout: Duration) -> &mut Config { - self.user_timeout = Some(user_timeout); + /// + /// This is ignored for Unix domain socket connections. It is only supported on systems where + /// TCP_USER_TIMEOUT is available and will default to the system default; on other systems, + /// it has no effect. + pub fn tcp_user_timeout(&mut self, tcp_user_timeout: Duration) -> &mut Config { + self.tcp_user_timeout = Some(tcp_user_timeout); self } /// Gets the TCP user timeout, if one has been set with the /// `user_timeout` method. - pub fn get_user_timeout(&self) -> Option<&Duration> { - self.user_timeout.as_ref() + pub fn get_tcp_user_timeout(&self) -> Option<&Duration> { + self.tcp_user_timeout.as_ref() } /// Controls the use of TCP keepalive. @@ -488,6 +495,14 @@ impl Config { self.connect_timeout(Duration::from_secs(timeout as u64)); } } + "tcp_user_timeout" => { + let timeout = value + .parse::() + .map_err(|_| Error::config_parse(Box::new(InvalidValue("tcp_user_timeout"))))?; + if timeout > 0 { + self.tcp_user_timeout(Duration::from_secs(timeout as u64)); + } + } "keepalives" => { let keepalives = value .parse::() @@ -609,6 +624,7 @@ impl fmt::Debug for Config { .field("host", &self.host) .field("port", &self.port) .field("connect_timeout", &self.connect_timeout) + .field("tcp_user_timeout", &self.tcp_user_timeout) .field("keepalives", &self.keepalives) .field("keepalives_idle", &self.keepalive_config.idle) .field("keepalives_interval", &self.keepalive_config.interval) diff --git a/tokio-postgres/src/connect.rs b/tokio-postgres/src/connect.rs index 0006be154..ed7ecac66 100644 --- a/tokio-postgres/src/connect.rs +++ b/tokio-postgres/src/connect.rs @@ -65,7 +65,7 @@ where host, port, config.connect_timeout, - config.user_timeout, + config.tcp_user_timeout, if config.keepalives { Some(&config.keepalive_config) } else { @@ -119,7 +119,7 @@ where host: host.clone(), port, connect_timeout: config.connect_timeout, - user_timeout: config.user_timeout, + tcp_user_timeout: config.tcp_user_timeout, keepalive: if config.keepalives { Some(config.keepalive_config.clone()) } else { diff --git a/tokio-postgres/src/connect_socket.rs b/tokio-postgres/src/connect_socket.rs index 3380ccae9..7937df280 100644 --- a/tokio-postgres/src/connect_socket.rs +++ b/tokio-postgres/src/connect_socket.rs @@ -14,7 +14,7 @@ pub(crate) async fn connect_socket( host: &Host, port: u16, connect_timeout: Option, - user_timeout: Option, + tcp_user_timeout: Option, keepalive_config: Option<&KeepaliveConfig>, ) -> Result { match host { @@ -41,7 +41,7 @@ pub(crate) async fn connect_socket( #[cfg(target_os = "linux")] { sock_ref - .set_tcp_user_timeout(user_timeout) + .set_tcp_user_timeout(tcp_user_timeout) .map_err(Error::timeout)?; } From a9967c05ff40de34e1471bf28cd956e756d1f6f9 Mon Sep 17 00:00:00 2001 From: Paul Hemberger Date: Mon, 27 Mar 2023 16:47:48 -0400 Subject: [PATCH 3/4] docs: mention sys default if 0 --- tokio-postgres/src/config.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index fd848153f..a8aa7a9f5 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -98,7 +98,7 @@ pub enum Host { /// can resolve to multiple IP addresses, and this limit is applied to each address. Defaults to no timeout. /// * `tcp_user_timeout` - The time limit that transmitted data may remain unacknowledged before a connection is forcibly closed. /// This is ignored for Unix domain socket connections. It is only supported on systems where TCP_USER_TIMEOUT is available -/// and will default to the system default; on other systems, it has no effect. +/// and will default to the system default if omitted or set to 0; on other systems, it has no effect. /// * `keepalives` - Controls the use of TCP keepalive. A value of 0 disables keepalive and nonzero integers enable it. /// This option is ignored when connecting with Unix sockets. Defaults to on. /// * `keepalives_idle` - The number of seconds of inactivity after which a keepalive message is sent to the server. @@ -348,8 +348,8 @@ impl Config { /// Sets the TCP user timeout. /// /// This is ignored for Unix domain socket connections. It is only supported on systems where - /// TCP_USER_TIMEOUT is available and will default to the system default; on other systems, - /// it has no effect. + /// TCP_USER_TIMEOUT is available and will default to the system default if omitted or set to 0; + /// on other systems, it has no effect. pub fn tcp_user_timeout(&mut self, tcp_user_timeout: Duration) -> &mut Config { self.tcp_user_timeout = Some(tcp_user_timeout); self From 62a443222c8f660438251ef17cb2ca088f48e207 Mon Sep 17 00:00:00 2001 From: Paul Hemberger Date: Mon, 27 Mar 2023 16:47:58 -0400 Subject: [PATCH 4/4] use correct error type --- tokio-postgres/src/connect_socket.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio-postgres/src/connect_socket.rs b/tokio-postgres/src/connect_socket.rs index 7937df280..9b3d31d72 100644 --- a/tokio-postgres/src/connect_socket.rs +++ b/tokio-postgres/src/connect_socket.rs @@ -42,7 +42,7 @@ pub(crate) async fn connect_socket( { sock_ref .set_tcp_user_timeout(tcp_user_timeout) - .map_err(Error::timeout)?; + .map_err(Error::connect)?; } if let Some(keepalive_config) = keepalive_config {