1use crate::config::{EthernetConfig, 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::HashSet;
20use std::sync::{Arc, Mutex as StdMutex};
21use thiserror::Error;
22use tokio::sync::{Mutex, mpsc, oneshot};
23use tokio::task::JoinHandle;
24
25const ENDPOINT_DATA_BATCH_MAX: usize = 128;
26const ENDPOINT_RECV_BATCH_MAX: usize = 128;
27
28mod builder;
29mod receive;
30mod status;
31
32#[cfg(test)]
33mod tests;
34
35pub use crate::node::{
36 FipsEndpointDirectDeliveryError, FipsEndpointDirectPacketBatch, FipsEndpointDirectPacketRun,
37 FipsEndpointDirectSink,
38};
39pub use builder::FipsEndpointBuilder;
40use receive::{EndpointReceiveState, ServiceReceiveState};
41pub use status::{FipsEndpointPeer, FipsEndpointRelayStatus};
42
43pub type FipsEndpointData = crate::transport::PacketBuffer;
48
49#[derive(Debug, Error)]
51pub enum FipsEndpointError {
52 #[error("node error: {0}")]
53 Node(#[from] NodeError),
54
55 #[error("endpoint task failed: {0}")]
56 TaskJoin(#[from] tokio::task::JoinError),
57
58 #[error("endpoint is closed")]
59 Closed,
60
61 #[error("endpoint data payload is too large: {len} bytes exceeds max {max} bytes")]
62 EndpointDataTooLarge { len: usize, max: usize },
63
64 #[error("service datagram payload is too large: {len} bytes exceeds max {max} bytes")]
65 ServiceDatagramTooLarge { len: usize, max: usize },
66
67 #[error("FSP service port {port} is reserved")]
68 ServicePortReserved { port: u16 },
69
70 #[error("FSP service port {port} is already registered")]
71 ServicePortAlreadyRegistered { port: u16 },
72}
73
74#[derive(Debug, Clone, PartialEq, Eq)]
76pub struct FipsEndpointMessage {
77 pub source_peer: PeerIdentity,
79 pub data: FipsEndpointData,
81 pub enqueued_at_ms: u64,
83}
84
85#[derive(Debug, Clone, PartialEq, Eq)]
87pub struct FipsEndpointOutboundDatagram {
88 pub source_port: u16,
89 pub destination_port: u16,
90 pub data: Vec<u8>,
91}
92
93impl FipsEndpointOutboundDatagram {
94 pub fn new(source_port: u16, destination_port: u16, data: Vec<u8>) -> Self {
95 Self {
96 source_port,
97 destination_port,
98 data,
99 }
100 }
101}
102
103#[derive(Debug, Clone, PartialEq, Eq)]
105pub struct FipsEndpointServiceDatagram {
106 pub source_peer: PeerIdentity,
107 pub source_port: u16,
108 pub destination_port: u16,
109 pub data: FipsEndpointData,
110 pub enqueued_at_ms: u64,
111}
112
113#[derive(Debug, Clone, Default, PartialEq, Eq)]
115pub struct UpdatePeersOutcome {
116 pub added: usize,
119 pub removed: usize,
123 pub updated: usize,
128 pub unchanged: usize,
130}
131
132impl From<crate::node::UpdatePeersOutcome> for UpdatePeersOutcome {
133 fn from(value: crate::node::UpdatePeersOutcome) -> Self {
134 Self {
135 added: value.added,
136 removed: value.removed,
137 updated: value.updated,
138 unchanged: value.unchanged,
139 }
140 }
141}
142
143fn apply_default_scoped_discovery(config: &mut Config, scope: &str) {
144 if config.node.discovery.nostr.enabled || !config.transports.is_empty() {
145 return;
146 }
147
148 config.node.discovery.nostr.enabled = true;
149 config.node.discovery.nostr.advertise = true;
150 config.node.discovery.nostr.policy = NostrDiscoveryPolicy::Open;
151 config.node.discovery.nostr.share_local_candidates = true;
152 config.node.discovery.nostr.app = scope.to_string();
153 config.node.discovery.lan.scope = Some(scope.to_string());
154 config.node.discovery.local.enabled = true;
155 config.transports.udp = TransportInstances::Single(UdpConfig {
156 bind_addr: Some("0.0.0.0:0".to_string()),
157 advertise_on_nostr: Some(true),
158 public: Some(false),
159 outbound_only: Some(false),
160 accept_connections: Some(true),
161 ..UdpConfig::default()
162 });
163}
164
165fn endpoint_ethernet_config(interface: &str, scope: Option<&str>) -> EthernetConfig {
166 EthernetConfig {
167 interface: interface.to_string(),
168 discovery: Some(true),
169 announce: Some(true),
170 auto_connect: Some(true),
171 accept_connections: Some(true),
172 discovery_scope: scope
173 .map(str::trim)
174 .filter(|s| !s.is_empty())
175 .map(str::to_string),
176 ..EthernetConfig::default()
177 }
178}
179
180fn add_endpoint_ethernet_transport(config: &mut Config, interface: &str, scope: Option<&str>) {
181 let eth = endpoint_ethernet_config(interface, scope);
182 if config.transports.ethernet.is_empty() {
183 config.transports.ethernet = TransportInstances::Single(eth);
184 return;
185 }
186
187 let existing = std::mem::take(&mut config.transports.ethernet);
188 let mut named = match existing {
189 TransportInstances::Single(config) => {
190 let mut map = std::collections::HashMap::new();
191 map.insert("default".to_string(), config);
192 map
193 }
194 TransportInstances::Named(map) => map,
195 };
196
197 let base_name = endpoint_ethernet_instance_name(interface);
198 let mut name = base_name.clone();
199 let mut suffix = 2usize;
200 while named.contains_key(&name) {
201 name = format!("{base_name}-{suffix}");
202 suffix += 1;
203 }
204 named.insert(name, eth);
205 config.transports.ethernet = TransportInstances::Named(named);
206}
207
208fn endpoint_ethernet_instance_name(interface: &str) -> String {
209 let suffix: String = interface
210 .chars()
211 .map(|c| {
212 if c.is_ascii_alphanumeric() {
213 c.to_ascii_lowercase()
214 } else {
215 '-'
216 }
217 })
218 .collect();
219 let suffix = suffix.trim_matches('-');
220 if suffix.is_empty() {
221 "local-ethernet".to_string()
222 } else {
223 format!("local-ethernet-{suffix}")
224 }
225}
226
227fn endpoint_data_payloads_from_vecs(
228 payloads: Vec<Vec<u8>>,
229) -> Result<Vec<EndpointDataPayload>, FipsEndpointError> {
230 let mut converted = Vec::with_capacity(payloads.len());
231 for payload in payloads {
232 let len = payload.len();
233 let Some(payload) = EndpointDataPayload::from_packet_payload(payload) else {
234 let max = crate::node::session_wire::fsp_endpoint_data_max_body_len();
235 return Err(FipsEndpointError::EndpointDataTooLarge { len, max });
236 };
237 converted.push(payload);
238 }
239 Ok(converted)
240}
241
242fn service_datagram_payloads(
243 datagrams: Vec<FipsEndpointOutboundDatagram>,
244) -> Result<Vec<EndpointDataPayload>, FipsEndpointError> {
245 let max = crate::node::session_wire::fsp_service_datagram_max_body_len();
246 let mut payloads = Vec::with_capacity(datagrams.len());
247 for datagram in datagrams {
248 let len = datagram.data.len();
249 let Some(payload) = EndpointDataPayload::from_service_datagram(
250 datagram.source_port,
251 datagram.destination_port,
252 datagram.data,
253 ) else {
254 return Err(FipsEndpointError::ServiceDatagramTooLarge { len, max });
255 };
256 payloads.push(payload);
257 }
258 Ok(payloads)
259}
260
261fn spawn_node_task(
262 mut node: Node,
263 shutdown_rx: oneshot::Receiver<()>,
264) -> JoinHandle<Result<(), NodeError>> {
265 tokio::spawn(async move {
266 tokio::pin!(shutdown_rx);
267 let loop_result = tokio::select! {
268 result = node.run_rx_loop() => result,
269 _ = &mut shutdown_rx => Ok(()),
270 };
271 let stop_result = if node.state().can_stop() {
272 node.stop().await
273 } else {
274 Ok(())
275 };
276 loop_result?;
277 stop_result
278 })
279}
280
281pub struct FipsEndpoint {
283 identity: PeerIdentity,
284 npub: String,
285 node_addr: NodeAddr,
286 address: FipsAddress,
287 discovery_scope: Option<String>,
288 outbound_packets: TunOutboundTx,
289 delivered_packets: Arc<Mutex<mpsc::Receiver<NodeDeliveredPacket>>>,
290 endpoint_control_tx: mpsc::Sender<NodeEndpointControlCommand>,
291 endpoint_data_batches: EndpointDataBatchTx,
292 inbound_endpoint_tx: EndpointEventSender,
298 inbound_endpoint_rx: Arc<Mutex<EndpointReceiveState>>,
305 inbound_service_tx: EndpointServiceEventSender,
306 inbound_service_rx: Arc<Mutex<ServiceReceiveState>>,
307 registered_services: Arc<StdMutex<HashSet<u16>>>,
308 shutdown_tx: StdMutex<Option<oneshot::Sender<()>>>,
309 task: StdMutex<Option<JoinHandle<Result<(), NodeError>>>>,
310}
311
312impl FipsEndpoint {
313 pub fn builder() -> FipsEndpointBuilder {
315 FipsEndpointBuilder::default()
316 }
317
318 pub fn npub(&self) -> &str {
320 &self.npub
321 }
322
323 pub fn node_addr(&self) -> &NodeAddr {
325 &self.node_addr
326 }
327
328 pub fn address(&self) -> FipsAddress {
330 self.address
331 }
332
333 pub fn discovery_scope(&self) -> Option<&str> {
335 self.discovery_scope.as_deref()
336 }
337
338 pub async fn send_batch_to_peer(
346 &self,
347 remote: PeerIdentity,
348 payloads: Vec<Vec<u8>>,
349 ) -> Result<(), FipsEndpointError> {
350 self.send_payloads_to_peer(remote, payloads)
351 }
352
353 pub async fn register_service(&self, port: u16) -> Result<(), FipsEndpointError> {
358 if port == crate::node::session_wire::FSP_PORT_IPV6_SHIM {
359 return Err(FipsEndpointError::ServicePortReserved { port });
360 }
361
362 let (response_tx, response_rx) = oneshot::channel();
363 self.endpoint_control_tx
364 .send(NodeEndpointControlCommand::RegisterService { port, response_tx })
365 .await
366 .map_err(|_| FipsEndpointError::Closed)?;
367 if !response_rx.await.map_err(|_| FipsEndpointError::Closed)? {
368 return Err(FipsEndpointError::ServicePortAlreadyRegistered { port });
369 }
370 self.registered_services
371 .lock()
372 .map_err(|_| FipsEndpointError::Closed)?
373 .insert(port);
374 Ok(())
375 }
376
377 pub async fn send_datagram(
379 &self,
380 remote: PeerIdentity,
381 source_port: u16,
382 destination_port: u16,
383 payload: Vec<u8>,
384 ) -> Result<(), FipsEndpointError> {
385 self.send_service_datagrams_to_peer(
386 remote,
387 vec![FipsEndpointOutboundDatagram::new(
388 source_port,
389 destination_port,
390 payload,
391 )],
392 )
393 }
394
395 pub async fn send_datagram_batch_to_peer(
397 &self,
398 remote: PeerIdentity,
399 datagrams: Vec<FipsEndpointOutboundDatagram>,
400 ) -> Result<(), FipsEndpointError> {
401 self.send_service_datagrams_to_peer(remote, datagrams)
402 }
403
404 fn send_service_datagrams_to_peer(
405 &self,
406 remote: PeerIdentity,
407 datagrams: Vec<FipsEndpointOutboundDatagram>,
408 ) -> Result<(), FipsEndpointError> {
409 let max = crate::node::session_wire::fsp_service_datagram_max_body_len();
410 if let Some(datagram) = datagrams.iter().find(|datagram| datagram.data.len() > max) {
411 return Err(FipsEndpointError::ServiceDatagramTooLarge {
412 len: datagram.data.len(),
413 max,
414 });
415 }
416 if datagrams.is_empty() {
417 return Ok(());
418 }
419
420 if *remote.node_addr() == self.node_addr {
421 let deliveries = {
422 let registered = self
423 .registered_services
424 .lock()
425 .map_err(|_| FipsEndpointError::Closed)?;
426 datagrams
427 .into_iter()
428 .filter(|datagram| registered.contains(&datagram.destination_port))
429 .map(|datagram| {
430 crate::node::EndpointServiceDatagramDelivery::new(
431 self.identity,
432 datagram.source_port,
433 datagram.destination_port,
434 crate::transport::PacketBuffer::new(datagram.data),
435 )
436 })
437 .collect()
438 };
439 return self
440 .inbound_service_tx
441 .send(deliveries)
442 .map_err(|_| FipsEndpointError::Closed);
443 }
444
445 self.send_endpoint_data_batch(remote, service_datagram_payloads(datagrams)?)
446 }
447
448 fn send_payloads_to_peer(
449 &self,
450 remote: PeerIdentity,
451 payloads: Vec<Vec<u8>>,
452 ) -> Result<(), FipsEndpointError> {
453 let payloads = endpoint_data_payloads_from_vecs(payloads)?;
454 if *remote.node_addr() == self.node_addr {
455 for payload in payloads {
456 self.send_loopback(payload)?;
457 }
458 return Ok(());
459 }
460
461 self.send_endpoint_data_batch(remote, payloads)
462 }
463
464 fn send_endpoint_data_batch(
465 &self,
466 remote: PeerIdentity,
467 payloads: Vec<EndpointDataPayload>,
468 ) -> Result<(), FipsEndpointError> {
469 if payloads.is_empty() {
470 return Ok(());
471 }
472
473 if payloads.len() <= ENDPOINT_DATA_BATCH_MAX {
474 self.enqueue_endpoint_data_batch(remote, payloads)?;
475 return Ok(());
476 }
477
478 let mut payloads = payloads.into_iter();
479 loop {
480 let payload_batch: Vec<_> = payloads.by_ref().take(ENDPOINT_DATA_BATCH_MAX).collect();
481 if payload_batch.is_empty() {
482 break;
483 }
484 self.enqueue_endpoint_data_batch(remote, payload_batch)?;
485 }
486 Ok(())
487 }
488
489 fn enqueue_endpoint_data_batch(
490 &self,
491 remote: PeerIdentity,
492 payload_batch: Vec<EndpointDataPayload>,
493 ) -> Result<(), FipsEndpointError> {
494 if let Some(batch) = NodeEndpointDataBatch::from_payloads(
499 remote,
500 payload_batch,
501 crate::perf_profile::stamp(),
502 ) {
503 self.endpoint_data_batches
504 .send_or_drop(batch)
505 .map_err(|_| FipsEndpointError::Closed)?;
506 }
507 Ok(())
508 }
509
510 fn send_loopback(&self, payload: EndpointDataPayload) -> Result<(), FipsEndpointError> {
511 self.inbound_endpoint_tx
512 .send(NodeEndpointEvent {
513 messages: vec![crate::node::EndpointDataDelivery::new(
514 self.identity,
515 payload.into_body(),
516 )],
517 queued_at: crate::perf_profile::stamp(),
518 })
519 .map_err(|_| FipsEndpointError::Closed)
520 }
521
522 pub async fn recv_batch_into(
529 &self,
530 messages: &mut Vec<FipsEndpointMessage>,
531 max: usize,
532 ) -> Option<usize> {
533 let max = max.clamp(1, ENDPOINT_RECV_BATCH_MAX);
534 messages.clear();
535
536 let mut state = self.inbound_endpoint_rx.lock().await;
537 state.drain_pending_into(messages, max);
538
539 while messages.len() < max {
540 let event = if messages.is_empty() {
541 state.rx.recv().await?
542 } else {
543 match state.rx.try_recv() {
544 Ok(event) => event,
545 Err(_) => break,
546 }
547 };
548 state.push_event_into(event, messages, max);
549 }
550
551 Some(messages.len())
552 }
553
554 pub async fn recv_service_datagram_batch_into(
556 &self,
557 datagrams: &mut Vec<FipsEndpointServiceDatagram>,
558 max: usize,
559 ) -> Option<usize> {
560 let max = max.clamp(1, ENDPOINT_RECV_BATCH_MAX);
561 datagrams.clear();
562
563 let mut state = self.inbound_service_rx.lock().await;
564 state.drain_pending_into(datagrams, max);
565 while datagrams.len() < max {
566 let event = if datagrams.is_empty() {
567 state.rx.recv().await?
568 } else {
569 match state.rx.try_recv() {
570 Ok(event) => event,
571 Err(_) => break,
572 }
573 };
574 state.push_event_into(event, datagrams, max);
575 }
576 Some(datagrams.len())
577 }
578
579 pub fn blocking_send_batch_to_peer(
585 &self,
586 remote: PeerIdentity,
587 payloads: Vec<Vec<u8>>,
588 ) -> Result<(), FipsEndpointError> {
589 self.send_payloads_to_peer(remote, payloads)
590 }
591
592 pub fn blocking_send_datagram(
594 &self,
595 remote: PeerIdentity,
596 source_port: u16,
597 destination_port: u16,
598 payload: Vec<u8>,
599 ) -> Result<(), FipsEndpointError> {
600 self.send_service_datagrams_to_peer(
601 remote,
602 vec![FipsEndpointOutboundDatagram::new(
603 source_port,
604 destination_port,
605 payload,
606 )],
607 )
608 }
609
610 pub fn blocking_send_datagram_batch_to_peer(
612 &self,
613 remote: PeerIdentity,
614 datagrams: Vec<FipsEndpointOutboundDatagram>,
615 ) -> Result<(), FipsEndpointError> {
616 self.send_service_datagrams_to_peer(remote, datagrams)
617 }
618
619 pub fn blocking_recv_batch_into(
627 &self,
628 messages: &mut Vec<FipsEndpointMessage>,
629 max: usize,
630 ) -> Option<usize> {
631 let max = max.clamp(1, ENDPOINT_RECV_BATCH_MAX);
632 messages.clear();
633
634 let mut state = self.inbound_endpoint_rx.blocking_lock();
635 state.drain_pending_into(messages, max);
636
637 while messages.len() < max {
638 let event = if messages.is_empty() {
639 state.rx.blocking_recv()?
640 } else {
641 match state.rx.try_recv() {
642 Ok(event) => event,
643 Err(_) => break,
644 }
645 };
646 state.push_event_into(event, messages, max);
647 }
648
649 Some(messages.len())
650 }
651
652 pub fn blocking_recv_service_datagram_batch_into(
654 &self,
655 datagrams: &mut Vec<FipsEndpointServiceDatagram>,
656 max: usize,
657 ) -> Option<usize> {
658 let max = max.clamp(1, ENDPOINT_RECV_BATCH_MAX);
659 datagrams.clear();
660
661 let mut state = self.inbound_service_rx.blocking_lock();
662 state.drain_pending_into(datagrams, max);
663 while datagrams.len() < max {
664 let event = if datagrams.is_empty() {
665 state.rx.blocking_recv()?
666 } else {
667 match state.rx.try_recv() {
668 Ok(event) => event,
669 Err(_) => break,
670 }
671 };
672 state.push_event_into(event, datagrams, max);
673 }
674 Some(datagrams.len())
675 }
676
677 pub async fn update_peers(
687 &self,
688 peers: Vec<crate::config::PeerConfig>,
689 ) -> Result<UpdatePeersOutcome, FipsEndpointError> {
690 let (response_tx, response_rx) = oneshot::channel();
691 self.endpoint_control_tx
692 .send(NodeEndpointControlCommand::UpdatePeers { peers, response_tx })
693 .await
694 .map_err(|_| FipsEndpointError::Closed)?;
695
696 match response_rx.await.map_err(|_| FipsEndpointError::Closed)? {
697 Ok(outcome) => Ok(UpdatePeersOutcome::from(outcome)),
698 Err(error) => Err(FipsEndpointError::Node(error)),
699 }
700 }
701
702 pub async fn refresh_peer_paths(
708 &self,
709 peers: Vec<PeerIdentity>,
710 ) -> Result<usize, FipsEndpointError> {
711 let (response_tx, response_rx) = oneshot::channel();
712 let npubs = peers.into_iter().map(|peer| peer.npub()).collect();
713 self.endpoint_control_tx
714 .send(NodeEndpointControlCommand::RefreshPeerPaths { npubs, response_tx })
715 .await
716 .map_err(|_| FipsEndpointError::Closed)?;
717
718 match response_rx.await.map_err(|_| FipsEndpointError::Closed)? {
719 Ok(refreshed) => Ok(refreshed),
720 Err(error) => Err(FipsEndpointError::Node(error)),
721 }
722 }
723
724 pub async fn peers(&self) -> Result<Vec<FipsEndpointPeer>, FipsEndpointError> {
726 let (response_tx, response_rx) = oneshot::channel();
727 self.endpoint_control_tx
728 .send(NodeEndpointControlCommand::PeerSnapshot { response_tx })
729 .await
730 .map_err(|_| FipsEndpointError::Closed)?;
731
732 response_rx
733 .await
734 .map(|peers| peers.into_iter().map(FipsEndpointPeer::from).collect())
735 .map_err(|_| FipsEndpointError::Closed)
736 }
737
738 pub async fn local_advertised_endpoints(
741 &self,
742 ) -> Result<Vec<crate::discovery::nostr::OverlayEndpointAdvert>, FipsEndpointError> {
743 let (response_tx, response_rx) = oneshot::channel();
744 self.endpoint_control_tx
745 .send(NodeEndpointControlCommand::LocalAdvertSnapshot { response_tx })
746 .await
747 .map_err(|_| FipsEndpointError::Closed)?;
748
749 response_rx.await.map_err(|_| FipsEndpointError::Closed)
750 }
751
752 pub async fn relay_statuses(&self) -> Result<Vec<FipsEndpointRelayStatus>, FipsEndpointError> {
754 let (response_tx, response_rx) = oneshot::channel();
755 self.endpoint_control_tx
756 .send(NodeEndpointControlCommand::RelaySnapshot { response_tx })
757 .await
758 .map_err(|_| FipsEndpointError::Closed)?;
759
760 response_rx
761 .await
762 .map(|relays| {
763 relays
764 .into_iter()
765 .map(FipsEndpointRelayStatus::from)
766 .collect()
767 })
768 .map_err(|_| FipsEndpointError::Closed)
769 }
770
771 pub async fn update_relays(
773 &self,
774 advert_relays: Vec<String>,
775 dm_relays: Vec<String>,
776 ) -> Result<(), FipsEndpointError> {
777 let (response_tx, response_rx) = oneshot::channel();
778 self.endpoint_control_tx
779 .send(NodeEndpointControlCommand::UpdateRelays {
780 advert_relays,
781 dm_relays,
782 response_tx,
783 })
784 .await
785 .map_err(|_| FipsEndpointError::Closed)?;
786
787 response_rx
788 .await
789 .map_err(|_| FipsEndpointError::Closed)?
790 .map_err(FipsEndpointError::Node)
791 }
792
793 pub async fn send_ip_packet(
795 &self,
796 packet: impl Into<Vec<u8>>,
797 ) -> Result<(), FipsEndpointError> {
798 self.outbound_packets
799 .send(packet.into())
800 .await
801 .map_err(|_| FipsEndpointError::Closed)
802 }
803
804 pub async fn recv_ip_packet(&self) -> Option<NodeDeliveredPacket> {
806 self.delivered_packets.lock().await.recv().await
807 }
808
809 pub async fn shutdown(&self) -> Result<(), FipsEndpointError> {
811 let shutdown_tx = self
812 .shutdown_tx
813 .lock()
814 .map_err(|_| FipsEndpointError::Closed)?
815 .take();
816 if let Some(shutdown_tx) = shutdown_tx {
817 let _ = shutdown_tx.send(());
818 }
819 let task = self
820 .task
821 .lock()
822 .map_err(|_| FipsEndpointError::Closed)?
823 .take();
824 if let Some(task) = task {
825 task.await??;
826 }
827 Ok(())
828 }
829}
830
831impl Drop for FipsEndpoint {
832 fn drop(&mut self) {
833 if let Ok(mut shutdown_tx) = self.shutdown_tx.lock()
834 && let Some(shutdown_tx) = shutdown_tx.take()
835 {
836 let _ = shutdown_tx.send(());
837 }
838 if let Ok(mut task) = self.task.lock()
839 && let Some(task) = task.take()
840 {
841 task.abort();
842 }
843 }
844}