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 { 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_monitor_data_response_delta(
889 ioid: u32,
890 subcmd: u8,
891 prev_value: &NtPayload,
892 next_value: &NtPayload,
893 filtered_desc: &StructureDesc,
894 version: u8,
895 is_be: bool,
896) -> Option<Vec<u8>> {
897 let (bitset, values) =
898 encode_nt_payload_delta(prev_value, next_value, filtered_desc, is_be)?;
899 let mut payload = Vec::new();
900 payload.extend_from_slice(&if is_be {
901 ioid.to_be_bytes()
902 } else {
903 ioid.to_le_bytes()
904 });
905 payload.push(subcmd);
906 if (subcmd & 0x10) != 0 {
907 payload.extend_from_slice(&encode_status_ok());
908 }
909 payload.extend_from_slice(&bitset);
910 payload.extend_from_slice(&values);
911 payload.extend_from_slice(&encode_size_pva(0, is_be));
912 let mut out = encode_header(true, is_be, false, version, 13, payload.len() as u32);
913 out.extend_from_slice(&payload);
914 Some(out)
915}
916
917pub fn encode_destroy_channel_response(sid: u32, cid: u32, version: u8, is_be: bool) -> Vec<u8> {
918 let mut payload = Vec::new();
919 payload.extend_from_slice(&if is_be {
920 sid.to_be_bytes()
921 } else {
922 sid.to_le_bytes()
923 });
924 payload.extend_from_slice(&if is_be {
925 cid.to_be_bytes()
926 } else {
927 cid.to_le_bytes()
928 });
929 let mut out = encode_header(true, is_be, false, version, 8, payload.len() as u32);
930 out.extend_from_slice(&payload);
931 out
932}
933
934pub fn encode_op_error(
935 command: u8,
936 subcmd: u8,
937 ioid: u32,
938 message: &str,
939 version: u8,
940 is_be: bool,
941) -> Vec<u8> {
942 let mut payload = Vec::new();
943 payload.extend_from_slice(&if is_be {
944 ioid.to_be_bytes()
945 } else {
946 ioid.to_le_bytes()
947 });
948 payload.push(subcmd);
949 payload.push(0x02); payload.extend_from_slice(&encode_string_pva(message, is_be));
951 payload.extend_from_slice(&encode_string_pva("", is_be));
952 let mut out = encode_header(true, is_be, false, version, command, payload.len() as u32);
953 out.extend_from_slice(&payload);
954 out
955}
956
957pub fn encode_beacon(
958 guid: [u8; 12],
959 seq: u8,
960 change_count: u16,
961 addr: [u8; 16],
962 port: u16,
963 protocol: &str,
964 version: u8,
965 is_be: bool,
966) -> Vec<u8> {
967 let mut payload = Vec::new();
968 payload.extend_from_slice(&guid);
969 payload.push(0x00); payload.push(seq);
971 payload.extend_from_slice(&if is_be {
972 change_count.to_be_bytes()
973 } else {
974 change_count.to_le_bytes()
975 });
976 payload.extend_from_slice(&addr);
977 payload.extend_from_slice(&if is_be {
978 port.to_be_bytes()
979 } else {
980 port.to_le_bytes()
981 });
982 payload.extend_from_slice(&encode_string_pva(protocol, is_be));
983 payload.push(0xFF);
987 let mut out = encode_header(true, is_be, false, version, 0, payload.len() as u32);
988 out.extend_from_slice(&payload);
989 out
990}
991
992pub fn ip_to_bytes(ip: IpAddr) -> [u8; 16] {
1001 match ip {
1002 IpAddr::V4(v4) => {
1003 let mut out = [0u8; 16];
1004 out[10] = 0xFF;
1005 out[11] = 0xFF;
1006 out[12..16].copy_from_slice(&v4.octets());
1007 out
1008 }
1009 IpAddr::V6(v6) => v6.octets(),
1010 }
1011}
1012
1013pub fn ip_from_bytes(addr: &[u8; 16]) -> Option<IpAddr> {
1018 if addr.iter().all(|&b| b == 0) {
1019 return None;
1020 }
1021 if addr[0..10].iter().all(|&b| b == 0) && addr[10] == 0xFF && addr[11] == 0xFF {
1023 return Some(IpAddr::V4(Ipv4Addr::new(
1024 addr[12], addr[13], addr[14], addr[15],
1025 )));
1026 }
1027 Some(IpAddr::V6(Ipv6Addr::from(*addr)))
1028}
1029
1030pub fn socket_addr_from_pva_bytes(addr: [u8; 16], port: u16) -> Option<SocketAddr> {
1031 ip_from_bytes(&addr).map(|ip| SocketAddr::new(ip, port))
1032}
1033
1034pub fn format_pva_address(addr: &[u8; 16]) -> String {
1038 match ip_from_bytes(addr) {
1039 Some(ip) => ip.to_string(),
1040 None => "0.0.0.0".to_string(),
1041 }
1042}
1043
1044#[cfg(test)]
1045mod tests {
1046 use super::*;
1047 use crate::epics_decode::{PvaPacket, PvaPacketCommand};
1048
1049 #[test]
1050 fn encode_decode_connection_validation_roundtrip() {
1051 let msg = encode_connection_validation(4096, 2, &["anonymous", "ca"], 2, true);
1052 let mut pkt = PvaPacket::new(&msg);
1053 let cmd = pkt.decode_payload().expect("decoded");
1054 match cmd {
1055 PvaPacketCommand::ConnectionValidation(payload) => {
1056 assert!(payload.is_server);
1057 assert_eq!(payload.buffer_size, 4096);
1058 assert_eq!(payload.introspection_registry_size, 2);
1059 assert_eq!(payload.qos, 0); assert_eq!(payload.authz.as_deref(), Some("anonymous"));
1061 }
1062 other => panic!("unexpected decode: {:?}", other),
1063 }
1064 }
1065
1066 #[test]
1067 fn encode_decode_client_connection_validation_roundtrip() {
1068 let msg = encode_client_connection_validation(
1069 87_040, 32_767, 0, "ca", "alice", "host1", 2, false,
1070 );
1071 let mut pkt = PvaPacket::new(&msg);
1072 let cmd = pkt.decode_payload().expect("decoded");
1073 match cmd {
1074 PvaPacketCommand::ConnectionValidation(payload) => {
1075 assert!(!payload.is_server);
1076 assert_eq!(payload.buffer_size, 87_040);
1077 assert_eq!(payload.introspection_registry_size, 32_767);
1078 assert_eq!(payload.qos, 0);
1079 }
1080 other => panic!("unexpected decode: {:?}", other),
1081 }
1082 }
1083
1084 #[test]
1085 fn encode_decode_search_response_roundtrip() {
1086 let guid = [1u8; 12];
1087 let seq = 42;
1088 let addr = [0u8; 16];
1089 let port = 5075;
1090 let cids = vec![100u32, 101u32];
1091 let msg = encode_search_response(guid, seq, addr, port, "tcp", true, &cids, 2, false);
1092 let mut pkt = PvaPacket::new(&msg);
1093 let cmd = pkt.decode_payload().expect("decoded");
1094 match cmd {
1095 PvaPacketCommand::SearchResponse(payload) => {
1096 assert_eq!(payload.guid, guid);
1097 assert_eq!(payload.seq, seq);
1098 assert_eq!(payload.port, port);
1099 assert!(payload.found);
1100 assert_eq!(payload.cids, cids);
1101 }
1102 other => panic!("unexpected decode: {:?}", other),
1103 }
1104 }
1105
1106 #[test]
1107 fn encode_decode_connection_validated_roundtrip() {
1108 let msg = encode_connection_validated(true, 2, false);
1109 let mut pkt = PvaPacket::new(&msg);
1110 let cmd = pkt.decode_payload().expect("decoded");
1111 match cmd {
1112 PvaPacketCommand::ConnectionValidated(payload) => {
1113 assert!(payload.status.is_none());
1115 }
1116 other => panic!("unexpected decode: {:?}", other),
1117 }
1118 }
1119
1120 #[test]
1121 fn get_data_response_includes_status() {
1122 let nt = NtScalar::from_value(spvirit_types::ScalarValue::F64(1.0));
1123 let msg = encode_op_get_data_response_payload(0x11223344, &NtPayload::Scalar(nt), 2, false);
1124 assert!(msg.len() > 13);
1125 let status_offset = 8 + 4 + 1;
1126 assert_eq!(msg[status_offset], 0xFF);
1127
1128 let mut pkt = PvaPacket::new(&msg);
1129 let cmd = pkt.decode_payload().expect("decoded");
1130 match cmd {
1131 PvaPacketCommand::Op(op) => {
1132 assert_eq!(op.command, 10);
1133 assert_eq!(op.subcmd, 0x00);
1134 assert!(!op.body.is_empty());
1135 }
1136 other => panic!("unexpected decode: {:?}", other),
1137 }
1138 }
1139
1140 #[test]
1141 fn put_get_init_includes_two_descriptors() {
1142 let nt = NtScalar::from_value(spvirit_types::ScalarValue::F64(1.0));
1143 let desc = crate::spvd_encode::nt_scalar_desc(&nt.value);
1144 let msg = encode_op_put_get_init_response(0x01020304, &desc, &desc, 2, false);
1145
1146 let payload = &msg[8..];
1147 assert!(payload.len() > 6);
1148 assert_eq!(payload[5], 0xFF);
1150 let rest = &payload[6..];
1151 let first = rest.first().copied().unwrap_or(0);
1152 assert_eq!(first, 0x80);
1153 let second_pos = rest.iter().skip(1).position(|b| *b == 0x80);
1154 assert!(second_pos.is_some(), "expected second descriptor marker");
1155 }
1156
1157 #[test]
1158 fn put_get_data_includes_status() {
1159 let nt = NtScalar::from_value(spvirit_types::ScalarValue::F64(2.0));
1160 let msg = encode_op_put_get_data_response(0x55667788, &nt, 2, false);
1161 assert!(msg.len() > 13);
1162 let status_offset = 8 + 4 + 1;
1163 assert_eq!(msg[status_offset], 0xFF);
1164 }
1165
1166 #[test]
1167 fn put_getput_response_encodes_subcmd_0x40() {
1168 let nt = NtScalar::from_value(spvirit_types::ScalarValue::F64(2.0));
1169 let msg = encode_op_put_getput_response(0x01020304, &nt, 2, false);
1170 assert!(msg.len() > 13);
1171 let status_offset = 8 + 4 + 1;
1172 assert_eq!(msg[status_offset], 0xFF);
1173 let mut pkt = PvaPacket::new(&msg);
1174 let cmd = pkt.decode_payload().expect("decoded");
1175 match cmd {
1176 PvaPacketCommand::Op(op) => {
1177 assert_eq!(op.command, 11);
1178 assert_eq!(op.subcmd, 0x40);
1179 }
1180 other => panic!("unexpected decode: {:?}", other),
1181 }
1182 }
1183
1184 #[test]
1185 fn encode_get_field_response_roundtrip() {
1186 let desc = StructureDesc {
1187 struct_id: Some("epics:nt/NTScalar:1.0".to_string()),
1188 fields: vec![crate::spvd_decode::FieldDesc {
1189 name: "value".to_string(),
1190 field_type: crate::spvd_decode::FieldType::Scalar(
1191 crate::spvd_decode::TypeCode::String,
1192 ),
1193 }],
1194 };
1195 let msg = encode_get_field_response(11, &desc, 2, false);
1196 let mut pkt = PvaPacket::new(&msg);
1197 let cmd = pkt.decode_payload().expect("decoded");
1198 match cmd {
1199 PvaPacketCommand::GetField(payload) => {
1200 assert!(payload.is_server);
1201 assert_eq!(payload.cid, 11);
1202 assert!(payload.status.is_none());
1203 let intro = payload.introspection.expect("introspection");
1204 assert_eq!(intro.fields.len(), 1);
1205 assert_eq!(intro.fields[0].name, "value");
1206 }
1207 other => panic!("unexpected decode: {:?}", other),
1208 }
1209 }
1210
1211 #[test]
1212 fn encode_get_field_error_roundtrip() {
1213 let msg = encode_get_field_error(7, "listing disabled", 2, false);
1214 let mut pkt = PvaPacket::new(&msg);
1215 let cmd = pkt.decode_payload().expect("decoded");
1216 match cmd {
1217 PvaPacketCommand::GetField(payload) => {
1218 assert!(payload.is_server);
1219 assert_eq!(payload.cid, 7);
1220 let status = payload.status.expect("status");
1221 assert_eq!(status.code, 0x02);
1222 assert_eq!(status.message.as_deref(), Some("listing disabled"));
1223 }
1224 other => panic!("unexpected decode: {:?}", other),
1225 }
1226 }
1227
1228 #[test]
1229 fn encode_decode_create_channel_request_roundtrip() {
1230 let msg = encode_create_channel_request(7, "TEST:PV", 2, false);
1231 let mut pkt = PvaPacket::new(&msg);
1232 let cmd = pkt.decode_payload().expect("decoded");
1233 match cmd {
1234 PvaPacketCommand::CreateChannel(payload) => {
1235 assert!(!payload.is_server);
1236 assert_eq!(payload.channels, vec![(7, "TEST:PV".to_string())]);
1237 }
1238 other => panic!("unexpected decode: {:?}", other),
1239 }
1240 }
1241
1242 #[test]
1243 fn encode_decode_get_field_request_roundtrip() {
1244 let msg = encode_get_field_request(9, 1, Some("*"), 2, false);
1245 let mut pkt = PvaPacket::new(&msg);
1246 let cmd = pkt.decode_payload().expect("decoded");
1247 match cmd {
1248 PvaPacketCommand::GetField(payload) => {
1249 assert!(!payload.is_server);
1250 assert_eq!(payload.sid, Some(9));
1251 assert_eq!(payload.ioid, Some(1));
1252 assert_eq!(payload.field_name.as_deref(), Some("*"));
1253 }
1254 other => panic!("unexpected decode: {:?}", other),
1255 }
1256 }
1257
1258 #[test]
1259 fn encode_decode_get_request_roundtrip() {
1260 let msg = encode_get_request(1, 2, 0x08, &[0xfd, 0x02, 0x00], 2, false);
1261 let mut pkt = PvaPacket::new(&msg);
1262 let cmd = pkt.decode_payload().expect("decoded");
1263 match cmd {
1264 PvaPacketCommand::Op(op) => {
1265 assert_eq!(op.command, 10);
1266 assert_eq!(op.sid_or_cid, 1);
1267 assert_eq!(op.ioid, 2);
1268 assert_eq!(op.subcmd, 0x08);
1269 }
1270 other => panic!("unexpected decode: {:?}", other),
1271 }
1272 }
1273
1274 #[test]
1275 fn encode_decode_put_request_roundtrip() {
1276 let msg = encode_put_request(3, 4, 0x40, &[0xAA], 2, false);
1277 let mut pkt = PvaPacket::new(&msg);
1278 let cmd = pkt.decode_payload().expect("decoded");
1279 match cmd {
1280 PvaPacketCommand::Op(op) => {
1281 assert_eq!(op.command, 11);
1282 assert_eq!(op.sid_or_cid, 3);
1283 assert_eq!(op.ioid, 4);
1284 assert_eq!(op.subcmd, 0x40);
1285 }
1286 other => panic!("unexpected decode: {:?}", other),
1287 }
1288 }
1289
1290 #[test]
1291 fn encode_decode_monitor_request_roundtrip() {
1292 let msg = encode_monitor_request(5, 6, 0x44, &[], 2, false);
1293 let mut pkt = PvaPacket::new(&msg);
1294 let cmd = pkt.decode_payload().expect("decoded");
1295 match cmd {
1296 PvaPacketCommand::Op(op) => {
1297 assert_eq!(op.command, 13);
1298 assert_eq!(op.sid_or_cid, 5);
1299 assert_eq!(op.ioid, 6);
1300 assert_eq!(op.subcmd, 0x44);
1301 }
1302 other => panic!("unexpected decode: {:?}", other),
1303 }
1304 }
1305
1306 #[test]
1307 fn encode_decode_rpc_request_roundtrip() {
1308 let msg = encode_rpc_request(7, 8, 0x00, &[0x80, 0x00], 2, false);
1309 let mut pkt = PvaPacket::new(&msg);
1310 let cmd = pkt.decode_payload().expect("decoded");
1311 match cmd {
1312 PvaPacketCommand::Op(op) => {
1313 assert_eq!(op.command, 20);
1314 assert_eq!(op.sid_or_cid, 7);
1315 assert_eq!(op.ioid, 8);
1316 assert_eq!(op.subcmd, 0x00);
1317 }
1318 other => panic!("unexpected decode: {:?}", other),
1319 }
1320 }
1321
1322 #[test]
1323 fn encode_decode_search_request_roundtrip() {
1324 let seq = 1234;
1325 let cid = 42;
1326 let port = 5076;
1327 let reply_addr = ip_to_bytes(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 20)));
1328 let requests = [(cid, "TEST:PV")];
1329 let msg = encode_search_request(seq, 0x81, port, reply_addr, &requests, 2, false);
1330 let mut pkt = PvaPacket::new(&msg);
1331 let cmd = pkt.decode_payload().expect("decoded");
1332 match cmd {
1333 PvaPacketCommand::Search(payload) => {
1334 assert_eq!(payload.seq, seq);
1335 assert_eq!(payload.mask, 0x81);
1336 assert_eq!(payload.addr, reply_addr);
1337 assert_eq!(payload.port, port);
1338 assert_eq!(payload.protocols, vec!["tcp".to_string()]);
1339 assert_eq!(payload.pv_requests.len(), 1);
1340 assert_eq!(payload.pv_requests[0].0, cid);
1341 assert_eq!(payload.pv_requests[0].1, "TEST:PV");
1342 }
1343 other => panic!("unexpected decode: {:?}", other),
1344 }
1345 }
1346
1347 #[test]
1348 fn socket_addr_from_pva_bytes_decodes_ipv4_mapped() {
1349 let addr = ip_to_bytes(IpAddr::V4(Ipv4Addr::new(10, 20, 30, 40)));
1350 assert_eq!(
1351 socket_addr_from_pva_bytes(addr, 5075),
1352 Some("10.20.30.40:5075".parse().unwrap())
1353 );
1354 }
1355
1356 #[test]
1357 fn socket_addr_from_pva_bytes_decodes_ipv6() {
1358 let addr = ip_to_bytes(IpAddr::V6("2001:db8::1".parse().unwrap()));
1359 assert_eq!(
1360 socket_addr_from_pva_bytes(addr, 5075),
1361 Some("[2001:db8::1]:5075".parse().unwrap())
1362 );
1363 }
1364
1365 #[test]
1366 fn socket_addr_from_pva_bytes_returns_none_for_unspecified() {
1367 assert_eq!(socket_addr_from_pva_bytes([0u8; 16], 5075), None);
1368 }
1369}