1use std::future::Future;
3use std::pin::Pin;
4use std::sync::{Arc, Mutex, Weak};
5use std::task::{Context, Poll, Waker};
6
7use futures::channel::oneshot;
8
9#[derive(Debug, Clone, PartialEq, Eq)]
11pub enum LinkSendError {
12 QueueFull,
13 DriverStopped,
14 Interrupted,
15 Draining,
16 InvalidPacket(crate::event::LinkDatagramError),
17 PacketBuildFailed,
18 NoRoute,
19 Rejected,
20 InterfaceUnavailable,
21 WriteFailed(String),
22}
23
24impl std::fmt::Display for LinkSendError {
25 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26 match self {
27 Self::QueueFull => f.write_str("outbound queue is full"),
28 Self::DriverStopped => f.write_str("driver stopped before transmission completed"),
29 Self::Interrupted => f.write_str("transmission interrupted before completion"),
30 Self::Draining => f.write_str("node is draining"),
31 Self::InvalidPacket(error) => write!(f, "{error}"),
32 Self::PacketBuildFailed => f.write_str("failed to build or encrypt outbound packet"),
33 Self::NoRoute => f.write_str("no outgoing interface route"),
34 Self::Rejected => f.write_str("outbound packet rejected by routing or policy"),
35 Self::InterfaceUnavailable => f.write_str("outbound interface is unavailable"),
36 Self::WriteFailed(error) => write!(f, "interface write failed: {error}"),
37 }
38 }
39}
40impl std::error::Error for LinkSendError {}
41
42#[must_use = "await the receipt (or call wait) to observe transmission completion"]
46pub struct LinkSendReceipt(oneshot::Receiver<Result<(), LinkSendError>>);
47
48impl Future for LinkSendReceipt {
49 type Output = Result<(), LinkSendError>;
50 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
51 Pin::new(&mut self.0)
52 .poll(cx)
53 .map(|result| result.unwrap_or(Err(LinkSendError::Interrupted)))
54 }
55}
56
57impl LinkSendReceipt {
58 pub fn wait(self) -> Result<(), LinkSendError> {
60 futures::executor::block_on(self)
61 }
62}
63
64#[must_use = "await the receipt (or call wait) to observe transmission completion"]
68pub struct PacketSendReceipt {
69 pub(crate) completion: LinkSendReceipt,
70 pub(crate) hash: rns_core::types::PacketHash,
71}
72impl PacketSendReceipt {
73 pub fn packet_hash(&self) -> rns_core::types::PacketHash {
74 self.hash
75 }
76 pub fn wait(self) -> Result<rns_core::types::PacketHash, LinkSendError> {
78 futures::executor::block_on(self)
79 }
80}
81impl Future for PacketSendReceipt {
82 type Output = Result<rns_core::types::PacketHash, LinkSendError>;
83 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
84 let hash = self.hash;
85 Pin::new(&mut self.completion)
86 .poll(cx)
87 .map(|r| r.map(|()| hash))
88 }
89}
90
91#[derive(Default)]
92pub(crate) struct Waiter(Mutex<Option<Waker>>);
93
94impl Waiter {
95 pub(crate) fn register(&self, cx: &Context<'_>) {
96 *self.0.lock().unwrap() = Some(cx.waker().clone());
97 }
98 pub(crate) fn wake(&self) {
99 let waker = self.0.lock().unwrap().take();
100 if let Some(waker) = waker {
101 waker.wake();
102 }
103 }
104}
105
106struct PoolState {
107 used: usize,
108 closed: bool,
109 waiters: Vec<Weak<Waiter>>,
110 completions: Vec<Weak<CompletionState>>,
111 links: std::collections::HashMap<[u8; 16], SendCounts>,
112}
113
114#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
115pub(crate) struct SendCounts {
116 pub pending: usize,
117 pub waiting: usize,
118}
119
120enum SendPhase {
121 Unadmitted,
122 Waiting,
123 Pending,
124}
125
126pub(crate) struct SendTracking {
127 pool: Arc<SendPool>,
128 link_id: [u8; 16],
129 phase: SendPhase,
130}
131
132impl SendTracking {
133 fn admit(&mut self) {
134 let mut state = self.pool.state.lock().unwrap();
135 if state.closed {
136 return;
137 }
138 let counts = state.links.entry(self.link_id).or_default();
139 match self.phase {
140 SendPhase::Waiting => counts.waiting -= 1,
141 SendPhase::Pending => return,
142 SendPhase::Unadmitted => {}
143 }
144 counts.pending += 1;
145 self.phase = SendPhase::Pending;
146 }
147}
148
149impl Drop for SendTracking {
150 fn drop(&mut self) {
151 let mut state = self.pool.state.lock().unwrap();
152 if let Some(counts) = state.links.get_mut(&self.link_id) {
153 match self.phase {
154 SendPhase::Waiting => counts.waiting -= 1,
155 SendPhase::Pending => counts.pending -= 1,
156 SendPhase::Unadmitted => {}
157 }
158 if counts.pending == 0 && counts.waiting == 0 {
159 state.links.remove(&self.link_id);
160 }
161 }
162 }
163}
164
165pub(crate) struct SendPool {
166 capacity: usize,
167 state: Mutex<PoolState>,
168}
169
170impl SendPool {
171 pub(crate) fn new(capacity: usize) -> Arc<Self> {
172 Arc::new(Self {
173 capacity: capacity.max(1),
174 state: Mutex::new(PoolState {
175 used: 0,
176 closed: false,
177 waiters: Vec::new(),
178 completions: Vec::new(),
179 links: std::collections::HashMap::new(),
180 }),
181 })
182 }
183
184 pub(crate) fn try_acquire(self: &Arc<Self>) -> Result<Permit, LinkSendError> {
185 let mut state = self.state.lock().unwrap();
186 if state.closed {
187 return Err(LinkSendError::DriverStopped);
188 }
189 if state.used == self.capacity {
190 return Err(LinkSendError::QueueFull);
191 }
192 state.used += 1;
193 Ok(Permit(self.clone()))
194 }
195
196 pub(crate) fn track(self: &Arc<Self>, link_id: [u8; 16], waiting: bool) -> SendTracking {
197 let mut state = self.state.lock().unwrap();
198 let phase = if waiting && !state.closed {
199 state.links.entry(link_id).or_default().waiting += 1;
200 SendPhase::Waiting
201 } else {
202 SendPhase::Unadmitted
203 };
204 SendTracking {
205 pool: self.clone(),
206 link_id,
207 phase,
208 }
209 }
210
211 pub(crate) fn snapshot(&self) -> std::collections::HashMap<[u8; 16], SendCounts> {
212 self.state.lock().unwrap().links.clone()
213 }
214
215 pub(crate) async fn acquire(self: &Arc<Self>) -> Result<Permit, LinkSendError> {
216 let waiter = Arc::new(Waiter::default());
217 {
218 let mut state = self.state.lock().unwrap();
219 state.waiters.retain(|waiter| waiter.strong_count() > 0);
220 state.waiters.push(Arc::downgrade(&waiter));
221 }
222 futures::future::poll_fn(|cx| {
223 waiter.register(cx);
224 match self.try_acquire() {
225 Err(LinkSendError::QueueFull) => Poll::Pending,
226 result => Poll::Ready(result),
227 }
228 })
229 .await
230 }
231
232 pub(crate) fn close(&self) {
233 let (waiters, completions) = {
234 let mut state = self.state.lock().unwrap();
235 state.closed = true;
236 state.links.clear();
237 (
238 std::mem::take(&mut state.waiters),
239 std::mem::take(&mut state.completions),
240 )
241 };
242 for waiter in waiters.into_iter().filter_map(|w| w.upgrade()) {
243 waiter.wake();
244 }
245 for completion in completions.into_iter().filter_map(|w| w.upgrade()) {
246 completion.finish(Err(LinkSendError::DriverStopped));
247 }
248 }
249
250 pub(crate) fn in_flight(&self) -> usize {
251 self.state.lock().unwrap().used
252 }
253}
254
255pub(crate) struct Permit(Arc<SendPool>);
256impl Drop for Permit {
257 fn drop(&mut self) {
258 let waiters = {
259 let mut state = self.0.state.lock().unwrap();
260 state.used -= 1;
261 state.waiters.retain(|waiter| waiter.strong_count() > 0);
262 state.waiters.clone()
263 };
264 for waiter in waiters.into_iter().filter_map(|w| w.upgrade()) {
265 waiter.wake();
266 }
267 }
268}
269
270#[doc(hidden)]
272pub struct Completion {
273 ratchet_lease: Option<crate::local_ratchet::AnnouncementLease>,
274 state: Arc<CompletionState>,
275 settled: bool,
276}
277
278struct CompletionData {
279 tx: oneshot::Sender<Result<(), LinkSendError>>,
280 tracking: Option<SendTracking>,
281 permit: Permit,
282 remaining: usize,
283 error: Option<LinkSendError>,
284}
285struct CompletionState(Mutex<Option<CompletionData>>);
286impl Drop for CompletionState {
287 fn drop(&mut self) {
288 self.finish(Err(LinkSendError::Interrupted));
290 }
291}
292impl CompletionState {
293 fn finish(&self, result: Result<(), LinkSendError>) {
294 let data = self.0.lock().unwrap().take();
295 if let Some(data) = data {
296 drop(data.tracking);
297 drop(data.permit);
298 let _ = data.tx.send(result);
299 }
300 }
301}
302
303impl Completion {
304 pub(crate) fn retain_ratchet(
305 &mut self,
306 lease: Option<crate::local_ratchet::AnnouncementLease>,
307 ) {
308 self.ratchet_lease = lease;
309 }
310
311 pub(crate) fn new(permit: Permit) -> (Self, LinkSendReceipt) {
312 Self::new_inner(permit, None)
313 }
314
315 pub(crate) fn new_tracked(permit: Permit, tracking: SendTracking) -> (Self, LinkSendReceipt) {
316 Self::new_inner(permit, Some(tracking))
317 }
318
319 fn new_inner(permit: Permit, tracking: Option<SendTracking>) -> (Self, LinkSendReceipt) {
320 let (tx, rx) = oneshot::channel();
321 let pool = permit.0.clone();
322 let completion = Arc::new(CompletionState(Mutex::new(Some(CompletionData {
323 tx,
324 tracking,
325 permit,
326 remaining: 1,
327 error: None,
328 }))));
329 {
330 let mut pool = pool.state.lock().unwrap();
331 pool.completions.retain(|w| w.strong_count() > 0);
332 if pool.closed {
333 drop(pool);
334 completion.finish(Err(LinkSendError::DriverStopped));
335 } else {
336 pool.completions.push(Arc::downgrade(&completion));
337 }
338 }
339 (
340 Self {
341 ratchet_lease: None,
342 state: completion,
343 settled: false,
344 },
345 LinkSendReceipt(rx),
346 )
347 }
348 pub(crate) fn finish(mut self, result: Result<(), LinkSendError>) {
349 self.settle(result);
350 }
351
352 pub(crate) fn branch(&self) -> Self {
355 if let Some(data) = self.state.0.lock().unwrap().as_mut() {
356 data.remaining += 1;
357 }
358 Self {
359 ratchet_lease: self.ratchet_lease.clone(),
360 state: self.state.clone(),
361 settled: false,
362 }
363 }
364
365 fn settle(&mut self, result: Result<(), LinkSendError>) {
366 self.ratchet_lease = None;
369 self.settled = true;
370 let final_data = {
371 let mut guard = self.state.0.lock().unwrap();
372 let Some(data) = guard.as_mut() else { return };
373 if data.error.is_none() {
374 data.error = result.err();
375 }
376 data.remaining -= 1;
377 if data.remaining == 0 {
378 guard.take()
379 } else {
380 None
381 }
382 };
383 if let Some(data) = final_data {
384 drop(data.tracking);
385 drop(data.permit);
386 let _ = data.tx.send(data.error.map_or(Ok(()), Err));
387 }
388 }
389 pub(crate) fn is_finished(&self) -> bool {
390 self.state.0.lock().unwrap().is_none()
391 }
392
393 pub(crate) fn admit(&self) {
394 if let Some(data) = self.state.0.lock().unwrap().as_mut() {
395 if let Some(tracking) = data.tracking.as_mut() {
396 tracking.admit();
397 }
398 }
399 }
400}
401
402impl Drop for Completion {
403 fn drop(&mut self) {
404 if !self.settled {
405 self.settle(Err(LinkSendError::Interrupted));
406 }
407 }
408}
409
410#[cfg(test)]
411mod tests {
412 use super::*;
413 use futures::{executor::block_on, FutureExt};
414
415 #[test]
416 fn fanout_keeps_capacity_until_all_writes_settle() {
417 let pool = SendPool::new(1);
418 let (completion, mut receipt) = Completion::new(pool.try_acquire().unwrap());
419 let first = completion.branch();
420 let last = completion.branch();
421 completion.finish(Ok(()));
422 first.finish(Err(LinkSendError::WriteFailed("first failed".into())));
423 assert!((&mut receipt).now_or_never().is_none());
424 assert!(matches!(pool.try_acquire(), Err(LinkSendError::QueueFull)));
425 last.finish(Ok(()));
426 assert_eq!(
427 receipt.wait(),
428 Err(LinkSendError::WriteFailed("first failed".into()))
429 );
430 assert_eq!(pool.in_flight(), 0);
431
432 let (completion, receipt) = Completion::new(pool.try_acquire().unwrap());
433 let child = completion.branch();
434 completion.finish(Ok(()));
435 drop(child);
436 assert_eq!(receipt.wait(), Err(LinkSendError::Interrupted));
437 assert_eq!(pool.in_flight(), 0);
438
439 let (completion, receipt) = Completion::new(pool.try_acquire().unwrap());
440 let child = completion.branch();
441 pool.close();
442 assert_eq!(receipt.wait(), Err(LinkSendError::DriverStopped));
443 assert_eq!(pool.in_flight(), 0);
444 drop((completion, child));
445 }
446
447 #[test]
448 fn packet_and_announce_admission_is_bounded_and_runtime_independent() {
449 use crate::event::Event;
450 let (tx, rx) = crate::event::channel_with_capacity(1);
451 let node = crate::RnsNode::from_parts(
452 tx.clone(),
453 std::thread::spawn(|| {}),
454 None,
455 Arc::new(std::sync::atomic::AtomicU64::new(1000)),
456 );
457 let dest = crate::Destination::plain("confirmed", &["packet"]);
458 let identity = rns_crypto::identity::Identity::new(&mut rns_crypto::OsRng);
459 let announce_dest = crate::Destination::single_in(
460 "confirmed",
461 &["announce"],
462 crate::IdentityHash(*identity.hash()),
463 );
464 drop(node.announce(&announce_dest, &identity, None));
465 assert!(
466 rx.try_recv().is_err(),
467 "unpolled sends must have no side effects"
468 );
469 tx.send(Event::Tick).unwrap();
470 assert!(matches!(
471 node.try_announce(&announce_dest, &identity, None),
472 Err(LinkSendError::QueueFull)
473 ));
474 let mut cancelled = Box::pin(node.announce(&announce_dest, &identity, None));
475 assert!(cancelled.as_mut().now_or_never().is_none());
476 drop(cancelled);
477 assert_eq!(tx.link_send_pool().in_flight(), 0);
478 assert!(matches!(rx.try_recv(), Ok(Event::Tick)));
479 assert!(
480 rx.try_recv().is_err(),
481 "cancelled admission must not update replay state"
482 );
483 let receipt = node.try_send_packet(&dest, b"first").unwrap();
484 let hash = receipt.packet_hash();
485 let Event::SendOutboundTracked {
486 completion: first, ..
487 } = rx.try_recv().unwrap()
488 else {
489 panic!("expected tracked packet")
490 };
491 assert!(matches!(
492 node.try_announce(&announce_dest, &identity, None),
493 Err(LinkSendError::QueueFull)
494 ));
495 let mut announce = Box::pin(node.announce(&announce_dest, &identity, None));
496 assert!(announce.as_mut().now_or_never().is_none());
497 assert!(rx.try_recv().is_err());
498 first.finish(Ok(()));
499 assert_eq!(receipt.wait().unwrap(), hash);
500 assert!(announce.as_mut().now_or_never().is_none());
501 let Event::SendOutboundTracked {
502 completion, replay, ..
503 } = rx.try_recv().unwrap()
504 else {
505 panic!("expected tracked announce")
506 };
507 assert_eq!(replay.unwrap().dest_hash, announce_dest.hash.0);
508 assert!(matches!(
509 node.try_send_packet(&dest, b"full"),
510 Err(LinkSendError::QueueFull)
511 ));
512 completion.finish(Ok(()));
513 block_on(announce).unwrap();
514 let receipt = node.try_announce(&announce_dest, &identity, None).unwrap();
515 let Event::SendOutboundTracked { completion, .. } = rx.try_recv().unwrap() else {
516 panic!("expected tracked announce")
517 };
518 completion.finish(Ok(()));
519 receipt.wait().unwrap();
520 let mut packet = Box::pin(node.send_packet(&dest, b"async"));
521 assert!(packet.as_mut().now_or_never().is_none());
522 let Event::SendOutboundTracked {
523 completion, raw, ..
524 } = rx.try_recv().unwrap()
525 else {
526 panic!("expected tracked packet")
527 };
528 let hash = rns_core::types::PacketHash(
529 rns_core::packet::RawPacket::unpack(&raw)
530 .unwrap()
531 .packet_hash,
532 );
533 completion.finish(Ok(()));
534 assert_eq!(block_on(packet).unwrap(), hash);
535 assert!(
536 tx.link_send_pool().snapshot().is_empty(),
537 "non-Link sends must not affect per-Link counts"
538 );
539 drop(rx);
540 assert!(matches!(
541 node.try_send_packet(&dest, b"stopped"),
542 Err(LinkSendError::DriverStopped)
543 ));
544 assert_eq!(
545 block_on(node.announce(&announce_dest, &identity, None)),
546 Err(LinkSendError::DriverStopped)
547 );
548 }
549
550 #[test]
551 fn per_link_counts_cover_failure_shutdown_and_receipt_cancellation() {
552 let pool = SendPool::new(3);
553 let waiting = pool.track([1; 16], true);
554 let tracking = pool.track([2; 16], true);
555 let (completion, receipt) = Completion::new_tracked(pool.try_acquire().unwrap(), tracking);
556 completion.admit();
557 assert_eq!(
558 pool.snapshot().get(&[1; 16]),
559 Some(&SendCounts {
560 pending: 0,
561 waiting: 1
562 })
563 );
564 assert_eq!(
565 pool.snapshot().get(&[2; 16]),
566 Some(&SendCounts {
567 pending: 1,
568 waiting: 0
569 })
570 );
571 drop(receipt);
572 assert_eq!(
573 pool.snapshot()[&[2; 16]].pending,
574 1,
575 "dropping a receipt does not cancel transmission"
576 );
577 completion.finish(Err(LinkSendError::WriteFailed("broken pipe".into())));
578 assert!(!pool.snapshot().contains_key(&[2; 16]));
579 drop(waiting);
580 assert!(pool.snapshot().is_empty());
581
582 let tracking = pool.track([4; 16], false);
583 let (completion, receipt) = Completion::new_tracked(pool.try_acquire().unwrap(), tracking);
584 completion.admit();
585 drop(completion);
586 assert_eq!(receipt.wait(), Err(LinkSendError::Interrupted));
587 assert!(pool.snapshot().is_empty());
588
589 let tracking = pool.track([3; 16], false);
590 let (completion, receipt) = Completion::new_tracked(pool.try_acquire().unwrap(), tracking);
591 completion.admit();
592 let waiting = pool.track([3; 16], true);
593 pool.close();
594 assert_eq!(receipt.wait(), Err(LinkSendError::DriverStopped));
595 assert!(pool.snapshot().is_empty());
596 drop(waiting);
597 drop(completion);
598 assert!(pool.snapshot().is_empty());
599 }
600
601 #[test]
602 fn node_try_rejects_full_capacity_and_async_send_wakes_without_blocking() {
603 use crate::event::Event;
604 use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
605 struct WakeCount(AtomicUsize);
606 impl futures::task::ArcWake for WakeCount {
607 fn wake_by_ref(this: &Arc<Self>) {
608 this.0.fetch_add(1, Ordering::SeqCst);
609 }
610 }
611 let (tx, rx) = crate::event::channel_with_capacity(1);
612 let node = crate::RnsNode::from_parts(
613 tx.clone(),
614 std::thread::spawn(|| {}),
615 None,
616 Arc::new(AtomicU64::new(1000)),
617 );
618 let receipt = node.try_send_on_link([1; 16], vec![1], 0).unwrap();
619 assert_eq!(
620 tx.link_send_pool().snapshot()[&[1; 16]],
621 SendCounts {
622 pending: 1,
623 waiting: 0
624 }
625 );
626 let first = match rx.try_recv().unwrap() {
627 Event::SendLinkTracked { completion, .. } => completion,
628 _ => panic!("expected a tracked send"),
629 };
630 assert!(matches!(
631 node.try_send_on_link([1; 16], vec![2], 0),
632 Err(LinkSendError::QueueFull)
633 ));
634 let mut pending = Box::pin(node.send_on_link([1; 16], vec![2], 0));
635 let wakes = Arc::new(WakeCount(AtomicUsize::new(0)));
636 let waker = futures::task::waker(wakes.clone());
637 let mut cx = Context::from_waker(&waker);
638 assert!(pending.as_mut().poll(&mut cx).is_pending());
639 assert_eq!(
640 tx.link_send_pool().snapshot()[&[1; 16]],
641 SendCounts {
642 pending: 1,
643 waiting: 1
644 }
645 );
646 assert!(
647 rx.try_recv().is_err(),
648 "capacity wait must not enqueue prematurely"
649 );
650 first.finish(Ok(()));
651 receipt.wait().unwrap();
652 assert_eq!(
653 tx.link_send_pool().snapshot()[&[1; 16]],
654 SendCounts {
655 pending: 0,
656 waiting: 1
657 }
658 );
659 assert!(
660 wakes.0.load(Ordering::SeqCst) > 0,
661 "capacity release must wake the task"
662 );
663 assert!(pending.as_mut().poll(&mut cx).is_pending());
664 let second = match rx.try_recv().unwrap() {
665 Event::SendLinkTracked { completion, .. } => completion,
666 _ => panic!("expected a tracked send"),
667 };
668 assert_eq!(
669 tx.link_send_pool().snapshot()[&[1; 16]],
670 SendCounts {
671 pending: 1,
672 waiting: 0
673 }
674 );
675 second.finish(Ok(()));
676 assert!(tx.link_send_pool().snapshot().is_empty());
677 assert_eq!(pending.as_mut().poll(&mut cx), Poll::Ready(Ok(())));
678 drop(pending);
679
680 tx.try_send(Event::Tick).unwrap();
682 assert!(matches!(
683 node.try_send_on_link([1; 16], vec![3], 0),
684 Err(LinkSendError::QueueFull)
685 ));
686 let mut cancelled = Box::pin(node.send_on_link([1; 16], vec![3], 0));
687 assert!(cancelled.as_mut().poll(&mut cx).is_pending());
688 assert_eq!(
689 tx.link_send_pool().snapshot()[&[1; 16]],
690 SendCounts {
691 pending: 0,
692 waiting: 1
693 }
694 );
695 drop(cancelled);
696 assert!(tx.link_send_pool().snapshot().is_empty());
697 assert_eq!(tx.link_send_pool().in_flight(), 0);
698 assert!(matches!(rx.try_recv(), Ok(Event::Tick)));
699 assert!(
700 rx.try_recv().is_err(),
701 "cancelled admission must not send later"
702 );
703 drop(rx);
704 node.shutdown();
705 }
706
707 #[test]
708 fn capacity_waits_for_transmission_not_receipt_creation() {
709 let pool = SendPool::new(1);
710 let (completion, mut receipt) = Completion::new(pool.try_acquire().unwrap());
711 assert!(matches!(pool.try_acquire(), Err(LinkSendError::QueueFull)));
712 assert!((&mut receipt).now_or_never().is_none());
713 let mut waiting = Box::pin(pool.acquire());
714 assert!(waiting.as_mut().now_or_never().is_none());
715 completion.finish(Ok(()));
716 receipt.wait().unwrap();
717 let permit = block_on(waiting).unwrap();
718 assert!(matches!(pool.try_acquire(), Err(LinkSendError::QueueFull)));
719 drop(permit);
720 assert!(pool.try_acquire().is_ok());
721 }
722
723 #[test]
724 fn shutdown_resolves_in_flight_receipts_and_capacity_waiters() {
725 let pool = SendPool::new(1);
726 let (completion, receipt) = Completion::new(pool.try_acquire().unwrap());
727 let mut waiting = Box::pin(pool.acquire());
728 assert!(waiting.as_mut().now_or_never().is_none());
729 pool.close();
730 assert_eq!(receipt.wait(), Err(LinkSendError::DriverStopped));
731 assert!(matches!(
732 block_on(waiting),
733 Err(LinkSendError::DriverStopped)
734 ));
735 completion.finish(Ok(()));
737 }
738
739 #[test]
740 fn dropping_receipt_does_not_release_an_in_flight_slot() {
741 let pool = SendPool::new(1);
742 let (completion, receipt) = Completion::new(pool.try_acquire().unwrap());
743 drop(receipt);
744 assert!(matches!(pool.try_acquire(), Err(LinkSendError::QueueFull)));
745 drop(completion);
746 assert!(pool.try_acquire().is_ok());
747 }
748
749 #[test]
750 fn both_node_apis_report_the_same_invalid_link_error() {
751 struct Callbacks;
752 impl crate::Callbacks for Callbacks {
753 fn on_announce(&mut self, _: crate::AnnouncedIdentity) {}
754 fn on_path_updated(&mut self, _: crate::DestHash, _: u8) {}
755 fn on_local_delivery(&mut self, _: crate::DestHash, _: Vec<u8>, _: crate::PacketHash) {}
756 }
757 let node =
758 crate::RnsNode::start(crate::NodeConfig::default(), Box::new(Callbacks)).unwrap();
759 let expected = Err(LinkSendError::InvalidPacket(
760 crate::event::LinkDatagramError::LinkNotFound,
761 ));
762 assert_eq!(
763 block_on(node.send_on_link([0x42; 16], vec![1], 0)),
764 expected
765 );
766 assert_eq!(
767 node.try_send_on_link([0x42; 16], vec![1], 0)
768 .unwrap()
769 .wait(),
770 expected
771 );
772 let dest = crate::Destination::plain("confirmed", &["no_route"]);
773 assert_eq!(
774 block_on(node.send_packet(&dest, b"data")),
775 Err(LinkSendError::NoRoute)
776 );
777 assert_eq!(
778 node.try_send_packet(&dest, b"data").unwrap().wait(),
779 Err(LinkSendError::NoRoute)
780 );
781 let identity = rns_crypto::identity::Identity::new(&mut rns_crypto::OsRng);
782 let announce_dest = crate::Destination::single_in(
783 "confirmed",
784 &["announce"],
785 crate::IdentityHash(*identity.hash()),
786 );
787 assert_eq!(
788 block_on(node.announce(&announce_dest, &identity, None)),
789 Err(LinkSendError::NoRoute)
790 );
791 assert_eq!(
792 node.try_announce(&announce_dest, &identity, None)
793 .unwrap()
794 .wait(),
795 Err(LinkSendError::NoRoute)
796 );
797 let oversized = vec![0; rns_core::constants::MTU * 2];
798 assert_eq!(
799 block_on(node.send_packet(&dest, &oversized)),
800 Err(LinkSendError::PacketBuildFailed)
801 );
802 assert!(matches!(
803 node.try_send_packet(&dest, &oversized),
804 Err(LinkSendError::PacketBuildFailed)
805 ));
806 node.begin_drain(std::time::Duration::from_secs(30))
807 .unwrap();
808 node.drain_status().unwrap();
809 assert_eq!(
810 block_on(node.send_packet(&dest, b"data")),
811 Err(LinkSendError::Draining)
812 );
813 assert_eq!(
814 node.try_announce(&announce_dest, &identity, None)
815 .unwrap()
816 .wait(),
817 Err(LinkSendError::Draining)
818 );
819 node.shutdown();
820 }
821}