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