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