Skip to content

Commit

Permalink
Improved server logging.
Browse files Browse the repository at this point in the history
  • Loading branch information
manforowicz committed Dec 1, 2024
1 parent e6e34e0 commit ace9846
Show file tree
Hide file tree
Showing 11 changed files with 103 additions and 61 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ This may not work on very restrictive NATs. If that happens, enable IPv6 or move

- Server connection encrypted with
[TLS](https://en.wikipedia.org/wiki/Transport_Layer_Security)
and file transfer end-to-end encrypted with
and file transfer is over TCP that's end-to-end encrypted with
[ChaCha20Poly1305](https://en.wikipedia.org/wiki/ChaCha20-Poly1305).

- Automatically tries both IPv4 and IPv6.
Expand All @@ -75,7 +75,7 @@ Commands:
Options:
-s, --server <SERVER> Use a custom gday server with this domain name
-p, --port <PORT> Connect to a custom server port
-u, --unencrypted Use TCP without TLS
-u, --unencrypted Connect to server with TCP instead of TLS
-v, --verbosity <VERBOSITY> Verbosity. (trace, debug, info, warn, error) [default: warn]
-h, --help Print help
-V, --version Print version
Expand Down
2 changes: 1 addition & 1 deletion gday/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ Commands:
Options:
-s, --server <SERVER> Use a custom gday server with this domain name
-p, --port <PORT> Connect to a custom server port
-u, --unencrypted Use TCP without TLS
-u, --unencrypted Connect to server with TCP instead of TLS
-v, --verbosity <VERBOSITY> Verbosity. (trace, debug, info, warn, error) [default: warn]
-h, --help Print help
-V, --version Print version
Expand Down
34 changes: 17 additions & 17 deletions gday/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use owo_colors::OwoColorize;
use std::path::PathBuf;

/// How long to try hole punching before giving up.
const HOLE_PUNCH_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
const HOLE_PUNCH_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(5);

/// How long to try connecting to a server before giving up.
const SERVER_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(5);
Expand All @@ -26,7 +26,7 @@ const SERVER_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(5);
#[command(author, version, about)]
struct Args {
#[command(subcommand)]
operation: Command,
command: Command,

/// Use a custom gday server with this domain name.
#[arg(short, long)]
Expand All @@ -36,7 +36,7 @@ struct Args {
#[arg(short, long, requires("server"))]
port: Option<u16>,

/// Use TCP without TLS.
/// Connect to server with TCP instead of TLS.
#[arg(short, long, requires("server"))]
unencrypted: bool,

Expand All @@ -49,6 +49,10 @@ struct Args {
enum Command {
/// Send files and/or directories.
Send {
/// Files and/or directories to send.
#[arg(required = true, num_args = 1..)]
paths: Vec<PathBuf>,

/// Custom shared code of form "server_id.room_code.shared_secret".
///
/// A server_id of 0 causes a random server to be used.
Expand All @@ -59,20 +63,16 @@ enum Command {
/// Length of room_code and shared_secret to generate.
#[arg(short, long, default_value = "5", conflicts_with = "code")]
length: usize,

/// Files and/or directories to send.
#[arg(required = true, num_args = 1..)]
paths: Vec<PathBuf>,
},

/// Receive files.
Get {
/// The code your peer gave you (of form "server_id.room_code.shared_secret")
code: PeerCode,

/// Directory where to save the files.
#[arg(short, long, default_value = ".")]
path: PathBuf,

/// The code your peer gave you (of form "server_id.room_code.shared_secret")
code: PeerCode,
},
}

Expand Down Expand Up @@ -117,7 +117,7 @@ async fn run(args: crate::Args) -> Result<(), Box<dyn std::error::Error>> {
None
};

match args.operation {
match args.command {
crate::Command::Send {
paths,
code,
Expand Down Expand Up @@ -195,6 +195,9 @@ async fn run(args: crate::Args) -> Result<(), Box<dyn std::error::Error>> {
.await
.map_err(|_| gday_hole_punch::Error::HolePunchTimeout)??;

// Gracefully close the server connection
server_connection.shutdown().await?;

let mut stream = EncryptedStream::encrypt_connection(stream, &shared_key).await?;

info!("Established authenticated encrypted connection with peer.");
Expand Down Expand Up @@ -226,9 +229,6 @@ async fn run(args: crate::Args) -> Result<(), Box<dyn std::error::Error>> {
if num_accepted != 0 {
transfer::send_files(local_files, response, &mut stream).await?;
}

// Gracefully close the server connection
server_connection.shutdown().await?;
}

// receiving files
Expand Down Expand Up @@ -264,6 +264,9 @@ async fn run(args: crate::Args) -> Result<(), Box<dyn std::error::Error>> {
.await
.map_err(|_| gday_hole_punch::Error::HolePunchTimeout)??;

// Gracefully close the server connection
server_connection.shutdown().await?;

let mut stream = EncryptedStream::encrypt_connection(stream, &shared_key).await?;

info!("Established authenticated encrypted connection with peer.");
Expand All @@ -281,9 +284,6 @@ async fn run(args: crate::Args) -> Result<(), Box<dyn std::error::Error>> {
} else {
transfer::receive_files(offer, response, &path, &mut stream).await?;
}

// Gracefully close the server connection
server_connection.shutdown().await?;
}
}

Expand Down
5 changes: 0 additions & 5 deletions gday_contact_exchange_protocol/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,6 @@ pub enum ServerMsg {
/// The server then closes the connection.
ErrorSyntax,

/// The server responds with this if it has any sort of connection error.
/// The server then closes the connection.
ErrorConnection,

/// The server responds with this if it has an internal error.
/// The server then closes the connection.
ErrorInternal,
Expand Down Expand Up @@ -226,7 +222,6 @@ impl Display for ServerMsg {
"Exceeded request limit from this IP address. Try again in a minute."
),
Self::ErrorSyntax => write!(f, "Server couldn't parse message syntax from client."),
Self::ErrorConnection => write!(f, "Connection error to server."),
Self::ErrorInternal => write!(f, "Server had an internal error."),
}
}
Expand Down
1 change: 0 additions & 1 deletion gday_contact_exchange_protocol/tests/test_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,5 @@ fn get_server_msg_examples() -> Vec<ServerMsg> {
ServerMsg::ErrorNoSuchRoomCode,
ServerMsg::ErrorTooManyRequests,
ServerMsg::ErrorSyntax,
ServerMsg::ErrorConnection,
]
}
2 changes: 1 addition & 1 deletion gday_server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Options:
-a, --addresses <ADDRESSES> Socket addresses on which to listen [default: 0.0.0.0:2311 [::]:2311]
-t, --timeout <TIMEOUT> Number of seconds before a new room is deleted [default: 600]
-r, --request-limit <REQUEST_LIMIT> Max number of create room requests and requests with an invalid room code an IP address can send per minute before they're rejected [default: 10]
-v, --verbosity <VERBOSITY> Log verbosity. (trace, debug, info, warn, error) [default: info]
-v, --verbosity <VERBOSITY> Log verbosity. (trace, debug, info, warn, error) [default: debug]
-h, --help Print help
-V, --version Print version
```
Expand Down
41 changes: 18 additions & 23 deletions gday_server/src/connection_handler.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::state::{self, State};
use gday_contact_exchange_protocol::{read_from_async, write_to_async, ClientMsg, ServerMsg};
use log::{info, warn};
use log::{error, info, warn};
use std::net::SocketAddr;
use tokio::{
io::{AsyncRead, AsyncWrite},
Expand All @@ -14,18 +14,10 @@ use tokio_rustls::TlsAcceptor;
/// Logs information and errors with [`log`].
pub async fn handle_connection(
mut tcp_stream: TcpStream,
origin: SocketAddr,
tls_acceptor: Option<TlsAcceptor>,
state: State,
) {
// try establishing a TLS connectio
let origin = match tcp_stream.peer_addr() {
Ok(origin) => origin,
Err(err) => {
warn!("Couldn't get client's IP address: {err}");
return;
}
};

if let Some(tls_acceptor) = tls_acceptor {
let mut tls_stream = match tls_acceptor.accept(tcp_stream).await {
Ok(tls_stream) => tls_stream,
Expand All @@ -34,17 +26,9 @@ pub async fn handle_connection(
return;
}
};
handle_requests(&mut tls_stream, state, origin)
.await
.unwrap_or_else(|err| {
info!("Dropping connection with '{origin}' because: {err}");
});
let _ = handle_requests(&mut tls_stream, state, origin).await;
} else {
handle_requests(&mut tcp_stream, state, origin)
.await
.unwrap_or_else(|err| {
info!("Dropping connection with '{origin}' because: {err}");
});
let _ = handle_requests(&mut tcp_stream, state, origin).await;
}
}

Expand All @@ -60,31 +44,38 @@ async fn handle_requests(
match result {
Ok(()) => (),
Err(HandleMessageError::State(state::Error::NoSuchRoomCode)) => {
warn!("Replying with ServerMsg::ErrorNoSuchRoomCode.");
write_to_async(ServerMsg::ErrorNoSuchRoomCode, stream).await?;
}
Err(HandleMessageError::Receiver(_)) => {
warn!("Replying with ServerMsg::ErrorPeerTimedOut.");
write_to_async(ServerMsg::ErrorPeerTimedOut, stream).await?;
}
Err(HandleMessageError::State(state::Error::RoomCodeTaken)) => {
warn!("Replying with ServerMsg::ErrorRoomTaken.");
write_to_async(ServerMsg::ErrorRoomTaken, stream).await?;
}
Err(HandleMessageError::State(state::Error::TooManyRequests)) => {
warn!("Replying with ServerMsg::ErrorTooManyRequests and disconnecting.");
write_to_async(ServerMsg::ErrorTooManyRequests, stream).await?;
return result;
}
Err(HandleMessageError::State(state::Error::CantUpdateDoneClient)) => {
warn!("Replying with ServerMsg::ErrorUnexpectedMsg.");
write_to_async(ServerMsg::ErrorUnexpectedMsg, stream).await?;
}
Err(HandleMessageError::Protocol(_)) => {
Err(HandleMessageError::Protocol(ref err)) => {
warn!("Replying with ServerMsg::ErrorSyntax and disconnecting, because: {err}");
write_to_async(ServerMsg::ErrorSyntax, stream).await?;
return result;
}
Err(HandleMessageError::UnknownMessage(_)) => {
Err(HandleMessageError::UnknownMessage(msg)) => {
warn!("Replying with ServerMsg::ErrorSyntax because received unknown message: {msg:?}");
write_to_async(ServerMsg::ErrorSyntax, stream).await?;
return result;
}
Err(HandleMessageError::IO(_)) => {
write_to_async(ServerMsg::ErrorConnection, stream).await?;
info!("'{origin}' disconnected.");
return result;
}
}
Expand Down Expand Up @@ -150,11 +141,15 @@ async fn handle_message(
// responds to the client with their own contact info
write_to_async(ServerMsg::ClientContact(client_contact), stream).await?;

info!("Sent client '{origin}' their contact of '{client_contact}'.");

// wait for the peer to be done sending as well
let peer_contact = rx.await?;

// send the peer's contact info to this client
write_to_async(ServerMsg::PeerContact(peer_contact), stream).await?;

info!("Sent client '{origin}' their peer's contact of '{client_contact}'.");
}
unknown_msg => return Err(HandleMessageError::UnknownMessage(unknown_msg)),
}
Expand Down
16 changes: 8 additions & 8 deletions gday_server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ pub fn start_server(args: Args) -> Result<(Vec<SocketAddr>, JoinSet<()>), Error>

// log the addresses being listened on
info!("Listening on these addresses: {addresses:?}");

info!("Is encrypted?: {}", tls_acceptor.is_some());
info!(
"Critical requests per minute per IP address limit: {}",
Expand Down Expand Up @@ -134,18 +133,19 @@ async fn run_single_server(
) {
loop {
// try to accept another connection
let (stream, addr) = match tcp_listener.accept().await {
let (stream, origin) = match tcp_listener.accept().await {
Ok(ok) => ok,
Err(err) => {
warn!("Error accepting incoming TCP connection: {err}.");
continue;
}
};
debug!("Accepted incoming TCP connection from {addr}.");
debug!("Accepted incoming TCP connection from {origin}.");

// spawn a thread to handle the connection
tokio::spawn(handle_connection(
stream,
origin,
tls_acceptor.clone(),
state.clone(),
));
Expand Down Expand Up @@ -185,11 +185,6 @@ fn get_tcp_listener(addr: SocketAddr) -> Result<tokio::net::TcpListener, Error>
source,
})?;

socket.set_nonblocking(true).map_err(|source| Error {
msg: "Couldn't set TCP socket to non blocking".to_string(),
source,
})?;

socket.bind(&addr.into()).map_err(|source| Error {
msg: format!("Couldn't bind socket to address {addr}"),
source,
Expand All @@ -202,6 +197,11 @@ fn get_tcp_listener(addr: SocketAddr) -> Result<tokio::net::TcpListener, Error>

let listener: std::net::TcpListener = socket.into();

listener.set_nonblocking(true).map_err(|source| Error {
msg: "Couldn't set TCP socket to non blocking".to_string(),
source,
})?;

// convert to a tokio listener
let listener = tokio::net::TcpListener::from_std(listener).map_err(|source| Error {
msg: "Couldn't create async TCP listener".to_string(),
Expand Down
2 changes: 1 addition & 1 deletion gday_server/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ impl State {
if *conns_count >= *self.max_requests_per_minute {
Err(Error::TooManyRequests)
} else {
*conns_count += 1;
*conns_count = conns_count.saturating_add(1);
Ok(())
}
}
Expand Down
7 changes: 5 additions & 2 deletions other/demo.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
#!/usr/bin/env bash

# Custom script for starting a tmux 2-pane asciinema recording.
# Intended for recording gday demos.
# Script for recording gday demos.
# Requires: asciinema, tmux

# Creates temporary folders and
# starts a tmux 2-pane asciinema recording.

# Use ctrl+b <arrow key> to switch between panes.
# Press ctrl+d multiple times to end the recording.

Expand Down
Loading

0 comments on commit ace9846

Please sign in to comment.