1use std::collections::HashMap;
10
11use rns_core::buffer::types::NoopCompressor;
12use rns_core::channel::Channel;
13use rns_core::constants;
14use rns_core::link::types::{LinkId, LinkState, TeardownReason};
15use rns_core::link::{LinkAction, LinkEngine, LinkMode};
16use rns_core::packet::{PacketFlags, RawPacket};
17use rns_core::resource::{ResourceAction, ResourceReceiver, ResourceSender};
18use rns_crypto::ed25519::Ed25519PrivateKey;
19use rns_crypto::Rng;
20
21use crate::time;
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub enum ResourceStrategy {
26 AcceptNone,
28 AcceptAll,
30 AcceptApp,
32}
33
34impl Default for ResourceStrategy {
35 fn default() -> Self {
36 ResourceStrategy::AcceptNone
37 }
38}
39
40struct ManagedLink {
42 engine: LinkEngine,
43 channel: Option<Channel>,
44 dest_hash: [u8; 16],
46 remote_identity: Option<([u8; 16], [u8; 64])>,
48 dest_sig_pub_bytes: Option<[u8; 32]>,
50 incoming_resources: Vec<ResourceReceiver>,
52 outgoing_resources: Vec<ResourceSender>,
54 resource_strategy: ResourceStrategy,
56}
57
58struct LinkDestination {
60 dest_hash: [u8; 16],
61 sig_prv: Ed25519PrivateKey,
62 sig_pub_bytes: [u8; 32],
63}
64
65struct RequestHandlerEntry {
67 path: String,
69 path_hash: [u8; 16],
71 allowed_list: Option<Vec<[u8; 16]>>,
73 handler: Box<dyn Fn(LinkId, &str, &[u8], Option<&([u8; 16], [u8; 64])>) -> Option<Vec<u8>> + Send>,
75}
76
77#[derive(Debug)]
79pub enum LinkManagerAction {
80 SendPacket {
82 raw: Vec<u8>,
83 dest_type: u8,
84 attached_interface: Option<rns_core::transport::types::InterfaceId>,
85 },
86 LinkEstablished {
88 link_id: LinkId,
89 dest_hash: [u8; 16],
90 rtt: f64,
91 is_initiator: bool,
92 },
93 LinkClosed {
95 link_id: LinkId,
96 reason: Option<TeardownReason>,
97 },
98 RemoteIdentified {
100 link_id: LinkId,
101 identity_hash: [u8; 16],
102 public_key: [u8; 64],
103 },
104 RegisterLinkDest {
106 link_id: LinkId,
107 },
108 DeregisterLinkDest {
110 link_id: LinkId,
111 },
112 ManagementRequest {
115 link_id: LinkId,
116 path_hash: [u8; 16],
117 data: Vec<u8>,
119 request_id: [u8; 16],
121 remote_identity: Option<([u8; 16], [u8; 64])>,
122 },
123 ResourceReceived {
125 link_id: LinkId,
126 data: Vec<u8>,
127 metadata: Option<Vec<u8>>,
128 },
129 ResourceCompleted {
131 link_id: LinkId,
132 },
133 ResourceFailed {
135 link_id: LinkId,
136 error: String,
137 },
138 ResourceProgress {
140 link_id: LinkId,
141 received: usize,
142 total: usize,
143 },
144 ResourceAcceptQuery {
146 link_id: LinkId,
147 resource_hash: Vec<u8>,
148 transfer_size: u64,
149 has_metadata: bool,
150 },
151 ChannelMessageReceived {
153 link_id: LinkId,
154 msgtype: u16,
155 payload: Vec<u8>,
156 },
157 LinkDataReceived {
159 link_id: LinkId,
160 context: u8,
161 data: Vec<u8>,
162 },
163 ResponseReceived {
165 link_id: LinkId,
166 request_id: [u8; 16],
167 data: Vec<u8>,
168 },
169}
170
171pub struct LinkManager {
173 links: HashMap<LinkId, ManagedLink>,
174 link_destinations: HashMap<[u8; 16], LinkDestination>,
175 request_handlers: Vec<RequestHandlerEntry>,
176 management_paths: Vec<[u8; 16]>,
179}
180
181impl LinkManager {
182 pub fn new() -> Self {
184 LinkManager {
185 links: HashMap::new(),
186 link_destinations: HashMap::new(),
187 request_handlers: Vec::new(),
188 management_paths: Vec::new(),
189 }
190 }
191
192 pub fn register_management_path(&mut self, path_hash: [u8; 16]) {
196 if !self.management_paths.contains(&path_hash) {
197 self.management_paths.push(path_hash);
198 }
199 }
200
201 pub fn register_link_destination(
203 &mut self,
204 dest_hash: [u8; 16],
205 sig_prv: Ed25519PrivateKey,
206 sig_pub_bytes: [u8; 32],
207 ) {
208 self.link_destinations.insert(dest_hash, LinkDestination {
209 dest_hash,
210 sig_prv,
211 sig_pub_bytes,
212 });
213 }
214
215 pub fn deregister_link_destination(&mut self, dest_hash: &[u8; 16]) {
217 self.link_destinations.remove(dest_hash);
218 }
219
220 pub fn register_request_handler<F>(
226 &mut self,
227 path: &str,
228 allowed_list: Option<Vec<[u8; 16]>>,
229 handler: F,
230 ) where
231 F: Fn(LinkId, &str, &[u8], Option<&([u8; 16], [u8; 64])>) -> Option<Vec<u8>> + Send + 'static,
232 {
233 let path_hash = compute_path_hash(path);
234 self.request_handlers.push(RequestHandlerEntry {
235 path: path.to_string(),
236 path_hash,
237 allowed_list,
238 handler: Box::new(handler),
239 });
240 }
241
242 pub fn create_link(
250 &mut self,
251 dest_hash: &[u8; 16],
252 dest_sig_pub_bytes: &[u8; 32],
253 hops: u8,
254 rng: &mut dyn Rng,
255 ) -> (LinkId, Vec<LinkManagerAction>) {
256 let mode = LinkMode::Aes256Cbc;
257 let (mut engine, request_data) =
258 LinkEngine::new_initiator(dest_hash, hops, mode, Some(constants::MTU as u32), time::now(), rng);
259
260 let flags = PacketFlags {
262 header_type: constants::HEADER_1,
263 context_flag: constants::FLAG_UNSET,
264 transport_type: constants::TRANSPORT_BROADCAST,
265 destination_type: constants::DESTINATION_LINK,
266 packet_type: constants::PACKET_TYPE_LINKREQUEST,
267 };
268
269 let packet = match RawPacket::pack(
270 flags, 0, dest_hash, None, constants::CONTEXT_NONE, &request_data,
271 ) {
272 Ok(p) => p,
273 Err(_) => {
274 return ([0u8; 16], Vec::new());
276 }
277 };
278
279 engine.set_link_id_from_hashable(&packet.get_hashable_part(), request_data.len());
280 let link_id = *engine.link_id();
281
282 let managed = ManagedLink {
283 engine,
284 channel: None,
285 dest_hash: *dest_hash,
286 remote_identity: None,
287 dest_sig_pub_bytes: Some(*dest_sig_pub_bytes),
288 incoming_resources: Vec::new(),
289 outgoing_resources: Vec::new(),
290 resource_strategy: ResourceStrategy::default(),
291 };
292 self.links.insert(link_id, managed);
293
294 let mut actions = Vec::new();
295 actions.push(LinkManagerAction::RegisterLinkDest { link_id });
297 actions.push(LinkManagerAction::SendPacket {
299 raw: packet.raw,
300 dest_type: constants::DESTINATION_LINK,
301 attached_interface: None,
302 });
303
304 (link_id, actions)
305 }
306
307 pub fn handle_local_delivery(
313 &mut self,
314 dest_hash: [u8; 16],
315 raw: &[u8],
316 packet_hash: [u8; 32],
317 rng: &mut dyn Rng,
318 ) -> Vec<LinkManagerAction> {
319 let packet = match RawPacket::unpack(raw) {
320 Ok(p) => p,
321 Err(_) => return Vec::new(),
322 };
323
324 match packet.flags.packet_type {
325 constants::PACKET_TYPE_LINKREQUEST => {
326 self.handle_linkrequest(&dest_hash, &packet, rng)
327 }
328 constants::PACKET_TYPE_PROOF if packet.context == constants::CONTEXT_LRPROOF => {
329 self.handle_lrproof(&dest_hash, &packet, rng)
331 }
332 constants::PACKET_TYPE_DATA => {
333 self.handle_link_data(&dest_hash, &packet, packet_hash, rng)
334 }
335 _ => Vec::new(),
336 }
337 }
338
339 fn handle_linkrequest(
341 &mut self,
342 dest_hash: &[u8; 16],
343 packet: &RawPacket,
344 rng: &mut dyn Rng,
345 ) -> Vec<LinkManagerAction> {
346 let ld = match self.link_destinations.get(dest_hash) {
348 Some(ld) => ld,
349 None => return Vec::new(),
350 };
351
352 let hashable = packet.get_hashable_part();
353 let now = time::now();
354
355 let (engine, lrproof_data) = match LinkEngine::new_responder(
357 &ld.sig_prv,
358 &ld.sig_pub_bytes,
359 &packet.data,
360 &hashable,
361 dest_hash,
362 packet.hops,
363 now,
364 rng,
365 ) {
366 Ok(r) => r,
367 Err(e) => {
368 log::debug!("LINKREQUEST rejected: {}", e);
369 return Vec::new();
370 }
371 };
372
373 let link_id = *engine.link_id();
374
375 let managed = ManagedLink {
376 engine,
377 channel: None,
378 dest_hash: *dest_hash,
379 remote_identity: None,
380 dest_sig_pub_bytes: None,
381 incoming_resources: Vec::new(),
382 outgoing_resources: Vec::new(),
383 resource_strategy: ResourceStrategy::default(),
384 };
385 self.links.insert(link_id, managed);
386
387 let flags = PacketFlags {
389 header_type: constants::HEADER_1,
390 context_flag: constants::FLAG_UNSET,
391 transport_type: constants::TRANSPORT_BROADCAST,
392 destination_type: constants::DESTINATION_LINK,
393 packet_type: constants::PACKET_TYPE_PROOF,
394 };
395
396 let mut actions = Vec::new();
397
398 actions.push(LinkManagerAction::RegisterLinkDest { link_id });
400
401 if let Ok(pkt) = RawPacket::pack(
402 flags, 0, &link_id, None, constants::CONTEXT_LRPROOF, &lrproof_data,
403 ) {
404 actions.push(LinkManagerAction::SendPacket {
405 raw: pkt.raw,
406 dest_type: constants::DESTINATION_LINK,
407 attached_interface: None,
408 });
409 }
410
411 actions
412 }
413
414 fn handle_lrproof(
416 &mut self,
417 link_id_bytes: &[u8; 16],
418 packet: &RawPacket,
419 rng: &mut dyn Rng,
420 ) -> Vec<LinkManagerAction> {
421 let link = match self.links.get_mut(link_id_bytes) {
422 Some(l) => l,
423 None => return Vec::new(),
424 };
425
426 if link.engine.state() != LinkState::Pending || !link.engine.is_initiator() {
427 return Vec::new();
428 }
429
430 let dest_sig_pub_bytes = match link.dest_sig_pub_bytes {
432 Some(b) => b,
433 None => {
434 log::debug!("LRPROOF: no destination signing key available");
435 return Vec::new();
436 }
437 };
438
439 let now = time::now();
440 let (lrrtt_encrypted, link_actions) = match link.engine.handle_lrproof(
441 &packet.data,
442 &dest_sig_pub_bytes,
443 now,
444 rng,
445 ) {
446 Ok(r) => r,
447 Err(e) => {
448 log::debug!("LRPROOF validation failed: {}", e);
449 return Vec::new();
450 }
451 };
452
453 let link_id = *link.engine.link_id();
454 let mut actions = Vec::new();
455
456 actions.extend(self.process_link_actions(&link_id, &link_actions));
458
459 let flags = PacketFlags {
461 header_type: constants::HEADER_1,
462 context_flag: constants::FLAG_UNSET,
463 transport_type: constants::TRANSPORT_BROADCAST,
464 destination_type: constants::DESTINATION_LINK,
465 packet_type: constants::PACKET_TYPE_DATA,
466 };
467
468 if let Ok(pkt) = RawPacket::pack(
469 flags, 0, &link_id, None, constants::CONTEXT_LRRTT, &lrrtt_encrypted,
470 ) {
471 actions.push(LinkManagerAction::SendPacket {
472 raw: pkt.raw,
473 dest_type: constants::DESTINATION_LINK,
474 attached_interface: None,
475 });
476 }
477
478 if let Some(link) = self.links.get_mut(&link_id) {
480 if link.engine.state() == LinkState::Active {
481 let rtt = link.engine.rtt().unwrap_or(1.0);
482 link.channel = Some(Channel::new(rtt));
483 }
484 }
485
486 actions
487 }
488
489 fn handle_link_data(
495 &mut self,
496 link_id_bytes: &[u8; 16],
497 packet: &RawPacket,
498 _packet_hash: [u8; 32],
499 rng: &mut dyn Rng,
500 ) -> Vec<LinkManagerAction> {
501 enum LinkDataResult {
503 Lrrtt { link_id: LinkId, link_actions: Vec<LinkAction> },
504 Identify { link_id: LinkId, link_actions: Vec<LinkAction> },
505 Keepalive { link_id: LinkId, inbound_actions: Vec<LinkAction> },
506 LinkClose { link_id: LinkId, teardown_actions: Vec<LinkAction> },
507 Channel { link_id: LinkId, inbound_actions: Vec<LinkAction>, plaintext: Vec<u8> },
508 Request { link_id: LinkId, inbound_actions: Vec<LinkAction>, plaintext: Vec<u8> },
509 Response { link_id: LinkId, inbound_actions: Vec<LinkAction>, plaintext: Vec<u8> },
510 Generic { link_id: LinkId, inbound_actions: Vec<LinkAction>, plaintext: Vec<u8>, context: u8 },
511 ResourceAdv { link_id: LinkId, inbound_actions: Vec<LinkAction>, plaintext: Vec<u8> },
513 ResourceReq { link_id: LinkId, inbound_actions: Vec<LinkAction>, plaintext: Vec<u8> },
515 ResourceHmu { link_id: LinkId, inbound_actions: Vec<LinkAction>, plaintext: Vec<u8> },
517 ResourcePart { link_id: LinkId, inbound_actions: Vec<LinkAction>, raw_data: Vec<u8> },
519 ResourcePrf { link_id: LinkId, inbound_actions: Vec<LinkAction>, plaintext: Vec<u8> },
521 ResourceIcl { link_id: LinkId, inbound_actions: Vec<LinkAction> },
523 ResourceRcl { link_id: LinkId, inbound_actions: Vec<LinkAction> },
525 Error,
526 }
527
528 let result = {
529 let link = match self.links.get_mut(link_id_bytes) {
530 Some(l) => l,
531 None => return Vec::new(),
532 };
533
534 match packet.context {
535 constants::CONTEXT_LRRTT => {
536 match link.engine.handle_lrrtt(&packet.data, time::now()) {
537 Ok(link_actions) => {
538 let link_id = *link.engine.link_id();
539 LinkDataResult::Lrrtt { link_id, link_actions }
540 }
541 Err(e) => {
542 log::debug!("LRRTT handling failed: {}", e);
543 LinkDataResult::Error
544 }
545 }
546 }
547 constants::CONTEXT_LINKIDENTIFY => {
548 match link.engine.handle_identify(&packet.data) {
549 Ok(link_actions) => {
550 let link_id = *link.engine.link_id();
551 link.remote_identity = link.engine.remote_identity().cloned();
552 LinkDataResult::Identify { link_id, link_actions }
553 }
554 Err(e) => {
555 log::debug!("LINKIDENTIFY failed: {}", e);
556 LinkDataResult::Error
557 }
558 }
559 }
560 constants::CONTEXT_KEEPALIVE => {
561 let inbound_actions = link.engine.record_inbound(time::now());
562 let link_id = *link.engine.link_id();
563 LinkDataResult::Keepalive { link_id, inbound_actions }
564 }
565 constants::CONTEXT_LINKCLOSE => {
566 let teardown_actions = link.engine.handle_teardown();
567 let link_id = *link.engine.link_id();
568 LinkDataResult::LinkClose { link_id, teardown_actions }
569 }
570 constants::CONTEXT_CHANNEL => {
571 match link.engine.decrypt(&packet.data) {
572 Ok(plaintext) => {
573 let inbound_actions = link.engine.record_inbound(time::now());
574 let link_id = *link.engine.link_id();
575 LinkDataResult::Channel { link_id, inbound_actions, plaintext }
576 }
577 Err(_) => LinkDataResult::Error,
578 }
579 }
580 constants::CONTEXT_REQUEST => {
581 match link.engine.decrypt(&packet.data) {
582 Ok(plaintext) => {
583 let inbound_actions = link.engine.record_inbound(time::now());
584 let link_id = *link.engine.link_id();
585 LinkDataResult::Request { link_id, inbound_actions, plaintext }
586 }
587 Err(_) => LinkDataResult::Error,
588 }
589 }
590 constants::CONTEXT_RESPONSE => {
591 match link.engine.decrypt(&packet.data) {
592 Ok(plaintext) => {
593 let inbound_actions = link.engine.record_inbound(time::now());
594 let link_id = *link.engine.link_id();
595 LinkDataResult::Response { link_id, inbound_actions, plaintext }
596 }
597 Err(_) => LinkDataResult::Error,
598 }
599 }
600 constants::CONTEXT_RESOURCE_ADV => {
602 match link.engine.decrypt(&packet.data) {
603 Ok(plaintext) => {
604 let inbound_actions = link.engine.record_inbound(time::now());
605 let link_id = *link.engine.link_id();
606 LinkDataResult::ResourceAdv { link_id, inbound_actions, plaintext }
607 }
608 Err(_) => LinkDataResult::Error,
609 }
610 }
611 constants::CONTEXT_RESOURCE_REQ => {
612 match link.engine.decrypt(&packet.data) {
613 Ok(plaintext) => {
614 let inbound_actions = link.engine.record_inbound(time::now());
615 let link_id = *link.engine.link_id();
616 LinkDataResult::ResourceReq { link_id, inbound_actions, plaintext }
617 }
618 Err(_) => LinkDataResult::Error,
619 }
620 }
621 constants::CONTEXT_RESOURCE_HMU => {
622 match link.engine.decrypt(&packet.data) {
623 Ok(plaintext) => {
624 let inbound_actions = link.engine.record_inbound(time::now());
625 let link_id = *link.engine.link_id();
626 LinkDataResult::ResourceHmu { link_id, inbound_actions, plaintext }
627 }
628 Err(_) => LinkDataResult::Error,
629 }
630 }
631 constants::CONTEXT_RESOURCE => {
632 let inbound_actions = link.engine.record_inbound(time::now());
634 let link_id = *link.engine.link_id();
635 LinkDataResult::ResourcePart { link_id, inbound_actions, raw_data: packet.data.clone() }
636 }
637 constants::CONTEXT_RESOURCE_PRF => {
638 match link.engine.decrypt(&packet.data) {
639 Ok(plaintext) => {
640 let inbound_actions = link.engine.record_inbound(time::now());
641 let link_id = *link.engine.link_id();
642 LinkDataResult::ResourcePrf { link_id, inbound_actions, plaintext }
643 }
644 Err(_) => LinkDataResult::Error,
645 }
646 }
647 constants::CONTEXT_RESOURCE_ICL => {
648 let _ = link.engine.decrypt(&packet.data); let inbound_actions = link.engine.record_inbound(time::now());
650 let link_id = *link.engine.link_id();
651 LinkDataResult::ResourceIcl { link_id, inbound_actions }
652 }
653 constants::CONTEXT_RESOURCE_RCL => {
654 let _ = link.engine.decrypt(&packet.data); let inbound_actions = link.engine.record_inbound(time::now());
656 let link_id = *link.engine.link_id();
657 LinkDataResult::ResourceRcl { link_id, inbound_actions }
658 }
659 _ => {
660 match link.engine.decrypt(&packet.data) {
661 Ok(plaintext) => {
662 let inbound_actions = link.engine.record_inbound(time::now());
663 let link_id = *link.engine.link_id();
664 LinkDataResult::Generic { link_id, inbound_actions, plaintext, context: packet.context }
665 }
666 Err(_) => LinkDataResult::Error,
667 }
668 }
669 }
670 }; let mut actions = Vec::new();
674 match result {
675 LinkDataResult::Lrrtt { link_id, link_actions } => {
676 actions.extend(self.process_link_actions(&link_id, &link_actions));
677 if let Some(link) = self.links.get_mut(&link_id) {
679 if link.engine.state() == LinkState::Active {
680 let rtt = link.engine.rtt().unwrap_or(1.0);
681 link.channel = Some(Channel::new(rtt));
682 }
683 }
684 }
685 LinkDataResult::Identify { link_id, link_actions } => {
686 actions.extend(self.process_link_actions(&link_id, &link_actions));
687 }
688 LinkDataResult::Keepalive { link_id, inbound_actions } => {
689 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
690 }
691 LinkDataResult::LinkClose { link_id, teardown_actions } => {
692 actions.extend(self.process_link_actions(&link_id, &teardown_actions));
693 }
694 LinkDataResult::Channel { link_id, inbound_actions, plaintext } => {
695 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
696 if let Some(link) = self.links.get_mut(&link_id) {
698 if let Some(ref mut channel) = link.channel {
699 let chan_actions = channel.receive(&plaintext, time::now());
700 let _ = link;
702 actions.extend(self.process_channel_actions(&link_id, chan_actions, rng));
703 }
704 }
705 }
706 LinkDataResult::Request { link_id, inbound_actions, plaintext } => {
707 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
708 actions.extend(self.handle_request(&link_id, &plaintext, rng));
709 }
710 LinkDataResult::Response { link_id, inbound_actions, plaintext } => {
711 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
712 actions.extend(self.handle_response(&link_id, &plaintext));
714 }
715 LinkDataResult::Generic { link_id, inbound_actions, plaintext, context } => {
716 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
717 actions.push(LinkManagerAction::LinkDataReceived {
718 link_id,
719 context,
720 data: plaintext,
721 });
722 }
723 LinkDataResult::ResourceAdv { link_id, inbound_actions, plaintext } => {
724 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
725 actions.extend(self.handle_resource_adv(&link_id, &plaintext, rng));
726 }
727 LinkDataResult::ResourceReq { link_id, inbound_actions, plaintext } => {
728 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
729 actions.extend(self.handle_resource_req(&link_id, &plaintext, rng));
730 }
731 LinkDataResult::ResourceHmu { link_id, inbound_actions, plaintext } => {
732 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
733 actions.extend(self.handle_resource_hmu(&link_id, &plaintext, rng));
734 }
735 LinkDataResult::ResourcePart { link_id, inbound_actions, raw_data } => {
736 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
737 actions.extend(self.handle_resource_part(&link_id, &raw_data, rng));
738 }
739 LinkDataResult::ResourcePrf { link_id, inbound_actions, plaintext } => {
740 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
741 actions.extend(self.handle_resource_prf(&link_id, &plaintext));
742 }
743 LinkDataResult::ResourceIcl { link_id, inbound_actions } => {
744 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
745 actions.extend(self.handle_resource_icl(&link_id));
746 }
747 LinkDataResult::ResourceRcl { link_id, inbound_actions } => {
748 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
749 actions.extend(self.handle_resource_rcl(&link_id));
750 }
751 LinkDataResult::Error => {}
752 }
753
754 actions
755 }
756
757 fn handle_request(
759 &mut self,
760 link_id: &LinkId,
761 plaintext: &[u8],
762 rng: &mut dyn Rng,
763 ) -> Vec<LinkManagerAction> {
764 use rns_core::msgpack::{self, Value};
765
766 let arr = match msgpack::unpack_exact(plaintext) {
768 Ok(Value::Array(arr)) if arr.len() >= 3 => arr,
769 _ => return Vec::new(),
770 };
771
772 let path_hash_bytes = match &arr[1] {
773 Value::Bin(b) if b.len() == 16 => b,
774 _ => return Vec::new(),
775 };
776 let mut path_hash = [0u8; 16];
777 path_hash.copy_from_slice(path_hash_bytes);
778
779 let request_id = rns_core::hash::truncated_hash(plaintext);
781
782 let request_data = msgpack::pack(&arr[2]);
784
785 if self.management_paths.contains(&path_hash) {
787 let remote_identity = self.links.get(link_id)
788 .and_then(|l| l.remote_identity)
789 .map(|(h, k)| (h, k));
790 return vec![LinkManagerAction::ManagementRequest {
791 link_id: *link_id,
792 path_hash,
793 data: request_data,
794 request_id,
795 remote_identity,
796 }];
797 }
798
799 let handler_idx = self.request_handlers.iter().position(|h| h.path_hash == path_hash);
801 let handler_idx = match handler_idx {
802 Some(i) => i,
803 None => return Vec::new(),
804 };
805
806 let remote_identity = self.links.get(link_id).and_then(|l| l.remote_identity.as_ref());
808 let handler = &self.request_handlers[handler_idx];
809 if let Some(ref allowed) = handler.allowed_list {
810 match remote_identity {
811 Some((identity_hash, _)) => {
812 if !allowed.contains(identity_hash) {
813 log::debug!("Request denied: identity not in allowed list");
814 return Vec::new();
815 }
816 }
817 None => {
818 log::debug!("Request denied: peer not identified");
819 return Vec::new();
820 }
821 }
822 }
823
824 let path = handler.path.clone();
826 let response = (handler.handler)(*link_id, &path, &request_data, remote_identity);
827
828 let mut actions = Vec::new();
829 if let Some(response_data) = response {
830 actions.extend(self.build_response_packet(link_id, &request_id, &response_data, rng));
831 }
832
833 actions
834 }
835
836 fn build_response_packet(
839 &self,
840 link_id: &LinkId,
841 request_id: &[u8; 16],
842 response_data: &[u8],
843 rng: &mut dyn Rng,
844 ) -> Vec<LinkManagerAction> {
845 use rns_core::msgpack::{self, Value};
846
847 let response_value = msgpack::unpack_exact(response_data)
849 .unwrap_or_else(|_| Value::Bin(response_data.to_vec()));
850
851 let response_array = Value::Array(vec![
852 Value::Bin(request_id.to_vec()),
853 response_value,
854 ]);
855 let response_plaintext = msgpack::pack(&response_array);
856
857 let mut actions = Vec::new();
858 if let Some(link) = self.links.get(link_id) {
859 if let Ok(encrypted) = link.engine.encrypt(&response_plaintext, rng) {
860 let flags = PacketFlags {
861 header_type: constants::HEADER_1,
862 context_flag: constants::FLAG_UNSET,
863 transport_type: constants::TRANSPORT_BROADCAST,
864 destination_type: constants::DESTINATION_LINK,
865 packet_type: constants::PACKET_TYPE_DATA,
866 };
867 if let Ok(pkt) = RawPacket::pack(
868 flags, 0, link_id, None, constants::CONTEXT_RESPONSE, &encrypted,
869 ) {
870 actions.push(LinkManagerAction::SendPacket {
871 raw: pkt.raw,
872 dest_type: constants::DESTINATION_LINK,
873 attached_interface: None,
874 });
875 }
876 }
877 }
878 actions
879 }
880
881 pub fn send_management_response(
884 &self,
885 link_id: &LinkId,
886 request_id: &[u8; 16],
887 response_data: &[u8],
888 rng: &mut dyn Rng,
889 ) -> Vec<LinkManagerAction> {
890 self.build_response_packet(link_id, request_id, response_data, rng)
891 }
892
893 pub fn send_request(
901 &self,
902 link_id: &LinkId,
903 path: &str,
904 data: &[u8],
905 rng: &mut dyn Rng,
906 ) -> Vec<LinkManagerAction> {
907 use rns_core::msgpack::{self, Value};
908
909 let link = match self.links.get(link_id) {
910 Some(l) => l,
911 None => return Vec::new(),
912 };
913
914 if link.engine.state() != LinkState::Active {
915 return Vec::new();
916 }
917
918 let path_hash = compute_path_hash(path);
919
920 let data_value = msgpack::unpack_exact(data)
922 .unwrap_or_else(|_| Value::Bin(data.to_vec()));
923
924 let request_array = Value::Array(vec![
926 Value::Float(time::now()),
927 Value::Bin(path_hash.to_vec()),
928 data_value,
929 ]);
930 let plaintext = msgpack::pack(&request_array);
931
932 let encrypted = match link.engine.encrypt(&plaintext, rng) {
933 Ok(e) => e,
934 Err(_) => return Vec::new(),
935 };
936
937 let flags = PacketFlags {
938 header_type: constants::HEADER_1,
939 context_flag: constants::FLAG_UNSET,
940 transport_type: constants::TRANSPORT_BROADCAST,
941 destination_type: constants::DESTINATION_LINK,
942 packet_type: constants::PACKET_TYPE_DATA,
943 };
944
945 let mut actions = Vec::new();
946 if let Ok(pkt) = RawPacket::pack(
947 flags, 0, link_id, None, constants::CONTEXT_REQUEST, &encrypted,
948 ) {
949 actions.push(LinkManagerAction::SendPacket {
950 raw: pkt.raw,
951 dest_type: constants::DESTINATION_LINK,
952 attached_interface: None,
953 });
954 }
955 actions
956 }
957
958 pub fn send_on_link(
960 &self,
961 link_id: &LinkId,
962 plaintext: &[u8],
963 context: u8,
964 rng: &mut dyn Rng,
965 ) -> Vec<LinkManagerAction> {
966 let link = match self.links.get(link_id) {
967 Some(l) => l,
968 None => return Vec::new(),
969 };
970
971 if link.engine.state() != LinkState::Active {
972 return Vec::new();
973 }
974
975 let encrypted = match link.engine.encrypt(plaintext, rng) {
976 Ok(e) => e,
977 Err(_) => return Vec::new(),
978 };
979
980 let flags = PacketFlags {
981 header_type: constants::HEADER_1,
982 context_flag: constants::FLAG_UNSET,
983 transport_type: constants::TRANSPORT_BROADCAST,
984 destination_type: constants::DESTINATION_LINK,
985 packet_type: constants::PACKET_TYPE_DATA,
986 };
987
988 let mut actions = Vec::new();
989 if let Ok(pkt) = RawPacket::pack(
990 flags, 0, link_id, None, context, &encrypted,
991 ) {
992 actions.push(LinkManagerAction::SendPacket {
993 raw: pkt.raw,
994 dest_type: constants::DESTINATION_LINK,
995 attached_interface: None,
996 });
997 }
998 actions
999 }
1000
1001 pub fn identify(
1003 &self,
1004 link_id: &LinkId,
1005 identity: &rns_crypto::identity::Identity,
1006 rng: &mut dyn Rng,
1007 ) -> Vec<LinkManagerAction> {
1008 let link = match self.links.get(link_id) {
1009 Some(l) => l,
1010 None => return Vec::new(),
1011 };
1012
1013 let encrypted = match link.engine.build_identify(identity, rng) {
1014 Ok(e) => e,
1015 Err(_) => return Vec::new(),
1016 };
1017
1018 let flags = PacketFlags {
1019 header_type: constants::HEADER_1,
1020 context_flag: constants::FLAG_UNSET,
1021 transport_type: constants::TRANSPORT_BROADCAST,
1022 destination_type: constants::DESTINATION_LINK,
1023 packet_type: constants::PACKET_TYPE_DATA,
1024 };
1025
1026 let mut actions = Vec::new();
1027 if let Ok(pkt) = RawPacket::pack(
1028 flags, 0, link_id, None, constants::CONTEXT_LINKIDENTIFY, &encrypted,
1029 ) {
1030 actions.push(LinkManagerAction::SendPacket {
1031 raw: pkt.raw,
1032 dest_type: constants::DESTINATION_LINK,
1033 attached_interface: None,
1034 });
1035 }
1036 actions
1037 }
1038
1039 pub fn teardown_link(&mut self, link_id: &LinkId) -> Vec<LinkManagerAction> {
1041 let link = match self.links.get_mut(link_id) {
1042 Some(l) => l,
1043 None => return Vec::new(),
1044 };
1045
1046 let teardown_actions = link.engine.teardown();
1047 if let Some(ref mut channel) = link.channel {
1048 channel.shutdown();
1049 }
1050
1051 let mut actions = self.process_link_actions(link_id, &teardown_actions);
1052
1053 let flags = PacketFlags {
1055 header_type: constants::HEADER_1,
1056 context_flag: constants::FLAG_UNSET,
1057 transport_type: constants::TRANSPORT_BROADCAST,
1058 destination_type: constants::DESTINATION_LINK,
1059 packet_type: constants::PACKET_TYPE_DATA,
1060 };
1061 if let Ok(pkt) = RawPacket::pack(
1062 flags, 0, link_id, None, constants::CONTEXT_LINKCLOSE, &[],
1063 ) {
1064 actions.push(LinkManagerAction::SendPacket {
1065 raw: pkt.raw,
1066 dest_type: constants::DESTINATION_LINK,
1067 attached_interface: None,
1068 });
1069 }
1070
1071 actions
1072 }
1073
1074 fn handle_response(
1076 &self,
1077 link_id: &LinkId,
1078 plaintext: &[u8],
1079 ) -> Vec<LinkManagerAction> {
1080 use rns_core::msgpack;
1081
1082 let arr = match msgpack::unpack_exact(plaintext) {
1084 Ok(msgpack::Value::Array(arr)) if arr.len() >= 2 => arr,
1085 _ => return Vec::new(),
1086 };
1087
1088 let request_id_bytes = match &arr[0] {
1089 msgpack::Value::Bin(b) if b.len() == 16 => b,
1090 _ => return Vec::new(),
1091 };
1092 let mut request_id = [0u8; 16];
1093 request_id.copy_from_slice(request_id_bytes);
1094
1095 let response_data = msgpack::pack(&arr[1]);
1096
1097 vec![LinkManagerAction::ResponseReceived {
1098 link_id: *link_id,
1099 request_id,
1100 data: response_data,
1101 }]
1102 }
1103
1104 fn handle_resource_adv(
1106 &mut self,
1107 link_id: &LinkId,
1108 adv_plaintext: &[u8],
1109 rng: &mut dyn Rng,
1110 ) -> Vec<LinkManagerAction> {
1111 let link = match self.links.get_mut(link_id) {
1112 Some(l) => l,
1113 None => return Vec::new(),
1114 };
1115
1116 let link_rtt = link.engine.rtt().unwrap_or(1.0);
1117 let now = time::now();
1118
1119 let receiver = match ResourceReceiver::from_advertisement(
1120 adv_plaintext,
1121 constants::RESOURCE_SDU,
1122 link_rtt,
1123 now,
1124 None,
1125 None,
1126 ) {
1127 Ok(r) => r,
1128 Err(e) => {
1129 log::debug!("Resource ADV rejected: {}", e);
1130 return Vec::new();
1131 }
1132 };
1133
1134 let strategy = link.resource_strategy;
1135 let resource_hash = receiver.resource_hash.clone();
1136 let transfer_size = receiver.transfer_size;
1137 let has_metadata = receiver.has_metadata;
1138
1139 match strategy {
1140 ResourceStrategy::AcceptNone => {
1141 let reject_actions = {
1143 let mut r = receiver;
1144 r.reject()
1145 };
1146 self.process_resource_actions(link_id, reject_actions, rng)
1147 }
1148 ResourceStrategy::AcceptAll => {
1149 link.incoming_resources.push(receiver);
1150 let idx = link.incoming_resources.len() - 1;
1151 let resource_actions = link.incoming_resources[idx].accept(now);
1152 let _ = link;
1153 self.process_resource_actions(link_id, resource_actions, rng)
1154 }
1155 ResourceStrategy::AcceptApp => {
1156 link.incoming_resources.push(receiver);
1157 vec![LinkManagerAction::ResourceAcceptQuery {
1159 link_id: *link_id,
1160 resource_hash,
1161 transfer_size,
1162 has_metadata,
1163 }]
1164 }
1165 }
1166 }
1167
1168 pub fn accept_resource(
1170 &mut self,
1171 link_id: &LinkId,
1172 resource_hash: &[u8],
1173 accept: bool,
1174 rng: &mut dyn Rng,
1175 ) -> Vec<LinkManagerAction> {
1176 let link = match self.links.get_mut(link_id) {
1177 Some(l) => l,
1178 None => return Vec::new(),
1179 };
1180
1181 let now = time::now();
1182 let idx = link.incoming_resources.iter().position(|r| r.resource_hash == resource_hash);
1183 let idx = match idx {
1184 Some(i) => i,
1185 None => return Vec::new(),
1186 };
1187
1188 let resource_actions = if accept {
1189 link.incoming_resources[idx].accept(now)
1190 } else {
1191 link.incoming_resources[idx].reject()
1192 };
1193
1194 let _ = link;
1195 self.process_resource_actions(link_id, resource_actions, rng)
1196 }
1197
1198 fn handle_resource_req(
1200 &mut self,
1201 link_id: &LinkId,
1202 plaintext: &[u8],
1203 rng: &mut dyn Rng,
1204 ) -> Vec<LinkManagerAction> {
1205 let link = match self.links.get_mut(link_id) {
1206 Some(l) => l,
1207 None => return Vec::new(),
1208 };
1209
1210 let now = time::now();
1211 let mut all_actions = Vec::new();
1212 for sender in &mut link.outgoing_resources {
1213 let resource_actions = sender.handle_request(plaintext, now);
1214 if !resource_actions.is_empty() {
1215 all_actions.extend(resource_actions);
1216 break;
1217 }
1218 }
1219
1220 let _ = link;
1221 self.process_resource_actions(link_id, all_actions, rng)
1222 }
1223
1224 fn handle_resource_hmu(
1226 &mut self,
1227 link_id: &LinkId,
1228 plaintext: &[u8],
1229 rng: &mut dyn Rng,
1230 ) -> Vec<LinkManagerAction> {
1231 let link = match self.links.get_mut(link_id) {
1232 Some(l) => l,
1233 None => return Vec::new(),
1234 };
1235
1236 let now = time::now();
1237 let mut all_actions = Vec::new();
1238 for receiver in &mut link.incoming_resources {
1239 let resource_actions = receiver.handle_hashmap_update(plaintext, now);
1240 if !resource_actions.is_empty() {
1241 all_actions.extend(resource_actions);
1242 break;
1243 }
1244 }
1245
1246 let _ = link;
1247 self.process_resource_actions(link_id, all_actions, rng)
1248 }
1249
1250 fn handle_resource_part(
1252 &mut self,
1253 link_id: &LinkId,
1254 raw_data: &[u8],
1255 rng: &mut dyn Rng,
1256 ) -> Vec<LinkManagerAction> {
1257 let link = match self.links.get_mut(link_id) {
1258 Some(l) => l,
1259 None => return Vec::new(),
1260 };
1261
1262 let now = time::now();
1263 let mut all_actions = Vec::new();
1264 let mut assemble_idx = None;
1265
1266 for (idx, receiver) in link.incoming_resources.iter_mut().enumerate() {
1267 let resource_actions = receiver.receive_part(raw_data, now);
1268 if !resource_actions.is_empty() {
1269 if receiver.received_count == receiver.total_parts {
1271 assemble_idx = Some(idx);
1272 }
1273 all_actions.extend(resource_actions);
1274 break;
1275 }
1276 }
1277
1278 if let Some(idx) = assemble_idx {
1280 let decrypt_fn = |ciphertext: &[u8]| -> Result<Vec<u8>, ()> {
1281 link.engine.decrypt(ciphertext).map_err(|_| ())
1282 };
1283 let assemble_actions = link.incoming_resources[idx].assemble(&decrypt_fn, &NoopCompressor);
1284 all_actions.extend(assemble_actions);
1285 }
1286
1287 let _ = link;
1288 self.process_resource_actions(link_id, all_actions, rng)
1289 }
1290
1291 fn handle_resource_prf(
1293 &mut self,
1294 link_id: &LinkId,
1295 plaintext: &[u8],
1296 ) -> Vec<LinkManagerAction> {
1297 let link = match self.links.get_mut(link_id) {
1298 Some(l) => l,
1299 None => return Vec::new(),
1300 };
1301
1302 let now = time::now();
1303 let mut result_actions = Vec::new();
1304 for sender in &mut link.outgoing_resources {
1305 let resource_actions = sender.handle_proof(plaintext, now);
1306 if !resource_actions.is_empty() {
1307 result_actions.extend(resource_actions);
1308 break;
1309 }
1310 }
1311
1312 let mut actions = Vec::new();
1314 for ra in result_actions {
1315 match ra {
1316 ResourceAction::Completed => {
1317 actions.push(LinkManagerAction::ResourceCompleted { link_id: *link_id });
1318 }
1319 ResourceAction::Failed(e) => {
1320 actions.push(LinkManagerAction::ResourceFailed {
1321 link_id: *link_id,
1322 error: format!("{}", e),
1323 });
1324 }
1325 _ => {}
1326 }
1327 }
1328
1329 link.outgoing_resources.retain(|s| {
1331 s.status < rns_core::resource::ResourceStatus::Complete
1332 });
1333
1334 actions
1335 }
1336
1337 fn handle_resource_icl(
1339 &mut self,
1340 link_id: &LinkId,
1341 ) -> Vec<LinkManagerAction> {
1342 let link = match self.links.get_mut(link_id) {
1343 Some(l) => l,
1344 None => return Vec::new(),
1345 };
1346
1347 let mut actions = Vec::new();
1348 for receiver in &mut link.incoming_resources {
1349 let ra = receiver.handle_cancel();
1350 for a in ra {
1351 if let ResourceAction::Failed(ref e) = a {
1352 actions.push(LinkManagerAction::ResourceFailed {
1353 link_id: *link_id,
1354 error: format!("{}", e),
1355 });
1356 }
1357 }
1358 }
1359 link.incoming_resources.retain(|r| {
1360 r.status < rns_core::resource::ResourceStatus::Complete
1361 });
1362 actions
1363 }
1364
1365 fn handle_resource_rcl(
1367 &mut self,
1368 link_id: &LinkId,
1369 ) -> Vec<LinkManagerAction> {
1370 let link = match self.links.get_mut(link_id) {
1371 Some(l) => l,
1372 None => return Vec::new(),
1373 };
1374
1375 let mut actions = Vec::new();
1376 for sender in &mut link.outgoing_resources {
1377 let ra = sender.handle_reject();
1378 for a in ra {
1379 if let ResourceAction::Failed(ref e) = a {
1380 actions.push(LinkManagerAction::ResourceFailed {
1381 link_id: *link_id,
1382 error: format!("{}", e),
1383 });
1384 }
1385 }
1386 }
1387 link.outgoing_resources.retain(|s| {
1388 s.status < rns_core::resource::ResourceStatus::Complete
1389 });
1390 actions
1391 }
1392
1393 fn process_resource_actions(
1395 &self,
1396 link_id: &LinkId,
1397 actions: Vec<ResourceAction>,
1398 rng: &mut dyn Rng,
1399 ) -> Vec<LinkManagerAction> {
1400 let link = match self.links.get(link_id) {
1401 Some(l) => l,
1402 None => return Vec::new(),
1403 };
1404
1405 let mut result = Vec::new();
1406 for action in actions {
1407 match action {
1408 ResourceAction::SendAdvertisement(data) => {
1409 if let Ok(encrypted) = link.engine.encrypt(&data, rng) {
1411 result.extend(self.build_link_packet(
1412 link_id, constants::CONTEXT_RESOURCE_ADV, &encrypted,
1413 ));
1414 }
1415 }
1416 ResourceAction::SendPart(data) => {
1417 result.extend(self.build_link_packet(
1419 link_id, constants::CONTEXT_RESOURCE, &data,
1420 ));
1421 }
1422 ResourceAction::SendRequest(data) => {
1423 if let Ok(encrypted) = link.engine.encrypt(&data, rng) {
1424 result.extend(self.build_link_packet(
1425 link_id, constants::CONTEXT_RESOURCE_REQ, &encrypted,
1426 ));
1427 }
1428 }
1429 ResourceAction::SendHmu(data) => {
1430 if let Ok(encrypted) = link.engine.encrypt(&data, rng) {
1431 result.extend(self.build_link_packet(
1432 link_id, constants::CONTEXT_RESOURCE_HMU, &encrypted,
1433 ));
1434 }
1435 }
1436 ResourceAction::SendProof(data) => {
1437 if let Ok(encrypted) = link.engine.encrypt(&data, rng) {
1438 result.extend(self.build_link_packet(
1439 link_id, constants::CONTEXT_RESOURCE_PRF, &encrypted,
1440 ));
1441 }
1442 }
1443 ResourceAction::SendCancelInitiator(data) => {
1444 if let Ok(encrypted) = link.engine.encrypt(&data, rng) {
1445 result.extend(self.build_link_packet(
1446 link_id, constants::CONTEXT_RESOURCE_ICL, &encrypted,
1447 ));
1448 }
1449 }
1450 ResourceAction::SendCancelReceiver(data) => {
1451 if let Ok(encrypted) = link.engine.encrypt(&data, rng) {
1452 result.extend(self.build_link_packet(
1453 link_id, constants::CONTEXT_RESOURCE_RCL, &encrypted,
1454 ));
1455 }
1456 }
1457 ResourceAction::DataReceived { data, metadata } => {
1458 result.push(LinkManagerAction::ResourceReceived {
1459 link_id: *link_id,
1460 data,
1461 metadata,
1462 });
1463 }
1464 ResourceAction::Completed => {
1465 result.push(LinkManagerAction::ResourceCompleted { link_id: *link_id });
1466 }
1467 ResourceAction::Failed(e) => {
1468 result.push(LinkManagerAction::ResourceFailed {
1469 link_id: *link_id,
1470 error: format!("{}", e),
1471 });
1472 }
1473 ResourceAction::ProgressUpdate { received, total } => {
1474 result.push(LinkManagerAction::ResourceProgress {
1475 link_id: *link_id,
1476 received,
1477 total,
1478 });
1479 }
1480 }
1481 }
1482 result
1483 }
1484
1485 fn build_link_packet(
1487 &self,
1488 link_id: &LinkId,
1489 context: u8,
1490 data: &[u8],
1491 ) -> Vec<LinkManagerAction> {
1492 let flags = PacketFlags {
1493 header_type: constants::HEADER_1,
1494 context_flag: constants::FLAG_UNSET,
1495 transport_type: constants::TRANSPORT_BROADCAST,
1496 destination_type: constants::DESTINATION_LINK,
1497 packet_type: constants::PACKET_TYPE_DATA,
1498 };
1499 let mut actions = Vec::new();
1500 if let Ok(pkt) = RawPacket::pack(flags, 0, link_id, None, context, data) {
1501 actions.push(LinkManagerAction::SendPacket {
1502 raw: pkt.raw,
1503 dest_type: constants::DESTINATION_LINK,
1504 attached_interface: None,
1505 });
1506 }
1507 actions
1508 }
1509
1510 pub fn send_resource(
1512 &mut self,
1513 link_id: &LinkId,
1514 data: &[u8],
1515 metadata: Option<&[u8]>,
1516 rng: &mut dyn Rng,
1517 ) -> Vec<LinkManagerAction> {
1518 let link = match self.links.get_mut(link_id) {
1519 Some(l) => l,
1520 None => return Vec::new(),
1521 };
1522
1523 if link.engine.state() != LinkState::Active {
1524 return Vec::new();
1525 }
1526
1527 let link_rtt = link.engine.rtt().unwrap_or(1.0);
1528 let now = time::now();
1529
1530 let enc_rng = std::cell::RefCell::new(rns_crypto::OsRng);
1533 let encrypt_fn = |plaintext: &[u8]| -> Vec<u8> {
1534 link.engine.encrypt(plaintext, &mut *enc_rng.borrow_mut()).unwrap_or_else(|_| plaintext.to_vec())
1535 };
1536
1537 let sender = match ResourceSender::new(
1538 data,
1539 metadata,
1540 constants::RESOURCE_SDU,
1541 &encrypt_fn,
1542 &NoopCompressor,
1543 rng,
1544 now,
1545 false, false, None, 1, 1, None, link_rtt,
1552 6.0, ) {
1554 Ok(s) => s,
1555 Err(e) => {
1556 log::debug!("Failed to create ResourceSender: {}", e);
1557 return Vec::new();
1558 }
1559 };
1560
1561 let mut sender = sender;
1562 let adv_actions = sender.advertise(now);
1563 link.outgoing_resources.push(sender);
1564
1565 let _ = link;
1566 self.process_resource_actions(link_id, adv_actions, rng)
1567 }
1568
1569 pub fn set_resource_strategy(&mut self, link_id: &LinkId, strategy: ResourceStrategy) {
1571 if let Some(link) = self.links.get_mut(link_id) {
1572 link.resource_strategy = strategy;
1573 }
1574 }
1575
1576 pub fn send_channel_message(
1578 &mut self,
1579 link_id: &LinkId,
1580 msgtype: u16,
1581 payload: &[u8],
1582 rng: &mut dyn Rng,
1583 ) -> Vec<LinkManagerAction> {
1584 let link = match self.links.get_mut(link_id) {
1585 Some(l) => l,
1586 None => return Vec::new(),
1587 };
1588
1589 let channel = match link.channel {
1590 Some(ref mut ch) => ch,
1591 None => return Vec::new(),
1592 };
1593
1594 let link_mdu = constants::MDU; let now = time::now();
1596 let chan_actions = match channel.send(msgtype, payload, now, link_mdu) {
1597 Ok(a) => a,
1598 Err(e) => {
1599 log::debug!("Channel send failed: {:?}", e);
1600 return Vec::new();
1601 }
1602 };
1603
1604 let _ = link;
1605 self.process_channel_actions(link_id, chan_actions, rng)
1606 }
1607
1608 pub fn tick(&mut self, rng: &mut dyn Rng) -> Vec<LinkManagerAction> {
1610 let now = time::now();
1611 let mut all_actions = Vec::new();
1612
1613 let link_ids: Vec<LinkId> = self.links.keys().copied().collect();
1615
1616 for link_id in &link_ids {
1617 let link = match self.links.get_mut(link_id) {
1618 Some(l) => l,
1619 None => continue,
1620 };
1621
1622 let tick_actions = link.engine.tick(now);
1624 all_actions.extend(self.process_link_actions(link_id, &tick_actions));
1625
1626 let link = match self.links.get_mut(link_id) {
1628 Some(l) => l,
1629 None => continue,
1630 };
1631 if link.engine.needs_keepalive(now) {
1632 let flags = PacketFlags {
1634 header_type: constants::HEADER_1,
1635 context_flag: constants::FLAG_UNSET,
1636 transport_type: constants::TRANSPORT_BROADCAST,
1637 destination_type: constants::DESTINATION_LINK,
1638 packet_type: constants::PACKET_TYPE_DATA,
1639 };
1640 if let Ok(pkt) = RawPacket::pack(
1641 flags, 0, link_id, None, constants::CONTEXT_KEEPALIVE, &[],
1642 ) {
1643 all_actions.push(LinkManagerAction::SendPacket {
1644 raw: pkt.raw,
1645 dest_type: constants::DESTINATION_LINK,
1646 attached_interface: None,
1647 });
1648 link.engine.record_outbound(now, true);
1649 }
1650 }
1651 }
1652
1653 for link_id in &link_ids {
1655 let link = match self.links.get_mut(link_id) {
1656 Some(l) => l,
1657 None => continue,
1658 };
1659
1660 let mut sender_actions = Vec::new();
1662 for sender in &mut link.outgoing_resources {
1663 sender_actions.extend(sender.tick(now));
1664 }
1665
1666 let mut receiver_actions = Vec::new();
1668 for receiver in &mut link.incoming_resources {
1669 let decrypt_fn = |ciphertext: &[u8]| -> Result<Vec<u8>, ()> {
1670 link.engine.decrypt(ciphertext).map_err(|_| ())
1671 };
1672 receiver_actions.extend(receiver.tick(now, &decrypt_fn, &NoopCompressor));
1673 }
1674
1675 link.outgoing_resources.retain(|s| {
1677 s.status < rns_core::resource::ResourceStatus::Complete
1678 });
1679 link.incoming_resources.retain(|r| {
1680 r.status < rns_core::resource::ResourceStatus::Assembling
1681 });
1682
1683 let _ = link;
1684 all_actions.extend(self.process_resource_actions(link_id, sender_actions, rng));
1685 all_actions.extend(self.process_resource_actions(link_id, receiver_actions, rng));
1686 }
1687
1688 let closed: Vec<LinkId> = self.links.iter()
1690 .filter(|(_, l)| l.engine.state() == LinkState::Closed)
1691 .map(|(id, _)| *id)
1692 .collect();
1693 for id in closed {
1694 self.links.remove(&id);
1695 all_actions.push(LinkManagerAction::DeregisterLinkDest { link_id: id });
1696 }
1697
1698 all_actions
1699 }
1700
1701 pub fn is_link_destination(&self, dest_hash: &[u8; 16]) -> bool {
1703 self.links.contains_key(dest_hash) || self.link_destinations.contains_key(dest_hash)
1704 }
1705
1706 pub fn link_state(&self, link_id: &LinkId) -> Option<LinkState> {
1708 self.links.get(link_id).map(|l| l.engine.state())
1709 }
1710
1711 pub fn link_rtt(&self, link_id: &LinkId) -> Option<f64> {
1713 self.links.get(link_id).and_then(|l| l.engine.rtt())
1714 }
1715
1716 pub fn link_count(&self) -> usize {
1718 self.links.len()
1719 }
1720
1721 pub fn link_entries(&self) -> Vec<crate::event::LinkInfoEntry> {
1723 self.links
1724 .iter()
1725 .map(|(link_id, managed)| {
1726 let state = match managed.engine.state() {
1727 LinkState::Pending => "pending",
1728 LinkState::Handshake => "handshake",
1729 LinkState::Active => "active",
1730 LinkState::Stale => "stale",
1731 LinkState::Closed => "closed",
1732 };
1733 crate::event::LinkInfoEntry {
1734 link_id: *link_id,
1735 state: state.to_string(),
1736 is_initiator: managed.engine.is_initiator(),
1737 dest_hash: managed.dest_hash,
1738 remote_identity: managed.remote_identity.as_ref().map(|(h, _)| *h),
1739 rtt: managed.engine.rtt(),
1740 }
1741 })
1742 .collect()
1743 }
1744
1745 pub fn resource_entries(&self) -> Vec<crate::event::ResourceInfoEntry> {
1747 let mut entries = Vec::new();
1748 for (link_id, managed) in &self.links {
1749 for recv in &managed.incoming_resources {
1750 let (received, total) = recv.progress();
1751 entries.push(crate::event::ResourceInfoEntry {
1752 link_id: *link_id,
1753 direction: "incoming".to_string(),
1754 total_parts: total,
1755 transferred_parts: received,
1756 complete: received >= total && total > 0,
1757 });
1758 }
1759 for send in &managed.outgoing_resources {
1760 let total = send.total_parts();
1761 let sent = send.sent_parts;
1762 entries.push(crate::event::ResourceInfoEntry {
1763 link_id: *link_id,
1764 direction: "outgoing".to_string(),
1765 total_parts: total,
1766 transferred_parts: sent,
1767 complete: sent >= total && total > 0,
1768 });
1769 }
1770 }
1771 entries
1772 }
1773
1774 fn process_link_actions(&self, link_id: &LinkId, actions: &[LinkAction]) -> Vec<LinkManagerAction> {
1776 let mut result = Vec::new();
1777 for action in actions {
1778 match action {
1779 LinkAction::StateChanged { new_state, reason, .. } => {
1780 match new_state {
1781 LinkState::Closed => {
1782 result.push(LinkManagerAction::LinkClosed {
1783 link_id: *link_id,
1784 reason: *reason,
1785 });
1786 }
1787 _ => {}
1788 }
1789 }
1790 LinkAction::LinkEstablished { rtt, is_initiator, .. } => {
1791 let dest_hash = self.links.get(link_id)
1792 .map(|l| l.dest_hash)
1793 .unwrap_or([0u8; 16]);
1794 result.push(LinkManagerAction::LinkEstablished {
1795 link_id: *link_id,
1796 dest_hash,
1797 rtt: *rtt,
1798 is_initiator: *is_initiator,
1799 });
1800 }
1801 LinkAction::RemoteIdentified { identity_hash, public_key, .. } => {
1802 result.push(LinkManagerAction::RemoteIdentified {
1803 link_id: *link_id,
1804 identity_hash: *identity_hash,
1805 public_key: *public_key,
1806 });
1807 }
1808 LinkAction::DataReceived { .. } => {
1809 }
1811 }
1812 }
1813 result
1814 }
1815
1816 fn process_channel_actions(
1818 &self,
1819 link_id: &LinkId,
1820 actions: Vec<rns_core::channel::ChannelAction>,
1821 rng: &mut dyn Rng,
1822 ) -> Vec<LinkManagerAction> {
1823 let mut result = Vec::new();
1824 for action in actions {
1825 match action {
1826 rns_core::channel::ChannelAction::SendOnLink { raw } => {
1827 if let Some(link) = self.links.get(link_id) {
1829 if let Ok(encrypted) = link.engine.encrypt(&raw, rng) {
1830 let flags = PacketFlags {
1831 header_type: constants::HEADER_1,
1832 context_flag: constants::FLAG_UNSET,
1833 transport_type: constants::TRANSPORT_BROADCAST,
1834 destination_type: constants::DESTINATION_LINK,
1835 packet_type: constants::PACKET_TYPE_DATA,
1836 };
1837 if let Ok(pkt) = RawPacket::pack(
1838 flags, 0, link_id, None, constants::CONTEXT_CHANNEL, &encrypted,
1839 ) {
1840 result.push(LinkManagerAction::SendPacket {
1841 raw: pkt.raw,
1842 dest_type: constants::DESTINATION_LINK,
1843 attached_interface: None,
1844 });
1845 }
1846 }
1847 }
1848 }
1849 rns_core::channel::ChannelAction::MessageReceived { msgtype, payload, .. } => {
1850 result.push(LinkManagerAction::ChannelMessageReceived {
1851 link_id: *link_id,
1852 msgtype,
1853 payload,
1854 });
1855 }
1856 rns_core::channel::ChannelAction::TeardownLink => {
1857 result.push(LinkManagerAction::LinkClosed {
1858 link_id: *link_id,
1859 reason: Some(TeardownReason::Timeout),
1860 });
1861 }
1862 }
1863 }
1864 result
1865 }
1866}
1867
1868fn compute_path_hash(path: &str) -> [u8; 16] {
1871 let full = rns_core::hash::full_hash(path.as_bytes());
1872 let mut result = [0u8; 16];
1873 result.copy_from_slice(&full[..16]);
1874 result
1875}
1876
1877#[cfg(test)]
1878mod tests {
1879 use super::*;
1880 use rns_crypto::identity::Identity;
1881 use rns_crypto::{FixedRng, OsRng};
1882
1883 fn make_rng(seed: u8) -> FixedRng {
1884 FixedRng::new(&[seed; 128])
1885 }
1886
1887 fn make_dest_keys(rng: &mut dyn Rng) -> (Ed25519PrivateKey, [u8; 32]) {
1888 let sig_prv = Ed25519PrivateKey::generate(rng);
1889 let sig_pub_bytes = sig_prv.public_key().public_bytes();
1890 (sig_prv, sig_pub_bytes)
1891 }
1892
1893 #[test]
1894 fn test_register_link_destination() {
1895 let mut mgr = LinkManager::new();
1896 let mut rng = make_rng(0x01);
1897 let (sig_prv, sig_pub_bytes) = make_dest_keys(&mut rng);
1898 let dest_hash = [0xDD; 16];
1899
1900 mgr.register_link_destination(dest_hash, sig_prv, sig_pub_bytes);
1901 assert!(mgr.is_link_destination(&dest_hash));
1902
1903 mgr.deregister_link_destination(&dest_hash);
1904 assert!(!mgr.is_link_destination(&dest_hash));
1905 }
1906
1907 #[test]
1908 fn test_create_link() {
1909 let mut mgr = LinkManager::new();
1910 let mut rng = OsRng;
1911 let dest_hash = [0xDD; 16];
1912
1913 let sig_pub_bytes = [0xAA; 32]; let (link_id, actions) = mgr.create_link(&dest_hash, &sig_pub_bytes, 1, &mut rng);
1915 assert_ne!(link_id, [0u8; 16]);
1916 assert_eq!(actions.len(), 2);
1918 assert!(matches!(actions[0], LinkManagerAction::RegisterLinkDest { .. }));
1919 assert!(matches!(actions[1], LinkManagerAction::SendPacket { .. }));
1920
1921 assert_eq!(mgr.link_state(&link_id), Some(LinkState::Pending));
1923 }
1924
1925 #[test]
1926 fn test_full_handshake_via_manager() {
1927 let mut rng = OsRng;
1928 let dest_hash = [0xDD; 16];
1929
1930 let mut responder_mgr = LinkManager::new();
1932 let (sig_prv, sig_pub_bytes) = make_dest_keys(&mut rng);
1933 responder_mgr.register_link_destination(dest_hash, sig_prv, sig_pub_bytes);
1934
1935 let mut initiator_mgr = LinkManager::new();
1937
1938 let (link_id, init_actions) = initiator_mgr.create_link(&dest_hash, &sig_pub_bytes, 1, &mut rng);
1940 assert_eq!(init_actions.len(), 2);
1941
1942 let linkrequest_raw = match &init_actions[1] {
1944 LinkManagerAction::SendPacket { raw, .. } => raw.clone(),
1945 _ => panic!("Expected SendPacket"),
1946 };
1947
1948 let lr_packet = RawPacket::unpack(&linkrequest_raw).unwrap();
1950
1951 let resp_actions = responder_mgr.handle_local_delivery(
1953 lr_packet.destination_hash,
1954 &linkrequest_raw,
1955 lr_packet.packet_hash,
1956 &mut rng,
1957 );
1958 assert!(resp_actions.len() >= 2);
1960 assert!(matches!(resp_actions[0], LinkManagerAction::RegisterLinkDest { .. }));
1961
1962 let lrproof_raw = match &resp_actions[1] {
1964 LinkManagerAction::SendPacket { raw, .. } => raw.clone(),
1965 _ => panic!("Expected SendPacket for LRPROOF"),
1966 };
1967
1968 let lrproof_packet = RawPacket::unpack(&lrproof_raw).unwrap();
1970 let init_actions2 = initiator_mgr.handle_local_delivery(
1971 lrproof_packet.destination_hash,
1972 &lrproof_raw,
1973 lrproof_packet.packet_hash,
1974 &mut rng,
1975 );
1976
1977 let has_established = init_actions2.iter().any(|a| matches!(a, LinkManagerAction::LinkEstablished { .. }));
1979 assert!(has_established, "Initiator should emit LinkEstablished");
1980
1981 let lrrtt_raw = init_actions2.iter().find_map(|a| match a {
1983 LinkManagerAction::SendPacket { raw, .. } => Some(raw.clone()),
1984 _ => None,
1985 }).expect("Should have LRRTT SendPacket");
1986
1987 let lrrtt_packet = RawPacket::unpack(&lrrtt_raw).unwrap();
1989 let resp_link_id = lrrtt_packet.destination_hash;
1990 let resp_actions2 = responder_mgr.handle_local_delivery(
1991 resp_link_id,
1992 &lrrtt_raw,
1993 lrrtt_packet.packet_hash,
1994 &mut rng,
1995 );
1996
1997 let has_established = resp_actions2.iter().any(|a| matches!(a, LinkManagerAction::LinkEstablished { .. }));
1998 assert!(has_established, "Responder should emit LinkEstablished");
1999
2000 assert_eq!(initiator_mgr.link_state(&link_id), Some(LinkState::Active));
2002 assert_eq!(responder_mgr.link_state(&link_id), Some(LinkState::Active));
2003
2004 assert!(initiator_mgr.link_rtt(&link_id).is_some());
2006 assert!(responder_mgr.link_rtt(&link_id).is_some());
2007 }
2008
2009 #[test]
2010 fn test_encrypted_data_exchange() {
2011 let mut rng = OsRng;
2012 let dest_hash = [0xDD; 16];
2013 let mut resp_mgr = LinkManager::new();
2014 let (sig_prv, sig_pub_bytes) = make_dest_keys(&mut rng);
2015 resp_mgr.register_link_destination(dest_hash, sig_prv, sig_pub_bytes);
2016 let mut init_mgr = LinkManager::new();
2017
2018 let (link_id, init_actions) = init_mgr.create_link(&dest_hash, &sig_pub_bytes, 1, &mut rng);
2020 let lr_raw = extract_send_packet(&init_actions);
2021 let lr_pkt = RawPacket::unpack(&lr_raw).unwrap();
2022 let resp_actions = resp_mgr.handle_local_delivery(lr_pkt.destination_hash, &lr_raw, lr_pkt.packet_hash, &mut rng);
2023 let lrproof_raw = extract_send_packet_at(&resp_actions, 1);
2024 let lrproof_pkt = RawPacket::unpack(&lrproof_raw).unwrap();
2025 let init_actions2 = init_mgr.handle_local_delivery(lrproof_pkt.destination_hash, &lrproof_raw, lrproof_pkt.packet_hash, &mut rng);
2026 let lrrtt_raw = extract_any_send_packet(&init_actions2);
2027 let lrrtt_pkt = RawPacket::unpack(&lrrtt_raw).unwrap();
2028 resp_mgr.handle_local_delivery(lrrtt_pkt.destination_hash, &lrrtt_raw, lrrtt_pkt.packet_hash, &mut rng);
2029
2030 let actions = init_mgr.send_on_link(&link_id, b"hello link!", constants::CONTEXT_NONE, &mut rng);
2032 assert_eq!(actions.len(), 1);
2033 assert!(matches!(actions[0], LinkManagerAction::SendPacket { .. }));
2034 }
2035
2036 #[test]
2037 fn test_request_response() {
2038 let mut rng = OsRng;
2039 let dest_hash = [0xDD; 16];
2040 let mut resp_mgr = LinkManager::new();
2041 let (sig_prv, sig_pub_bytes) = make_dest_keys(&mut rng);
2042 resp_mgr.register_link_destination(dest_hash, sig_prv, sig_pub_bytes);
2043
2044 resp_mgr.register_request_handler("/status", None, |_link_id, _path, _data, _remote| {
2046 Some(b"OK".to_vec())
2047 });
2048
2049 let mut init_mgr = LinkManager::new();
2050
2051 let (link_id, init_actions) = init_mgr.create_link(&dest_hash, &sig_pub_bytes, 1, &mut rng);
2053 let lr_raw = extract_send_packet(&init_actions);
2054 let lr_pkt = RawPacket::unpack(&lr_raw).unwrap();
2055 let resp_actions = resp_mgr.handle_local_delivery(lr_pkt.destination_hash, &lr_raw, lr_pkt.packet_hash, &mut rng);
2056 let lrproof_raw = extract_send_packet_at(&resp_actions, 1);
2057 let lrproof_pkt = RawPacket::unpack(&lrproof_raw).unwrap();
2058 let init_actions2 = init_mgr.handle_local_delivery(lrproof_pkt.destination_hash, &lrproof_raw, lrproof_pkt.packet_hash, &mut rng);
2059 let lrrtt_raw = extract_any_send_packet(&init_actions2);
2060 let lrrtt_pkt = RawPacket::unpack(&lrrtt_raw).unwrap();
2061 resp_mgr.handle_local_delivery(lrrtt_pkt.destination_hash, &lrrtt_raw, lrrtt_pkt.packet_hash, &mut rng);
2062
2063 let req_actions = init_mgr.send_request(&link_id, "/status", b"query", &mut rng);
2065 assert_eq!(req_actions.len(), 1);
2066
2067 let req_raw = extract_send_packet_from(&req_actions);
2069 let req_pkt = RawPacket::unpack(&req_raw).unwrap();
2070 let resp_actions = resp_mgr.handle_local_delivery(
2071 req_pkt.destination_hash, &req_raw, req_pkt.packet_hash, &mut rng,
2072 );
2073
2074 let has_response = resp_actions.iter().any(|a| matches!(a, LinkManagerAction::SendPacket { .. }));
2076 assert!(has_response, "Handler should produce a response packet");
2077 }
2078
2079 #[test]
2080 fn test_request_acl_deny_unidentified() {
2081 let mut rng = OsRng;
2082 let dest_hash = [0xDD; 16];
2083 let mut resp_mgr = LinkManager::new();
2084 let (sig_prv, sig_pub_bytes) = make_dest_keys(&mut rng);
2085 resp_mgr.register_link_destination(dest_hash, sig_prv, sig_pub_bytes);
2086
2087 resp_mgr.register_request_handler(
2089 "/restricted",
2090 Some(vec![[0xAA; 16]]),
2091 |_link_id, _path, _data, _remote| Some(b"secret".to_vec()),
2092 );
2093
2094 let mut init_mgr = LinkManager::new();
2095
2096 let (link_id, init_actions) = init_mgr.create_link(&dest_hash, &sig_pub_bytes, 1, &mut rng);
2098 let lr_raw = extract_send_packet(&init_actions);
2099 let lr_pkt = RawPacket::unpack(&lr_raw).unwrap();
2100 let resp_actions = resp_mgr.handle_local_delivery(lr_pkt.destination_hash, &lr_raw, lr_pkt.packet_hash, &mut rng);
2101 let lrproof_raw = extract_send_packet_at(&resp_actions, 1);
2102 let lrproof_pkt = RawPacket::unpack(&lrproof_raw).unwrap();
2103 let init_actions2 = init_mgr.handle_local_delivery(lrproof_pkt.destination_hash, &lrproof_raw, lrproof_pkt.packet_hash, &mut rng);
2104 let lrrtt_raw = extract_any_send_packet(&init_actions2);
2105 let lrrtt_pkt = RawPacket::unpack(&lrrtt_raw).unwrap();
2106 resp_mgr.handle_local_delivery(lrrtt_pkt.destination_hash, &lrrtt_raw, lrrtt_pkt.packet_hash, &mut rng);
2107
2108 let req_actions = init_mgr.send_request(&link_id, "/restricted", b"query", &mut rng);
2110 let req_raw = extract_send_packet_from(&req_actions);
2111 let req_pkt = RawPacket::unpack(&req_raw).unwrap();
2112 let resp_actions = resp_mgr.handle_local_delivery(
2113 req_pkt.destination_hash, &req_raw, req_pkt.packet_hash, &mut rng,
2114 );
2115
2116 let has_response = resp_actions.iter().any(|a| matches!(a, LinkManagerAction::SendPacket { .. }));
2118 assert!(!has_response, "Unidentified peer should be denied");
2119 }
2120
2121 #[test]
2122 fn test_teardown_link() {
2123 let mut rng = OsRng;
2124 let dest_hash = [0xDD; 16];
2125 let mut mgr = LinkManager::new();
2126
2127 let dummy_sig = [0xAA; 32];
2128 let (link_id, _) = mgr.create_link(&dest_hash, &dummy_sig, 1, &mut rng);
2129 assert_eq!(mgr.link_count(), 1);
2130
2131 let actions = mgr.teardown_link(&link_id);
2132 let has_close = actions.iter().any(|a| matches!(a, LinkManagerAction::LinkClosed { .. }));
2133 assert!(has_close);
2134
2135 let tick_actions = mgr.tick(&mut rng);
2137 let has_deregister = tick_actions.iter().any(|a| matches!(a, LinkManagerAction::DeregisterLinkDest { .. }));
2138 assert!(has_deregister);
2139 assert_eq!(mgr.link_count(), 0);
2140 }
2141
2142 #[test]
2143 fn test_identify_on_link() {
2144 let mut rng = OsRng;
2145 let dest_hash = [0xDD; 16];
2146 let mut resp_mgr = LinkManager::new();
2147 let (sig_prv, sig_pub_bytes) = make_dest_keys(&mut rng);
2148 resp_mgr.register_link_destination(dest_hash, sig_prv, sig_pub_bytes);
2149 let mut init_mgr = LinkManager::new();
2150
2151 let (link_id, init_actions) = init_mgr.create_link(&dest_hash, &sig_pub_bytes, 1, &mut rng);
2153 let lr_raw = extract_send_packet(&init_actions);
2154 let lr_pkt = RawPacket::unpack(&lr_raw).unwrap();
2155 let resp_actions = resp_mgr.handle_local_delivery(lr_pkt.destination_hash, &lr_raw, lr_pkt.packet_hash, &mut rng);
2156 let lrproof_raw = extract_send_packet_at(&resp_actions, 1);
2157 let lrproof_pkt = RawPacket::unpack(&lrproof_raw).unwrap();
2158 let init_actions2 = init_mgr.handle_local_delivery(lrproof_pkt.destination_hash, &lrproof_raw, lrproof_pkt.packet_hash, &mut rng);
2159 let lrrtt_raw = extract_any_send_packet(&init_actions2);
2160 let lrrtt_pkt = RawPacket::unpack(&lrrtt_raw).unwrap();
2161 resp_mgr.handle_local_delivery(lrrtt_pkt.destination_hash, &lrrtt_raw, lrrtt_pkt.packet_hash, &mut rng);
2162
2163 let identity = Identity::new(&mut rng);
2165 let id_actions = init_mgr.identify(&link_id, &identity, &mut rng);
2166 assert_eq!(id_actions.len(), 1);
2167
2168 let id_raw = extract_send_packet_from(&id_actions);
2170 let id_pkt = RawPacket::unpack(&id_raw).unwrap();
2171 let resp_actions = resp_mgr.handle_local_delivery(
2172 id_pkt.destination_hash, &id_raw, id_pkt.packet_hash, &mut rng,
2173 );
2174
2175 let has_identified = resp_actions.iter().any(|a| matches!(a, LinkManagerAction::RemoteIdentified { .. }));
2176 assert!(has_identified, "Responder should emit RemoteIdentified");
2177 }
2178
2179 #[test]
2180 fn test_path_hash_computation() {
2181 let h1 = compute_path_hash("/status");
2182 let h2 = compute_path_hash("/path");
2183 assert_ne!(h1, h2);
2184
2185 assert_eq!(h1, compute_path_hash("/status"));
2187 }
2188
2189 #[test]
2190 fn test_link_count() {
2191 let mut mgr = LinkManager::new();
2192 let mut rng = OsRng;
2193
2194 assert_eq!(mgr.link_count(), 0);
2195
2196 let dummy_sig = [0xAA; 32];
2197 mgr.create_link(&[0x11; 16], &dummy_sig, 1, &mut rng);
2198 assert_eq!(mgr.link_count(), 1);
2199
2200 mgr.create_link(&[0x22; 16], &dummy_sig, 1, &mut rng);
2201 assert_eq!(mgr.link_count(), 2);
2202 }
2203
2204 fn extract_send_packet(actions: &[LinkManagerAction]) -> Vec<u8> {
2207 extract_send_packet_at(actions, actions.len() - 1)
2208 }
2209
2210 fn extract_send_packet_at(actions: &[LinkManagerAction], idx: usize) -> Vec<u8> {
2211 match &actions[idx] {
2212 LinkManagerAction::SendPacket { raw, .. } => raw.clone(),
2213 other => panic!("Expected SendPacket at index {}, got {:?}", idx, other),
2214 }
2215 }
2216
2217 fn extract_any_send_packet(actions: &[LinkManagerAction]) -> Vec<u8> {
2218 actions.iter().find_map(|a| match a {
2219 LinkManagerAction::SendPacket { raw, .. } => Some(raw.clone()),
2220 _ => None,
2221 }).expect("Expected at least one SendPacket action")
2222 }
2223
2224 fn extract_send_packet_from(actions: &[LinkManagerAction]) -> Vec<u8> {
2225 extract_any_send_packet(actions)
2226 }
2227
2228 fn setup_active_link() -> (LinkManager, LinkManager, LinkId) {
2231 let mut rng = OsRng;
2232 let dest_hash = [0xDD; 16];
2233 let mut resp_mgr = LinkManager::new();
2234 let (sig_prv, sig_pub_bytes) = make_dest_keys(&mut rng);
2235 resp_mgr.register_link_destination(dest_hash, sig_prv, sig_pub_bytes);
2236 let mut init_mgr = LinkManager::new();
2237
2238 let (link_id, init_actions) = init_mgr.create_link(&dest_hash, &sig_pub_bytes, 1, &mut rng);
2239 let lr_raw = extract_send_packet(&init_actions);
2240 let lr_pkt = RawPacket::unpack(&lr_raw).unwrap();
2241 let resp_actions = resp_mgr.handle_local_delivery(
2242 lr_pkt.destination_hash, &lr_raw, lr_pkt.packet_hash, &mut rng,
2243 );
2244 let lrproof_raw = extract_send_packet_at(&resp_actions, 1);
2245 let lrproof_pkt = RawPacket::unpack(&lrproof_raw).unwrap();
2246 let init_actions2 = init_mgr.handle_local_delivery(
2247 lrproof_pkt.destination_hash, &lrproof_raw, lrproof_pkt.packet_hash, &mut rng,
2248 );
2249 let lrrtt_raw = extract_any_send_packet(&init_actions2);
2250 let lrrtt_pkt = RawPacket::unpack(&lrrtt_raw).unwrap();
2251 resp_mgr.handle_local_delivery(
2252 lrrtt_pkt.destination_hash, &lrrtt_raw, lrrtt_pkt.packet_hash, &mut rng,
2253 );
2254
2255 assert_eq!(init_mgr.link_state(&link_id), Some(LinkState::Active));
2256 assert_eq!(resp_mgr.link_state(&link_id), Some(LinkState::Active));
2257
2258 (init_mgr, resp_mgr, link_id)
2259 }
2260
2261 #[test]
2266 fn test_resource_strategy_default() {
2267 let mut mgr = LinkManager::new();
2268 let mut rng = OsRng;
2269 let dummy_sig = [0xAA; 32];
2270 let (link_id, _) = mgr.create_link(&[0x11; 16], &dummy_sig, 1, &mut rng);
2271
2272 let link = mgr.links.get(&link_id).unwrap();
2274 assert_eq!(link.resource_strategy, ResourceStrategy::AcceptNone);
2275 }
2276
2277 #[test]
2278 fn test_set_resource_strategy() {
2279 let mut mgr = LinkManager::new();
2280 let mut rng = OsRng;
2281 let dummy_sig = [0xAA; 32];
2282 let (link_id, _) = mgr.create_link(&[0x11; 16], &dummy_sig, 1, &mut rng);
2283
2284 mgr.set_resource_strategy(&link_id, ResourceStrategy::AcceptAll);
2285 assert_eq!(mgr.links.get(&link_id).unwrap().resource_strategy, ResourceStrategy::AcceptAll);
2286
2287 mgr.set_resource_strategy(&link_id, ResourceStrategy::AcceptApp);
2288 assert_eq!(mgr.links.get(&link_id).unwrap().resource_strategy, ResourceStrategy::AcceptApp);
2289 }
2290
2291 #[test]
2292 fn test_send_resource_on_active_link() {
2293 let (mut init_mgr, _resp_mgr, link_id) = setup_active_link();
2294 let mut rng = OsRng;
2295
2296 let data = vec![0xAB; 100]; let actions = init_mgr.send_resource(&link_id, &data, None, &mut rng);
2299
2300 let has_send = actions.iter().any(|a| matches!(a, LinkManagerAction::SendPacket { .. }));
2302 assert!(has_send, "send_resource should emit advertisement SendPacket");
2303 }
2304
2305 #[test]
2306 fn test_send_resource_on_inactive_link() {
2307 let mut mgr = LinkManager::new();
2308 let mut rng = OsRng;
2309 let dummy_sig = [0xAA; 32];
2310 let (link_id, _) = mgr.create_link(&[0x11; 16], &dummy_sig, 1, &mut rng);
2311
2312 let actions = mgr.send_resource(&link_id, b"data", None, &mut rng);
2314 assert!(actions.is_empty(), "Cannot send resource on inactive link");
2315 }
2316
2317 #[test]
2318 fn test_resource_adv_rejected_by_accept_none() {
2319 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
2320 let mut rng = OsRng;
2321
2322 let data = vec![0xCD; 100];
2325 let adv_actions = init_mgr.send_resource(&link_id, &data, None, &mut rng);
2326
2327 for action in &adv_actions {
2329 if let LinkManagerAction::SendPacket { raw, .. } = action {
2330 let pkt = RawPacket::unpack(raw).unwrap();
2331 let resp_actions = resp_mgr.handle_local_delivery(
2332 pkt.destination_hash, raw, pkt.packet_hash, &mut rng,
2333 );
2334 let has_resource_received = resp_actions.iter().any(|a|
2336 matches!(a, LinkManagerAction::ResourceReceived { .. })
2337 );
2338 assert!(!has_resource_received, "AcceptNone should not accept resource");
2339 }
2340 }
2341 }
2342
2343 #[test]
2344 fn test_resource_adv_accepted_by_accept_all() {
2345 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
2346 let mut rng = OsRng;
2347
2348 resp_mgr.set_resource_strategy(&link_id, ResourceStrategy::AcceptAll);
2350
2351 let data = vec![0xCD; 100];
2353 let adv_actions = init_mgr.send_resource(&link_id, &data, None, &mut rng);
2354
2355 for action in &adv_actions {
2357 if let LinkManagerAction::SendPacket { raw, .. } = action {
2358 let pkt = RawPacket::unpack(raw).unwrap();
2359 let resp_actions = resp_mgr.handle_local_delivery(
2360 pkt.destination_hash, raw, pkt.packet_hash, &mut rng,
2361 );
2362 let has_send = resp_actions.iter().any(|a|
2364 matches!(a, LinkManagerAction::SendPacket { .. })
2365 );
2366 assert!(has_send, "AcceptAll should accept and request parts");
2367 }
2368 }
2369 }
2370
2371 #[test]
2372 fn test_resource_accept_app_query() {
2373 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
2374 let mut rng = OsRng;
2375
2376 resp_mgr.set_resource_strategy(&link_id, ResourceStrategy::AcceptApp);
2378
2379 let data = vec![0xCD; 100];
2381 let adv_actions = init_mgr.send_resource(&link_id, &data, None, &mut rng);
2382
2383 let mut got_query = false;
2385 for action in &adv_actions {
2386 if let LinkManagerAction::SendPacket { raw, .. } = action {
2387 let pkt = RawPacket::unpack(raw).unwrap();
2388 let resp_actions = resp_mgr.handle_local_delivery(
2389 pkt.destination_hash, raw, pkt.packet_hash, &mut rng,
2390 );
2391 for a in &resp_actions {
2392 if matches!(a, LinkManagerAction::ResourceAcceptQuery { .. }) {
2393 got_query = true;
2394 }
2395 }
2396 }
2397 }
2398 assert!(got_query, "AcceptApp should emit ResourceAcceptQuery");
2399 }
2400
2401 #[test]
2402 fn test_resource_accept_app_accept() {
2403 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
2404 let mut rng = OsRng;
2405
2406 resp_mgr.set_resource_strategy(&link_id, ResourceStrategy::AcceptApp);
2407
2408 let data = vec![0xCD; 100];
2409 let adv_actions = init_mgr.send_resource(&link_id, &data, None, &mut rng);
2410
2411 for action in &adv_actions {
2412 if let LinkManagerAction::SendPacket { raw, .. } = action {
2413 let pkt = RawPacket::unpack(raw).unwrap();
2414 let resp_actions = resp_mgr.handle_local_delivery(
2415 pkt.destination_hash, raw, pkt.packet_hash, &mut rng,
2416 );
2417 for a in &resp_actions {
2418 if let LinkManagerAction::ResourceAcceptQuery { link_id: lid, resource_hash, .. } = a {
2419 let accept_actions = resp_mgr.accept_resource(lid, resource_hash, true, &mut rng);
2421 let has_send = accept_actions.iter().any(|a|
2423 matches!(a, LinkManagerAction::SendPacket { .. })
2424 );
2425 assert!(has_send, "Accepting resource should produce request for parts");
2426 }
2427 }
2428 }
2429 }
2430 }
2431
2432 #[test]
2433 fn test_resource_accept_app_reject() {
2434 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
2435 let mut rng = OsRng;
2436
2437 resp_mgr.set_resource_strategy(&link_id, ResourceStrategy::AcceptApp);
2438
2439 let data = vec![0xCD; 100];
2440 let adv_actions = init_mgr.send_resource(&link_id, &data, None, &mut rng);
2441
2442 for action in &adv_actions {
2443 if let LinkManagerAction::SendPacket { raw, .. } = action {
2444 let pkt = RawPacket::unpack(raw).unwrap();
2445 let resp_actions = resp_mgr.handle_local_delivery(
2446 pkt.destination_hash, raw, pkt.packet_hash, &mut rng,
2447 );
2448 for a in &resp_actions {
2449 if let LinkManagerAction::ResourceAcceptQuery { link_id: lid, resource_hash, .. } = a {
2450 let reject_actions = resp_mgr.accept_resource(lid, resource_hash, false, &mut rng);
2452 let has_resource_received = reject_actions.iter().any(|a|
2455 matches!(a, LinkManagerAction::ResourceReceived { .. })
2456 );
2457 assert!(!has_resource_received);
2458 }
2459 }
2460 }
2461 }
2462 }
2463
2464 #[test]
2465 fn test_resource_full_transfer() {
2466 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
2467 let mut rng = OsRng;
2468
2469 resp_mgr.set_resource_strategy(&link_id, ResourceStrategy::AcceptAll);
2471
2472 let original_data = b"Hello, Resource Transfer!".to_vec();
2474 let adv_actions = init_mgr.send_resource(&link_id, &original_data, None, &mut rng);
2475
2476 let mut pending: Vec<(char, LinkManagerAction)> = adv_actions.into_iter()
2479 .map(|a| ('i', a))
2480 .collect();
2481 let mut rounds = 0;
2482 let max_rounds = 50;
2483 let mut resource_received = false;
2484 let mut sender_completed = false;
2485
2486 while !pending.is_empty() && rounds < max_rounds {
2487 rounds += 1;
2488 let mut next: Vec<(char, LinkManagerAction)> = Vec::new();
2489
2490 for (source, action) in pending.drain(..) {
2491 if let LinkManagerAction::SendPacket { raw, .. } = action {
2492 let pkt = RawPacket::unpack(&raw).unwrap();
2493
2494 let target_actions = if source == 'i' {
2496 resp_mgr.handle_local_delivery(
2497 pkt.destination_hash, &raw, pkt.packet_hash, &mut rng,
2498 )
2499 } else {
2500 init_mgr.handle_local_delivery(
2501 pkt.destination_hash, &raw, pkt.packet_hash, &mut rng,
2502 )
2503 };
2504
2505 let target_source = if source == 'i' { 'r' } else { 'i' };
2506 for a in &target_actions {
2507 match a {
2508 LinkManagerAction::ResourceReceived { data, .. } => {
2509 assert_eq!(*data, original_data);
2510 resource_received = true;
2511 }
2512 LinkManagerAction::ResourceCompleted { .. } => {
2513 sender_completed = true;
2514 }
2515 _ => {}
2516 }
2517 }
2518 next.extend(target_actions.into_iter().map(|a| (target_source, a)));
2519 }
2520 }
2521 pending = next;
2522 }
2523
2524 assert!(resource_received, "Responder should receive resource data (rounds={})", rounds);
2525 assert!(sender_completed, "Sender should get completion proof (rounds={})", rounds);
2526 }
2527
2528 #[test]
2529 fn test_resource_cancel_icl() {
2530 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
2531 let mut rng = OsRng;
2532
2533 resp_mgr.set_resource_strategy(&link_id, ResourceStrategy::AcceptAll);
2534
2535 let data = vec![0xAB; 2000];
2537 let adv_actions = init_mgr.send_resource(&link_id, &data, None, &mut rng);
2538
2539 for action in &adv_actions {
2541 if let LinkManagerAction::SendPacket { raw, .. } = action {
2542 let pkt = RawPacket::unpack(raw).unwrap();
2543 resp_mgr.handle_local_delivery(
2544 pkt.destination_hash, raw, pkt.packet_hash, &mut rng,
2545 );
2546 }
2547 }
2548
2549 assert!(!resp_mgr.links.get(&link_id).unwrap().incoming_resources.is_empty());
2551
2552 let icl_actions = resp_mgr.handle_resource_icl(&link_id);
2554
2555 let has_failed = icl_actions.iter().any(|a| matches!(a, LinkManagerAction::ResourceFailed { .. }));
2557 assert!(has_failed, "ICL should produce ResourceFailed");
2558 }
2559
2560 #[test]
2561 fn test_resource_cancel_rcl() {
2562 let (mut init_mgr, _resp_mgr, link_id) = setup_active_link();
2563 let mut rng = OsRng;
2564
2565 let data = vec![0xAB; 2000];
2567 init_mgr.send_resource(&link_id, &data, None, &mut rng);
2568
2569 assert!(!init_mgr.links.get(&link_id).unwrap().outgoing_resources.is_empty());
2571
2572 let rcl_actions = init_mgr.handle_resource_rcl(&link_id);
2574
2575 let has_failed = rcl_actions.iter().any(|a| matches!(a, LinkManagerAction::ResourceFailed { .. }));
2576 assert!(has_failed, "RCL should produce ResourceFailed");
2577 }
2578
2579 #[test]
2580 fn test_resource_tick_cleans_up() {
2581 let (mut init_mgr, _resp_mgr, link_id) = setup_active_link();
2582 let mut rng = OsRng;
2583
2584 let data = vec![0xAB; 100];
2585 init_mgr.send_resource(&link_id, &data, None, &mut rng);
2586
2587 assert!(!init_mgr.links.get(&link_id).unwrap().outgoing_resources.is_empty());
2588
2589 init_mgr.handle_resource_rcl(&link_id);
2591
2592 init_mgr.tick(&mut rng);
2594
2595 assert!(init_mgr.links.get(&link_id).unwrap().outgoing_resources.is_empty(),
2596 "Tick should clean up completed/failed outgoing resources");
2597 }
2598
2599 #[test]
2600 fn test_build_link_packet() {
2601 let (init_mgr, _resp_mgr, link_id) = setup_active_link();
2602
2603 let actions = init_mgr.build_link_packet(&link_id, constants::CONTEXT_RESOURCE, b"test data");
2604 assert_eq!(actions.len(), 1);
2605 if let LinkManagerAction::SendPacket { raw, dest_type, .. } = &actions[0] {
2606 let pkt = RawPacket::unpack(raw).unwrap();
2607 assert_eq!(pkt.context, constants::CONTEXT_RESOURCE);
2608 assert_eq!(*dest_type, constants::DESTINATION_LINK);
2609 } else {
2610 panic!("Expected SendPacket");
2611 }
2612 }
2613
2614 #[test]
2619 fn test_channel_message_delivery() {
2620 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
2621 let mut rng = OsRng;
2622
2623 let chan_actions = init_mgr.send_channel_message(&link_id, 42, b"channel data", &mut rng);
2625 assert!(!chan_actions.is_empty());
2626
2627 let mut got_channel_msg = false;
2629 for action in &chan_actions {
2630 if let LinkManagerAction::SendPacket { raw, .. } = action {
2631 let pkt = RawPacket::unpack(raw).unwrap();
2632 let resp_actions = resp_mgr.handle_local_delivery(
2633 pkt.destination_hash, raw, pkt.packet_hash, &mut rng,
2634 );
2635 for a in &resp_actions {
2636 if let LinkManagerAction::ChannelMessageReceived { msgtype, payload, .. } = a {
2637 assert_eq!(*msgtype, 42);
2638 assert_eq!(*payload, b"channel data");
2639 got_channel_msg = true;
2640 }
2641 }
2642 }
2643 }
2644 assert!(got_channel_msg, "Responder should receive channel message");
2645 }
2646
2647 #[test]
2648 fn test_generic_link_data_delivery() {
2649 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
2650 let mut rng = OsRng;
2651
2652 let actions = init_mgr.send_on_link(&link_id, b"raw stuff", 0x42, &mut rng);
2654 assert_eq!(actions.len(), 1);
2655
2656 let raw = extract_any_send_packet(&actions);
2658 let pkt = RawPacket::unpack(&raw).unwrap();
2659 let resp_actions = resp_mgr.handle_local_delivery(
2660 pkt.destination_hash, &raw, pkt.packet_hash, &mut rng,
2661 );
2662
2663 let has_data = resp_actions.iter().any(|a|
2664 matches!(a, LinkManagerAction::LinkDataReceived { context: 0x42, .. })
2665 );
2666 assert!(has_data, "Responder should receive LinkDataReceived for unknown context");
2667 }
2668
2669 #[test]
2670 fn test_response_delivery() {
2671 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
2672 let mut rng = OsRng;
2673
2674 resp_mgr.register_request_handler("/echo", None, |_link_id, _path, data, _remote| {
2676 Some(data.to_vec())
2677 });
2678
2679 let req_actions = init_mgr.send_request(&link_id, "/echo", b"\xc0", &mut rng); assert!(!req_actions.is_empty());
2682
2683 let req_raw = extract_any_send_packet(&req_actions);
2685 let req_pkt = RawPacket::unpack(&req_raw).unwrap();
2686 let resp_actions = resp_mgr.handle_local_delivery(
2687 req_pkt.destination_hash, &req_raw, req_pkt.packet_hash, &mut rng,
2688 );
2689 let has_resp_send = resp_actions.iter().any(|a| matches!(a, LinkManagerAction::SendPacket { .. }));
2690 assert!(has_resp_send, "Handler should produce response");
2691
2692 let resp_raw = extract_any_send_packet(&resp_actions);
2694 let resp_pkt = RawPacket::unpack(&resp_raw).unwrap();
2695 let init_actions = init_mgr.handle_local_delivery(
2696 resp_pkt.destination_hash, &resp_raw, resp_pkt.packet_hash, &mut rng,
2697 );
2698
2699 let has_response_received = init_actions.iter().any(|a|
2700 matches!(a, LinkManagerAction::ResponseReceived { .. })
2701 );
2702 assert!(has_response_received, "Initiator should receive ResponseReceived");
2703 }
2704
2705 #[test]
2706 fn test_send_channel_message_on_no_channel() {
2707 let mut mgr = LinkManager::new();
2708 let mut rng = OsRng;
2709 let dummy_sig = [0xAA; 32];
2710 let (link_id, _) = mgr.create_link(&[0x11; 16], &dummy_sig, 1, &mut rng);
2711
2712 let actions = mgr.send_channel_message(&link_id, 1, b"test", &mut rng);
2714 assert!(actions.is_empty(), "No channel on pending link");
2715 }
2716
2717 #[test]
2718 fn test_send_on_link_requires_active() {
2719 let mut mgr = LinkManager::new();
2720 let mut rng = OsRng;
2721 let dummy_sig = [0xAA; 32];
2722 let (link_id, _) = mgr.create_link(&[0x11; 16], &dummy_sig, 1, &mut rng);
2723
2724 let actions = mgr.send_on_link(&link_id, b"test", constants::CONTEXT_NONE, &mut rng);
2725 assert!(actions.is_empty(), "Cannot send on pending link");
2726 }
2727
2728 #[test]
2729 fn test_send_on_link_unknown_link() {
2730 let mgr = LinkManager::new();
2731 let mut rng = OsRng;
2732
2733 let actions = mgr.send_on_link(&[0xFF; 16], b"test", constants::CONTEXT_NONE, &mut rng);
2734 assert!(actions.is_empty());
2735 }
2736
2737 #[test]
2738 fn test_resource_full_transfer_large() {
2739 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
2740 let mut rng = OsRng;
2741
2742 resp_mgr.set_resource_strategy(&link_id, ResourceStrategy::AcceptAll);
2743
2744 let original_data: Vec<u8> = (0..2000u32).map(|i| {
2746 let pos = i as usize;
2747 (pos ^ (pos >> 8) ^ (pos >> 16)) as u8
2748 }).collect();
2749
2750 let adv_actions = init_mgr.send_resource(&link_id, &original_data, None, &mut rng);
2751
2752 let mut pending: Vec<(char, LinkManagerAction)> = adv_actions.into_iter()
2753 .map(|a| ('i', a))
2754 .collect();
2755 let mut rounds = 0;
2756 let max_rounds = 200;
2757 let mut resource_received = false;
2758 let mut sender_completed = false;
2759
2760 while !pending.is_empty() && rounds < max_rounds {
2761 rounds += 1;
2762 let mut next: Vec<(char, LinkManagerAction)> = Vec::new();
2763
2764 for (source, action) in pending.drain(..) {
2765 if let LinkManagerAction::SendPacket { raw, .. } = action {
2766 let pkt = match RawPacket::unpack(&raw) {
2767 Ok(p) => p,
2768 Err(_) => continue,
2769 };
2770
2771 let target_actions = if source == 'i' {
2772 resp_mgr.handle_local_delivery(
2773 pkt.destination_hash, &raw, pkt.packet_hash, &mut rng,
2774 )
2775 } else {
2776 init_mgr.handle_local_delivery(
2777 pkt.destination_hash, &raw, pkt.packet_hash, &mut rng,
2778 )
2779 };
2780
2781 let target_source = if source == 'i' { 'r' } else { 'i' };
2782 for a in &target_actions {
2783 match a {
2784 LinkManagerAction::ResourceReceived { data, .. } => {
2785 assert_eq!(*data, original_data);
2786 resource_received = true;
2787 }
2788 LinkManagerAction::ResourceCompleted { .. } => {
2789 sender_completed = true;
2790 }
2791 _ => {}
2792 }
2793 }
2794 next.extend(target_actions.into_iter().map(|a| (target_source, a)));
2795 }
2796 }
2797 pending = next;
2798 }
2799
2800 assert!(resource_received, "Should receive large resource (rounds={})", rounds);
2801 assert!(sender_completed, "Sender should complete (rounds={})", rounds);
2802 }
2803
2804 #[test]
2805 fn test_process_resource_actions_mapping() {
2806 let (init_mgr, _resp_mgr, link_id) = setup_active_link();
2807 let mut rng = OsRng;
2808
2809 let actions = vec![
2811 ResourceAction::DataReceived { data: vec![1, 2, 3], metadata: Some(vec![4, 5]) },
2812 ResourceAction::Completed,
2813 ResourceAction::Failed(rns_core::resource::ResourceError::Timeout),
2814 ResourceAction::ProgressUpdate { received: 10, total: 20 },
2815 ];
2816
2817 let result = init_mgr.process_resource_actions(&link_id, actions, &mut rng);
2818
2819 assert!(matches!(result[0], LinkManagerAction::ResourceReceived { .. }));
2820 assert!(matches!(result[1], LinkManagerAction::ResourceCompleted { .. }));
2821 assert!(matches!(result[2], LinkManagerAction::ResourceFailed { .. }));
2822 assert!(matches!(result[3], LinkManagerAction::ResourceProgress { received: 10, total: 20, .. }));
2823 }
2824}