netreplay/src/main.rs

197 lines
4.2 KiB
Rust

#![feature(ascii_char)]
mod client;
mod codec;
mod record;
mod server;
mod util;
use record::Records;
use argp::FromArgs;
use static_cell::StaticCell;
/// Play recorded requests and responses
#[derive(FromArgs)]
struct Opt {
/// Path to record file
#[argp(positional)]
record_file: String,
#[argp(subcommand)]
subcommand: Subcommand,
}
#[derive(FromArgs)]
#[argp(subcommand)]
enum Subcommand {
/// Replay from records (client)
Client(OptClient),
/// Replay from records (server)
Server(OptServer),
/// Print records
Print(OptPrint),
/// Record traffic
#[cfg(feature = "record")]
Record(OptRecord),
/// Remove record
Remove(OptRemove),
/// Write test record
Test(OptTest),
}
/// Replay from records
#[derive(FromArgs)]
#[argp(subcommand, name = "client")]
struct OptClient {
/// Connect to address
#[argp(positional)]
connect_addr: String,
/// Connect to port
#[argp(positional)]
connect_port: u16,
/// Whether to use TLS
#[argp(switch, long = "tls")]
tls: bool,
/// Repeat N times
#[argp(option, short = 'r', default = "1")]
repeat: u32,
/// UDP end notification will be sent to this address:port
#[argp(option, short = 'n')]
notify_addr: Option<String>,
/// Only play this record
#[argp(option)]
record: Option<u64>,
/// Path to PEM certificates (if not provided, use system's certificates)
#[argp(option, short = 'c')]
certs: Option<String>,
/// Do not verify certificates
#[argp(switch, short = 's')]
skip_verif: bool,
/// Maximum number of concurrent clients
#[argp(option, default = "16")]
concurrency: usize,
/// Print debug info
#[argp(switch, short = 'd')]
debug: bool,
}
/// Replay from records
#[derive(FromArgs)]
#[argp(subcommand, name = "server")]
struct OptServer {
/// Listen to port
#[argp(positional)]
listen_port: u16,
/// Path to PEM certificates and keys
#[argp(positional)]
certs: String,
/// Whether to use TLS
#[argp(switch, long = "tls")]
tls: bool,
/// Print debug info
#[argp(switch, short = 'd')]
debug: bool,
}
/// Print records
#[derive(FromArgs)]
#[argp(subcommand, name = "print")]
struct OptPrint {
/// Record number
#[argp(option, short = 'n')]
number: Option<u64>,
}
/// Record traffic
#[cfg(feature = "record")]
#[derive(FromArgs)]
#[argp(subcommand, name = "record")]
struct OptRecord {}
/// Record traffic
#[derive(FromArgs)]
#[argp(subcommand, name = "test")]
struct OptTest {}
/// Copy record but removing one connection id
#[derive(FromArgs)]
#[argp(subcommand, name = "remove")]
struct OptRemove {
/// Output path
#[argp(positional)]
output: String,
/// Record number to remove
#[argp(positional)]
record_number: u64,
/// Packet number to remove
#[argp(positional)]
packet_number: usize,
}
static RECORDS: StaticCell<Records> = StaticCell::new();
#[tokio::main]
async fn main() {
env_logger::init();
let opt: Opt = argp::parse_args_or_exit(argp::DEFAULT);
match opt.subcommand {
Subcommand::Client(subopt) => {
let records = RECORDS.init(record::read_record_file(&opt.record_file));
if let Some(only_record) = subopt.record {
records.retain(|id, _| *id == only_record);
}
util::init_provider();
//console_subscriber::init();
client::play(
records,
subopt.tls,
(subopt.connect_addr, subopt.connect_port),
subopt.repeat,
subopt.certs.as_deref(),
subopt.skip_verif,
subopt.concurrency,
subopt.notify_addr.as_deref(),
subopt.debug,
)
.await;
}
Subcommand::Server(subopt) => {
let records = RECORDS.init(record::read_record_file(&opt.record_file));
util::init_provider();
//console_subscriber::init();
server::play(
records,
subopt.tls,
&subopt.certs,
("0.0.0.0", subopt.listen_port),
subopt.debug,
)
.await;
}
Subcommand::Print(subopt) => {
let records = record::read_record_file(&opt.record_file);
record::print_records(&records, subopt.number);
}
#[cfg(feature = "record")]
Subcommand::Record(_subopt) => {
record::make_record(&opt.record_file);
}
Subcommand::Remove(subopt) => {
record::remove_record(
&opt.record_file,
&subopt.output,
subopt.record_number,
subopt.packet_number,
);
}
Subcommand::Test(_subopt) => {
record::make_test_record(&opt.record_file);
}
}
}