fips_core/node/
io_impl.rs1use super::*;
2
3impl Node {
4 pub fn tun_tx(&self) -> Option<&TunTx> {
8 self.tun_tx.as_ref()
9 }
10
11 pub fn attach_external_packet_io(
18 &mut self,
19 capacity: usize,
20 ) -> Result<ExternalPacketIo, NodeError> {
21 if self.state != NodeState::Created {
22 return Err(NodeError::Config(ConfigError::Validation(
23 "external packet I/O must be attached before node start".to_string(),
24 )));
25 }
26 if self.config.tun.enabled {
27 return Err(NodeError::Config(ConfigError::Validation(
28 "external packet I/O requires tun.enabled=false".to_string(),
29 )));
30 }
31
32 let capacity = capacity.max(1);
33 let (outbound_tx, outbound_rx) = crate::upper::tun::tun_outbound_channel(capacity);
34 let (inbound_tx, inbound_rx) = tokio::sync::mpsc::channel(capacity);
35 self.tun_outbound_rx = Some(outbound_rx);
36 self.external_packet_tx = Some(inbound_tx);
37
38 Ok(ExternalPacketIo {
39 outbound_tx,
40 inbound_rx,
41 })
42 }
43
44 pub(crate) fn attach_endpoint_data_io(
49 &mut self,
50 capacity: usize,
51 ) -> Result<EndpointDataIo, NodeError> {
52 self.attach_endpoint_data_io_inner(capacity, None)
53 }
54
55 pub(crate) fn attach_endpoint_data_io_with_direct_sink(
56 &mut self,
57 capacity: usize,
58 direct_sink: EndpointDirectSink,
59 ) -> Result<EndpointDataIo, NodeError> {
60 self.attach_endpoint_data_io_inner(capacity, Some(direct_sink))
61 }
62
63 fn attach_endpoint_data_io_inner(
64 &mut self,
65 capacity: usize,
66 direct_sink: Option<EndpointDirectSink>,
67 ) -> Result<EndpointDataIo, NodeError> {
68 if self.state != NodeState::Created {
69 return Err(NodeError::Config(ConfigError::Validation(
70 "endpoint data I/O must be attached before node start".to_string(),
71 )));
72 }
73
74 let command_capacity = capacity.max(1);
75 let (control_tx, control_rx) = tokio::sync::mpsc::channel(command_capacity);
76 let (data_batch_tx, data_rx) = endpoint_data_batch_channel(command_capacity);
77 let (event_tx, event_rx) =
81 EndpointEventSender::channel_with_direct_sink(capacity, direct_sink);
82 let (service_event_tx, service_event_rx) = EndpointServiceEventSender::channel(capacity);
83 self.endpoint_control_rx = Some(control_rx);
84 self.endpoint_data_rx = Some(data_rx);
85 self.endpoint_events.attach(event_tx.clone());
86
87 Ok(EndpointDataIo {
88 control_tx,
89 data_batch_tx,
90 event_rx,
91 event_tx,
92 service_event_rx,
93 service_event_tx,
94 })
95 }
96
97 pub(crate) fn pubkey_for_node_addr(&self, addr: &NodeAddr) -> Option<secp256k1::PublicKey> {
98 self.identity_cache.pubkey_for_node_addr(addr)
99 }
100
101 pub(crate) fn npub_for_node_addr(&self, addr: &NodeAddr) -> Option<String> {
102 self.identity_cache.npub_for_node_addr(addr)
103 }
104
105 pub(in crate::node) fn deliver_external_ipv6_packet(
106 &self,
107 src_addr: &NodeAddr,
108 packet: Vec<u8>,
109 ) {
110 let Some(external_packet_tx) = &self.external_packet_tx else {
111 return;
112 };
113 if packet.len() < 40 {
114 return;
115 }
116 let Ok(destination) = FipsAddress::from_slice(&packet[24..40]) else {
117 return;
118 };
119 let delivered = NodeDeliveredPacket {
120 source_node_addr: *src_addr,
121 source_npub: self.npub_for_node_addr(src_addr),
122 destination,
123 packet,
124 };
125 if let Err(error) = external_packet_tx.try_send(delivered) {
126 debug!(error = %error, "Failed to deliver packet to external app sink");
127 }
128 }
129
130 pub(in crate::node) fn note_local_send_outcome(
136 &mut self,
137 node_addr: &NodeAddr,
138 result: &Result<usize, TransportError>,
139 ) {
140 self.local_send_failures
141 .note_send_outcome(node_addr, result, std::time::Instant::now());
142 }
143
144 pub(in crate::node) fn note_candidate_send_outcome(
150 &mut self,
151 node_addr: &NodeAddr,
152 candidate_addr: &TransportAddr,
153 result: &Result<usize, TransportError>,
154 ) {
155 if result.is_ok() {
156 self.note_local_send_outcome(node_addr, result);
157 return;
158 }
159
160 let candidate_is_active_path = self
161 .peers
162 .get(node_addr)
163 .is_none_or(|peer| !peer.can_send() || peer.current_addr() == Some(candidate_addr));
164 if candidate_is_active_path {
165 self.note_local_send_outcome(node_addr, result);
166 }
167 }
168
169 pub(in crate::node) fn local_send_failure_dead_timeout_for_peer(
175 &self,
176 node_addr: &NodeAddr,
177 now: std::time::Instant,
178 dead_timeout: std::time::Duration,
179 fast_dead_timeout: std::time::Duration,
180 ) -> std::time::Duration {
181 self.local_send_failures.dead_timeout_for_peer(
182 node_addr,
183 now,
184 dead_timeout,
185 fast_dead_timeout,
186 )
187 }
188
189 pub(in crate::node) fn purge_expired_local_send_failures(&mut self, now: std::time::Instant) {
190 self.local_send_failures.purge_expired(now);
191 }
192
193 pub(in crate::node) fn mark_rx_loop_maintenance_timeout(&mut self) {
194 self.last_rx_loop_maintenance_timeout_at = Some(std::time::Instant::now());
195 }
196
197 pub(in crate::node) fn rx_loop_maintenance_timed_out_recently(&self) -> bool {
198 let Some(t) = self.last_rx_loop_maintenance_timeout_at else {
199 return false;
200 };
201 let grace = std::time::Duration::from_secs(self.config.node.link_dead_timeout_secs.max(1));
202 std::time::Instant::now().duration_since(t) <= grace
203 }
204}