1#![forbid(unsafe_code)]
2#![warn(clippy::all)]
3mod connection_handler;
8mod state;
9
10use anyhow::Context;
11use anyhow::anyhow;
12use clap::Parser;
13use connection_handler::handle_connection;
14use log::{debug, error, info, warn};
15use socket2::{Domain, Protocol, TcpKeepalive, Type};
16use state::State;
17use std::future::Future;
18use std::net::SocketAddr;
19use std::{
20 io::BufReader,
21 path::{Path, PathBuf},
22 sync::Arc,
23 time::Duration,
24};
25use tokio::task::JoinSet;
26use tokio_rustls::{
27 TlsAcceptor,
28 rustls::{self, pki_types::CertificateDer},
29};
30
31#[derive(Parser, Debug)]
32#[command(author, version, about)]
33pub struct Args {
34 #[arg(short, long, required_unless_present("unencrypted"))]
36 pub key: Option<PathBuf>,
37
38 #[arg(short, long, required_unless_present("unencrypted"))]
40 pub certificate: Option<PathBuf>,
41
42 #[arg(short, long, conflicts_with_all(["key", "certificate"]))]
44 pub unencrypted: bool,
45
46 #[arg(short, long, default_values = ["0.0.0.0:2311", "[::]:2311"])]
48 pub addresses: Vec<SocketAddr>,
49
50 #[arg(short, long, default_value = "600")]
52 pub timeout: u64,
53
54 #[arg(short, long, default_value = "10")]
59 pub request_limit: u32,
60
61 #[arg(short, long, default_value = "debug")]
63 pub verbosity: log::LevelFilter,
64}
65
66pub fn start_server(args: Args) -> anyhow::Result<(Vec<SocketAddr>, impl Future<Output = ()>)> {
73 if let Err(err) = env_logger::builder()
75 .filter_level(args.verbosity)
76 .try_init()
77 {
78 error!("Non-fatal error. Couldn't initialize logger: {err}")
79 }
80
81 let tcp_listeners: anyhow::Result<Vec<tokio::net::TcpListener>> =
83 args.addresses.into_iter().map(get_tcp_listener).collect();
84 let tcp_listeners = tcp_listeners?;
85
86 let addresses: std::io::Result<Vec<SocketAddr>> =
88 tcp_listeners.iter().map(|l| l.local_addr()).collect();
89 let addresses = addresses.context("Couldn't determine local address")?;
90
91 let tls_acceptor = if let (Some(key), Some(cert)) = (args.key, args.certificate) {
93 Some(get_tls_acceptor(&key, &cert)?)
94 } else {
95 None
96 };
97
98 let state = State::new(
100 args.request_limit,
101 std::time::Duration::from_secs(args.timeout),
102 );
103
104 let mut joinset = JoinSet::new();
105
106 for tcp_listener in tcp_listeners {
107 joinset.spawn(run_single_server(
108 state.clone(),
109 tcp_listener,
110 tls_acceptor.clone(),
111 ));
112 }
113
114 let handle = async {
115 joinset.join_all().await;
116 };
117
118 info!("Listening on these addresses: {addresses:?}");
120 info!("Is encrypted?: {}", tls_acceptor.is_some());
121 info!(
122 "Critical requests per minute per IP address limit: {}",
123 args.request_limit
124 );
125 info!(
126 "Number of seconds before a new room is deleted: {}",
127 args.timeout
128 );
129 info!("Server is now running.");
130
131 Ok((addresses, handle))
132}
133
134async fn run_single_server(
135 state: State,
136 tcp_listener: tokio::net::TcpListener,
137 tls_acceptor: Option<TlsAcceptor>,
138) {
139 loop {
140 let (stream, origin) = match tcp_listener.accept().await {
142 Ok(ok) => ok,
143 Err(err) => {
144 error!("Error accepting incoming TCP connection: {err}.");
145 continue;
146 }
147 };
148 debug!("Accepted incoming TCP connection from {origin}.");
149
150 tokio::spawn(handle_connection(
152 stream,
153 origin,
154 tls_acceptor.clone(),
155 state.clone(),
156 ));
157 }
158}
159
160fn get_tcp_listener(addr: SocketAddr) -> anyhow::Result<tokio::net::TcpListener> {
165 let socket = socket2::Socket::new(Domain::for_address(addr), Type::STREAM, Some(Protocol::TCP))
167 .context("Couldn't create TCP socket")?;
168
169 if addr.is_ipv6() {
172 socket
173 .set_only_v6(true)
174 .with_context(|| format!("Couldn't set IPV6_V6ONLY on {addr}"))?;
175 }
176
177 let tcp_keepalive = TcpKeepalive::new()
179 .with_time(Duration::from_secs(60))
180 .with_interval(Duration::from_secs(10));
181 socket
182 .set_tcp_keepalive(&tcp_keepalive)
183 .context("Couldn't set TCP keepalive")?;
184
185 socket
186 .bind(&addr.into())
187 .with_context(|| format!("Couldn't bind socket to address {addr}"))?;
188
189 socket
190 .listen(128)
191 .with_context(|| format!("Couldn't listen on {addr}"))?;
192
193 let listener: std::net::TcpListener = socket.into();
194
195 listener
196 .set_nonblocking(true)
197 .context("Couldn't set TCP socket to non blocking")?;
198
199 let listener = tokio::net::TcpListener::from_std(listener)
201 .context("Couldn't create async TCP listener")?;
202
203 Ok(listener)
204}
205
206fn get_tls_acceptor(key_path: &Path, cert_path: &Path) -> anyhow::Result<TlsAcceptor> {
209 let key = std::fs::File::open(key_path)
211 .with_context(|| format!("Couldn't open key file {key_path:?}."))?;
212 let mut key = BufReader::new(key);
213
214 let key = rustls_pemfile::private_key(&mut key)
216 .with_context(|| format!("Couldn't parse key file {key_path:?}."))?
217 .ok_or(anyhow!("No private keys found in file {key_path:?}."))?;
218
219 let cert = std::fs::File::open(cert_path)
221 .with_context(|| format!("Couldn't open certificate file {cert_path:?}."))?;
222 let mut cert = BufReader::new(cert);
223
224 let cert: Result<Vec<CertificateDer<'static>>, _> = rustls_pemfile::certs(&mut cert).collect();
226 let cert = cert.with_context(|| format!("Couldn't parse certificate file {cert_path:?}."))?;
227
228 let tls_config = rustls::ServerConfig::builder()
230 .with_no_client_auth()
231 .with_single_cert(cert, key)
232 .context("Couldn't configure TLS")?;
233
234 Ok(tokio_rustls::TlsAcceptor::from(Arc::new(tls_config)))
236}