1use std::collections::HashMap;
10
11use super::compressor::Bzip2Compressor;
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 super::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 sig_prv: Ed25519PrivateKey,
61 sig_pub_bytes: [u8; 32],
62 resource_strategy: ResourceStrategy,
63}
64
65struct RequestHandlerEntry {
67 path: String,
69 path_hash: [u8; 16],
71 allowed_list: Option<Vec<[u8; 16]>>,
73 handler:
75 Box<dyn Fn(LinkId, &str, &[u8], Option<&([u8; 16], [u8; 64])>) -> Option<Vec<u8>> + Send>,
76}
77
78#[derive(Debug)]
80pub enum LinkManagerAction {
81 SendPacket {
83 raw: Vec<u8>,
84 dest_type: u8,
85 attached_interface: Option<rns_core::transport::types::InterfaceId>,
86 },
87 LinkEstablished {
89 link_id: LinkId,
90 dest_hash: [u8; 16],
91 rtt: f64,
92 is_initiator: bool,
93 },
94 LinkClosed {
96 link_id: LinkId,
97 reason: Option<TeardownReason>,
98 },
99 RemoteIdentified {
101 link_id: LinkId,
102 identity_hash: [u8; 16],
103 public_key: [u8; 64],
104 },
105 RegisterLinkDest { link_id: LinkId },
107 DeregisterLinkDest { link_id: LinkId },
109 ManagementRequest {
112 link_id: LinkId,
113 path_hash: [u8; 16],
114 data: Vec<u8>,
116 request_id: [u8; 16],
118 remote_identity: Option<([u8; 16], [u8; 64])>,
119 },
120 ResourceReceived {
122 link_id: LinkId,
123 data: Vec<u8>,
124 metadata: Option<Vec<u8>>,
125 },
126 ResourceCompleted { link_id: LinkId },
128 ResourceFailed { link_id: LinkId, error: String },
130 ResourceProgress {
132 link_id: LinkId,
133 received: usize,
134 total: usize,
135 },
136 ResourceAcceptQuery {
138 link_id: LinkId,
139 resource_hash: Vec<u8>,
140 transfer_size: u64,
141 has_metadata: bool,
142 },
143 ChannelMessageReceived {
145 link_id: LinkId,
146 msgtype: u16,
147 payload: Vec<u8>,
148 },
149 LinkDataReceived {
151 link_id: LinkId,
152 context: u8,
153 data: Vec<u8>,
154 },
155 ResponseReceived {
157 link_id: LinkId,
158 request_id: [u8; 16],
159 data: Vec<u8>,
160 },
161 LinkRequestReceived {
163 link_id: LinkId,
164 receiving_interface: rns_core::transport::types::InterfaceId,
165 },
166}
167
168pub struct LinkManager {
170 links: HashMap<LinkId, ManagedLink>,
171 link_destinations: HashMap<[u8; 16], LinkDestination>,
172 request_handlers: Vec<RequestHandlerEntry>,
173 management_paths: Vec<[u8; 16]>,
176}
177
178impl LinkManager {
179 pub fn new() -> Self {
181 LinkManager {
182 links: HashMap::new(),
183 link_destinations: HashMap::new(),
184 request_handlers: Vec::new(),
185 management_paths: Vec::new(),
186 }
187 }
188
189 pub fn register_management_path(&mut self, path_hash: [u8; 16]) {
193 if !self.management_paths.contains(&path_hash) {
194 self.management_paths.push(path_hash);
195 }
196 }
197
198 pub fn get_derived_key(&self, link_id: &LinkId) -> Option<Vec<u8>> {
200 self.links
201 .get(link_id)
202 .and_then(|link| link.engine.derived_key().map(|dk| dk.to_vec()))
203 }
204
205 pub fn register_link_destination(
207 &mut self,
208 dest_hash: [u8; 16],
209 sig_prv: Ed25519PrivateKey,
210 sig_pub_bytes: [u8; 32],
211 resource_strategy: ResourceStrategy,
212 ) {
213 self.link_destinations.insert(
214 dest_hash,
215 LinkDestination {
216 sig_prv,
217 sig_pub_bytes,
218 resource_strategy,
219 },
220 );
221 }
222
223 pub fn deregister_link_destination(&mut self, dest_hash: &[u8; 16]) {
225 self.link_destinations.remove(dest_hash);
226 }
227
228 pub fn register_request_handler<F>(
234 &mut self,
235 path: &str,
236 allowed_list: Option<Vec<[u8; 16]>>,
237 handler: F,
238 ) where
239 F: Fn(LinkId, &str, &[u8], Option<&([u8; 16], [u8; 64])>) -> Option<Vec<u8>>
240 + Send
241 + 'static,
242 {
243 let path_hash = compute_path_hash(path);
244 self.request_handlers.push(RequestHandlerEntry {
245 path: path.to_string(),
246 path_hash,
247 allowed_list,
248 handler: Box::new(handler),
249 });
250 }
251
252 pub fn create_link(
260 &mut self,
261 dest_hash: &[u8; 16],
262 dest_sig_pub_bytes: &[u8; 32],
263 hops: u8,
264 mtu: u32,
265 rng: &mut dyn Rng,
266 ) -> (LinkId, Vec<LinkManagerAction>) {
267 let mode = LinkMode::Aes256Cbc;
268 let (mut engine, request_data) =
269 LinkEngine::new_initiator(dest_hash, hops, mode, Some(mtu), time::now(), rng);
270
271 let flags = PacketFlags {
273 header_type: constants::HEADER_1,
274 context_flag: constants::FLAG_UNSET,
275 transport_type: constants::TRANSPORT_BROADCAST,
276 destination_type: constants::DESTINATION_SINGLE,
277 packet_type: constants::PACKET_TYPE_LINKREQUEST,
278 };
279
280 let packet = match RawPacket::pack(
281 flags,
282 0,
283 dest_hash,
284 None,
285 constants::CONTEXT_NONE,
286 &request_data,
287 ) {
288 Ok(p) => p,
289 Err(_) => {
290 return ([0u8; 16], Vec::new());
292 }
293 };
294
295 engine.set_link_id_from_hashable(&packet.get_hashable_part(), request_data.len());
296 let link_id = *engine.link_id();
297
298 let managed = ManagedLink {
299 engine,
300 channel: None,
301 dest_hash: *dest_hash,
302 remote_identity: None,
303 dest_sig_pub_bytes: Some(*dest_sig_pub_bytes),
304 incoming_resources: Vec::new(),
305 outgoing_resources: Vec::new(),
306 resource_strategy: ResourceStrategy::default(),
307 };
308 self.links.insert(link_id, managed);
309
310 let mut actions = Vec::new();
311 actions.push(LinkManagerAction::RegisterLinkDest { link_id });
313 actions.push(LinkManagerAction::SendPacket {
315 raw: packet.raw,
316 dest_type: constants::DESTINATION_LINK,
317 attached_interface: None,
318 });
319
320 (link_id, actions)
321 }
322
323 pub fn handle_local_delivery(
329 &mut self,
330 dest_hash: [u8; 16],
331 raw: &[u8],
332 packet_hash: [u8; 32],
333 receiving_interface: rns_core::transport::types::InterfaceId,
334 rng: &mut dyn Rng,
335 ) -> Vec<LinkManagerAction> {
336 let packet = match RawPacket::unpack(raw) {
337 Ok(p) => p,
338 Err(_) => return Vec::new(),
339 };
340
341 match packet.flags.packet_type {
342 constants::PACKET_TYPE_LINKREQUEST => {
343 self.handle_linkrequest(&dest_hash, &packet, receiving_interface, rng)
344 }
345 constants::PACKET_TYPE_PROOF if packet.context == constants::CONTEXT_LRPROOF => {
346 self.handle_lrproof(&dest_hash, &packet, rng)
348 }
349 constants::PACKET_TYPE_DATA => {
350 self.handle_link_data(&dest_hash, &packet, packet_hash, rng)
351 }
352 _ => Vec::new(),
353 }
354 }
355
356 fn handle_linkrequest(
358 &mut self,
359 dest_hash: &[u8; 16],
360 packet: &RawPacket,
361 receiving_interface: rns_core::transport::types::InterfaceId,
362 rng: &mut dyn Rng,
363 ) -> Vec<LinkManagerAction> {
364 let ld = match self.link_destinations.get(dest_hash) {
366 Some(ld) => ld,
367 None => return Vec::new(),
368 };
369
370 let hashable = packet.get_hashable_part();
371 let now = time::now();
372
373 let (engine, lrproof_data) = match LinkEngine::new_responder(
375 &ld.sig_prv,
376 &ld.sig_pub_bytes,
377 &packet.data,
378 &hashable,
379 dest_hash,
380 packet.hops,
381 now,
382 rng,
383 ) {
384 Ok(r) => r,
385 Err(e) => {
386 log::debug!("LINKREQUEST rejected: {}", e);
387 return Vec::new();
388 }
389 };
390
391 let link_id = *engine.link_id();
392
393 let managed = ManagedLink {
394 engine,
395 channel: None,
396 dest_hash: *dest_hash,
397 remote_identity: None,
398 dest_sig_pub_bytes: None,
399 incoming_resources: Vec::new(),
400 outgoing_resources: Vec::new(),
401 resource_strategy: ld.resource_strategy,
402 };
403 self.links.insert(link_id, managed);
404
405 let flags = PacketFlags {
407 header_type: constants::HEADER_1,
408 context_flag: constants::FLAG_UNSET,
409 transport_type: constants::TRANSPORT_BROADCAST,
410 destination_type: constants::DESTINATION_LINK,
411 packet_type: constants::PACKET_TYPE_PROOF,
412 };
413
414 let mut actions = Vec::new();
415
416 actions.push(LinkManagerAction::RegisterLinkDest { link_id });
418
419 if let Ok(pkt) = RawPacket::pack(
420 flags,
421 0,
422 &link_id,
423 None,
424 constants::CONTEXT_LRPROOF,
425 &lrproof_data,
426 ) {
427 actions.push(LinkManagerAction::SendPacket {
428 raw: pkt.raw,
429 dest_type: constants::DESTINATION_LINK,
430 attached_interface: None,
431 });
432 }
433
434 actions.push(LinkManagerAction::LinkRequestReceived {
436 link_id,
437 receiving_interface,
438 });
439
440 actions
441 }
442
443 fn handle_lrproof(
445 &mut self,
446 link_id_bytes: &[u8; 16],
447 packet: &RawPacket,
448 rng: &mut dyn Rng,
449 ) -> Vec<LinkManagerAction> {
450 let link = match self.links.get_mut(link_id_bytes) {
451 Some(l) => l,
452 None => return Vec::new(),
453 };
454
455 if link.engine.state() != LinkState::Pending || !link.engine.is_initiator() {
456 return Vec::new();
457 }
458
459 let dest_sig_pub_bytes = match link.dest_sig_pub_bytes {
461 Some(b) => b,
462 None => {
463 log::debug!("LRPROOF: no destination signing key available");
464 return Vec::new();
465 }
466 };
467
468 let now = time::now();
469 let (lrrtt_encrypted, link_actions) =
470 match link
471 .engine
472 .handle_lrproof(&packet.data, &dest_sig_pub_bytes, now, rng)
473 {
474 Ok(r) => r,
475 Err(e) => {
476 log::debug!("LRPROOF validation failed: {}", e);
477 return Vec::new();
478 }
479 };
480
481 let link_id = *link.engine.link_id();
482 let mut actions = Vec::new();
483
484 actions.extend(self.process_link_actions(&link_id, &link_actions));
486
487 let flags = PacketFlags {
489 header_type: constants::HEADER_1,
490 context_flag: constants::FLAG_UNSET,
491 transport_type: constants::TRANSPORT_BROADCAST,
492 destination_type: constants::DESTINATION_LINK,
493 packet_type: constants::PACKET_TYPE_DATA,
494 };
495
496 if let Ok(pkt) = RawPacket::pack(
497 flags,
498 0,
499 &link_id,
500 None,
501 constants::CONTEXT_LRRTT,
502 &lrrtt_encrypted,
503 ) {
504 actions.push(LinkManagerAction::SendPacket {
505 raw: pkt.raw,
506 dest_type: constants::DESTINATION_LINK,
507 attached_interface: None,
508 });
509 }
510
511 if let Some(link) = self.links.get_mut(&link_id) {
513 if link.engine.state() == LinkState::Active {
514 let rtt = link.engine.rtt().unwrap_or(1.0);
515 link.channel = Some(Channel::new(rtt));
516 }
517 }
518
519 actions
520 }
521
522 fn handle_link_data(
528 &mut self,
529 link_id_bytes: &[u8; 16],
530 packet: &RawPacket,
531 packet_hash: [u8; 32],
532 rng: &mut dyn Rng,
533 ) -> Vec<LinkManagerAction> {
534 enum LinkDataResult {
536 Lrrtt {
537 link_id: LinkId,
538 link_actions: Vec<LinkAction>,
539 },
540 Identify {
541 link_id: LinkId,
542 link_actions: Vec<LinkAction>,
543 },
544 Keepalive {
545 link_id: LinkId,
546 inbound_actions: Vec<LinkAction>,
547 },
548 LinkClose {
549 link_id: LinkId,
550 teardown_actions: Vec<LinkAction>,
551 },
552 Channel {
553 link_id: LinkId,
554 inbound_actions: Vec<LinkAction>,
555 plaintext: Vec<u8>,
556 },
557 Request {
558 link_id: LinkId,
559 inbound_actions: Vec<LinkAction>,
560 plaintext: Vec<u8>,
561 },
562 Response {
563 link_id: LinkId,
564 inbound_actions: Vec<LinkAction>,
565 plaintext: Vec<u8>,
566 },
567 Generic {
568 link_id: LinkId,
569 inbound_actions: Vec<LinkAction>,
570 plaintext: Vec<u8>,
571 context: u8,
572 packet_hash: [u8; 32],
573 },
574 ResourceAdv {
576 link_id: LinkId,
577 inbound_actions: Vec<LinkAction>,
578 plaintext: Vec<u8>,
579 },
580 ResourceReq {
582 link_id: LinkId,
583 inbound_actions: Vec<LinkAction>,
584 plaintext: Vec<u8>,
585 },
586 ResourceHmu {
588 link_id: LinkId,
589 inbound_actions: Vec<LinkAction>,
590 plaintext: Vec<u8>,
591 },
592 ResourcePart {
594 link_id: LinkId,
595 inbound_actions: Vec<LinkAction>,
596 raw_data: Vec<u8>,
597 },
598 ResourcePrf {
600 link_id: LinkId,
601 inbound_actions: Vec<LinkAction>,
602 plaintext: Vec<u8>,
603 },
604 ResourceIcl {
606 link_id: LinkId,
607 inbound_actions: Vec<LinkAction>,
608 },
609 ResourceRcl {
611 link_id: LinkId,
612 inbound_actions: Vec<LinkAction>,
613 },
614 Error,
615 }
616
617 let result = {
618 let link = match self.links.get_mut(link_id_bytes) {
619 Some(l) => l,
620 None => return Vec::new(),
621 };
622
623 match packet.context {
624 constants::CONTEXT_LRRTT => {
625 match link.engine.handle_lrrtt(&packet.data, time::now()) {
626 Ok(link_actions) => {
627 let link_id = *link.engine.link_id();
628 LinkDataResult::Lrrtt {
629 link_id,
630 link_actions,
631 }
632 }
633 Err(e) => {
634 log::debug!("LRRTT handling failed: {}", e);
635 LinkDataResult::Error
636 }
637 }
638 }
639 constants::CONTEXT_LINKIDENTIFY => {
640 match link.engine.handle_identify(&packet.data) {
641 Ok(link_actions) => {
642 let link_id = *link.engine.link_id();
643 link.remote_identity = link.engine.remote_identity().cloned();
644 LinkDataResult::Identify {
645 link_id,
646 link_actions,
647 }
648 }
649 Err(e) => {
650 log::debug!("LINKIDENTIFY failed: {}", e);
651 LinkDataResult::Error
652 }
653 }
654 }
655 constants::CONTEXT_KEEPALIVE => {
656 let inbound_actions = link.engine.record_inbound(time::now());
657 let link_id = *link.engine.link_id();
658 LinkDataResult::Keepalive {
659 link_id,
660 inbound_actions,
661 }
662 }
663 constants::CONTEXT_LINKCLOSE => {
664 let teardown_actions = link.engine.handle_teardown();
665 let link_id = *link.engine.link_id();
666 LinkDataResult::LinkClose {
667 link_id,
668 teardown_actions,
669 }
670 }
671 constants::CONTEXT_CHANNEL => match link.engine.decrypt(&packet.data) {
672 Ok(plaintext) => {
673 let inbound_actions = link.engine.record_inbound(time::now());
674 let link_id = *link.engine.link_id();
675 LinkDataResult::Channel {
676 link_id,
677 inbound_actions,
678 plaintext,
679 }
680 }
681 Err(_) => LinkDataResult::Error,
682 },
683 constants::CONTEXT_REQUEST => match link.engine.decrypt(&packet.data) {
684 Ok(plaintext) => {
685 let inbound_actions = link.engine.record_inbound(time::now());
686 let link_id = *link.engine.link_id();
687 LinkDataResult::Request {
688 link_id,
689 inbound_actions,
690 plaintext,
691 }
692 }
693 Err(_) => LinkDataResult::Error,
694 },
695 constants::CONTEXT_RESPONSE => match link.engine.decrypt(&packet.data) {
696 Ok(plaintext) => {
697 let inbound_actions = link.engine.record_inbound(time::now());
698 let link_id = *link.engine.link_id();
699 LinkDataResult::Response {
700 link_id,
701 inbound_actions,
702 plaintext,
703 }
704 }
705 Err(_) => LinkDataResult::Error,
706 },
707 constants::CONTEXT_RESOURCE_ADV => match link.engine.decrypt(&packet.data) {
709 Ok(plaintext) => {
710 let inbound_actions = link.engine.record_inbound(time::now());
711 let link_id = *link.engine.link_id();
712 LinkDataResult::ResourceAdv {
713 link_id,
714 inbound_actions,
715 plaintext,
716 }
717 }
718 Err(_) => LinkDataResult::Error,
719 },
720 constants::CONTEXT_RESOURCE_REQ => match link.engine.decrypt(&packet.data) {
721 Ok(plaintext) => {
722 let inbound_actions = link.engine.record_inbound(time::now());
723 let link_id = *link.engine.link_id();
724 LinkDataResult::ResourceReq {
725 link_id,
726 inbound_actions,
727 plaintext,
728 }
729 }
730 Err(_) => LinkDataResult::Error,
731 },
732 constants::CONTEXT_RESOURCE_HMU => match link.engine.decrypt(&packet.data) {
733 Ok(plaintext) => {
734 let inbound_actions = link.engine.record_inbound(time::now());
735 let link_id = *link.engine.link_id();
736 LinkDataResult::ResourceHmu {
737 link_id,
738 inbound_actions,
739 plaintext,
740 }
741 }
742 Err(_) => LinkDataResult::Error,
743 },
744 constants::CONTEXT_RESOURCE => {
745 let inbound_actions = link.engine.record_inbound(time::now());
747 let link_id = *link.engine.link_id();
748 LinkDataResult::ResourcePart {
749 link_id,
750 inbound_actions,
751 raw_data: packet.data.clone(),
752 }
753 }
754 constants::CONTEXT_RESOURCE_PRF => match link.engine.decrypt(&packet.data) {
755 Ok(plaintext) => {
756 let inbound_actions = link.engine.record_inbound(time::now());
757 let link_id = *link.engine.link_id();
758 LinkDataResult::ResourcePrf {
759 link_id,
760 inbound_actions,
761 plaintext,
762 }
763 }
764 Err(_) => LinkDataResult::Error,
765 },
766 constants::CONTEXT_RESOURCE_ICL => {
767 let _ = link.engine.decrypt(&packet.data); let inbound_actions = link.engine.record_inbound(time::now());
769 let link_id = *link.engine.link_id();
770 LinkDataResult::ResourceIcl {
771 link_id,
772 inbound_actions,
773 }
774 }
775 constants::CONTEXT_RESOURCE_RCL => {
776 let _ = link.engine.decrypt(&packet.data); let inbound_actions = link.engine.record_inbound(time::now());
778 let link_id = *link.engine.link_id();
779 LinkDataResult::ResourceRcl {
780 link_id,
781 inbound_actions,
782 }
783 }
784 _ => match link.engine.decrypt(&packet.data) {
785 Ok(plaintext) => {
786 let inbound_actions = link.engine.record_inbound(time::now());
787 let link_id = *link.engine.link_id();
788 LinkDataResult::Generic {
789 link_id,
790 inbound_actions,
791 plaintext,
792 context: packet.context,
793 packet_hash,
794 }
795 }
796 Err(_) => LinkDataResult::Error,
797 },
798 }
799 }; let mut actions = Vec::new();
803 match result {
804 LinkDataResult::Lrrtt {
805 link_id,
806 link_actions,
807 } => {
808 actions.extend(self.process_link_actions(&link_id, &link_actions));
809 if let Some(link) = self.links.get_mut(&link_id) {
811 if link.engine.state() == LinkState::Active {
812 let rtt = link.engine.rtt().unwrap_or(1.0);
813 link.channel = Some(Channel::new(rtt));
814 }
815 }
816 }
817 LinkDataResult::Identify {
818 link_id,
819 link_actions,
820 } => {
821 actions.extend(self.process_link_actions(&link_id, &link_actions));
822 }
823 LinkDataResult::Keepalive {
824 link_id,
825 inbound_actions,
826 } => {
827 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
828 }
834 LinkDataResult::LinkClose {
835 link_id,
836 teardown_actions,
837 } => {
838 actions.extend(self.process_link_actions(&link_id, &teardown_actions));
839 }
840 LinkDataResult::Channel {
841 link_id,
842 inbound_actions,
843 plaintext,
844 } => {
845 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
846 if let Some(link) = self.links.get_mut(&link_id) {
848 if let Some(ref mut channel) = link.channel {
849 let chan_actions = channel.receive(&plaintext, time::now());
850 let _ = link;
852 actions.extend(self.process_channel_actions(&link_id, chan_actions, rng));
853 }
854 }
855 }
856 LinkDataResult::Request {
857 link_id,
858 inbound_actions,
859 plaintext,
860 } => {
861 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
862 actions.extend(self.handle_request(&link_id, &plaintext, rng));
863 }
864 LinkDataResult::Response {
865 link_id,
866 inbound_actions,
867 plaintext,
868 } => {
869 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
870 actions.extend(self.handle_response(&link_id, &plaintext));
872 }
873 LinkDataResult::Generic {
874 link_id,
875 inbound_actions,
876 plaintext,
877 context,
878 packet_hash,
879 } => {
880 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
881 actions.push(LinkManagerAction::LinkDataReceived {
882 link_id,
883 context,
884 data: plaintext,
885 });
886
887 if let Some(link) = self.links.get(&link_id) {
889 if let Some(ld) = self.link_destinations.get(&link.dest_hash) {
890 let signature = ld.sig_prv.sign(&packet_hash);
891 let mut proof_data = Vec::with_capacity(96);
892 proof_data.extend_from_slice(&packet_hash);
893 proof_data.extend_from_slice(&signature);
894
895 let flags = PacketFlags {
896 header_type: constants::HEADER_1,
897 context_flag: constants::FLAG_UNSET,
898 transport_type: constants::TRANSPORT_BROADCAST,
899 destination_type: constants::DESTINATION_LINK,
900 packet_type: constants::PACKET_TYPE_PROOF,
901 };
902 if let Ok(pkt) = RawPacket::pack(
903 flags,
904 0,
905 &link_id,
906 None,
907 constants::CONTEXT_NONE,
908 &proof_data,
909 ) {
910 actions.push(LinkManagerAction::SendPacket {
911 raw: pkt.raw,
912 dest_type: constants::DESTINATION_LINK,
913 attached_interface: None,
914 });
915 }
916 }
917 }
918 }
919 LinkDataResult::ResourceAdv {
920 link_id,
921 inbound_actions,
922 plaintext,
923 } => {
924 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
925 actions.extend(self.handle_resource_adv(&link_id, &plaintext, rng));
926 }
927 LinkDataResult::ResourceReq {
928 link_id,
929 inbound_actions,
930 plaintext,
931 } => {
932 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
933 actions.extend(self.handle_resource_req(&link_id, &plaintext, rng));
934 }
935 LinkDataResult::ResourceHmu {
936 link_id,
937 inbound_actions,
938 plaintext,
939 } => {
940 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
941 actions.extend(self.handle_resource_hmu(&link_id, &plaintext, rng));
942 }
943 LinkDataResult::ResourcePart {
944 link_id,
945 inbound_actions,
946 raw_data,
947 } => {
948 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
949 actions.extend(self.handle_resource_part(&link_id, &raw_data, rng));
950 }
951 LinkDataResult::ResourcePrf {
952 link_id,
953 inbound_actions,
954 plaintext,
955 } => {
956 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
957 actions.extend(self.handle_resource_prf(&link_id, &plaintext));
958 }
959 LinkDataResult::ResourceIcl {
960 link_id,
961 inbound_actions,
962 } => {
963 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
964 actions.extend(self.handle_resource_icl(&link_id));
965 }
966 LinkDataResult::ResourceRcl {
967 link_id,
968 inbound_actions,
969 } => {
970 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
971 actions.extend(self.handle_resource_rcl(&link_id));
972 }
973 LinkDataResult::Error => {}
974 }
975
976 actions
977 }
978
979 fn handle_request(
981 &mut self,
982 link_id: &LinkId,
983 plaintext: &[u8],
984 rng: &mut dyn Rng,
985 ) -> Vec<LinkManagerAction> {
986 use rns_core::msgpack::{self, Value};
987
988 let arr = match msgpack::unpack_exact(plaintext) {
990 Ok(Value::Array(arr)) if arr.len() >= 3 => arr,
991 _ => return Vec::new(),
992 };
993
994 let path_hash_bytes = match &arr[1] {
995 Value::Bin(b) if b.len() == 16 => b,
996 _ => return Vec::new(),
997 };
998 let mut path_hash = [0u8; 16];
999 path_hash.copy_from_slice(path_hash_bytes);
1000
1001 let request_id = rns_core::hash::truncated_hash(plaintext);
1003
1004 let request_data = msgpack::pack(&arr[2]);
1006
1007 if self.management_paths.contains(&path_hash) {
1009 let remote_identity = self
1010 .links
1011 .get(link_id)
1012 .and_then(|l| l.remote_identity)
1013 .map(|(h, k)| (h, k));
1014 return vec![LinkManagerAction::ManagementRequest {
1015 link_id: *link_id,
1016 path_hash,
1017 data: request_data,
1018 request_id,
1019 remote_identity,
1020 }];
1021 }
1022
1023 let handler_idx = self
1025 .request_handlers
1026 .iter()
1027 .position(|h| h.path_hash == path_hash);
1028 let handler_idx = match handler_idx {
1029 Some(i) => i,
1030 None => return Vec::new(),
1031 };
1032
1033 let remote_identity = self
1035 .links
1036 .get(link_id)
1037 .and_then(|l| l.remote_identity.as_ref());
1038 let handler = &self.request_handlers[handler_idx];
1039 if let Some(ref allowed) = handler.allowed_list {
1040 match remote_identity {
1041 Some((identity_hash, _)) => {
1042 if !allowed.contains(identity_hash) {
1043 log::debug!("Request denied: identity not in allowed list");
1044 return Vec::new();
1045 }
1046 }
1047 None => {
1048 log::debug!("Request denied: peer not identified");
1049 return Vec::new();
1050 }
1051 }
1052 }
1053
1054 let path = handler.path.clone();
1056 let response = (handler.handler)(*link_id, &path, &request_data, remote_identity);
1057
1058 let mut actions = Vec::new();
1059 if let Some(response_data) = response {
1060 actions.extend(self.build_response_packet(link_id, &request_id, &response_data, rng));
1061 }
1062
1063 actions
1064 }
1065
1066 fn build_response_packet(
1069 &self,
1070 link_id: &LinkId,
1071 request_id: &[u8; 16],
1072 response_data: &[u8],
1073 rng: &mut dyn Rng,
1074 ) -> Vec<LinkManagerAction> {
1075 use rns_core::msgpack::{self, Value};
1076
1077 let response_value = msgpack::unpack_exact(response_data)
1079 .unwrap_or_else(|_| Value::Bin(response_data.to_vec()));
1080
1081 let response_array = Value::Array(vec![Value::Bin(request_id.to_vec()), response_value]);
1082 let response_plaintext = msgpack::pack(&response_array);
1083
1084 let mut actions = Vec::new();
1085 if let Some(link) = self.links.get(link_id) {
1086 if let Ok(encrypted) = link.engine.encrypt(&response_plaintext, rng) {
1087 let flags = PacketFlags {
1088 header_type: constants::HEADER_1,
1089 context_flag: constants::FLAG_UNSET,
1090 transport_type: constants::TRANSPORT_BROADCAST,
1091 destination_type: constants::DESTINATION_LINK,
1092 packet_type: constants::PACKET_TYPE_DATA,
1093 };
1094 if let Ok(pkt) = RawPacket::pack(
1095 flags,
1096 0,
1097 link_id,
1098 None,
1099 constants::CONTEXT_RESPONSE,
1100 &encrypted,
1101 ) {
1102 actions.push(LinkManagerAction::SendPacket {
1103 raw: pkt.raw,
1104 dest_type: constants::DESTINATION_LINK,
1105 attached_interface: None,
1106 });
1107 }
1108 }
1109 }
1110 actions
1111 }
1112
1113 pub fn send_management_response(
1116 &self,
1117 link_id: &LinkId,
1118 request_id: &[u8; 16],
1119 response_data: &[u8],
1120 rng: &mut dyn Rng,
1121 ) -> Vec<LinkManagerAction> {
1122 self.build_response_packet(link_id, request_id, response_data, rng)
1123 }
1124
1125 pub fn send_request(
1133 &self,
1134 link_id: &LinkId,
1135 path: &str,
1136 data: &[u8],
1137 rng: &mut dyn Rng,
1138 ) -> Vec<LinkManagerAction> {
1139 use rns_core::msgpack::{self, Value};
1140
1141 let link = match self.links.get(link_id) {
1142 Some(l) => l,
1143 None => return Vec::new(),
1144 };
1145
1146 if link.engine.state() != LinkState::Active {
1147 return Vec::new();
1148 }
1149
1150 let path_hash = compute_path_hash(path);
1151
1152 let data_value = msgpack::unpack_exact(data).unwrap_or_else(|_| Value::Bin(data.to_vec()));
1154
1155 let request_array = Value::Array(vec![
1157 Value::Float(time::now()),
1158 Value::Bin(path_hash.to_vec()),
1159 data_value,
1160 ]);
1161 let plaintext = msgpack::pack(&request_array);
1162
1163 let encrypted = match link.engine.encrypt(&plaintext, rng) {
1164 Ok(e) => e,
1165 Err(_) => return Vec::new(),
1166 };
1167
1168 let flags = PacketFlags {
1169 header_type: constants::HEADER_1,
1170 context_flag: constants::FLAG_UNSET,
1171 transport_type: constants::TRANSPORT_BROADCAST,
1172 destination_type: constants::DESTINATION_LINK,
1173 packet_type: constants::PACKET_TYPE_DATA,
1174 };
1175
1176 let mut actions = Vec::new();
1177 if let Ok(pkt) = RawPacket::pack(
1178 flags,
1179 0,
1180 link_id,
1181 None,
1182 constants::CONTEXT_REQUEST,
1183 &encrypted,
1184 ) {
1185 actions.push(LinkManagerAction::SendPacket {
1186 raw: pkt.raw,
1187 dest_type: constants::DESTINATION_LINK,
1188 attached_interface: None,
1189 });
1190 }
1191 actions
1192 }
1193
1194 pub fn send_on_link(
1196 &self,
1197 link_id: &LinkId,
1198 plaintext: &[u8],
1199 context: u8,
1200 rng: &mut dyn Rng,
1201 ) -> Vec<LinkManagerAction> {
1202 let link = match self.links.get(link_id) {
1203 Some(l) => l,
1204 None => return Vec::new(),
1205 };
1206
1207 if link.engine.state() != LinkState::Active {
1208 return Vec::new();
1209 }
1210
1211 let encrypted = match link.engine.encrypt(plaintext, rng) {
1212 Ok(e) => e,
1213 Err(_) => return Vec::new(),
1214 };
1215
1216 let flags = PacketFlags {
1217 header_type: constants::HEADER_1,
1218 context_flag: constants::FLAG_UNSET,
1219 transport_type: constants::TRANSPORT_BROADCAST,
1220 destination_type: constants::DESTINATION_LINK,
1221 packet_type: constants::PACKET_TYPE_DATA,
1222 };
1223
1224 let mut actions = Vec::new();
1225 if let Ok(pkt) = RawPacket::pack(flags, 0, link_id, None, context, &encrypted) {
1226 actions.push(LinkManagerAction::SendPacket {
1227 raw: pkt.raw,
1228 dest_type: constants::DESTINATION_LINK,
1229 attached_interface: None,
1230 });
1231 }
1232 actions
1233 }
1234
1235 pub fn identify(
1237 &self,
1238 link_id: &LinkId,
1239 identity: &rns_crypto::identity::Identity,
1240 rng: &mut dyn Rng,
1241 ) -> Vec<LinkManagerAction> {
1242 let link = match self.links.get(link_id) {
1243 Some(l) => l,
1244 None => return Vec::new(),
1245 };
1246
1247 let encrypted = match link.engine.build_identify(identity, rng) {
1248 Ok(e) => e,
1249 Err(_) => return Vec::new(),
1250 };
1251
1252 let flags = PacketFlags {
1253 header_type: constants::HEADER_1,
1254 context_flag: constants::FLAG_UNSET,
1255 transport_type: constants::TRANSPORT_BROADCAST,
1256 destination_type: constants::DESTINATION_LINK,
1257 packet_type: constants::PACKET_TYPE_DATA,
1258 };
1259
1260 let mut actions = Vec::new();
1261 if let Ok(pkt) = RawPacket::pack(
1262 flags,
1263 0,
1264 link_id,
1265 None,
1266 constants::CONTEXT_LINKIDENTIFY,
1267 &encrypted,
1268 ) {
1269 actions.push(LinkManagerAction::SendPacket {
1270 raw: pkt.raw,
1271 dest_type: constants::DESTINATION_LINK,
1272 attached_interface: None,
1273 });
1274 }
1275 actions
1276 }
1277
1278 pub fn teardown_link(&mut self, link_id: &LinkId) -> Vec<LinkManagerAction> {
1280 let link = match self.links.get_mut(link_id) {
1281 Some(l) => l,
1282 None => return Vec::new(),
1283 };
1284
1285 let teardown_actions = link.engine.teardown();
1286 if let Some(ref mut channel) = link.channel {
1287 channel.shutdown();
1288 }
1289
1290 let mut actions = self.process_link_actions(link_id, &teardown_actions);
1291
1292 let flags = PacketFlags {
1294 header_type: constants::HEADER_1,
1295 context_flag: constants::FLAG_UNSET,
1296 transport_type: constants::TRANSPORT_BROADCAST,
1297 destination_type: constants::DESTINATION_LINK,
1298 packet_type: constants::PACKET_TYPE_DATA,
1299 };
1300 if let Ok(pkt) = RawPacket::pack(flags, 0, link_id, None, constants::CONTEXT_LINKCLOSE, &[])
1301 {
1302 actions.push(LinkManagerAction::SendPacket {
1303 raw: pkt.raw,
1304 dest_type: constants::DESTINATION_LINK,
1305 attached_interface: None,
1306 });
1307 }
1308
1309 actions
1310 }
1311
1312 fn handle_response(&self, link_id: &LinkId, plaintext: &[u8]) -> Vec<LinkManagerAction> {
1314 use rns_core::msgpack;
1315
1316 let arr = match msgpack::unpack_exact(plaintext) {
1318 Ok(msgpack::Value::Array(arr)) if arr.len() >= 2 => arr,
1319 _ => return Vec::new(),
1320 };
1321
1322 let request_id_bytes = match &arr[0] {
1323 msgpack::Value::Bin(b) if b.len() == 16 => b,
1324 _ => return Vec::new(),
1325 };
1326 let mut request_id = [0u8; 16];
1327 request_id.copy_from_slice(request_id_bytes);
1328
1329 let response_data = msgpack::pack(&arr[1]);
1330
1331 vec![LinkManagerAction::ResponseReceived {
1332 link_id: *link_id,
1333 request_id,
1334 data: response_data,
1335 }]
1336 }
1337
1338 fn handle_resource_adv(
1340 &mut self,
1341 link_id: &LinkId,
1342 adv_plaintext: &[u8],
1343 rng: &mut dyn Rng,
1344 ) -> Vec<LinkManagerAction> {
1345 let link = match self.links.get_mut(link_id) {
1346 Some(l) => l,
1347 None => return Vec::new(),
1348 };
1349
1350 let link_rtt = link.engine.rtt().unwrap_or(1.0);
1351 let now = time::now();
1352
1353 let receiver = match ResourceReceiver::from_advertisement(
1354 adv_plaintext,
1355 constants::RESOURCE_SDU,
1356 link_rtt,
1357 now,
1358 None,
1359 None,
1360 ) {
1361 Ok(r) => r,
1362 Err(e) => {
1363 log::debug!("Resource ADV rejected: {}", e);
1364 return Vec::new();
1365 }
1366 };
1367
1368 let strategy = link.resource_strategy;
1369 let resource_hash = receiver.resource_hash.clone();
1370 let transfer_size = receiver.transfer_size;
1371 let has_metadata = receiver.has_metadata;
1372
1373 match strategy {
1374 ResourceStrategy::AcceptNone => {
1375 let reject_actions = {
1377 let mut r = receiver;
1378 r.reject()
1379 };
1380 self.process_resource_actions(link_id, reject_actions, rng)
1381 }
1382 ResourceStrategy::AcceptAll => {
1383 link.incoming_resources.push(receiver);
1384 let idx = link.incoming_resources.len() - 1;
1385 let resource_actions = link.incoming_resources[idx].accept(now);
1386 let _ = link;
1387 self.process_resource_actions(link_id, resource_actions, rng)
1388 }
1389 ResourceStrategy::AcceptApp => {
1390 link.incoming_resources.push(receiver);
1391 vec![LinkManagerAction::ResourceAcceptQuery {
1393 link_id: *link_id,
1394 resource_hash,
1395 transfer_size,
1396 has_metadata,
1397 }]
1398 }
1399 }
1400 }
1401
1402 pub fn accept_resource(
1404 &mut self,
1405 link_id: &LinkId,
1406 resource_hash: &[u8],
1407 accept: bool,
1408 rng: &mut dyn Rng,
1409 ) -> Vec<LinkManagerAction> {
1410 let link = match self.links.get_mut(link_id) {
1411 Some(l) => l,
1412 None => return Vec::new(),
1413 };
1414
1415 let now = time::now();
1416 let idx = link
1417 .incoming_resources
1418 .iter()
1419 .position(|r| r.resource_hash == resource_hash);
1420 let idx = match idx {
1421 Some(i) => i,
1422 None => return Vec::new(),
1423 };
1424
1425 let resource_actions = if accept {
1426 link.incoming_resources[idx].accept(now)
1427 } else {
1428 link.incoming_resources[idx].reject()
1429 };
1430
1431 let _ = link;
1432 self.process_resource_actions(link_id, resource_actions, rng)
1433 }
1434
1435 fn handle_resource_req(
1437 &mut self,
1438 link_id: &LinkId,
1439 plaintext: &[u8],
1440 rng: &mut dyn Rng,
1441 ) -> Vec<LinkManagerAction> {
1442 let link = match self.links.get_mut(link_id) {
1443 Some(l) => l,
1444 None => return Vec::new(),
1445 };
1446
1447 let now = time::now();
1448 let mut all_actions = Vec::new();
1449 for sender in &mut link.outgoing_resources {
1450 let resource_actions = sender.handle_request(plaintext, now);
1451 if !resource_actions.is_empty() {
1452 all_actions.extend(resource_actions);
1453 break;
1454 }
1455 }
1456
1457 let _ = link;
1458 self.process_resource_actions(link_id, all_actions, rng)
1459 }
1460
1461 fn handle_resource_hmu(
1463 &mut self,
1464 link_id: &LinkId,
1465 plaintext: &[u8],
1466 rng: &mut dyn Rng,
1467 ) -> Vec<LinkManagerAction> {
1468 let link = match self.links.get_mut(link_id) {
1469 Some(l) => l,
1470 None => return Vec::new(),
1471 };
1472
1473 let now = time::now();
1474 let mut all_actions = Vec::new();
1475 for receiver in &mut link.incoming_resources {
1476 let resource_actions = receiver.handle_hashmap_update(plaintext, now);
1477 if !resource_actions.is_empty() {
1478 all_actions.extend(resource_actions);
1479 break;
1480 }
1481 }
1482
1483 let _ = link;
1484 self.process_resource_actions(link_id, all_actions, rng)
1485 }
1486
1487 fn handle_resource_part(
1489 &mut self,
1490 link_id: &LinkId,
1491 raw_data: &[u8],
1492 rng: &mut dyn Rng,
1493 ) -> Vec<LinkManagerAction> {
1494 let link = match self.links.get_mut(link_id) {
1495 Some(l) => l,
1496 None => return Vec::new(),
1497 };
1498
1499 let now = time::now();
1500 let mut all_actions = Vec::new();
1501 let mut assemble_idx = None;
1502
1503 for (idx, receiver) in link.incoming_resources.iter_mut().enumerate() {
1504 let resource_actions = receiver.receive_part(raw_data, now);
1505 if !resource_actions.is_empty() {
1506 if receiver.received_count == receiver.total_parts {
1508 assemble_idx = Some(idx);
1509 }
1510 all_actions.extend(resource_actions);
1511 break;
1512 }
1513 }
1514
1515 if let Some(idx) = assemble_idx {
1517 let decrypt_fn = |ciphertext: &[u8]| -> Result<Vec<u8>, ()> {
1518 link.engine.decrypt(ciphertext).map_err(|_| ())
1519 };
1520 let assemble_actions =
1521 link.incoming_resources[idx].assemble(&decrypt_fn, &Bzip2Compressor);
1522 all_actions.extend(assemble_actions);
1523 }
1524
1525 let _ = link;
1526 self.process_resource_actions(link_id, all_actions, rng)
1527 }
1528
1529 fn handle_resource_prf(
1531 &mut self,
1532 link_id: &LinkId,
1533 plaintext: &[u8],
1534 ) -> Vec<LinkManagerAction> {
1535 let link = match self.links.get_mut(link_id) {
1536 Some(l) => l,
1537 None => return Vec::new(),
1538 };
1539
1540 let now = time::now();
1541 let mut result_actions = Vec::new();
1542 for sender in &mut link.outgoing_resources {
1543 let resource_actions = sender.handle_proof(plaintext, now);
1544 if !resource_actions.is_empty() {
1545 result_actions.extend(resource_actions);
1546 break;
1547 }
1548 }
1549
1550 let mut actions = Vec::new();
1552 for ra in result_actions {
1553 match ra {
1554 ResourceAction::Completed => {
1555 actions.push(LinkManagerAction::ResourceCompleted { link_id: *link_id });
1556 }
1557 ResourceAction::Failed(e) => {
1558 actions.push(LinkManagerAction::ResourceFailed {
1559 link_id: *link_id,
1560 error: format!("{}", e),
1561 });
1562 }
1563 _ => {}
1564 }
1565 }
1566
1567 link.outgoing_resources
1569 .retain(|s| s.status < rns_core::resource::ResourceStatus::Complete);
1570
1571 actions
1572 }
1573
1574 fn handle_resource_icl(&mut self, link_id: &LinkId) -> Vec<LinkManagerAction> {
1576 let link = match self.links.get_mut(link_id) {
1577 Some(l) => l,
1578 None => return Vec::new(),
1579 };
1580
1581 let mut actions = Vec::new();
1582 for receiver in &mut link.incoming_resources {
1583 let ra = receiver.handle_cancel();
1584 for a in ra {
1585 if let ResourceAction::Failed(ref e) = a {
1586 actions.push(LinkManagerAction::ResourceFailed {
1587 link_id: *link_id,
1588 error: format!("{}", e),
1589 });
1590 }
1591 }
1592 }
1593 link.incoming_resources
1594 .retain(|r| r.status < rns_core::resource::ResourceStatus::Complete);
1595 actions
1596 }
1597
1598 fn handle_resource_rcl(&mut self, link_id: &LinkId) -> Vec<LinkManagerAction> {
1600 let link = match self.links.get_mut(link_id) {
1601 Some(l) => l,
1602 None => return Vec::new(),
1603 };
1604
1605 let mut actions = Vec::new();
1606 for sender in &mut link.outgoing_resources {
1607 let ra = sender.handle_reject();
1608 for a in ra {
1609 if let ResourceAction::Failed(ref e) = a {
1610 actions.push(LinkManagerAction::ResourceFailed {
1611 link_id: *link_id,
1612 error: format!("{}", e),
1613 });
1614 }
1615 }
1616 }
1617 link.outgoing_resources
1618 .retain(|s| s.status < rns_core::resource::ResourceStatus::Complete);
1619 actions
1620 }
1621
1622 fn process_resource_actions(
1624 &self,
1625 link_id: &LinkId,
1626 actions: Vec<ResourceAction>,
1627 rng: &mut dyn Rng,
1628 ) -> Vec<LinkManagerAction> {
1629 let link = match self.links.get(link_id) {
1630 Some(l) => l,
1631 None => return Vec::new(),
1632 };
1633
1634 let mut result = Vec::new();
1635 for action in actions {
1636 match action {
1637 ResourceAction::SendAdvertisement(data) => {
1638 if let Ok(encrypted) = link.engine.encrypt(&data, rng) {
1640 result.extend(self.build_link_packet(
1641 link_id,
1642 constants::CONTEXT_RESOURCE_ADV,
1643 &encrypted,
1644 ));
1645 }
1646 }
1647 ResourceAction::SendPart(data) => {
1648 result.extend(self.build_link_packet(
1650 link_id,
1651 constants::CONTEXT_RESOURCE,
1652 &data,
1653 ));
1654 }
1655 ResourceAction::SendRequest(data) => {
1656 if let Ok(encrypted) = link.engine.encrypt(&data, rng) {
1657 result.extend(self.build_link_packet(
1658 link_id,
1659 constants::CONTEXT_RESOURCE_REQ,
1660 &encrypted,
1661 ));
1662 }
1663 }
1664 ResourceAction::SendHmu(data) => {
1665 if let Ok(encrypted) = link.engine.encrypt(&data, rng) {
1666 result.extend(self.build_link_packet(
1667 link_id,
1668 constants::CONTEXT_RESOURCE_HMU,
1669 &encrypted,
1670 ));
1671 }
1672 }
1673 ResourceAction::SendProof(data) => {
1674 if let Ok(encrypted) = link.engine.encrypt(&data, rng) {
1675 result.extend(self.build_link_packet(
1676 link_id,
1677 constants::CONTEXT_RESOURCE_PRF,
1678 &encrypted,
1679 ));
1680 }
1681 }
1682 ResourceAction::SendCancelInitiator(data) => {
1683 if let Ok(encrypted) = link.engine.encrypt(&data, rng) {
1684 result.extend(self.build_link_packet(
1685 link_id,
1686 constants::CONTEXT_RESOURCE_ICL,
1687 &encrypted,
1688 ));
1689 }
1690 }
1691 ResourceAction::SendCancelReceiver(data) => {
1692 if let Ok(encrypted) = link.engine.encrypt(&data, rng) {
1693 result.extend(self.build_link_packet(
1694 link_id,
1695 constants::CONTEXT_RESOURCE_RCL,
1696 &encrypted,
1697 ));
1698 }
1699 }
1700 ResourceAction::DataReceived { data, metadata } => {
1701 result.push(LinkManagerAction::ResourceReceived {
1702 link_id: *link_id,
1703 data,
1704 metadata,
1705 });
1706 }
1707 ResourceAction::Completed => {
1708 result.push(LinkManagerAction::ResourceCompleted { link_id: *link_id });
1709 }
1710 ResourceAction::Failed(e) => {
1711 result.push(LinkManagerAction::ResourceFailed {
1712 link_id: *link_id,
1713 error: format!("{}", e),
1714 });
1715 }
1716 ResourceAction::ProgressUpdate { received, total } => {
1717 result.push(LinkManagerAction::ResourceProgress {
1718 link_id: *link_id,
1719 received,
1720 total,
1721 });
1722 }
1723 }
1724 }
1725 result
1726 }
1727
1728 fn build_link_packet(
1730 &self,
1731 link_id: &LinkId,
1732 context: u8,
1733 data: &[u8],
1734 ) -> Vec<LinkManagerAction> {
1735 let flags = PacketFlags {
1736 header_type: constants::HEADER_1,
1737 context_flag: constants::FLAG_UNSET,
1738 transport_type: constants::TRANSPORT_BROADCAST,
1739 destination_type: constants::DESTINATION_LINK,
1740 packet_type: constants::PACKET_TYPE_DATA,
1741 };
1742 let mut actions = Vec::new();
1743 if let Ok(pkt) = RawPacket::pack(flags, 0, link_id, None, context, data) {
1744 actions.push(LinkManagerAction::SendPacket {
1745 raw: pkt.raw,
1746 dest_type: constants::DESTINATION_LINK,
1747 attached_interface: None,
1748 });
1749 }
1750 actions
1751 }
1752
1753 pub fn send_resource(
1755 &mut self,
1756 link_id: &LinkId,
1757 data: &[u8],
1758 metadata: Option<&[u8]>,
1759 rng: &mut dyn Rng,
1760 ) -> Vec<LinkManagerAction> {
1761 let link = match self.links.get_mut(link_id) {
1762 Some(l) => l,
1763 None => return Vec::new(),
1764 };
1765
1766 if link.engine.state() != LinkState::Active {
1767 return Vec::new();
1768 }
1769
1770 let link_rtt = link.engine.rtt().unwrap_or(1.0);
1771 let now = time::now();
1772
1773 let enc_rng = std::cell::RefCell::new(rns_crypto::OsRng);
1776 let encrypt_fn = |plaintext: &[u8]| -> Vec<u8> {
1777 link.engine
1778 .encrypt(plaintext, &mut *enc_rng.borrow_mut())
1779 .unwrap_or_else(|_| plaintext.to_vec())
1780 };
1781
1782 let sender = match ResourceSender::new(
1783 data,
1784 metadata,
1785 constants::RESOURCE_SDU,
1786 &encrypt_fn,
1787 &Bzip2Compressor,
1788 rng,
1789 now,
1790 true, false, None, 1, 1, None, link_rtt,
1797 6.0, ) {
1799 Ok(s) => s,
1800 Err(e) => {
1801 log::debug!("Failed to create ResourceSender: {}", e);
1802 return Vec::new();
1803 }
1804 };
1805
1806 let mut sender = sender;
1807 let adv_actions = sender.advertise(now);
1808 link.outgoing_resources.push(sender);
1809
1810 let _ = link;
1811 self.process_resource_actions(link_id, adv_actions, rng)
1812 }
1813
1814 pub fn set_resource_strategy(&mut self, link_id: &LinkId, strategy: ResourceStrategy) {
1816 if let Some(link) = self.links.get_mut(link_id) {
1817 link.resource_strategy = strategy;
1818 }
1819 }
1820
1821 pub fn flush_channel_tx(&mut self, link_id: &LinkId) {
1824 if let Some(link) = self.links.get_mut(link_id) {
1825 if let Some(ref mut channel) = link.channel {
1826 channel.flush_tx();
1827 }
1828 }
1829 }
1830
1831 pub fn send_channel_message(
1833 &mut self,
1834 link_id: &LinkId,
1835 msgtype: u16,
1836 payload: &[u8],
1837 rng: &mut dyn Rng,
1838 ) -> Vec<LinkManagerAction> {
1839 let link = match self.links.get_mut(link_id) {
1840 Some(l) => l,
1841 None => return Vec::new(),
1842 };
1843
1844 let channel = match link.channel {
1845 Some(ref mut ch) => ch,
1846 None => return Vec::new(),
1847 };
1848
1849 let link_mdu = constants::MDU; let now = time::now();
1851 let chan_actions = match channel.send(msgtype, payload, now, link_mdu) {
1852 Ok(a) => a,
1853 Err(e) => {
1854 log::debug!("Channel send failed: {:?}", e);
1855 return Vec::new();
1856 }
1857 };
1858
1859 let _ = link;
1860 self.process_channel_actions(link_id, chan_actions, rng)
1861 }
1862
1863 pub fn tick(&mut self, rng: &mut dyn Rng) -> Vec<LinkManagerAction> {
1865 let now = time::now();
1866 let mut all_actions = Vec::new();
1867
1868 let link_ids: Vec<LinkId> = self.links.keys().copied().collect();
1870
1871 for link_id in &link_ids {
1872 let link = match self.links.get_mut(link_id) {
1873 Some(l) => l,
1874 None => continue,
1875 };
1876
1877 let tick_actions = link.engine.tick(now);
1879 all_actions.extend(self.process_link_actions(link_id, &tick_actions));
1880
1881 let link = match self.links.get_mut(link_id) {
1883 Some(l) => l,
1884 None => continue,
1885 };
1886 if link.engine.needs_keepalive(now) {
1887 let flags = PacketFlags {
1889 header_type: constants::HEADER_1,
1890 context_flag: constants::FLAG_UNSET,
1891 transport_type: constants::TRANSPORT_BROADCAST,
1892 destination_type: constants::DESTINATION_LINK,
1893 packet_type: constants::PACKET_TYPE_DATA,
1894 };
1895 if let Ok(pkt) =
1896 RawPacket::pack(flags, 0, link_id, None, constants::CONTEXT_KEEPALIVE, &[])
1897 {
1898 all_actions.push(LinkManagerAction::SendPacket {
1899 raw: pkt.raw,
1900 dest_type: constants::DESTINATION_LINK,
1901 attached_interface: None,
1902 });
1903 link.engine.record_outbound(now, true);
1904 }
1905 }
1906 }
1907
1908 for link_id in &link_ids {
1910 let link = match self.links.get_mut(link_id) {
1911 Some(l) => l,
1912 None => continue,
1913 };
1914
1915 let mut sender_actions = Vec::new();
1917 for sender in &mut link.outgoing_resources {
1918 sender_actions.extend(sender.tick(now));
1919 }
1920
1921 let mut receiver_actions = Vec::new();
1923 for receiver in &mut link.incoming_resources {
1924 let decrypt_fn = |ciphertext: &[u8]| -> Result<Vec<u8>, ()> {
1925 link.engine.decrypt(ciphertext).map_err(|_| ())
1926 };
1927 receiver_actions.extend(receiver.tick(now, &decrypt_fn, &Bzip2Compressor));
1928 }
1929
1930 link.outgoing_resources
1932 .retain(|s| s.status < rns_core::resource::ResourceStatus::Complete);
1933 link.incoming_resources
1934 .retain(|r| r.status < rns_core::resource::ResourceStatus::Assembling);
1935
1936 let _ = link;
1937 all_actions.extend(self.process_resource_actions(link_id, sender_actions, rng));
1938 all_actions.extend(self.process_resource_actions(link_id, receiver_actions, rng));
1939 }
1940
1941 let closed: Vec<LinkId> = self
1943 .links
1944 .iter()
1945 .filter(|(_, l)| l.engine.state() == LinkState::Closed)
1946 .map(|(id, _)| *id)
1947 .collect();
1948 for id in closed {
1949 self.links.remove(&id);
1950 all_actions.push(LinkManagerAction::DeregisterLinkDest { link_id: id });
1951 }
1952
1953 all_actions
1954 }
1955
1956 pub fn is_link_destination(&self, dest_hash: &[u8; 16]) -> bool {
1958 self.links.contains_key(dest_hash) || self.link_destinations.contains_key(dest_hash)
1959 }
1960
1961 pub fn link_state(&self, link_id: &LinkId) -> Option<LinkState> {
1963 self.links.get(link_id).map(|l| l.engine.state())
1964 }
1965
1966 pub fn link_rtt(&self, link_id: &LinkId) -> Option<f64> {
1968 self.links.get(link_id).and_then(|l| l.engine.rtt())
1969 }
1970
1971 pub fn set_link_rtt(&mut self, link_id: &LinkId, rtt: f64) {
1973 if let Some(link) = self.links.get_mut(link_id) {
1974 link.engine.set_rtt(rtt);
1975 }
1976 }
1977
1978 pub fn record_link_inbound(&mut self, link_id: &LinkId) {
1980 if let Some(link) = self.links.get_mut(link_id) {
1981 link.engine.record_inbound(time::now());
1982 }
1983 }
1984
1985 pub fn set_link_mtu(&mut self, link_id: &LinkId, mtu: u32) {
1987 if let Some(link) = self.links.get_mut(link_id) {
1988 link.engine.set_mtu(mtu);
1989 }
1990 }
1991
1992 pub fn link_count(&self) -> usize {
1994 self.links.len()
1995 }
1996
1997 pub fn link_entries(&self) -> Vec<crate::event::LinkInfoEntry> {
1999 self.links
2000 .iter()
2001 .map(|(link_id, managed)| {
2002 let state = match managed.engine.state() {
2003 LinkState::Pending => "pending",
2004 LinkState::Handshake => "handshake",
2005 LinkState::Active => "active",
2006 LinkState::Stale => "stale",
2007 LinkState::Closed => "closed",
2008 };
2009 crate::event::LinkInfoEntry {
2010 link_id: *link_id,
2011 state: state.to_string(),
2012 is_initiator: managed.engine.is_initiator(),
2013 dest_hash: managed.dest_hash,
2014 remote_identity: managed.remote_identity.as_ref().map(|(h, _)| *h),
2015 rtt: managed.engine.rtt(),
2016 }
2017 })
2018 .collect()
2019 }
2020
2021 pub fn resource_entries(&self) -> Vec<crate::event::ResourceInfoEntry> {
2023 let mut entries = Vec::new();
2024 for (link_id, managed) in &self.links {
2025 for recv in &managed.incoming_resources {
2026 let (received, total) = recv.progress();
2027 entries.push(crate::event::ResourceInfoEntry {
2028 link_id: *link_id,
2029 direction: "incoming".to_string(),
2030 total_parts: total,
2031 transferred_parts: received,
2032 complete: received >= total && total > 0,
2033 });
2034 }
2035 for send in &managed.outgoing_resources {
2036 let total = send.total_parts();
2037 let sent = send.sent_parts;
2038 entries.push(crate::event::ResourceInfoEntry {
2039 link_id: *link_id,
2040 direction: "outgoing".to_string(),
2041 total_parts: total,
2042 transferred_parts: sent,
2043 complete: sent >= total && total > 0,
2044 });
2045 }
2046 }
2047 entries
2048 }
2049
2050 fn process_link_actions(
2052 &self,
2053 link_id: &LinkId,
2054 actions: &[LinkAction],
2055 ) -> Vec<LinkManagerAction> {
2056 let mut result = Vec::new();
2057 for action in actions {
2058 match action {
2059 LinkAction::StateChanged {
2060 new_state, reason, ..
2061 } => match new_state {
2062 LinkState::Closed => {
2063 result.push(LinkManagerAction::LinkClosed {
2064 link_id: *link_id,
2065 reason: *reason,
2066 });
2067 }
2068 _ => {}
2069 },
2070 LinkAction::LinkEstablished {
2071 rtt, is_initiator, ..
2072 } => {
2073 let dest_hash = self
2074 .links
2075 .get(link_id)
2076 .map(|l| l.dest_hash)
2077 .unwrap_or([0u8; 16]);
2078 result.push(LinkManagerAction::LinkEstablished {
2079 link_id: *link_id,
2080 dest_hash,
2081 rtt: *rtt,
2082 is_initiator: *is_initiator,
2083 });
2084 }
2085 LinkAction::RemoteIdentified {
2086 identity_hash,
2087 public_key,
2088 ..
2089 } => {
2090 result.push(LinkManagerAction::RemoteIdentified {
2091 link_id: *link_id,
2092 identity_hash: *identity_hash,
2093 public_key: *public_key,
2094 });
2095 }
2096 LinkAction::DataReceived { .. } => {
2097 }
2099 }
2100 }
2101 result
2102 }
2103
2104 fn process_channel_actions(
2106 &self,
2107 link_id: &LinkId,
2108 actions: Vec<rns_core::channel::ChannelAction>,
2109 rng: &mut dyn Rng,
2110 ) -> Vec<LinkManagerAction> {
2111 let mut result = Vec::new();
2112 for action in actions {
2113 match action {
2114 rns_core::channel::ChannelAction::SendOnLink { raw } => {
2115 if let Some(link) = self.links.get(link_id) {
2117 if let Ok(encrypted) = link.engine.encrypt(&raw, rng) {
2118 let flags = PacketFlags {
2119 header_type: constants::HEADER_1,
2120 context_flag: constants::FLAG_UNSET,
2121 transport_type: constants::TRANSPORT_BROADCAST,
2122 destination_type: constants::DESTINATION_LINK,
2123 packet_type: constants::PACKET_TYPE_DATA,
2124 };
2125 if let Ok(pkt) = RawPacket::pack(
2126 flags,
2127 0,
2128 link_id,
2129 None,
2130 constants::CONTEXT_CHANNEL,
2131 &encrypted,
2132 ) {
2133 result.push(LinkManagerAction::SendPacket {
2134 raw: pkt.raw,
2135 dest_type: constants::DESTINATION_LINK,
2136 attached_interface: None,
2137 });
2138 }
2139 }
2140 }
2141 }
2142 rns_core::channel::ChannelAction::MessageReceived {
2143 msgtype, payload, ..
2144 } => {
2145 result.push(LinkManagerAction::ChannelMessageReceived {
2146 link_id: *link_id,
2147 msgtype,
2148 payload,
2149 });
2150 }
2151 rns_core::channel::ChannelAction::TeardownLink => {
2152 result.push(LinkManagerAction::LinkClosed {
2153 link_id: *link_id,
2154 reason: Some(TeardownReason::Timeout),
2155 });
2156 }
2157 }
2158 }
2159 result
2160 }
2161}
2162
2163fn compute_path_hash(path: &str) -> [u8; 16] {
2166 let full = rns_core::hash::full_hash(path.as_bytes());
2167 let mut result = [0u8; 16];
2168 result.copy_from_slice(&full[..16]);
2169 result
2170}
2171
2172#[cfg(test)]
2173mod tests {
2174 use super::*;
2175 use rns_crypto::identity::Identity;
2176 use rns_crypto::{FixedRng, OsRng};
2177
2178 fn make_rng(seed: u8) -> FixedRng {
2179 FixedRng::new(&[seed; 128])
2180 }
2181
2182 fn make_dest_keys(rng: &mut dyn Rng) -> (Ed25519PrivateKey, [u8; 32]) {
2183 let sig_prv = Ed25519PrivateKey::generate(rng);
2184 let sig_pub_bytes = sig_prv.public_key().public_bytes();
2185 (sig_prv, sig_pub_bytes)
2186 }
2187
2188 #[test]
2189 fn test_register_link_destination() {
2190 let mut mgr = LinkManager::new();
2191 let mut rng = make_rng(0x01);
2192 let (sig_prv, sig_pub_bytes) = make_dest_keys(&mut rng);
2193 let dest_hash = [0xDD; 16];
2194
2195 mgr.register_link_destination(
2196 dest_hash,
2197 sig_prv,
2198 sig_pub_bytes,
2199 ResourceStrategy::AcceptNone,
2200 );
2201 assert!(mgr.is_link_destination(&dest_hash));
2202
2203 mgr.deregister_link_destination(&dest_hash);
2204 assert!(!mgr.is_link_destination(&dest_hash));
2205 }
2206
2207 #[test]
2208 fn test_create_link() {
2209 let mut mgr = LinkManager::new();
2210 let mut rng = OsRng;
2211 let dest_hash = [0xDD; 16];
2212
2213 let sig_pub_bytes = [0xAA; 32]; let (link_id, actions) = mgr.create_link(
2215 &dest_hash,
2216 &sig_pub_bytes,
2217 1,
2218 constants::MTU as u32,
2219 &mut rng,
2220 );
2221 assert_ne!(link_id, [0u8; 16]);
2222 assert_eq!(actions.len(), 2);
2224 assert!(matches!(
2225 actions[0],
2226 LinkManagerAction::RegisterLinkDest { .. }
2227 ));
2228 assert!(matches!(actions[1], LinkManagerAction::SendPacket { .. }));
2229
2230 assert_eq!(mgr.link_state(&link_id), Some(LinkState::Pending));
2232 }
2233
2234 #[test]
2235 fn test_full_handshake_via_manager() {
2236 let mut rng = OsRng;
2237 let dest_hash = [0xDD; 16];
2238
2239 let mut responder_mgr = LinkManager::new();
2241 let (sig_prv, sig_pub_bytes) = make_dest_keys(&mut rng);
2242 responder_mgr.register_link_destination(
2243 dest_hash,
2244 sig_prv,
2245 sig_pub_bytes,
2246 ResourceStrategy::AcceptNone,
2247 );
2248
2249 let mut initiator_mgr = LinkManager::new();
2251
2252 let (link_id, init_actions) = initiator_mgr.create_link(
2254 &dest_hash,
2255 &sig_pub_bytes,
2256 1,
2257 constants::MTU as u32,
2258 &mut rng,
2259 );
2260 assert_eq!(init_actions.len(), 2);
2261
2262 let linkrequest_raw = match &init_actions[1] {
2264 LinkManagerAction::SendPacket { raw, .. } => raw.clone(),
2265 _ => panic!("Expected SendPacket"),
2266 };
2267
2268 let lr_packet = RawPacket::unpack(&linkrequest_raw).unwrap();
2270
2271 let resp_actions = responder_mgr.handle_local_delivery(
2273 lr_packet.destination_hash,
2274 &linkrequest_raw,
2275 lr_packet.packet_hash,
2276 rns_core::transport::types::InterfaceId(0),
2277 &mut rng,
2278 );
2279 assert!(resp_actions.len() >= 2);
2281 assert!(matches!(
2282 resp_actions[0],
2283 LinkManagerAction::RegisterLinkDest { .. }
2284 ));
2285
2286 let lrproof_raw = match &resp_actions[1] {
2288 LinkManagerAction::SendPacket { raw, .. } => raw.clone(),
2289 _ => panic!("Expected SendPacket for LRPROOF"),
2290 };
2291
2292 let lrproof_packet = RawPacket::unpack(&lrproof_raw).unwrap();
2294 let init_actions2 = initiator_mgr.handle_local_delivery(
2295 lrproof_packet.destination_hash,
2296 &lrproof_raw,
2297 lrproof_packet.packet_hash,
2298 rns_core::transport::types::InterfaceId(0),
2299 &mut rng,
2300 );
2301
2302 let has_established = init_actions2
2304 .iter()
2305 .any(|a| matches!(a, LinkManagerAction::LinkEstablished { .. }));
2306 assert!(has_established, "Initiator should emit LinkEstablished");
2307
2308 let lrrtt_raw = init_actions2
2310 .iter()
2311 .find_map(|a| match a {
2312 LinkManagerAction::SendPacket { raw, .. } => Some(raw.clone()),
2313 _ => None,
2314 })
2315 .expect("Should have LRRTT SendPacket");
2316
2317 let lrrtt_packet = RawPacket::unpack(&lrrtt_raw).unwrap();
2319 let resp_link_id = lrrtt_packet.destination_hash;
2320 let resp_actions2 = responder_mgr.handle_local_delivery(
2321 resp_link_id,
2322 &lrrtt_raw,
2323 lrrtt_packet.packet_hash,
2324 rns_core::transport::types::InterfaceId(0),
2325 &mut rng,
2326 );
2327
2328 let has_established = resp_actions2
2329 .iter()
2330 .any(|a| matches!(a, LinkManagerAction::LinkEstablished { .. }));
2331 assert!(has_established, "Responder should emit LinkEstablished");
2332
2333 assert_eq!(initiator_mgr.link_state(&link_id), Some(LinkState::Active));
2335 assert_eq!(responder_mgr.link_state(&link_id), Some(LinkState::Active));
2336
2337 assert!(initiator_mgr.link_rtt(&link_id).is_some());
2339 assert!(responder_mgr.link_rtt(&link_id).is_some());
2340 }
2341
2342 #[test]
2343 fn test_encrypted_data_exchange() {
2344 let mut rng = OsRng;
2345 let dest_hash = [0xDD; 16];
2346 let mut resp_mgr = LinkManager::new();
2347 let (sig_prv, sig_pub_bytes) = make_dest_keys(&mut rng);
2348 resp_mgr.register_link_destination(
2349 dest_hash,
2350 sig_prv,
2351 sig_pub_bytes,
2352 ResourceStrategy::AcceptNone,
2353 );
2354 let mut init_mgr = LinkManager::new();
2355
2356 let (link_id, init_actions) = init_mgr.create_link(
2358 &dest_hash,
2359 &sig_pub_bytes,
2360 1,
2361 constants::MTU as u32,
2362 &mut rng,
2363 );
2364 let lr_raw = extract_send_packet(&init_actions);
2365 let lr_pkt = RawPacket::unpack(&lr_raw).unwrap();
2366 let resp_actions = resp_mgr.handle_local_delivery(
2367 lr_pkt.destination_hash,
2368 &lr_raw,
2369 lr_pkt.packet_hash,
2370 rns_core::transport::types::InterfaceId(0),
2371 &mut rng,
2372 );
2373 let lrproof_raw = extract_send_packet_at(&resp_actions, 1);
2374 let lrproof_pkt = RawPacket::unpack(&lrproof_raw).unwrap();
2375 let init_actions2 = init_mgr.handle_local_delivery(
2376 lrproof_pkt.destination_hash,
2377 &lrproof_raw,
2378 lrproof_pkt.packet_hash,
2379 rns_core::transport::types::InterfaceId(0),
2380 &mut rng,
2381 );
2382 let lrrtt_raw = extract_any_send_packet(&init_actions2);
2383 let lrrtt_pkt = RawPacket::unpack(&lrrtt_raw).unwrap();
2384 resp_mgr.handle_local_delivery(
2385 lrrtt_pkt.destination_hash,
2386 &lrrtt_raw,
2387 lrrtt_pkt.packet_hash,
2388 rns_core::transport::types::InterfaceId(0),
2389 &mut rng,
2390 );
2391
2392 let actions =
2394 init_mgr.send_on_link(&link_id, b"hello link!", constants::CONTEXT_NONE, &mut rng);
2395 assert_eq!(actions.len(), 1);
2396 assert!(matches!(actions[0], LinkManagerAction::SendPacket { .. }));
2397 }
2398
2399 #[test]
2400 fn test_request_response() {
2401 let mut rng = OsRng;
2402 let dest_hash = [0xDD; 16];
2403 let mut resp_mgr = LinkManager::new();
2404 let (sig_prv, sig_pub_bytes) = make_dest_keys(&mut rng);
2405 resp_mgr.register_link_destination(
2406 dest_hash,
2407 sig_prv,
2408 sig_pub_bytes,
2409 ResourceStrategy::AcceptNone,
2410 );
2411
2412 resp_mgr.register_request_handler("/status", None, |_link_id, _path, _data, _remote| {
2414 Some(b"OK".to_vec())
2415 });
2416
2417 let mut init_mgr = LinkManager::new();
2418
2419 let (link_id, init_actions) = init_mgr.create_link(
2421 &dest_hash,
2422 &sig_pub_bytes,
2423 1,
2424 constants::MTU as u32,
2425 &mut rng,
2426 );
2427 let lr_raw = extract_send_packet(&init_actions);
2428 let lr_pkt = RawPacket::unpack(&lr_raw).unwrap();
2429 let resp_actions = resp_mgr.handle_local_delivery(
2430 lr_pkt.destination_hash,
2431 &lr_raw,
2432 lr_pkt.packet_hash,
2433 rns_core::transport::types::InterfaceId(0),
2434 &mut rng,
2435 );
2436 let lrproof_raw = extract_send_packet_at(&resp_actions, 1);
2437 let lrproof_pkt = RawPacket::unpack(&lrproof_raw).unwrap();
2438 let init_actions2 = init_mgr.handle_local_delivery(
2439 lrproof_pkt.destination_hash,
2440 &lrproof_raw,
2441 lrproof_pkt.packet_hash,
2442 rns_core::transport::types::InterfaceId(0),
2443 &mut rng,
2444 );
2445 let lrrtt_raw = extract_any_send_packet(&init_actions2);
2446 let lrrtt_pkt = RawPacket::unpack(&lrrtt_raw).unwrap();
2447 resp_mgr.handle_local_delivery(
2448 lrrtt_pkt.destination_hash,
2449 &lrrtt_raw,
2450 lrrtt_pkt.packet_hash,
2451 rns_core::transport::types::InterfaceId(0),
2452 &mut rng,
2453 );
2454
2455 let req_actions = init_mgr.send_request(&link_id, "/status", b"query", &mut rng);
2457 assert_eq!(req_actions.len(), 1);
2458
2459 let req_raw = extract_send_packet_from(&req_actions);
2461 let req_pkt = RawPacket::unpack(&req_raw).unwrap();
2462 let resp_actions = resp_mgr.handle_local_delivery(
2463 req_pkt.destination_hash,
2464 &req_raw,
2465 req_pkt.packet_hash,
2466 rns_core::transport::types::InterfaceId(0),
2467 &mut rng,
2468 );
2469
2470 let has_response = resp_actions
2472 .iter()
2473 .any(|a| matches!(a, LinkManagerAction::SendPacket { .. }));
2474 assert!(has_response, "Handler should produce a response packet");
2475 }
2476
2477 #[test]
2478 fn test_request_acl_deny_unidentified() {
2479 let mut rng = OsRng;
2480 let dest_hash = [0xDD; 16];
2481 let mut resp_mgr = LinkManager::new();
2482 let (sig_prv, sig_pub_bytes) = make_dest_keys(&mut rng);
2483 resp_mgr.register_link_destination(
2484 dest_hash,
2485 sig_prv,
2486 sig_pub_bytes,
2487 ResourceStrategy::AcceptNone,
2488 );
2489
2490 resp_mgr.register_request_handler(
2492 "/restricted",
2493 Some(vec![[0xAA; 16]]),
2494 |_link_id, _path, _data, _remote| Some(b"secret".to_vec()),
2495 );
2496
2497 let mut init_mgr = LinkManager::new();
2498
2499 let (link_id, init_actions) = init_mgr.create_link(
2501 &dest_hash,
2502 &sig_pub_bytes,
2503 1,
2504 constants::MTU as u32,
2505 &mut rng,
2506 );
2507 let lr_raw = extract_send_packet(&init_actions);
2508 let lr_pkt = RawPacket::unpack(&lr_raw).unwrap();
2509 let resp_actions = resp_mgr.handle_local_delivery(
2510 lr_pkt.destination_hash,
2511 &lr_raw,
2512 lr_pkt.packet_hash,
2513 rns_core::transport::types::InterfaceId(0),
2514 &mut rng,
2515 );
2516 let lrproof_raw = extract_send_packet_at(&resp_actions, 1);
2517 let lrproof_pkt = RawPacket::unpack(&lrproof_raw).unwrap();
2518 let init_actions2 = init_mgr.handle_local_delivery(
2519 lrproof_pkt.destination_hash,
2520 &lrproof_raw,
2521 lrproof_pkt.packet_hash,
2522 rns_core::transport::types::InterfaceId(0),
2523 &mut rng,
2524 );
2525 let lrrtt_raw = extract_any_send_packet(&init_actions2);
2526 let lrrtt_pkt = RawPacket::unpack(&lrrtt_raw).unwrap();
2527 resp_mgr.handle_local_delivery(
2528 lrrtt_pkt.destination_hash,
2529 &lrrtt_raw,
2530 lrrtt_pkt.packet_hash,
2531 rns_core::transport::types::InterfaceId(0),
2532 &mut rng,
2533 );
2534
2535 let req_actions = init_mgr.send_request(&link_id, "/restricted", b"query", &mut rng);
2537 let req_raw = extract_send_packet_from(&req_actions);
2538 let req_pkt = RawPacket::unpack(&req_raw).unwrap();
2539 let resp_actions = resp_mgr.handle_local_delivery(
2540 req_pkt.destination_hash,
2541 &req_raw,
2542 req_pkt.packet_hash,
2543 rns_core::transport::types::InterfaceId(0),
2544 &mut rng,
2545 );
2546
2547 let has_response = resp_actions
2549 .iter()
2550 .any(|a| matches!(a, LinkManagerAction::SendPacket { .. }));
2551 assert!(!has_response, "Unidentified peer should be denied");
2552 }
2553
2554 #[test]
2555 fn test_teardown_link() {
2556 let mut rng = OsRng;
2557 let dest_hash = [0xDD; 16];
2558 let mut mgr = LinkManager::new();
2559
2560 let dummy_sig = [0xAA; 32];
2561 let (link_id, _) =
2562 mgr.create_link(&dest_hash, &dummy_sig, 1, constants::MTU as u32, &mut rng);
2563 assert_eq!(mgr.link_count(), 1);
2564
2565 let actions = mgr.teardown_link(&link_id);
2566 let has_close = actions
2567 .iter()
2568 .any(|a| matches!(a, LinkManagerAction::LinkClosed { .. }));
2569 assert!(has_close);
2570
2571 let tick_actions = mgr.tick(&mut rng);
2573 let has_deregister = tick_actions
2574 .iter()
2575 .any(|a| matches!(a, LinkManagerAction::DeregisterLinkDest { .. }));
2576 assert!(has_deregister);
2577 assert_eq!(mgr.link_count(), 0);
2578 }
2579
2580 #[test]
2581 fn test_identify_on_link() {
2582 let mut rng = OsRng;
2583 let dest_hash = [0xDD; 16];
2584 let mut resp_mgr = LinkManager::new();
2585 let (sig_prv, sig_pub_bytes) = make_dest_keys(&mut rng);
2586 resp_mgr.register_link_destination(
2587 dest_hash,
2588 sig_prv,
2589 sig_pub_bytes,
2590 ResourceStrategy::AcceptNone,
2591 );
2592 let mut init_mgr = LinkManager::new();
2593
2594 let (link_id, init_actions) = init_mgr.create_link(
2596 &dest_hash,
2597 &sig_pub_bytes,
2598 1,
2599 constants::MTU as u32,
2600 &mut rng,
2601 );
2602 let lr_raw = extract_send_packet(&init_actions);
2603 let lr_pkt = RawPacket::unpack(&lr_raw).unwrap();
2604 let resp_actions = resp_mgr.handle_local_delivery(
2605 lr_pkt.destination_hash,
2606 &lr_raw,
2607 lr_pkt.packet_hash,
2608 rns_core::transport::types::InterfaceId(0),
2609 &mut rng,
2610 );
2611 let lrproof_raw = extract_send_packet_at(&resp_actions, 1);
2612 let lrproof_pkt = RawPacket::unpack(&lrproof_raw).unwrap();
2613 let init_actions2 = init_mgr.handle_local_delivery(
2614 lrproof_pkt.destination_hash,
2615 &lrproof_raw,
2616 lrproof_pkt.packet_hash,
2617 rns_core::transport::types::InterfaceId(0),
2618 &mut rng,
2619 );
2620 let lrrtt_raw = extract_any_send_packet(&init_actions2);
2621 let lrrtt_pkt = RawPacket::unpack(&lrrtt_raw).unwrap();
2622 resp_mgr.handle_local_delivery(
2623 lrrtt_pkt.destination_hash,
2624 &lrrtt_raw,
2625 lrrtt_pkt.packet_hash,
2626 rns_core::transport::types::InterfaceId(0),
2627 &mut rng,
2628 );
2629
2630 let identity = Identity::new(&mut rng);
2632 let id_actions = init_mgr.identify(&link_id, &identity, &mut rng);
2633 assert_eq!(id_actions.len(), 1);
2634
2635 let id_raw = extract_send_packet_from(&id_actions);
2637 let id_pkt = RawPacket::unpack(&id_raw).unwrap();
2638 let resp_actions = resp_mgr.handle_local_delivery(
2639 id_pkt.destination_hash,
2640 &id_raw,
2641 id_pkt.packet_hash,
2642 rns_core::transport::types::InterfaceId(0),
2643 &mut rng,
2644 );
2645
2646 let has_identified = resp_actions
2647 .iter()
2648 .any(|a| matches!(a, LinkManagerAction::RemoteIdentified { .. }));
2649 assert!(has_identified, "Responder should emit RemoteIdentified");
2650 }
2651
2652 #[test]
2653 fn test_path_hash_computation() {
2654 let h1 = compute_path_hash("/status");
2655 let h2 = compute_path_hash("/path");
2656 assert_ne!(h1, h2);
2657
2658 assert_eq!(h1, compute_path_hash("/status"));
2660 }
2661
2662 #[test]
2663 fn test_link_count() {
2664 let mut mgr = LinkManager::new();
2665 let mut rng = OsRng;
2666
2667 assert_eq!(mgr.link_count(), 0);
2668
2669 let dummy_sig = [0xAA; 32];
2670 mgr.create_link(&[0x11; 16], &dummy_sig, 1, constants::MTU as u32, &mut rng);
2671 assert_eq!(mgr.link_count(), 1);
2672
2673 mgr.create_link(&[0x22; 16], &dummy_sig, 1, constants::MTU as u32, &mut rng);
2674 assert_eq!(mgr.link_count(), 2);
2675 }
2676
2677 fn extract_send_packet(actions: &[LinkManagerAction]) -> Vec<u8> {
2680 extract_send_packet_at(actions, actions.len() - 1)
2681 }
2682
2683 fn extract_send_packet_at(actions: &[LinkManagerAction], idx: usize) -> Vec<u8> {
2684 match &actions[idx] {
2685 LinkManagerAction::SendPacket { raw, .. } => raw.clone(),
2686 other => panic!("Expected SendPacket at index {}, got {:?}", idx, other),
2687 }
2688 }
2689
2690 fn extract_any_send_packet(actions: &[LinkManagerAction]) -> Vec<u8> {
2691 actions
2692 .iter()
2693 .find_map(|a| match a {
2694 LinkManagerAction::SendPacket { raw, .. } => Some(raw.clone()),
2695 _ => None,
2696 })
2697 .expect("Expected at least one SendPacket action")
2698 }
2699
2700 fn extract_send_packet_from(actions: &[LinkManagerAction]) -> Vec<u8> {
2701 extract_any_send_packet(actions)
2702 }
2703
2704 fn setup_active_link() -> (LinkManager, LinkManager, LinkId) {
2707 let mut rng = OsRng;
2708 let dest_hash = [0xDD; 16];
2709 let mut resp_mgr = LinkManager::new();
2710 let (sig_prv, sig_pub_bytes) = make_dest_keys(&mut rng);
2711 resp_mgr.register_link_destination(
2712 dest_hash,
2713 sig_prv,
2714 sig_pub_bytes,
2715 ResourceStrategy::AcceptNone,
2716 );
2717 let mut init_mgr = LinkManager::new();
2718
2719 let (link_id, init_actions) = init_mgr.create_link(
2720 &dest_hash,
2721 &sig_pub_bytes,
2722 1,
2723 constants::MTU as u32,
2724 &mut rng,
2725 );
2726 let lr_raw = extract_send_packet(&init_actions);
2727 let lr_pkt = RawPacket::unpack(&lr_raw).unwrap();
2728 let resp_actions = resp_mgr.handle_local_delivery(
2729 lr_pkt.destination_hash,
2730 &lr_raw,
2731 lr_pkt.packet_hash,
2732 rns_core::transport::types::InterfaceId(0),
2733 &mut rng,
2734 );
2735 let lrproof_raw = extract_send_packet_at(&resp_actions, 1);
2736 let lrproof_pkt = RawPacket::unpack(&lrproof_raw).unwrap();
2737 let init_actions2 = init_mgr.handle_local_delivery(
2738 lrproof_pkt.destination_hash,
2739 &lrproof_raw,
2740 lrproof_pkt.packet_hash,
2741 rns_core::transport::types::InterfaceId(0),
2742 &mut rng,
2743 );
2744 let lrrtt_raw = extract_any_send_packet(&init_actions2);
2745 let lrrtt_pkt = RawPacket::unpack(&lrrtt_raw).unwrap();
2746 resp_mgr.handle_local_delivery(
2747 lrrtt_pkt.destination_hash,
2748 &lrrtt_raw,
2749 lrrtt_pkt.packet_hash,
2750 rns_core::transport::types::InterfaceId(0),
2751 &mut rng,
2752 );
2753
2754 assert_eq!(init_mgr.link_state(&link_id), Some(LinkState::Active));
2755 assert_eq!(resp_mgr.link_state(&link_id), Some(LinkState::Active));
2756
2757 (init_mgr, resp_mgr, link_id)
2758 }
2759
2760 #[test]
2765 fn test_resource_strategy_default() {
2766 let mut mgr = LinkManager::new();
2767 let mut rng = OsRng;
2768 let dummy_sig = [0xAA; 32];
2769 let (link_id, _) =
2770 mgr.create_link(&[0x11; 16], &dummy_sig, 1, constants::MTU as u32, &mut rng);
2771
2772 let link = mgr.links.get(&link_id).unwrap();
2774 assert_eq!(link.resource_strategy, ResourceStrategy::AcceptNone);
2775 }
2776
2777 #[test]
2778 fn test_set_resource_strategy() {
2779 let mut mgr = LinkManager::new();
2780 let mut rng = OsRng;
2781 let dummy_sig = [0xAA; 32];
2782 let (link_id, _) =
2783 mgr.create_link(&[0x11; 16], &dummy_sig, 1, constants::MTU as u32, &mut rng);
2784
2785 mgr.set_resource_strategy(&link_id, ResourceStrategy::AcceptAll);
2786 assert_eq!(
2787 mgr.links.get(&link_id).unwrap().resource_strategy,
2788 ResourceStrategy::AcceptAll
2789 );
2790
2791 mgr.set_resource_strategy(&link_id, ResourceStrategy::AcceptApp);
2792 assert_eq!(
2793 mgr.links.get(&link_id).unwrap().resource_strategy,
2794 ResourceStrategy::AcceptApp
2795 );
2796 }
2797
2798 #[test]
2799 fn test_send_resource_on_active_link() {
2800 let (mut init_mgr, _resp_mgr, link_id) = setup_active_link();
2801 let mut rng = OsRng;
2802
2803 let data = vec![0xAB; 100]; let actions = init_mgr.send_resource(&link_id, &data, None, &mut rng);
2806
2807 let has_send = actions
2809 .iter()
2810 .any(|a| matches!(a, LinkManagerAction::SendPacket { .. }));
2811 assert!(
2812 has_send,
2813 "send_resource should emit advertisement SendPacket"
2814 );
2815 }
2816
2817 #[test]
2818 fn test_send_resource_on_inactive_link() {
2819 let mut mgr = LinkManager::new();
2820 let mut rng = OsRng;
2821 let dummy_sig = [0xAA; 32];
2822 let (link_id, _) =
2823 mgr.create_link(&[0x11; 16], &dummy_sig, 1, constants::MTU as u32, &mut rng);
2824
2825 let actions = mgr.send_resource(&link_id, b"data", None, &mut rng);
2827 assert!(actions.is_empty(), "Cannot send resource on inactive link");
2828 }
2829
2830 #[test]
2831 fn test_resource_adv_rejected_by_accept_none() {
2832 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
2833 let mut rng = OsRng;
2834
2835 let data = vec![0xCD; 100];
2838 let adv_actions = init_mgr.send_resource(&link_id, &data, None, &mut rng);
2839
2840 for action in &adv_actions {
2842 if let LinkManagerAction::SendPacket { raw, .. } = action {
2843 let pkt = RawPacket::unpack(raw).unwrap();
2844 let resp_actions = resp_mgr.handle_local_delivery(
2845 pkt.destination_hash,
2846 raw,
2847 pkt.packet_hash,
2848 rns_core::transport::types::InterfaceId(0),
2849 &mut rng,
2850 );
2851 let has_resource_received = resp_actions
2853 .iter()
2854 .any(|a| matches!(a, LinkManagerAction::ResourceReceived { .. }));
2855 assert!(
2856 !has_resource_received,
2857 "AcceptNone should not accept resource"
2858 );
2859 }
2860 }
2861 }
2862
2863 #[test]
2864 fn test_resource_adv_accepted_by_accept_all() {
2865 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
2866 let mut rng = OsRng;
2867
2868 resp_mgr.set_resource_strategy(&link_id, ResourceStrategy::AcceptAll);
2870
2871 let data = vec![0xCD; 100];
2873 let adv_actions = init_mgr.send_resource(&link_id, &data, None, &mut rng);
2874
2875 for action in &adv_actions {
2877 if let LinkManagerAction::SendPacket { raw, .. } = action {
2878 let pkt = RawPacket::unpack(raw).unwrap();
2879 let resp_actions = resp_mgr.handle_local_delivery(
2880 pkt.destination_hash,
2881 raw,
2882 pkt.packet_hash,
2883 rns_core::transport::types::InterfaceId(0),
2884 &mut rng,
2885 );
2886 let has_send = resp_actions
2888 .iter()
2889 .any(|a| matches!(a, LinkManagerAction::SendPacket { .. }));
2890 assert!(has_send, "AcceptAll should accept and request parts");
2891 }
2892 }
2893 }
2894
2895 #[test]
2896 fn test_resource_accept_app_query() {
2897 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
2898 let mut rng = OsRng;
2899
2900 resp_mgr.set_resource_strategy(&link_id, ResourceStrategy::AcceptApp);
2902
2903 let data = vec![0xCD; 100];
2905 let adv_actions = init_mgr.send_resource(&link_id, &data, None, &mut rng);
2906
2907 let mut got_query = false;
2909 for action in &adv_actions {
2910 if let LinkManagerAction::SendPacket { raw, .. } = action {
2911 let pkt = RawPacket::unpack(raw).unwrap();
2912 let resp_actions = resp_mgr.handle_local_delivery(
2913 pkt.destination_hash,
2914 raw,
2915 pkt.packet_hash,
2916 rns_core::transport::types::InterfaceId(0),
2917 &mut rng,
2918 );
2919 for a in &resp_actions {
2920 if matches!(a, LinkManagerAction::ResourceAcceptQuery { .. }) {
2921 got_query = true;
2922 }
2923 }
2924 }
2925 }
2926 assert!(got_query, "AcceptApp should emit ResourceAcceptQuery");
2927 }
2928
2929 #[test]
2930 fn test_resource_accept_app_accept() {
2931 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
2932 let mut rng = OsRng;
2933
2934 resp_mgr.set_resource_strategy(&link_id, ResourceStrategy::AcceptApp);
2935
2936 let data = vec![0xCD; 100];
2937 let adv_actions = init_mgr.send_resource(&link_id, &data, None, &mut rng);
2938
2939 for action in &adv_actions {
2940 if let LinkManagerAction::SendPacket { raw, .. } = action {
2941 let pkt = RawPacket::unpack(raw).unwrap();
2942 let resp_actions = resp_mgr.handle_local_delivery(
2943 pkt.destination_hash,
2944 raw,
2945 pkt.packet_hash,
2946 rns_core::transport::types::InterfaceId(0),
2947 &mut rng,
2948 );
2949 for a in &resp_actions {
2950 if let LinkManagerAction::ResourceAcceptQuery {
2951 link_id: lid,
2952 resource_hash,
2953 ..
2954 } = a
2955 {
2956 let accept_actions =
2958 resp_mgr.accept_resource(lid, resource_hash, true, &mut rng);
2959 let has_send = accept_actions
2961 .iter()
2962 .any(|a| matches!(a, LinkManagerAction::SendPacket { .. }));
2963 assert!(
2964 has_send,
2965 "Accepting resource should produce request for parts"
2966 );
2967 }
2968 }
2969 }
2970 }
2971 }
2972
2973 #[test]
2974 fn test_resource_accept_app_reject() {
2975 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
2976 let mut rng = OsRng;
2977
2978 resp_mgr.set_resource_strategy(&link_id, ResourceStrategy::AcceptApp);
2979
2980 let data = vec![0xCD; 100];
2981 let adv_actions = init_mgr.send_resource(&link_id, &data, None, &mut rng);
2982
2983 for action in &adv_actions {
2984 if let LinkManagerAction::SendPacket { raw, .. } = action {
2985 let pkt = RawPacket::unpack(raw).unwrap();
2986 let resp_actions = resp_mgr.handle_local_delivery(
2987 pkt.destination_hash,
2988 raw,
2989 pkt.packet_hash,
2990 rns_core::transport::types::InterfaceId(0),
2991 &mut rng,
2992 );
2993 for a in &resp_actions {
2994 if let LinkManagerAction::ResourceAcceptQuery {
2995 link_id: lid,
2996 resource_hash,
2997 ..
2998 } = a
2999 {
3000 let reject_actions =
3002 resp_mgr.accept_resource(lid, resource_hash, false, &mut rng);
3003 let has_resource_received = reject_actions
3006 .iter()
3007 .any(|a| matches!(a, LinkManagerAction::ResourceReceived { .. }));
3008 assert!(!has_resource_received);
3009 }
3010 }
3011 }
3012 }
3013 }
3014
3015 #[test]
3016 fn test_resource_full_transfer() {
3017 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
3018 let mut rng = OsRng;
3019
3020 resp_mgr.set_resource_strategy(&link_id, ResourceStrategy::AcceptAll);
3022
3023 let original_data = b"Hello, Resource Transfer!".to_vec();
3025 let adv_actions = init_mgr.send_resource(&link_id, &original_data, None, &mut rng);
3026
3027 let mut pending: Vec<(char, LinkManagerAction)> =
3030 adv_actions.into_iter().map(|a| ('i', a)).collect();
3031 let mut rounds = 0;
3032 let max_rounds = 50;
3033 let mut resource_received = false;
3034 let mut sender_completed = false;
3035
3036 while !pending.is_empty() && rounds < max_rounds {
3037 rounds += 1;
3038 let mut next: Vec<(char, LinkManagerAction)> = Vec::new();
3039
3040 for (source, action) in pending.drain(..) {
3041 if let LinkManagerAction::SendPacket { raw, .. } = action {
3042 let pkt = RawPacket::unpack(&raw).unwrap();
3043
3044 let target_actions = if source == 'i' {
3046 resp_mgr.handle_local_delivery(
3047 pkt.destination_hash,
3048 &raw,
3049 pkt.packet_hash,
3050 rns_core::transport::types::InterfaceId(0),
3051 &mut rng,
3052 )
3053 } else {
3054 init_mgr.handle_local_delivery(
3055 pkt.destination_hash,
3056 &raw,
3057 pkt.packet_hash,
3058 rns_core::transport::types::InterfaceId(0),
3059 &mut rng,
3060 )
3061 };
3062
3063 let target_source = if source == 'i' { 'r' } else { 'i' };
3064 for a in &target_actions {
3065 match a {
3066 LinkManagerAction::ResourceReceived { data, .. } => {
3067 assert_eq!(*data, original_data);
3068 resource_received = true;
3069 }
3070 LinkManagerAction::ResourceCompleted { .. } => {
3071 sender_completed = true;
3072 }
3073 _ => {}
3074 }
3075 }
3076 next.extend(target_actions.into_iter().map(|a| (target_source, a)));
3077 }
3078 }
3079 pending = next;
3080 }
3081
3082 assert!(
3083 resource_received,
3084 "Responder should receive resource data (rounds={})",
3085 rounds
3086 );
3087 assert!(
3088 sender_completed,
3089 "Sender should get completion proof (rounds={})",
3090 rounds
3091 );
3092 }
3093
3094 #[test]
3095 fn test_resource_cancel_icl() {
3096 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
3097 let mut rng = OsRng;
3098
3099 resp_mgr.set_resource_strategy(&link_id, ResourceStrategy::AcceptAll);
3100
3101 let data = vec![0xAB; 2000];
3103 let adv_actions = init_mgr.send_resource(&link_id, &data, None, &mut rng);
3104
3105 for action in &adv_actions {
3107 if let LinkManagerAction::SendPacket { raw, .. } = action {
3108 let pkt = RawPacket::unpack(raw).unwrap();
3109 resp_mgr.handle_local_delivery(
3110 pkt.destination_hash,
3111 raw,
3112 pkt.packet_hash,
3113 rns_core::transport::types::InterfaceId(0),
3114 &mut rng,
3115 );
3116 }
3117 }
3118
3119 assert!(!resp_mgr
3121 .links
3122 .get(&link_id)
3123 .unwrap()
3124 .incoming_resources
3125 .is_empty());
3126
3127 let icl_actions = resp_mgr.handle_resource_icl(&link_id);
3129
3130 let has_failed = icl_actions
3132 .iter()
3133 .any(|a| matches!(a, LinkManagerAction::ResourceFailed { .. }));
3134 assert!(has_failed, "ICL should produce ResourceFailed");
3135 }
3136
3137 #[test]
3138 fn test_resource_cancel_rcl() {
3139 let (mut init_mgr, _resp_mgr, link_id) = setup_active_link();
3140 let mut rng = OsRng;
3141
3142 let data = vec![0xAB; 2000];
3144 init_mgr.send_resource(&link_id, &data, None, &mut rng);
3145
3146 assert!(!init_mgr
3148 .links
3149 .get(&link_id)
3150 .unwrap()
3151 .outgoing_resources
3152 .is_empty());
3153
3154 let rcl_actions = init_mgr.handle_resource_rcl(&link_id);
3156
3157 let has_failed = rcl_actions
3158 .iter()
3159 .any(|a| matches!(a, LinkManagerAction::ResourceFailed { .. }));
3160 assert!(has_failed, "RCL should produce ResourceFailed");
3161 }
3162
3163 #[test]
3164 fn test_resource_tick_cleans_up() {
3165 let (mut init_mgr, _resp_mgr, link_id) = setup_active_link();
3166 let mut rng = OsRng;
3167
3168 let data = vec![0xAB; 100];
3169 init_mgr.send_resource(&link_id, &data, None, &mut rng);
3170
3171 assert!(!init_mgr
3172 .links
3173 .get(&link_id)
3174 .unwrap()
3175 .outgoing_resources
3176 .is_empty());
3177
3178 init_mgr.handle_resource_rcl(&link_id);
3180
3181 init_mgr.tick(&mut rng);
3183
3184 assert!(
3185 init_mgr
3186 .links
3187 .get(&link_id)
3188 .unwrap()
3189 .outgoing_resources
3190 .is_empty(),
3191 "Tick should clean up completed/failed outgoing resources"
3192 );
3193 }
3194
3195 #[test]
3196 fn test_build_link_packet() {
3197 let (init_mgr, _resp_mgr, link_id) = setup_active_link();
3198
3199 let actions =
3200 init_mgr.build_link_packet(&link_id, constants::CONTEXT_RESOURCE, b"test data");
3201 assert_eq!(actions.len(), 1);
3202 if let LinkManagerAction::SendPacket { raw, dest_type, .. } = &actions[0] {
3203 let pkt = RawPacket::unpack(raw).unwrap();
3204 assert_eq!(pkt.context, constants::CONTEXT_RESOURCE);
3205 assert_eq!(*dest_type, constants::DESTINATION_LINK);
3206 } else {
3207 panic!("Expected SendPacket");
3208 }
3209 }
3210
3211 #[test]
3216 fn test_channel_message_delivery() {
3217 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
3218 let mut rng = OsRng;
3219
3220 let chan_actions = init_mgr.send_channel_message(&link_id, 42, b"channel data", &mut rng);
3222 assert!(!chan_actions.is_empty());
3223
3224 let mut got_channel_msg = false;
3226 for action in &chan_actions {
3227 if let LinkManagerAction::SendPacket { raw, .. } = action {
3228 let pkt = RawPacket::unpack(raw).unwrap();
3229 let resp_actions = resp_mgr.handle_local_delivery(
3230 pkt.destination_hash,
3231 raw,
3232 pkt.packet_hash,
3233 rns_core::transport::types::InterfaceId(0),
3234 &mut rng,
3235 );
3236 for a in &resp_actions {
3237 if let LinkManagerAction::ChannelMessageReceived {
3238 msgtype, payload, ..
3239 } = a
3240 {
3241 assert_eq!(*msgtype, 42);
3242 assert_eq!(*payload, b"channel data");
3243 got_channel_msg = true;
3244 }
3245 }
3246 }
3247 }
3248 assert!(got_channel_msg, "Responder should receive channel message");
3249 }
3250
3251 #[test]
3252 fn test_generic_link_data_delivery() {
3253 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
3254 let mut rng = OsRng;
3255
3256 let actions = init_mgr.send_on_link(&link_id, b"raw stuff", 0x42, &mut rng);
3258 assert_eq!(actions.len(), 1);
3259
3260 let raw = extract_any_send_packet(&actions);
3262 let pkt = RawPacket::unpack(&raw).unwrap();
3263 let resp_actions = resp_mgr.handle_local_delivery(
3264 pkt.destination_hash,
3265 &raw,
3266 pkt.packet_hash,
3267 rns_core::transport::types::InterfaceId(0),
3268 &mut rng,
3269 );
3270
3271 let has_data = resp_actions
3272 .iter()
3273 .any(|a| matches!(a, LinkManagerAction::LinkDataReceived { context: 0x42, .. }));
3274 assert!(
3275 has_data,
3276 "Responder should receive LinkDataReceived for unknown context"
3277 );
3278 }
3279
3280 #[test]
3281 fn test_response_delivery() {
3282 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
3283 let mut rng = OsRng;
3284
3285 resp_mgr.register_request_handler("/echo", None, |_link_id, _path, data, _remote| {
3287 Some(data.to_vec())
3288 });
3289
3290 let req_actions = init_mgr.send_request(&link_id, "/echo", b"\xc0", &mut rng); assert!(!req_actions.is_empty());
3293
3294 let req_raw = extract_any_send_packet(&req_actions);
3296 let req_pkt = RawPacket::unpack(&req_raw).unwrap();
3297 let resp_actions = resp_mgr.handle_local_delivery(
3298 req_pkt.destination_hash,
3299 &req_raw,
3300 req_pkt.packet_hash,
3301 rns_core::transport::types::InterfaceId(0),
3302 &mut rng,
3303 );
3304 let has_resp_send = resp_actions
3305 .iter()
3306 .any(|a| matches!(a, LinkManagerAction::SendPacket { .. }));
3307 assert!(has_resp_send, "Handler should produce response");
3308
3309 let resp_raw = extract_any_send_packet(&resp_actions);
3311 let resp_pkt = RawPacket::unpack(&resp_raw).unwrap();
3312 let init_actions = init_mgr.handle_local_delivery(
3313 resp_pkt.destination_hash,
3314 &resp_raw,
3315 resp_pkt.packet_hash,
3316 rns_core::transport::types::InterfaceId(0),
3317 &mut rng,
3318 );
3319
3320 let has_response_received = init_actions
3321 .iter()
3322 .any(|a| matches!(a, LinkManagerAction::ResponseReceived { .. }));
3323 assert!(
3324 has_response_received,
3325 "Initiator should receive ResponseReceived"
3326 );
3327 }
3328
3329 #[test]
3330 fn test_send_channel_message_on_no_channel() {
3331 let mut mgr = LinkManager::new();
3332 let mut rng = OsRng;
3333 let dummy_sig = [0xAA; 32];
3334 let (link_id, _) =
3335 mgr.create_link(&[0x11; 16], &dummy_sig, 1, constants::MTU as u32, &mut rng);
3336
3337 let actions = mgr.send_channel_message(&link_id, 1, b"test", &mut rng);
3339 assert!(actions.is_empty(), "No channel on pending link");
3340 }
3341
3342 #[test]
3343 fn test_send_on_link_requires_active() {
3344 let mut mgr = LinkManager::new();
3345 let mut rng = OsRng;
3346 let dummy_sig = [0xAA; 32];
3347 let (link_id, _) =
3348 mgr.create_link(&[0x11; 16], &dummy_sig, 1, constants::MTU as u32, &mut rng);
3349
3350 let actions = mgr.send_on_link(&link_id, b"test", constants::CONTEXT_NONE, &mut rng);
3351 assert!(actions.is_empty(), "Cannot send on pending link");
3352 }
3353
3354 #[test]
3355 fn test_send_on_link_unknown_link() {
3356 let mgr = LinkManager::new();
3357 let mut rng = OsRng;
3358
3359 let actions = mgr.send_on_link(&[0xFF; 16], b"test", constants::CONTEXT_NONE, &mut rng);
3360 assert!(actions.is_empty());
3361 }
3362
3363 #[test]
3364 fn test_resource_full_transfer_large() {
3365 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
3366 let mut rng = OsRng;
3367
3368 resp_mgr.set_resource_strategy(&link_id, ResourceStrategy::AcceptAll);
3369
3370 let original_data: Vec<u8> = (0..2000u32)
3372 .map(|i| {
3373 let pos = i as usize;
3374 (pos ^ (pos >> 8) ^ (pos >> 16)) as u8
3375 })
3376 .collect();
3377
3378 let adv_actions = init_mgr.send_resource(&link_id, &original_data, None, &mut rng);
3379
3380 let mut pending: Vec<(char, LinkManagerAction)> =
3381 adv_actions.into_iter().map(|a| ('i', a)).collect();
3382 let mut rounds = 0;
3383 let max_rounds = 200;
3384 let mut resource_received = false;
3385 let mut sender_completed = false;
3386
3387 while !pending.is_empty() && rounds < max_rounds {
3388 rounds += 1;
3389 let mut next: Vec<(char, LinkManagerAction)> = Vec::new();
3390
3391 for (source, action) in pending.drain(..) {
3392 if let LinkManagerAction::SendPacket { raw, .. } = action {
3393 let pkt = match RawPacket::unpack(&raw) {
3394 Ok(p) => p,
3395 Err(_) => continue,
3396 };
3397
3398 let target_actions = if source == 'i' {
3399 resp_mgr.handle_local_delivery(
3400 pkt.destination_hash,
3401 &raw,
3402 pkt.packet_hash,
3403 rns_core::transport::types::InterfaceId(0),
3404 &mut rng,
3405 )
3406 } else {
3407 init_mgr.handle_local_delivery(
3408 pkt.destination_hash,
3409 &raw,
3410 pkt.packet_hash,
3411 rns_core::transport::types::InterfaceId(0),
3412 &mut rng,
3413 )
3414 };
3415
3416 let target_source = if source == 'i' { 'r' } else { 'i' };
3417 for a in &target_actions {
3418 match a {
3419 LinkManagerAction::ResourceReceived { data, .. } => {
3420 assert_eq!(*data, original_data);
3421 resource_received = true;
3422 }
3423 LinkManagerAction::ResourceCompleted { .. } => {
3424 sender_completed = true;
3425 }
3426 _ => {}
3427 }
3428 }
3429 next.extend(target_actions.into_iter().map(|a| (target_source, a)));
3430 }
3431 }
3432 pending = next;
3433 }
3434
3435 assert!(
3436 resource_received,
3437 "Should receive large resource (rounds={})",
3438 rounds
3439 );
3440 assert!(
3441 sender_completed,
3442 "Sender should complete (rounds={})",
3443 rounds
3444 );
3445 }
3446
3447 #[test]
3448 fn test_process_resource_actions_mapping() {
3449 let (init_mgr, _resp_mgr, link_id) = setup_active_link();
3450 let mut rng = OsRng;
3451
3452 let actions = vec![
3454 ResourceAction::DataReceived {
3455 data: vec![1, 2, 3],
3456 metadata: Some(vec![4, 5]),
3457 },
3458 ResourceAction::Completed,
3459 ResourceAction::Failed(rns_core::resource::ResourceError::Timeout),
3460 ResourceAction::ProgressUpdate {
3461 received: 10,
3462 total: 20,
3463 },
3464 ];
3465
3466 let result = init_mgr.process_resource_actions(&link_id, actions, &mut rng);
3467
3468 assert!(matches!(
3469 result[0],
3470 LinkManagerAction::ResourceReceived { .. }
3471 ));
3472 assert!(matches!(
3473 result[1],
3474 LinkManagerAction::ResourceCompleted { .. }
3475 ));
3476 assert!(matches!(
3477 result[2],
3478 LinkManagerAction::ResourceFailed { .. }
3479 ));
3480 assert!(matches!(
3481 result[3],
3482 LinkManagerAction::ResourceProgress {
3483 received: 10,
3484 total: 20,
3485 ..
3486 }
3487 ));
3488 }
3489
3490 #[test]
3491 fn test_link_state_empty() {
3492 let mgr = LinkManager::new();
3493 let fake_id = [0xAA; 16];
3494 assert!(mgr.link_state(&fake_id).is_none());
3495 }
3496}