#[cfg(all(test, feature = "std", feature = "slab"))]
#[allow(
clippy::unwrap_used,
clippy::expect_used,
clippy::panic,
clippy::indexing_slicing,
clippy::arithmetic_side_effects
)]
mod tests;
mod matching;
pub(crate) use matching::*;
mod route;
pub use route::RouteEvents;
pub(crate) use route::Section;
mod query;
mod receive;
mod service;
mod withdrawal;
use core::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use rand_core::Rng;
use crate::{
Instant, Name, Pool, QueryHandle, ServiceHandle,
cache::{Cache, CacheEntry},
config::{EndpointConfig, QuerySpec, ServiceSpec},
error::{
CancelQueryError, HandleError, HandleServiceRenamedError, HandleTimeoutError,
RegisterServiceError, StartQueryError, StorageFullError, TransmitError,
},
event::{
EndpointEvent, HostConflict, KnownAnswer, ProbeConflict, QueryEvent, QueryUpdate, RouteEvent,
ServiceEvent, ServiceQuestion, ToQuery, ToService,
},
query::{CollectedAnswer, Query},
service::Service,
trace::*,
transmit::Transmit,
wire::{MessageReader, NameRef, ResourceClass, ResourceType},
};
cfg_heap! {
const WITHDRAWAL_SENDS: u8 = 3;
#[allow(dead_code)]
const WITHDRAWAL_INTERVAL: core::time::Duration = core::time::Duration::from_millis(250);
#[allow(dead_code)]
const WITHDRAWAL_RETRY_BACKOFF: core::time::Duration = core::time::Duration::from_millis(20);
const WITHDRAWAL_CEILING: core::time::Duration = core::time::Duration::from_secs(2);
}
cfg_heap! {
#[derive(Clone, Copy, Debug, Eq, PartialEq, derive_more::Display)]
#[display("{}", self.as_str())]
pub enum WithdrawalSend {
Sent,
Retry,
WriteOff,
}
impl WithdrawalSend {
pub const fn as_str(&self) -> &'static str {
match self {
Self::Sent => "sent",
Self::Retry => "retry",
Self::WriteOff => "write_off",
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct WithdrawalToken(u64);
struct WithdrawalItem<I> {
#[allow(dead_code)]
records: crate::records::ServiceRecords,
#[allow(dead_code)]
owned: crate::service::EmittedRecords,
#[allow(dead_code)]
host_a: std::vec::Vec<Ipv4Addr>,
#[allow(dead_code)]
host_aaaa: std::vec::Vec<Ipv6Addr>,
#[allow(dead_code)]
owed: [u8; 2],
#[allow(dead_code)]
next_at: I,
#[allow(dead_code)]
ceiling_at: I,
#[allow(dead_code)]
final_attempt: bool,
#[allow(dead_code)]
route: Option<ServiceHandle>,
#[allow(dead_code)]
holds_name: bool,
}
}
#[derive(Debug, Clone)]
pub struct ServiceRoute {
service_type: Name,
name: Name,
host: Name,
handle: ServiceHandle,
a_addrs: std::vec::Vec<Ipv4Addr>,
aaaa_addrs: std::vec::Vec<Ipv6Addr>,
aaaa_scopes: std::vec::Vec<u32>,
subtypes: std::vec::Vec<Name>,
#[cfg(any(feature = "alloc", feature = "std", feature = "no-atomic"))]
advertised_a: std::vec::Vec<Ipv4Addr>,
#[cfg(any(feature = "alloc", feature = "std", feature = "no-atomic"))]
advertised_aaaa: std::vec::Vec<Ipv6Addr>,
#[allow(dead_code)]
withdrawing: bool,
}
impl ServiceRoute {
#[inline(always)]
pub fn service_type(&self) -> &Name {
&self.service_type
}
#[inline(always)]
pub fn name(&self) -> &Name {
&self.name
}
#[inline(always)]
pub fn host(&self) -> &Name {
&self.host
}
#[inline(always)]
pub const fn handle(&self) -> ServiceHandle {
self.handle
}
#[inline(always)]
pub fn a_addrs(&self) -> &[Ipv4Addr] {
&self.a_addrs
}
#[inline(always)]
pub fn aaaa_addrs(&self) -> &[Ipv6Addr] {
&self.aaaa_addrs
}
#[inline(always)]
pub fn aaaa_scopes(&self) -> &[u32] {
&self.aaaa_scopes
}
cfg_heap! {
#[inline(always)]
pub(crate) fn advertised_a(&self) -> &[Ipv4Addr] {
&self.advertised_a
}
#[inline(always)]
pub(crate) fn advertised_aaaa(&self) -> &[Ipv6Addr] {
&self.advertised_aaaa
}
}
}
#[derive(Debug, Clone)]
pub struct EndpointEventEntry(EndpointEvent);
impl EndpointEventEntry {
#[inline(always)]
pub const fn event(&self) -> &EndpointEvent {
&self.0
}
}
pub struct Endpoint<I, R, C, SR, QS, EV, AN, EvQ> {
config: EndpointConfig,
rng: R,
services: SR,
queries: QS,
cache: Cache<I, C>,
pending_events: EV,
next_service_handle: u32,
next_query_handle: u32,
next_txid: u16,
#[cfg(any(feature = "alloc", feature = "std", feature = "no-atomic"))]
withdrawals: std::vec::Vec<(WithdrawalToken, WithdrawalItem<I>)>,
#[cfg(any(feature = "alloc", feature = "std", feature = "no-atomic"))]
next_withdrawal_token: u64,
#[cfg(feature = "stats")]
stats: std::sync::Arc<hick_trace::stats::Stats>,
_phantom: core::marker::PhantomData<(AN, EvQ)>,
}
impl<I, R, C, SR, QS, EV, AN, EvQ> Endpoint<I, R, C, SR, QS, EV, AN, EvQ>
where
I: Instant,
R: Rng,
C: Pool<CacheEntry<I>>,
SR: Pool<ServiceRoute>,
QS: Pool<Query<I, AN, EvQ>>,
EV: Pool<EndpointEventEntry>,
AN: Pool<CollectedAnswer>,
EvQ: Pool<QueryUpdate>,
{
pub fn try_new(config: EndpointConfig, mut rng: R) -> Self {
let raw_txid = rng.next_u32() as u16;
let next_txid = if raw_txid == 0 { 1 } else { raw_txid };
#[cfg(feature = "stats")]
let stats = std::sync::Arc::new(hick_trace::stats::Stats::default());
#[cfg(feature = "stats")]
let mut cache = Cache::new();
#[cfg(feature = "stats")]
cache.set_stats(stats.clone());
#[cfg(not(feature = "stats"))]
let cache = Cache::new();
Self {
config,
rng,
services: SR::new(),
queries: QS::new(),
cache,
pending_events: EV::new(),
next_service_handle: 0,
next_query_handle: 0,
next_txid,
#[cfg(any(feature = "alloc", feature = "std", feature = "no-atomic"))]
withdrawals: std::vec::Vec::new(),
#[cfg(any(feature = "alloc", feature = "std", feature = "no-atomic"))]
next_withdrawal_token: 0,
#[cfg(feature = "stats")]
stats,
_phantom: core::marker::PhantomData,
}
}
cfg_stats! {
pub fn stats(&self) -> hick_trace::stats::StatsSnapshot {
self.stats.snapshot()
}
pub fn stats_handle(&self) -> std::sync::Arc<hick_trace::stats::Stats> {
self.stats.clone()
}
}
#[inline(always)]
pub const fn config(&self) -> &EndpointConfig {
&self.config
}
}