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