diff --git a/src/server.rs b/src/server.rs index e34e5a5..3106ffc 100644 --- a/src/server.rs +++ b/src/server.rs @@ -88,8 +88,10 @@ struct SharedServerInner { max_connections: usize, incoming_capacity: usize, outgoing_capacity: usize, + /// The tokio handle used by the server. tokio_handle: Handle, - /// Store this here so we don't drop it. + /// Holding a runtime handle is not enough to keep tokio working. We need + /// to store the runtime here so we don't drop it. _tokio_runtime: Option, dimensions: Vec, biomes: Vec, @@ -254,8 +256,8 @@ impl SharedServer { /// Consumes the configuration and starts the server. /// -/// The function returns once the server has shut down, a runtime error -/// occurs, or the configuration is found to be invalid. +/// This function blocks the current thread and returns once the server has shut +/// down, a runtime error occurs, or the configuration is found to be invalid. pub fn start_server(config: C, data: C::ServerState) -> ShutdownResult { let shared = setup_server(config) .context("failed to initialize server") @@ -522,6 +524,7 @@ async fn handle_connection( ctrl: ctrl.into_play_packet_controller( server.0.incoming_capacity, server.0.outgoing_capacity, + server.tokio_handle().clone(), ), }; diff --git a/src/server/packet_controller.rs b/src/server/packet_controller.rs index ac173b5..3aa6074 100644 --- a/src/server/packet_controller.rs +++ b/src/server/packet_controller.rs @@ -3,6 +3,7 @@ use std::time::Duration; use tokio::io; use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; +use tokio::runtime::Handle; use tokio::task::JoinHandle; use tokio::time::timeout; @@ -91,6 +92,7 @@ where mut self, incoming_limit: usize, outgoing_limit: usize, + handle: Handle, ) -> PlayPacketController where R: Send + 'static, @@ -144,6 +146,7 @@ where recv: incoming_receiver, reader_task, writer_task: Some(writer_task), + handle, } } } @@ -158,6 +161,7 @@ pub struct PlayPacketController { recv: ByteReceiver, reader_task: JoinHandle<()>, writer_task: Option>, + handle: Handle, } impl PlayPacketController { @@ -214,8 +218,11 @@ impl Drop for PlayPacketController { if let Some(writer_task) = self.writer_task.take() { if !writer_task.is_finished() { + let _guard = self.handle.enter(); + // Give any unsent packets a moment to send before we cut the connection. - tokio::spawn(timeout(Duration::from_secs(1), writer_task)); + self.handle + .spawn(timeout(Duration::from_secs(1), writer_task)); } } }