Skip to main content

rns_net/common/
event.rs

1//! Event types for the driver loop — generic over the writer type.
2
3use std::fmt;
4use std::io::Read;
5use std::net::IpAddr;
6use std::sync::mpsc;
7use std::time::Duration;
8
9use rns_core::announce::ValidatedAnnounce;
10use rns_core::transport::announce_verify_queue::AnnounceVerifyKey;
11use rns_core::transport::types::{InterfaceId, InterfaceInfo};
12
13use crate::common::link_manager::RequestResponse;
14
15#[derive(Debug, Clone, Default, PartialEq)]
16pub struct InterfaceTelemetry {
17    pub cpu_load: Option<f64>,
18    pub mem_load: Option<f64>,
19    pub switch_id: Option<[u8; 4]>,
20    pub endpoint_id: Option<[u8; 8]>,
21    pub via_switch_id: Option<[u8; 4]>,
22    pub peers: Option<usize>,
23}
24
25#[derive(Debug, Clone)]
26pub struct DynamicInterfaceRegistration {
27    pub info: InterfaceInfo,
28    pub interface_type: String,
29    pub parent_id: InterfaceId,
30    pub telemetry: InterfaceTelemetry,
31    pub ifac: Option<crate::ifac::IfacState>,
32}
33
34/// Policy for handling incoming direct-connect proposals.
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub enum HolePunchPolicy {
37    /// Reject all proposals.
38    Reject,
39    /// Accept all proposals automatically.
40    AcceptAll,
41    /// Ask the application callback.
42    AskApp,
43}
44
45impl Default for HolePunchPolicy {
46    fn default() -> Self {
47        HolePunchPolicy::AcceptAll
48    }
49}
50
51/// Scalar runtime-config value.
52#[derive(Debug, Clone, PartialEq)]
53pub enum RuntimeConfigValue {
54    Int(i64),
55    Float(f64),
56    Bool(bool),
57    String(String),
58    Null,
59}
60
61/// Source of a runtime-config value.
62#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63pub enum RuntimeConfigSource {
64    Startup,
65    RuntimeOverride,
66}
67
68/// How a runtime-config change applies.
69#[derive(Debug, Clone, Copy, PartialEq, Eq)]
70pub enum RuntimeConfigApplyMode {
71    Immediate,
72    NewConnectionsOnly,
73    NextReconnect,
74    RestartRequired,
75}
76
77/// A runtime-config entry exposed by the daemon.
78#[derive(Debug, Clone, PartialEq)]
79pub struct RuntimeConfigEntry {
80    pub key: String,
81    pub value: RuntimeConfigValue,
82    pub default: RuntimeConfigValue,
83    pub source: RuntimeConfigSource,
84    pub apply_mode: RuntimeConfigApplyMode,
85    pub description: Option<String>,
86}
87
88/// Runtime-config mutation error.
89#[derive(Debug, Clone, PartialEq, Eq)]
90pub struct RuntimeConfigError {
91    pub code: RuntimeConfigErrorCode,
92    pub message: String,
93}
94
95/// Category of runtime-config mutation error.
96#[derive(Debug, Clone, Copy, PartialEq, Eq)]
97pub enum RuntimeConfigErrorCode {
98    UnknownKey,
99    InvalidType,
100    InvalidValue,
101    Unsupported,
102    NotFound,
103    ApplyFailed,
104}
105
106#[derive(Debug, Clone, Copy, PartialEq, Eq)]
107pub enum LifecycleState {
108    Active,
109    Draining,
110    Stopping,
111    Stopped,
112}
113
114#[derive(Debug, Clone, PartialEq)]
115pub struct DrainStatus {
116    pub state: LifecycleState,
117    pub drain_age_seconds: Option<f64>,
118    pub deadline_remaining_seconds: Option<f64>,
119    pub drain_complete: bool,
120    pub interface_writer_queued_frames: usize,
121    pub provider_backlog_events: usize,
122    pub provider_consumer_queued_events: usize,
123    pub detail: Option<String>,
124}
125
126/// Events sent to the driver thread.
127///
128/// `W` is the writer type (e.g. `Box<dyn Writer>` for sync,
129/// or a channel sender for async).
130pub enum Event<W: Send> {
131    /// A decoded frame arrived from an interface.
132    Frame {
133        interface_id: InterfaceId,
134        data: Vec<u8>,
135        rssi: Option<i16>,
136        snr: Option<f32>,
137    },
138    /// (Internal) An announce was verified off-thread and is ready for driver-side processing.
139    AnnounceVerified {
140        key: AnnounceVerifyKey,
141        validated: ValidatedAnnounce,
142        sig_cache_key: [u8; 32],
143    },
144    /// (Internal) An announce failed off-thread verification.
145    AnnounceVerifyFailed {
146        key: AnnounceVerifyKey,
147        sig_cache_key: [u8; 32],
148    },
149    /// An interface came online after (re)connecting.
150    /// Carries a new writer if the connection was re-established.
151    /// Carries InterfaceInfo if this is a new dynamic interface (e.g. TCP server client).
152    InterfaceUp(InterfaceId, Option<W>, Option<InterfaceInfo>),
153    /// Register a dynamic interface with an exact type and parent identity.
154    DynamicInterfaceUp {
155        id: InterfaceId,
156        writer: W,
157        registration: DynamicInterfaceRegistration,
158    },
159    /// Update optional device/interface telemetry without replacing counters.
160    InterfaceTelemetry {
161        interface_id: InterfaceId,
162        telemetry: InterfaceTelemetry,
163    },
164    /// An interface went offline (socket closed, error).
165    InterfaceDown(InterfaceId),
166    /// Periodic maintenance tick (1s interval).
167    Tick,
168    /// Enter drain mode and stop admitting new work.
169    BeginDrain { timeout: Duration },
170    /// Shut down the driver loop.
171    Shutdown,
172    /// Send an outbound packet.
173    SendOutbound {
174        raw: Vec<u8>,
175        dest_type: u8,
176        attached_interface: Option<InterfaceId>,
177    },
178    /// Register a local destination.
179    RegisterDestination { dest_hash: [u8; 16], dest_type: u8 },
180    /// Remember the latest explicit SINGLE announce for shared-client replay.
181    StoreSharedAnnounce {
182        dest_hash: [u8; 16],
183        name_hash: [u8; 10],
184        identity_prv_key: [u8; 64],
185        app_data: Option<Vec<u8>>,
186    },
187    /// Deregister a local destination.
188    DeregisterDestination { dest_hash: [u8; 16] },
189    /// Deregister a link destination (stop accepting incoming links).
190    DeregisterLinkDestination { dest_hash: [u8; 16] },
191    /// Query driver state. Response is sent via the provided channel.
192    Query(QueryRequest, mpsc::Sender<QueryResponse>),
193    /// Register a link destination (accepts incoming LINKREQUEST).
194    RegisterLinkDestination {
195        dest_hash: [u8; 16],
196        sig_prv_bytes: [u8; 32],
197        sig_pub_bytes: [u8; 32],
198        resource_strategy: u8,
199        max_request_size: Option<usize>,
200    },
201    /// Register a request handler for a path on established links.
202    RegisterRequestHandler {
203        path: String,
204        allowed_list: Option<Vec<[u8; 16]>>,
205        handler: Box<
206            dyn Fn([u8; 16], &str, &[u8], Option<&([u8; 16], [u8; 64])>) -> Option<Vec<u8>> + Send,
207        >,
208    },
209    /// Register a request handler that may return resource responses with metadata.
210    RegisterRequestHandlerResponse {
211        path: String,
212        allowed_list: Option<Vec<[u8; 16]>>,
213        handler: Box<
214            dyn Fn([u8; 16], &str, &[u8], Option<&([u8; 16], [u8; 64])>) -> Option<RequestResponse>
215                + Send,
216        >,
217    },
218    /// Register a request handler that sends its response later.
219    RegisterDeferredRequestHandler {
220        path: String,
221        allowed_list: Option<Vec<[u8; 16]>>,
222        handler: Box<dyn Fn([u8; 16], &str, [u8; 16], &[u8], Option<&([u8; 16], [u8; 64])>) + Send>,
223    },
224    /// Create an outbound link. Response sends (link_id) back.
225    CreateLink {
226        dest_hash: [u8; 16],
227        dest_sig_pub_bytes: [u8; 32],
228        response_tx: mpsc::Sender<[u8; 16]>,
229    },
230    /// Send a request on an established link.
231    SendRequest {
232        link_id: [u8; 16],
233        path: String,
234        data: Vec<u8>,
235        max_response_size: Option<usize>,
236    },
237    /// Complete a request previously delivered to a deferred handler.
238    SendDeferredResponse {
239        link_id: [u8; 16],
240        request_id: [u8; 16],
241        data: Vec<u8>,
242    },
243    /// Identify on a link (send identity to remote peer).
244    IdentifyOnLink {
245        link_id: [u8; 16],
246        identity_prv_key: [u8; 64],
247    },
248    /// Tear down a link.
249    TeardownLink { link_id: [u8; 16] },
250    /// Send a resource on a link.
251    SendResource {
252        link_id: [u8; 16],
253        data: Vec<u8>,
254        metadata: Option<Vec<u8>>,
255        auto_compress: bool,
256    },
257    /// Send a Resource from a sequential reader without buffering the full payload.
258    SendResourceStream {
259        link_id: [u8; 16],
260        transfer_id: crate::resource::ResourceTransferId,
261        reader: Box<dyn Read + Send>,
262        declared_length: u64,
263        metadata: Option<Vec<u8>>,
264        auto_compress: bool,
265    },
266    /// Set the resource acceptance strategy for a link.
267    SetResourceStrategy { link_id: [u8; 16], strategy: u8 },
268    /// Select in-memory or disk-backed delivery for independent Resources.
269    SetResourceReceiveMode {
270        link_id: [u8; 16],
271        mode: crate::resource::ResourceReceiveMode,
272    },
273    /// Accept or reject a pending resource (for AcceptApp strategy).
274    AcceptResource {
275        link_id: [u8; 16],
276        resource_hash: Vec<u8>,
277        accept: bool,
278    },
279    /// Send a channel message on a link.
280    SendChannelMessage {
281        link_id: [u8; 16],
282        msgtype: u16,
283        payload: Vec<u8>,
284        response_tx: mpsc::Sender<Result<(), String>>,
285    },
286    /// Send generic data on a link with a given context.
287    SendOnLink {
288        link_id: [u8; 16],
289        data: Vec<u8>,
290        context: u8,
291    },
292    /// Request a path to a destination from the network.
293    RequestPath { dest_hash: [u8; 16] },
294    /// Register a proof strategy for a destination.
295    RegisterProofStrategy {
296        dest_hash: [u8; 16],
297        strategy: rns_core::types::ProofStrategy,
298        /// Full identity private key (64 bytes) for signing proofs.
299        signing_key: Option<[u8; 64]>,
300    },
301    /// Propose a direct connection to a peer via hole punching.
302    ProposeDirectConnect { link_id: [u8; 16] },
303    /// Set the direct-connect policy.
304    SetDirectConnectPolicy { policy: HolePunchPolicy },
305    /// (Internal) Probe result arrived from a worker thread.
306    HolePunchProbeResult {
307        link_id: [u8; 16],
308        session_id: [u8; 16],
309        observed_addr: std::net::SocketAddr,
310        socket: std::net::UdpSocket,
311        /// The probe server that responded successfully.
312        probe_server: std::net::SocketAddr,
313    },
314    /// (Internal) Probe failed.
315    HolePunchProbeFailed {
316        link_id: [u8; 16],
317        session_id: [u8; 16],
318    },
319    /// An interface's configuration changed (placeholder for future use).
320    InterfaceConfigChanged(InterfaceId),
321    /// A backbone server accepted a new inbound peer connection.
322    BackbonePeerConnected {
323        server_interface_id: InterfaceId,
324        peer_interface_id: InterfaceId,
325        peer_ip: IpAddr,
326        peer_port: u16,
327    },
328    /// A backbone peer connection closed for any reason.
329    BackbonePeerDisconnected {
330        server_interface_id: InterfaceId,
331        peer_interface_id: InterfaceId,
332        peer_ip: IpAddr,
333        peer_port: u16,
334        connected_for: Duration,
335        had_received_data: bool,
336    },
337    /// A backbone peer was disconnected for idling without sending data.
338    BackbonePeerIdleTimeout {
339        server_interface_id: InterfaceId,
340        peer_interface_id: InterfaceId,
341        peer_ip: IpAddr,
342        peer_port: u16,
343        connected_for: Duration,
344    },
345    /// A backbone peer was disconnected because its writer stalled.
346    BackbonePeerWriteStall {
347        server_interface_id: InterfaceId,
348        peer_interface_id: InterfaceId,
349        peer_ip: IpAddr,
350        peer_port: u16,
351        connected_for: Duration,
352    },
353    /// A backbone peer IP was penalized due to abusive behavior.
354    BackbonePeerPenalty {
355        server_interface_id: InterfaceId,
356        peer_ip: IpAddr,
357        penalty_level: u8,
358        blacklist_for: Duration,
359    },
360    /// Load an in-memory WASM hook at runtime.
361    LoadHook {
362        name: String,
363        wasm_bytes: Vec<u8>,
364        attach_point: String,
365        priority: i32,
366        response_tx: mpsc::Sender<Result<(), String>>,
367    },
368    /// Load a hook from a server-local filesystem path at runtime.
369    LoadHookFile {
370        name: String,
371        path: String,
372        hook_type: String,
373        attach_point: String,
374        priority: i32,
375        response_tx: mpsc::Sender<Result<(), String>>,
376    },
377    /// Load a registered built-in hook by ID at runtime.
378    LoadBuiltinHook {
379        name: String,
380        builtin_id: String,
381        attach_point: String,
382        priority: i32,
383        response_tx: mpsc::Sender<Result<(), String>>,
384    },
385    /// Unload a hook at runtime.
386    UnloadHook {
387        name: String,
388        attach_point: String,
389        response_tx: mpsc::Sender<Result<(), String>>,
390    },
391    /// Reload an in-memory WASM hook at runtime (detach + recompile + reattach with same priority).
392    ReloadHook {
393        name: String,
394        attach_point: String,
395        wasm_bytes: Vec<u8>,
396        response_tx: mpsc::Sender<Result<(), String>>,
397    },
398    /// Reload a hook from a server-local filesystem path at runtime.
399    ReloadHookFile {
400        name: String,
401        attach_point: String,
402        path: String,
403        hook_type: String,
404        response_tx: mpsc::Sender<Result<(), String>>,
405    },
406    /// Reload a registered built-in hook by ID at runtime.
407    ReloadBuiltinHook {
408        name: String,
409        attach_point: String,
410        builtin_id: String,
411        response_tx: mpsc::Sender<Result<(), String>>,
412    },
413    /// Enable or disable a loaded hook at runtime.
414    SetHookEnabled {
415        name: String,
416        attach_point: String,
417        enabled: bool,
418        response_tx: mpsc::Sender<Result<(), String>>,
419    },
420    /// Update the priority of a loaded hook at runtime.
421    SetHookPriority {
422        name: String,
423        attach_point: String,
424        priority: i32,
425        response_tx: mpsc::Sender<Result<(), String>>,
426    },
427    /// List all loaded hooks.
428    ListHooks {
429        response_tx: mpsc::Sender<Vec<HookInfo>>,
430    },
431}
432
433/// Information about a loaded hook program.
434#[derive(Debug, Clone)]
435pub struct HookInfo {
436    pub name: String,
437    pub hook_type: String,
438    pub attach_point: String,
439    pub priority: i32,
440    pub enabled: bool,
441    pub consecutive_traps: u32,
442}
443
444/// Live behavioral state for a backbone peer IP.
445#[derive(Debug, Clone, PartialEq)]
446pub struct BackbonePeerStateEntry {
447    pub interface_name: String,
448    pub peer_ip: IpAddr,
449    pub connected_count: usize,
450    pub blacklisted_remaining_secs: Option<f64>,
451    pub blacklist_reason: Option<String>,
452    pub reject_count: u64,
453}
454
455/// Hook-visible snapshot of a backbone peer lifecycle event.
456#[derive(Debug, Clone, PartialEq, Eq)]
457pub struct BackbonePeerHookEvent {
458    pub server_interface_id: InterfaceId,
459    pub peer_interface_id: Option<InterfaceId>,
460    pub peer_ip: IpAddr,
461    pub peer_port: u16,
462    pub connected_for: Duration,
463    pub had_received_data: bool,
464    pub penalty_level: u8,
465    pub blacklist_for: Duration,
466}
467
468#[derive(Debug, Clone, PartialEq, Eq)]
469pub struct BackboneInterfaceEntry {
470    pub interface_id: InterfaceId,
471    pub interface_name: String,
472}
473
474#[derive(Debug, Clone, PartialEq)]
475pub struct KnownDestinationEntry {
476    pub dest_hash: [u8; 16],
477    pub identity_hash: [u8; 16],
478    pub public_key: [u8; 64],
479    pub app_data: Option<Vec<u8>>,
480    pub hops: u8,
481    pub received_at: f64,
482    pub receiving_interface: InterfaceId,
483    pub was_used: bool,
484    pub last_used_at: Option<f64>,
485    pub retained: bool,
486}
487
488#[derive(Debug, Clone, PartialEq, Eq)]
489pub struct ProviderBridgeConsumerStats {
490    pub id: u64,
491    pub connected: bool,
492    pub queue_len: usize,
493    pub queued_bytes: usize,
494    pub dropped_pending: u64,
495    pub dropped_total: u64,
496    pub queue_max_events: usize,
497    pub queue_max_bytes: usize,
498}
499
500#[derive(Debug, Clone, PartialEq, Eq)]
501pub struct ProviderBridgeStats {
502    pub connected: bool,
503    pub consumer_count: usize,
504    pub queue_max_events: usize,
505    pub queue_max_bytes: usize,
506    pub backlog_len: usize,
507    pub backlog_bytes: usize,
508    pub backlog_dropped_pending: u64,
509    pub backlog_dropped_total: u64,
510    pub total_disconnect_count: u64,
511    pub consumers: Vec<ProviderBridgeConsumerStats>,
512}
513
514/// Queries that can be sent to the driver.
515#[derive(Debug)]
516pub enum QueryRequest {
517    /// Get interface statistics and transport info.
518    InterfaceStats,
519    /// Get path table entries, optionally filtered by max hops.
520    PathTable { max_hops: Option<u8> },
521    /// Get rate table entries.
522    RateTable,
523    /// Look up the next hop for a destination.
524    NextHop { dest_hash: [u8; 16] },
525    /// Look up the next hop interface name for a destination.
526    NextHopIfName { dest_hash: [u8; 16] },
527    /// Get link table entry count.
528    LinkCount,
529    /// Drop a specific path.
530    DropPath { dest_hash: [u8; 16] },
531    /// Drop all paths that route via a given transport hash.
532    DropAllVia { transport_hash: [u8; 16] },
533    /// Drop all announce queues.
534    DropAnnounceQueues,
535    /// Get the transport identity hash.
536    TransportIdentity,
537    /// Snapshot restart-relevant transport routing state.
538    TransportStateSnapshot,
539    /// Get all blackholed identities.
540    GetBlackholed,
541    /// Add an identity to the blackhole list.
542    BlackholeIdentity {
543        identity_hash: [u8; 16],
544        duration_hours: Option<f64>,
545        reason: Option<String>,
546    },
547    /// Remove an identity from the blackhole list.
548    UnblackholeIdentity { identity_hash: [u8; 16] },
549    /// Check if a path exists to a destination.
550    HasPath { dest_hash: [u8; 16] },
551    /// Get hop count to a destination.
552    HopsTo { dest_hash: [u8; 16] },
553    /// Recall identity info for a destination.
554    RecallIdentity { dest_hash: [u8; 16] },
555    /// List known-destination lifecycle state.
556    KnownDestinations,
557    /// Get locally registered destinations.
558    LocalDestinations,
559    /// Get active links.
560    Links,
561    /// Get active resource transfers.
562    Resources,
563    /// Inject a path entry into the path table.
564    InjectPath {
565        dest_hash: [u8; 16],
566        next_hop: [u8; 16],
567        hops: u8,
568        expires: f64,
569        interface_name: String,
570        packet_hash: [u8; 32],
571    },
572    /// Inject an identity into the known destinations cache.
573    InjectIdentity {
574        dest_hash: [u8; 16],
575        identity_hash: [u8; 16],
576        public_key: [u8; 64],
577        app_data: Option<Vec<u8>>,
578        hops: u8,
579        received_at: f64,
580    },
581    /// Restore a known destination with full lifecycle state.
582    RestoreKnownDestination(KnownDestinationEntry),
583    /// Mark a known destination as explicitly retained.
584    RetainKnownDestination { dest_hash: [u8; 16] },
585    /// Mark all known destinations announced by an identity as retained.
586    RetainIdentity { identity_hash: [u8; 16] },
587    /// Clear the retained flag on a known destination.
588    UnretainKnownDestination { dest_hash: [u8; 16] },
589    /// Mark a known destination as used.
590    MarkKnownDestinationUsed { dest_hash: [u8; 16] },
591    /// Get discovered interfaces.
592    DiscoveredInterfaces {
593        only_available: bool,
594        only_transport: bool,
595    },
596    /// Send a probe packet to a destination and return (packet_hash, hops).
597    SendProbe {
598        dest_hash: [u8; 16],
599        payload_size: usize,
600    },
601    /// Check if a proof was received for a probe packet.
602    CheckProof { packet_hash: [u8; 32] },
603    /// List runtime-config entries currently supported by the daemon.
604    ListRuntimeConfig,
605    /// Get a single runtime-config entry by key.
606    GetRuntimeConfig { key: String },
607    /// Set a runtime-config value by key.
608    SetRuntimeConfig {
609        key: String,
610        value: RuntimeConfigValue,
611    },
612    /// Reset a runtime-config value to its startup/default value.
613    ResetRuntimeConfig { key: String },
614    /// List live backbone peer state, optionally filtered to one interface.
615    BackbonePeerState { interface_name: Option<String> },
616    /// List registered backbone server interfaces.
617    BackboneInterfaces,
618    /// Report live provider-bridge queue/drop state.
619    ProviderBridgeStats,
620    /// Report current lifecycle/drain status.
621    DrainStatus,
622    /// Clear live backbone peer state for one interface/IP pair.
623    ClearBackbonePeerState {
624        interface_name: String,
625        peer_ip: IpAddr,
626    },
627    /// Blacklist a backbone peer IP for a duration.
628    BlacklistBackbonePeer {
629        interface_name: String,
630        peer_ip: IpAddr,
631        duration: Duration,
632        reason: String,
633        penalty_level: u8,
634    },
635}
636
637/// Responses to queries.
638#[derive(Debug)]
639pub enum QueryResponse {
640    InterfaceStats(InterfaceStatsResponse),
641    PathTable(Vec<PathTableEntry>),
642    RateTable(Vec<RateTableEntry>),
643    NextHop(Option<NextHopResponse>),
644    NextHopIfName(Option<String>),
645    LinkCount(usize),
646    DropPath(bool),
647    DropAllVia(usize),
648    DropAnnounceQueues,
649    TransportIdentity(Option<[u8; 16]>),
650    TransportStateSnapshot(rns_core::transport::persistence::TransportStateSnapshot),
651    Blackholed(Vec<BlackholeInfo>),
652    BlackholeResult(bool),
653    UnblackholeResult(bool),
654    HasPath(bool),
655    HopsTo(Option<u8>),
656    RecallIdentity(Option<crate::common::destination::AnnouncedIdentity>),
657    KnownDestinations(Vec<KnownDestinationEntry>),
658    LocalDestinations(Vec<LocalDestinationEntry>),
659    Links(Vec<LinkInfoEntry>),
660    Resources(Vec<ResourceInfoEntry>),
661    InjectPath(bool),
662    InjectIdentity(bool),
663    RestoreKnownDestination(bool),
664    RetainKnownDestination(bool),
665    RetainIdentity(bool),
666    UnretainKnownDestination(bool),
667    MarkKnownDestinationUsed(bool),
668    /// List of discovered interfaces.
669    DiscoveredInterfaces(Vec<crate::common::discovery::DiscoveredInterface>),
670    /// Probe sent: (packet_hash, hops) or None if identity unknown.
671    SendProbe(Option<([u8; 32], u8)>),
672    /// Proof check: RTT if received, None if still pending.
673    CheckProof(Option<f64>),
674    /// Runtime-config entries currently supported by the daemon.
675    RuntimeConfigList(Vec<RuntimeConfigEntry>),
676    /// A specific runtime-config entry, or None if the key is unknown.
677    RuntimeConfigEntry(Option<RuntimeConfigEntry>),
678    /// Result of setting a runtime-config value.
679    RuntimeConfigSet(Result<RuntimeConfigEntry, RuntimeConfigError>),
680    /// Result of resetting a runtime-config value.
681    RuntimeConfigReset(Result<RuntimeConfigEntry, RuntimeConfigError>),
682    /// Live backbone peer state entries.
683    BackbonePeerState(Vec<BackbonePeerStateEntry>),
684    /// Registered backbone server interfaces.
685    BackboneInterfaces(Vec<BackboneInterfaceEntry>),
686    /// Live provider-bridge queue/drop state if enabled.
687    ProviderBridgeStats(Option<ProviderBridgeStats>),
688    /// Current lifecycle/drain status.
689    DrainStatus(DrainStatus),
690    /// Result of clearing one backbone peer state entry.
691    ClearBackbonePeerState(bool),
692    /// Result of blacklisting a backbone peer.
693    BlacklistBackbonePeer(bool),
694}
695
696/// Interface statistics response.
697#[derive(Debug, Clone)]
698pub struct InterfaceStatsResponse {
699    pub interfaces: Vec<SingleInterfaceStat>,
700    pub transport_id: Option<[u8; 16]>,
701    pub transport_enabled: bool,
702    pub transport_uptime: f64,
703    /// Total received bytes across all interfaces.
704    pub total_rxb: u64,
705    /// Total transmitted bytes across all interfaces.
706    pub total_txb: u64,
707    /// Probe responder destination hash (if enabled).
708    pub probe_responder: Option<[u8; 16]>,
709    /// Outbound Backbone peer-pool state, if enabled.
710    pub backbone_peer_pool: Option<BackbonePeerPoolStatus>,
711}
712
713/// Runtime status for the outbound Backbone peer pool.
714#[derive(Debug, Clone)]
715pub struct BackbonePeerPoolStatus {
716    pub max_connected: usize,
717    pub active_count: usize,
718    pub standby_count: usize,
719    pub cooldown_count: usize,
720    pub members: Vec<BackbonePeerPoolMemberStatus>,
721}
722
723/// Runtime status for one outbound Backbone peer-pool member.
724#[derive(Debug, Clone)]
725pub struct BackbonePeerPoolMemberStatus {
726    pub name: String,
727    pub remote: String,
728    pub source: String,
729    pub priority: u8,
730    pub state: String,
731    pub interface_id: Option<u64>,
732    pub failure_count: usize,
733    pub last_error: Option<String>,
734    pub cooldown_remaining_seconds: Option<f64>,
735}
736
737/// Statistics for a single interface.
738#[derive(Debug, Clone)]
739pub struct SingleInterfaceStat {
740    pub id: u64,
741    pub name: String,
742    pub status: bool,
743    pub mode: u8,
744    /// Signed interface preference used by path selection.
745    pub gravity: i64,
746    /// Whether boundary ingress announces may propagate to internal interfaces.
747    pub announces_to_internal: Option<bool>,
748    pub rxb: u64,
749    pub txb: u64,
750    pub rx_packets: u64,
751    pub tx_packets: u64,
752    pub cpu_load: Option<f64>,
753    pub mem_load: Option<f64>,
754    pub switch_id: Option<[u8; 4]>,
755    pub endpoint_id: Option<[u8; 8]>,
756    pub via_switch_id: Option<[u8; 4]>,
757    pub peers: Option<usize>,
758    pub bitrate: Option<u64>,
759    pub ifac_size: Option<usize>,
760    pub started: f64,
761    /// Incoming announce frequency (per second).
762    pub ia_freq: f64,
763    /// Outgoing announce frequency (per second).
764    pub oa_freq: f64,
765    /// Incoming path request frequency (per second).
766    pub ip_freq: f64,
767    /// Outgoing path request frequency (per second).
768    pub op_freq: f64,
769    /// Outgoing path request samples currently retained.
770    pub op_samples: usize,
771    /// Whether announce ingress-control burst limiting is currently active.
772    pub burst_active: bool,
773    /// Timestamp when announce ingress-control burst limiting activated.
774    pub burst_activated: f64,
775    /// Whether path-request ingress-control burst limiting is currently active.
776    pub pr_burst_active: bool,
777    /// Timestamp when path-request burst limiting activated.
778    pub pr_burst_activated: f64,
779    /// Connected client count for aggregate server interfaces, if reported.
780    pub clients: Option<u64>,
781    /// Fast-flapping IPs currently blocked by an aggregate server interface.
782    pub blocked_ips: Option<u64>,
783    /// Sorted textual IP addresses currently blocked for fast flapping.
784    pub blocked_ip_list: Option<Vec<String>>,
785    /// Target interval for outgoing announce rate control, in seconds.
786    pub announce_rate_target: Option<f64>,
787    /// Announce-rate control grace count.
788    pub announce_rate_grace: u32,
789    /// Announce-rate control penalty, in seconds.
790    pub announce_rate_penalty: f64,
791    /// Human-readable interface type string (e.g. "TCPClientInterface").
792    pub interface_type: String,
793}
794
795/// A locally registered destination.
796#[derive(Debug, Clone)]
797pub struct LocalDestinationEntry {
798    pub hash: [u8; 16],
799    pub dest_type: u8,
800}
801
802/// Information about an active link.
803#[derive(Debug, Clone)]
804pub struct LinkInfoEntry {
805    pub link_id: [u8; 16],
806    pub state: String,
807    pub is_initiator: bool,
808    pub dest_hash: [u8; 16],
809    pub remote_identity: Option<[u8; 16]>,
810    pub rtt: Option<f64>,
811    pub expected_hops: u8,
812    pub tx_packets: u64,
813    pub rx_packets: u64,
814    pub tx_bytes: u64,
815    pub rx_bytes: u64,
816    pub channel_window: Option<u16>,
817    pub channel_outstanding: Option<usize>,
818    pub pending_channel_packets: usize,
819    pub channel_send_ok: u64,
820    pub channel_send_not_ready: u64,
821    pub channel_send_too_big: u64,
822    pub channel_send_other_error: u64,
823    pub channel_messages_received: u64,
824    pub channel_proofs_sent: u64,
825    pub channel_proofs_received: u64,
826}
827
828/// Information about an active resource transfer.
829#[derive(Debug, Clone)]
830pub struct ResourceInfoEntry {
831    pub link_id: [u8; 16],
832    pub direction: String,
833    pub total_parts: usize,
834    pub transferred_parts: usize,
835    pub complete: bool,
836}
837
838/// A single path table entry for query responses.
839#[derive(Debug, Clone)]
840pub struct PathTableEntry {
841    pub hash: [u8; 16],
842    pub timestamp: f64,
843    pub via: [u8; 16],
844    pub hops: u8,
845    pub expires: f64,
846    pub interface: InterfaceId,
847    pub interface_name: String,
848}
849
850/// A single rate table entry for query responses.
851#[derive(Debug, Clone)]
852pub struct RateTableEntry {
853    pub hash: [u8; 16],
854    pub last: f64,
855    pub rate_violations: u32,
856    pub blocked_until: f64,
857    pub timestamps: Vec<f64>,
858}
859
860/// A blackholed identity for query responses.
861#[derive(Debug, Clone)]
862pub struct BlackholeInfo {
863    pub identity_hash: [u8; 16],
864    pub created: f64,
865    pub expires: f64,
866    pub reason: Option<String>,
867}
868
869/// Next hop lookup result.
870#[derive(Debug, Clone)]
871pub struct NextHopResponse {
872    pub next_hop: [u8; 16],
873    pub hops: u8,
874    pub interface: InterfaceId,
875}
876
877impl<W: Send> fmt::Debug for Event<W> {
878    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
879        match self {
880            Event::Frame {
881                interface_id,
882                data,
883                rssi,
884                snr,
885            } => f
886                .debug_struct("Frame")
887                .field("interface_id", interface_id)
888                .field("data_len", &data.len())
889                .field("rssi", rssi)
890                .field("snr", snr)
891                .finish(),
892            Event::AnnounceVerified { key, .. } => f
893                .debug_struct("AnnounceVerified")
894                .field("destination_hash", &key.destination_hash)
895                .field("received_from", &key.received_from)
896                .finish(),
897            Event::AnnounceVerifyFailed { key, .. } => f
898                .debug_struct("AnnounceVerifyFailed")
899                .field("destination_hash", &key.destination_hash)
900                .field("received_from", &key.received_from)
901                .finish(),
902            Event::InterfaceUp(id, writer, info) => f
903                .debug_tuple("InterfaceUp")
904                .field(id)
905                .field(&writer.is_some())
906                .field(&info.is_some())
907                .finish(),
908            Event::DynamicInterfaceUp {
909                id, registration, ..
910            } => f
911                .debug_struct("DynamicInterfaceUp")
912                .field("id", id)
913                .field("type", &registration.interface_type)
914                .field("parent_id", &registration.parent_id)
915                .finish(),
916            Event::InterfaceTelemetry {
917                interface_id,
918                telemetry,
919            } => f
920                .debug_struct("InterfaceTelemetry")
921                .field("interface_id", interface_id)
922                .field("telemetry", telemetry)
923                .finish(),
924            Event::InterfaceDown(id) => f.debug_tuple("InterfaceDown").field(id).finish(),
925            Event::Tick => write!(f, "Tick"),
926            Event::BeginDrain { timeout } => f
927                .debug_struct("BeginDrain")
928                .field("timeout", timeout)
929                .finish(),
930            Event::Shutdown => write!(f, "Shutdown"),
931            Event::SendOutbound { raw, dest_type, .. } => f
932                .debug_struct("SendOutbound")
933                .field("raw_len", &raw.len())
934                .field("dest_type", dest_type)
935                .finish(),
936            Event::RegisterDestination {
937                dest_hash,
938                dest_type,
939            } => f
940                .debug_struct("RegisterDestination")
941                .field("dest_hash", dest_hash)
942                .field("dest_type", dest_type)
943                .finish(),
944            Event::StoreSharedAnnounce {
945                dest_hash,
946                name_hash,
947                app_data,
948                ..
949            } => f
950                .debug_struct("StoreSharedAnnounce")
951                .field("dest_hash", dest_hash)
952                .field("name_hash", name_hash)
953                .field("app_data_len", &app_data.as_ref().map(|d| d.len()))
954                .finish(),
955            Event::DeregisterDestination { dest_hash } => f
956                .debug_struct("DeregisterDestination")
957                .field("dest_hash", dest_hash)
958                .finish(),
959            Event::DeregisterLinkDestination { dest_hash } => f
960                .debug_struct("DeregisterLinkDestination")
961                .field("dest_hash", dest_hash)
962                .finish(),
963            Event::Query(req, _) => f.debug_tuple("Query").field(req).finish(),
964            Event::RegisterLinkDestination { dest_hash, .. } => f
965                .debug_struct("RegisterLinkDestination")
966                .field("dest_hash", dest_hash)
967                .finish(),
968            Event::RegisterRequestHandler { path, .. } => f
969                .debug_struct("RegisterRequestHandler")
970                .field("path", path)
971                .finish(),
972            Event::RegisterRequestHandlerResponse { path, .. } => f
973                .debug_struct("RegisterRequestHandlerResponse")
974                .field("path", path)
975                .finish(),
976            Event::RegisterDeferredRequestHandler { path, .. } => f
977                .debug_struct("RegisterDeferredRequestHandler")
978                .field("path", path)
979                .finish(),
980            Event::CreateLink { dest_hash, .. } => f
981                .debug_struct("CreateLink")
982                .field("dest_hash", dest_hash)
983                .finish(),
984            Event::SendRequest { link_id, path, .. } => f
985                .debug_struct("SendRequest")
986                .field("link_id", link_id)
987                .field("path", path)
988                .finish(),
989            Event::SendDeferredResponse {
990                link_id,
991                request_id,
992                data,
993            } => f
994                .debug_struct("SendDeferredResponse")
995                .field("link_id", link_id)
996                .field("request_id", request_id)
997                .field("data_len", &data.len())
998                .finish(),
999            Event::IdentifyOnLink { link_id, .. } => f
1000                .debug_struct("IdentifyOnLink")
1001                .field("link_id", link_id)
1002                .finish(),
1003            Event::TeardownLink { link_id } => f
1004                .debug_struct("TeardownLink")
1005                .field("link_id", link_id)
1006                .finish(),
1007            Event::SendResource { link_id, data, .. } => f
1008                .debug_struct("SendResource")
1009                .field("link_id", link_id)
1010                .field("data_len", &data.len())
1011                .finish(),
1012            Event::SendResourceStream {
1013                link_id,
1014                transfer_id,
1015                declared_length,
1016                ..
1017            } => f
1018                .debug_struct("SendResourceStream")
1019                .field("link_id", link_id)
1020                .field("transfer_id", transfer_id)
1021                .field("declared_length", declared_length)
1022                .finish(),
1023            Event::SetResourceStrategy { link_id, strategy } => f
1024                .debug_struct("SetResourceStrategy")
1025                .field("link_id", link_id)
1026                .field("strategy", strategy)
1027                .finish(),
1028            Event::SetResourceReceiveMode { link_id, mode } => f
1029                .debug_struct("SetResourceReceiveMode")
1030                .field("link_id", link_id)
1031                .field("mode", mode)
1032                .finish(),
1033            Event::AcceptResource {
1034                link_id, accept, ..
1035            } => f
1036                .debug_struct("AcceptResource")
1037                .field("link_id", link_id)
1038                .field("accept", accept)
1039                .finish(),
1040            Event::SendChannelMessage {
1041                link_id,
1042                msgtype,
1043                payload,
1044                ..
1045            } => f
1046                .debug_struct("SendChannelMessage")
1047                .field("link_id", link_id)
1048                .field("msgtype", msgtype)
1049                .field("payload_len", &payload.len())
1050                .finish(),
1051            Event::SendOnLink {
1052                link_id,
1053                data,
1054                context,
1055            } => f
1056                .debug_struct("SendOnLink")
1057                .field("link_id", link_id)
1058                .field("data_len", &data.len())
1059                .field("context", context)
1060                .finish(),
1061            Event::RequestPath { dest_hash } => f
1062                .debug_struct("RequestPath")
1063                .field("dest_hash", dest_hash)
1064                .finish(),
1065            Event::RegisterProofStrategy {
1066                dest_hash,
1067                strategy,
1068                ..
1069            } => f
1070                .debug_struct("RegisterProofStrategy")
1071                .field("dest_hash", dest_hash)
1072                .field("strategy", strategy)
1073                .finish(),
1074            Event::ProposeDirectConnect { link_id } => f
1075                .debug_struct("ProposeDirectConnect")
1076                .field("link_id", link_id)
1077                .finish(),
1078            Event::SetDirectConnectPolicy { .. } => {
1079                write!(f, "SetDirectConnectPolicy")
1080            }
1081            Event::HolePunchProbeResult {
1082                link_id,
1083                session_id,
1084                observed_addr,
1085                probe_server,
1086                ..
1087            } => f
1088                .debug_struct("HolePunchProbeResult")
1089                .field("link_id", link_id)
1090                .field("session_id", session_id)
1091                .field("observed_addr", observed_addr)
1092                .field("probe_server", probe_server)
1093                .finish(),
1094            Event::HolePunchProbeFailed {
1095                link_id,
1096                session_id,
1097            } => f
1098                .debug_struct("HolePunchProbeFailed")
1099                .field("link_id", link_id)
1100                .field("session_id", session_id)
1101                .finish(),
1102            Event::InterfaceConfigChanged(id) => {
1103                f.debug_tuple("InterfaceConfigChanged").field(id).finish()
1104            }
1105            Event::BackbonePeerConnected {
1106                server_interface_id,
1107                peer_interface_id,
1108                peer_ip,
1109                peer_port,
1110            } => f
1111                .debug_struct("BackbonePeerConnected")
1112                .field("server_interface_id", server_interface_id)
1113                .field("peer_interface_id", peer_interface_id)
1114                .field("peer_ip", peer_ip)
1115                .field("peer_port", peer_port)
1116                .finish(),
1117            Event::BackbonePeerDisconnected {
1118                server_interface_id,
1119                peer_interface_id,
1120                peer_ip,
1121                peer_port,
1122                connected_for,
1123                had_received_data,
1124            } => f
1125                .debug_struct("BackbonePeerDisconnected")
1126                .field("server_interface_id", server_interface_id)
1127                .field("peer_interface_id", peer_interface_id)
1128                .field("peer_ip", peer_ip)
1129                .field("peer_port", peer_port)
1130                .field("connected_for", connected_for)
1131                .field("had_received_data", had_received_data)
1132                .finish(),
1133            Event::BackbonePeerIdleTimeout {
1134                server_interface_id,
1135                peer_interface_id,
1136                peer_ip,
1137                peer_port,
1138                connected_for,
1139            } => f
1140                .debug_struct("BackbonePeerIdleTimeout")
1141                .field("server_interface_id", server_interface_id)
1142                .field("peer_interface_id", peer_interface_id)
1143                .field("peer_ip", peer_ip)
1144                .field("peer_port", peer_port)
1145                .field("connected_for", connected_for)
1146                .finish(),
1147            Event::BackbonePeerWriteStall {
1148                server_interface_id,
1149                peer_interface_id,
1150                peer_ip,
1151                peer_port,
1152                connected_for,
1153            } => f
1154                .debug_struct("BackbonePeerWriteStall")
1155                .field("server_interface_id", server_interface_id)
1156                .field("peer_interface_id", peer_interface_id)
1157                .field("peer_ip", peer_ip)
1158                .field("peer_port", peer_port)
1159                .field("connected_for", connected_for)
1160                .finish(),
1161            Event::BackbonePeerPenalty {
1162                server_interface_id,
1163                peer_ip,
1164                penalty_level,
1165                blacklist_for,
1166            } => f
1167                .debug_struct("BackbonePeerPenalty")
1168                .field("server_interface_id", server_interface_id)
1169                .field("peer_ip", peer_ip)
1170                .field("penalty_level", penalty_level)
1171                .field("blacklist_for", blacklist_for)
1172                .finish(),
1173            Event::LoadHook {
1174                name,
1175                attach_point,
1176                priority,
1177                ..
1178            } => f
1179                .debug_struct("LoadHook")
1180                .field("name", name)
1181                .field("attach_point", attach_point)
1182                .field("priority", priority)
1183                .finish(),
1184            Event::LoadHookFile {
1185                name,
1186                path,
1187                hook_type,
1188                attach_point,
1189                priority,
1190                ..
1191            } => f
1192                .debug_struct("LoadHookFile")
1193                .field("name", name)
1194                .field("path", path)
1195                .field("hook_type", hook_type)
1196                .field("attach_point", attach_point)
1197                .field("priority", priority)
1198                .finish(),
1199            Event::LoadBuiltinHook {
1200                name,
1201                builtin_id,
1202                attach_point,
1203                priority,
1204                ..
1205            } => f
1206                .debug_struct("LoadBuiltinHook")
1207                .field("name", name)
1208                .field("builtin_id", builtin_id)
1209                .field("attach_point", attach_point)
1210                .field("priority", priority)
1211                .finish(),
1212            Event::UnloadHook {
1213                name, attach_point, ..
1214            } => f
1215                .debug_struct("UnloadHook")
1216                .field("name", name)
1217                .field("attach_point", attach_point)
1218                .finish(),
1219            Event::ReloadHook {
1220                name, attach_point, ..
1221            } => f
1222                .debug_struct("ReloadHook")
1223                .field("name", name)
1224                .field("attach_point", attach_point)
1225                .finish(),
1226            Event::ReloadHookFile {
1227                name,
1228                attach_point,
1229                path,
1230                hook_type,
1231                ..
1232            } => f
1233                .debug_struct("ReloadHookFile")
1234                .field("name", name)
1235                .field("attach_point", attach_point)
1236                .field("path", path)
1237                .field("hook_type", hook_type)
1238                .finish(),
1239            Event::ReloadBuiltinHook {
1240                name,
1241                attach_point,
1242                builtin_id,
1243                ..
1244            } => f
1245                .debug_struct("ReloadBuiltinHook")
1246                .field("name", name)
1247                .field("attach_point", attach_point)
1248                .field("builtin_id", builtin_id)
1249                .finish(),
1250            Event::SetHookEnabled {
1251                name,
1252                attach_point,
1253                enabled,
1254                ..
1255            } => f
1256                .debug_struct("SetHookEnabled")
1257                .field("name", name)
1258                .field("attach_point", attach_point)
1259                .field("enabled", enabled)
1260                .finish(),
1261            Event::SetHookPriority {
1262                name,
1263                attach_point,
1264                priority,
1265                ..
1266            } => f
1267                .debug_struct("SetHookPriority")
1268                .field("name", name)
1269                .field("attach_point", attach_point)
1270                .field("priority", priority)
1271                .finish(),
1272            Event::ListHooks { .. } => write!(f, "ListHooks"),
1273        }
1274    }
1275}