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