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