runtime
cargo devel CI / cargo CI (push) Successful in 2m17s Details

This commit is contained in:
Christoph J. Scherr 2024-01-23 09:13:40 +01:00
parent 6078ee58a9
commit b0edd17825
Signed by: PlexSheep
GPG Key ID: 7CDD0B14851A08EF
4 changed files with 75 additions and 53 deletions

View File

@ -1,6 +1,6 @@
[package] [package]
name = "netpong" name = "netpong"
version = "0.1.0" version = "0.1.1"
edition = "2021" edition = "2021"
publish = true publish = true
authors = ["Christoph J. Scherr <software@cscherr.de>"] authors = ["Christoph J. Scherr <software@cscherr.de>"]
@ -19,9 +19,8 @@ clap-num = "1.0.2"
clap-verbosity-flag = "2.1.2" clap-verbosity-flag = "2.1.2"
libpt = { version = "0.3.10", features = ["net"] } libpt = { version = "0.3.10", features = ["net"] }
thiserror = "1.0.56" thiserror = "1.0.56"
threadpool = { version = "1.8.1", optional = true }
tokio = { version = "1.35.1", features = ["net", "rt", "macros"] } tokio = { version = "1.35.1", features = ["net", "rt", "macros"] }
[features] [features]
default = ["server"] default = ["server"]
server = ["dep:threadpool"] server = []

View File

