1use crate::spvd_decode::StructureDesc;
4use crate::spvd_encode::{
5 encode_nt_payload_bitset, encode_nt_payload_bitset_parts, encode_nt_payload_delta,
6 encode_nt_payload_filtered, encode_nt_payload_full, encode_nt_scalar_bitset,
7 encode_nt_scalar_full, encode_structure_desc, nt_payload_desc,
8};
9use spvirit_types::{NtPayload, NtScalar};
10use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
11
12pub fn encode_size_pva(size: usize, is_be: bool) -> Vec<u8> {
13 crate::encode_common::encode_size(size, is_be)
14}
15
16pub fn encode_string_pva(value: &str, is_be: bool) -> Vec<u8> {
17 crate::encode_common::encode_string(value, is_be)
18}
19
20fn encode_status_ok() -> Vec<u8> {
21 vec![0xFF]
22}
23
24fn encode_status_error(message: &str, is_be: bool) -> Vec<u8> {
25 let mut out = Vec::new();
26 out.push(0x02);
27 out.extend_from_slice(&encode_string_pva(message, is_be));
28 out.extend_from_slice(&encode_string_pva("", is_be));
29 out
30}
31
32pub fn encode_status_warning(message: &str, is_be: bool) -> Vec<u8> {
34 let mut out = Vec::new();
35 out.push(0x01);
36 out.extend_from_slice(&encode_string_pva(message, is_be));
37 out.extend_from_slice(&encode_string_pva("", is_be));
38 out
39}
40
41pub fn encode_status_fatal(message: &str, is_be: bool) -> Vec<u8> {
43 let mut out = Vec::new();
44 out.push(0x03);
45 out.extend_from_slice(&encode_string_pva(message, is_be));
46 out.extend_from_slice(&encode_string_pva("", is_be));
47 out
48}
49
50pub fn encode_message_error(message: &str, version: u8, is_be: bool) -> Vec<u8> {
51 let mut payload = Vec::new();
54 payload.extend_from_slice(&if is_be {
55 0u32.to_be_bytes()
56 } else {
57 0u32.to_le_bytes()
58 });
59 payload.push(2); payload.extend_from_slice(&encode_string_pva(message, is_be));
61 let mut out = encode_header(true, is_be, false, version, 18, payload.len() as u32);
62 out.extend_from_slice(&payload);
63 out
64}
65
66pub fn encode_header(
67 is_server: bool,
68 is_be: bool,
69 is_control: bool,
70 version: u8,
71 command: u8,
72 payload_length: u32,
73) -> Vec<u8> {
74 let magic = 0xCA;
75 let mut flags = 0u8;
76 if is_control {
77 flags |= 0x01;
78 }
79 if is_server {
80 flags |= 0x40;
81 }
82 if is_be {
83 flags |= 0x80;
84 }
85 let mut out = vec![magic, version, flags, command];
86 let len_bytes = if is_be {
87 payload_length.to_be_bytes()
88 } else {
89 payload_length.to_le_bytes()
90 };
91 out.extend_from_slice(&len_bytes);
92 out
93}
94
95pub fn encode_search_response(
96 guid: [u8; 12],
97 seq: u32,
98 addr: [u8; 16],
99 port: u16,
100 protocol: &str,
101 found: bool,
102 cids: &[u32],
103 version: u8,
104 is_be: bool,
105) -> Vec<u8> {
106 let mut payload = Vec::new();
107 payload.extend_from_slice(&guid);
108 payload.extend_from_slice(&if is_be {
109 seq.to_be_bytes()
110 } else {
111 seq.to_le_bytes()
112 });
113 payload.extend_from_slice(&addr);
114 payload.extend_from_slice(&if is_be {
115 port.to_be_bytes()
116 } else {
117 port.to_le_bytes()
118 });
119 payload.extend_from_slice(&encode_string_pva(protocol, is_be));
120 payload.push(if found { 1 } else { 0 });
121 let count = cids.len() as u16;
122 payload.extend_from_slice(&if is_be {
123 count.to_be_bytes()
124 } else {
125 count.to_le_bytes()
126 });
127 for cid in cids {
128 payload.extend_from_slice(&if is_be {
129 cid.to_be_bytes()
130 } else {
131 cid.to_le_bytes()
132 });
133 }
134
135 let mut out = encode_header(true, is_be, false, version, 4, payload.len() as u32);
136 out.extend_from_slice(&payload);
137 out
138}
139
140pub fn encode_connection_validated(is_server: bool, version: u8, is_be: bool) -> Vec<u8> {
141 let payload = encode_status_ok();
142 let mut out = encode_header(is_server, is_be, false, version, 9, payload.len() as u32);
143 out.extend_from_slice(&payload);
144 out
145}
146
147pub fn encode_control_message(
148 is_server: bool,
149 is_be: bool,
150 version: u8,
151 command: u8,
152 data: u32,
153) -> Vec<u8> {
154 encode_header(is_server, is_be, true, version, command, data)
156}
157
158pub fn encode_connection_validation(
159 buffer_size: u32,
160 introspection_registry_size: u16,
161 auth_methods: &[&str],
162 version: u8,
163 is_be: bool,
164) -> Vec<u8> {
165 let mut payload = Vec::new();
170 payload.extend_from_slice(&if is_be {
171 buffer_size.to_be_bytes()
172 } else {
173 buffer_size.to_le_bytes()
174 });
175 payload.extend_from_slice(&if is_be {
176 introspection_registry_size.to_be_bytes()
177 } else {
178 introspection_registry_size.to_le_bytes()
179 });
180 payload.extend_from_slice(&encode_size_pva(auth_methods.len(), is_be));
181 for method in auth_methods {
182 payload.extend_from_slice(&encode_string_pva(method, is_be));
183 }
184 let mut out = encode_header(true, is_be, false, version, 1, payload.len() as u32);
185 out.extend_from_slice(&payload);
186 out
187}
188
189pub fn encode_authnz_user_host(user: &str, host: &str, is_be: bool) -> Vec<u8> {
190 let mut out = Vec::new();
191 out.extend_from_slice(&[0xFD]);
192 if is_be {
193 out.extend_from_slice(&1u16.to_be_bytes());
194 } else {
195 out.extend_from_slice(&1u16.to_le_bytes());
196 }
197 out.extend_from_slice(&[0x80, 0x00]);
198 out.push(0x02);
199 out.push(0x04);
200 out.extend_from_slice(b"user");
201 out.push(0x60);
202 out.push(0x04);
203 out.extend_from_slice(b"host");
204 out.push(0x60);
205 out.extend_from_slice(&encode_string_pva(user, is_be));
206 out.extend_from_slice(&encode_string_pva(host, is_be));
207 out
208}
209
210pub fn encode_client_connection_validation(
211 buffer_size: u32,
212 introspection_registry_size: u16,
213 qos: u16,
214 authz: &str,
215 user: &str,
216 host: &str,
217 version: u8,
218 is_be: bool,
219) -> Vec<u8> {
220 let mut payload = Vec::new();
221 payload.extend_from_slice(&if is_be {
222 buffer_size.to_be_bytes()
223 } else {
224 buffer_size.to_le_bytes()
225 });
226 payload.extend_from_slice(&if is_be {
227 introspection_registry_size.to_be_bytes()
228 } else {
229 introspection_registry_size.to_le_bytes()
230 });
231 payload.extend_from_slice(&if is_be {
232 qos.to_be_bytes()
233 } else {
234 qos.to_le_bytes()
235 });
236 payload.extend_from_slice(&encode_string_pva(authz, is_be));
237 payload.extend_from_slice(&encode_authnz_user_host(user, host, is_be));
238 let mut out = encode_header(false, is_be, false, version, 1, payload.len() as u32);
239 out.extend_from_slice(&payload);
240 out
241}
242
243pub fn encode_connection_validation_client_ca(
248 buffer_size: u32,
249 introspection_registry_size: u16,
250 qos: u16,
251 method: &str,
252 user: &str,
253 host: &str,
254 is_be: bool,
255) -> Vec<u8> {
256 let mut payload = Vec::new();
257 payload.extend_from_slice(&if is_be {
258 buffer_size.to_be_bytes()
259 } else {
260 buffer_size.to_le_bytes()
261 });
262 payload.extend_from_slice(&if is_be {
263 introspection_registry_size.to_be_bytes()
264 } else {
265 introspection_registry_size.to_le_bytes()
266 });
267 payload.extend_from_slice(&if is_be {
268 qos.to_be_bytes()
269 } else {
270 qos.to_le_bytes()
271 });
272 payload.extend_from_slice(&encode_string_pva(method, is_be));
273 payload.extend_from_slice(&encode_authnz_user_host(user, host, is_be));
274 payload
275}
276
277pub fn encode_connection_validation_client_anon(
281 buffer_size: u32,
282 introspection_registry_size: u16,
283 qos: u16,
284 method: &str,
285 is_be: bool,
286) -> Vec<u8> {
287 let mut payload = Vec::new();
288 payload.extend_from_slice(&if is_be {
289 buffer_size.to_be_bytes()
290 } else {
291 buffer_size.to_le_bytes()
292 });
293 payload.extend_from_slice(&if is_be {
294 introspection_registry_size.to_be_bytes()
295 } else {
296 introspection_registry_size.to_le_bytes()
297 });
298 payload.extend_from_slice(&if is_be {
299 qos.to_be_bytes()
300 } else {
301 qos.to_le_bytes()
302 });
303 payload.extend_from_slice(&encode_string_pva(method, is_be));
304 payload
305}
306
307pub fn encode_create_channel_request(cid: u32, pv_name: &str, version: u8, is_be: bool) -> Vec<u8> {
308 let mut payload = Vec::new();
309 payload.extend_from_slice(&if is_be {
310 1u16.to_be_bytes()
311 } else {
312 1u16.to_le_bytes()
313 });
314 payload.extend_from_slice(&if is_be {
315 cid.to_be_bytes()
316 } else {
317 cid.to_le_bytes()
318 });
319 payload.extend_from_slice(&encode_string_pva(pv_name, is_be));
320 let mut out = encode_header(false, is_be, false, version, 7, payload.len() as u32);
321 out.extend_from_slice(&payload);
322 out
323}
324
325pub fn encode_get_field_request(
326 sid: u32,
327 ioid: u32,
328 sub_field: Option<&str>,
329 version: u8,
330 is_be: bool,
331) -> Vec<u8> {
332 let mut payload = Vec::new();
333 payload.extend_from_slice(&if is_be {
334 sid.to_be_bytes()
335 } else {
336 sid.to_le_bytes()
337 });
338 payload.extend_from_slice(&if is_be {
339 ioid.to_be_bytes()
340 } else {
341 ioid.to_le_bytes()
342 });
343 payload.extend_from_slice(&encode_string_pva(sub_field.unwrap_or(""), is_be));
344 let mut out = encode_header(false, is_be, false, version, 17, payload.len() as u32);
345 out.extend_from_slice(&payload);
346 out
347}
348
349pub fn encode_op_request(
350 command: u8,
351 sid: u32,
352 ioid: u32,
353 subcmd: u8,
354 extra: &[u8],
355 version: u8,
356 is_be: bool,
357) -> Vec<u8> {
358 let mut payload = Vec::new();
359 payload.extend_from_slice(&if is_be {
360 sid.to_be_bytes()
361 } else {
362 sid.to_le_bytes()
363 });
364 payload.extend_from_slice(&if is_be {
365 ioid.to_be_bytes()
366 } else {
367 ioid.to_le_bytes()
368 });
369 payload.push(subcmd);
370 payload.extend_from_slice(extra);
371 let mut out = encode_header(false, is_be, false, version, command, payload.len() as u32);
372 out.extend_from_slice(&payload);
373 out
374}
375
376pub fn encode_get_request(
377 sid: u32,
378 ioid: u32,
379 subcmd: u8,
380 extra: &[u8],
381 version: u8,
382 is_be: bool,
383) -> Vec<u8> {
384 encode_op_request(10, sid, ioid, subcmd, extra, version, is_be)
385}
386
387pub fn encode_put_request(
388 sid: u32,
389 ioid: u32,
390 subcmd: u8,
391 extra: &[u8],
392 version: u8,
393 is_be: bool,
394) -> Vec<u8> {
395 encode_op_request(11, sid, ioid, subcmd, extra, version, is_be)
396}
397
398pub fn encode_monitor_request(
399 sid: u32,
400 ioid: u32,
401 subcmd: u8,
402 extra: &[u8],
403 version: u8,
404 is_be: bool,
405) -> Vec<u8> {
406 encode_op_request(13, sid, ioid, subcmd, extra, version, is_be)
407}
408
409pub fn encode_rpc_request(
410 sid: u32,
411 ioid: u32,
412 subcmd: u8,
413 extra: &[u8],
414 version: u8,
415 is_be: bool,
416) -> Vec<u8> {
417 encode_op_request(20, sid, ioid, subcmd, extra, version, is_be)
418}
419
420pub fn encode_search_request(
421 seq: u32,
422 flags: u8,
423 port: u16,
424 reply_addr: [u8; 16],
425 pv_requests: &[(u32, &str)],
426 version: u8,
427 is_be: bool,
428) -> Vec<u8> {
429 let mut payload = Vec::new();
430 payload.extend_from_slice(&if is_be {
431 seq.to_be_bytes()
432 } else {
433 seq.to_le_bytes()
434 });
435 payload.push(flags);
436 payload.extend_from_slice(&[0u8; 3]);
437 payload.extend_from_slice(&reply_addr);
438 payload.extend_from_slice(&if is_be {
439 port.to_be_bytes()
440 } else {
441 port.to_le_bytes()
442 });
443 payload.extend_from_slice(&encode_size_pva(1, is_be));
444 payload.extend_from_slice(&encode_string_pva("tcp", is_be));
445 payload.extend_from_slice(&if is_be {
446 (pv_requests.len() as u16).to_be_bytes()
447 } else {
448 (pv_requests.len() as u16).to_le_bytes()
449 });
450 for (cid, pv_name) in pv_requests {
451 payload.extend_from_slice(&if is_be {
452 cid.to_be_bytes()
453 } else {
454 cid.to_le_bytes()
455 });
456 payload.extend_from_slice(&encode_string_pva(pv_name, is_be));
457 }
458
459 let mut out = encode_header(false, is_be, false, version, 3, payload.len() as u32);
460 out.extend_from_slice(&payload);
461 out
462}
463
464pub fn encode_create_channel_response(cid: u32, sid: u32, version: u8, is_be: bool) -> Vec<u8> {
465 let mut payload = Vec::new();
466 payload.extend_from_slice(&if is_be {
467 cid.to_be_bytes()
468 } else {
469 cid.to_le_bytes()
470 });
471 payload.extend_from_slice(&if is_be {
472 sid.to_be_bytes()
473 } else {
474 sid.to_le_bytes()
475 });
476 payload.extend_from_slice(&encode_status_ok());
477 let mut out = encode_header(true, is_be, false, version, 7, payload.len() as u32);
478 out.extend_from_slice(&payload);
479 out
480}
481
482pub fn encode_create_channel_error(cid: u32, message: &str, version: u8, is_be: bool) -> Vec<u8> {
483 let mut payload = Vec::new();
484 payload.extend_from_slice(&if is_be {
485 cid.to_be_bytes()
486 } else {
487 cid.to_le_bytes()
488 });
489 payload.extend_from_slice(&if is_be {
490 0u32.to_be_bytes()
491 } else {
492 0u32.to_le_bytes()
493 });
494 payload.push(0x01);
495 payload.extend_from_slice(&encode_string_pva(message, is_be));
496 payload.extend_from_slice(&encode_string_pva("", is_be));
497 let mut out = encode_header(true, is_be, false, version, 7, payload.len() as u32);
498 out.extend_from_slice(&payload);
499 out
500}
501
502pub fn encode_get_field_response(
503 request_id: u32,
504 desc: &StructureDesc,
505 version: u8,
506 is_be: bool,
507) -> Vec<u8> {
508 let mut payload = Vec::new();
509 payload.extend_from_slice(&if is_be {
510 request_id.to_be_bytes()
511 } else {
512 request_id.to_le_bytes()
513 });
514 payload.extend_from_slice(&encode_status_ok());
515 payload.push(0x80);
516 payload.extend_from_slice(&encode_structure_desc(desc, is_be));
517 let mut out = encode_header(true, is_be, false, version, 17, payload.len() as u32);
518 out.extend_from_slice(&payload);
519 out
520}
521
522pub fn encode_get_field_error(request_id: u32, message: &str, version: u8, is_be: bool) -> Vec<u8> {
523 let mut payload = Vec::new();
524 payload.extend_from_slice(&if is_be {
525 request_id.to_be_bytes()
526 } else {
527 request_id.to_le_bytes()
528 });
529 payload.extend_from_slice(&encode_status_error(message, is_be));
530 let mut out = encode_header(true, is_be, false, version, 17, payload.len() as u32);
531 out.extend_from_slice(&payload);
532 out
533}
534
535pub fn encode_op_init_response(
536 command: u8,
537 ioid: u32,
538 subcmd: u8,
539 desc: &StructureDesc,
540 nt: &NtScalar,
541 version: u8,
542 is_be: bool,
543) -> Vec<u8> {
544 let mut payload = Vec::new();
545 payload.extend_from_slice(&if is_be {
546 ioid.to_be_bytes()
547 } else {
548 ioid.to_le_bytes()
549 });
550 payload.push(subcmd);
551 payload.extend_from_slice(&encode_status_ok());
552 payload.push(0x80); payload.extend_from_slice(&encode_structure_desc(desc, is_be));
554 payload.extend_from_slice(&encode_nt_scalar_full(nt, is_be));
555
556 let mut out = encode_header(true, is_be, false, version, command, payload.len() as u32);
557 out.extend_from_slice(&payload);
558 out
559}
560
561pub fn encode_op_init_response_desc(
562 command: u8,
563 ioid: u32,
564 subcmd: u8,
565 desc: &StructureDesc,
566 version: u8,
567 is_be: bool,
568) -> Vec<u8> {
569 let mut payload = Vec::new();
570 payload.extend_from_slice(&if is_be {
571 ioid.to_be_bytes()
572 } else {
573 ioid.to_le_bytes()
574 });
575 payload.push(subcmd);
576 payload.extend_from_slice(&encode_status_ok());
577 payload.push(0x80); payload.extend_from_slice(&encode_structure_desc(desc, is_be));
579
580 let mut out = encode_header(true, is_be, false, version, command, payload.len() as u32);
581 out.extend_from_slice(&payload);
582 out
583}
584
585pub fn encode_op_data_response(
586 command: u8,
587 ioid: u32,
588 nt: &NtScalar,
589 version: u8,
590 is_be: bool,
591) -> Vec<u8> {
592 let mut payload = Vec::new();
593 payload.extend_from_slice(&if is_be {
594 ioid.to_be_bytes()
595 } else {
596 ioid.to_le_bytes()
597 });
598 payload.push(0x00);
599 payload.extend_from_slice(&encode_nt_scalar_bitset(nt, is_be));
600 let mut out = encode_header(true, is_be, false, version, command, payload.len() as u32);
601 out.extend_from_slice(&payload);
602 out
603}
604
605pub fn encode_op_get_data_response_payload(
606 ioid: u32,
607 payload_value: &NtPayload,
608 version: u8,
609 is_be: bool,
610) -> Vec<u8> {
611 encode_op_data_response_payload(10, ioid, payload_value, version, is_be)
612}
613
614pub fn encode_op_data_response_payload(
615 command: u8,
616 ioid: u32,
617 payload_value: &NtPayload,
618 version: u8,
619 is_be: bool,
620) -> Vec<u8> {
621 let mut payload = Vec::new();
622 payload.extend_from_slice(&if is_be {
623 ioid.to_be_bytes()
624 } else {
625 ioid.to_le_bytes()
626 });
627 payload.push(0x00);
628 payload.extend_from_slice(&encode_status_ok());
629 payload.extend_from_slice(&encode_nt_payload_bitset(payload_value, is_be));
630 let mut out = encode_header(true, is_be, false, version, command, payload.len() as u32);
631 out.extend_from_slice(&payload);
632 out
633}
634
635pub fn encode_op_data_response_filtered(
638 command: u8,
639 ioid: u32,
640 payload_value: &NtPayload,
641 filtered_desc: &StructureDesc,
642 version: u8,
643 is_be: bool,
644) -> Vec<u8> {
645 let (bitset, values) = encode_nt_payload_filtered(payload_value, filtered_desc, is_be);
646 let mut payload = Vec::new();
647 payload.extend_from_slice(&if is_be {
648 ioid.to_be_bytes()
649 } else {
650 ioid.to_le_bytes()
651 });
652 payload.push(0x00);
653 payload.extend_from_slice(&encode_status_ok());
654 payload.extend_from_slice(&bitset);
655 payload.extend_from_slice(&values);
656 let mut out = encode_header(true, is_be, false, version, command, payload.len() as u32);
657 out.extend_from_slice(&payload);
658 out
659}
660
661pub fn encode_op_status_response(
662 command: u8,
663 ioid: u32,
664 subcmd: u8,
665 version: u8,
666 is_be: bool,
667) -> Vec<u8> {
668 let mut payload = Vec::new();
669 payload.extend_from_slice(&if is_be {
670 ioid.to_be_bytes()
671 } else {
672 ioid.to_le_bytes()
673 });
674 payload.push(subcmd);
675 payload.extend_from_slice(&encode_status_ok());
676 let mut out = encode_header(true, is_be, false, version, command, payload.len() as u32);
677 out.extend_from_slice(&payload);
678 out
679}
680
681pub fn encode_op_status_error_response(
682 command: u8,
683 ioid: u32,
684 subcmd: u8,
685 message: &str,
686 version: u8,
687 is_be: bool,
688) -> Vec<u8> {
689 let mut payload = Vec::new();
690 payload.extend_from_slice(&if is_be {
691 ioid.to_be_bytes()
692 } else {
693 ioid.to_le_bytes()
694 });
695 payload.push(subcmd);
696 payload.extend_from_slice(&encode_status_error(message, is_be));
697 let mut out = encode_header(true, is_be, false, version, command, payload.len() as u32);
698 out.extend_from_slice(&payload);
699 out
700}
701
702pub fn encode_op_rpc_data_response_payload(
703 ioid: u32,
704 subcmd: u8,
705 payload_value: &NtPayload,
706 version: u8,
707 is_be: bool,
708) -> Vec<u8> {
709 let desc = nt_payload_desc(payload_value);
710 let mut payload = Vec::new();
711 payload.extend_from_slice(&if is_be {
712 ioid.to_be_bytes()
713 } else {
714 ioid.to_le_bytes()
715 });
716 payload.push(subcmd);
717 payload.extend_from_slice(&encode_status_ok());
718 payload.push(0x80);
719 payload.extend_from_slice(&encode_structure_desc(&desc, is_be));
720 payload.extend_from_slice(&encode_nt_payload_full(payload_value, is_be));
721 let mut out = encode_header(true, is_be, false, version, 20, payload.len() as u32);
722 out.extend_from_slice(&payload);
723 out
724}
725
726pub fn encode_op_put_get_init_response(
727 ioid: u32,
728 put_desc: &StructureDesc,
729 get_desc: &StructureDesc,
730 version: u8,
731 is_be: bool,
732) -> Vec<u8> {
733 let mut payload = Vec::new();
734 payload.extend_from_slice(&if is_be {
735 ioid.to_be_bytes()
736 } else {
737 ioid.to_le_bytes()
738 });
739 payload.push(0x08);
740 payload.extend_from_slice(&encode_status_ok());
741 payload.push(0x80);
742 payload.extend_from_slice(&encode_structure_desc(put_desc, is_be));
743 payload.push(0x80);
744 payload.extend_from_slice(&encode_structure_desc(get_desc, is_be));
745 let mut out = encode_header(true, is_be, false, version, 12, payload.len() as u32);
746 out.extend_from_slice(&payload);
747 out
748}
749
750pub fn encode_op_put_get_data_response(
751 ioid: u32,
752 nt: &NtScalar,
753 version: u8,
754 is_be: bool,
755) -> Vec<u8> {
756 encode_op_put_get_data_response_payload(ioid, &NtPayload::Scalar(nt.clone()), version, is_be)
757}
758
759pub fn encode_op_put_get_data_response_payload(
760 ioid: u32,
761 payload_value: &NtPayload,
762 version: u8,
763 is_be: bool,
764) -> Vec<u8> {
765 let mut payload = Vec::new();
766 payload.extend_from_slice(&if is_be {
767 ioid.to_be_bytes()
768 } else {
769 ioid.to_le_bytes()
770 });
771 payload.push(0x00);
772 payload.extend_from_slice(&encode_status_ok());
773 payload.extend_from_slice(&encode_nt_payload_bitset(payload_value, is_be));
774 let mut out = encode_header(true, is_be, false, version, 12, payload.len() as u32);
775 out.extend_from_slice(&payload);
776 out
777}
778
779pub fn encode_op_put_response(ioid: u32, subcmd: u8, version: u8, is_be: bool) -> Vec<u8> {
780 let mut payload = Vec::new();
781 payload.extend_from_slice(&if is_be {
782 ioid.to_be_bytes()
783 } else {
784 ioid.to_le_bytes()
785 });
786 payload.push(subcmd);
787 payload.extend_from_slice(&encode_status_ok());
788 let mut out = encode_header(true, is_be, false, version, 11, payload.len() as u32);
789 out.extend_from_slice(&payload);
790 out
791}
792
793pub fn encode_op_put_status_response(
794 ioid: u32,
795 subcmd: u8,
796 message: &str,
797 version: u8,
798 is_be: bool,
799) -> Vec<u8> {
800 let mut payload = Vec::new();
801 payload.extend_from_slice(&if is_be {
802 ioid.to_be_bytes()
803 } else {
804 ioid.to_le_bytes()
805 });
806 payload.push(subcmd);
807 payload.extend_from_slice(&encode_status_error(message, is_be));
808 let mut out = encode_header(true, is_be, false, version, 11, payload.len() as u32);
809 out.extend_from_slice(&payload);
810 out
811}
812
813pub fn encode_op_put_getput_response(
814 ioid: u32,
815 nt: &NtScalar,
816 version: u8,
817 is_be: bool,
818) -> Vec<u8> {
819 encode_op_put_getput_response_payload(ioid, &NtPayload::Scalar(nt.clone()), version, is_be)
820}
821
822pub fn encode_op_put_getput_response_payload(
823 ioid: u32,
824 payload_value: &NtPayload,
825 version: u8,
826 is_be: bool,
827) -> Vec<u8> {
828 let mut payload = Vec::new();
829 payload.extend_from_slice(&if is_be {
830 ioid.to_be_bytes()
831 } else {
832 ioid.to_le_bytes()
833 });
834 payload.push(0x40);
835 payload.extend_from_slice(&encode_status_ok());
836 payload.extend_from_slice(&encode_nt_payload_bitset(payload_value, is_be));
837 let mut out = encode_header(true, is_be, false, version, 11, payload.len() as u32);
838 out.extend_from_slice(&payload);
839 out
840}
841
842pub fn encode_op_put_get_init_error_response(
843 ioid: u32,
844 message: &str,
845 version: u8,
846 is_be: bool,
847) -> Vec<u8> {
848 let mut payload = Vec::new();
849 payload.extend_from_slice(&if is_be {
850 ioid.to_be_bytes()
851 } else {
852 ioid.to_le_bytes()
853 });
854 payload.push(0x08);
855 payload.extend_from_slice(&encode_status_error(message, is_be));
856 let mut out = encode_header(true, is_be, false, version, 12, payload.len() as u32);
857 out.extend_from_slice(&payload);
858 out
859}
860
861pub fn encode_op_put_get_data_error_response(
862 ioid: u32,
863 message: &str,
864 version: u8,
865 is_be: bool,
866) -> Vec<u8> {
867 let mut payload = Vec::new();
868 payload.extend_from_slice(&if is_be {
869 ioid.to_be_bytes()
870 } else {
871 ioid.to_le_bytes()
872 });
873 payload.push(0x00);
874 payload.extend_from_slice(&encode_status_error(message, is_be));
875 let mut out = encode_header(true, is_be, false, version, 12, payload.len() as u32);
876 out.extend_from_slice(&payload);
877 out
878}
879
880pub fn encode_monitor_data_response(
881 ioid: u32,
882 subcmd: u8,
883 nt: &NtScalar,
884 version: u8,
885 is_be: bool,
886) -> Vec<u8> {
887 encode_monitor_data_response_payload(
888 ioid,
889 subcmd,
890 &NtPayload::Scalar(nt.clone()),
891 version,
892 is_be,
893 )
894}
895
896pub fn encode_monitor_data_response_payload(
897 ioid: u32,
898 subcmd: u8,
899 payload_value: &NtPayload,
900 version: u8,
901 is_be: bool,
902) -> Vec<u8> {
903 let (changed_bitset, values) = encode_nt_payload_bitset_parts(payload_value, is_be);
904 let mut payload = Vec::new();
905 payload.extend_from_slice(&if is_be {
906 ioid.to_be_bytes()
907 } else {
908 ioid.to_le_bytes()
909 });
910 payload.push(subcmd);
911 if (subcmd & 0x10) != 0 {
912 payload.extend_from_slice(&encode_status_ok());
913 }
914 payload.extend_from_slice(&changed_bitset);
915 payload.extend_from_slice(&values);
916 payload.extend_from_slice(&encode_size_pva(0, is_be));
918 let mut out = encode_header(true, is_be, false, version, 13, payload.len() as u32);
919 out.extend_from_slice(&payload);
920 out
921}
922
923pub fn encode_monitor_data_response_filtered(
926 ioid: u32,
927 subcmd: u8,
928 payload_value: &NtPayload,
929 filtered_desc: &StructureDesc,
930 version: u8,
931 is_be: bool,
932) -> Vec<u8> {
933 let (bitset, values) = encode_nt_payload_filtered(payload_value, filtered_desc, is_be);
934 let mut payload = Vec::new();
935 payload.extend_from_slice(&if is_be {
936 ioid.to_be_bytes()
937 } else {
938 ioid.to_le_bytes()
939 });
940 payload.push(subcmd);
941 if (subcmd & 0x10) != 0 {
942 payload.extend_from_slice(&encode_status_ok());
943 }
944 payload.extend_from_slice(&bitset);
945 payload.extend_from_slice(&values);
946 payload.extend_from_slice(&encode_size_pva(0, is_be));
947 let mut out = encode_header(true, is_be, false, version, 13, payload.len() as u32);
948 out.extend_from_slice(&payload);
949 out
950}
951
952pub fn encode_monitor_data_response_delta(
957 ioid: u32,
958 subcmd: u8,
959 prev_value: &NtPayload,
960 next_value: &NtPayload,
961 filtered_desc: &StructureDesc,
962 version: u8,
963 is_be: bool,
964) -> Option<Vec<u8>> {
965 let (bitset, values) = encode_nt_payload_delta(prev_value, next_value, filtered_desc, is_be)?;
966 let mut payload = Vec::new();
967 payload.extend_from_slice(&if is_be {
968 ioid.to_be_bytes()
969 } else {
970 ioid.to_le_bytes()
971 });
972 payload.push(subcmd);
973 if (subcmd & 0x10) != 0 {
974 payload.extend_from_slice(&encode_status_ok());
975 }
976 payload.extend_from_slice(&bitset);
977 payload.extend_from_slice(&values);
978 payload.extend_from_slice(&encode_size_pva(0, is_be));
979 let mut out = encode_header(true, is_be, false, version, 13, payload.len() as u32);
980 out.extend_from_slice(&payload);
981 Some(out)
982}
983
984pub fn encode_destroy_channel_response(sid: u32, cid: u32, version: u8, is_be: bool) -> Vec<u8> {
985 let mut payload = Vec::new();
986 payload.extend_from_slice(&if is_be {
987 sid.to_be_bytes()
988 } else {
989 sid.to_le_bytes()
990 });
991 payload.extend_from_slice(&if is_be {
992 cid.to_be_bytes()
993 } else {
994 cid.to_le_bytes()
995 });
996 let mut out = encode_header(true, is_be, false, version, 8, payload.len() as u32);
997 out.extend_from_slice(&payload);
998 out
999}
1000
1001pub fn encode_op_error(
1002 command: u8,
1003 subcmd: u8,
1004 ioid: u32,
1005 message: &str,
1006 version: u8,
1007 is_be: bool,
1008) -> Vec<u8> {
1009 let mut payload = Vec::new();
1010 payload.extend_from_slice(&if is_be {
1011 ioid.to_be_bytes()
1012 } else {
1013 ioid.to_le_bytes()
1014 });
1015 payload.push(subcmd);
1016 payload.push(0x02); payload.extend_from_slice(&encode_string_pva(message, is_be));
1018 payload.extend_from_slice(&encode_string_pva("", is_be));
1019 let mut out = encode_header(true, is_be, false, version, command, payload.len() as u32);
1020 out.extend_from_slice(&payload);
1021 out
1022}
1023
1024pub fn encode_beacon(
1025 guid: [u8; 12],
1026 seq: u8,
1027 change_count: u16,
1028 addr: [u8; 16],
1029 port: u16,
1030 protocol: &str,
1031 version: u8,
1032 is_be: bool,
1033) -> Vec<u8> {
1034 let mut payload = Vec::new();
1035 payload.extend_from_slice(&guid);
1036 payload.push(0x00); payload.push(seq);
1038 payload.extend_from_slice(&if is_be {
1039 change_count.to_be_bytes()
1040 } else {
1041 change_count.to_le_bytes()
1042 });
1043 payload.extend_from_slice(&addr);
1044 payload.extend_from_slice(&if is_be {
1045 port.to_be_bytes()
1046 } else {
1047 port.to_le_bytes()
1048 });
1049 payload.extend_from_slice(&encode_string_pva(protocol, is_be));
1050 payload.push(0xFF);
1054 let mut out = encode_header(true, is_be, false, version, 0, payload.len() as u32);
1055 out.extend_from_slice(&payload);
1056 out
1057}
1058
1059pub fn ip_to_bytes(ip: IpAddr) -> [u8; 16] {
1068 match ip {
1069 IpAddr::V4(v4) => {
1070 let mut out = [0u8; 16];
1071 out[10] = 0xFF;
1072 out[11] = 0xFF;
1073 out[12..16].copy_from_slice(&v4.octets());
1074 out
1075 }
1076 IpAddr::V6(v6) => v6.octets(),
1077 }
1078}
1079
1080pub fn ip_from_bytes(addr: &[u8; 16]) -> Option<IpAddr> {
1085 if addr.iter().all(|&b| b == 0) {
1086 return None;
1087 }
1088 if addr[0..10].iter().all(|&b| b == 0) && addr[10] == 0xFF && addr[11] == 0xFF {
1090 return Some(IpAddr::V4(Ipv4Addr::new(
1091 addr[12], addr[13], addr[14], addr[15],
1092 )));
1093 }
1094 Some(IpAddr::V6(Ipv6Addr::from(*addr)))
1095}
1096
1097pub fn socket_addr_from_pva_bytes(addr: [u8; 16], port: u16) -> Option<SocketAddr> {
1098 ip_from_bytes(&addr).map(|ip| SocketAddr::new(ip, port))
1099}
1100
1101pub fn format_pva_address(addr: &[u8; 16]) -> String {
1105 match ip_from_bytes(addr) {
1106 Some(ip) => ip.to_string(),
1107 None => "0.0.0.0".to_string(),
1108 }
1109}
1110
1111#[cfg(test)]
1112mod tests {
1113 use super::*;
1114 use crate::epics_decode::{PvaPacket, PvaPacketCommand};
1115
1116 #[test]
1117 fn encode_decode_connection_validation_roundtrip() {
1118 let msg = encode_connection_validation(4096, 2, &["anonymous", "ca"], 2, true);
1119 let mut pkt = PvaPacket::new(&msg);
1120 let cmd = pkt.decode_payload().expect("decoded");
1121 match cmd {
1122 PvaPacketCommand::ConnectionValidation(payload) => {
1123 assert!(payload.is_server);
1124 assert_eq!(payload.buffer_size, 4096);
1125 assert_eq!(payload.introspection_registry_size, 2);
1126 assert_eq!(payload.qos, 0); assert_eq!(payload.authz.as_deref(), Some("anonymous"));
1128 }
1129 other => panic!("unexpected decode: {:?}", other),
1130 }
1131 }
1132
1133 #[test]
1134 fn encode_decode_client_connection_validation_roundtrip() {
1135 let msg = encode_client_connection_validation(
1136 87_040, 32_767, 0, "ca", "alice", "host1", 2, false,
1137 );
1138 let mut pkt = PvaPacket::new(&msg);
1139 let cmd = pkt.decode_payload().expect("decoded");
1140 match cmd {
1141 PvaPacketCommand::ConnectionValidation(payload) => {
1142 assert!(!payload.is_server);
1143 assert_eq!(payload.buffer_size, 87_040);
1144 assert_eq!(payload.introspection_registry_size, 32_767);
1145 assert_eq!(payload.qos, 0);
1146 }
1147 other => panic!("unexpected decode: {:?}", other),
1148 }
1149 }
1150
1151 #[test]
1152 fn encode_decode_search_response_roundtrip() {
1153 let guid = [1u8; 12];
1154 let seq = 42;
1155 let addr = [0u8; 16];
1156 let port = 5075;
1157 let cids = vec![100u32, 101u32];
1158 let msg = encode_search_response(guid, seq, addr, port, "tcp", true, &cids, 2, false);
1159 let mut pkt = PvaPacket::new(&msg);
1160 let cmd = pkt.decode_payload().expect("decoded");
1161 match cmd {
1162 PvaPacketCommand::SearchResponse(payload) => {
1163 assert_eq!(payload.guid, guid);
1164 assert_eq!(payload.seq, seq);
1165 assert_eq!(payload.port, port);
1166 assert!(payload.found);
1167 assert_eq!(payload.cids, cids);
1168 }
1169 other => panic!("unexpected decode: {:?}", other),
1170 }
1171 }
1172
1173 #[test]
1174 fn encode_decode_connection_validated_roundtrip() {
1175 let msg = encode_connection_validated(true, 2, false);
1176 let mut pkt = PvaPacket::new(&msg);
1177 let cmd = pkt.decode_payload().expect("decoded");
1178 match cmd {
1179 PvaPacketCommand::ConnectionValidated(payload) => {
1180 assert!(payload.status.is_none());
1182 }
1183 other => panic!("unexpected decode: {:?}", other),
1184 }
1185 }
1186
1187 #[test]
1188 fn get_data_response_includes_status() {
1189 let nt = NtScalar::from_value(spvirit_types::ScalarValue::F64(1.0));
1190 let msg = encode_op_get_data_response_payload(0x11223344, &NtPayload::Scalar(nt), 2, false);
1191 assert!(msg.len() > 13);
1192 let status_offset = 8 + 4 + 1;
1193 assert_eq!(msg[status_offset], 0xFF);
1194
1195 let mut pkt = PvaPacket::new(&msg);
1196 let cmd = pkt.decode_payload().expect("decoded");
1197 match cmd {
1198 PvaPacketCommand::Op(op) => {
1199 assert_eq!(op.command, 10);
1200 assert_eq!(op.subcmd, 0x00);
1201 assert!(!op.body.is_empty());
1202 }
1203 other => panic!("unexpected decode: {:?}", other),
1204 }
1205 }
1206
1207 #[test]
1208 fn put_get_init_includes_two_descriptors() {
1209 let nt = NtScalar::from_value(spvirit_types::ScalarValue::F64(1.0));
1210 let desc = crate::spvd_encode::nt_scalar_desc(&nt.value);
1211 let msg = encode_op_put_get_init_response(0x01020304, &desc, &desc, 2, false);
1212
1213 let payload = &msg[8..];
1214 assert!(payload.len() > 6);
1215 assert_eq!(payload[5], 0xFF);
1217 let rest = &payload[6..];
1218 let first = rest.first().copied().unwrap_or(0);
1219 assert_eq!(first, 0x80);
1220 let second_pos = rest.iter().skip(1).position(|b| *b == 0x80);
1221 assert!(second_pos.is_some(), "expected second descriptor marker");
1222 }
1223
1224 #[test]
1225 fn put_get_data_includes_status() {
1226 let nt = NtScalar::from_value(spvirit_types::ScalarValue::F64(2.0));
1227 let msg = encode_op_put_get_data_response(0x55667788, &nt, 2, false);
1228 assert!(msg.len() > 13);
1229 let status_offset = 8 + 4 + 1;
1230 assert_eq!(msg[status_offset], 0xFF);
1231 }
1232
1233 #[test]
1234 fn put_getput_response_encodes_subcmd_0x40() {
1235 let nt = NtScalar::from_value(spvirit_types::ScalarValue::F64(2.0));
1236 let msg = encode_op_put_getput_response(0x01020304, &nt, 2, false);
1237 assert!(msg.len() > 13);
1238 let status_offset = 8 + 4 + 1;
1239 assert_eq!(msg[status_offset], 0xFF);
1240 let mut pkt = PvaPacket::new(&msg);
1241 let cmd = pkt.decode_payload().expect("decoded");
1242 match cmd {
1243 PvaPacketCommand::Op(op) => {
1244 assert_eq!(op.command, 11);
1245 assert_eq!(op.subcmd, 0x40);
1246 }
1247 other => panic!("unexpected decode: {:?}", other),
1248 }
1249 }
1250
1251 #[test]
1252 fn encode_get_field_response_roundtrip() {
1253 let desc = StructureDesc {
1254 struct_id: Some("epics:nt/NTScalar:1.0".to_string()),
1255 fields: vec![crate::spvd_decode::FieldDesc {
1256 name: "value".to_string(),
1257 field_type: crate::spvd_decode::FieldType::Scalar(
1258 crate::spvd_decode::TypeCode::String,
1259 ),
1260 }],
1261 };
1262 let msg = encode_get_field_response(11, &desc, 2, false);
1263 let mut pkt = PvaPacket::new(&msg);
1264 let cmd = pkt.decode_payload().expect("decoded");
1265 match cmd {
1266 PvaPacketCommand::GetField(payload) => {
1267 assert!(payload.is_server);
1268 assert_eq!(payload.cid, 11);
1269 assert!(payload.status.is_none());
1270 let intro = payload.introspection.expect("introspection");
1271 assert_eq!(intro.fields.len(), 1);
1272 assert_eq!(intro.fields[0].name, "value");
1273 }
1274 other => panic!("unexpected decode: {:?}", other),
1275 }
1276 }
1277
1278 #[test]
1279 fn encode_get_field_error_roundtrip() {
1280 let msg = encode_get_field_error(7, "listing disabled", 2, false);
1281 let mut pkt = PvaPacket::new(&msg);
1282 let cmd = pkt.decode_payload().expect("decoded");
1283 match cmd {
1284 PvaPacketCommand::GetField(payload) => {
1285 assert!(payload.is_server);
1286 assert_eq!(payload.cid, 7);
1287 let status = payload.status.expect("status");
1288 assert_eq!(status.code, 0x02);
1289 assert_eq!(status.message.as_deref(), Some("listing disabled"));
1290 }
1291 other => panic!("unexpected decode: {:?}", other),
1292 }
1293 }
1294
1295 #[test]
1296 fn encode_decode_create_channel_request_roundtrip() {
1297 let msg = encode_create_channel_request(7, "TEST:PV", 2, false);
1298 let mut pkt = PvaPacket::new(&msg);
1299 let cmd = pkt.decode_payload().expect("decoded");
1300 match cmd {
1301 PvaPacketCommand::CreateChannel(payload) => {
1302 assert!(!payload.is_server);
1303 assert_eq!(payload.channels, vec![(7, "TEST:PV".to_string())]);
1304 }
1305 other => panic!("unexpected decode: {:?}", other),
1306 }
1307 }
1308
1309 #[test]
1310 fn encode_decode_get_field_request_roundtrip() {
1311 let msg = encode_get_field_request(9, 1, Some("*"), 2, false);
1312 let mut pkt = PvaPacket::new(&msg);
1313 let cmd = pkt.decode_payload().expect("decoded");
1314 match cmd {
1315 PvaPacketCommand::GetField(payload) => {
1316 assert!(!payload.is_server);
1317 assert_eq!(payload.sid, Some(9));
1318 assert_eq!(payload.ioid, Some(1));
1319 assert_eq!(payload.field_name.as_deref(), Some("*"));
1320 }
1321 other => panic!("unexpected decode: {:?}", other),
1322 }
1323 }
1324
1325 #[test]
1326 fn encode_decode_get_request_roundtrip() {
1327 let msg = encode_get_request(1, 2, 0x08, &[0xfd, 0x02, 0x00], 2, false);
1328 let mut pkt = PvaPacket::new(&msg);
1329 let cmd = pkt.decode_payload().expect("decoded");
1330 match cmd {
1331 PvaPacketCommand::Op(op) => {
1332 assert_eq!(op.command, 10);
1333 assert_eq!(op.sid_or_cid, 1);
1334 assert_eq!(op.ioid, 2);
1335 assert_eq!(op.subcmd, 0x08);
1336 }
1337 other => panic!("unexpected decode: {:?}", other),
1338 }
1339 }
1340
1341 #[test]
1342 fn encode_decode_put_request_roundtrip() {
1343 let msg = encode_put_request(3, 4, 0x40, &[0xAA], 2, false);
1344 let mut pkt = PvaPacket::new(&msg);
1345 let cmd = pkt.decode_payload().expect("decoded");
1346 match cmd {
1347 PvaPacketCommand::Op(op) => {
1348 assert_eq!(op.command, 11);
1349 assert_eq!(op.sid_or_cid, 3);
1350 assert_eq!(op.ioid, 4);
1351 assert_eq!(op.subcmd, 0x40);
1352 }
1353 other => panic!("unexpected decode: {:?}", other),
1354 }
1355 }
1356
1357 #[test]
1358 fn encode_decode_monitor_request_roundtrip() {
1359 let msg = encode_monitor_request(5, 6, 0x44, &[], 2, false);
1360 let mut pkt = PvaPacket::new(&msg);
1361 let cmd = pkt.decode_payload().expect("decoded");
1362 match cmd {
1363 PvaPacketCommand::Op(op) => {
1364 assert_eq!(op.command, 13);
1365 assert_eq!(op.sid_or_cid, 5);
1366 assert_eq!(op.ioid, 6);
1367 assert_eq!(op.subcmd, 0x44);
1368 }
1369 other => panic!("unexpected decode: {:?}", other),
1370 }
1371 }
1372
1373 #[test]
1374 fn encode_decode_rpc_request_roundtrip() {
1375 let msg = encode_rpc_request(7, 8, 0x00, &[0x80, 0x00], 2, false);
1376 let mut pkt = PvaPacket::new(&msg);
1377 let cmd = pkt.decode_payload().expect("decoded");
1378 match cmd {
1379 PvaPacketCommand::Op(op) => {
1380 assert_eq!(op.command, 20);
1381 assert_eq!(op.sid_or_cid, 7);
1382 assert_eq!(op.ioid, 8);
1383 assert_eq!(op.subcmd, 0x00);
1384 }
1385 other => panic!("unexpected decode: {:?}", other),
1386 }
1387 }
1388
1389 #[test]
1390 fn encode_decode_search_request_roundtrip() {
1391 let seq = 1234;
1392 let cid = 42;
1393 let port = 5076;
1394 let reply_addr = ip_to_bytes(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 20)));
1395 let requests = [(cid, "TEST:PV")];
1396 let msg = encode_search_request(seq, 0x81, port, reply_addr, &requests, 2, false);
1397 let mut pkt = PvaPacket::new(&msg);
1398 let cmd = pkt.decode_payload().expect("decoded");
1399 match cmd {
1400 PvaPacketCommand::Search(payload) => {
1401 assert_eq!(payload.seq, seq);
1402 assert_eq!(payload.mask, 0x81);
1403 assert_eq!(payload.addr, reply_addr);
1404 assert_eq!(payload.port, port);
1405 assert_eq!(payload.protocols, vec!["tcp".to_string()]);
1406 assert_eq!(payload.pv_requests.len(), 1);
1407 assert_eq!(payload.pv_requests[0].0, cid);
1408 assert_eq!(payload.pv_requests[0].1, "TEST:PV");
1409 }
1410 other => panic!("unexpected decode: {:?}", other),
1411 }
1412 }
1413
1414 #[test]
1415 fn socket_addr_from_pva_bytes_decodes_ipv4_mapped() {
1416 let addr = ip_to_bytes(IpAddr::V4(Ipv4Addr::new(10, 20, 30, 40)));
1417 assert_eq!(
1418 socket_addr_from_pva_bytes(addr, 5075),
1419 Some("10.20.30.40:5075".parse().unwrap())
1420 );
1421 }
1422
1423 #[test]
1424 fn socket_addr_from_pva_bytes_decodes_ipv6() {
1425 let addr = ip_to_bytes(IpAddr::V6("2001:db8::1".parse().unwrap()));
1426 assert_eq!(
1427 socket_addr_from_pva_bytes(addr, 5075),
1428 Some("[2001:db8::1]:5075".parse().unwrap())
1429 );
1430 }
1431
1432 #[test]
1433 fn socket_addr_from_pva_bytes_returns_none_for_unspecified() {
1434 assert_eq!(socket_addr_from_pva_bytes([0u8; 16], 5075), None);
1435 }
1436}