Skip to main content

network_protocol/service/
daemon.rs

1use bincode;
2use futures::{SinkExt, StreamExt};
3use std::net::SocketAddr;
4use std::sync::Arc;
5use std::time::Duration;
6use tokio::net::{TcpListener, TcpStream};
7use tokio::sync::{mpsc, oneshot, Mutex};
8use tokio::task::JoinSet;
9use tokio::time;
10use tokio_util::codec::Framed;
11use tracing::{debug, error, info, instrument, warn};
12
13use crate::config::ServerConfig;
14
15use crate::utils::timeout::with_timeout_error;
16
17use crate::core::codec::PacketCodec;
18use crate::core::packet::Packet;
19use crate::protocol::message::Message;
20// Import secure handshake functions
21use crate::error::{ProtocolError, Result};
22use crate::protocol::dispatcher::Dispatcher;
23use crate::protocol::handshake::{
24    server_secure_handshake_finalize, server_secure_handshake_response,
25};
26use crate::protocol::heartbeat::{build_ping, is_pong};
27use crate::protocol::keepalive::KeepAliveManager;
28use crate::service::secure::SecureConnection;
29use crate::utils::replay_cache::ReplayCache;
30
31/// Start a secure server and listen for connections using default configuration
32#[instrument(skip(addr), fields(address = %addr))]
33pub async fn start(addr: &str) -> Result<()> {
34    // Create a never-resolving shutdown receiver for standard operation
35    let (_, shutdown_rx) = oneshot::channel::<()>();
36    start_with_shutdown(addr, shutdown_rx).await
37}
38
39/// Start a secure server with custom configuration
40#[instrument(skip(config), fields(address = %config.address))]
41pub async fn start_with_config(config: ServerConfig) -> Result<()> {
42    // Create a never-resolving shutdown receiver for standard operation
43    let (_, shutdown_rx) = oneshot::channel::<()>();
44    start_with_config_and_shutdown(config, shutdown_rx).await
45}
46
47/// Start a secure server with shutdown control for testing
48#[instrument(skip(addr, shutdown_rx), fields(address = %addr))]
49pub async fn start_with_shutdown(addr: &str, shutdown_rx: oneshot::Receiver<()>) -> Result<()> {
50    // Use default configuration with overridden address
51    let config = ServerConfig {
52        address: addr.to_string(),
53        ..Default::default()
54    };
55    start_with_config_and_shutdown(config, shutdown_rx).await
56}
57
58/// Start a secure server with custom configuration and shutdown control
59#[instrument(skip(config, shutdown_rx), fields(address = %config.address))]
60pub async fn start_with_config_and_shutdown(
61    config: ServerConfig,
62    shutdown_rx: oneshot::Receiver<()>,
63) -> Result<()> {
64    // Shared dispatcher with the default PING and ECHO handlers
65    let dispatcher = Arc::new(Dispatcher::new());
66    register_default_handlers(&dispatcher)?;
67
68    run_server(config, dispatcher, shutdown_rx, true).await
69}
70
71/// The server loop shared by every `start_*` entry point.
72///
73/// Applies `config.max_connections` (connections over the limit are closed as soon
74/// as they are accepted), `config.backpressure_limit` (per-connection message queue
75/// depth), `config.connection_timeout` (each handshake step), `config.heartbeat_interval`
76/// and `config.shutdown_timeout`. With `handle_ctrl_c`, Ctrl-C also starts a graceful
77/// shutdown.
78async fn run_server(
79    config: ServerConfig,
80    dispatcher: Arc<Dispatcher>,
81    shutdown_rx: oneshot::Receiver<()>,
82    handle_ctrl_c: bool,
83) -> Result<()> {
84    let listener = TcpListener::bind(&config.address).await?;
85    info!(address = %config.address, "Server listening");
86
87    // Track active connections for graceful shutdown
88    let active_connections = Arc::new(Mutex::new(0u32));
89
90    // Create a shutdown channel for internal use
91    let (internal_shutdown_tx, mut internal_shutdown_rx) = mpsc::channel::<()>(1);
92
93    // Extract configuration values we need before moving config
94    let shutdown_timeout = config.shutdown_timeout;
95    let heartbeat_interval = config.heartbeat_interval;
96
97    if handle_ctrl_c {
98        let shutdown_tx_clone = internal_shutdown_tx.clone();
99        tokio::spawn(async move {
100            match tokio::signal::ctrl_c().await {
101                Ok(()) => {
102                    info!("Shutdown signal received");
103                    let _ = shutdown_tx_clone.send(()).await;
104                }
105                Err(err) => {
106                    error!(error = %err, "Failed to listen for shutdown signal");
107                }
108            }
109        });
110    }
111
112    // Also set up the oneshot receiver to trigger shutdown
113    let internal_shutdown_tx_clone = internal_shutdown_tx.clone();
114    tokio::spawn(async move {
115        if shutdown_rx.await.is_ok() {
116            info!("External shutdown signal received");
117            let _ = internal_shutdown_tx_clone.send(()).await;
118        }
119    });
120
121    // Connection tasks, so shutdown can wait for them and then close the rest
122    let mut connections = JoinSet::new();
123
124    // Server main loop with graceful shutdown
125    loop {
126        tokio::select! {
127            // Check for shutdown signal
128            _ = internal_shutdown_rx.recv() => {
129                info!(connections = connections.len(), "Shutting down server. Waiting for connections to close...");
130                close_connections(&mut connections, shutdown_timeout).await;
131                return Ok(());
132            }
133
134            // Reap finished connection tasks
135            Some(_) = connections.join_next(), if !connections.is_empty() => {}
136
137            // Accept new connections
138            accept_result = listener.accept() => {
139                match accept_result {
140                    Ok((stream, peer)) => {
141                        // Enforce the connection limit before doing any work for the peer
142                        {
143                            let mut count = active_connections.lock().await;
144                            if *count as usize >= config.max_connections {
145                                warn!(peer = %peer, limit = config.max_connections, "Connection limit reached, closing new connection");
146                                drop(stream);
147                                continue;
148                            }
149                            *count += 1;
150                        }
151
152                        info!(peer = %peer, "New connection established");
153                        let dispatcher = dispatcher.clone();
154                        let active_connections = active_connections.clone();
155
156                        // Clone the things we need to move into the task
157                        let active_connections_clone = active_connections.clone();
158                        let config_clone = config.clone();
159
160                        connections.spawn(async move {
161                            handle_connection(stream, peer, dispatcher, active_connections_clone, config_clone, heartbeat_interval).await;
162                        });
163                    }
164                    Err(e) => {
165                        error!(error = %e, "Error accepting connection");
166                    }
167                }
168            }
169        }
170    }
171}
172
173/// Wait up to `grace` for the connection tasks to finish, then close the ones still
174/// open. Returning from the server without this would leave every open session
175/// running after "shutdown".
176pub(crate) async fn close_connections(connections: &mut JoinSet<()>, grace: Duration) {
177    let drained = time::timeout(grace, async {
178        while connections.join_next().await.is_some() {}
179    })
180    .await;
181    if drained.is_ok() {
182        info!("All connections closed, shutting down");
183    } else {
184        warn!(
185            remaining = connections.len(),
186            "Shutdown timeout reached, closing remaining connections"
187        );
188        connections.shutdown().await;
189    }
190}
191
192/// Handle a client connection with proper cleanup on exit
193#[instrument(skip(stream, dispatcher, active_connections, config, heartbeat_interval), fields(peer = %peer))]
194async fn handle_connection(
195    stream: tokio::net::TcpStream,
196    peer: std::net::SocketAddr,
197    dispatcher: Arc<Dispatcher>,
198    active_connections: Arc<Mutex<u32>>,
199    config: ServerConfig,
200    heartbeat_interval: Duration,
201) {
202    // `connection_timeout` bounds each handshake step inside `process_connection`.
203    // An established session lives until the peer disconnects or the keep-alive
204    // detects it is dead; it is not cut off after `connection_timeout`.
205    let result = process_connection(stream, dispatcher, peer, config, heartbeat_interval).await;
206
207    // If there was an error, log it
208    match result {
209        Ok(_) => info!("Connection closed gracefully"),
210        Err(ProtocolError::Timeout) => warn!("Connection timed out"),
211        Err(e) => error!(error = %e, "Connection error"),
212    }
213
214    // Always decrement active connections on exit
215    {
216        let mut count = active_connections.lock().await;
217        *count -= 1;
218    }
219
220    info!("Client disconnected");
221}
222
223/// Process a client connection with handshake and secure messages
224#[instrument(skip(stream, dispatcher, peer, config, heartbeat_interval), fields(peer = %peer))]
225async fn process_connection(
226    stream: TcpStream,
227    dispatcher: Arc<Dispatcher>,
228    peer: SocketAddr,
229    config: ServerConfig,
230    heartbeat_interval: Duration,
231) -> Result<()> {
232    // Create the framed stream for packet codec
233    let mut framed = Framed::new(stream, PacketCodec);
234
235    // --- Expect Secure Handshake Init (with timeout) ---
236    let init = with_timeout_error(
237        async {
238            match framed.next().await {
239                Some(Ok(pkt)) => bincode::deserialize::<Message>(&pkt.payload)
240                    .map_err(|e| ProtocolError::DeserializeError(e.to_string())),
241                Some(Err(e)) => Err(ProtocolError::TransportError(e.to_string())),
242                None => Err(ProtocolError::ConnectionClosed),
243            }
244        },
245        config.connection_timeout,
246    )
247    .await?;
248
249    // Extract the client's handshake init data
250    let (client_pub_key, client_timestamp, client_nonce) = match init {
251        Message::SecureHandshakeInit {
252            pub_key,
253            timestamp,
254            nonce,
255        } => (pub_key, timestamp, nonce),
256        _ => {
257            return Err(ProtocolError::HandshakeError(
258                "Unexpected message type".to_string(),
259            ))
260        }
261    };
262
263    // --- Send Secure Handshake Response ---
264    let mut replay_cache = ReplayCache::new();
265    let (server_state, response) = server_secure_handshake_response(
266        client_pub_key,
267        client_nonce,
268        client_timestamp,
269        &peer.to_string(),
270        &mut replay_cache,
271    )?;
272
273    let response_bytes =
274        bincode::serialize(&response).map_err(|e| ProtocolError::SerializeError(e.to_string()))?;
275
276    framed
277        .send(Packet {
278            version: 1,
279            payload: response_bytes,
280        })
281        .await
282        .map_err(|e| ProtocolError::TransportError(e.to_string()))?;
283
284    // --- Expect Handshake Confirmation (with timeout) ---
285    let confirm = with_timeout_error(
286        async {
287            match framed.next().await {
288                Some(Ok(pkt)) => bincode::deserialize::<Message>(&pkt.payload)
289                    .map_err(|e| ProtocolError::DeserializeError(e.to_string())),
290                Some(Err(e)) => Err(ProtocolError::TransportError(e.to_string())),
291                None => Err(ProtocolError::ConnectionClosed),
292            }
293        },
294        config.connection_timeout,
295    )
296    .await?;
297
298    let nonce_verification = match confirm {
299        Message::SecureHandshakeConfirm { nonce_verification } => nonce_verification,
300        _ => {
301            return Err(ProtocolError::HandshakeError(
302                "Expected handshake confirmation".to_string(),
303            ))
304        }
305    };
306
307    // --- Finalize Handshake and Derive Session Key ---
308    let session_key = server_secure_handshake_finalize(server_state, nonce_verification)?;
309
310    // Session state is zeroized automatically on drop
311
312    // Create secure connection with derived key
313    let conn = SecureConnection::new(framed, session_key);
314
315    // Handle the secure message loop
316    handle_secure_connection(
317        conn,
318        dispatcher,
319        peer,
320        heartbeat_interval,
321        config.backpressure_limit,
322    )
323    .await?;
324
325    Ok(())
326}
327
328/// Register default message handlers
329#[instrument(skip(dispatcher))]
330fn register_default_handlers(dispatcher: &Arc<Dispatcher>) -> Result<()> {
331    // Handle Ping messages
332    dispatcher.register("PING", |_| {
333        debug!("Responding to ping with pong");
334        Ok(Message::Pong)
335    })?;
336
337    // Handle Echo messages
338    dispatcher.register("ECHO", |msg| {
339        if let Message::Echo(text) = msg {
340            debug!(text = %text, "Echoing message");
341            Ok(Message::Echo(text.clone()))
342        } else {
343            Err(ProtocolError::Custom(
344                "Invalid Echo message format".to_string(),
345            ))
346        }
347    })?;
348
349    Ok(())
350}
351
352/// Message type for the internal processing channel
353#[derive(Debug)]
354enum ProcessingMessage {
355    /// Regular message to be processed
356    Message(Message),
357    /// Signal to terminate the processing task
358    Terminate,
359}
360
361/// Response from the processing task
362#[derive(Debug)]
363struct ProcessingResult {
364    /// The original message ID or correlation ID
365    original_id: usize,
366    /// The response message to send back
367    response: Option<Message>,
368}
369
370/// Handle a secure connection after handshake with backpressure
371#[instrument(skip(conn, dispatcher, heartbeat_interval, backpressure_limit), fields(peer = %peer))]
372async fn handle_secure_connection(
373    mut conn: SecureConnection,
374    dispatcher: Arc<Dispatcher>,
375    peer: std::net::SocketAddr,
376    heartbeat_interval: Duration,
377    backpressure_limit: usize,
378) -> Result<()> {
379    // --- Initialize Keep-Alive Manager with configured interval ---
380    let dead_timeout = heartbeat_interval.mul_f32(4.0); // 4x the heartbeat interval for dead connection detection
381    let mut keep_alive = KeepAliveManager::with_settings(heartbeat_interval, dead_timeout);
382    let mut ping_interval = time::interval(keep_alive.ping_interval());
383
384    // --- Create bounded channels for backpressure with capacity from config ---
385    // `ServerConfig::validate()` rejects 0; clamp anyway, since a zero-capacity tokio
386    // channel panics.
387    let capacity = backpressure_limit.max(1);
388    let (msg_tx, msg_rx) = mpsc::channel::<ProcessingMessage>(capacity);
389    let (resp_tx, mut resp_rx) = mpsc::channel::<ProcessingResult>(capacity);
390
391    // --- Spawn message processing task ---
392    let dispatcher_clone = dispatcher.clone();
393    let processor_handle =
394        tokio::spawn(async move { process_messages(msg_rx, resp_tx, dispatcher_clone).await });
395
396    // --- Set up result for final status ---
397    let mut final_result = Ok(());
398    let mut next_msg_id: usize = 0;
399
400    // --- Secure Message Loop with Backpressure ---
401    'main: loop {
402        tokio::select! {
403            // Check if we need to send a ping
404            _ = ping_interval.tick() => {
405                if keep_alive.should_ping() {
406                    debug!("Sending keep-alive ping");
407                    let ping = build_ping();
408                    if let Err(e) = conn.secure_send(ping).await {
409                        warn!(error = %e, "Failed to send ping");
410                        final_result = Err(e);
411                        break 'main;
412                    }
413                    keep_alive.update_send();
414                }
415
416                // Check if connection is dead
417                if keep_alive.is_connection_dead() {
418                    warn!(dead_seconds = ?keep_alive.time_since_last_recv().as_secs(),
419                          "Connection appears dead, closing");
420                    final_result = Err(ProtocolError::ConnectionTimeout);
421                    break 'main;
422                }
423            }
424
425            // Process any responses from the processing task
426            Some(result) = resp_rx.recv() => {
427                if let Some(response) = result.response {
428                    debug!("Sending response for message {}", result.original_id);
429                    if let Err(e) = conn.secure_send(response).await {
430                        warn!(error = %e, "Failed to send response");
431                        final_result = Err(e);
432                        break 'main;
433                    }
434                    keep_alive.update_send();
435                }
436            }
437
438            // Try to receive a message with backpressure awareness
439            recv_result = conn.secure_recv::<Message>() => {
440                match recv_result {
441                    Ok(msg) => {
442                        debug!(message = ?msg, "Received message");
443                        keep_alive.update_recv();
444
445                        // Check for disconnect message - handle directly without channel
446                        if matches!(msg, Message::Disconnect) {
447                            info!("Received disconnect request");
448                            break 'main;
449                        }
450
451                        // Special handling for pong messages - handle directly
452                        if is_pong(&msg) {
453                            debug!("Received pong response");
454                            continue;
455                        }
456
457                        // Just increment the ID counter for the next message
458                        next_msg_id = next_msg_id.wrapping_add(1);
459
460                        // Apply backpressure if needed
461                        if msg_tx.capacity() == 0 {
462                            debug!("Channel full - applying backpressure");
463
464                            // Wait until the channel has capacity before receiving more messages
465                            match msg_tx.reserve().await {
466                                Ok(permit) => {
467                                    // Channel has capacity again, send the message
468                                    permit.send(ProcessingMessage::Message(msg));
469                                },
470                                Err(_) => {
471                                    // Channel was closed, exit the loop
472                                    warn!("Processing channel closed unexpectedly");
473                                    break 'main;
474                                }
475                            }
476                        } else {
477                            // Channel has capacity, send the message
478                            if (msg_tx.send(ProcessingMessage::Message(msg)).await).is_err() {
479                                // Channel was closed, exit the loop
480                                warn!("Failed to send message to processing channel");
481                                break 'main;
482                            }
483                        }
484                    }
485                    Err(ProtocolError::Timeout) => {
486                        // Timeout is expected, just continue the loop
487                        continue;
488                    }
489                    Err(e) => {
490                        final_result = Err(e);
491                        break 'main;
492                    }
493                }
494            }
495        }
496    }
497
498    // Signal the processor to terminate
499    debug!("Signaling processor to terminate");
500    let _ = msg_tx.send(ProcessingMessage::Terminate).await;
501
502    // Wait for processor to finish
503    debug!("Waiting for processor to terminate");
504    let _ = processor_handle.await;
505
506    final_result
507}
508
509/// Process messages from the channel
510#[instrument(skip(rx, resp_tx, dispatcher), level = "debug")]
511async fn process_messages(
512    mut rx: mpsc::Receiver<ProcessingMessage>,
513    resp_tx: mpsc::Sender<ProcessingResult>,
514    dispatcher: Arc<Dispatcher>,
515) {
516    let mut msg_counter: usize = 0;
517
518    while let Some(proc_msg) = rx.recv().await {
519        match proc_msg {
520            ProcessingMessage::Message(msg) => {
521                let msg_id = msg_counter;
522                msg_counter += 1;
523
524                debug!(msg_id = msg_id, message = ?msg, "Processing message from channel");
525
526                let response = match dispatcher.dispatch(&msg) {
527                    Ok(reply) => {
528                        // Successfully dispatched, prepare response
529                        Some(reply)
530                    }
531                    Err(e) => {
532                        // Log dispatch error but continue processing messages
533                        warn!(error = %e, "Error dispatching message");
534                        None
535                    }
536                };
537
538                // Send response back through the response channel
539                let result = ProcessingResult {
540                    original_id: msg_id,
541                    response,
542                };
543
544                if (resp_tx.send(result).await).is_err() {
545                    warn!("Failed to send processing result - reader likely disconnected");
546                    break;
547                }
548            }
549            ProcessingMessage::Terminate => {
550                debug!("Processor received terminate signal");
551                break;
552            }
553        }
554    }
555
556    debug!("Message processor terminated");
557}
558
559/// A server daemon handle that can be controlled externally
560#[derive(Debug)]
561pub struct Daemon {
562    /// Address the server is listening on
563    pub address: String,
564    /// Shutdown signal sender
565    shutdown_tx: Option<oneshot::Sender<()>>,
566}
567
568impl Daemon {
569    /// Create a new daemon handle
570    pub fn new(address: String, shutdown_tx: oneshot::Sender<()>) -> Self {
571        Self {
572            address,
573            shutdown_tx: Some(shutdown_tx),
574        }
575    }
576
577    /// Run the daemon until completion or shutdown signal
578    ///
579    /// This does nothing and returns immediately: the server is already running once
580    /// [`start_daemon_no_signals`] has returned the handle.
581    #[deprecated(
582        since = "1.3.0",
583        note = "does nothing: the server started by start_daemon_no_signals() is already running"
584    )]
585    pub async fn run(self) -> Result<()> {
586        // This function doesn't actually do anything - the server is started in the start_* functions
587        // This is just a placeholder for API compatibility
588        Ok(())
589    }
590
591    /// Shutdown the daemon gracefully
592    pub async fn shutdown(&mut self) -> Result<()> {
593        if let Some(tx) = self.shutdown_tx.take() {
594            let _ = tx.send(());
595            Ok(())
596        } else {
597            Err(ProtocolError::Custom("Shutdown already called".to_string()))
598        }
599    }
600
601    /// Shutdown the daemon with a custom timeout
602    ///
603    /// The timeout argument is not used: the server waits for open connections for
604    /// `ServerConfig::shutdown_timeout`, fixed when it was started. This is the same
605    /// as [`shutdown`](Self::shutdown).
606    #[deprecated(
607        since = "1.3.0",
608        note = "the timeout argument is ignored; set ServerConfig::shutdown_timeout and call shutdown()"
609    )]
610    pub async fn shutdown_with_timeout(&mut self, _timeout: Duration) -> Result<()> {
611        // The timeout is handled internally in the server loop
612        self.shutdown().await
613    }
614}
615
616/// Start a server daemon with provided configuration and return a handle to it
617///
618/// The server dispatches messages with `dispatcher`, as given: register every
619/// handler you need (including `PING` and `ECHO` if clients use them) before calling.
620/// It installs no signal handler: it stops when [`Daemon::shutdown`] is called (or
621/// the handle is dropped without it, in which case it runs until the runtime ends).
622#[instrument(skip(config, dispatcher), fields(address = %config.address))]
623pub async fn start_daemon_no_signals(
624    config: ServerConfig,
625    dispatcher: Arc<Dispatcher>,
626) -> Result<Daemon> {
627    // Create a shutdown channel
628    let (shutdown_tx, shutdown_rx) = oneshot::channel::<()>();
629
630    let address = config.address.clone();
631
632    // Start the server in a background task
633    tokio::spawn(async move {
634        if let Err(e) = run_server(config, dispatcher, shutdown_rx, false).await {
635            error!(error = ?e, "Server error");
636        }
637    });
638
639    // Return a daemon handle
640    Ok(Daemon::new(address, shutdown_tx))
641}
642
643/// Create a new server daemon with configuration and dispatcher
644///
645/// This does not start a server: it returns a handle whose `shutdown()` has nothing to
646/// stop, and the dispatcher is not used. Call [`start_daemon_no_signals`] instead.
647#[deprecated(
648    since = "1.3.0",
649    note = "starts nothing and ignores the dispatcher; use start_daemon_no_signals()"
650)]
651pub fn new_with_config(config: ServerConfig, _dispatcher: Arc<Dispatcher>) -> Daemon {
652    let (shutdown_tx, _) = oneshot::channel::<()>();
653    Daemon::new(config.address.clone(), shutdown_tx)
654}