This is an automated email from the ASF dual-hosted git repository.

hubcio pushed a commit to branch feat/iggy-server-hardening
in repository https://gitbox.apache.org/repos/asf/iggy.git

commit 9ce4dd0fa90c1440ec299d94cdde5f0d9c05aa45
Author: Hubert Gruszecki <[email protected]>
AuthorDate: Fri Jul 24 18:29:10 2026 +0200

    fix(server-ng): source TLS grace from config, align listener backlog
    
    The HTTP-TLS accept path pinned its handshake grace in a local
    const that duplicated message_bus.handshake_grace, so raising the
    configured grace silently left HTTP handshakes on the stale 10s
    budget. Thread the bus value through the accept pump instead and
    drop the const; identical at defaults.
    
    The client listener also capped its accept backlog at 128 while
    the replica listener uses SOMAXCONN; align them, the kernel clamps
    to net.core.somaxconn either way. Drop the dead per-replica
    connection-count const while here.
---
 core/message_bus/src/cache/connection.rs    |  2 --
 core/message_bus/src/client_listener/mod.rs |  2 +-
 core/server-ng/src/http.rs                  |  8 ++++++--
 core/server-ng/src/http/tls.rs              | 29 +++++++++++++++++++----------
 4 files changed, 26 insertions(+), 15 deletions(-)

diff --git a/core/message_bus/src/cache/connection.rs 
b/core/message_bus/src/cache/connection.rs
index f4373f7d3..8aded4271 100644
--- a/core/message_bus/src/cache/connection.rs
+++ b/core/message_bus/src/cache/connection.rs
@@ -22,8 +22,6 @@ use rand::seq::SliceRandom;
 use std::cell::{Cell, RefCell};
 use std::collections::{HashMap, HashSet};
 
