Skip to main content

rns_net/
event.rs

1//! Event types for the driver loop.
2
3use std::fmt;
4use std::sync::mpsc;
5
6use rns_core::transport::types::{InterfaceId, InterfaceInfo};
7
8use crate::interface::Writer;
9
10/// Events sent to the driver thread.
11pub enum Event {
12    /// A decoded frame arrived from an interface.
13    Frame { interface_id: InterfaceId, data: Vec<u8> },
14    /// An interface came online after (re)connecting.
15    /// Carries a new writer if the connection was re-established.
16    /// Carries InterfaceInfo if this is a new dynamic interface (e.g. TCP server client).
17    InterfaceUp(InterfaceId, Option<Box<dyn Writer>>, Option<InterfaceInfo>),
18    /// An interface went offline (socket closed, error).
19    InterfaceDown(InterfaceId),
20    /// Periodic maintenance tick (1s interval).
21    Tick,
22    /// Shut down the driver loop.
23    Shutdown,
24    /// Send an outbound packet.
25    SendOutbound {
26        raw: Vec<u8>,
27        dest_type: u8,
28        attached_interface: Option<InterfaceId>,
29    },
30    /// Register a local destination.
31    RegisterDestination {
32        dest_hash: [u8; 16],
33        dest_type: u8,
34    },
35    /// Deregister a local destination.
36    DeregisterDestination {
37        dest_hash: [u8; 16],
38    },
39    /// Deregister a link destination (stop accepting incoming links).
40    DeregisterLinkDestination {
41        dest_hash: [u8; 16],
42    },
43    /// Query driver state. Response is sent via the provided channel.
44    Query(QueryRequest, mpsc::Sender<QueryResponse>),
45    /// Register a link destination (accepts incoming LINKREQUEST).
46    RegisterLinkDestination {
47        dest_hash: [u8; 16],
48        sig_prv_bytes: [u8; 32],
49        sig_pub_bytes: [u8; 32],
50        resource_strategy: u8,
51    },
52    /// Register a request handler for a path on established links.
53    RegisterRequestHandler {
54        path: String,
55        allowed_list: Option<Vec<[u8; 16]>>,
56        handler: Box<dyn Fn([u8; 16], &str, &[u8], Option<&([u8; 16], [u8; 64])>) -> Option<Vec<u8>> + Send>,
57    },
58    /// Create an outbound link. Response sends (link_id) back.
59    CreateLink {
60        dest_hash: [u8; 16],
61        dest_sig_pub_bytes: [u8; 32],
62        response_tx: mpsc::Sender<[u8; 16]>,
63    },
64    /// Send a request on an established link.
65    SendRequest {
66        link_id: [u8; 16],
67        path: String,
68        data: Vec<u8>,
69    },
70    /// Identify on a link (send identity to remote peer).
71    IdentifyOnLink {
72        link_id: [u8; 16],
73        identity_prv_key: [u8; 64],
74    },
75    /// Tear down a link.
76    TeardownLink {
77        link_id: [u8; 16],
78    },
79    /// Send a resource on a link.
80    SendResource {
81        link_id: [u8; 16],
82        data: Vec<u8>,
83        metadata: Option<Vec<u8>>,
84    },
85    /// Set the resource acceptance strategy for a link.
86    SetResourceStrategy {
87        link_id: [u8; 16],
88        strategy: u8,
89    },
90    /// Accept or reject a pending resource (for AcceptApp strategy).
91    AcceptResource {
92        link_id: [u8; 16],
93        resource_hash: Vec<u8>,
94        accept: bool,
95    },
96    /// Send a channel message on a link.
97    SendChannelMessage {
98        link_id: [u8; 16],
99        msgtype: u16,
100        payload: Vec<u8>,
101    },
102    /// Send generic data on a link with a given context.
103    SendOnLink {
104        link_id: [u8; 16],
105        data: Vec<u8>,
106        context: u8,
107    },
108    /// Request a path to a destination from the network.
109    RequestPath {
110        dest_hash: [u8; 16],
111    },
112    /// Register a proof strategy for a destination.
113    RegisterProofStrategy {
114        dest_hash: [u8; 16],
115        strategy: rns_core::types::ProofStrategy,
116        /// Full identity private key (64 bytes) for signing proofs.
117        signing_key: Option<[u8; 64]>,
118    },
119    /// Propose a direct connection to a peer via hole punching.
120    ProposeDirectConnect {
121        link_id: [u8; 16],
122    },
123    /// Set the direct-connect policy.
124    SetDirectConnectPolicy {
125        policy: crate::holepunch::orchestrator::HolePunchPolicy,
126    },
127    /// (Internal) Probe result arrived from a worker thread.
128    HolePunchProbeResult {
129        link_id: [u8; 16],
130        session_id: [u8; 16],
131        observed_addr: std::net::SocketAddr,
132        socket: std::net::UdpSocket,
133    },
134    /// (Internal) Probe failed.
135    HolePunchProbeFailed {
136        link_id: [u8; 16],
137        session_id: [u8; 16],
138    },
139    /// An interface's configuration changed (placeholder for future use).
140    InterfaceConfigChanged(InterfaceId),
141    /// Load a WASM hook at runtime.
142    LoadHook {
143        name: String,
144        wasm_bytes: Vec<u8>,
145        attach_point: String,
146        priority: i32,
147        response_tx: mpsc::Sender<Result<(), String>>,
148    },
149    /// Unload a WASM hook at runtime.
150    UnloadHook {
151        name: String,
152        attach_point: String,
153        response_tx: mpsc::Sender<Result<(), String>>,
154    },
155    /// Reload a WASM hook at runtime (detach + recompile + reattach with same priority).
156    ReloadHook {
157        name: String,
158        attach_point: String,
159        wasm_bytes: Vec<u8>,
160        response_tx: mpsc::Sender<Result<(), String>>,
161    },
162    /// List all loaded hooks.
163    ListHooks {
164        response_tx: mpsc::Sender<Vec<HookInfo>>,
165    },
166}
167
168/// Information about a loaded hook program.
169#[derive(Debug, Clone)]
170pub struct HookInfo {
171    pub name: String,
172    pub attach_point: String,
173    pub priority: i32,
174    pub enabled: bool,
175    pub consecutive_traps: u32,
176}
177
178/// Queries that can be sent to the driver.
179#[derive(Debug)]
180pub enum QueryRequest {
181    /// Get interface statistics and transport info.
182    InterfaceStats,
183    /// Get path table entries, optionally filtered by max hops.
184    PathTable { max_hops: Option<u8> },
185    /// Get rate table entries.
186    RateTable,
187    /// Look up the next hop for a destination.
188    NextHop { dest_hash: [u8; 16] },
189    /// Look up the next hop interface name for a destination.
190    NextHopIfName { dest_hash: [u8; 16] },
191    /// Get link table entry count.
192    LinkCount,
193    /// Drop a specific path.
194    DropPath { dest_hash: [u8; 16] },
195    /// Drop all paths that route via a given transport hash.
196    DropAllVia { transport_hash: [u8; 16] },
197    /// Drop all announce queues.
198    DropAnnounceQueues,
199    /// Get the transport identity hash.
200    TransportIdentity,
201    /// Get all blackholed identities.
202    GetBlackholed,
203    /// Add an identity to the blackhole list.
204    BlackholeIdentity {
205        identity_hash: [u8; 16],
206        duration_hours: Option<f64>,
207        reason: Option<String>,
208    },
209    /// Remove an identity from the blackhole list.
210    UnblackholeIdentity {
211        identity_hash: [u8; 16],
212    },
213    /// Check if a path exists to a destination.
214    HasPath { dest_hash: [u8; 16] },
215    /// Get hop count to a destination.
216    HopsTo { dest_hash: [u8; 16] },
217    /// Recall identity info for a destination.
218    RecallIdentity { dest_hash: [u8; 16] },
219    /// Get locally registered destinations.
220    LocalDestinations,
221    /// Get active links.
222    Links,
223    /// Get active resource transfers.
224    Resources,
225    /// Inject a path entry into the path table.
226    InjectPath {
227        dest_hash: [u8; 16],
228        next_hop: [u8; 16],
229        hops: u8,
230        expires: f64,
231        interface_name: String,
232        packet_hash: [u8; 32],
233    },
234    /// Inject an identity into the known destinations cache.
235    InjectIdentity {
236        dest_hash: [u8; 16],
237        identity_hash: [u8; 16],
238        public_key: [u8; 64],
239        app_data: Option<Vec<u8>>,
240        hops: u8,
241        received_at: f64,
242    },
243    /// Get discovered interfaces.
244    DiscoveredInterfaces {
245        only_available: bool,
246        only_transport: bool,
247    },
248    /// Send a probe packet to a destination and return (packet_hash, hops).
249    SendProbe {
250        dest_hash: [u8; 16],
251        payload_size: usize,
252    },
253    /// Check if a proof was received for a probe packet.
254    CheckProof {
255        packet_hash: [u8; 32],
256    },
257}
258
259/// Responses to queries.
260#[derive(Debug)]
261pub enum QueryResponse {
262    InterfaceStats(InterfaceStatsResponse),
263    PathTable(Vec<PathTableEntry>),
264    RateTable(Vec<RateTableEntry>),
265    NextHop(Option<NextHopResponse>),
266    NextHopIfName(Option<String>),
267    LinkCount(usize),
268    DropPath(bool),
269    DropAllVia(usize),
270    DropAnnounceQueues,
271    TransportIdentity(Option<[u8; 16]>),
272    Blackholed(Vec<BlackholeInfo>),
273    BlackholeResult(bool),
274    UnblackholeResult(bool),
275    HasPath(bool),
276    HopsTo(Option<u8>),
277    RecallIdentity(Option<crate::destination::AnnouncedIdentity>),
278    LocalDestinations(Vec<LocalDestinationEntry>),
279    Links(Vec<LinkInfoEntry>),
280    Resources(Vec<ResourceInfoEntry>),
281    InjectPath(bool),
282    InjectIdentity(bool),
283    /// List of discovered interfaces.
284    DiscoveredInterfaces(Vec<crate::discovery::DiscoveredInterface>),
285    /// Probe sent: (packet_hash, hops) or None if identity unknown.
286    SendProbe(Option<([u8; 32], u8)>),
287    /// Proof check: RTT if received, None if still pending.
288    CheckProof(Option<f64>),
289}
290
291/// Interface statistics response.
292#[derive(Debug, Clone)]
293pub struct InterfaceStatsResponse {
294    pub interfaces: Vec<SingleInterfaceStat>,
295    pub transport_id: Option<[u8; 16]>,
296    pub transport_enabled: bool,
297    pub transport_uptime: f64,
298    /// Total received bytes across all interfaces.
299    pub total_rxb: u64,
300    /// Total transmitted bytes across all interfaces.
301    pub total_txb: u64,
302    /// Probe responder destination hash (if enabled).
303    pub probe_responder: Option<[u8; 16]>,
304}
305
306/// Statistics for a single interface.
307#[derive(Debug, Clone)]
308pub struct SingleInterfaceStat {
309    pub name: String,
310    pub status: bool,
311    pub mode: u8,
312    pub rxb: u64,
313    pub txb: u64,
314    pub rx_packets: u64,
315    pub tx_packets: u64,
316    pub bitrate: Option<u64>,
317    pub ifac_size: Option<usize>,
318    pub started: f64,
319    /// Incoming announce frequency (per second).
320    pub ia_freq: f64,
321    /// Outgoing announce frequency (per second).
322    pub oa_freq: f64,
323    /// Human-readable interface type string (e.g. "TCPClientInterface").
324    pub interface_type: String,
325}
326
327/// A locally registered destination.
328#[derive(Debug, Clone)]
329pub struct LocalDestinationEntry {
330    pub hash: [u8; 16],
331    pub dest_type: u8,
332}
333
334/// Information about an active link.
335#[derive(Debug, Clone)]
336pub struct LinkInfoEntry {
337    pub link_id: [u8; 16],
338    pub state: String,
339    pub is_initiator: bool,
340    pub dest_hash: [u8; 16],
341    pub remote_identity: Option<[u8; 16]>,
342    pub rtt: Option<f64>,
343}
344
345/// Information about an active resource transfer.
346#[derive(Debug, Clone)]
347pub struct ResourceInfoEntry {
348    pub link_id: [u8; 16],
349    pub direction: String,
350    pub total_parts: usize,
351    pub transferred_parts: usize,
352    pub complete: bool,
353}
354
355/// A single path table entry for query responses.
356#[derive(Debug, Clone)]
357pub struct PathTableEntry {
358    pub hash: [u8; 16],
359    pub timestamp: f64,
360    pub via: [u8; 16],
361    pub hops: u8,
362    pub expires: f64,
363    pub interface: InterfaceId,
364    pub interface_name: String,
365}
366
367/// A single rate table entry for query responses.
368#[derive(Debug, Clone)]
369pub struct RateTableEntry {
370    pub hash: [u8; 16],
371    pub last: f64,
372    pub rate_violations: u32,
373    pub blocked_until: f64,
374    pub timestamps: Vec<f64>,
375}
376
377/// A blackholed identity for query responses.
378#[derive(Debug, Clone)]
379pub struct BlackholeInfo {
380    pub identity_hash: [u8; 16],
381    pub created: f64,
382    pub expires: f64,
383    pub reason: Option<String>,
384}
385
386/// Next hop lookup result.
387#[derive(Debug, Clone)]
388pub struct NextHopResponse {
389    pub next_hop: [u8; 16],
390    pub hops: u8,
391    pub interface: InterfaceId,
392}
393
394impl fmt::Debug for Event {
395    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
396        match self {
397            Event::Frame { interface_id, data } => {
398                f.debug_struct("Frame")
399                    .field("interface_id", interface_id)
400                    .field("data_len", &data.len())
401                    .finish()
402            }
403            Event::InterfaceUp(id, writer, info) => {
404                f.debug_tuple("InterfaceUp")
405                    .field(id)
406                    .field(&writer.is_some())
407                    .field(&info.is_some())
408                    .finish()
409            }
410            Event::InterfaceDown(id) => f.debug_tuple("InterfaceDown").field(id).finish(),
411            Event::Tick => write!(f, "Tick"),
412            Event::Shutdown => write!(f, "Shutdown"),
413            Event::SendOutbound { raw, dest_type, .. } => {
414                f.debug_struct("SendOutbound")
415                    .field("raw_len", &raw.len())
416                    .field("dest_type", dest_type)
417                    .finish()
418            }
419            Event::RegisterDestination { dest_hash, dest_type } => {
420                f.debug_struct("RegisterDestination")
421                    .field("dest_hash", dest_hash)
422                    .field("dest_type", dest_type)
423                    .finish()
424            }
425            Event::DeregisterDestination { dest_hash } => {
426                f.debug_struct("DeregisterDestination")
427                    .field("dest_hash", dest_hash)
428                    .finish()
429            }
430            Event::DeregisterLinkDestination { dest_hash } => {
431                f.debug_struct("DeregisterLinkDestination")
432                    .field("dest_hash", dest_hash)
433                    .finish()
434            }
435            Event::Query(req, _) => {
436                f.debug_tuple("Query")
437                    .field(req)
438                    .finish()
439            }
440            Event::RegisterLinkDestination { dest_hash, .. } => {
441                f.debug_struct("RegisterLinkDestination")
442                    .field("dest_hash", dest_hash)
443                    .finish()
444            }
445            Event::RegisterRequestHandler { path, .. } => {
446                f.debug_struct("RegisterRequestHandler")
447                    .field("path", path)
448                    .finish()
449            }
450            Event::CreateLink { dest_hash, .. } => {
451                f.debug_struct("CreateLink")
452                    .field("dest_hash", dest_hash)
453                    .finish()
454            }
455            Event::SendRequest { link_id, path, .. } => {
456                f.debug_struct("SendRequest")
457                    .field("link_id", link_id)
458                    .field("path", path)
459                    .finish()
460            }
461            Event::IdentifyOnLink { link_id, .. } => {
462                f.debug_struct("IdentifyOnLink")
463                    .field("link_id", link_id)
464                    .finish()
465            }
466            Event::TeardownLink { link_id } => {
467                f.debug_struct("TeardownLink")
468                    .field("link_id", link_id)
469                    .finish()
470            }
471            Event::SendResource { link_id, data, .. } => {
472                f.debug_struct("SendResource")
473                    .field("link_id", link_id)
474                    .field("data_len", &data.len())
475                    .finish()
476            }
477            Event::SetResourceStrategy { link_id, strategy } => {
478                f.debug_struct("SetResourceStrategy")
479                    .field("link_id", link_id)
480                    .field("strategy", strategy)
481                    .finish()
482            }
483            Event::AcceptResource { link_id, accept, .. } => {
484                f.debug_struct("AcceptResource")
485                    .field("link_id", link_id)
486                    .field("accept", accept)
487                    .finish()
488            }
489            Event::SendChannelMessage { link_id, msgtype, payload } => {
490                f.debug_struct("SendChannelMessage")
491                    .field("link_id", link_id)
492                    .field("msgtype", msgtype)
493                    .field("payload_len", &payload.len())
494                    .finish()
495            }
496            Event::SendOnLink { link_id, data, context } => {
497                f.debug_struct("SendOnLink")
498                    .field("link_id", link_id)
499                    .field("data_len", &data.len())
500                    .field("context", context)
501                    .finish()
502            }
503            Event::RequestPath { dest_hash } => {
504                f.debug_struct("RequestPath")
505                    .field("dest_hash", dest_hash)
506                    .finish()
507            }
508            Event::RegisterProofStrategy { dest_hash, strategy, .. } => {
509                f.debug_struct("RegisterProofStrategy")
510                    .field("dest_hash", dest_hash)
511                    .field("strategy", strategy)
512                    .finish()
513            }
514            Event::ProposeDirectConnect { link_id } => {
515                f.debug_struct("ProposeDirectConnect")
516                    .field("link_id", link_id)
517                    .finish()
518            }
519            Event::SetDirectConnectPolicy { .. } => {
520                write!(f, "SetDirectConnectPolicy")
521            }
522            Event::HolePunchProbeResult { link_id, session_id, observed_addr, .. } => {
523                f.debug_struct("HolePunchProbeResult")
524                    .field("link_id", link_id)
525                    .field("session_id", session_id)
526                    .field("observed_addr", observed_addr)
527                    .finish()
528            }
529            Event::HolePunchProbeFailed { link_id, session_id } => {
530                f.debug_struct("HolePunchProbeFailed")
531                    .field("link_id", link_id)
532                    .field("session_id", session_id)
533                    .finish()
534            }
535            Event::InterfaceConfigChanged(id) => {
536                f.debug_tuple("InterfaceConfigChanged").field(id).finish()
537            }
538            Event::LoadHook { name, attach_point, priority, .. } => {
539                f.debug_struct("LoadHook")
540                    .field("name", name)
541                    .field("attach_point", attach_point)
542                    .field("priority", priority)
543                    .finish()
544            }
545            Event::UnloadHook { name, attach_point, .. } => {
546                f.debug_struct("UnloadHook")
547                    .field("name", name)
548                    .field("attach_point", attach_point)
549                    .finish()
550            }
551            Event::ReloadHook { name, attach_point, .. } => {
552                f.debug_struct("ReloadHook")
553                    .field("name", name)
554                    .field("attach_point", attach_point)
555                    .finish()
556            }
557            Event::ListHooks { .. } => write!(f, "ListHooks"),
558        }
559    }
560}
561
562pub type EventSender = mpsc::Sender<Event>;
563pub type EventReceiver = mpsc::Receiver<Event>;
564
565pub fn channel() -> (EventSender, EventReceiver) {
566    mpsc::channel()
567}