1use std::collections::HashMap;
10
11use crate::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 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 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 if let Some(link) = self.links.get_mut(&link_id) {
711 let now = time::now();
712 let flags = PacketFlags {
713 header_type: constants::HEADER_1,
714 context_flag: constants::FLAG_UNSET,
715 transport_type: constants::TRANSPORT_BROADCAST,
716 destination_type: constants::DESTINATION_LINK,
717 packet_type: constants::PACKET_TYPE_DATA,
718 };
719 if let Ok(pkt) = RawPacket::pack(
720 flags, 0, &link_id, None, constants::CONTEXT_KEEPALIVE, &[],
721 ) {
722 actions.push(LinkManagerAction::SendPacket {
723 raw: pkt.raw,
724 dest_type: constants::DESTINATION_LINK,
725 attached_interface: None,
726 });
727 link.engine.record_outbound(now, true);
728 }
729 }
730 }
731 LinkDataResult::LinkClose { link_id, teardown_actions } => {
732 actions.extend(self.process_link_actions(&link_id, &teardown_actions));
733 }
734 LinkDataResult::Channel { link_id, inbound_actions, plaintext } => {
735 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
736 if let Some(link) = self.links.get_mut(&link_id) {
738 if let Some(ref mut channel) = link.channel {
739 let chan_actions = channel.receive(&plaintext, time::now());
740 let _ = link;
742 actions.extend(self.process_channel_actions(&link_id, chan_actions, rng));
743 }
744 }
745 }
746 LinkDataResult::Request { link_id, inbound_actions, plaintext } => {
747 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
748 actions.extend(self.handle_request(&link_id, &plaintext, rng));
749 }
750 LinkDataResult::Response { link_id, inbound_actions, plaintext } => {
751 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
752 actions.extend(self.handle_response(&link_id, &plaintext));
754 }
755 LinkDataResult::Generic { link_id, inbound_actions, plaintext, context, packet_hash } => {
756 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
757 actions.push(LinkManagerAction::LinkDataReceived {
758 link_id,
759 context,
760 data: plaintext,
761 });
762
763 if let Some(link) = self.links.get(&link_id) {
765 if let Some(ld) = self.link_destinations.get(&link.dest_hash) {
766 let signature = ld.sig_prv.sign(&packet_hash);
767 let mut proof_data = Vec::with_capacity(96);
768 proof_data.extend_from_slice(&packet_hash);
769 proof_data.extend_from_slice(&signature);
770
771 let flags = PacketFlags {
772 header_type: constants::HEADER_1,
773 context_flag: constants::FLAG_UNSET,
774 transport_type: constants::TRANSPORT_BROADCAST,
775 destination_type: constants::DESTINATION_LINK,
776 packet_type: constants::PACKET_TYPE_PROOF,
777 };
778 if let Ok(pkt) = RawPacket::pack(
779 flags, 0, &link_id, None,
780 constants::CONTEXT_NONE, &proof_data,
781 ) {
782 actions.push(LinkManagerAction::SendPacket {
783 raw: pkt.raw,
784 dest_type: constants::DESTINATION_LINK,
785 attached_interface: None,
786 });
787 }
788 }
789 }
790 }
791 LinkDataResult::ResourceAdv { link_id, inbound_actions, plaintext } => {
792 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
793 actions.extend(self.handle_resource_adv(&link_id, &plaintext, rng));
794 }
795 LinkDataResult::ResourceReq { link_id, inbound_actions, plaintext } => {
796 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
797 actions.extend(self.handle_resource_req(&link_id, &plaintext, rng));
798 }
799 LinkDataResult::ResourceHmu { link_id, inbound_actions, plaintext } => {
800 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
801 actions.extend(self.handle_resource_hmu(&link_id, &plaintext, rng));
802 }
803 LinkDataResult::ResourcePart { link_id, inbound_actions, raw_data } => {
804 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
805 actions.extend(self.handle_resource_part(&link_id, &raw_data, rng));
806 }
807 LinkDataResult::ResourcePrf { link_id, inbound_actions, plaintext } => {
808 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
809 actions.extend(self.handle_resource_prf(&link_id, &plaintext));
810 }
811 LinkDataResult::ResourceIcl { link_id, inbound_actions } => {
812 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
813 actions.extend(self.handle_resource_icl(&link_id));
814 }
815 LinkDataResult::ResourceRcl { link_id, inbound_actions } => {
816 actions.extend(self.process_link_actions(&link_id, &inbound_actions));
817 actions.extend(self.handle_resource_rcl(&link_id));
818 }
819 LinkDataResult::Error => {}
820 }
821
822 actions
823 }
824
825 fn handle_request(
827 &mut self,
828 link_id: &LinkId,
829 plaintext: &[u8],
830 rng: &mut dyn Rng,
831 ) -> Vec<LinkManagerAction> {
832 use rns_core::msgpack::{self, Value};
833
834 let arr = match msgpack::unpack_exact(plaintext) {
836 Ok(Value::Array(arr)) if arr.len() >= 3 => arr,
837 _ => return Vec::new(),
838 };
839
840 let path_hash_bytes = match &arr[1] {
841 Value::Bin(b) if b.len() == 16 => b,
842 _ => return Vec::new(),
843 };
844 let mut path_hash = [0u8; 16];
845 path_hash.copy_from_slice(path_hash_bytes);
846
847 let request_id = rns_core::hash::truncated_hash(plaintext);
849
850 let request_data = msgpack::pack(&arr[2]);
852
853 if self.management_paths.contains(&path_hash) {
855 let remote_identity = self.links.get(link_id)
856 .and_then(|l| l.remote_identity)
857 .map(|(h, k)| (h, k));
858 return vec![LinkManagerAction::ManagementRequest {
859 link_id: *link_id,
860 path_hash,
861 data: request_data,
862 request_id,
863 remote_identity,
864 }];
865 }
866
867 let handler_idx = self.request_handlers.iter().position(|h| h.path_hash == path_hash);
869 let handler_idx = match handler_idx {
870 Some(i) => i,
871 None => return Vec::new(),
872 };
873
874 let remote_identity = self.links.get(link_id).and_then(|l| l.remote_identity.as_ref());
876 let handler = &self.request_handlers[handler_idx];
877 if let Some(ref allowed) = handler.allowed_list {
878 match remote_identity {
879 Some((identity_hash, _)) => {
880 if !allowed.contains(identity_hash) {
881 log::debug!("Request denied: identity not in allowed list");
882 return Vec::new();
883 }
884 }
885 None => {
886 log::debug!("Request denied: peer not identified");
887 return Vec::new();
888 }
889 }
890 }
891
892 let path = handler.path.clone();
894 let response = (handler.handler)(*link_id, &path, &request_data, remote_identity);
895
896 let mut actions = Vec::new();
897 if let Some(response_data) = response {
898 actions.extend(self.build_response_packet(link_id, &request_id, &response_data, rng));
899 }
900
901 actions
902 }
903
904 fn build_response_packet(
907 &self,
908 link_id: &LinkId,
909 request_id: &[u8; 16],
910 response_data: &[u8],
911 rng: &mut dyn Rng,
912 ) -> Vec<LinkManagerAction> {
913 use rns_core::msgpack::{self, Value};
914
915 let response_value = msgpack::unpack_exact(response_data)
917 .unwrap_or_else(|_| Value::Bin(response_data.to_vec()));
918
919 let response_array = Value::Array(vec![
920 Value::Bin(request_id.to_vec()),
921 response_value,
922 ]);
923 let response_plaintext = msgpack::pack(&response_array);
924
925 let mut actions = Vec::new();
926 if let Some(link) = self.links.get(link_id) {
927 if let Ok(encrypted) = link.engine.encrypt(&response_plaintext, rng) {
928 let flags = PacketFlags {
929 header_type: constants::HEADER_1,
930 context_flag: constants::FLAG_UNSET,
931 transport_type: constants::TRANSPORT_BROADCAST,
932 destination_type: constants::DESTINATION_LINK,
933 packet_type: constants::PACKET_TYPE_DATA,
934 };
935 if let Ok(pkt) = RawPacket::pack(
936 flags, 0, link_id, None, constants::CONTEXT_RESPONSE, &encrypted,
937 ) {
938 actions.push(LinkManagerAction::SendPacket {
939 raw: pkt.raw,
940 dest_type: constants::DESTINATION_LINK,
941 attached_interface: None,
942 });
943 }
944 }
945 }
946 actions
947 }
948
949 pub fn send_management_response(
952 &self,
953 link_id: &LinkId,
954 request_id: &[u8; 16],
955 response_data: &[u8],
956 rng: &mut dyn Rng,
957 ) -> Vec<LinkManagerAction> {
958 self.build_response_packet(link_id, request_id, response_data, rng)
959 }
960
961 pub fn send_request(
969 &self,
970 link_id: &LinkId,
971 path: &str,
972 data: &[u8],
973 rng: &mut dyn Rng,
974 ) -> Vec<LinkManagerAction> {
975 use rns_core::msgpack::{self, Value};
976
977 let link = match self.links.get(link_id) {
978 Some(l) => l,
979 None => return Vec::new(),
980 };
981
982 if link.engine.state() != LinkState::Active {
983 return Vec::new();
984 }
985
986 let path_hash = compute_path_hash(path);
987
988 let data_value = msgpack::unpack_exact(data)
990 .unwrap_or_else(|_| Value::Bin(data.to_vec()));
991
992 let request_array = Value::Array(vec![
994 Value::Float(time::now()),
995 Value::Bin(path_hash.to_vec()),
996 data_value,
997 ]);
998 let plaintext = msgpack::pack(&request_array);
999
1000 let encrypted = match link.engine.encrypt(&plaintext, rng) {
1001 Ok(e) => e,
1002 Err(_) => return Vec::new(),
1003 };
1004
1005 let flags = PacketFlags {
1006 header_type: constants::HEADER_1,
1007 context_flag: constants::FLAG_UNSET,
1008 transport_type: constants::TRANSPORT_BROADCAST,
1009 destination_type: constants::DESTINATION_LINK,
1010 packet_type: constants::PACKET_TYPE_DATA,
1011 };
1012
1013 let mut actions = Vec::new();
1014 if let Ok(pkt) = RawPacket::pack(
1015 flags, 0, link_id, None, constants::CONTEXT_REQUEST, &encrypted,
1016 ) {
1017 actions.push(LinkManagerAction::SendPacket {
1018 raw: pkt.raw,
1019 dest_type: constants::DESTINATION_LINK,
1020 attached_interface: None,
1021 });
1022 }
1023 actions
1024 }
1025
1026 pub fn send_on_link(
1028 &self,
1029 link_id: &LinkId,
1030 plaintext: &[u8],
1031 context: u8,
1032 rng: &mut dyn Rng,
1033 ) -> Vec<LinkManagerAction> {
1034 let link = match self.links.get(link_id) {
1035 Some(l) => l,
1036 None => return Vec::new(),
1037 };
1038
1039 if link.engine.state() != LinkState::Active {
1040 return Vec::new();
1041 }
1042
1043 let encrypted = match link.engine.encrypt(plaintext, rng) {
1044 Ok(e) => e,
1045 Err(_) => return Vec::new(),
1046 };
1047
1048 let flags = PacketFlags {
1049 header_type: constants::HEADER_1,
1050 context_flag: constants::FLAG_UNSET,
1051 transport_type: constants::TRANSPORT_BROADCAST,
1052 destination_type: constants::DESTINATION_LINK,
1053 packet_type: constants::PACKET_TYPE_DATA,
1054 };
1055
1056 let mut actions = Vec::new();
1057 if let Ok(pkt) = RawPacket::pack(
1058 flags, 0, link_id, None, context, &encrypted,
1059 ) {
1060 actions.push(LinkManagerAction::SendPacket {
1061 raw: pkt.raw,
1062 dest_type: constants::DESTINATION_LINK,
1063 attached_interface: None,
1064 });
1065 }
1066 actions
1067 }
1068
1069 pub fn identify(
1071 &self,
1072 link_id: &LinkId,
1073 identity: &rns_crypto::identity::Identity,
1074 rng: &mut dyn Rng,
1075 ) -> Vec<LinkManagerAction> {
1076 let link = match self.links.get(link_id) {
1077 Some(l) => l,
1078 None => return Vec::new(),
1079 };
1080
1081 let encrypted = match link.engine.build_identify(identity, rng) {
1082 Ok(e) => e,
1083 Err(_) => return Vec::new(),
1084 };
1085
1086 let flags = PacketFlags {
1087 header_type: constants::HEADER_1,
1088 context_flag: constants::FLAG_UNSET,
1089 transport_type: constants::TRANSPORT_BROADCAST,
1090 destination_type: constants::DESTINATION_LINK,
1091 packet_type: constants::PACKET_TYPE_DATA,
1092 };
1093
1094 let mut actions = Vec::new();
1095 if let Ok(pkt) = RawPacket::pack(
1096 flags, 0, link_id, None, constants::CONTEXT_LINKIDENTIFY, &encrypted,
1097 ) {
1098 actions.push(LinkManagerAction::SendPacket {
1099 raw: pkt.raw,
1100 dest_type: constants::DESTINATION_LINK,
1101 attached_interface: None,
1102 });
1103 }
1104 actions
1105 }
1106
1107 pub fn teardown_link(&mut self, link_id: &LinkId) -> Vec<LinkManagerAction> {
1109 let link = match self.links.get_mut(link_id) {
1110 Some(l) => l,
1111 None => return Vec::new(),
1112 };
1113
1114 let teardown_actions = link.engine.teardown();
1115 if let Some(ref mut channel) = link.channel {
1116 channel.shutdown();
1117 }
1118
1119 let mut actions = self.process_link_actions(link_id, &teardown_actions);
1120
1121 let flags = PacketFlags {
1123 header_type: constants::HEADER_1,
1124 context_flag: constants::FLAG_UNSET,
1125 transport_type: constants::TRANSPORT_BROADCAST,
1126 destination_type: constants::DESTINATION_LINK,
1127 packet_type: constants::PACKET_TYPE_DATA,
1128 };
1129 if let Ok(pkt) = RawPacket::pack(
1130 flags, 0, link_id, None, constants::CONTEXT_LINKCLOSE, &[],
1131 ) {
1132 actions.push(LinkManagerAction::SendPacket {
1133 raw: pkt.raw,
1134 dest_type: constants::DESTINATION_LINK,
1135 attached_interface: None,
1136 });
1137 }
1138
1139 actions
1140 }
1141
1142 fn handle_response(
1144 &self,
1145 link_id: &LinkId,
1146 plaintext: &[u8],
1147 ) -> Vec<LinkManagerAction> {
1148 use rns_core::msgpack;
1149
1150 let arr = match msgpack::unpack_exact(plaintext) {
1152 Ok(msgpack::Value::Array(arr)) if arr.len() >= 2 => arr,
1153 _ => return Vec::new(),
1154 };
1155
1156 let request_id_bytes = match &arr[0] {
1157 msgpack::Value::Bin(b) if b.len() == 16 => b,
1158 _ => return Vec::new(),
1159 };
1160 let mut request_id = [0u8; 16];
1161 request_id.copy_from_slice(request_id_bytes);
1162
1163 let response_data = msgpack::pack(&arr[1]);
1164
1165 vec![LinkManagerAction::ResponseReceived {
1166 link_id: *link_id,
1167 request_id,
1168 data: response_data,
1169 }]
1170 }
1171
1172 fn handle_resource_adv(
1174 &mut self,
1175 link_id: &LinkId,
1176 adv_plaintext: &[u8],
1177 rng: &mut dyn Rng,
1178 ) -> Vec<LinkManagerAction> {
1179 let link = match self.links.get_mut(link_id) {
1180 Some(l) => l,
1181 None => return Vec::new(),
1182 };
1183
1184 let link_rtt = link.engine.rtt().unwrap_or(1.0);
1185 let now = time::now();
1186
1187 let receiver = match ResourceReceiver::from_advertisement(
1188 adv_plaintext,
1189 constants::RESOURCE_SDU,
1190 link_rtt,
1191 now,
1192 None,
1193 None,
1194 ) {
1195 Ok(r) => r,
1196 Err(e) => {
1197 log::debug!("Resource ADV rejected: {}", e);
1198 return Vec::new();
1199 }
1200 };
1201
1202 let strategy = link.resource_strategy;
1203 let resource_hash = receiver.resource_hash.clone();
1204 let transfer_size = receiver.transfer_size;
1205 let has_metadata = receiver.has_metadata;
1206
1207 match strategy {
1208 ResourceStrategy::AcceptNone => {
1209 let reject_actions = {
1211 let mut r = receiver;
1212 r.reject()
1213 };
1214 self.process_resource_actions(link_id, reject_actions, rng)
1215 }
1216 ResourceStrategy::AcceptAll => {
1217 link.incoming_resources.push(receiver);
1218 let idx = link.incoming_resources.len() - 1;
1219 let resource_actions = link.incoming_resources[idx].accept(now);
1220 let _ = link;
1221 self.process_resource_actions(link_id, resource_actions, rng)
1222 }
1223 ResourceStrategy::AcceptApp => {
1224 link.incoming_resources.push(receiver);
1225 vec![LinkManagerAction::ResourceAcceptQuery {
1227 link_id: *link_id,
1228 resource_hash,
1229 transfer_size,
1230 has_metadata,
1231 }]
1232 }
1233 }
1234 }
1235
1236 pub fn accept_resource(
1238 &mut self,
1239 link_id: &LinkId,
1240 resource_hash: &[u8],
1241 accept: bool,
1242 rng: &mut dyn Rng,
1243 ) -> Vec<LinkManagerAction> {
1244 let link = match self.links.get_mut(link_id) {
1245 Some(l) => l,
1246 None => return Vec::new(),
1247 };
1248
1249 let now = time::now();
1250 let idx = link.incoming_resources.iter().position(|r| r.resource_hash == resource_hash);
1251 let idx = match idx {
1252 Some(i) => i,
1253 None => return Vec::new(),
1254 };
1255
1256 let resource_actions = if accept {
1257 link.incoming_resources[idx].accept(now)
1258 } else {
1259 link.incoming_resources[idx].reject()
1260 };
1261
1262 let _ = link;
1263 self.process_resource_actions(link_id, resource_actions, rng)
1264 }
1265
1266 fn handle_resource_req(
1268 &mut self,
1269 link_id: &LinkId,
1270 plaintext: &[u8],
1271 rng: &mut dyn Rng,
1272 ) -> Vec<LinkManagerAction> {
1273 let link = match self.links.get_mut(link_id) {
1274 Some(l) => l,
1275 None => return Vec::new(),
1276 };
1277
1278 let now = time::now();
1279 let mut all_actions = Vec::new();
1280 for sender in &mut link.outgoing_resources {
1281 let resource_actions = sender.handle_request(plaintext, now);
1282 if !resource_actions.is_empty() {
1283 all_actions.extend(resource_actions);
1284 break;
1285 }
1286 }
1287
1288 let _ = link;
1289 self.process_resource_actions(link_id, all_actions, rng)
1290 }
1291
1292 fn handle_resource_hmu(
1294 &mut self,
1295 link_id: &LinkId,
1296 plaintext: &[u8],
1297 rng: &mut dyn Rng,
1298 ) -> Vec<LinkManagerAction> {
1299 let link = match self.links.get_mut(link_id) {
1300 Some(l) => l,
1301 None => return Vec::new(),
1302 };
1303
1304 let now = time::now();
1305 let mut all_actions = Vec::new();
1306 for receiver in &mut link.incoming_resources {
1307 let resource_actions = receiver.handle_hashmap_update(plaintext, now);
1308 if !resource_actions.is_empty() {
1309 all_actions.extend(resource_actions);
1310 break;
1311 }
1312 }
1313
1314 let _ = link;
1315 self.process_resource_actions(link_id, all_actions, rng)
1316 }
1317
1318 fn handle_resource_part(
1320 &mut self,
1321 link_id: &LinkId,
1322 raw_data: &[u8],
1323 rng: &mut dyn Rng,
1324 ) -> Vec<LinkManagerAction> {
1325 let link = match self.links.get_mut(link_id) {
1326 Some(l) => l,
1327 None => return Vec::new(),
1328 };
1329
1330 let now = time::now();
1331 let mut all_actions = Vec::new();
1332 let mut assemble_idx = None;
1333
1334 for (idx, receiver) in link.incoming_resources.iter_mut().enumerate() {
1335 let resource_actions = receiver.receive_part(raw_data, now);
1336 if !resource_actions.is_empty() {
1337 if receiver.received_count == receiver.total_parts {
1339 assemble_idx = Some(idx);
1340 }
1341 all_actions.extend(resource_actions);
1342 break;
1343 }
1344 }
1345
1346 if let Some(idx) = assemble_idx {
1348 let decrypt_fn = |ciphertext: &[u8]| -> Result<Vec<u8>, ()> {
1349 link.engine.decrypt(ciphertext).map_err(|_| ())
1350 };
1351 let assemble_actions = link.incoming_resources[idx].assemble(&decrypt_fn, &Bzip2Compressor);
1352 all_actions.extend(assemble_actions);
1353 }
1354
1355 let _ = link;
1356 self.process_resource_actions(link_id, all_actions, rng)
1357 }
1358
1359 fn handle_resource_prf(
1361 &mut self,
1362 link_id: &LinkId,
1363 plaintext: &[u8],
1364 ) -> Vec<LinkManagerAction> {
1365 let link = match self.links.get_mut(link_id) {
1366 Some(l) => l,
1367 None => return Vec::new(),
1368 };
1369
1370 let now = time::now();
1371 let mut result_actions = Vec::new();
1372 for sender in &mut link.outgoing_resources {
1373 let resource_actions = sender.handle_proof(plaintext, now);
1374 if !resource_actions.is_empty() {
1375 result_actions.extend(resource_actions);
1376 break;
1377 }
1378 }
1379
1380 let mut actions = Vec::new();
1382 for ra in result_actions {
1383 match ra {
1384 ResourceAction::Completed => {
1385 actions.push(LinkManagerAction::ResourceCompleted { link_id: *link_id });
1386 }
1387 ResourceAction::Failed(e) => {
1388 actions.push(LinkManagerAction::ResourceFailed {
1389 link_id: *link_id,
1390 error: format!("{}", e),
1391 });
1392 }
1393 _ => {}
1394 }
1395 }
1396
1397 link.outgoing_resources.retain(|s| {
1399 s.status < rns_core::resource::ResourceStatus::Complete
1400 });
1401
1402 actions
1403 }
1404
1405 fn handle_resource_icl(
1407 &mut self,
1408 link_id: &LinkId,
1409 ) -> Vec<LinkManagerAction> {
1410 let link = match self.links.get_mut(link_id) {
1411 Some(l) => l,
1412 None => return Vec::new(),
1413 };
1414
1415 let mut actions = Vec::new();
1416 for receiver in &mut link.incoming_resources {
1417 let ra = receiver.handle_cancel();
1418 for a in ra {
1419 if let ResourceAction::Failed(ref e) = a {
1420 actions.push(LinkManagerAction::ResourceFailed {
1421 link_id: *link_id,
1422 error: format!("{}", e),
1423 });
1424 }
1425 }
1426 }
1427 link.incoming_resources.retain(|r| {
1428 r.status < rns_core::resource::ResourceStatus::Complete
1429 });
1430 actions
1431 }
1432
1433 fn handle_resource_rcl(
1435 &mut self,
1436 link_id: &LinkId,
1437 ) -> Vec<LinkManagerAction> {
1438 let link = match self.links.get_mut(link_id) {
1439 Some(l) => l,
1440 None => return Vec::new(),
1441 };
1442
1443 let mut actions = Vec::new();
1444 for sender in &mut link.outgoing_resources {
1445 let ra = sender.handle_reject();
1446 for a in ra {
1447 if let ResourceAction::Failed(ref e) = a {
1448 actions.push(LinkManagerAction::ResourceFailed {
1449 link_id: *link_id,
1450 error: format!("{}", e),
1451 });
1452 }
1453 }
1454 }
1455 link.outgoing_resources.retain(|s| {
1456 s.status < rns_core::resource::ResourceStatus::Complete
1457 });
1458 actions
1459 }
1460
1461 fn process_resource_actions(
1463 &self,
1464 link_id: &LinkId,
1465 actions: Vec<ResourceAction>,
1466 rng: &mut dyn Rng,
1467 ) -> Vec<LinkManagerAction> {
1468 let link = match self.links.get(link_id) {
1469 Some(l) => l,
1470 None => return Vec::new(),
1471 };
1472
1473 let mut result = Vec::new();
1474 for action in actions {
1475 match action {
1476 ResourceAction::SendAdvertisement(data) => {
1477 if let Ok(encrypted) = link.engine.encrypt(&data, rng) {
1479 result.extend(self.build_link_packet(
1480 link_id, constants::CONTEXT_RESOURCE_ADV, &encrypted,
1481 ));
1482 }
1483 }
1484 ResourceAction::SendPart(data) => {
1485 result.extend(self.build_link_packet(
1487 link_id, constants::CONTEXT_RESOURCE, &data,
1488 ));
1489 }
1490 ResourceAction::SendRequest(data) => {
1491 if let Ok(encrypted) = link.engine.encrypt(&data, rng) {
1492 result.extend(self.build_link_packet(
1493 link_id, constants::CONTEXT_RESOURCE_REQ, &encrypted,
1494 ));
1495 }
1496 }
1497 ResourceAction::SendHmu(data) => {
1498 if let Ok(encrypted) = link.engine.encrypt(&data, rng) {
1499 result.extend(self.build_link_packet(
1500 link_id, constants::CONTEXT_RESOURCE_HMU, &encrypted,
1501 ));
1502 }
1503 }
1504 ResourceAction::SendProof(data) => {
1505 if let Ok(encrypted) = link.engine.encrypt(&data, rng) {
1506 result.extend(self.build_link_packet(
1507 link_id, constants::CONTEXT_RESOURCE_PRF, &encrypted,
1508 ));
1509 }
1510 }
1511 ResourceAction::SendCancelInitiator(data) => {
1512 if let Ok(encrypted) = link.engine.encrypt(&data, rng) {
1513 result.extend(self.build_link_packet(
1514 link_id, constants::CONTEXT_RESOURCE_ICL, &encrypted,
1515 ));
1516 }
1517 }
1518 ResourceAction::SendCancelReceiver(data) => {
1519 if let Ok(encrypted) = link.engine.encrypt(&data, rng) {
1520 result.extend(self.build_link_packet(
1521 link_id, constants::CONTEXT_RESOURCE_RCL, &encrypted,
1522 ));
1523 }
1524 }
1525 ResourceAction::DataReceived { data, metadata } => {
1526 result.push(LinkManagerAction::ResourceReceived {
1527 link_id: *link_id,
1528 data,
1529 metadata,
1530 });
1531 }
1532 ResourceAction::Completed => {
1533 result.push(LinkManagerAction::ResourceCompleted { link_id: *link_id });
1534 }
1535 ResourceAction::Failed(e) => {
1536 result.push(LinkManagerAction::ResourceFailed {
1537 link_id: *link_id,
1538 error: format!("{}", e),
1539 });
1540 }
1541 ResourceAction::ProgressUpdate { received, total } => {
1542 result.push(LinkManagerAction::ResourceProgress {
1543 link_id: *link_id,
1544 received,
1545 total,
1546 });
1547 }
1548 }
1549 }
1550 result
1551 }
1552
1553 fn build_link_packet(
1555 &self,
1556 link_id: &LinkId,
1557 context: u8,
1558 data: &[u8],
1559 ) -> Vec<LinkManagerAction> {
1560 let flags = PacketFlags {
1561 header_type: constants::HEADER_1,
1562 context_flag: constants::FLAG_UNSET,
1563 transport_type: constants::TRANSPORT_BROADCAST,
1564 destination_type: constants::DESTINATION_LINK,
1565 packet_type: constants::PACKET_TYPE_DATA,
1566 };
1567 let mut actions = Vec::new();
1568 if let Ok(pkt) = RawPacket::pack(flags, 0, link_id, None, context, data) {
1569 actions.push(LinkManagerAction::SendPacket {
1570 raw: pkt.raw,
1571 dest_type: constants::DESTINATION_LINK,
1572 attached_interface: None,
1573 });
1574 }
1575 actions
1576 }
1577
1578 pub fn send_resource(
1580 &mut self,
1581 link_id: &LinkId,
1582 data: &[u8],
1583 metadata: Option<&[u8]>,
1584 rng: &mut dyn Rng,
1585 ) -> Vec<LinkManagerAction> {
1586 let link = match self.links.get_mut(link_id) {
1587 Some(l) => l,
1588 None => return Vec::new(),
1589 };
1590
1591 if link.engine.state() != LinkState::Active {
1592 return Vec::new();
1593 }
1594
1595 let link_rtt = link.engine.rtt().unwrap_or(1.0);
1596 let now = time::now();
1597
1598 let enc_rng = std::cell::RefCell::new(rns_crypto::OsRng);
1601 let encrypt_fn = |plaintext: &[u8]| -> Vec<u8> {
1602 link.engine.encrypt(plaintext, &mut *enc_rng.borrow_mut()).unwrap_or_else(|_| plaintext.to_vec())
1603 };
1604
1605 let sender = match ResourceSender::new(
1606 data,
1607 metadata,
1608 constants::RESOURCE_SDU,
1609 &encrypt_fn,
1610 &Bzip2Compressor,
1611 rng,
1612 now,
1613 true, false, None, 1, 1, None, link_rtt,
1620 6.0, ) {
1622 Ok(s) => s,
1623 Err(e) => {
1624 log::debug!("Failed to create ResourceSender: {}", e);
1625 return Vec::new();
1626 }
1627 };
1628
1629 let mut sender = sender;
1630 let adv_actions = sender.advertise(now);
1631 link.outgoing_resources.push(sender);
1632
1633 let _ = link;
1634 self.process_resource_actions(link_id, adv_actions, rng)
1635 }
1636
1637 pub fn set_resource_strategy(&mut self, link_id: &LinkId, strategy: ResourceStrategy) {
1639 if let Some(link) = self.links.get_mut(link_id) {
1640 link.resource_strategy = strategy;
1641 }
1642 }
1643
1644 pub fn flush_channel_tx(&mut self, link_id: &LinkId) {
1647 if let Some(link) = self.links.get_mut(link_id) {
1648 if let Some(ref mut channel) = link.channel {
1649 channel.flush_tx();
1650 }
1651 }
1652 }
1653
1654 pub fn send_channel_message(
1656 &mut self,
1657 link_id: &LinkId,
1658 msgtype: u16,
1659 payload: &[u8],
1660 rng: &mut dyn Rng,
1661 ) -> Vec<LinkManagerAction> {
1662 let link = match self.links.get_mut(link_id) {
1663 Some(l) => l,
1664 None => return Vec::new(),
1665 };
1666
1667 let channel = match link.channel {
1668 Some(ref mut ch) => ch,
1669 None => return Vec::new(),
1670 };
1671
1672 let link_mdu = constants::MDU; let now = time::now();
1674 let chan_actions = match channel.send(msgtype, payload, now, link_mdu) {
1675 Ok(a) => a,
1676 Err(e) => {
1677 log::debug!("Channel send failed: {:?}", e);
1678 return Vec::new();
1679 }
1680 };
1681
1682 let _ = link;
1683 self.process_channel_actions(link_id, chan_actions, rng)
1684 }
1685
1686 pub fn tick(&mut self, rng: &mut dyn Rng) -> Vec<LinkManagerAction> {
1688 let now = time::now();
1689 let mut all_actions = Vec::new();
1690
1691 let link_ids: Vec<LinkId> = self.links.keys().copied().collect();
1693
1694 for link_id in &link_ids {
1695 let link = match self.links.get_mut(link_id) {
1696 Some(l) => l,
1697 None => continue,
1698 };
1699
1700 let tick_actions = link.engine.tick(now);
1702 all_actions.extend(self.process_link_actions(link_id, &tick_actions));
1703
1704 let link = match self.links.get_mut(link_id) {
1706 Some(l) => l,
1707 None => continue,
1708 };
1709 if link.engine.needs_keepalive(now) {
1710 let flags = PacketFlags {
1712 header_type: constants::HEADER_1,
1713 context_flag: constants::FLAG_UNSET,
1714 transport_type: constants::TRANSPORT_BROADCAST,
1715 destination_type: constants::DESTINATION_LINK,
1716 packet_type: constants::PACKET_TYPE_DATA,
1717 };
1718 if let Ok(pkt) = RawPacket::pack(
1719 flags, 0, link_id, None, constants::CONTEXT_KEEPALIVE, &[],
1720 ) {
1721 all_actions.push(LinkManagerAction::SendPacket {
1722 raw: pkt.raw,
1723 dest_type: constants::DESTINATION_LINK,
1724 attached_interface: None,
1725 });
1726 link.engine.record_outbound(now, true);
1727 }
1728 }
1729 }
1730
1731 for link_id in &link_ids {
1733 let link = match self.links.get_mut(link_id) {
1734 Some(l) => l,
1735 None => continue,
1736 };
1737
1738 let mut sender_actions = Vec::new();
1740 for sender in &mut link.outgoing_resources {
1741 sender_actions.extend(sender.tick(now));
1742 }
1743
1744 let mut receiver_actions = Vec::new();
1746 for receiver in &mut link.incoming_resources {
1747 let decrypt_fn = |ciphertext: &[u8]| -> Result<Vec<u8>, ()> {
1748 link.engine.decrypt(ciphertext).map_err(|_| ())
1749 };
1750 receiver_actions.extend(receiver.tick(now, &decrypt_fn, &Bzip2Compressor));
1751 }
1752
1753 link.outgoing_resources.retain(|s| {
1755 s.status < rns_core::resource::ResourceStatus::Complete
1756 });
1757 link.incoming_resources.retain(|r| {
1758 r.status < rns_core::resource::ResourceStatus::Assembling
1759 });
1760
1761 let _ = link;
1762 all_actions.extend(self.process_resource_actions(link_id, sender_actions, rng));
1763 all_actions.extend(self.process_resource_actions(link_id, receiver_actions, rng));
1764 }
1765
1766 let closed: Vec<LinkId> = self.links.iter()
1768 .filter(|(_, l)| l.engine.state() == LinkState::Closed)
1769 .map(|(id, _)| *id)
1770 .collect();
1771 for id in closed {
1772 self.links.remove(&id);
1773 all_actions.push(LinkManagerAction::DeregisterLinkDest { link_id: id });
1774 }
1775
1776 all_actions
1777 }
1778
1779 pub fn is_link_destination(&self, dest_hash: &[u8; 16]) -> bool {
1781 self.links.contains_key(dest_hash) || self.link_destinations.contains_key(dest_hash)
1782 }
1783
1784 pub fn link_state(&self, link_id: &LinkId) -> Option<LinkState> {
1786 self.links.get(link_id).map(|l| l.engine.state())
1787 }
1788
1789 pub fn link_rtt(&self, link_id: &LinkId) -> Option<f64> {
1791 self.links.get(link_id).and_then(|l| l.engine.rtt())
1792 }
1793
1794 pub fn set_link_rtt(&mut self, link_id: &LinkId, rtt: f64) {
1796 if let Some(link) = self.links.get_mut(link_id) {
1797 link.engine.set_rtt(rtt);
1798 }
1799 }
1800
1801 pub fn record_link_inbound(&mut self, link_id: &LinkId) {
1803 if let Some(link) = self.links.get_mut(link_id) {
1804 link.engine.record_inbound(time::now());
1805 }
1806 }
1807
1808 pub fn set_link_mtu(&mut self, link_id: &LinkId, mtu: u32) {
1810 if let Some(link) = self.links.get_mut(link_id) {
1811 link.engine.set_mtu(mtu);
1812 }
1813 }
1814
1815 pub fn link_count(&self) -> usize {
1817 self.links.len()
1818 }
1819
1820 pub fn link_entries(&self) -> Vec<crate::event::LinkInfoEntry> {
1822 self.links
1823 .iter()
1824 .map(|(link_id, managed)| {
1825 let state = match managed.engine.state() {
1826 LinkState::Pending => "pending",
1827 LinkState::Handshake => "handshake",
1828 LinkState::Active => "active",
1829 LinkState::Stale => "stale",
1830 LinkState::Closed => "closed",
1831 };
1832 crate::event::LinkInfoEntry {
1833 link_id: *link_id,
1834 state: state.to_string(),
1835 is_initiator: managed.engine.is_initiator(),
1836 dest_hash: managed.dest_hash,
1837 remote_identity: managed.remote_identity.as_ref().map(|(h, _)| *h),
1838 rtt: managed.engine.rtt(),
1839 }
1840 })
1841 .collect()
1842 }
1843
1844 pub fn resource_entries(&self) -> Vec<crate::event::ResourceInfoEntry> {
1846 let mut entries = Vec::new();
1847 for (link_id, managed) in &self.links {
1848 for recv in &managed.incoming_resources {
1849 let (received, total) = recv.progress();
1850 entries.push(crate::event::ResourceInfoEntry {
1851 link_id: *link_id,
1852 direction: "incoming".to_string(),
1853 total_parts: total,
1854 transferred_parts: received,
1855 complete: received >= total && total > 0,
1856 });
1857 }
1858 for send in &managed.outgoing_resources {
1859 let total = send.total_parts();
1860 let sent = send.sent_parts;
1861 entries.push(crate::event::ResourceInfoEntry {
1862 link_id: *link_id,
1863 direction: "outgoing".to_string(),
1864 total_parts: total,
1865 transferred_parts: sent,
1866 complete: sent >= total && total > 0,
1867 });
1868 }
1869 }
1870 entries
1871 }
1872
1873 fn process_link_actions(&self, link_id: &LinkId, actions: &[LinkAction]) -> Vec<LinkManagerAction> {
1875 let mut result = Vec::new();
1876 for action in actions {
1877 match action {
1878 LinkAction::StateChanged { new_state, reason, .. } => {
1879 match new_state {
1880 LinkState::Closed => {
1881 result.push(LinkManagerAction::LinkClosed {
1882 link_id: *link_id,
1883 reason: *reason,
1884 });
1885 }
1886 _ => {}
1887 }
1888 }
1889 LinkAction::LinkEstablished { rtt, is_initiator, .. } => {
1890 let dest_hash = self.links.get(link_id)
1891 .map(|l| l.dest_hash)
1892 .unwrap_or([0u8; 16]);
1893 result.push(LinkManagerAction::LinkEstablished {
1894 link_id: *link_id,
1895 dest_hash,
1896 rtt: *rtt,
1897 is_initiator: *is_initiator,
1898 });
1899 }
1900 LinkAction::RemoteIdentified { identity_hash, public_key, .. } => {
1901 result.push(LinkManagerAction::RemoteIdentified {
1902 link_id: *link_id,
1903 identity_hash: *identity_hash,
1904 public_key: *public_key,
1905 });
1906 }
1907 LinkAction::DataReceived { .. } => {
1908 }
1910 }
1911 }
1912 result
1913 }
1914
1915 fn process_channel_actions(
1917 &self,
1918 link_id: &LinkId,
1919 actions: Vec<rns_core::channel::ChannelAction>,
1920 rng: &mut dyn Rng,
1921 ) -> Vec<LinkManagerAction> {
1922 let mut result = Vec::new();
1923 for action in actions {
1924 match action {
1925 rns_core::channel::ChannelAction::SendOnLink { raw } => {
1926 if let Some(link) = self.links.get(link_id) {
1928 if let Ok(encrypted) = link.engine.encrypt(&raw, rng) {
1929 let flags = PacketFlags {
1930 header_type: constants::HEADER_1,
1931 context_flag: constants::FLAG_UNSET,
1932 transport_type: constants::TRANSPORT_BROADCAST,
1933 destination_type: constants::DESTINATION_LINK,
1934 packet_type: constants::PACKET_TYPE_DATA,
1935 };
1936 if let Ok(pkt) = RawPacket::pack(
1937 flags, 0, link_id, None, constants::CONTEXT_CHANNEL, &encrypted,
1938 ) {
1939 result.push(LinkManagerAction::SendPacket {
1940 raw: pkt.raw,
1941 dest_type: constants::DESTINATION_LINK,
1942 attached_interface: None,
1943 });
1944 }
1945 }
1946 }
1947 }
1948 rns_core::channel::ChannelAction::MessageReceived { msgtype, payload, .. } => {
1949 result.push(LinkManagerAction::ChannelMessageReceived {
1950 link_id: *link_id,
1951 msgtype,
1952 payload,
1953 });
1954 }
1955 rns_core::channel::ChannelAction::TeardownLink => {
1956 result.push(LinkManagerAction::LinkClosed {
1957 link_id: *link_id,
1958 reason: Some(TeardownReason::Timeout),
1959 });
1960 }
1961 }
1962 }
1963 result
1964 }
1965}
1966
1967fn compute_path_hash(path: &str) -> [u8; 16] {
1970 let full = rns_core::hash::full_hash(path.as_bytes());
1971 let mut result = [0u8; 16];
1972 result.copy_from_slice(&full[..16]);
1973 result
1974}
1975
1976#[cfg(test)]
1977mod tests {
1978 use super::*;
1979 use rns_crypto::identity::Identity;
1980 use rns_crypto::{FixedRng, OsRng};
1981
1982 fn make_rng(seed: u8) -> FixedRng {
1983 FixedRng::new(&[seed; 128])
1984 }
1985
1986 fn make_dest_keys(rng: &mut dyn Rng) -> (Ed25519PrivateKey, [u8; 32]) {
1987 let sig_prv = Ed25519PrivateKey::generate(rng);
1988 let sig_pub_bytes = sig_prv.public_key().public_bytes();
1989 (sig_prv, sig_pub_bytes)
1990 }
1991
1992 #[test]
1993 fn test_register_link_destination() {
1994 let mut mgr = LinkManager::new();
1995 let mut rng = make_rng(0x01);
1996 let (sig_prv, sig_pub_bytes) = make_dest_keys(&mut rng);
1997 let dest_hash = [0xDD; 16];
1998
1999 mgr.register_link_destination(dest_hash, sig_prv, sig_pub_bytes, ResourceStrategy::AcceptNone);
2000 assert!(mgr.is_link_destination(&dest_hash));
2001
2002 mgr.deregister_link_destination(&dest_hash);
2003 assert!(!mgr.is_link_destination(&dest_hash));
2004 }
2005
2006 #[test]
2007 fn test_create_link() {
2008 let mut mgr = LinkManager::new();
2009 let mut rng = OsRng;
2010 let dest_hash = [0xDD; 16];
2011
2012 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);
2014 assert_ne!(link_id, [0u8; 16]);
2015 assert_eq!(actions.len(), 2);
2017 assert!(matches!(actions[0], LinkManagerAction::RegisterLinkDest { .. }));
2018 assert!(matches!(actions[1], LinkManagerAction::SendPacket { .. }));
2019
2020 assert_eq!(mgr.link_state(&link_id), Some(LinkState::Pending));
2022 }
2023
2024 #[test]
2025 fn test_full_handshake_via_manager() {
2026 let mut rng = OsRng;
2027 let dest_hash = [0xDD; 16];
2028
2029 let mut responder_mgr = LinkManager::new();
2031 let (sig_prv, sig_pub_bytes) = make_dest_keys(&mut rng);
2032 responder_mgr.register_link_destination(dest_hash, sig_prv, sig_pub_bytes, ResourceStrategy::AcceptNone);
2033
2034 let mut initiator_mgr = LinkManager::new();
2036
2037 let (link_id, init_actions) = initiator_mgr.create_link(&dest_hash, &sig_pub_bytes, 1, constants::MTU as u32, &mut rng);
2039 assert_eq!(init_actions.len(), 2);
2040
2041 let linkrequest_raw = match &init_actions[1] {
2043 LinkManagerAction::SendPacket { raw, .. } => raw.clone(),
2044 _ => panic!("Expected SendPacket"),
2045 };
2046
2047 let lr_packet = RawPacket::unpack(&linkrequest_raw).unwrap();
2049
2050 let resp_actions = responder_mgr.handle_local_delivery(
2052 lr_packet.destination_hash,
2053 &linkrequest_raw,
2054 lr_packet.packet_hash,
2055 rns_core::transport::types::InterfaceId(0),
2056 &mut rng,
2057 );
2058 assert!(resp_actions.len() >= 2);
2060 assert!(matches!(resp_actions[0], LinkManagerAction::RegisterLinkDest { .. }));
2061
2062 let lrproof_raw = match &resp_actions[1] {
2064 LinkManagerAction::SendPacket { raw, .. } => raw.clone(),
2065 _ => panic!("Expected SendPacket for LRPROOF"),
2066 };
2067
2068 let lrproof_packet = RawPacket::unpack(&lrproof_raw).unwrap();
2070 let init_actions2 = initiator_mgr.handle_local_delivery(
2071 lrproof_packet.destination_hash,
2072 &lrproof_raw,
2073 lrproof_packet.packet_hash,
2074 rns_core::transport::types::InterfaceId(0),
2075 &mut rng,
2076 );
2077
2078 let has_established = init_actions2.iter().any(|a| matches!(a, LinkManagerAction::LinkEstablished { .. }));
2080 assert!(has_established, "Initiator should emit LinkEstablished");
2081
2082 let lrrtt_raw = init_actions2.iter().find_map(|a| match a {
2084 LinkManagerAction::SendPacket { raw, .. } => Some(raw.clone()),
2085 _ => None,
2086 }).expect("Should have LRRTT SendPacket");
2087
2088 let lrrtt_packet = RawPacket::unpack(&lrrtt_raw).unwrap();
2090 let resp_link_id = lrrtt_packet.destination_hash;
2091 let resp_actions2 = responder_mgr.handle_local_delivery(
2092 resp_link_id,
2093 &lrrtt_raw,
2094 lrrtt_packet.packet_hash,
2095 rns_core::transport::types::InterfaceId(0),
2096 &mut rng,
2097 );
2098
2099 let has_established = resp_actions2.iter().any(|a| matches!(a, LinkManagerAction::LinkEstablished { .. }));
2100 assert!(has_established, "Responder should emit LinkEstablished");
2101
2102 assert_eq!(initiator_mgr.link_state(&link_id), Some(LinkState::Active));
2104 assert_eq!(responder_mgr.link_state(&link_id), Some(LinkState::Active));
2105
2106 assert!(initiator_mgr.link_rtt(&link_id).is_some());
2108 assert!(responder_mgr.link_rtt(&link_id).is_some());
2109 }
2110
2111 #[test]
2112 fn test_encrypted_data_exchange() {
2113 let mut rng = OsRng;
2114 let dest_hash = [0xDD; 16];
2115 let mut resp_mgr = LinkManager::new();
2116 let (sig_prv, sig_pub_bytes) = make_dest_keys(&mut rng);
2117 resp_mgr.register_link_destination(dest_hash, sig_prv, sig_pub_bytes, ResourceStrategy::AcceptNone);
2118 let mut init_mgr = LinkManager::new();
2119
2120 let (link_id, init_actions) = init_mgr.create_link(&dest_hash, &sig_pub_bytes, 1, constants::MTU as u32, &mut rng);
2122 let lr_raw = extract_send_packet(&init_actions);
2123 let lr_pkt = RawPacket::unpack(&lr_raw).unwrap();
2124 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);
2125 let lrproof_raw = extract_send_packet_at(&resp_actions, 1);
2126 let lrproof_pkt = RawPacket::unpack(&lrproof_raw).unwrap();
2127 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);
2128 let lrrtt_raw = extract_any_send_packet(&init_actions2);
2129 let lrrtt_pkt = RawPacket::unpack(&lrrtt_raw).unwrap();
2130 resp_mgr.handle_local_delivery(lrrtt_pkt.destination_hash, &lrrtt_raw, lrrtt_pkt.packet_hash, rns_core::transport::types::InterfaceId(0), &mut rng);
2131
2132 let actions = init_mgr.send_on_link(&link_id, b"hello link!", constants::CONTEXT_NONE, &mut rng);
2134 assert_eq!(actions.len(), 1);
2135 assert!(matches!(actions[0], LinkManagerAction::SendPacket { .. }));
2136 }
2137
2138 #[test]
2139 fn test_request_response() {
2140 let mut rng = OsRng;
2141 let dest_hash = [0xDD; 16];
2142 let mut resp_mgr = LinkManager::new();
2143 let (sig_prv, sig_pub_bytes) = make_dest_keys(&mut rng);
2144 resp_mgr.register_link_destination(dest_hash, sig_prv, sig_pub_bytes, ResourceStrategy::AcceptNone);
2145
2146 resp_mgr.register_request_handler("/status", None, |_link_id, _path, _data, _remote| {
2148 Some(b"OK".to_vec())
2149 });
2150
2151 let mut init_mgr = LinkManager::new();
2152
2153 let (link_id, init_actions) = init_mgr.create_link(&dest_hash, &sig_pub_bytes, 1, constants::MTU as u32, &mut rng);
2155 let lr_raw = extract_send_packet(&init_actions);
2156 let lr_pkt = RawPacket::unpack(&lr_raw).unwrap();
2157 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);
2158 let lrproof_raw = extract_send_packet_at(&resp_actions, 1);
2159 let lrproof_pkt = RawPacket::unpack(&lrproof_raw).unwrap();
2160 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);
2161 let lrrtt_raw = extract_any_send_packet(&init_actions2);
2162 let lrrtt_pkt = RawPacket::unpack(&lrrtt_raw).unwrap();
2163 resp_mgr.handle_local_delivery(lrrtt_pkt.destination_hash, &lrrtt_raw, lrrtt_pkt.packet_hash, rns_core::transport::types::InterfaceId(0), &mut rng);
2164
2165 let req_actions = init_mgr.send_request(&link_id, "/status", b"query", &mut rng);
2167 assert_eq!(req_actions.len(), 1);
2168
2169 let req_raw = extract_send_packet_from(&req_actions);
2171 let req_pkt = RawPacket::unpack(&req_raw).unwrap();
2172 let resp_actions = resp_mgr.handle_local_delivery(
2173 req_pkt.destination_hash, &req_raw, req_pkt.packet_hash, rns_core::transport::types::InterfaceId(0), &mut rng,
2174 );
2175
2176 let has_response = resp_actions.iter().any(|a| matches!(a, LinkManagerAction::SendPacket { .. }));
2178 assert!(has_response, "Handler should produce a response packet");
2179 }
2180
2181 #[test]
2182 fn test_request_acl_deny_unidentified() {
2183 let mut rng = OsRng;
2184 let dest_hash = [0xDD; 16];
2185 let mut resp_mgr = LinkManager::new();
2186 let (sig_prv, sig_pub_bytes) = make_dest_keys(&mut rng);
2187 resp_mgr.register_link_destination(dest_hash, sig_prv, sig_pub_bytes, ResourceStrategy::AcceptNone);
2188
2189 resp_mgr.register_request_handler(
2191 "/restricted",
2192 Some(vec![[0xAA; 16]]),
2193 |_link_id, _path, _data, _remote| Some(b"secret".to_vec()),
2194 );
2195
2196 let mut init_mgr = LinkManager::new();
2197
2198 let (link_id, init_actions) = init_mgr.create_link(&dest_hash, &sig_pub_bytes, 1, constants::MTU as u32, &mut rng);
2200 let lr_raw = extract_send_packet(&init_actions);
2201 let lr_pkt = RawPacket::unpack(&lr_raw).unwrap();
2202 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);
2203 let lrproof_raw = extract_send_packet_at(&resp_actions, 1);
2204 let lrproof_pkt = RawPacket::unpack(&lrproof_raw).unwrap();
2205 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);
2206 let lrrtt_raw = extract_any_send_packet(&init_actions2);
2207 let lrrtt_pkt = RawPacket::unpack(&lrrtt_raw).unwrap();
2208 resp_mgr.handle_local_delivery(lrrtt_pkt.destination_hash, &lrrtt_raw, lrrtt_pkt.packet_hash, rns_core::transport::types::InterfaceId(0), &mut rng);
2209
2210 let req_actions = init_mgr.send_request(&link_id, "/restricted", b"query", &mut rng);
2212 let req_raw = extract_send_packet_from(&req_actions);
2213 let req_pkt = RawPacket::unpack(&req_raw).unwrap();
2214 let resp_actions = resp_mgr.handle_local_delivery(
2215 req_pkt.destination_hash, &req_raw, req_pkt.packet_hash, rns_core::transport::types::InterfaceId(0), &mut rng,
2216 );
2217
2218 let has_response = resp_actions.iter().any(|a| matches!(a, LinkManagerAction::SendPacket { .. }));
2220 assert!(!has_response, "Unidentified peer should be denied");
2221 }
2222
2223 #[test]
2224 fn test_teardown_link() {
2225 let mut rng = OsRng;
2226 let dest_hash = [0xDD; 16];
2227 let mut mgr = LinkManager::new();
2228
2229 let dummy_sig = [0xAA; 32];
2230 let (link_id, _) = mgr.create_link(&dest_hash, &dummy_sig, 1, constants::MTU as u32, &mut rng);
2231 assert_eq!(mgr.link_count(), 1);
2232
2233 let actions = mgr.teardown_link(&link_id);
2234 let has_close = actions.iter().any(|a| matches!(a, LinkManagerAction::LinkClosed { .. }));
2235 assert!(has_close);
2236
2237 let tick_actions = mgr.tick(&mut rng);
2239 let has_deregister = tick_actions.iter().any(|a| matches!(a, LinkManagerAction::DeregisterLinkDest { .. }));
2240 assert!(has_deregister);
2241 assert_eq!(mgr.link_count(), 0);
2242 }
2243
2244 #[test]
2245 fn test_identify_on_link() {
2246 let mut rng = OsRng;
2247 let dest_hash = [0xDD; 16];
2248 let mut resp_mgr = LinkManager::new();
2249 let (sig_prv, sig_pub_bytes) = make_dest_keys(&mut rng);
2250 resp_mgr.register_link_destination(dest_hash, sig_prv, sig_pub_bytes, ResourceStrategy::AcceptNone);
2251 let mut init_mgr = LinkManager::new();
2252
2253 let (link_id, init_actions) = init_mgr.create_link(&dest_hash, &sig_pub_bytes, 1, constants::MTU as u32, &mut rng);
2255 let lr_raw = extract_send_packet(&init_actions);
2256 let lr_pkt = RawPacket::unpack(&lr_raw).unwrap();
2257 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);
2258 let lrproof_raw = extract_send_packet_at(&resp_actions, 1);
2259 let lrproof_pkt = RawPacket::unpack(&lrproof_raw).unwrap();
2260 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);
2261 let lrrtt_raw = extract_any_send_packet(&init_actions2);
2262 let lrrtt_pkt = RawPacket::unpack(&lrrtt_raw).unwrap();
2263 resp_mgr.handle_local_delivery(lrrtt_pkt.destination_hash, &lrrtt_raw, lrrtt_pkt.packet_hash, rns_core::transport::types::InterfaceId(0), &mut rng);
2264
2265 let identity = Identity::new(&mut rng);
2267 let id_actions = init_mgr.identify(&link_id, &identity, &mut rng);
2268 assert_eq!(id_actions.len(), 1);
2269
2270 let id_raw = extract_send_packet_from(&id_actions);
2272 let id_pkt = RawPacket::unpack(&id_raw).unwrap();
2273 let resp_actions = resp_mgr.handle_local_delivery(
2274 id_pkt.destination_hash, &id_raw, id_pkt.packet_hash, rns_core::transport::types::InterfaceId(0), &mut rng,
2275 );
2276
2277 let has_identified = resp_actions.iter().any(|a| matches!(a, LinkManagerAction::RemoteIdentified { .. }));
2278 assert!(has_identified, "Responder should emit RemoteIdentified");
2279 }
2280
2281 #[test]
2282 fn test_path_hash_computation() {
2283 let h1 = compute_path_hash("/status");
2284 let h2 = compute_path_hash("/path");
2285 assert_ne!(h1, h2);
2286
2287 assert_eq!(h1, compute_path_hash("/status"));
2289 }
2290
2291 #[test]
2292 fn test_link_count() {
2293 let mut mgr = LinkManager::new();
2294 let mut rng = OsRng;
2295
2296 assert_eq!(mgr.link_count(), 0);
2297
2298 let dummy_sig = [0xAA; 32];
2299 mgr.create_link(&[0x11; 16], &dummy_sig, 1, constants::MTU as u32, &mut rng);
2300 assert_eq!(mgr.link_count(), 1);
2301
2302 mgr.create_link(&[0x22; 16], &dummy_sig, 1, constants::MTU as u32, &mut rng);
2303 assert_eq!(mgr.link_count(), 2);
2304 }
2305
2306 fn extract_send_packet(actions: &[LinkManagerAction]) -> Vec<u8> {
2309 extract_send_packet_at(actions, actions.len() - 1)
2310 }
2311
2312 fn extract_send_packet_at(actions: &[LinkManagerAction], idx: usize) -> Vec<u8> {
2313 match &actions[idx] {
2314 LinkManagerAction::SendPacket { raw, .. } => raw.clone(),
2315 other => panic!("Expected SendPacket at index {}, got {:?}", idx, other),
2316 }
2317 }
2318
2319 fn extract_any_send_packet(actions: &[LinkManagerAction]) -> Vec<u8> {
2320 actions.iter().find_map(|a| match a {
2321 LinkManagerAction::SendPacket { raw, .. } => Some(raw.clone()),
2322 _ => None,
2323 }).expect("Expected at least one SendPacket action")
2324 }
2325
2326 fn extract_send_packet_from(actions: &[LinkManagerAction]) -> Vec<u8> {
2327 extract_any_send_packet(actions)
2328 }
2329
2330 fn setup_active_link() -> (LinkManager, LinkManager, LinkId) {
2333 let mut rng = OsRng;
2334 let dest_hash = [0xDD; 16];
2335 let mut resp_mgr = LinkManager::new();
2336 let (sig_prv, sig_pub_bytes) = make_dest_keys(&mut rng);
2337 resp_mgr.register_link_destination(dest_hash, sig_prv, sig_pub_bytes, ResourceStrategy::AcceptNone);
2338 let mut init_mgr = LinkManager::new();
2339
2340 let (link_id, init_actions) = init_mgr.create_link(&dest_hash, &sig_pub_bytes, 1, constants::MTU as u32, &mut rng);
2341 let lr_raw = extract_send_packet(&init_actions);
2342 let lr_pkt = RawPacket::unpack(&lr_raw).unwrap();
2343 let resp_actions = resp_mgr.handle_local_delivery(
2344 lr_pkt.destination_hash, &lr_raw, lr_pkt.packet_hash, rns_core::transport::types::InterfaceId(0), &mut rng,
2345 );
2346 let lrproof_raw = extract_send_packet_at(&resp_actions, 1);
2347 let lrproof_pkt = RawPacket::unpack(&lrproof_raw).unwrap();
2348 let init_actions2 = init_mgr.handle_local_delivery(
2349 lrproof_pkt.destination_hash, &lrproof_raw, lrproof_pkt.packet_hash, rns_core::transport::types::InterfaceId(0), &mut rng,
2350 );
2351 let lrrtt_raw = extract_any_send_packet(&init_actions2);
2352 let lrrtt_pkt = RawPacket::unpack(&lrrtt_raw).unwrap();
2353 resp_mgr.handle_local_delivery(
2354 lrrtt_pkt.destination_hash, &lrrtt_raw, lrrtt_pkt.packet_hash, rns_core::transport::types::InterfaceId(0), &mut rng,
2355 );
2356
2357 assert_eq!(init_mgr.link_state(&link_id), Some(LinkState::Active));
2358 assert_eq!(resp_mgr.link_state(&link_id), Some(LinkState::Active));
2359
2360 (init_mgr, resp_mgr, link_id)
2361 }
2362
2363 #[test]
2368 fn test_resource_strategy_default() {
2369 let mut mgr = LinkManager::new();
2370 let mut rng = OsRng;
2371 let dummy_sig = [0xAA; 32];
2372 let (link_id, _) = mgr.create_link(&[0x11; 16], &dummy_sig, 1, constants::MTU as u32, &mut rng);
2373
2374 let link = mgr.links.get(&link_id).unwrap();
2376 assert_eq!(link.resource_strategy, ResourceStrategy::AcceptNone);
2377 }
2378
2379 #[test]
2380 fn test_set_resource_strategy() {
2381 let mut mgr = LinkManager::new();
2382 let mut rng = OsRng;
2383 let dummy_sig = [0xAA; 32];
2384 let (link_id, _) = mgr.create_link(&[0x11; 16], &dummy_sig, 1, constants::MTU as u32, &mut rng);
2385
2386 mgr.set_resource_strategy(&link_id, ResourceStrategy::AcceptAll);
2387 assert_eq!(mgr.links.get(&link_id).unwrap().resource_strategy, ResourceStrategy::AcceptAll);
2388
2389 mgr.set_resource_strategy(&link_id, ResourceStrategy::AcceptApp);
2390 assert_eq!(mgr.links.get(&link_id).unwrap().resource_strategy, ResourceStrategy::AcceptApp);
2391 }
2392
2393 #[test]
2394 fn test_send_resource_on_active_link() {
2395 let (mut init_mgr, _resp_mgr, link_id) = setup_active_link();
2396 let mut rng = OsRng;
2397
2398 let data = vec![0xAB; 100]; let actions = init_mgr.send_resource(&link_id, &data, None, &mut rng);
2401
2402 let has_send = actions.iter().any(|a| matches!(a, LinkManagerAction::SendPacket { .. }));
2404 assert!(has_send, "send_resource should emit advertisement SendPacket");
2405 }
2406
2407 #[test]
2408 fn test_send_resource_on_inactive_link() {
2409 let mut mgr = LinkManager::new();
2410 let mut rng = OsRng;
2411 let dummy_sig = [0xAA; 32];
2412 let (link_id, _) = mgr.create_link(&[0x11; 16], &dummy_sig, 1, constants::MTU as u32, &mut rng);
2413
2414 let actions = mgr.send_resource(&link_id, b"data", None, &mut rng);
2416 assert!(actions.is_empty(), "Cannot send resource on inactive link");
2417 }
2418
2419 #[test]
2420 fn test_resource_adv_rejected_by_accept_none() {
2421 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
2422 let mut rng = OsRng;
2423
2424 let data = vec![0xCD; 100];
2427 let adv_actions = init_mgr.send_resource(&link_id, &data, None, &mut rng);
2428
2429 for action in &adv_actions {
2431 if let LinkManagerAction::SendPacket { raw, .. } = action {
2432 let pkt = RawPacket::unpack(raw).unwrap();
2433 let resp_actions = resp_mgr.handle_local_delivery(
2434 pkt.destination_hash, raw, pkt.packet_hash, rns_core::transport::types::InterfaceId(0), &mut rng,
2435 );
2436 let has_resource_received = resp_actions.iter().any(|a|
2438 matches!(a, LinkManagerAction::ResourceReceived { .. })
2439 );
2440 assert!(!has_resource_received, "AcceptNone should not accept resource");
2441 }
2442 }
2443 }
2444
2445 #[test]
2446 fn test_resource_adv_accepted_by_accept_all() {
2447 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
2448 let mut rng = OsRng;
2449
2450 resp_mgr.set_resource_strategy(&link_id, ResourceStrategy::AcceptAll);
2452
2453 let data = vec![0xCD; 100];
2455 let adv_actions = init_mgr.send_resource(&link_id, &data, None, &mut rng);
2456
2457 for action in &adv_actions {
2459 if let LinkManagerAction::SendPacket { raw, .. } = action {
2460 let pkt = RawPacket::unpack(raw).unwrap();
2461 let resp_actions = resp_mgr.handle_local_delivery(
2462 pkt.destination_hash, raw, pkt.packet_hash, rns_core::transport::types::InterfaceId(0), &mut rng,
2463 );
2464 let has_send = resp_actions.iter().any(|a|
2466 matches!(a, LinkManagerAction::SendPacket { .. })
2467 );
2468 assert!(has_send, "AcceptAll should accept and request parts");
2469 }
2470 }
2471 }
2472
2473 #[test]
2474 fn test_resource_accept_app_query() {
2475 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
2476 let mut rng = OsRng;
2477
2478 resp_mgr.set_resource_strategy(&link_id, ResourceStrategy::AcceptApp);
2480
2481 let data = vec![0xCD; 100];
2483 let adv_actions = init_mgr.send_resource(&link_id, &data, None, &mut rng);
2484
2485 let mut got_query = false;
2487 for action in &adv_actions {
2488 if let LinkManagerAction::SendPacket { raw, .. } = action {
2489 let pkt = RawPacket::unpack(raw).unwrap();
2490 let resp_actions = resp_mgr.handle_local_delivery(
2491 pkt.destination_hash, raw, pkt.packet_hash, rns_core::transport::types::InterfaceId(0), &mut rng,
2492 );
2493 for a in &resp_actions {
2494 if matches!(a, LinkManagerAction::ResourceAcceptQuery { .. }) {
2495 got_query = true;
2496 }
2497 }
2498 }
2499 }
2500 assert!(got_query, "AcceptApp should emit ResourceAcceptQuery");
2501 }
2502
2503 #[test]
2504 fn test_resource_accept_app_accept() {
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 accept_actions = resp_mgr.accept_resource(lid, resource_hash, true, &mut rng);
2523 let has_send = accept_actions.iter().any(|a|
2525 matches!(a, LinkManagerAction::SendPacket { .. })
2526 );
2527 assert!(has_send, "Accepting resource should produce request for parts");
2528 }
2529 }
2530 }
2531 }
2532 }
2533
2534 #[test]
2535 fn test_resource_accept_app_reject() {
2536 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
2537 let mut rng = OsRng;
2538
2539 resp_mgr.set_resource_strategy(&link_id, ResourceStrategy::AcceptApp);
2540
2541 let data = vec![0xCD; 100];
2542 let adv_actions = init_mgr.send_resource(&link_id, &data, None, &mut rng);
2543
2544 for action in &adv_actions {
2545 if let LinkManagerAction::SendPacket { raw, .. } = action {
2546 let pkt = RawPacket::unpack(raw).unwrap();
2547 let resp_actions = resp_mgr.handle_local_delivery(
2548 pkt.destination_hash, raw, pkt.packet_hash, rns_core::transport::types::InterfaceId(0), &mut rng,
2549 );
2550 for a in &resp_actions {
2551 if let LinkManagerAction::ResourceAcceptQuery { link_id: lid, resource_hash, .. } = a {
2552 let reject_actions = resp_mgr.accept_resource(lid, resource_hash, false, &mut rng);
2554 let has_resource_received = reject_actions.iter().any(|a|
2557 matches!(a, LinkManagerAction::ResourceReceived { .. })
2558 );
2559 assert!(!has_resource_received);
2560 }
2561 }
2562 }
2563 }
2564 }
2565
2566 #[test]
2567 fn test_resource_full_transfer() {
2568 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
2569 let mut rng = OsRng;
2570
2571 resp_mgr.set_resource_strategy(&link_id, ResourceStrategy::AcceptAll);
2573
2574 let original_data = b"Hello, Resource Transfer!".to_vec();
2576 let adv_actions = init_mgr.send_resource(&link_id, &original_data, None, &mut rng);
2577
2578 let mut pending: Vec<(char, LinkManagerAction)> = adv_actions.into_iter()
2581 .map(|a| ('i', a))
2582 .collect();
2583 let mut rounds = 0;
2584 let max_rounds = 50;
2585 let mut resource_received = false;
2586 let mut sender_completed = false;
2587
2588 while !pending.is_empty() && rounds < max_rounds {
2589 rounds += 1;
2590 let mut next: Vec<(char, LinkManagerAction)> = Vec::new();
2591
2592 for (source, action) in pending.drain(..) {
2593 if let LinkManagerAction::SendPacket { raw, .. } = action {
2594 let pkt = RawPacket::unpack(&raw).unwrap();
2595
2596 let target_actions = if source == 'i' {
2598 resp_mgr.handle_local_delivery(
2599 pkt.destination_hash, &raw, pkt.packet_hash, rns_core::transport::types::InterfaceId(0), &mut rng,
2600 )
2601 } else {
2602 init_mgr.handle_local_delivery(
2603 pkt.destination_hash, &raw, pkt.packet_hash, rns_core::transport::types::InterfaceId(0), &mut rng,
2604 )
2605 };
2606
2607 let target_source = if source == 'i' { 'r' } else { 'i' };
2608 for a in &target_actions {
2609 match a {
2610 LinkManagerAction::ResourceReceived { data, .. } => {
2611 assert_eq!(*data, original_data);
2612 resource_received = true;
2613 }
2614 LinkManagerAction::ResourceCompleted { .. } => {
2615 sender_completed = true;
2616 }
2617 _ => {}
2618 }
2619 }
2620 next.extend(target_actions.into_iter().map(|a| (target_source, a)));
2621 }
2622 }
2623 pending = next;
2624 }
2625
2626 assert!(resource_received, "Responder should receive resource data (rounds={})", rounds);
2627 assert!(sender_completed, "Sender should get completion proof (rounds={})", rounds);
2628 }
2629
2630 #[test]
2631 fn test_resource_cancel_icl() {
2632 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
2633 let mut rng = OsRng;
2634
2635 resp_mgr.set_resource_strategy(&link_id, ResourceStrategy::AcceptAll);
2636
2637 let data = vec![0xAB; 2000];
2639 let adv_actions = init_mgr.send_resource(&link_id, &data, None, &mut rng);
2640
2641 for action in &adv_actions {
2643 if let LinkManagerAction::SendPacket { raw, .. } = action {
2644 let pkt = RawPacket::unpack(raw).unwrap();
2645 resp_mgr.handle_local_delivery(
2646 pkt.destination_hash, raw, pkt.packet_hash, rns_core::transport::types::InterfaceId(0), &mut rng,
2647 );
2648 }
2649 }
2650
2651 assert!(!resp_mgr.links.get(&link_id).unwrap().incoming_resources.is_empty());
2653
2654 let icl_actions = resp_mgr.handle_resource_icl(&link_id);
2656
2657 let has_failed = icl_actions.iter().any(|a| matches!(a, LinkManagerAction::ResourceFailed { .. }));
2659 assert!(has_failed, "ICL should produce ResourceFailed");
2660 }
2661
2662 #[test]
2663 fn test_resource_cancel_rcl() {
2664 let (mut init_mgr, _resp_mgr, link_id) = setup_active_link();
2665 let mut rng = OsRng;
2666
2667 let data = vec![0xAB; 2000];
2669 init_mgr.send_resource(&link_id, &data, None, &mut rng);
2670
2671 assert!(!init_mgr.links.get(&link_id).unwrap().outgoing_resources.is_empty());
2673
2674 let rcl_actions = init_mgr.handle_resource_rcl(&link_id);
2676
2677 let has_failed = rcl_actions.iter().any(|a| matches!(a, LinkManagerAction::ResourceFailed { .. }));
2678 assert!(has_failed, "RCL should produce ResourceFailed");
2679 }
2680
2681 #[test]
2682 fn test_resource_tick_cleans_up() {
2683 let (mut init_mgr, _resp_mgr, link_id) = setup_active_link();
2684 let mut rng = OsRng;
2685
2686 let data = vec![0xAB; 100];
2687 init_mgr.send_resource(&link_id, &data, None, &mut rng);
2688
2689 assert!(!init_mgr.links.get(&link_id).unwrap().outgoing_resources.is_empty());
2690
2691 init_mgr.handle_resource_rcl(&link_id);
2693
2694 init_mgr.tick(&mut rng);
2696
2697 assert!(init_mgr.links.get(&link_id).unwrap().outgoing_resources.is_empty(),
2698 "Tick should clean up completed/failed outgoing resources");
2699 }
2700
2701 #[test]
2702 fn test_build_link_packet() {
2703 let (init_mgr, _resp_mgr, link_id) = setup_active_link();
2704
2705 let actions = init_mgr.build_link_packet(&link_id, constants::CONTEXT_RESOURCE, b"test data");
2706 assert_eq!(actions.len(), 1);
2707 if let LinkManagerAction::SendPacket { raw, dest_type, .. } = &actions[0] {
2708 let pkt = RawPacket::unpack(raw).unwrap();
2709 assert_eq!(pkt.context, constants::CONTEXT_RESOURCE);
2710 assert_eq!(*dest_type, constants::DESTINATION_LINK);
2711 } else {
2712 panic!("Expected SendPacket");
2713 }
2714 }
2715
2716 #[test]
2721 fn test_channel_message_delivery() {
2722 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
2723 let mut rng = OsRng;
2724
2725 let chan_actions = init_mgr.send_channel_message(&link_id, 42, b"channel data", &mut rng);
2727 assert!(!chan_actions.is_empty());
2728
2729 let mut got_channel_msg = false;
2731 for action in &chan_actions {
2732 if let LinkManagerAction::SendPacket { raw, .. } = action {
2733 let pkt = RawPacket::unpack(raw).unwrap();
2734 let resp_actions = resp_mgr.handle_local_delivery(
2735 pkt.destination_hash, raw, pkt.packet_hash, rns_core::transport::types::InterfaceId(0), &mut rng,
2736 );
2737 for a in &resp_actions {
2738 if let LinkManagerAction::ChannelMessageReceived { msgtype, payload, .. } = a {
2739 assert_eq!(*msgtype, 42);
2740 assert_eq!(*payload, b"channel data");
2741 got_channel_msg = true;
2742 }
2743 }
2744 }
2745 }
2746 assert!(got_channel_msg, "Responder should receive channel message");
2747 }
2748
2749 #[test]
2750 fn test_generic_link_data_delivery() {
2751 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
2752 let mut rng = OsRng;
2753
2754 let actions = init_mgr.send_on_link(&link_id, b"raw stuff", 0x42, &mut rng);
2756 assert_eq!(actions.len(), 1);
2757
2758 let raw = extract_any_send_packet(&actions);
2760 let pkt = RawPacket::unpack(&raw).unwrap();
2761 let resp_actions = resp_mgr.handle_local_delivery(
2762 pkt.destination_hash, &raw, pkt.packet_hash, rns_core::transport::types::InterfaceId(0), &mut rng,
2763 );
2764
2765 let has_data = resp_actions.iter().any(|a|
2766 matches!(a, LinkManagerAction::LinkDataReceived { context: 0x42, .. })
2767 );
2768 assert!(has_data, "Responder should receive LinkDataReceived for unknown context");
2769 }
2770
2771 #[test]
2772 fn test_response_delivery() {
2773 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
2774 let mut rng = OsRng;
2775
2776 resp_mgr.register_request_handler("/echo", None, |_link_id, _path, data, _remote| {
2778 Some(data.to_vec())
2779 });
2780
2781 let req_actions = init_mgr.send_request(&link_id, "/echo", b"\xc0", &mut rng); assert!(!req_actions.is_empty());
2784
2785 let req_raw = extract_any_send_packet(&req_actions);
2787 let req_pkt = RawPacket::unpack(&req_raw).unwrap();
2788 let resp_actions = resp_mgr.handle_local_delivery(
2789 req_pkt.destination_hash, &req_raw, req_pkt.packet_hash, rns_core::transport::types::InterfaceId(0), &mut rng,
2790 );
2791 let has_resp_send = resp_actions.iter().any(|a| matches!(a, LinkManagerAction::SendPacket { .. }));
2792 assert!(has_resp_send, "Handler should produce response");
2793
2794 let resp_raw = extract_any_send_packet(&resp_actions);
2796 let resp_pkt = RawPacket::unpack(&resp_raw).unwrap();
2797 let init_actions = init_mgr.handle_local_delivery(
2798 resp_pkt.destination_hash, &resp_raw, resp_pkt.packet_hash, rns_core::transport::types::InterfaceId(0), &mut rng,
2799 );
2800
2801 let has_response_received = init_actions.iter().any(|a|
2802 matches!(a, LinkManagerAction::ResponseReceived { .. })
2803 );
2804 assert!(has_response_received, "Initiator should receive ResponseReceived");
2805 }
2806
2807 #[test]
2808 fn test_send_channel_message_on_no_channel() {
2809 let mut mgr = LinkManager::new();
2810 let mut rng = OsRng;
2811 let dummy_sig = [0xAA; 32];
2812 let (link_id, _) = mgr.create_link(&[0x11; 16], &dummy_sig, 1, constants::MTU as u32, &mut rng);
2813
2814 let actions = mgr.send_channel_message(&link_id, 1, b"test", &mut rng);
2816 assert!(actions.is_empty(), "No channel on pending link");
2817 }
2818
2819 #[test]
2820 fn test_send_on_link_requires_active() {
2821 let mut mgr = LinkManager::new();
2822 let mut rng = OsRng;
2823 let dummy_sig = [0xAA; 32];
2824 let (link_id, _) = mgr.create_link(&[0x11; 16], &dummy_sig, 1, constants::MTU as u32, &mut rng);
2825
2826 let actions = mgr.send_on_link(&link_id, b"test", constants::CONTEXT_NONE, &mut rng);
2827 assert!(actions.is_empty(), "Cannot send on pending link");
2828 }
2829
2830 #[test]
2831 fn test_send_on_link_unknown_link() {
2832 let mgr = LinkManager::new();
2833 let mut rng = OsRng;
2834
2835 let actions = mgr.send_on_link(&[0xFF; 16], b"test", constants::CONTEXT_NONE, &mut rng);
2836 assert!(actions.is_empty());
2837 }
2838
2839 #[test]
2840 fn test_resource_full_transfer_large() {
2841 let (mut init_mgr, mut resp_mgr, link_id) = setup_active_link();
2842 let mut rng = OsRng;
2843
2844 resp_mgr.set_resource_strategy(&link_id, ResourceStrategy::AcceptAll);
2845
2846 let original_data: Vec<u8> = (0..2000u32).map(|i| {
2848 let pos = i as usize;
2849 (pos ^ (pos >> 8) ^ (pos >> 16)) as u8
2850 }).collect();
2851
2852 let adv_actions = init_mgr.send_resource(&link_id, &original_data, None, &mut rng);
2853
2854 let mut pending: Vec<(char, LinkManagerAction)> = adv_actions.into_iter()
2855 .map(|a| ('i', a))
2856 .collect();
2857 let mut rounds = 0;
2858 let max_rounds = 200;
2859 let mut resource_received = false;
2860 let mut sender_completed = false;
2861
2862 while !pending.is_empty() && rounds < max_rounds {
2863 rounds += 1;
2864 let mut next: Vec<(char, LinkManagerAction)> = Vec::new();
2865
2866 for (source, action) in pending.drain(..) {
2867 if let LinkManagerAction::SendPacket { raw, .. } = action {
2868 let pkt = match RawPacket::unpack(&raw) {
2869 Ok(p) => p,
2870 Err(_) => continue,
2871 };
2872
2873 let target_actions = if source == 'i' {
2874 resp_mgr.handle_local_delivery(
2875 pkt.destination_hash, &raw, pkt.packet_hash, rns_core::transport::types::InterfaceId(0), &mut rng,
2876 )
2877 } else {
2878 init_mgr.handle_local_delivery(
2879 pkt.destination_hash, &raw, pkt.packet_hash, rns_core::transport::types::InterfaceId(0), &mut rng,
2880 )
2881 };
2882
2883 let target_source = if source == 'i' { 'r' } else { 'i' };
2884 for a in &target_actions {
2885 match a {
2886 LinkManagerAction::ResourceReceived { data, .. } => {
2887 assert_eq!(*data, original_data);
2888 resource_received = true;
2889 }
2890 LinkManagerAction::ResourceCompleted { .. } => {
2891 sender_completed = true;
2892 }
2893 _ => {}
2894 }
2895 }
2896 next.extend(target_actions.into_iter().map(|a| (target_source, a)));
2897 }
2898 }
2899 pending = next;
2900 }
2901
2902 assert!(resource_received, "Should receive large resource (rounds={})", rounds);
2903 assert!(sender_completed, "Sender should complete (rounds={})", rounds);
2904 }
2905
2906 #[test]
2907 fn test_process_resource_actions_mapping() {
2908 let (init_mgr, _resp_mgr, link_id) = setup_active_link();
2909 let mut rng = OsRng;
2910
2911 let actions = vec![
2913 ResourceAction::DataReceived { data: vec![1, 2, 3], metadata: Some(vec![4, 5]) },
2914 ResourceAction::Completed,
2915 ResourceAction::Failed(rns_core::resource::ResourceError::Timeout),
2916 ResourceAction::ProgressUpdate { received: 10, total: 20 },
2917 ];
2918
2919 let result = init_mgr.process_resource_actions(&link_id, actions, &mut rng);
2920
2921 assert!(matches!(result[0], LinkManagerAction::ResourceReceived { .. }));
2922 assert!(matches!(result[1], LinkManagerAction::ResourceCompleted { .. }));
2923 assert!(matches!(result[2], LinkManagerAction::ResourceFailed { .. }));
2924 assert!(matches!(result[3], LinkManagerAction::ResourceProgress { received: 10, total: 20, .. }));
2925 }
2926
2927 #[test]
2928 fn test_link_state_empty() {
2929 let mgr = LinkManager::new();
2930 let fake_id = [0xAA; 16];
2931 assert!(mgr.link_state(&fake_id).is_none());
2932 }
2933}