diff --git a/src/imap/client.rs b/src/imap/client.rs index e27580c44..d82f6c8e6 100644 --- a/src/imap/client.rs +++ b/src/imap/client.rs @@ -1,7 +1,4 @@ -use std::{ - ops::{Deref, DerefMut}, - time::Duration, -}; +use std::ops::{Deref, DerefMut}; use anyhow::{Context as _, Result}; use async_imap::Client as ImapClient; @@ -17,9 +14,6 @@ use crate::net::{connect_starttls_imap, connect_tcp, connect_tls}; use crate::socks::Socks5Config; use fast_socks5::client::Socks5Stream; -/// IMAP connection, write and read timeout. -pub(crate) const IMAP_TIMEOUT: Duration = Duration::from_secs(60); - #[derive(Debug)] pub(crate) struct Client { inner: ImapClient>, @@ -104,8 +98,7 @@ impl Client { port: u16, strict_tls: bool, ) -> Result { - let tls_stream = - connect_tls(context, hostname, port, IMAP_TIMEOUT, strict_tls, "imap").await?; + let tls_stream = connect_tls(context, hostname, port, strict_tls, "imap").await?; let buffered_stream = BufWriter::new(tls_stream); let session_stream: Box = Box::new(buffered_stream); let mut client = Client::new(session_stream); @@ -117,7 +110,7 @@ impl Client { } pub async fn connect_insecure(context: &Context, hostname: &str, port: u16) -> Result { - let tcp_stream = connect_tcp(context, hostname, port, IMAP_TIMEOUT, false).await?; + let tcp_stream = connect_tcp(context, hostname, port, false).await?; let buffered_stream = BufWriter::new(tcp_stream); let session_stream: Box = Box::new(buffered_stream); let mut client = Client::new(session_stream); @@ -134,8 +127,7 @@ impl Client { port: u16, strict_tls: bool, ) -> Result { - let tls_stream = - connect_starttls_imap(context, hostname, port, IMAP_TIMEOUT, strict_tls).await?; + let tls_stream = connect_starttls_imap(context, hostname, port, strict_tls).await?; let buffered_stream = BufWriter::new(tls_stream); let session_stream: Box = Box::new(buffered_stream); @@ -151,7 +143,7 @@ impl Client { socks5_config: Socks5Config, ) -> Result { let socks5_stream = socks5_config - .connect(context, domain, port, IMAP_TIMEOUT, strict_tls) + .connect(context, domain, port, strict_tls) .await?; let tls_stream = wrap_tls(strict_tls, domain, "imap", socks5_stream).await?; let buffered_stream = BufWriter::new(tls_stream); @@ -170,9 +162,7 @@ impl Client { port: u16, socks5_config: Socks5Config, ) -> Result { - let socks5_stream = socks5_config - .connect(context, domain, port, IMAP_TIMEOUT, false) - .await?; + let socks5_stream = socks5_config.connect(context, domain, port, false).await?; let buffered_stream = BufWriter::new(socks5_stream); let session_stream: Box = Box::new(buffered_stream); let mut client = Client::new(session_stream); @@ -191,7 +181,7 @@ impl Client { strict_tls: bool, ) -> Result { let socks5_stream = socks5_config - .connect(context, hostname, port, IMAP_TIMEOUT, strict_tls) + .connect(context, hostname, port, strict_tls) .await?; // Run STARTTLS command and convert the client back into a stream. diff --git a/src/imap/idle.rs b/src/imap/idle.rs index 0bb3afe77..892e8757b 100644 --- a/src/imap/idle.rs +++ b/src/imap/idle.rs @@ -9,7 +9,8 @@ use tokio::time::timeout; use super::session::Session; use super::Imap; use crate::context::Context; -use crate::imap::{client::IMAP_TIMEOUT, FolderMeaning}; +use crate::imap::FolderMeaning; +use crate::net::TIMEOUT; use crate::tools::{self, time_elapsed}; /// Timeout after which IDLE is finished @@ -51,7 +52,7 @@ impl Session { // At this point IDLE command was sent and we received a "+ idling" response. We will now // read from the stream without getting any data for up to `IDLE_TIMEOUT`. If we don't - // disable read timeout, we would get a timeout after `IMAP_TIMEOUT`, which is a lot + // disable read timeout, we would get a timeout after `crate::net::TIMEOUT`, which is a lot // shorter than `IDLE_TIMEOUT`. handle.as_mut().set_read_timeout(None); let (idle_wait, interrupt) = handle.wait_with_timeout(IDLE_TIMEOUT); @@ -93,7 +94,7 @@ impl Session { .await .with_context(|| format!("{folder}: IMAP IDLE protocol timed out"))? .with_context(|| format!("{folder}: IMAP IDLE failed"))?; - session.as_mut().set_read_timeout(Some(IMAP_TIMEOUT)); + session.as_mut().set_read_timeout(Some(TIMEOUT)); self.inner = session; // Fetch mail once we exit IDLE. diff --git a/src/net.rs b/src/net.rs index d51988cb7..535f0ba7b 100644 --- a/src/net.rs +++ b/src/net.rs @@ -22,16 +22,18 @@ use dns::lookup_host_with_cache; pub use http::{read_url, read_url_blob, Response as HttpResponse}; use tls::wrap_tls; +/// Connection, write and read timeout. +/// +/// This constant should be more than the largest expected RTT. +pub(crate) const TIMEOUT: Duration = Duration::from_secs(60); + /// Returns a TCP connection stream with read/write timeouts set /// and Nagle's algorithm disabled with `TCP_NODELAY`. /// /// `TCP_NODELAY` ensures writing to the stream always results in immediate sending of the packet /// to the network, which is important to reduce the latency of interactive protocols such as IMAP. -async fn connect_tcp_inner( - addr: SocketAddr, - timeout_val: Duration, -) -> Result>>> { - let tcp_stream = timeout(timeout_val, TcpStream::connect(addr)) +async fn connect_tcp_inner(addr: SocketAddr) -> Result>>> { + let tcp_stream = timeout(TIMEOUT, TcpStream::connect(addr)) .await .context("connection timeout")? .context("connection failure")?; @@ -40,8 +42,8 @@ async fn connect_tcp_inner( tcp_stream.set_nodelay(true)?; let mut timeout_stream = TimeoutStream::new(tcp_stream); - timeout_stream.set_write_timeout(Some(timeout_val)); - timeout_stream.set_read_timeout(Some(timeout_val)); + timeout_stream.set_write_timeout(Some(TIMEOUT)); + timeout_stream.set_read_timeout(Some(TIMEOUT)); Ok(Box::pin(timeout_stream)) } @@ -50,12 +52,11 @@ async fn connect_tcp_inner( /// given the result of the hostname to address resolution. async fn connect_tls_inner( addr: SocketAddr, - timeout_val: Duration, host: &str, strict_tls: bool, alpn: &str, ) -> Result>>>> { - let tcp_stream = connect_tcp_inner(addr, timeout_val).await?; + let tcp_stream = connect_tcp_inner(addr).await?; let tls_stream = wrap_tls(strict_tls, host, alpn, tcp_stream).await?; Ok(tls_stream) } @@ -70,15 +71,12 @@ pub(crate) async fn connect_tcp( context: &Context, host: &str, port: u16, - timeout_val: Duration, load_cache: bool, ) -> Result>>> { let mut first_error = None; - for resolved_addr in - lookup_host_with_cache(context, host, port, timeout_val, load_cache).await? - { - match connect_tcp_inner(resolved_addr, timeout_val).await { + for resolved_addr in lookup_host_with_cache(context, host, port, load_cache).await? { + match connect_tcp_inner(resolved_addr).await { Ok(stream) => { return Ok(stream); } @@ -99,16 +97,13 @@ pub(crate) async fn connect_tls( context: &Context, host: &str, port: u16, - timeout_val: Duration, strict_tls: bool, alpn: &str, ) -> Result>>>> { let mut first_error = None; - for resolved_addr in - lookup_host_with_cache(context, host, port, timeout_val, strict_tls).await? - { - match connect_tls_inner(resolved_addr, timeout_val, host, strict_tls, alpn).await { + for resolved_addr in lookup_host_with_cache(context, host, port, strict_tls).await? { + match connect_tls_inner(resolved_addr, host, strict_tls, alpn).await { Ok(tls_stream) => { if strict_tls { dns::update_connect_timestamp(context, host, &resolved_addr.ip().to_string()) @@ -129,10 +124,9 @@ pub(crate) async fn connect_tls( async fn connect_starttls_imap_inner( addr: SocketAddr, host: &str, - timeout_val: Duration, strict_tls: bool, ) -> Result>>>> { - let tcp_stream = connect_tcp_inner(addr, timeout_val).await?; + let tcp_stream = connect_tcp_inner(addr).await?; // Run STARTTLS command and convert the client back into a stream. let buffered_tcp_stream = BufWriter::new(tcp_stream); @@ -159,15 +153,12 @@ pub(crate) async fn connect_starttls_imap( context: &Context, host: &str, port: u16, - timeout_val: Duration, strict_tls: bool, ) -> Result>>>> { let mut first_error = None; - for resolved_addr in - lookup_host_with_cache(context, host, port, timeout_val, strict_tls).await? - { - match connect_starttls_imap_inner(resolved_addr, host, timeout_val, strict_tls).await { + for resolved_addr in lookup_host_with_cache(context, host, port, strict_tls).await? { + match connect_starttls_imap_inner(resolved_addr, host, strict_tls).await { Ok(tls_stream) => { if strict_tls { dns::update_connect_timestamp(context, host, &resolved_addr.ip().to_string()) @@ -188,10 +179,9 @@ pub(crate) async fn connect_starttls_imap( async fn connect_starttls_smtp_inner( addr: SocketAddr, host: &str, - timeout_val: Duration, strict_tls: bool, ) -> Result>>>> { - let tcp_stream = connect_tcp_inner(addr, timeout_val).await?; + let tcp_stream = connect_tcp_inner(addr).await?; // Run STARTTLS command and convert the client back into a stream. let client = async_smtp::SmtpClient::new().smtp_utf8(true); @@ -207,15 +197,12 @@ pub(crate) async fn connect_starttls_smtp( context: &Context, host: &str, port: u16, - timeout_val: Duration, strict_tls: bool, ) -> Result>>>> { let mut first_error = None; - for resolved_addr in - lookup_host_with_cache(context, host, port, timeout_val, strict_tls).await? - { - match connect_starttls_smtp_inner(resolved_addr, host, timeout_val, strict_tls).await { + for resolved_addr in lookup_host_with_cache(context, host, port, strict_tls).await? { + match connect_starttls_smtp_inner(resolved_addr, host, strict_tls).await { Ok(tls_stream) => { if strict_tls { dns::update_connect_timestamp(context, host, &resolved_addr.ip().to_string()) diff --git a/src/net/dns.rs b/src/net/dns.rs index 96dbaca36..afd4379f1 100644 --- a/src/net/dns.rs +++ b/src/net/dns.rs @@ -3,19 +3,14 @@ use anyhow::{Context as _, Result}; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; use std::str::FromStr; -use std::time::Duration; use tokio::net::lookup_host; use tokio::time::timeout; use crate::context::Context; use crate::tools::time; -async fn lookup_host_with_timeout( - hostname: &str, - port: u16, - timeout_val: Duration, -) -> Result> { - let res = timeout(timeout_val, lookup_host((hostname, port))) +async fn lookup_host_with_timeout(hostname: &str, port: u16) -> Result> { + let res = timeout(super::TIMEOUT, lookup_host((hostname, port))) .await .context("DNS lookup timeout")? .context("DNS lookup failure")?; @@ -66,11 +61,10 @@ pub(crate) async fn lookup_host_with_cache( context: &Context, hostname: &str, port: u16, - timeout_val: Duration, load_cache: bool, ) -> Result> { let now = time(); - let mut resolved_addrs = match lookup_host_with_timeout(hostname, port, timeout_val).await { + let mut resolved_addrs = match lookup_host_with_timeout(hostname, port).await { Ok(res) => res, Err(err) => { warn!( diff --git a/src/net/http.rs b/src/net/http.rs index ea334a7fb..4037a00e7 100644 --- a/src/net/http.rs +++ b/src/net/http.rs @@ -1,7 +1,6 @@ //! # HTTP module. use std::sync::Arc; -use std::time::Duration; use anyhow::{anyhow, Result}; use mime::Mime; @@ -11,8 +10,6 @@ use crate::context::Context; use crate::net::lookup_host_with_cache; use crate::socks::Socks5Config; -const HTTP_TIMEOUT: Duration = Duration::from_secs(30); - static LETSENCRYPT_ROOT: Lazy = Lazy::new(|| { reqwest::tls::Certificate::from_der(include_bytes!( "../../assets/root-certificates/letsencrypt/isrgrootx1.der" @@ -122,8 +119,7 @@ impl reqwest::dns::Resolve for CustomResolver { let port = 443; // Actual port does not matter. let socket_addrs = - lookup_host_with_cache(&context, hostname.as_str(), port, HTTP_TIMEOUT, load_cache) - .await; + lookup_host_with_cache(&context, hostname.as_str(), port, load_cache).await; match socket_addrs { Ok(socket_addrs) => { let addrs: reqwest::dns::Addrs = Box::new(socket_addrs.into_iter()); @@ -141,7 +137,7 @@ pub(crate) async fn get_client(context: &Context, load_cache: bool) -> Result Result>> { let socks5_stream = socks5_config - .connect(context, hostname, port, SMTP_TIMEOUT, strict_tls) + .connect(context, hostname, port, strict_tls) .await?; let tls_stream = wrap_tls(strict_tls, hostname, "smtp", socks5_stream).await?; let buffered_stream = BufStream::new(tls_stream); @@ -137,7 +132,7 @@ impl Smtp { socks5_config: Socks5Config, ) -> Result>> { let socks5_stream = socks5_config - .connect(context, hostname, port, SMTP_TIMEOUT, strict_tls) + .connect(context, hostname, port, strict_tls) .await?; // Run STARTTLS command and convert the client back into a stream. @@ -162,7 +157,7 @@ impl Smtp { socks5_config: Socks5Config, ) -> Result>> { let socks5_stream = socks5_config - .connect(context, hostname, port, SMTP_TIMEOUT, false) + .connect(context, hostname, port, false) .await?; let buffered_stream = BufStream::new(socks5_stream); let session_stream: Box = Box::new(buffered_stream); @@ -178,8 +173,7 @@ impl Smtp { port: u16, strict_tls: bool, ) -> Result>> { - let tls_stream = - connect_tls(context, hostname, port, SMTP_TIMEOUT, strict_tls, "smtp").await?; + let tls_stream = connect_tls(context, hostname, port, strict_tls, "smtp").await?; let buffered_stream = BufStream::new(tls_stream); let session_stream: Box = Box::new(buffered_stream); let client = smtp::SmtpClient::new().smtp_utf8(true); @@ -194,8 +188,7 @@ impl Smtp { port: u16, strict_tls: bool, ) -> Result>> { - let tls_stream = - connect_starttls_smtp(context, hostname, port, SMTP_TIMEOUT, strict_tls).await?; + let tls_stream = connect_starttls_smtp(context, hostname, port, strict_tls).await?; let buffered_stream = BufStream::new(tls_stream); let session_stream: Box = Box::new(buffered_stream); @@ -210,7 +203,7 @@ impl Smtp { hostname: &str, port: u16, ) -> Result>> { - let tcp_stream = connect_tcp(context, hostname, port, SMTP_TIMEOUT, false).await?; + let tcp_stream = connect_tcp(context, hostname, port, false).await?; let buffered_stream = BufStream::new(tcp_stream); let session_stream: Box = Box::new(buffered_stream); let client = smtp::SmtpClient::new().smtp_utf8(true); diff --git a/src/socks.rs b/src/socks.rs index f409008ff..3a5eecde9 100644 --- a/src/socks.rs +++ b/src/socks.rs @@ -2,7 +2,6 @@ use std::fmt; use std::pin::Pin; -use std::time::Duration; use anyhow::Result; use fast_socks5::client::{Config, Socks5Stream}; @@ -76,11 +75,9 @@ impl Socks5Config { context: &Context, target_host: &str, target_port: u16, - timeout_val: Duration, load_dns_cache: bool, ) -> Result>>>> { - let tcp_stream = - connect_tcp(context, &self.host, self.port, timeout_val, load_dns_cache).await?; + let tcp_stream = connect_tcp(context, &self.host, self.port, load_dns_cache).await?; let authentication_method = if let Some((username, password)) = self.user_password.as_ref() {