1use super::*;
2use crate::transport::PacketBuffer;
3use std::sync::Arc;
4
5pub const FIPS_ENDPOINT_DIRECT_PACKET_RUN_MAX_PACKETS: usize = 128;
7
8pub const FIPS_ENDPOINT_DIRECT_PACKET_QUEUE_MAX_PACKETS: usize = 4096;
10
11#[derive(Debug, Clone, PartialEq, Eq)]
13pub(crate) struct FipsEndpointDirectPacketRunMeta {
14 source_peer: PeerIdentity,
15 previous_hop_addr: NodeAddr,
16 received_k_bit: bool,
17 direct_path: bool,
18 enqueued_at_ms: u64,
19}
20
21impl FipsEndpointDirectPacketRunMeta {
22 pub(crate) fn new(
23 source_peer: PeerIdentity,
24 previous_hop_addr: NodeAddr,
25 received_k_bit: bool,
26 direct_path: bool,
27 enqueued_at_ms: u64,
28 ) -> Self {
29 Self {
30 source_peer,
31 previous_hop_addr,
32 received_k_bit,
33 direct_path,
34 enqueued_at_ms,
35 }
36 }
37}
38
39#[derive(Debug, Clone, PartialEq, Eq)]
44pub struct FipsEndpointDirectPacketRun {
45 meta: FipsEndpointDirectPacketRunMeta,
46 packets: Vec<PacketBuffer>,
47 packet_bytes: usize,
48}
49
50pub struct FipsEndpointDirectPacketSlices<'a> {
52 packets: std::slice::Iter<'a, PacketBuffer>,
53}
54
55impl FipsEndpointDirectPacketRun {
56 pub(crate) fn from_packet(meta: FipsEndpointDirectPacketRunMeta, packet: PacketBuffer) -> Self {
57 let packet_bytes = packet.len();
58 let mut packets = Vec::with_capacity(FIPS_ENDPOINT_DIRECT_PACKET_RUN_MAX_PACKETS);
59 packets.push(packet);
60 Self {
61 meta,
62 packets,
63 packet_bytes,
64 }
65 }
66
67 pub fn source_peer(&self) -> &PeerIdentity {
69 &self.meta.source_peer
70 }
71
72 pub fn enqueued_at_ms(&self) -> u64 {
74 self.meta.enqueued_at_ms
75 }
76
77 pub fn len(&self) -> usize {
79 self.packets.len()
80 }
81
82 pub fn is_empty(&self) -> bool {
84 self.len() == 0
85 }
86
87 pub fn packet_bytes(&self) -> usize {
89 self.packet_bytes
90 }
91
92 pub fn packet_slice(&self, index: usize) -> Option<&[u8]> {
94 self.packets.get(index).map(PacketBuffer::as_slice)
95 }
96
97 pub(crate) fn push_packet(&mut self, packet: PacketBuffer) {
98 self.packet_bytes = self.packet_bytes.saturating_add(packet.len());
99 self.packets.push(packet);
100 }
101
102 pub(crate) fn try_append(&mut self, other: &mut Self) -> bool {
103 if self.len().saturating_add(other.len()) > FIPS_ENDPOINT_DIRECT_PACKET_RUN_MAX_PACKETS
104 || self.meta.source_peer != other.meta.source_peer
105 || self.meta.previous_hop_addr != other.meta.previous_hop_addr
106 || self.meta.received_k_bit != other.meta.received_k_bit
107 || self.meta.direct_path != other.meta.direct_path
108 {
109 return false;
110 }
111 self.packet_bytes = self.packet_bytes.saturating_add(other.packet_bytes);
112 other.packet_bytes = 0;
113 self.packets.append(&mut other.packets);
114 true
115 }
116
117 pub fn packet_slices(&self) -> FipsEndpointDirectPacketSlices<'_> {
119 FipsEndpointDirectPacketSlices {
120 packets: self.packets.iter(),
121 }
122 }
123
124 pub fn retain_packets<F>(&mut self, mut keep: F)
130 where
131 F: FnMut(usize, &[u8]) -> bool,
132 {
133 let mut index = 0usize;
134 let mut packet_bytes = 0usize;
135 self.packets.retain(|packet| {
136 let retained = keep(index, packet.as_slice());
137 index = index.saturating_add(1);
138 if retained {
139 packet_bytes = packet_bytes.saturating_add(packet.len());
140 }
141 retained
142 });
143 self.packet_bytes = packet_bytes;
144 }
145
146 pub fn split_off_packets(&mut self, at: usize) -> Option<Self> {
151 if at >= self.packets.len() {
152 return None;
153 }
154 let packets = self.packets.split_off(at);
155 let packet_bytes = packets.iter().map(PacketBuffer::len).sum();
156 self.packet_bytes = self.packet_bytes.saturating_sub(packet_bytes);
157 Some(Self {
158 meta: self.meta.clone(),
159 packets,
160 packet_bytes,
161 })
162 }
163}
164
165impl<'a> Iterator for FipsEndpointDirectPacketSlices<'a> {
166 type Item = &'a [u8];
167
168 fn next(&mut self) -> Option<Self::Item> {
169 self.packets.next().map(PacketBuffer::as_slice)
170 }
171
172 fn size_hint(&self) -> (usize, Option<usize>) {
173 self.packets.size_hint()
174 }
175}
176
177impl ExactSizeIterator for FipsEndpointDirectPacketSlices<'_> {}
178
179impl Drop for FipsEndpointDirectPacketRun {
180 fn drop(&mut self) {
181 PacketBuffer::recycle_batch(&mut self.packets);
182 }
183}
184
185#[derive(Debug, Clone, PartialEq, Eq)]
187pub struct FipsEndpointDirectPacketBatch {
188 packet_runs: Vec<FipsEndpointDirectPacketRun>,
189}
190
191impl FipsEndpointDirectPacketBatch {
192 pub(crate) fn from_packet_runs(packet_runs: Vec<FipsEndpointDirectPacketRun>) -> Self {
193 debug_assert!(
194 packet_runs
195 .iter()
196 .all(|run| run.len() <= FIPS_ENDPOINT_DIRECT_PACKET_RUN_MAX_PACKETS)
197 );
198 Self { packet_runs }
199 }
200
201 pub fn into_packet_runs(self) -> Vec<FipsEndpointDirectPacketRun> {
203 self.packet_runs
204 }
205}
206
207#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
209pub enum FipsEndpointDirectDeliveryError {
210 #[error("direct endpoint sink unavailable")]
212 Unavailable,
213}
214
215pub trait FipsEndpointDirectSink: Send + Sync + 'static {
220 fn deliver_endpoint_packet_batch(
222 &self,
223 batch: FipsEndpointDirectPacketBatch,
224 ) -> Result<(), FipsEndpointDirectDeliveryError>;
225}
226
227impl<F> FipsEndpointDirectSink for F
228where
229 F: Fn(FipsEndpointDirectPacketBatch) -> Result<(), FipsEndpointDirectDeliveryError>
230 + Send
231 + Sync
232 + 'static,
233{
234 fn deliver_endpoint_packet_batch(
235 &self,
236 batch: FipsEndpointDirectPacketBatch,
237 ) -> Result<(), FipsEndpointDirectDeliveryError> {
238 self(batch)
239 }
240}
241
242#[derive(Clone)]
243pub(crate) struct EndpointDirectSink {
244 sink: Arc<dyn FipsEndpointDirectSink>,
245}
246
247impl std::fmt::Debug for EndpointDirectSink {
248 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
249 f.debug_struct("EndpointDirectSink").finish_non_exhaustive()
250 }
251}
252
253impl EndpointDirectSink {
254 pub(crate) fn new<S>(sink: S) -> Self
255 where
256 S: FipsEndpointDirectSink,
257 {
258 Self {
259 sink: Arc::new(sink),
260 }
261 }
262
263 pub(crate) fn deliver_direct_packet_batch(
264 &self,
265 batch: FipsEndpointDirectPacketBatch,
266 ) -> Result<(), FipsEndpointDirectDeliveryError> {
267 self.sink.deliver_endpoint_packet_batch(batch)
268 }
269}
270
271#[derive(Debug)]
273pub struct ExternalPacketIo {
274 pub outbound_tx: crate::upper::tun::TunOutboundTx,
276 pub inbound_rx: tokio::sync::mpsc::Receiver<NodeDeliveredPacket>,
278}
279
280#[derive(Debug)]
282pub(crate) struct EndpointDataIo {
283 pub(crate) control_tx: tokio::sync::mpsc::Sender<NodeEndpointControlCommand>,
286 pub(crate) data_batch_tx: EndpointDataBatchTx,
292 pub(crate) event_rx: EndpointEventReceiver,
300 pub(crate) event_tx: EndpointEventSender,
304 pub(crate) service_event_rx: EndpointServiceEventReceiver,
306 pub(crate) service_event_tx: EndpointServiceEventSender,
308}
309
310#[derive(Debug, Clone)]
312pub(crate) struct EndpointEventSender {
313 tx: tokio::sync::mpsc::Sender<NodeEndpointEvent>,
314 direct_sink: Option<EndpointDirectSink>,
315 queued_messages: Arc<AtomicUsize>,
316 ready: Arc<EndpointEventReady>,
317 message_cap: usize,
318}
319
320#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
321pub(crate) enum EndpointEventSendError {
322 #[error("endpoint event channel closed")]
323 Closed,
324}
325
326#[derive(Debug)]
327pub(crate) struct EndpointEventReceiver {
328 rx: tokio::sync::mpsc::Receiver<NodeEndpointEvent>,
329 queued_messages: Arc<AtomicUsize>,
330 ready: Arc<EndpointEventReady>,
331 closed: bool,
332}
333
334#[derive(Debug, Default)]
335struct EndpointEventReady {
336 sequence: StdMutex<u64>,
337 changed: Condvar,
338}
339
340impl EndpointEventReady {
341 fn notify(&self) {
342 if let Ok(mut sequence) = self.sequence.lock() {
343 *sequence = sequence.wrapping_add(1);
344 self.changed.notify_one();
345 }
346 }
347
348 fn snapshot(&self) -> u64 {
349 self.sequence.lock().map(|sequence| *sequence).unwrap_or(0)
350 }
351
352 fn wait_for_change(&self, observed: &mut u64) {
353 let Ok(mut sequence) = self.sequence.lock() else {
354 return;
355 };
356 while *sequence == *observed {
357 match self.changed.wait(sequence) {
358 Ok(next) => sequence = next,
359 Err(_) => return,
360 }
361 }
362 *observed = *sequence;
363 }
364}
365
366fn endpoint_event_capacity(requested: usize) -> usize {
367 requested.max(1)
368}
369
370fn try_reserve_endpoint_event_messages(
371 counter: &AtomicUsize,
372 capacity: usize,
373 count: usize,
374) -> Option<usize> {
375 if count == 0 {
376 return Some(counter.load(Relaxed));
377 }
378
379 counter
380 .fetch_update(Relaxed, Relaxed, |current| {
381 current.checked_add(count).filter(|next| *next <= capacity)
382 })
383 .ok()
384}
385
386#[derive(Debug, Default)]
393pub(in crate::node) struct EndpointEventRuntime {
394 sender: Option<EndpointEventSender>,
395}
396
397impl EndpointEventSender {
398 pub(in crate::node) fn channel(capacity: usize) -> (Self, EndpointEventReceiver) {
399 Self::channel_with_direct_sink(capacity, None)
400 }
401
402 pub(in crate::node) fn channel_with_direct_sink(
403 capacity: usize,
404 direct_sink: Option<EndpointDirectSink>,
405 ) -> (Self, EndpointEventReceiver) {
406 let message_cap = endpoint_event_capacity(capacity);
407 let (tx, rx) = tokio::sync::mpsc::channel(message_cap);
408 let queued_messages = Arc::new(AtomicUsize::new(0));
409 let ready = Arc::new(EndpointEventReady::default());
410 (
411 Self {
412 tx,
413 direct_sink,
414 queued_messages: Arc::clone(&queued_messages),
415 ready: Arc::clone(&ready),
416 message_cap,
417 },
418 EndpointEventReceiver {
419 rx,
420 queued_messages,
421 ready,
422 closed: false,
423 },
424 )
425 }
426
427 pub(crate) fn direct_sink(&self) -> Option<&EndpointDirectSink> {
428 self.direct_sink.as_ref()
429 }
430
431 pub(crate) fn send(&self, event: NodeEndpointEvent) -> Result<(), EndpointEventSendError> {
432 if event.messages.is_empty() {
433 return Ok(());
434 }
435
436 self.send_event(event, true)
437 }
438
439 fn send_event(
440 &self,
441 event: NodeEndpointEvent,
442 split_on_pressure: bool,
443 ) -> Result<(), EndpointEventSendError> {
444 let count = event.message_count();
445 let Some(previous) =
446 try_reserve_endpoint_event_messages(&self.queued_messages, self.message_cap, count)
447 else {
448 if split_on_pressure && count > 1 {
449 return self.split_and_send_event(event);
450 }
451 crate::perf_profile::record_event_count(
452 crate::perf_profile::Event::EndpointEventBulkDropped,
453 count as u64,
454 );
455 return Ok(());
456 };
457
458 let queued = previous.saturating_add(count);
459 match self.tx.try_send(event) {
460 Ok(()) => {
461 self.note_send_success(previous, queued);
462 Ok(())
463 }
464 Err(tokio::sync::mpsc::error::TrySendError::Full(_event)) => {
465 self.note_send_rejected(count);
466 crate::perf_profile::record_event_count(
467 crate::perf_profile::Event::EndpointEventBulkDropped,
468 count as u64,
469 );
470 Ok(())
471 }
472 Err(tokio::sync::mpsc::error::TrySendError::Closed(event)) => {
473 self.note_send_rejected(count);
474 drop(event);
475 Err(EndpointEventSendError::Closed)
476 }
477 }
478 }
479
480 fn split_and_send_event(&self, event: NodeEndpointEvent) -> Result<(), EndpointEventSendError> {
481 let mut messages = event.messages;
482 let queued_at = event.queued_at;
483 if messages.len() <= 1 {
484 return self.send_event(
485 NodeEndpointEvent {
486 messages,
487 queued_at,
488 },
489 false,
490 );
491 }
492
493 let right = messages.split_off(messages.len() / 2);
494 if !messages.is_empty() {
495 self.send_event(
496 NodeEndpointEvent {
497 messages,
498 queued_at,
499 },
500 true,
501 )?;
502 }
503 if !right.is_empty() {
504 self.send_event(
505 NodeEndpointEvent {
506 messages: right,
507 queued_at,
508 },
509 true,
510 )?;
511 }
512 Ok(())
513 }
514
515 fn note_send_success(&self, previous: usize, queued: usize) {
516 if previous < ENDPOINT_EVENT_BACKLOG_HIGH_WATER
517 && queued >= ENDPOINT_EVENT_BACKLOG_HIGH_WATER
518 {
519 crate::perf_profile::record_event(crate::perf_profile::Event::EndpointEventBacklogHigh);
520 }
521 self.ready.notify();
522 }
523
524 fn note_send_rejected(&self, count: usize) {
525 release_endpoint_event_messages(&self.queued_messages, count);
526 self.ready.notify();
527 }
528
529 #[cfg(test)]
530 pub(crate) fn queued_messages(&self) -> usize {
531 self.queued_messages.load(Relaxed)
532 }
533}
534
535impl Drop for EndpointEventSender {
536 fn drop(&mut self) {
537 self.ready.notify();
538 }
539}
540
541impl Drop for EndpointEventReceiver {
542 fn drop(&mut self) {
543 self.queued_messages.store(0, Relaxed);
544 self.ready.notify();
545 }
546}
547
548impl EndpointEventRuntime {
549 pub(in crate::node) fn attach(&mut self, sender: EndpointEventSender) {
550 self.sender = Some(sender);
551 }
552
553 pub(in crate::node) fn is_attached(&self) -> bool {
554 self.sender.is_some()
555 }
556
557 pub(in crate::node) fn sender(&self) -> Option<EndpointEventSender> {
558 self.sender.clone()
559 }
560
561 pub(in crate::node) fn deliver_endpoint_data_batch(
562 &mut self,
563 messages: Vec<EndpointDataDelivery>,
564 ) -> Result<(), EndpointEventSendError> {
565 if messages.is_empty() {
566 return Ok(());
567 }
568
569 let Some(sender) = &self.sender else {
570 return Ok(());
571 };
572 let _t_deliver =
573 crate::perf_profile::Timer::start(crate::perf_profile::Stage::EndpointDeliver);
574 sender.send(NodeEndpointEvent {
575 messages,
576 queued_at: crate::perf_profile::stamp(),
577 })
578 }
579}
580
581impl EndpointEventReceiver {
582 pub(crate) async fn recv(&mut self) -> Option<NodeEndpointEvent> {
583 let event = self.rx.recv().await?;
584 self.note_observed(&event);
585 Some(event)
586 }
587
588 pub(crate) fn blocking_recv(&mut self) -> Option<NodeEndpointEvent> {
589 let mut observed = self.ready.snapshot();
590 loop {
591 match self.try_recv() {
592 Ok(event) => return Some(event),
593 Err(tokio::sync::mpsc::error::TryRecvError::Disconnected) => return None,
594 Err(tokio::sync::mpsc::error::TryRecvError::Empty) => {
595 self.ready.wait_for_change(&mut observed);
596 }
597 }
598 }
599 }
600
601 pub(crate) fn try_recv(
602 &mut self,
603 ) -> Result<NodeEndpointEvent, tokio::sync::mpsc::error::TryRecvError> {
604 match self.rx.try_recv() {
605 Ok(event) => {
606 self.note_observed(&event);
607 Ok(event)
608 }
609 Err(tokio::sync::mpsc::error::TryRecvError::Empty) => {
610 if self.closed {
611 Err(tokio::sync::mpsc::error::TryRecvError::Disconnected)
612 } else {
613 Err(tokio::sync::mpsc::error::TryRecvError::Empty)
614 }
615 }
616 Err(tokio::sync::mpsc::error::TryRecvError::Disconnected) => {
617 self.closed = true;
618 Err(tokio::sync::mpsc::error::TryRecvError::Disconnected)
619 }
620 }
621 }
622
623 pub(crate) fn release_messages(&self, count: usize) {
624 release_endpoint_event_messages(&self.queued_messages, count);
625 }
626
627 fn note_observed(&self, event: &NodeEndpointEvent) {
628 event.record_dequeue_wait();
629 }
630}
631
632pub(in crate::node) fn release_endpoint_event_messages(counter: &AtomicUsize, count: usize) {
633 if count == 0 {
634 return;
635 }
636
637 let previous = counter.fetch_sub(count, Relaxed);
638 debug_assert!(
639 previous >= count,
640 "endpoint event queued message accounting underflow"
641 );
642}
643
644#[derive(Debug, Clone, Default, PartialEq, Eq)]
646pub(crate) struct UpdatePeersOutcome {
647 pub(crate) added: usize,
648 pub(crate) removed: usize,
649 pub(crate) updated: usize,
650 pub(crate) unchanged: usize,
651}
652
653#[derive(Debug, Clone)]
659pub(crate) struct EndpointDataDelivery {
660 pub(crate) source_peer: PeerIdentity,
661 pub(crate) payload: PacketBuffer,
662 pub(crate) enqueued_at_ms: u64,
663}
664
665impl EndpointDataDelivery {
666 pub(crate) fn new(source_peer: PeerIdentity, payload: PacketBuffer) -> Self {
667 Self {
668 source_peer,
669 payload,
670 enqueued_at_ms: crate::time::now_ms(),
671 }
672 }
673}
674
675#[derive(Debug)]
677pub(crate) struct NodeEndpointEvent {
678 pub(crate) messages: Vec<EndpointDataDelivery>,
679 pub(crate) queued_at: Option<crate::perf_profile::TraceStamp>,
680}
681
682impl NodeEndpointEvent {
683 pub(in crate::node) fn message_count(&self) -> usize {
684 self.messages.len()
685 }
686
687 fn record_dequeue_wait(&self) {
688 let queued_at = self.queued_at;
689 if queued_at.is_none() {
690 return;
691 }
692 crate::perf_profile::record_since_count(
693 crate::perf_profile::Stage::EndpointEventWait,
694 queued_at,
695 self.message_count() as u64,
696 );
697 }
698}
699
700#[derive(Debug, Clone, PartialEq, Eq)]
702pub(crate) struct NodeEndpointPeer {
703 pub(crate) npub: String,
704 pub(crate) node_addr: NodeAddr,
705 pub(crate) connected: bool,
706 pub(crate) transport_addr: Option<String>,
707 pub(crate) transport_type: Option<String>,
708 pub(crate) link_id: u64,
709 pub(crate) srtt_ms: Option<u64>,
710 pub(crate) srtt_age_ms: Option<u64>,
711 pub(crate) packets_sent: u64,
712 pub(crate) packets_recv: u64,
713 pub(crate) bytes_sent: u64,
714 pub(crate) bytes_recv: u64,
715 pub(crate) rekey_in_progress: bool,
716 pub(crate) rekey_draining: bool,
717 pub(crate) current_k_bit: Option<bool>,
718 pub(crate) last_outbound_route: Option<String>,
719 pub(crate) direct_probe_pending: bool,
720 pub(crate) direct_probe_after_ms: Option<u64>,
721 pub(crate) direct_probe_retry_count: u32,
722 pub(crate) direct_probe_auto_reconnect: bool,
723 pub(crate) direct_probe_expires_at_ms: Option<u64>,
724 pub(crate) nostr_traversal_consecutive_failures: u32,
725 pub(crate) nostr_traversal_in_cooldown: bool,
726 pub(crate) nostr_traversal_cooldown_until_ms: Option<u64>,
727 pub(crate) nostr_traversal_last_observed_skew_ms: Option<i64>,
728}
729
730#[derive(Debug, Clone, PartialEq, Eq)]
732pub(crate) struct NodeEndpointRelayStatus {
733 pub(crate) url: String,
734 pub(crate) status: String,
735}