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