use crate::{
event,
inet::{
IpV4Address, IpV6Address, SocketAddress, SocketAddressV4, SocketAddressV6, Unspecified as _,
},
};
use core::fmt;
#[cfg(any(test, feature = "generator"))]
use bolero_generator::prelude::*;
pub mod ecn;
pub mod migration;
pub mod mtu;
pub use mtu::{BaseMtu, Config, Endpoint, InitialMtu, MaxMtu, MtuError, MINIMUM_MAX_DATAGRAM_SIZE};
pub const INITIAL_PTO_BACKOFF: u32 = 1;
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct Id(u8);
impl Id {
pub unsafe fn new(id: u8) -> Self {
Self(id)
}
pub fn as_u8(&self) -> u8 {
self.0
}
}
impl event::IntoEvent<u64> for Id {
#[inline]
fn into_event(self) -> u64 {
self.0 as u64
}
}
#[cfg(any(test, feature = "testing"))]
impl Id {
pub fn test_id() -> Self {
unsafe { Id::new(0) }
}
}
pub trait Handle: 'static + Copy + Send + fmt::Debug {
fn from_remote_address(remote_addr: RemoteAddress) -> Self;
fn remote_address(&self) -> RemoteAddress;
fn set_remote_address(&mut self, addr: RemoteAddress);
fn local_address(&self) -> LocalAddress;
fn set_local_address(&mut self, addr: LocalAddress);
fn unmapped_eq(&self, other: &Self) -> bool;
fn strict_eq(&self, other: &Self) -> bool;
fn maybe_update(&mut self, other: &Self);
}
macro_rules! impl_addr {
($name:ident) => {
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash)]
#[cfg_attr(any(test, feature = "generator"), derive(TypeGenerator))]
#[cfg_attr(kani, derive(kani::Arbitrary))]
pub struct $name(pub SocketAddress);
impl $name {
#[inline]
pub fn unmapped_eq(&self, other: &Self) -> bool {
self.0.unmapped_eq(&other.0)
}
}
impl From<event::api::SocketAddress<'_>> for $name {
#[inline]
fn from(value: event::api::SocketAddress<'_>) -> Self {
match value {
event::api::SocketAddress::IpV4 { ip, port } => {
$name(IpV4Address::new(*ip).with_port(port).into())
}
event::api::SocketAddress::IpV6 { ip, port } => {
$name(IpV6Address::new(*ip).with_port(port).into())
}
}
}
}
impl From<SocketAddress> for $name {
#[inline]
fn from(value: SocketAddress) -> Self {
Self(value)
}
}
impl From<SocketAddressV4> for $name {
#[inline]
fn from(value: SocketAddressV4) -> Self {
Self(value.into())
}
}
impl From<SocketAddressV6> for $name {
#[inline]
fn from(value: SocketAddressV6) -> Self {
Self(value.into())
}
}
impl From<$name> for core::net::SocketAddr {
#[inline]
fn from(value: $name) -> Self {
value.0.into()
}
}
impl core::ops::Deref for $name {
type Target = SocketAddress;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl core::ops::DerefMut for $name {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
};
}
impl_addr!(LocalAddress);
impl LocalAddress {
#[inline]
pub fn maybe_update(&mut self, other: &Self) {
ensure!(!other.is_unspecified());
*self = *other;
}
}
impl_addr!(RemoteAddress);
impl Handle for RemoteAddress {
#[inline]
fn from_remote_address(remote_address: RemoteAddress) -> Self {
remote_address
}
#[inline]
fn remote_address(&self) -> RemoteAddress {
*self
}
#[inline]
fn set_remote_address(&mut self, addr: RemoteAddress) {
*self = addr;
}
#[inline]
fn local_address(&self) -> LocalAddress {
SocketAddressV4::UNSPECIFIED.into()
}
#[inline]
fn set_local_address(&mut self, _addr: LocalAddress) {
}
#[inline]
fn unmapped_eq(&self, other: &Self) -> bool {
Self::unmapped_eq(self, other)
}
#[inline]
fn strict_eq(&self, other: &Self) -> bool {
PartialEq::eq(self, other)
}
#[inline]
fn maybe_update(&mut self, _other: &Self) {
}
}
#[derive(Clone, Copy, Debug, Eq)]
#[cfg_attr(any(test, feature = "generator"), derive(TypeGenerator))]
pub struct Tuple {
pub remote_address: RemoteAddress,
pub local_address: LocalAddress,
}
impl PartialEq for Tuple {
#[inline]
fn eq(&self, other: &Self) -> bool {
PartialEq::eq(&self.remote_address, &other.remote_address)
&& PartialEq::eq(&self.local_address, &other.local_address)
}
}
impl Handle for Tuple {
#[inline]
fn from_remote_address(remote_address: RemoteAddress) -> Self {
let local_address = SocketAddressV4::UNSPECIFIED.into();
Self {
remote_address,
local_address,
}
}
#[inline]
fn remote_address(&self) -> RemoteAddress {
self.remote_address
}
#[inline]
fn set_remote_address(&mut self, addr: RemoteAddress) {
self.remote_address = addr;
}
#[inline]
fn local_address(&self) -> LocalAddress {
self.local_address
}
#[inline]
fn set_local_address(&mut self, addr: LocalAddress) {
self.local_address = addr;
}
#[inline]
fn unmapped_eq(&self, other: &Self) -> bool {
self.local_address.unmapped_eq(&other.local_address)
&& self.remote_address.unmapped_eq(&other.remote_address)
}
#[inline]
fn strict_eq(&self, other: &Self) -> bool {
PartialEq::eq(self, other)
}
#[inline]
fn maybe_update(&mut self, other: &Self) {
self.local_address.maybe_update(&other.local_address);
}
}
const BLOCKED_PORTS: [u16; 11] = [
0, 17, 19, 53, 111, 123, 137, 138, 161, 389, 500, ];
const MAX_BLOCKED_PORT: u16 = BLOCKED_PORTS[BLOCKED_PORTS.len() - 1];
#[inline]
pub fn remote_port_blocked(port: u16) -> bool {
if port > MAX_BLOCKED_PORT {
return false;
}
for blocked in BLOCKED_PORTS {
if port == blocked {
return true;
}
}
false
}
const THROTTLED_PORTS: [u16; 5] = [
1900, 3702, 5353, 5355, 11211, ];
const MAX_THROTTLED_PORT: u16 = THROTTLED_PORTS[THROTTLED_PORTS.len() - 1];
pub const THROTTLED_PORTS_LEN: usize = THROTTLED_PORTS.len();
#[inline]
pub fn remote_port_throttled_index(port: u16) -> Option<usize> {
for (idx, throttled_port) in THROTTLED_PORTS.iter().enumerate() {
if *throttled_port == port {
return Some(idx);
}
}
None
}
#[inline]
pub fn remote_port_throttled(port: u16) -> bool {
if port > MAX_THROTTLED_PORT {
return false;
}
for throttled in THROTTLED_PORTS {
if port == throttled {
return true;
}
}
false
}
#[cfg(test)]
mod tests {
use crate::path::{
remote_port_blocked, remote_port_throttled, BLOCKED_PORTS, MAX_BLOCKED_PORT,
MAX_THROTTLED_PORT, THROTTLED_PORTS,
};
#[test]
fn blocked_ports_is_sorted() {
assert_eq!(Some(MAX_BLOCKED_PORT), BLOCKED_PORTS.iter().max().copied());
let mut sorted = BLOCKED_PORTS.to_vec();
sorted.sort_unstable();
for i in 0..BLOCKED_PORTS.len() {
assert_eq!(sorted[i], BLOCKED_PORTS[i]);
}
}
#[test]
#[cfg_attr(miri, ignore)]
fn blocked_port() {
for port in 0..u16::MAX {
let blocked_expected = BLOCKED_PORTS.iter().copied().any(|blocked| blocked == port);
assert_eq!(blocked_expected, remote_port_blocked(port));
}
}
#[test]
fn throttled_ports_is_sorted() {
assert_eq!(
Some(MAX_THROTTLED_PORT),
THROTTLED_PORTS.iter().max().copied()
);
let mut sorted = THROTTLED_PORTS.to_vec();
sorted.sort_unstable();
for i in 0..THROTTLED_PORTS.len() {
assert_eq!(sorted[i], THROTTLED_PORTS[i]);
}
}
#[test]
#[cfg_attr(miri, ignore)]
fn throttled_port() {
for port in 0..u16::MAX {
let throttled_expected = THROTTLED_PORTS
.iter()
.copied()
.any(|throttled| throttled == port);
assert_eq!(throttled_expected, remote_port_throttled(port));
}
}
}
#[cfg(any(test, feature = "testing"))]
pub mod testing {
use crate::{
connection, event,
event::{builder::SocketAddress, IntoEvent},
};
impl event::builder::Path<'_> {
pub fn test() -> Self {
Self {
local_addr: SocketAddress::IpV4 {
ip: &[127, 0, 0, 1],
port: 0,
},
local_cid: connection::LocalId::TEST_ID.into_event(),
remote_addr: SocketAddress::IpV4 {
ip: &[127, 0, 0, 1],
port: 0,
},
remote_cid: connection::PeerId::TEST_ID.into_event(),
id: 0,
is_active: false,
}
}
}
}