#![cfg_attr(test, allow(clippy::unwrap_used, clippy::expect_used, clippy::panic))]
use common::proxy::ProxyConfig;
use common::quic::Congestion;
use common::remote::RemoteRequest;
use common::tls::{ClientTlsConfig, ServerTlsConfig};
use std::fmt;
use std::net::{IpAddr, SocketAddr};
use std::time::Duration;
use tracing::{error, info};
pub mod cert;
pub mod client;
pub mod common;
pub mod embedded;
pub mod server;
#[derive(Debug)]
pub struct ServerConfig {
pub host: IpAddr,
pub port: u16,
pub allow_reverse: bool,
pub allow_socks: bool,
pub tls: ServerTlsConfig,
pub congestion: Congestion,
pub max_connections: Option<usize>,
}
#[derive(Debug, Clone)]
pub struct ServerEndpoint {
pub addrs: Vec<SocketAddr>,
pub host: String,
}
impl ServerEndpoint {
pub fn primary(&self) -> SocketAddr {
*self
.addrs
.first()
.expect("ServerEndpoint constructed with no addresses")
}
}
impl fmt::Display for ServerEndpoint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.addrs.len() == 1 {
let addr = self.addrs[0];
if self.host == addr.ip().to_string() {
write!(f, "{addr}")
} else {
write!(f, "{} ({addr})", self.host)
}
} else {
write!(f, "{} (", self.host)?;
for (i, a) in self.addrs.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{a}")?;
}
write!(f, ")")
}
}
}
#[derive(Debug)]
pub struct ClientConfig {
pub server: ServerEndpoint,
pub remotes: Vec<RemoteRequest>,
pub tls: ClientTlsConfig,
pub congestion: Congestion,
pub reconnect: ReconnectConfig,
pub proxy: Option<ProxyConfig>,
}
#[derive(Debug, Clone)]
pub struct ReconnectConfig {
pub max_retries: Option<u32>,
pub initial_backoff: Duration,
pub max_backoff: Duration,
}
impl Default for ReconnectConfig {
fn default() -> Self {
Self {
max_retries: None,
initial_backoff: Duration::from_millis(200),
max_backoff: Duration::from_secs(300),
}
}
}
pub fn run_server(config: ServerConfig) {
info!("running server");
let result = build_runtime().and_then(|rt| rt.block_on(server::run_async(config)));
if let Err(e) = result {
error!("an error occurred: {}", e);
}
}
pub fn run_client(config: ClientConfig) {
info!("running client");
let result = build_runtime().and_then(|rt| rt.block_on(client::run_async(config)));
if let Err(e) = result {
error!("an error occurred: {}", e);
}
}
fn build_runtime() -> anyhow::Result<tokio::runtime::Runtime> {
tokio::runtime::Runtime::new().map_err(Into::into)
}