use std::{net::SocketAddr, time::Duration};
use crate::{Authentication, ClientError};
pub use irtt_proto::MAX_SERVER_FILL_BYTES;
use irtt_proto::{Clock, ReceivedStats, StampAt};
pub(crate) const DEFAULT_PORT: u16 = 2112;
pub const MAX_DSCP_CODEPOINT: u8 = 63;
pub const MAX_TTL: u32 = 255;
pub const MAX_UDP_PAYLOAD_LENGTH: u32 = 65_507;
pub(crate) const DEFAULT_DURATION: Duration = Duration::from_secs(3);
pub(crate) const DEFAULT_INTERVAL: Duration = Duration::from_secs(1);
pub(crate) const DEFAULT_OPEN_TIMEOUTS: [Duration; 4] = [
Duration::from_secs(1),
Duration::from_secs(2),
Duration::from_secs(4),
Duration::from_secs(8),
];
pub(crate) const MIN_OPEN_TIMEOUT: Duration = Duration::from_millis(200);
pub(crate) const DEFAULT_PROBE_TIMEOUT: Duration = Duration::from_secs(4);
pub(crate) const DEFAULT_MAX_PENDING: usize = 4096;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ClientConfig {
pub address_family: AddressFamily,
pub socket: SocketConfig,
pub request: SessionRequest,
pub open: OpenPolicy,
pub auth: Authentication,
pub probe_timeout: Duration,
pub max_pending_probes: usize,
}
impl Default for ClientConfig {
fn default() -> Self {
Self {
address_family: AddressFamily::default(),
socket: SocketConfig::default(),
request: SessionRequest::default(),
open: OpenPolicy::default(),
auth: Authentication::Unauthenticated,
probe_timeout: DEFAULT_PROBE_TIMEOUT,
max_pending_probes: DEFAULT_MAX_PENDING,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum AddressFamily {
#[default]
Any,
Ipv4,
Ipv6,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SessionRequest {
pub duration: Option<Duration>,
pub interval: Duration,
pub length: u32,
pub received_stats: ReceivedStats,
pub stamp_at: StampAt,
pub clock: Clock,
pub dscp: u8,
pub server_fill: Option<String>,
pub run_mode: RunMode,
}
impl Default for SessionRequest {
fn default() -> Self {
Self {
duration: Some(DEFAULT_DURATION),
interval: DEFAULT_INTERVAL,
length: 0,
received_stats: ReceivedStats::Both,
stamp_at: StampAt::Both,
clock: Clock::Both,
dscp: 0,
server_fill: None,
run_mode: RunMode::Normal,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OpenPolicy {
pub timeouts: Vec<Duration>,
pub negotiation: NegotiationPolicy,
}
impl OpenPolicy {
pub(crate) fn validate(&self) -> Result<(), ClientError> {
if self.timeouts.is_empty() {
return Err(ClientError::NoOpenTimeouts);
}
for timeout in &self.timeouts {
if *timeout < MIN_OPEN_TIMEOUT {
return Err(ClientError::OpenTimeoutTooSmall {
timeout: *timeout,
minimum: MIN_OPEN_TIMEOUT,
});
}
}
Ok(())
}
}
impl Default for OpenPolicy {
fn default() -> Self {
Self {
timeouts: DEFAULT_OPEN_TIMEOUTS.to_vec(),
negotiation: NegotiationPolicy::Strict,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct SocketConfig {
pub bind_addr: Option<SocketAddr>,
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
pub bind_to_device: Option<String>,
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
pub mark: Option<u32>,
#[cfg(target_os = "freebsd")]
pub fib: Option<u32>,
pub ttl: Option<u32>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NegotiationPolicy {
Strict,
Loose,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RunMode {
Normal,
NoTest,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RecvBudget {
pub max_packets: usize,
}
impl Default for RecvBudget {
fn default() -> Self {
Self { max_packets: 64 }
}
}