1use crate::config::{NostrDiscoveryPolicy, TransportInstances, UdpConfig};
7#[cfg(test)]
8use crate::node::ENDPOINT_EVENT_TEST_PAYLOAD_LEN;
9use crate::node::{
10 EndpointDataBatchTx, EndpointDataPayload, EndpointDirectSink, EndpointEventSender,
11 EndpointServiceEventSender, NodeEndpointControlCommand, NodeEndpointDataBatch,
12 NodeEndpointEvent,
13};
14use crate::upper::tun::TunOutboundTx;
15use crate::{
16 Config, FipsAddress, IdentityConfig, Node, NodeAddr, NodeDeliveredPacket, NodeError,
17 PeerIdentity,
18};
19use std::collections::HashMap;
20use std::sync::{Arc, Mutex as StdMutex};
21use std::time::Duration;
22use thiserror::Error;
23use tokio::sync::{Mutex, mpsc, oneshot};
24use tokio::task::JoinHandle;
25
26const ENDPOINT_DATA_BATCH_MAX: usize = 128;
27const ENDPOINT_RECV_BATCH_MAX: usize = 128;
28const ENDPOINT_OPERATION_TIMEOUT: Duration = Duration::from_secs(5);
29
30mod builder;
31#[path = "endpoint/nostr.rs"]
32mod nostr_api;
33mod receive;
34mod recent_peers;
35mod service_receiver;
36mod status;
37
38#[cfg(test)]
39mod tests;
40
41pub use crate::node::{
42 FIPS_ENDPOINT_DIRECT_PACKET_QUEUE_MAX_PACKETS, FIPS_ENDPOINT_DIRECT_PACKET_RUN_MAX_PACKETS,
43 FipsEndpointDirectDeliveryError, FipsEndpointDirectPacketBatch, FipsEndpointDirectPacketRun,
44 FipsEndpointDirectReceiver, FipsEndpointDirectSink,
45};
46pub use builder::FipsEndpointBuilder;
47use receive::{EndpointReceiveState, ServiceReceiveState};
48pub use recent_peers::{
49 RECENT_PEERS_MAX_ENDPOINTS_PER_PEER, RECENT_PEERS_MAX_PEERS, RECENT_PEERS_VERSION, RecentPeer,
50 RecentPeerEndpoint, RecentPeerTransport, RecentPeers, RecentPeersError,
51};
52pub use status::{FipsEndpointPeer, FipsEndpointRelayStatus};
53
54pub type FipsEndpointData = crate::transport::PacketBuffer;
59
60#[derive(Debug, Error)]
62pub enum FipsEndpointError {
63 #[error("node error: {0}")]
64 Node(#[from] NodeError),
65
66 #[error("endpoint task failed: {0}")]
67 TaskJoin(#[from] tokio::task::JoinError),
68
69 #[error("endpoint is closed")]
70 Closed,
71
72 #[error("endpoint {operation} timed out")]
73 Timeout { operation: &'static str },
74
75 #[error("endpoint data payload is too large: {len} bytes exceeds max {max} bytes")]
76 EndpointDataTooLarge { len: usize, max: usize },
77
78 #[error("service datagram payload is too large: {len} bytes exceeds max {max} bytes")]
79 ServiceDatagramTooLarge { len: usize, max: usize },
80
81 #[error("FSP service port {port} is reserved")]
82 ServicePortReserved { port: u16 },
83
84 #[error("FSP service port {port} is already registered")]
85 ServicePortAlreadyRegistered { port: u16 },
86
87 #[cfg(feature = "host-ble-transport")]
88 #[error("host BLE adapter was already consumed by another endpoint bind")]
89 HostBleAdapterConsumed,
90}
91
92#[derive(Debug, Error)]
94pub enum LocalServiceRegistrationError {
95 #[error("local FSP service capability must include a port")]
96 ServiceCapabilityMissingPort,
97
98 #[error("local FSP service capability name must not be empty")]
99 ServiceCapabilityNameEmpty,
100
101 #[error("local FSP service capability name exceeds {max} bytes")]
102 ServiceCapabilityNameTooLong { max: usize },
103
104 #[error(transparent)]
105 Endpoint(#[from] FipsEndpointError),
106}
107
108#[derive(Debug, Clone, PartialEq, Eq)]
110pub struct FipsEndpointMessage {
111 pub source_peer: PeerIdentity,
113 pub data: FipsEndpointData,
115 pub enqueued_at_ms: u64,
117}
118
119#[derive(Debug, Clone, PartialEq, Eq)]
121pub struct FipsEndpointOutboundDatagram {
122 pub source_port: u16,
123 pub destination_port: u16,
124 pub data: Vec<u8>,
125}
126
127impl FipsEndpointOutboundDatagram {
128 pub fn new(source_port: u16, destination_port: u16, data: Vec<u8>) -> Self {
129 Self {
130 source_port,
131 destination_port,
132 data,
133 }
134 }
135}
136
137#[derive(Debug, Clone, PartialEq, Eq)]
139pub struct FipsEndpointServiceDatagram {
140 pub source_peer: PeerIdentity,
141 pub source_port: u16,
142 pub destination_port: u16,
143 pub data: FipsEndpointData,
144 pub enqueued_at_ms: u64,
145}
146
147pub struct FipsEndpointServiceReceiver {
152 state: Mutex<ServiceReceiveState>,
153}
154
155#[derive(Debug, Clone, Default, PartialEq, Eq)]
157pub struct UpdatePeersOutcome {
158 pub added: usize,
161 pub removed: usize,
165 pub updated: usize,
170 pub unchanged: usize,
172}
173
174impl From<crate::node::UpdatePeersOutcome> for UpdatePeersOutcome {
175 fn from(value: crate::node::UpdatePeersOutcome) -> Self {
176 Self {
177 added: value.added,
178 removed: value.removed,
179 updated: value.updated,
180 unchanged: value.unchanged,
181 }
182 }
183}
184
185fn apply_default_scoped_discovery(config: &mut Config, scope: &str) {
186 if config.node.discovery.nostr.enabled || !config.transports.is_empty() {
187 return;
188 }
189
190 config.node.discovery.nostr.enabled = true;
191 config.node.discovery.nostr.advertise = true;
192 config.node.discovery.nostr.policy = NostrDiscoveryPolicy::Open;
193 config.node.discovery.nostr.share_local_candidates = true;
194 config.node.discovery.nostr.app = scope.to_string();
195 config.node.discovery.lan.scope = Some(scope.to_string());
196 config.node.discovery.local.enabled = true;
197 config.transports.udp = TransportInstances::Single(UdpConfig {
198 bind_addr: Some("0.0.0.0:0".to_string()),
199 advertise_on_nostr: Some(true),
200 public: Some(false),
201 outbound_only: Some(false),
202 accept_connections: Some(true),
203 ..UdpConfig::default()
204 });
205}
206
207fn endpoint_data_payloads_from_vecs(
208 payloads: Vec<Vec<u8>>,
209) -> Result<Vec<EndpointDataPayload>, FipsEndpointError> {
210 let mut converted = Vec::with_capacity(payloads.len());
211 for payload in payloads {
212 let len = payload.len();
213 let Some(payload) = EndpointDataPayload::from_packet_payload(payload) else {
214 let max = crate::node::session_wire::fsp_endpoint_data_max_body_len();
215 return Err(FipsEndpointError::EndpointDataTooLarge { len, max });
216 };
217 converted.push(payload);
218 }
219 Ok(converted)
220}
221
222fn service_datagram_payloads(
223 datagrams: Vec<FipsEndpointOutboundDatagram>,
224) -> Result<Vec<EndpointDataPayload>, FipsEndpointError> {
225 let max = crate::node::session_wire::fsp_service_datagram_max_body_len();
226 let mut payloads = Vec::with_capacity(datagrams.len());
227 for datagram in datagrams {
228 let len = datagram.data.len();
229 let Some(payload) = EndpointDataPayload::from_service_datagram(
230 datagram.source_port,
231 datagram.destination_port,
232 datagram.data,
233 ) else {
234 return Err(FipsEndpointError::ServiceDatagramTooLarge { len, max });
235 };
236 payloads.push(payload);
237 }
238 Ok(payloads)
239}
240
241fn spawn_node_task(
242 mut node: Node,
243 shutdown_rx: oneshot::Receiver<()>,
244) -> JoinHandle<Result<(), NodeError>> {
245 tokio::spawn(async move {
246 tokio::pin!(shutdown_rx);
247 let loop_result = tokio::select! {
248 result = node.run_rx_loop() => result,
249 _ = &mut shutdown_rx => Ok(()),
250 };
251 let stop_result = if node.state().can_stop() {
252 node.stop().await
253 } else {
254 Ok(())
255 };
256 loop_result?;
257 stop_result
258 })
259}
260
261pub struct FipsEndpoint {
263 identity: PeerIdentity,
264 npub: String,
265 node_addr: NodeAddr,
266 address: FipsAddress,
267 discovery_scope: Option<String>,
268 local_capability_directory: crate::discovery::local::LocalCapabilityDirectory,
269 outbound_packets: TunOutboundTx,
270 delivered_packets: Arc<Mutex<mpsc::Receiver<NodeDeliveredPacket>>>,
271 endpoint_control_tx: mpsc::Sender<NodeEndpointControlCommand>,
272 endpoint_data_batches: EndpointDataBatchTx,
273 inbound_endpoint_tx: EndpointEventSender,
279 inbound_endpoint_rx: Arc<Mutex<EndpointReceiveState>>,
286 inbound_service_tx: EndpointServiceEventSender,
287 inbound_service_rx: Arc<Mutex<ServiceReceiveState>>,
288 registered_services: Arc<StdMutex<HashMap<u16, EndpointServiceEventSender>>>,
289 service_channel_capacity: usize,
290 shutdown_tx: StdMutex<Option<oneshot::Sender<()>>>,
291 task: StdMutex<Option<JoinHandle<Result<(), NodeError>>>>,
292}
293
294impl FipsEndpoint {
295 pub fn builder() -> FipsEndpointBuilder {
297 FipsEndpointBuilder::default()
298 }
299
300 async fn control<T>(
301 &self,
302 operation: &'static str,
303 command: NodeEndpointControlCommand,
304 response_rx: oneshot::Receiver<T>,
305 ) -> Result<T, FipsEndpointError> {
306 tokio::time::timeout(ENDPOINT_OPERATION_TIMEOUT, async {
307 self.endpoint_control_tx
308 .send(command)
309 .await
310 .map_err(|_| FipsEndpointError::Closed)?;
311 response_rx.await.map_err(|_| FipsEndpointError::Closed)
312 })
313 .await
314 .map_err(|_| FipsEndpointError::Timeout { operation })?
315 }
316
317 pub fn npub(&self) -> &str {
319 &self.npub
320 }
321
322 pub fn node_addr(&self) -> &NodeAddr {
324 &self.node_addr
325 }
326
327 pub fn address(&self) -> FipsAddress {
329 self.address
330 }
331
332 pub fn discovery_scope(&self) -> Option<&str> {
334 self.discovery_scope.as_deref()
335 }
336
337 pub fn local_instance_advertisements(
341 &self,
342 ) -> Result<
343 Vec<crate::discovery::local::LocalInstanceAdvertisement>,
344 crate::discovery::local::LocalInstanceRegistryError,
345 > {
346 Ok(self.local_capability_directory.snapshot())
347 }
348
349 pub async fn bound_udp_listen_addrs(
352 &self,
353 ) -> Result<Vec<std::net::SocketAddr>, FipsEndpointError> {
354 let (response_tx, response_rx) = oneshot::channel();
355 self.control(
356 "bound UDP listener snapshot",
357 NodeEndpointControlCommand::BoundUdpListenAddrs { response_tx },
358 response_rx,
359 )
360 .await
361 }
362
363 pub async fn send_batch_to_peer(
371 &self,
372 remote: PeerIdentity,
373 payloads: Vec<Vec<u8>>,
374 ) -> Result<(), FipsEndpointError> {
375 self.send_payloads_to_peer(remote, payloads)
376 }
377
378 pub async fn register_service(&self, port: u16) -> Result<(), FipsEndpointError> {
383 self.register_service_with_sender(port, self.inbound_service_tx.clone(), None)
384 .await
385 }
386
387 pub async fn register_service_receiver(
389 &self,
390 port: u16,
391 ) -> Result<FipsEndpointServiceReceiver, FipsEndpointError> {
392 let (sender, receiver) = EndpointServiceEventSender::channel(self.service_channel_capacity);
393 self.register_service_with_sender(port, sender, None)
394 .await?;
395 Ok(FipsEndpointServiceReceiver {
396 state: Mutex::new(ServiceReceiveState::new(receiver)),
397 })
398 }
399
400 pub async fn register_service_receiver_with_capability(
403 &self,
404 mut capability: crate::discovery::local::LocalInstanceCapability,
405 ) -> Result<FipsEndpointServiceReceiver, LocalServiceRegistrationError> {
406 let Some(port) = capability.fsp_port else {
407 return Err(LocalServiceRegistrationError::ServiceCapabilityMissingPort);
408 };
409 if capability.name.trim().is_empty() {
410 return Err(LocalServiceRegistrationError::ServiceCapabilityNameEmpty);
411 }
412 capability.name = capability.name.trim().to_string();
413 if !crate::discovery::local_udp::local_capability_name_is_valid(&capability.name) {
414 return Err(
415 LocalServiceRegistrationError::ServiceCapabilityNameTooLong {
416 max: crate::discovery::local_udp::LOCAL_CAPABILITY_MAX_NAME_BYTES,
417 },
418 );
419 }
420 let (sender, receiver) = EndpointServiceEventSender::channel(self.service_channel_capacity);
421 self.register_service_with_sender(port, sender, Some(capability))
422 .await?;
423 Ok(FipsEndpointServiceReceiver {
424 state: Mutex::new(ServiceReceiveState::new(receiver)),
425 })
426 }
427
428 async fn register_service_with_sender(
429 &self,
430 port: u16,
431 sender: EndpointServiceEventSender,
432 capability: Option<crate::discovery::local::LocalInstanceCapability>,
433 ) -> Result<(), FipsEndpointError> {
434 if port == crate::node::session_wire::FSP_PORT_IPV6_SHIM
435 || port == crate::transport::link_negotiation::LINK_NEGOTIATION_SERVICE_PORT
436 || port == crate::discovery::local_udp::LOCAL_CAPABILITY_FSP_PORT
437 {
438 return Err(FipsEndpointError::ServicePortReserved { port });
439 }
440
441 let (response_tx, response_rx) = oneshot::channel();
442 if !self
443 .control(
444 "service registration",
445 NodeEndpointControlCommand::RegisterService {
446 port,
447 sender: sender.clone(),
448 capability,
449 response_tx,
450 },
451 response_rx,
452 )
453 .await?
454 {
455 return Err(FipsEndpointError::ServicePortAlreadyRegistered { port });
456 }
457 self.registered_services
458 .lock()
459 .map_err(|_| FipsEndpointError::Closed)?
460 .insert(port, sender);
461 Ok(())
462 }
463
464 pub async fn send_datagram(
466 &self,
467 remote: PeerIdentity,
468 source_port: u16,
469 destination_port: u16,
470 payload: Vec<u8>,
471 ) -> Result<(), FipsEndpointError> {
472 self.send_service_datagrams_to_peer(
473 remote,
474 vec![FipsEndpointOutboundDatagram::new(
475 source_port,
476 destination_port,
477 payload,
478 )],
479 )
480 }
481
482 pub async fn send_datagram_batch_to_peer(
484 &self,
485 remote: PeerIdentity,
486 datagrams: Vec<FipsEndpointOutboundDatagram>,
487 ) -> Result<(), FipsEndpointError> {
488 self.send_service_datagrams_to_peer(remote, datagrams)
489 }
490
491 fn send_service_datagrams_to_peer(
492 &self,
493 remote: PeerIdentity,
494 datagrams: Vec<FipsEndpointOutboundDatagram>,
495 ) -> Result<(), FipsEndpointError> {
496 let max = crate::node::session_wire::fsp_service_datagram_max_body_len();
497 if let Some(datagram) = datagrams.iter().find(|datagram| datagram.data.len() > max) {
498 return Err(FipsEndpointError::ServiceDatagramTooLarge {
499 len: datagram.data.len(),
500 max,
501 });
502 }
503 if datagrams.is_empty() {
504 return Ok(());
505 }
506
507 if *remote.node_addr() == self.node_addr {
508 let deliveries_by_port = {
509 let mut registered = self
510 .registered_services
511 .lock()
512 .map_err(|_| FipsEndpointError::Closed)?;
513 registered.retain(|_, sender| !sender.is_closed());
514 let mut grouped: HashMap<
515 u16,
516 (
517 EndpointServiceEventSender,
518 Vec<crate::node::EndpointServiceDatagramDelivery>,
519 ),
520 > = HashMap::new();
521 for datagram in datagrams {
522 let Some(sender) = registered.get(&datagram.destination_port) else {
523 continue;
524 };
525 grouped
526 .entry(datagram.destination_port)
527 .or_insert_with(|| (sender.clone(), Vec::new()))
528 .1
529 .push(crate::node::EndpointServiceDatagramDelivery::new(
530 self.identity,
531 datagram.source_port,
532 datagram.destination_port,
533 crate::transport::PacketBuffer::new(datagram.data),
534 ));
535 }
536 grouped
537 };
538 for (_, (sender, deliveries)) in deliveries_by_port {
539 sender
540 .send(deliveries)
541 .map_err(|_| FipsEndpointError::Closed)?;
542 }
543 return Ok(());
544 }
545
546 self.send_endpoint_data_batch(remote, service_datagram_payloads(datagrams)?)
547 }
548
549 fn send_payloads_to_peer(
550 &self,
551 remote: PeerIdentity,
552 payloads: Vec<Vec<u8>>,
553 ) -> Result<(), FipsEndpointError> {
554 let payloads = endpoint_data_payloads_from_vecs(payloads)?;
555 if *remote.node_addr() == self.node_addr {
556 for payload in payloads {
557 self.send_loopback(payload)?;
558 }
559 return Ok(());
560 }
561
562 self.send_endpoint_data_batch(remote, payloads)
563 }
564
565 fn send_endpoint_data_batch(
566 &self,
567 remote: PeerIdentity,
568 payloads: Vec<EndpointDataPayload>,
569 ) -> Result<(), FipsEndpointError> {
570 if payloads.is_empty() {
571 return Ok(());
572 }
573
574 if payloads.len() <= ENDPOINT_DATA_BATCH_MAX {
575 self.enqueue_endpoint_data_batch(remote, payloads)?;
576 return Ok(());
577 }
578
579 let mut payloads = payloads.into_iter();
580 loop {
581 let payload_batch: Vec<_> = payloads.by_ref().take(ENDPOINT_DATA_BATCH_MAX).collect();
582 if payload_batch.is_empty() {
583 break;
584 }
585 self.enqueue_endpoint_data_batch(remote, payload_batch)?;
586 }
587 Ok(())
588 }
589
590 fn enqueue_endpoint_data_batch(
591 &self,
592 remote: PeerIdentity,
593 payload_batch: Vec<EndpointDataPayload>,
594 ) -> Result<(), FipsEndpointError> {
595 if let Some(batch) = NodeEndpointDataBatch::from_payloads(
600 remote,
601 payload_batch,
602 crate::perf_profile::stamp(),
603 ) {
604 self.endpoint_data_batches
605 .send_or_drop(batch)
606 .map_err(|_| FipsEndpointError::Closed)?;
607 }
608 Ok(())
609 }
610
611 fn send_loopback(&self, payload: EndpointDataPayload) -> Result<(), FipsEndpointError> {
612 self.inbound_endpoint_tx
613 .send(NodeEndpointEvent {
614 messages: vec![crate::node::EndpointDataDelivery::new(
615 self.identity,
616 payload.into_body(),
617 )],
618 queued_at: crate::perf_profile::stamp(),
619 })
620 .map_err(|_| FipsEndpointError::Closed)
621 }
622
623 pub async fn recv_batch_into(
630 &self,
631 messages: &mut Vec<FipsEndpointMessage>,
632 max: usize,
633 ) -> Option<usize> {
634 let max = max.clamp(1, ENDPOINT_RECV_BATCH_MAX);
635 messages.clear();
636
637 let mut state = self.inbound_endpoint_rx.lock().await;
638 state.drain_pending_into(messages, max);
639
640 while messages.len() < max {
641 let event = if messages.is_empty() {
642 state.rx.recv().await?
643 } else {
644 match state.rx.try_recv() {
645 Ok(event) => event,
646 Err(_) => break,
647 }
648 };
649 state.push_event_into(event, messages, max);
650 }
651
652 Some(messages.len())
653 }
654
655 pub async fn recv_service_datagram_batch_into(
657 &self,
658 datagrams: &mut Vec<FipsEndpointServiceDatagram>,
659 max: usize,
660 ) -> Option<usize> {
661 let max = max.clamp(1, ENDPOINT_RECV_BATCH_MAX);
662 datagrams.clear();
663
664 let mut state = self.inbound_service_rx.lock().await;
665 state.drain_pending_into(datagrams, max);
666 while datagrams.len() < max {
667 let event = if datagrams.is_empty() {
668 state.rx.recv().await?
669 } else {
670 match state.rx.try_recv() {
671 Ok(event) => event,
672 Err(_) => break,
673 }
674 };
675 state.push_event_into(event, datagrams, max);
676 }
677 Some(datagrams.len())
678 }
679
680 pub fn blocking_send_batch_to_peer(
686 &self,
687 remote: PeerIdentity,
688 payloads: Vec<Vec<u8>>,
689 ) -> Result<(), FipsEndpointError> {
690 self.send_payloads_to_peer(remote, payloads)
691 }
692
693 pub fn blocking_send_datagram(
695 &self,
696 remote: PeerIdentity,
697 source_port: u16,
698 destination_port: u16,
699 payload: Vec<u8>,
700 ) -> Result<(), FipsEndpointError> {
701 self.send_service_datagrams_to_peer(
702 remote,
703 vec![FipsEndpointOutboundDatagram::new(
704 source_port,
705 destination_port,
706 payload,
707 )],
708 )
709 }
710
711 pub fn blocking_send_datagram_batch_to_peer(
713 &self,
714 remote: PeerIdentity,
715 datagrams: Vec<FipsEndpointOutboundDatagram>,
716 ) -> Result<(), FipsEndpointError> {
717 self.send_service_datagrams_to_peer(remote, datagrams)
718 }
719
720 pub fn blocking_recv_batch_into(
728 &self,
729 messages: &mut Vec<FipsEndpointMessage>,
730 max: usize,
731 ) -> Option<usize> {
732 let max = max.clamp(1, ENDPOINT_RECV_BATCH_MAX);
733 messages.clear();
734
735 let mut state = self.inbound_endpoint_rx.blocking_lock();
736 state.drain_pending_into(messages, max);
737
738 while messages.len() < max {
739 let event = if messages.is_empty() {
740 state.rx.blocking_recv()?
741 } else {
742 match state.rx.try_recv() {
743 Ok(event) => event,
744 Err(_) => break,
745 }
746 };
747 state.push_event_into(event, messages, max);
748 }
749
750 Some(messages.len())
751 }
752
753 pub fn blocking_recv_service_datagram_batch_into(
755 &self,
756 datagrams: &mut Vec<FipsEndpointServiceDatagram>,
757 max: usize,
758 ) -> Option<usize> {
759 let max = max.clamp(1, ENDPOINT_RECV_BATCH_MAX);
760 datagrams.clear();
761
762 let mut state = self.inbound_service_rx.blocking_lock();
763 state.drain_pending_into(datagrams, max);
764 while datagrams.len() < max {
765 let event = if datagrams.is_empty() {
766 state.rx.blocking_recv()?
767 } else {
768 match state.rx.try_recv() {
769 Ok(event) => event,
770 Err(_) => break,
771 }
772 };
773 state.push_event_into(event, datagrams, max);
774 }
775 Some(datagrams.len())
776 }
777
778 pub async fn update_peers(
788 &self,
789 peers: Vec<crate::config::PeerConfig>,
790 ) -> Result<UpdatePeersOutcome, FipsEndpointError> {
791 let (response_tx, response_rx) = oneshot::channel();
792 match self
793 .control(
794 "peer update",
795 NodeEndpointControlCommand::UpdatePeers { peers, response_tx },
796 response_rx,
797 )
798 .await?
799 {
800 Ok(outcome) => Ok(UpdatePeersOutcome::from(outcome)),
801 Err(error) => Err(FipsEndpointError::Node(error)),
802 }
803 }
804
805 pub async fn refresh_peer_paths(
813 &self,
814 peers: Vec<PeerIdentity>,
815 ) -> Result<usize, FipsEndpointError> {
816 let (response_tx, response_rx) = oneshot::channel();
817 let npubs = peers.into_iter().map(|peer| peer.npub()).collect();
818 match self
819 .control(
820 "peer path refresh",
821 NodeEndpointControlCommand::RefreshPeerPaths { npubs, response_tx },
822 response_rx,
823 )
824 .await?
825 {
826 Ok(refreshed) => Ok(refreshed),
827 Err(error) => Err(FipsEndpointError::Node(error)),
828 }
829 }
830
831 pub async fn rebind_network_transports(
837 &self,
838 bind_interface: Option<String>,
839 ) -> Result<usize, FipsEndpointError> {
840 let (response_tx, response_rx) = oneshot::channel();
841 match self
842 .control(
843 "network transport rebind",
844 NodeEndpointControlCommand::RebindNetworkTransports {
845 bind_interface,
846 response_tx,
847 },
848 response_rx,
849 )
850 .await?
851 {
852 Ok(rebound) => Ok(rebound),
853 Err(error) => Err(FipsEndpointError::Node(error)),
854 }
855 }
856
857 pub async fn register_peer_identity(
863 &self,
864 identity: PeerIdentity,
865 ) -> Result<bool, FipsEndpointError> {
866 let (response_tx, response_rx) = oneshot::channel();
867 self.control(
868 "identity registration",
869 NodeEndpointControlCommand::RegisterIdentity {
870 identity,
871 response_tx,
872 },
873 response_rx,
874 )
875 .await
876 }
877
878 pub async fn peers(&self) -> Result<Vec<FipsEndpointPeer>, FipsEndpointError> {
880 let (response_tx, response_rx) = oneshot::channel();
881 self.control(
882 "peer snapshot",
883 NodeEndpointControlCommand::PeerSnapshot { response_tx },
884 response_rx,
885 )
886 .await
887 .map(|peers| peers.into_iter().map(FipsEndpointPeer::from).collect())
888 }
889
890 pub async fn send_ip_packet(
892 &self,
893 packet: impl Into<Vec<u8>>,
894 ) -> Result<(), FipsEndpointError> {
895 self.outbound_packets
896 .send(packet.into())
897 .await
898 .map_err(|_| FipsEndpointError::Closed)
899 }
900
901 pub fn blocking_send_ip_packet(
903 &self,
904 packet: impl Into<Vec<u8>>,
905 ) -> Result<(), FipsEndpointError> {
906 self.outbound_packets
907 .blocking_send(packet.into())
908 .map_err(|_| FipsEndpointError::Closed)
909 }
910
911 pub async fn recv_ip_packet(&self) -> Option<NodeDeliveredPacket> {
913 self.delivered_packets.lock().await.recv().await
914 }
915
916 pub async fn shutdown(&self) -> Result<(), FipsEndpointError> {
918 let shutdown_tx = self
919 .shutdown_tx
920 .lock()
921 .map_err(|_| FipsEndpointError::Closed)?
922 .take();
923 if let Some(shutdown_tx) = shutdown_tx {
924 let _ = shutdown_tx.send(());
925 }
926 let task = self
927 .task
928 .lock()
929 .map_err(|_| FipsEndpointError::Closed)?
930 .take();
931 if let Some(mut task) = task {
932 match tokio::time::timeout(ENDPOINT_OPERATION_TIMEOUT, &mut task).await {
933 Ok(result) => result??,
934 Err(_) => {
935 task.abort();
936 let _ = task.await;
937 return Err(FipsEndpointError::Timeout {
938 operation: "shutdown",
939 });
940 }
941 }
942 }
943 Ok(())
944 }
945}
946
947impl Drop for FipsEndpoint {
948 fn drop(&mut self) {
949 if let Ok(mut shutdown_tx) = self.shutdown_tx.lock()
950 && let Some(shutdown_tx) = shutdown_tx.take()
951 {
952 let _ = shutdown_tx.send(());
953 }
954 if let Ok(mut task) = self.task.lock()
955 && task.is_some()
956 {
957 drop(task.take());
961 }
962 }
963}