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