Added nodelay socket option

This commit is contained in:
Mauro D 2023-08-16 19:06:57 +02:00
parent 0c95388a70
commit c8c32f3198
7 changed files with 77 additions and 32 deletions

2
Cargo.lock generated
View file

@ -5748,7 +5748,7 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]] [[package]]
name = "utils" name = "utils"
version = "0.1.0" version = "0.3.4"
dependencies = [ dependencies = [
"ahash 0.8.3", "ahash 0.8.3",
"dashmap", "dashmap",

View file

@ -1,6 +1,6 @@
[package] [package]
name = "utils" name = "utils"
version = "0.1.0" version = "0.3.4"
edition = "2021" edition = "2021"
resolver = "2" resolver = "2"

View file

@ -21,7 +21,7 @@
* for more details. * for more details.
*/ */
use std::{net::SocketAddr, sync::Arc, time::Duration}; use std::{net::SocketAddr, sync::Arc};
use rustls::{ use rustls::{
cipher_suite::{ cipher_suite::{
@ -209,8 +209,6 @@ impl Config {
TcpSocket::new_v6() TcpSocket::new_v6()
} }
.map_err(|err| format!("Failed to create socket: {err}"))?; .map_err(|err| format!("Failed to create socket: {err}"))?;
let mut backlog = None;
let mut ttl = None;
// Set socket options // Set socket options
for option in [ for option in [
@ -218,10 +216,7 @@ impl Config {
"reuse-port", "reuse-port",
"send-buffer-size", "send-buffer-size",
"recv-buffer-size", "recv-buffer-size",
"linger",
"tos", "tos",
"backlog",
"ttl",
] { ] {
if let Some(value) = self.value_or_default( if let Some(value) = self.value_or_default(
("server.listener", id, "socket", option), ("server.listener", id, "socket", option),
@ -234,18 +229,7 @@ impl Config {
"reuse-port" => socket.set_reuseport(value.parse_key(key)?), "reuse-port" => socket.set_reuseport(value.parse_key(key)?),
"send-buffer-size" => socket.set_send_buffer_size(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)?), "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)?), "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!(), _ => unreachable!(),
} }
.map_err(|err| { .map_err(|err| {
@ -257,8 +241,24 @@ impl Config {
listeners.push(Listener { listeners.push(Listener {
socket, socket,
addr, addr,
ttl, ttl: self.property_or_default(
backlog, ("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 { data: match protocol {
ServerProtocol::Smtp | ServerProtocol::Lmtp => self ServerProtocol::Smtp | ServerProtocol::Lmtp => self
.value_or_default(("server.listener", id, "greeting"), "server.greeting") .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(), .to_string(),
ServerProtocol::Jmap => self ServerProtocol::Jmap => self

View file

@ -68,8 +68,12 @@ pub struct Servers {
pub struct Listener { pub struct Listener {
pub socket: TcpSocket, pub socket: TcpSocket,
pub addr: SocketAddr, pub addr: SocketAddr,
pub ttl: Option<u32>,
pub backlog: Option<u32>, pub backlog: Option<u32>,
// TCP options
pub ttl: Option<u32>,
pub linger: Option<Duration>,
pub nodelay: bool,
} }
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)] #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]

View file

@ -70,6 +70,11 @@ impl Server {
); );
let local_ip = listener.addr.ip(); let local_ip = listener.addr.ip();
// Obtain TCP options
let nodelay = listener.nodelay;
let ttl = listener.ttl;
let linger = listener.linger;
// Bind socket // Bind socket
let listener = listener.listen(); let listener = listener.listen();
@ -93,6 +98,36 @@ impl Server {
remote.port = remote_addr.port(), 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 // Spawn connection
manager.spawn(SessionData { manager.spawn(SessionData {
stream, stream,
@ -179,16 +214,9 @@ impl Servers {
impl Listener { impl Listener {
pub fn listen(self) -> TcpListener { pub fn listen(self) -> TcpListener {
let listener = self self.socket
.socket
.listen(self.backlog.unwrap_or(1024)) .listen(self.backlog.unwrap_or(1024))
.unwrap_or_else(|err| failed(&format!("Failed to listen on {}: {}", self.addr, err))); .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
} }
} }

View file

@ -21,6 +21,7 @@ certificate = "default"
ignore-client-order = true ignore-client-order = true
[server.socket] [server.socket]
nodelay = true
reuse-addr = true reuse-addr = true
#reuse-port = true #reuse-port = true
backlog = 1024 backlog = 1024

View file

@ -438,6 +438,8 @@ fn parse_servers() {
addr: "127.0.0.1:9925".parse().unwrap(), addr: "127.0.0.1:9925".parse().unwrap(),
ttl: 3600.into(), ttl: 3600.into(),
backlog: 1024.into(), backlog: 1024.into(),
linger: None,
nodelay: true,
}], }],
tls: None, tls: None,
tls_implicit: false, tls_implicit: false,
@ -455,12 +457,16 @@ fn parse_servers() {
addr: "127.0.0.1:9465".parse().unwrap(), addr: "127.0.0.1:9465".parse().unwrap(),
ttl: 4096.into(), ttl: 4096.into(),
backlog: 1024.into(), backlog: 1024.into(),
linger: None,
nodelay: true,
}, },
Listener { Listener {
socket: TcpSocket::new_v4().unwrap(), socket: TcpSocket::new_v4().unwrap(),
addr: "127.0.0.1:9466".parse().unwrap(), addr: "127.0.0.1:9466".parse().unwrap(),
ttl: 4096.into(), ttl: 4096.into(),
backlog: 1024.into(), backlog: 1024.into(),
linger: None,
nodelay: true,
}, },
], ],
tls: None, tls: None,
@ -478,6 +484,8 @@ fn parse_servers() {
addr: "127.0.0.1:9991".parse().unwrap(), addr: "127.0.0.1:9991".parse().unwrap(),
ttl: 3600.into(), ttl: 3600.into(),
backlog: 2048.into(), backlog: 2048.into(),
linger: None,
nodelay: true,
}], }],
tls: None, tls: None,
tls_implicit: true, tls_implicit: true,