From 8227b5d4f0645c1ea2b373392d1d5f0fc635a7e6 Mon Sep 17 00:00:00 2001 From: Garen Tyler Date: Sat, 15 Feb 2025 19:40:46 -0700 Subject: [PATCH] Stop crashing on EOF in codec --- .gitignore | 1 + Dockerfile | 5 ++++- docker-compose.yml | 2 ++ src/net/connection.rs | 15 +++++++++++-- src/proxy/mod.rs | 49 +++++++++++++++++++++++++++++++------------ 5 files changed, 56 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index 2590eaa..deca48f 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ target /world /server-icon.png /composition.toml +/reference diff --git a/Dockerfile b/Dockerfile index 8c2d005..a6bd591 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,15 @@ FROM rust:1.83.0-alpine3.20 AS base RUN apk add --no-cache musl-dev git RUN cargo install cargo-chef --locked --version 0.1.71 +RUN cargo install cargo-watch --locked --version 8.5.3 WORKDIR /app RUN git config --global --add safe.directory /app ARG FEATURES +RUN addgroup --gid 25565 --system composition && adduser --uid 25565 --system --ingroup composition --home /app composition +RUN chown -R composition:composition /app +USER composition FROM base AS dev -RUN cargo install cargo-watch --locked --version 8.5.3 VOLUME /app VOLUME /app/.git EXPOSE 25565 diff --git a/docker-compose.yml b/docker-compose.yml index e721e67..e05cf71 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -43,3 +43,5 @@ services: volumes: - .:/app - .git:/app/.git + environment: + CARGO_HOME: "/app/.cargo" diff --git a/src/net/connection.rs b/src/net/connection.rs index 38407e9..3973eea 100644 --- a/src/net/connection.rs +++ b/src/net/connection.rs @@ -219,11 +219,22 @@ impl Connection { } pub async fn read_packet(&mut self) -> Option> { self.last_received_data_time = Instant::now(); - self.stream.next().await + self.stream.next().await.map(|packet| { + packet.map_err(|mut e| { + // Set the codec error to something more descriptive. + if e.to_string() == "bytes remaining on stream" { + e = Error::Io(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, e)); + } + trace!("Error reading packet from connection {}: {:?}", self.id, e); + e + }) + }) } pub async fn send_packet>(&mut self, packet: P) -> Result<(), Error> { let packet: Packet = packet.into(); - self.stream.send(packet).await + self.stream.send(packet).await.inspect_err(|e| { + trace!("Error sending packet to connection {}: {:?}", self.id, e); + }) } pub async fn disconnect(mut self, reason: Option) -> Result<(), Error> { trace!("Connection disconnected (id {})", self.id); diff --git a/src/proxy/mod.rs b/src/proxy/mod.rs index 8c74bcc..afbae0c 100644 --- a/src/proxy/mod.rs +++ b/src/proxy/mod.rs @@ -90,7 +90,8 @@ impl App for Proxy { return Ok(()); }; - let mut client_parsing_error = false; + let mut client_error = false; + let mut server_error = false; // At the same time, try to read packets from the server and client. // Forward the packet onto the other. @@ -106,11 +107,24 @@ impl App for Proxy { *self.upstream.client_state_mut() = next_state; } } - Err(NetworkError::Parsing) => { - debug!("Got invalid data from client (id {})", client.id()); - client_parsing_error = true; + Err(e) => { + client_error = true; + match e { + NetworkError::Parsing => { + trace!("Got invalid data from client (id {})", client.id()); + return Err(Error::Network(NetworkError::Parsing)); + } + NetworkError::Io(e) => { + if e.kind() == std::io::ErrorKind::UnexpectedEof { + trace!("Client (id {}) disconnected", client.id()); + } else { + trace!("Got IO error from client (id {}): {}", client.id(), e); + return Err(Error::Io(e)); + } + } + e => return Err(Error::Network(e)), + }; } - Err(e) => return Err(Error::Network(e)), } } } @@ -125,17 +139,26 @@ impl App for Proxy { *client.client_state_mut() = next_state; } } - Err(NetworkError::Parsing) => { - error!("Got invalid data from upstream"); - return Err(Error::Network(NetworkError::Parsing)); - }, - Err(e) => return Err(Error::Network(e)), + Err(e) => { + server_error = true; + return match e { + NetworkError::Parsing => { + trace!("Got invalid data from upstream"); + Err(Error::Network(NetworkError::Parsing)) + } + NetworkError::Io(e) => { + trace!("Got IO error from upstream"); + Err(Error::Io(e)) + } + e => Err(Error::Network(e)), + }; + } } } } } - - if client_parsing_error { + + if client_error { let id = client.id(); // Drop the &mut Connection let _ = client; @@ -147,7 +170,7 @@ impl App for Proxy { ) .await; } - if self.upstream.client_state() == ClientState::Disconnected { + if self.upstream.client_state() == ClientState::Disconnected || server_error { // Start a new connection with the upstream server. self.upstream = Proxy::connect_upstream(&self.upstream_address).await?; }