mirror of
https://github.com/kristoferssolo/tls-pq-bench.git
synced 2026-03-22 00:36:21 +00:00
feat(common,server): add ProtocolMode and route server through protocol dispatch
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
use miette::Diagnostic;
|
use miette::Diagnostic;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
/// Result type using the common's custom error type.
|
/// Result type using the `common`'s custom error type.
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
#[derive(Debug, Error, Diagnostic)]
|
#[derive(Debug, Error, Diagnostic)]
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
//! Common types and utilities for the TLS benchmark harness
|
|
||||||
|
|
||||||
pub mod cert;
|
pub mod cert;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
@@ -10,7 +8,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use strum::{Display, EnumString};
|
use strum::{Display, EnumString};
|
||||||
|
|
||||||
/// TLS key exchange mode
|
/// TLS 1.3 key exchange mode used for benchmark runs
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, EnumString, Display)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, EnumString, Display)]
|
||||||
#[strum(serialize_all = "lowercase")]
|
#[strum(serialize_all = "lowercase")]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
@@ -21,6 +19,23 @@ pub enum KeyExchangeMode {
|
|||||||
X25519Mlkem768,
|
X25519Mlkem768,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Application protocol carried over TLS in benchmark runs.
|
||||||
|
///
|
||||||
|
/// `Raw` is a minimal custom framing protocol (8-byte LE length request, then N payload bytes)
|
||||||
|
/// used for low-overhead microbenchmarks.
|
||||||
|
///
|
||||||
|
/// `Http1` is an HTTP/1.1 request/response mode (`GET /bytes/{n}`) used for realism-oriented
|
||||||
|
/// comparisons where HTTP parsing and headers are part of measured overhead.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, EnumString, Display)]
|
||||||
|
#[strum(serialize_all = "lowercase")]
|
||||||
|
#[serde(rename_all = "lowercase")]
|
||||||
|
pub enum ProtocolMode {
|
||||||
|
/// Minimal custom framing protocol for primary microbenchmarks.
|
||||||
|
Raw,
|
||||||
|
/// HTTP/1.1 mode for realism-oriented comparisons.
|
||||||
|
Http1,
|
||||||
|
}
|
||||||
|
|
||||||
/// A single benchmark measurement record, output as NDJSON
|
/// A single benchmark measurement record, output as NDJSON
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct BenchRecord {
|
pub struct BenchRecord {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
pub use crate::{
|
pub use crate::{
|
||||||
BenchRecord, KeyExchangeMode,
|
BenchRecord, KeyExchangeMode, ProtocolMode,
|
||||||
protocol::{read_payload, read_request, write_payload, write_request},
|
protocol::{read_payload, read_request, write_payload, write_request},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ pub async fn write_request<W: AsyncWriteExt + Unpin>(writer: &mut W, size: u64)
|
|||||||
/// Generate deterministic payload of the given size.
|
/// Generate deterministic payload of the given size.
|
||||||
///
|
///
|
||||||
/// The pattern is a repeating sequence: 0x00, 0x01, ..., 0xFF, 0x00, ...
|
/// The pattern is a repeating sequence: 0x00, 0x01, ..., 0xFF, 0x00, ...
|
||||||
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn generate_payload(size: u64) -> Vec<u8> {
|
pub fn generate_payload(size: u64) -> Vec<u8> {
|
||||||
(0..size).map(|i| (i & 0xFF) as u8).collect()
|
(0..size).map(|i| (i & 0xFF) as u8).collect()
|
||||||
|
|||||||
3
justfile
3
justfile
@@ -66,10 +66,11 @@ server mode="x25519" listen="127.0.0.1:4433":
|
|||||||
|
|
||||||
# Run benchmark runner
|
# Run benchmark runner
|
||||||
[group("run")]
|
[group("run")]
|
||||||
runner server mode="x25519" payload="1024" iters="100" warmup="10":
|
runner server mode="x25519" proto="raw" payload="1024" iters="100" warmup="10":
|
||||||
cargo run --release --bin runner -- \
|
cargo run --release --bin runner -- \
|
||||||
--server {{server}} \
|
--server {{server}} \
|
||||||
--mode {{mode}} \
|
--mode {{mode}} \
|
||||||
|
--proto {{proto}} \
|
||||||
--payload-bytes {{payload}} \
|
--payload-bytes {{payload}} \
|
||||||
--iters {{iters}} \
|
--iters {{iters}} \
|
||||||
--warmup {{warmup}}
|
--warmup {{warmup}}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use common::KeyExchangeMode;
|
use common::prelude::*;
|
||||||
use std::{net::SocketAddr, path::PathBuf};
|
use std::{net::SocketAddr, path::PathBuf};
|
||||||
|
|
||||||
/// TLS benchmark runner.
|
/// TLS benchmark runner.
|
||||||
@@ -10,31 +10,31 @@ pub struct Args {
|
|||||||
#[arg(long, default_value = "x25519")]
|
#[arg(long, default_value = "x25519")]
|
||||||
pub mode: KeyExchangeMode,
|
pub mode: KeyExchangeMode,
|
||||||
|
|
||||||
/// Server address to connect to.
|
/// Server address to connect to
|
||||||
#[arg(long, required_unless_present = "config")]
|
#[arg(long, required_unless_present = "config")]
|
||||||
pub server: Option<SocketAddr>,
|
pub server: Option<SocketAddr>,
|
||||||
|
|
||||||
/// Payload size in bytes to request from server.
|
/// Payload size in bytes to request from server
|
||||||
#[arg(long, default_value = "1024")]
|
#[arg(long, default_value = "1024")]
|
||||||
pub payload_bytes: u32,
|
pub payload_bytes: u32,
|
||||||
|
|
||||||
/// Number of benchmark iterations (excluding warmup).
|
/// Number of benchmark iterations (excluding warmup)
|
||||||
#[arg(long, default_value = "100")]
|
#[arg(long, default_value = "100")]
|
||||||
pub iters: u32,
|
pub iters: u32,
|
||||||
|
|
||||||
/// Number of warmup iterations (not recorded).
|
/// Number of warmup iterations (not recorded)
|
||||||
#[arg(long, default_value = "10")]
|
#[arg(long, default_value = "10")]
|
||||||
pub warmup: u32,
|
pub warmup: u32,
|
||||||
|
|
||||||
/// Number of concurrent connections.
|
/// Number of concurrent connections
|
||||||
#[arg(long, default_value = "1")]
|
#[arg(long, default_value = "1")]
|
||||||
pub concurrency: u32,
|
pub concurrency: u32,
|
||||||
|
|
||||||
/// Output file for NDJSON records (stdout if not specified).
|
/// Output file for NDJSON records (stdout if not specified)
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
pub out: Option<PathBuf>,
|
pub out: Option<PathBuf>,
|
||||||
|
|
||||||
/// Config file for matrix benchmarks (TOML).
|
/// Config file for matrix benchmarks (TOML)
|
||||||
#[arg(long)]
|
#[arg(long, short)]
|
||||||
pub config: Option<PathBuf>,
|
pub config: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use miette::{Diagnostic, NamedSource, SourceSpan};
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
/// Result type using the runner's custom error type.
|
/// Result type using the `runner`'s custom error type.
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
/// Errors that can occur during benchmark execution.
|
/// Errors that can occur during benchmark execution.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use miette::Diagnostic;
|
use miette::Diagnostic;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
/// Result type using the servers's custom error type.
|
/// Result type using the `servers`'s custom error type.
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
#[derive(Debug, Error, Diagnostic)]
|
#[derive(Debug, Error, Diagnostic)]
|
||||||
|
|||||||
@@ -20,11 +20,15 @@ use tracing_subscriber::EnvFilter;
|
|||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
#[command(name = "server", version, about)]
|
#[command(name = "server", version, about)]
|
||||||
struct Args {
|
struct Args {
|
||||||
/// Key exchange mode.
|
/// Key exchange mode
|
||||||
#[arg(long, default_value = "x25519")]
|
#[arg(long, default_value = "x25519")]
|
||||||
mode: KeyExchangeMode,
|
mode: KeyExchangeMode,
|
||||||
|
|
||||||
/// Address to listen on.
|
/// Protocol carrier
|
||||||
|
#[arg(long, default_value = "raw")]
|
||||||
|
pub proto: ProtocolMode,
|
||||||
|
|
||||||
|
/// Address to listen on
|
||||||
#[arg(long, default_value = "127.0.0.1:4433")]
|
#[arg(long, default_value = "127.0.0.1:4433")]
|
||||||
listen: SocketAddr,
|
listen: SocketAddr,
|
||||||
}
|
}
|
||||||
@@ -65,7 +69,7 @@ async fn main() -> miette::Result<()> {
|
|||||||
"CA cert (truncated)"
|
"CA cert (truncated)"
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(run_server(args, tls_config).await?)
|
Ok(run_server(&args, tls_config).await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
32
server/src/server/mod.rs
Normal file
32
server/src/server/mod.rs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
mod raw;
|
||||||
|
|
||||||
|
use crate::{Args, error, server::raw::handle_raw_connection};
|
||||||
|
use common::prelude::*;
|
||||||
|
use rustls::ServerConfig;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use tokio::net::TcpListener;
|
||||||
|
use tracing::info;
|
||||||
|
|
||||||
|
pub async fn run_server(args: &Args, tls_config: Arc<ServerConfig>) -> error::Result<()> {
|
||||||
|
let listener = TcpListener::bind(args.listen)
|
||||||
|
.await
|
||||||
|
.map_err(|e| error::Error::network(format!("failed to bind to {}: {e}", args.listen)))?;
|
||||||
|
|
||||||
|
info!(listen = %args.listen, mode = %args.mode, "listening");
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let (stream, peer) = match listener.accept().await {
|
||||||
|
Ok(conn) => conn,
|
||||||
|
Err(e) => {
|
||||||
|
error!(error = %e, "accept error");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let config = tls_config.clone();
|
||||||
|
tokio::spawn(match args.proto {
|
||||||
|
ProtocolMode::Raw => handle_raw_connection(stream, peer, config),
|
||||||
|
ProtocolMode::Http1 => todo!(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
use crate::{Args, error};
|
|
||||||
use common::prelude::*;
|
use common::prelude::*;
|
||||||
use rustls::{ServerConfig, server::Acceptor};
|
use rustls::{ServerConfig, server::Acceptor};
|
||||||
use std::{io::ErrorKind, net::SocketAddr, sync::Arc};
|
use std::{io::ErrorKind, net::SocketAddr, sync::Arc};
|
||||||
use tokio::{
|
use tokio::{io::AsyncWriteExt, net::TcpStream};
|
||||||
io::AsyncWriteExt,
|
|
||||||
net::{TcpListener, TcpStream},
|
|
||||||
};
|
|
||||||
use tokio_rustls::LazyConfigAcceptor;
|
use tokio_rustls::LazyConfigAcceptor;
|
||||||
use tracing::{debug, info, warn};
|
use tracing::{debug, info, warn};
|
||||||
|
|
||||||
pub async fn handle_connection(stream: TcpStream, peer: SocketAddr, tls_config: Arc<ServerConfig>) {
|
pub async fn handle_raw_connection(
|
||||||
|
stream: TcpStream,
|
||||||
|
peer: SocketAddr,
|
||||||
|
tls_config: Arc<ServerConfig>,
|
||||||
|
) {
|
||||||
let acceptor = LazyConfigAcceptor::new(Acceptor::default(), stream);
|
let acceptor = LazyConfigAcceptor::new(Acceptor::default(), stream);
|
||||||
let start_handshake = match acceptor.await {
|
let start_handshake = match acceptor.await {
|
||||||
Ok(sh) => sh,
|
Ok(sh) => sh,
|
||||||
@@ -57,24 +57,3 @@ pub async fn handle_connection(stream: TcpStream, peer: SocketAddr, tls_config:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run_server(args: Args, tls_config: Arc<ServerConfig>) -> error::Result<()> {
|
|
||||||
let listener = TcpListener::bind(args.listen)
|
|
||||||
.await
|
|
||||||
.map_err(|e| error::Error::network(format!("failed to bind to {}: {e}", args.listen)))?;
|
|
||||||
|
|
||||||
info!(listen = %args.listen, mode = %args.mode, "listening");
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let (stream, peer) = match listener.accept().await {
|
|
||||||
Ok(conn) => conn,
|
|
||||||
Err(e) => {
|
|
||||||
error!(error = %e, "accept error");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let config = tls_config.clone();
|
|
||||||
tokio::spawn(handle_connection(stream, peer, config));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user