@ -9,12 +9,14 @@ const DEFAULT_WIN_AFTER: usize = 20;
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum Mode { pub enum Mode {
Tcp, Tcp,
Tls
} }
impl ValueEnum for Mode { impl ValueEnum for Mode {
fn to_possible_value(&self) -> Option<clap::builder::PossibleValue> { fn to_possible_value(&self) -> Option<clap::builder::PossibleValue> {
Some(match self { Some(match self {
Self::Tcp => clap::builder::PossibleValue::new("tcp"), Self::Tcp => clap::builder::PossibleValue::new("tcp"),
Self::Tls => clap::builder::PossibleValue::new("tls"),
}) })
} }
fn value_variants<'a>() -> &'a [Self] { fn value_variants<'a>() -> &'a [Self] {
@ -37,6 +39,7 @@ impl Display for Mode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let repr: String = match self { let repr: String = match self {
Self::Tcp => format!("tcp"), Self::Tcp => format!("tcp"),
Self::Tls => format!("tls"),
}; };
write!(f, "{}", repr) write!(f, "{}", repr)
} }

View File

@ -25,7 +25,10 @@ async fn main() -> Result<()> {
#[cfg(feature = "server")] #[cfg(feature = "server")]
if cli.server { if cli.server {
info!("starting server"); info!("starting server");
return Server::build(cfg).await?.run().await; return Server::build(cfg).await?.start().await;
loop {
// now we wait
}
} }
// implicit else, so we can work without the server feature // implicit else, so we can work without the server feature
info!("starting client"); info!("starting client");

View File

@ -5,6 +5,7 @@ use libpt::log::{debug, info, trace, warn};
use tokio::{ use tokio::{
io::{AsyncBufReadExt, AsyncWriteExt, BufReader}, io::{AsyncBufReadExt, AsyncWriteExt, BufReader},
net::{TcpListener, TcpStream}, net::{TcpListener, TcpStream},
runtime::{Builder, Runtime},
time::timeout, time::timeout,
}; };
@ -17,44 +18,62 @@ pub struct Server {
cfg: Config, cfg: Config,
pub timeout: Option<Duration>, pub timeout: Option<Duration>,
server: TcpListener, server: TcpListener,
accept_runtime: Runtime,
request_runtime: Runtime,
} }
impl Server { impl Server {
pub async fn build(cfg: Config) -> anyhow::Result<Self> { pub async fn build(cfg: Config) -> anyhow::Result<Self> {
let server = TcpListener::bind(cfg.addr).await?; let server = TcpListener::bind(cfg.addr).await?;
let timeout = Some(Duration::from_secs(5)); let timeout = Some(Duration::from_secs(5));
let accept_runtime = Builder::new_multi_thread()
.worker_threads(1)
.thread_stack_size(3 * 1024 * 1024)
.enable_io()
.enable_time()
.build()?;
let request_runtime = Builder::new_multi_thread()
.worker_threads(1)
.thread_stack_size(3 * 1024 * 1024)
.enable_io()
.enable_time()
.build()?;
Ok(Server { Ok(Server {
cfg, cfg,
timeout, timeout,
server, server,
accept_runtime,
request_runtime,
}) })
} }
pub async fn run(self) -> anyhow::Result<()> { pub async fn start(self) -> anyhow::Result<()> {
loop { self.accept_runtime.block_on(async {
let (stream, addr) = match self.server.accept().await { loop {
Ok(s) => s, let (stream, addr) = match self.server.accept().await {
Err(err) => { Ok(s) => s,
warn!("could not accept stream: {err:?}"); Err(err) => {
continue; warn!("could not accept stream: {err:?}");
} continue;
};
// TODO: handle the stream with multi threading, or async or something
// We need concurrency here!
match self.handle_stream(stream).await {
Ok(_) => (),
Err(err) => {
match err {
ServerError::Timeout(_) => {
info!("stream {:?} timed out", addr)
}
_ => {
warn!("error while handling stream: {:?}", err)
}
} }
continue; };
} let _guard = self.request_runtime.enter();
}; match self.handle_stream(stream).await {
} Ok(_) => (),
Err(err) => {
match err {
ServerError::Timeout(_) => {
info!("stream {:?} timed out", addr)
}
_ => {
warn!("error while handling stream: {:?}", err)
}
}
continue;
}
};
}
});
Ok(())
} }
async fn handle_stream(&self, stream: TcpStream) -> Result<()> { async fn handle_stream(&self, stream: TcpStream) -> Result<()> {
@ -69,9 +88,12 @@ impl Server {
info!("new peer: {:?}", addr); info!("new peer: {:?}", addr);
let mut buf = Vec::new(); let mut buf = Vec::new();
let mut reader = BufReader::new(stream); let mut reader = BufReader::new(stream);
let mut len;
loop { loop {
len = match self.read(&mut reader, &mut buf).await { match self.read(&mut reader, &mut buf).await {
Ok(len) if len == 0 => {
trace!("len is 0, so the stream has ended: {len:?}");
break;
}
Ok(len) => len, Ok(len) => len,
Err(err) => { Err(err) => {
match err { match err {
@ -84,29 +106,24 @@ impl Server {
} }
}; };
trace!("received message: {:X?}", buf); trace!("received message: {:X?}", buf);
if len == 0 { let msg = self.decode(&buf)?;
trace!("len is apperently 0: {len:?}"); info!("< {:?} : {}", addr, msg);
break; if msg.contains("ping") {
} else { pings += 1;
let msg = self.decode(&buf)?;
info!("< {:?} : {}", addr, msg);
if msg.contains("ping") {
pings += 1;
}
if pings < self.cfg.win_after {
reader.write_all(b"pong\0").await?;
info!("> {:?} : pong", addr,);
} else {
reader.write_all(b"you win!\0").await?;
info!("> {:?} : you win!", addr,);
reader.shutdown().await?;
break;
}
buf.clear();
// we should wait, so that we don't spam the client
std::thread::sleep(self.cfg.delay);
} }
if pings < self.cfg.win_after {
reader.write_all(b"pong\0").await?;
info!("> {:?} : pong", addr,);
} else {
reader.write_all(b"you win!\0").await?;
info!("> {:?} : you win!", addr,);
reader.shutdown().await?;
break;
}
buf.clear();
// we should wait, so that we don't spam the client
std::thread::sleep(self.cfg.delay);
} }
info!("disconnected peer: {:?}", addr); info!("disconnected peer: {:?}", addr);
Ok(()) Ok(())