From c8c32f31984aa29b0ed68186159be5ed9a07b73c Mon Sep 17 00:00:00 2001 From: Mauro D Date: Wed, 16 Aug 2023 19:06:57 +0200 Subject: [PATCH] Added nodelay socket option --- Cargo.lock | 2 +- crates/utils/Cargo.toml | 2 +- crates/utils/src/config/listener.rs | 44 ++++++++++++++------------- crates/utils/src/config/mod.rs | 6 +++- crates/utils/src/listener/listen.rs | 46 +++++++++++++++++++++++------ resources/config/common.toml | 1 + tests/src/smtp/config.rs | 8 +++++ 7 files changed, 77 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 975197ea..39b08235 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5748,7 +5748,7 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "utils" -version = "0.1.0" +version = "0.3.4" dependencies = [ "ahash 0.8.3", "dashmap", diff --git a/crates/utils/Cargo.toml b/crates/utils/Cargo.toml index 5ef2f58f..f6b5d4df 100644 --- a/crates/utils/Cargo.toml +++ b/crates/utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "utils" -version = "0.1.0" +version = "0.3.4" edition = "2021" resolver = "2" diff --git a/crates/utils/src/config/listener.rs b/crates/utils/src/config/listener.rs index bb46e371..ead99609 100644 --- a/crates/utils/src/config/listener.rs +++ b/crates/utils/src/config/listener.rs @@ -21,7 +21,7 @@ * for more details. */ -use std::{net::SocketAddr, sync::Arc, time::Duration}; +use std::{net::SocketAddr, sync::Arc}; use rustls::{ cipher_suite::{ @@ -209,8 +209,6 @@ impl Config { TcpSocket::new_v6() } .map_err(|err| format!("Failed to create socket: {err}"))?; - let mut backlog = None; - let mut ttl = None; // Set socket options for option in [ @@ -218,10 +216,7 @@ impl Config { "reuse-port", "send-buffer-size", "recv-buffer-size", - "linger", "tos", - "backlog", - "ttl", ] { if let Some(value) = self.value_or_default( ("server.listener", id, "socket", option), @@ -234,18 +229,7 @@ impl Config { "reuse-port" => socket.set_reuseport(value.parse_key(key)?), "send-buffer-size" => socket.set_send_buffer_size(value.parse_key(key)?), "recv-buffer-size" => socket.set_recv_buffer_size(value.parse_key(key)?), - "linger" => { - socket.set_linger(Duration::from_millis(value.parse_key(key)?).into()) - } "tos" => socket.set_tos(value.parse_key(key)?), - "backlog" => { - backlog = Some(value.parse_key(key)?); - continue; - } - "ttl" => { - ttl = Some(value.parse_key(key)?); - continue; - } _ => unreachable!(), } .map_err(|err| { @@ -257,8 +241,24 @@ impl Config { listeners.push(Listener { socket, addr, - ttl, - backlog, + ttl: self.property_or_default( + ("server.listener", id, "socket.ttl"), + "server.socket.ttl", + )?, + backlog: self.property_or_default( + ("server.listener", id, "socket.backlog"), + "server.socket.backlog", + )?, + linger: self.property_or_default( + ("server.listener", id, "socket.linger"), + "server.socket.linger", + )?, + nodelay: self + .property_or_default( + ("server.listener", id, "socket.nodelay"), + "server.socket.nodelay", + )? + .unwrap_or(true), }); } @@ -278,7 +278,11 @@ impl Config { data: match protocol { ServerProtocol::Smtp | ServerProtocol::Lmtp => self .value_or_default(("server.listener", id, "greeting"), "server.greeting") - .unwrap_or("Stalwart SMTP at your service") + .unwrap_or(concat!( + "Stalwart SMTP v", + env!("CARGO_PKG_VERSION"), + " at your service." + )) .to_string(), ServerProtocol::Jmap => self diff --git a/crates/utils/src/config/mod.rs b/crates/utils/src/config/mod.rs index 217354a2..e71d46e5 100644 --- a/crates/utils/src/config/mod.rs +++ b/crates/utils/src/config/mod.rs @@ -68,8 +68,12 @@ pub struct Servers { pub struct Listener { pub socket: TcpSocket, pub addr: SocketAddr, - pub ttl: Option, pub backlog: Option, + + // TCP options + pub ttl: Option, + pub linger: Option, + pub nodelay: bool, } #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)] diff --git a/crates/utils/src/listener/listen.rs b/crates/utils/src/listener/listen.rs index 80210633..7cf76c0e 100644 --- a/crates/utils/src/listener/listen.rs +++ b/crates/utils/src/listener/listen.rs @@ -70,6 +70,11 @@ impl Server { ); let local_ip = listener.addr.ip(); + // Obtain TCP options + let nodelay = listener.nodelay; + let ttl = listener.ttl; + let linger = listener.linger; + // Bind socket let listener = listener.listen(); @@ -93,6 +98,36 @@ impl Server { remote.port = remote_addr.port(), ); + // Set TCP options + if let Err(err) = stream.set_nodelay(nodelay) { + tracing::warn!( + context = "tcp", + event = "error", + instance = instance.id, + protocol = ?instance.protocol, + "Failed to set no-delay: {}", err); + } + if let Some(ttl) = ttl { + if let Err(err) = stream.set_ttl(ttl) { + tracing::warn!( + context = "tcp", + event = "error", + instance = instance.id, + protocol = ?instance.protocol, + "Failed to set TTL: {}", err); + } + } + if linger.is_some() { + if let Err(err) = stream.set_linger(linger) { + tracing::warn!( + context = "tcp", + event = "error", + instance = instance.id, + protocol = ?instance.protocol, + "Failed to set linger: {}", err); + } + } + // Spawn connection manager.spawn(SessionData { stream, @@ -179,16 +214,9 @@ impl Servers { impl Listener { pub fn listen(self) -> TcpListener { - let listener = self - .socket + self.socket .listen(self.backlog.unwrap_or(1024)) - .unwrap_or_else(|err| failed(&format!("Failed to listen on {}: {}", self.addr, err))); - if let Some(ttl) = self.ttl { - listener.set_ttl(ttl).unwrap_or_else(|err| { - failed(&format!("Failed to set TTL on {}: {}", self.addr, err)) - }); - } - listener + .unwrap_or_else(|err| failed(&format!("Failed to listen on {}: {}", self.addr, err))) } } diff --git a/resources/config/common.toml b/resources/config/common.toml index 9b621ade..0abe10ae 100644 --- a/resources/config/common.toml +++ b/resources/config/common.toml @@ -21,6 +21,7 @@ certificate = "default" ignore-client-order = true [server.socket] +nodelay = true reuse-addr = true #reuse-port = true backlog = 1024 diff --git a/tests/src/smtp/config.rs b/tests/src/smtp/config.rs index b441b994..08ec1d5b 100644 --- a/tests/src/smtp/config.rs +++ b/tests/src/smtp/config.rs @@ -438,6 +438,8 @@ fn parse_servers() { addr: "127.0.0.1:9925".parse().unwrap(), ttl: 3600.into(), backlog: 1024.into(), + linger: None, + nodelay: true, }], tls: None, tls_implicit: false, @@ -455,12 +457,16 @@ fn parse_servers() { addr: "127.0.0.1:9465".parse().unwrap(), ttl: 4096.into(), backlog: 1024.into(), + linger: None, + nodelay: true, }, Listener { socket: TcpSocket::new_v4().unwrap(), addr: "127.0.0.1:9466".parse().unwrap(), ttl: 4096.into(), backlog: 1024.into(), + linger: None, + nodelay: true, }, ], tls: None, @@ -478,6 +484,8 @@ fn parse_servers() { addr: "127.0.0.1:9991".parse().unwrap(), ttl: 3600.into(), backlog: 2048.into(), + linger: None, + nodelay: true, }], tls: None, tls_implicit: true,