-pub const DEFAULT_MAX_CONNECTIONS_PER_REPLICA: usize = 8;
-
 pub trait ShardedState {
     type Entry;
     type Delta;
diff --git a/core/message_bus/src/client_listener/mod.rs 
b/core/message_bus/src/client_listener/mod.rs
index 2503be876..8c65a6a16 100644
--- a/core/message_bus/src/client_listener/mod.rs
+++ b/core/message_bus/src/client_listener/mod.rs
@@ -130,7 +130,7 @@ pub async fn bind_nodelay_listener(
         .await
         .map_err(|_| IggyError::CannotBindToSocket(addr.to_string()))?;
     let listener = socket
-        .listen(128)
+        .listen(libc::SOMAXCONN)
         .await
         .map_err(|_| IggyError::CannotBindToSocket(addr.to_string()))?;
     let actual = listener
diff --git a/core/server-ng/src/http.rs b/core/server-ng/src/http.rs
index 423b5d58d..b13b845e2 100644
--- a/core/server-ng/src/http.rs
+++ b/core/server-ng/src/http.rs
@@ -146,8 +146,12 @@ pub async fn start(
 
     if http_config.tls.enabled {
         let server_config = 
tls::load_http_tls_server_config(&http_config.tls)?;
-        let (connections, pump) =
-            tls::spawn_accept_pump(listener, server_config, shard.bus.token());
+        let (connections, pump) = tls::spawn_accept_pump(
+            listener,
+            server_config,
+            shard.bus.config().handshake_grace,
+            shard.bus.token(),
+        );
         shard.bus.track_background(pump);
         info!(address = %bound_addr, "server-ng HTTPS listener started");
         let handle = compio::runtime::spawn(tls::serve(connections, router, 
shard.bus.token()));
diff --git a/core/server-ng/src/http/tls.rs b/core/server-ng/src/http/tls.rs
index dd974c897..830e79d22 100644
--- a/core/server-ng/src/http/tls.rs
+++ b/core/server-ng/src/http/tls.rs
@@ -65,11 +65,6 @@ use crate::server_error::ServerNgError;
 const ALPN_H2: &[u8] = b"h2";
 const ALPN_HTTP11: &[u8] = b"http/1.1";
 
-/// Handshake wall-clock bound for the accept pump. The HTTP listener has no
-/// `MessageBusConfig` to source it from, so it mirrors the binary
-/// transports' `DEFAULT_HANDSHAKE_GRACE` directly.
-const HTTP_TLS_HANDSHAKE_GRACE: Duration = Duration::from_secs(10);
-
 /// Depth of the handshaken-connection channel between the accept pump and
 /// the serve loop. The serve loop drains one per accept and immediately
 /// spawns a per-connection hyper task, so it rarely fills; the bound keeps
@@ -101,16 +96,26 @@ pub fn load_http_tls_server_config(
 
 /// Bind the accept pump: build the acceptor, spawn the pump task, and hand
 /// back the handshaken-connection receiver for [`serve`] plus the pump's
-/// join handle for the caller to track.
+/// join handle for the caller to track. `handshake_grace` bounds each
+/// connection's TLS handshake; the caller sources it from
+/// `MessageBusConfig::handshake_grace` so the HTTPS listener shares the same
+/// slowloris budget as the binary transports.
 pub fn spawn_accept_pump(
     listener: TcpListener,
     config: Arc<rustls::ServerConfig>,
+    handshake_grace: Duration,
     shutdown: ShutdownToken,
 ) -> (Receiver<Handshaken>, JoinHandle<()>) {
     let (connections_tx, connections_rx) =
         async_channel::bounded::<Handshaken>(ACCEPT_CHANNEL_DEPTH);
     let acceptor = TlsAcceptor::from(config);
-    let pump = compio::runtime::spawn(accept_pump(listener, acceptor, 
connections_tx, shutdown));
+    let pump = compio::runtime::spawn(accept_pump(
+        listener,
+        acceptor,
+        connections_tx,
+        handshake_grace,
+        shutdown,
+    ));
     (connections_rx, pump)
 }
 
@@ -205,6 +210,7 @@ async fn accept_pump(
     listener: TcpListener,
     acceptor: TlsAcceptor,
     connections: Sender<Handshaken>,
+    handshake_grace: Duration,
     shutdown: ShutdownToken,
 ) {
     loop {
@@ -214,7 +220,9 @@ async fn accept_pump(
                 break;
             }
             result = listener.accept().fuse() => match result {
-                Ok((stream, peer)) => spawn_handshake(&acceptor, &connections, 
stream, peer),
+                Ok((stream, peer)) => {
+                    spawn_handshake(&acceptor, &connections, handshake_grace, 
stream, peer);
+                }
                 Err(error) => error!(%error, "server-ng HTTPS accept failed"),
             },
         }
@@ -228,13 +236,14 @@ async fn accept_pump(
 fn spawn_handshake(
     acceptor: &TlsAcceptor,
     connections: &Sender<Handshaken>,
+    handshake_grace: Duration,
     stream: TcpStream,
     peer: SocketAddr,
 ) {
     let acceptor = acceptor.clone();
     let connections = connections.clone();
     compio::runtime::spawn(async move {
-        match compio::time::timeout(HTTP_TLS_HANDSHAKE_GRACE, 
acceptor.accept(stream)).await {
+        match compio::time::timeout(handshake_grace, 
acceptor.accept(stream)).await {
             Ok(Ok(tls)) => {
                 // Drop on send error: the channel is closed only at
                 // shutdown, when the serve loop is already tearing down.
@@ -242,7 +251,7 @@ fn spawn_handshake(
             }
             Ok(Err(error)) => debug!(%peer, %error, "server-ng HTTPS handshake 
failed"),
             Err(_elapsed) => {
-                debug!(%peer, grace = ?HTTP_TLS_HANDSHAKE_GRACE, "server-ng 
HTTPS handshake timed out");
+                debug!(%peer, grace = ?handshake_grace, "server-ng HTTPS 
handshake timed out");
             }
         }
     })

Reply via email to