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 state: Arc<CompletionState>,
274 settled: bool,
275}
276
277struct CompletionData {
278 tx: oneshot::Sender<Result<(), LinkSendError>>,
279 tracking: Option<SendTracking>,
280 permit: Permit,
281 remaining: usize,
282 error: Option<LinkSendError>,
283}
284struct CompletionState(Mutex<Option<CompletionData>>);
285impl Drop for CompletionState {
286 fn drop(&mut self) {
287 self.finish(Err(LinkSendError::Interrupted));
289 }
290}
291impl CompletionState {
292 fn finish(&self, result: Result<(), LinkSendError>) {
293 let data = self.0.lock().unwrap().take();
294 if let Some(data) = data {
295 drop(data.tracking);
296 drop(data.permit);
297 let _ = data.tx.send(result);
298 }
299 }
300}
301
302impl Completion {
303 pub(crate) fn new(permit: Permit) -> (Self, LinkSendReceipt) {
304 Self::new_inner(permit, None)
305 }
306
307 pub(crate) fn new_tracked(permit: Permit, tracking: SendTracking) -> (Self, LinkSendReceipt) {
308 Self::new_inner(permit, Some(tracking))
309 }
310
311 fn new_inner(permit: Permit, tracking: Option<SendTracking>) -> (Self, LinkSendReceipt) {
312 let (tx, rx) = oneshot::channel();
313 let pool = permit.0.clone();
314 let completion = Arc::new(CompletionState(Mutex::new(Some(CompletionData {
315 tx,
316 tracking,
317 permit,
318 remaining: 1,
319 error: None,
320 }))));
321 {
322 let mut pool = pool.state.lock().unwrap();
323 pool.completions.retain(|w| w.strong_count() > 0);
324 if pool.closed {
325 drop(pool);
326 completion.finish(Err(LinkSendError::DriverStopped));
327 } else {
328 pool.completions.push(Arc::downgrade(&completion));
329 }
330 }
331 (
332 Self {
333 state: completion,
334 settled: false,
335 },
336 LinkSendReceipt(rx),
337 )
338 }
339 pub(crate) fn finish(mut self, result: Result<(), LinkSendError>) {
340 self.settle(result);
341 }
342
343 pub(crate) fn branch(&self) -> Self {
346 if let Some(data) = self.state.0.lock().unwrap().as_mut() {
347 data.remaining += 1;
348 }
349 Self {
350 state: self.state.clone(),
351 settled: false,
352 }
353 }
354
355 fn settle(&mut self, result: Result<(), LinkSendError>) {
356 self.settled = true;
357 let final_data = {
358 let mut guard = self.state.0.lock().unwrap();
359 let Some(data) = guard.as_mut() else { return };
360 if data.error.is_none() {
361 data.error = result.err();
362 }
363 data.remaining -= 1;
364 if data.remaining == 0 {
365 guard.take()
366 } else {
367 None
368 }
369 };
370 if let Some(data) = final_data {
371 drop(data.tracking);
372 drop(data.permit);
373 let _ = data.tx.send(data.error.map_or(Ok(()), Err));
374 }
375 }
376 pub(crate) fn is_finished(&self) -> bool {
377 self.state.0.lock().unwrap().is_none()
378 }
379
380 pub(crate) fn admit(&self) {
381 if let Some(data) = self.state.0.lock().unwrap().as_mut() {
382 if let Some(tracking) = data.tracking.as_mut() {
383 tracking.admit();
384 }
385 }
386 }
387}
388
389impl Drop for Completion {
390 fn drop(&mut self) {
391 if !self.settled {
392 self.settle(Err(LinkSendError::Interrupted));
393 }
394 }
395}
396
397#[cfg(test)]
398mod tests {
399 use super::*;
400 use futures::{executor::block_on, FutureExt};
401
402 #[test]
403 fn fanout_keeps_capacity_until_all_writes_settle() {
404 let pool = SendPool::new(1);
405 let (completion, mut receipt) = Completion::new(pool.try_acquire().unwrap());
406 let first = completion.branch();
407 let last = completion.branch();
408 completion.finish(Ok(()));
409 first.finish(Err(LinkSendError::WriteFailed("first failed".into())));
410 assert!((&mut receipt).now_or_never().is_none());
411 assert!(matches!(pool.try_acquire(), Err(LinkSendError::QueueFull)));
412 last.finish(Ok(()));
413 assert_eq!(
414 receipt.wait(),
415 Err(LinkSendError::WriteFailed("first failed".into()))
416 );
417 assert_eq!(pool.in_flight(), 0);
418
419 let (completion, receipt) = Completion::new(pool.try_acquire().unwrap());
420 let child = completion.branch();
421 completion.finish(Ok(()));
422 drop(child);
423 assert_eq!(receipt.wait(), Err(LinkSendError::Interrupted));
424 assert_eq!(pool.in_flight(), 0);
425
426 let (completion, receipt) = Completion::new(pool.try_acquire().unwrap());
427 let child = completion.branch();
428 pool.close();
429 assert_eq!(receipt.wait(), Err(LinkSendError::DriverStopped));
430 assert_eq!(pool.in_flight(), 0);
431 drop((completion, child));
432 }
433
434 #[test]
435 fn packet_and_announce_admission_is_bounded_and_runtime_independent() {
436 use crate::event::Event;
437 let (tx, rx) = crate::event::channel_with_capacity(1);
438 let node = crate::RnsNode::from_parts(
439 tx.clone(),
440 std::thread::spawn(|| {}),
441 None,
442 Arc::new(std::sync::atomic::AtomicU64::new(1000)),
443 );
444 let dest = crate::Destination::plain("confirmed", &["packet"]);
445 let identity = rns_crypto::identity::Identity::new(&mut rns_crypto::OsRng);
446 let announce_dest = crate::Destination::single_in(
447 "confirmed",
448 &["announce"],
449 crate::IdentityHash(*identity.hash()),
450 );
451 drop(node.announce(&announce_dest, &identity, None));
452 assert!(
453 rx.try_recv().is_err(),
454 "unpolled sends must have no side effects"
455 );
456 tx.send(Event::Tick).unwrap();
457 assert!(matches!(
458 node.try_announce(&announce_dest, &identity, None),
459 Err(LinkSendError::QueueFull)
460 ));
461 let mut cancelled = Box::pin(node.announce(&announce_dest, &identity, None));
462 assert!(cancelled.as_mut().now_or_never().is_none());
463 drop(cancelled);
464 assert_eq!(tx.link_send_pool().in_flight(), 0);
465 assert!(matches!(rx.try_recv(), Ok(Event::Tick)));
466 assert!(
467 rx.try_recv().is_err(),
468 "cancelled admission must not update replay state"
469 );
470 let receipt = node.try_send_packet(&dest, b"first").unwrap();
471 let hash = receipt.packet_hash();
472 let Event::SendOutboundTracked {
473 completion: first, ..
474 } = rx.try_recv().unwrap()
475 else {
476 panic!("expected tracked packet")
477 };
478 assert!(matches!(
479 node.try_announce(&announce_dest, &identity, None),
480 Err(LinkSendError::QueueFull)
481 ));
482 let mut announce = Box::pin(node.announce(&announce_dest, &identity, None));
483 assert!(announce.as_mut().now_or_never().is_none());
484 assert!(rx.try_recv().is_err());
485 first.finish(Ok(()));
486 assert_eq!(receipt.wait().unwrap(), hash);
487 assert!(announce.as_mut().now_or_never().is_none());
488 let Event::SendOutboundTracked {
489 completion, replay, ..
490 } = rx.try_recv().unwrap()
491 else {
492 panic!("expected tracked announce")
493 };
494 assert_eq!(replay.unwrap().dest_hash, announce_dest.hash.0);
495 assert!(matches!(
496 node.try_send_packet(&dest, b"full"),
497 Err(LinkSendError::QueueFull)
498 ));
499 completion.finish(Ok(()));
500 block_on(announce).unwrap();
501 let receipt = node.try_announce(&announce_dest, &identity, None).unwrap();
502 let Event::SendOutboundTracked { completion, .. } = rx.try_recv().unwrap() else {
503 panic!("expected tracked announce")
504 };
505 completion.finish(Ok(()));
506 receipt.wait().unwrap();
507 let mut packet = Box::pin(node.send_packet(&dest, b"async"));
508 assert!(packet.as_mut().now_or_never().is_none());
509 let Event::SendOutboundTracked {
510 completion, raw, ..
511 } = rx.try_recv().unwrap()
512 else {
513 panic!("expected tracked packet")
514 };
515 let hash = rns_core::types::PacketHash(
516 rns_core::packet::RawPacket::unpack(&raw)
517 .unwrap()
518 .packet_hash,
519 );
520 completion.finish(Ok(()));
521 assert_eq!(block_on(packet).unwrap(), hash);
522 assert!(
523 tx.link_send_pool().snapshot().is_empty(),
524 "non-Link sends must not affect per-Link counts"
525 );
526 drop(rx);
527 assert!(matches!(
528 node.try_send_packet(&dest, b"stopped"),
529 Err(LinkSendError::DriverStopped)
530 ));
531 assert_eq!(
532 block_on(node.announce(&announce_dest, &identity, None)),
533 Err(LinkSendError::DriverStopped)
534 );
535 }
536
537 #[test]
538 fn per_link_counts_cover_failure_shutdown_and_receipt_cancellation() {
539 let pool = SendPool::new(3);
540 let waiting = pool.track([1; 16], true);
541 let tracking = pool.track([2; 16], true);
542 let (completion, receipt) = Completion::new_tracked(pool.try_acquire().unwrap(), tracking);
543 completion.admit();
544 assert_eq!(
545 pool.snapshot().get(&[1; 16]),
546 Some(&SendCounts {
547 pending: 0,
548 waiting: 1
549 })
550 );
551 assert_eq!(
552 pool.snapshot().get(&[2; 16]),
553 Some(&SendCounts {
554 pending: 1,
555 waiting: 0
556 })
557 );
558 drop(receipt);
559 assert_eq!(
560 pool.snapshot()[&[2; 16]].pending,
561 1,
562 "dropping a receipt does not cancel transmission"
563 );
564 completion.finish(Err(LinkSendError::WriteFailed("broken pipe".into())));
565 assert!(!pool.snapshot().contains_key(&[2; 16]));
566 drop(waiting);
567 assert!(pool.snapshot().is_empty());
568
569 let tracking = pool.track([4; 16], false);
570 let (completion, receipt) = Completion::new_tracked(pool.try_acquire().unwrap(), tracking);
571 completion.admit();
572 drop(completion);
573 assert_eq!(receipt.wait(), Err(LinkSendError::Interrupted));
574 assert!(pool.snapshot().is_empty());
575
576 let tracking = pool.track([3; 16], false);
577 let (completion, receipt) = Completion::new_tracked(pool.try_acquire().unwrap(), tracking);
578 completion.admit();
579 let waiting = pool.track([3; 16], true);
580 pool.close();
581 assert_eq!(receipt.wait(), Err(LinkSendError::DriverStopped));
582 assert!(pool.snapshot().is_empty());
583 drop(waiting);
584 drop(completion);
585 assert!(pool.snapshot().is_empty());
586 }
587
588 #[test]
589 fn node_try_rejects_full_capacity_and_async_send_wakes_without_blocking() {
590 use crate::event::Event;
591 use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
592 struct WakeCount(AtomicUsize);
593 impl futures::task::ArcWake for WakeCount {
594 fn wake_by_ref(this: &Arc<Self>) {
595 this.0.fetch_add(1, Ordering::SeqCst);
596 }
597 }
598 let (tx, rx) = crate::event::channel_with_capacity(1);
599 let node = crate::RnsNode::from_parts(
600 tx.clone(),
601 std::thread::spawn(|| {}),
602 None,
603 Arc::new(AtomicU64::new(1000)),
604 );
605 let receipt = node.try_send_on_link([1; 16], vec![1], 0).unwrap();
606 assert_eq!(
607 tx.link_send_pool().snapshot()[&[1; 16]],
608 SendCounts {
609 pending: 1,
610 waiting: 0
611 }
612 );
613 let first = match rx.try_recv().unwrap() {
614 Event::SendLinkTracked { completion, .. } => completion,
615 _ => panic!("expected a tracked send"),
616 };
617 assert!(matches!(
618 node.try_send_on_link([1; 16], vec![2], 0),
619 Err(LinkSendError::QueueFull)
620 ));
621 let mut pending = Box::pin(node.send_on_link([1; 16], vec![2], 0));
622 let wakes = Arc::new(WakeCount(AtomicUsize::new(0)));
623 let waker = futures::task::waker(wakes.clone());
624 let mut cx = Context::from_waker(&waker);
625 assert!(pending.as_mut().poll(&mut cx).is_pending());
626 assert_eq!(
627 tx.link_send_pool().snapshot()[&[1; 16]],
628 SendCounts {
629 pending: 1,
630 waiting: 1
631 }
632 );
633 assert!(
634 rx.try_recv().is_err(),
635 "capacity wait must not enqueue prematurely"
636 );
637 first.finish(Ok(()));
638 receipt.wait().unwrap();
639 assert_eq!(
640 tx.link_send_pool().snapshot()[&[1; 16]],
641 SendCounts {
642 pending: 0,
643 waiting: 1
644 }
645 );
646 assert!(
647 wakes.0.load(Ordering::SeqCst) > 0,
648 "capacity release must wake the task"
649 );
650 assert!(pending.as_mut().poll(&mut cx).is_pending());
651 let second = match rx.try_recv().unwrap() {
652 Event::SendLinkTracked { completion, .. } => completion,
653 _ => panic!("expected a tracked send"),
654 };
655 assert_eq!(
656 tx.link_send_pool().snapshot()[&[1; 16]],
657 SendCounts {
658 pending: 1,
659 waiting: 0
660 }
661 );
662 second.finish(Ok(()));
663 assert!(tx.link_send_pool().snapshot().is_empty());
664 assert_eq!(pending.as_mut().poll(&mut cx), Poll::Ready(Ok(())));
665 drop(pending);
666
667 tx.try_send(Event::Tick).unwrap();
669 assert!(matches!(
670 node.try_send_on_link([1; 16], vec![3], 0),
671 Err(LinkSendError::QueueFull)
672 ));
673 let mut cancelled = Box::pin(node.send_on_link([1; 16], vec![3], 0));
674 assert!(cancelled.as_mut().poll(&mut cx).is_pending());
675 assert_eq!(
676 tx.link_send_pool().snapshot()[&[1; 16]],
677 SendCounts {
678 pending: 0,
679 waiting: 1
680 }
681 );
682 drop(cancelled);
683 assert!(tx.link_send_pool().snapshot().is_empty());
684 assert_eq!(tx.link_send_pool().in_flight(), 0);
685 assert!(matches!(rx.try_recv(), Ok(Event::Tick)));
686 assert!(
687 rx.try_recv().is_err(),
688 "cancelled admission must not send later"
689 );
690 drop(rx);
691 node.shutdown();
692 }
693
694 #[test]
695 fn capacity_waits_for_transmission_not_receipt_creation() {
696 let pool = SendPool::new(1);
697 let (completion, mut receipt) = Completion::new(pool.try_acquire().unwrap());
698 assert!(matches!(pool.try_acquire(), Err(LinkSendError::QueueFull)));
699 assert!((&mut receipt).now_or_never().is_none());
700 let mut waiting = Box::pin(pool.acquire());
701 assert!(waiting.as_mut().now_or_never().is_none());
702 completion.finish(Ok(()));
703 receipt.wait().unwrap();
704 let permit = block_on(waiting).unwrap();
705 assert!(matches!(pool.try_acquire(), Err(LinkSendError::QueueFull)));
706 drop(permit);
707 assert!(pool.try_acquire().is_ok());
708 }
709
710 #[test]
711 fn shutdown_resolves_in_flight_receipts_and_capacity_waiters() {
712 let pool = SendPool::new(1);
713 let (completion, receipt) = Completion::new(pool.try_acquire().unwrap());
714 let mut waiting = Box::pin(pool.acquire());
715 assert!(waiting.as_mut().now_or_never().is_none());
716 pool.close();
717 assert_eq!(receipt.wait(), Err(LinkSendError::DriverStopped));
718 assert!(matches!(
719 block_on(waiting),
720 Err(LinkSendError::DriverStopped)
721 ));
722 completion.finish(Ok(()));
724 }
725
726 #[test]
727 fn dropping_receipt_does_not_release_an_in_flight_slot() {
728 let pool = SendPool::new(1);
729 let (completion, receipt) = Completion::new(pool.try_acquire().unwrap());
730 drop(receipt);
731 assert!(matches!(pool.try_acquire(), Err(LinkSendError::QueueFull)));
732 drop(completion);
733 assert!(pool.try_acquire().is_ok());
734 }
735
736 #[test]
737 fn both_node_apis_report_the_same_invalid_link_error() {
738 struct Callbacks;
739 impl crate::Callbacks for Callbacks {
740 fn on_announce(&mut self, _: crate::AnnouncedIdentity) {}
741 fn on_path_updated(&mut self, _: crate::DestHash, _: u8) {}
742 fn on_local_delivery(&mut self, _: crate::DestHash, _: Vec<u8>, _: crate::PacketHash) {}
743 }
744 let node =
745 crate::RnsNode::start(crate::NodeConfig::default(), Box::new(Callbacks)).unwrap();
746 let expected = Err(LinkSendError::InvalidPacket(
747 crate::event::LinkDatagramError::LinkNotFound,
748 ));
749 assert_eq!(
750 block_on(node.send_on_link([0x42; 16], vec![1], 0)),
751 expected
752 );
753 assert_eq!(
754 node.try_send_on_link([0x42; 16], vec![1], 0)
755 .unwrap()
756 .wait(),
757 expected
758 );
759 let dest = crate::Destination::plain("confirmed", &["no_route"]);
760 assert_eq!(
761 block_on(node.send_packet(&dest, b"data")),
762 Err(LinkSendError::NoRoute)
763 );
764 assert_eq!(
765 node.try_send_packet(&dest, b"data").unwrap().wait(),
766 Err(LinkSendError::NoRoute)
767 );
768 let identity = rns_crypto::identity::Identity::new(&mut rns_crypto::OsRng);
769 let announce_dest = crate::Destination::single_in(
770 "confirmed",
771 &["announce"],
772 crate::IdentityHash(*identity.hash()),
773 );
774 assert_eq!(
775 block_on(node.announce(&announce_dest, &identity, None)),
776 Err(LinkSendError::NoRoute)
777 );
778 assert_eq!(
779 node.try_announce(&announce_dest, &identity, None)
780 .unwrap()
781 .wait(),
782 Err(LinkSendError::NoRoute)
783 );
784 let oversized = vec![0; rns_core::constants::MTU * 2];
785 assert_eq!(
786 block_on(node.send_packet(&dest, &oversized)),
787 Err(LinkSendError::PacketBuildFailed)
788 );
789 assert!(matches!(
790 node.try_send_packet(&dest, &oversized),
791 Err(LinkSendError::PacketBuildFailed)
792 ));
793 node.begin_drain(std::time::Duration::from_secs(30))
794 .unwrap();
795 node.drain_status().unwrap();
796 assert_eq!(
797 block_on(node.send_packet(&dest, b"data")),
798 Err(LinkSendError::Draining)
799 );
800 assert_eq!(
801 node.try_announce(&announce_dest, &identity, None)
802 .unwrap()
803 .wait(),
804 Err(LinkSendError::Draining)
805 );
806 node.shutdown();
807 }
808}