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