1use umsh_ulcp::frame::{Cmd, Frame};
15use umsh_ulcp::status::Status;
16
17use crate::envelope::{Envelope, EnvelopeError, Token};
18
19pub const RETRY_MS: u64 = 8_000;
22
23pub const MAX_ATTEMPTS: u32 = 4;
27
28#[derive(Clone, Copy, Debug, PartialEq, Eq)]
30pub enum Failure {
31 TimedOut,
33 UnknownCriticalOption(u16),
36 Malformed,
39 TooLarge,
41 CursorInvalid,
44}
45
46#[derive(Clone, Copy, Debug, PartialEq, Eq)]
48pub enum Step {
49 Send { len: usize },
51 Wait { deadline_ms: u64 },
54 Done(Outcome),
56}
57
58#[derive(Clone, Copy, Debug, PartialEq, Eq)]
60pub enum Outcome {
61 Replied { len: usize },
65 NoResponse,
68 Failed(Failure),
70}
71
72#[derive(Clone, Copy, PartialEq, Eq)]
73enum State {
74 Awaiting {
76 deadline_ms: u64,
77 attempts: u32,
78 },
79 Finished(Outcome),
80}
81
82pub struct Reassembly<'a> {
87 buf: &'a mut [u8],
88 len: usize,
92}
93
94impl<'a> Reassembly<'a> {
95 pub fn new(buf: &'a mut [u8]) -> Self {
96 Self { buf, len: 0 }
97 }
98
99 pub fn resume(buf: &'a mut [u8], len: usize) -> Self {
105 let len = len.min(buf.len());
106 Self { buf, len }
107 }
108
109 pub fn frame(&self) -> &[u8] {
111 &self.buf[..self.len]
112 }
113
114 pub fn len(&self) -> usize {
116 self.len
117 }
118
119 pub fn is_empty(&self) -> bool {
121 self.len == 0
122 }
123
124 pub fn clear(&mut self) {
127 self.len = 0;
128 }
129
130 fn append(&mut self, bytes: &[u8]) -> bool {
131 let Some(end) = self.len.checked_add(bytes.len()) else {
132 return false;
133 };
134 if end > self.buf.len() {
135 return false;
136 }
137 self.buf[self.len..end].copy_from_slice(bytes);
138 self.len = end;
139 true
140 }
141}
142
143pub struct Exchange<const REQUEST: usize> {
145 frame: [u8; REQUEST],
147 frame_len: usize,
148 cursor: [u8; crate::envelope::CURSOR_MAX],
151 cursor_len: usize,
152 token: Token,
153 counter: u16,
156 resets: bool,
159 remaining: Option<u32>,
162 state: State,
163}
164
165impl<const REQUEST: usize> Exchange<REQUEST> {
166 pub fn new(frame: &[u8], seed: u16, now_ms: u64) -> Result<Self, Failure> {
175 if frame.len() > REQUEST {
176 return Err(Failure::TooLarge);
177 }
178 let resets = Frame::parse(frame)
179 .ok()
180 .and_then(|parsed| parsed.command())
181 .is_some_and(|cmd| {
182 matches!(
183 cmd,
184 Cmd::Reset | Cmd::Restore | Cmd::FactoryReset | Cmd::Reboot
185 )
186 });
187
188 let mut stored = [0u8; REQUEST];
189 stored[..frame.len()].copy_from_slice(frame);
190 Ok(Self {
191 frame: stored,
192 frame_len: frame.len(),
193 cursor: [0; crate::envelope::CURSOR_MAX],
194 cursor_len: 0,
195 token: seed.to_be_bytes(),
196 counter: seed,
197 resets,
198 remaining: None,
199 state: State::Awaiting {
200 deadline_ms: now_ms,
201 attempts: 0,
202 },
203 })
204 }
205
206 pub fn token(&self) -> Token {
209 self.token
210 }
211
212 pub fn counter(&self) -> u16 {
221 self.counter
222 }
223
224 pub fn remaining(&self) -> Option<u32> {
227 self.remaining
228 }
229
230 pub fn deadline_ms(&self) -> Option<u64> {
233 match self.state {
234 State::Awaiting { deadline_ms, .. } => Some(deadline_ms),
235 State::Finished(_) => None,
236 }
237 }
238
239 pub fn poll(&mut self, now_ms: u64, out: &mut [u8]) -> Step {
246 let (deadline_ms, attempts) = match self.state {
247 State::Finished(outcome) => return Step::Done(outcome),
248 State::Awaiting {
249 deadline_ms,
250 attempts,
251 } => (deadline_ms, attempts),
252 };
253
254 if now_ms < deadline_ms {
255 return Step::Wait { deadline_ms };
256 }
257 if attempts >= MAX_ATTEMPTS {
258 return self.finish(Outcome::Failed(Failure::TimedOut));
259 }
260
261 let mut request = Envelope::new(self.token, &self.frame[..self.frame_len]);
262 if self.cursor_len > 0 {
263 request = request.with_cursor(&self.cursor[..self.cursor_len]);
264 }
265 let Ok(len) = request.encode(out) else {
266 return self.finish(Outcome::Failed(Failure::TooLarge));
267 };
268
269 self.state = State::Awaiting {
270 deadline_ms: now_ms + RETRY_MS,
271 attempts: attempts + 1,
272 };
273 Step::Send { len }
274 }
275
276 pub fn delivered(&mut self) -> Step {
282 self.finish(Outcome::NoResponse)
283 }
284
285 pub fn expects_response(&self) -> bool {
294 !self.resets
295 }
296
297 pub fn receive(
305 &mut self,
306 payload: &[u8],
307 reassembly: &mut Reassembly<'_>,
308 now_ms: u64,
309 out: &mut [u8],
310 ) -> Option<Step> {
311 if matches!(self.state, State::Finished(_)) {
312 return None;
313 }
314
315 let &[token0, token1, ..] = payload else {
319 return None;
320 };
321 if [token0, token1] != self.token {
322 return None;
323 }
324
325 let response = match Envelope::parse(payload) {
326 Ok(response) => response,
327 Err(EnvelopeError::UnknownCritical(number)) => {
328 return Some(self.finish(Outcome::Failed(Failure::UnknownCriticalOption(number))));
329 }
330 Err(_) => return Some(self.finish(Outcome::Failed(Failure::Malformed))),
331 };
332
333 let Ok(parsed) = Frame::parse(response.frame) else {
334 return Some(self.finish(Outcome::Failed(Failure::Malformed)));
335 };
336
337 if self.cursor_len > 0 && reported_status(&parsed) == Some(Status::CURSOR_INVALID) {
340 return Some(self.finish(Outcome::Failed(Failure::CursorInvalid)));
341 }
342
343 self.remaining = response.remaining;
344
345 let contribution = if reassembly.len == 0 {
349 response.frame
350 } else {
351 crate::fragment::trailing(response.frame)
352 };
353 if !reassembly.append(contribution) {
354 return Some(self.finish(Outcome::Failed(Failure::TooLarge)));
355 }
356
357 let Some(cursor) = response.cursor else {
358 let len = reassembly.len;
359 return Some(self.finish(Outcome::Replied { len }));
360 };
361
362 let stalled = contribution.is_empty();
365 self.cursor[..cursor.len()].copy_from_slice(cursor);
366 self.cursor_len = cursor.len();
367 self.counter = self.counter.wrapping_add(1);
368 self.token = self.counter.to_be_bytes();
369
370 if stalled {
371 let deadline_ms = now_ms + RETRY_MS;
376 self.state = State::Awaiting {
377 deadline_ms,
378 attempts: 0,
379 };
380 return Some(Step::Wait { deadline_ms });
381 }
382
383 self.state = State::Awaiting {
384 deadline_ms: now_ms,
385 attempts: 0,
386 };
387 Some(self.poll(now_ms, out))
388 }
389
390 fn finish(&mut self, outcome: Outcome) -> Step {
391 self.state = State::Finished(outcome);
392 Step::Done(outcome)
393 }
394}
395
396fn reported_status(parsed: &Frame<'_>) -> Option<Status> {
398 if parsed.command() != Some(Cmd::PropIs) {
399 return None;
400 }
401 let (key, consumed) = umsh_ulcp::pui::decode(parsed.payload).ok()?;
402 if key != umsh_ulcp::ids::prop::LAST_STATUS {
403 return None;
404 }
405 let (status, _) = umsh_ulcp::pui::decode(&parsed.payload[consumed..]).ok()?;
406 Some(Status(status))
407}
408
409#[cfg(test)]
410mod tests {
411 use super::*;
412 use crate::device::{DeviceEngine, Dispatch, Ingress, Produced, PublicKey};
413 use umsh_ulcp::frame;
414 use umsh_ulcp::ids::prop;
415
416 const PAYLOAD: usize = 180;
417 const ADMIN: PublicKey = [0xAA; 32];
418 type Device = DeviceEngine<PAYLOAD, 2>;
419 type Admin = Exchange<64>;
420
421 fn get(key: u32, buf: &mut [u8]) -> usize {
422 frame::prop_get(buf, 0, key).expect("encode")
423 }
424
425 #[test]
426 fn the_first_poll_hands_out_a_request_and_the_next_one_waits() {
427 let mut buf = [0u8; 8];
428 let frame_len = get(prop::CAPS, &mut buf);
429 let frame = &buf[..frame_len];
430 let mut exchange = Admin::new(frame, 0x2A, 1_000).expect("begin");
431
432 let mut out = [0u8; PAYLOAD];
433 let Step::Send { len } = exchange.poll(1_000, &mut out) else {
434 panic!("expected a request");
435 };
436 let request = Envelope::parse(&out[..len]).expect("envelope");
437 assert_eq!(request.token, exchange.token());
438 assert_eq!(request.cursor, None);
439 assert_eq!(request.frame, frame);
440
441 assert_eq!(
442 exchange.poll(1_001, &mut out),
443 Step::Wait {
444 deadline_ms: 1_000 + RETRY_MS
445 }
446 );
447 }
448
449 #[test]
450 fn a_retransmission_repeats_the_request_under_the_same_token() {
451 let mut buf = [0u8; 8];
452 let frame_len = get(prop::CAPS, &mut buf);
453 let frame = &buf[..frame_len];
454 let mut exchange = Admin::new(frame, 1, 0).expect("begin");
455
456 let mut first = [0u8; PAYLOAD];
457 let Step::Send { len } = exchange.poll(0, &mut first) else {
458 panic!("expected a request");
459 };
460 let first = first[..len].to_vec();
461
462 let mut again = [0u8; PAYLOAD];
463 let Step::Send { len } = exchange.poll(RETRY_MS, &mut again) else {
464 panic!("expected a retransmission");
465 };
466 assert_eq!(&again[..len], &first[..]);
467 }
468
469 #[test]
470 fn an_unanswered_exchange_times_out_after_its_attempts() {
471 let mut buf = [0u8; 8];
472 let frame_len = get(prop::CAPS, &mut buf);
473 let frame = &buf[..frame_len];
474 let mut exchange = Admin::new(frame, 1, 0).expect("begin");
475 let mut out = [0u8; PAYLOAD];
476
477 for attempt in 0..MAX_ATTEMPTS {
478 let now = u64::from(attempt) * RETRY_MS;
479 assert!(matches!(exchange.poll(now, &mut out), Step::Send { .. }));
480 }
481 assert_eq!(
482 exchange.poll(u64::from(MAX_ATTEMPTS) * RETRY_MS, &mut out),
483 Step::Done(Outcome::Failed(Failure::TimedOut))
484 );
485 }
486
487 #[test]
488 fn a_response_for_another_exchange_is_not_this_ones() {
489 let mut buf = [0u8; 8];
490 let frame_len = get(prop::CAPS, &mut buf);
491 let frame = &buf[..frame_len];
492 let mut exchange = Admin::new(frame, 1, 0).expect("begin");
493 let mut out = [0u8; PAYLOAD];
494 exchange.poll(0, &mut out);
495
496 let mut storage = [0u8; 256];
497 let mut reassembly = Reassembly::new(&mut storage);
498 let mut stranger = [0u8; PAYLOAD];
499 let len = Envelope::new([0xFF, 0xFF], &[0x80, 0x06])
500 .encode(&mut stranger)
501 .unwrap();
502 assert_eq!(
503 exchange.receive(&stranger[..len], &mut reassembly, 0, &mut out),
504 None
505 );
506 }
507
508 #[test]
509 fn a_reset_expects_no_response() {
510 let mut buf = [0u8; 8];
511 for len in [
512 frame::reset(&mut buf, 0).unwrap(),
513 frame::factory_reset(&mut buf, 0).unwrap(),
514 frame::reboot(&mut buf, 0).unwrap(),
515 ] {
516 let mut exchange = Admin::new(&buf[..len], 1, 0).expect("begin");
517 assert!(!exchange.expects_response());
518 assert_eq!(exchange.delivered(), Step::Done(Outcome::NoResponse));
519 }
520
521 let len = get(prop::CAPS, &mut buf);
522 assert!(Admin::new(&buf[..len], 1, 0).unwrap().expects_response());
523 }
524
525 fn converse(request: &[u8], value: &[u8], chunk: usize) -> (Outcome, Vec<u8>) {
529 let mut device = Device::new(0x5AA5);
530 let mut admin = Admin::new(request, 7, 0).expect("begin");
531 let mut storage = [0u8; 1024];
532 let mut reassembly = Reassembly::new(&mut storage);
533 let mut wire = [0u8; PAYLOAD];
534 let mut now = 0u64;
535
536 let mut step = admin.poll(now, &mut wire);
537 while let Step::Send { len } = step {
538 let mut response = [0u8; PAYLOAD];
539 let Ingress::Dispatch(Dispatch { resume, budget, .. }) =
540 device.begin(&ADMIN, &wire[..len], 1, now, &mut response)
541 else {
542 panic!("expected a dispatch");
543 };
544
545 let resume = resume as usize;
547 let mut frame_buf = [0u8; PAYLOAD];
548 let head = frame::prop_is(&mut frame_buf, 0, prop::CAPS, &[]).unwrap();
549 let room = budget.saturating_sub(head).min(chunk);
550 let end = (resume + room).min(value.len());
551 let fragment = &value[resume..end];
552 let len = frame::prop_is(&mut frame_buf, 0, prop::CAPS, fragment).unwrap();
553 let remaining = (value.len() - end) as u32;
554 let len = device
555 .complete(
556 Produced::fragment(&frame_buf[..len], fragment.len() as u32, remaining),
557 &mut response,
558 )
559 .expect("complete")
560 .expect("a response");
561
562 now += 100;
563 step = admin
564 .receive(&response[..len], &mut reassembly, now, &mut wire)
565 .expect("this exchange's response");
566 }
567
568 let Step::Done(outcome) = step else {
569 panic!("expected a finished exchange, got {step:?}");
570 };
571 (outcome, reassembly.frame().to_vec())
572 }
573
574 #[test]
575 fn a_read_that_fits_one_payload_finishes_in_one_exchange() {
576 let mut buf = [0u8; 8];
577 let frame_len = get(prop::CAPS, &mut buf);
578 let frame = &buf[..frame_len];
579 let value: Vec<u8> = (0..16u8).collect();
580
581 let (outcome, assembled) = converse(frame, &value, 256);
582 let Outcome::Replied { len } = outcome else {
583 panic!("expected a reply, got {outcome:?}");
584 };
585 assert_eq!(len, assembled.len());
586 assert_eq!(crate::fragment::trailing(&assembled), &value[..]);
587 }
588
589 #[test]
590 fn a_read_spanning_several_exchanges_reassembles_to_the_whole_value() {
591 let mut buf = [0u8; 8];
592 let frame_len = get(prop::CAPS, &mut buf);
593 let frame = &buf[..frame_len];
594 let value: Vec<u8> = (0..500u32).map(|index| index as u8).collect();
595
596 for chunk in [1, 7, 64, 128] {
597 let (outcome, assembled) = converse(frame, &value, chunk);
598 assert!(
599 matches!(outcome, Outcome::Replied { .. }),
600 "chunk {chunk}: {outcome:?}"
601 );
602 assert_eq!(
603 crate::fragment::trailing(&assembled),
604 &value[..],
605 "chunk {chunk}"
606 );
607 }
608 }
609
610 #[test]
611 fn each_continuation_carries_a_fresh_token_and_the_cursor_verbatim() {
612 let mut buf = [0u8; 8];
613 let frame_len = get(prop::CAPS, &mut buf);
614 let frame = &buf[..frame_len];
615 let mut device = Device::new(1);
616 let mut admin = Admin::new(frame, 100, 0).expect("begin");
617 let mut storage = [0u8; 1024];
618 let mut reassembly = Reassembly::new(&mut storage);
619 let mut wire = [0u8; PAYLOAD];
620
621 let Step::Send { len } = admin.poll(0, &mut wire) else {
622 panic!("expected a request");
623 };
624 let first_token = Envelope::parse(&wire[..len]).unwrap().token;
625
626 let mut response = [0u8; PAYLOAD];
627 assert!(matches!(
628 device.begin(&ADMIN, &wire[..len], 1, 0, &mut response),
629 Ingress::Dispatch(_)
630 ));
631 let mut frame_buf = [0u8; 32];
632 let reply = frame::prop_is(&mut frame_buf, 0, prop::CAPS, &[1, 2, 3, 4]).unwrap();
633 let len = device
634 .complete(
635 Produced::fragment(&frame_buf[..reply], 4, 12),
636 &mut response,
637 )
638 .unwrap()
639 .unwrap();
640 let issued = Envelope::parse(&response[..len]).unwrap();
641 let cursor = issued.cursor.expect("a cursor").to_vec();
642 assert_eq!(admin.remaining(), None);
643
644 let Some(Step::Send { len }) =
645 admin.receive(&response[..len], &mut reassembly, 0, &mut wire)
646 else {
647 panic!("expected a continuation");
648 };
649 let continuation = Envelope::parse(&wire[..len]).unwrap();
650 assert_ne!(continuation.token, first_token);
651 assert_eq!(continuation.cursor, Some(&cursor[..]));
652 assert_eq!(continuation.frame, frame, "the read is repeated verbatim");
653 assert_eq!(admin.remaining(), Some(12));
654 assert_eq!(
655 admin.counter(),
656 101,
657 "the counter reports the continuation's token, so a successor \
658 seeded from it cannot reissue one the device has answered"
659 );
660 }
661
662 #[test]
663 fn a_refused_cursor_ends_the_exchange_so_the_caller_can_start_over() {
664 let mut buf = [0u8; 8];
665 let frame_len = get(prop::CAPS, &mut buf);
666 let frame = &buf[..frame_len];
667 let mut device = Device::new(1);
668 let mut admin = Admin::new(frame, 5, 0).expect("begin");
669 let mut storage = [0u8; 1024];
670 let mut reassembly = Reassembly::new(&mut storage);
671 let mut wire = [0u8; PAYLOAD];
672 let mut response = [0u8; PAYLOAD];
673
674 let Step::Send { len } = admin.poll(0, &mut wire) else {
676 panic!("expected a request");
677 };
678 assert!(matches!(
679 device.begin(&ADMIN, &wire[..len], 1, 0, &mut response),
680 Ingress::Dispatch(_)
681 ));
682 let mut frame_buf = [0u8; 32];
683 let reply = frame::prop_is(&mut frame_buf, 0, prop::CAPS, &[1, 2]).unwrap();
684 let len = device
685 .complete(Produced::fragment(&frame_buf[..reply], 2, 8), &mut response)
686 .unwrap()
687 .unwrap();
688 let Some(Step::Send { len }) =
689 admin.receive(&response[..len], &mut reassembly, 0, &mut wire)
690 else {
691 panic!("expected a continuation");
692 };
693
694 let Ingress::Respond { len } = device.begin(&ADMIN, &wire[..len], 2, 0, &mut response)
696 else {
697 panic!("expected a refusal");
698 };
699 assert_eq!(
700 admin.receive(&response[..len], &mut reassembly, 0, &mut wire),
701 Some(Step::Done(Outcome::Failed(Failure::CursorInvalid)))
702 );
703 }
704
705 #[test]
706 fn an_empty_fragment_paces_the_next_request_rather_than_spinning() {
707 let mut buf = [0u8; 8];
708 let frame_len = get(prop::CAPS, &mut buf);
709 let frame = &buf[..frame_len];
710 let mut device = Device::new(1);
711 let mut admin = Admin::new(frame, 11, 0).expect("begin");
712 let mut storage = [0u8; 256];
713 let mut reassembly = Reassembly::new(&mut storage);
714 let mut wire = [0u8; PAYLOAD];
715 let mut response = [0u8; PAYLOAD];
716 let mut frame_buf = [0u8; 32];
717
718 let Step::Send { len } = admin.poll(0, &mut wire) else {
719 panic!("expected a request");
720 };
721 assert!(matches!(
722 device.begin(&ADMIN, &wire[..len], 1, 0, &mut response),
723 Ingress::Dispatch(_)
724 ));
725 let reply = frame::prop_is(&mut frame_buf, 0, prop::CAPS, &[1, 2]).unwrap();
726 let len = device
727 .complete(Produced::fragment(&frame_buf[..reply], 2, 4), &mut response)
728 .unwrap()
729 .unwrap();
730 let Some(Step::Send { len }) =
731 admin.receive(&response[..len], &mut reassembly, 0, &mut wire)
732 else {
733 panic!("expected a continuation");
734 };
735
736 assert!(matches!(
739 device.begin(&ADMIN, &wire[..len], 1, 0, &mut response),
740 Ingress::Dispatch(_)
741 ));
742 let reply = frame::prop_is(&mut frame_buf, 0, prop::CAPS, &[]).unwrap();
743 let len = device
744 .complete(Produced::fragment(&frame_buf[..reply], 0, 4), &mut response)
745 .unwrap()
746 .unwrap();
747 assert_eq!(
748 admin.receive(&response[..len], &mut reassembly, 100, &mut wire),
749 Some(Step::Wait {
750 deadline_ms: 100 + RETRY_MS
751 })
752 );
753 assert_eq!(crate::fragment::trailing(reassembly.frame()), &[1u8, 2][..]);
755 assert!(matches!(
756 admin.poll(100 + RETRY_MS, &mut wire),
757 Step::Send { .. }
758 ));
759 }
760
761 #[test]
762 fn a_read_larger_than_the_reassembly_buffer_fails_rather_than_truncating() {
763 let mut buf = [0u8; 8];
764 let frame_len = get(prop::CAPS, &mut buf);
765 let frame = &buf[..frame_len];
766 let mut device = Device::new(1);
767 let mut admin = Admin::new(frame, 5, 0).expect("begin");
768 let mut storage = [0u8; 24];
769 let mut reassembly = Reassembly::new(&mut storage);
770 let mut wire = [0u8; PAYLOAD];
771 let mut response = [0u8; PAYLOAD];
772 let mut frame_buf = [0u8; 64];
773
774 let mut step = admin.poll(0, &mut wire);
775 for _ in 0..8 {
776 let Step::Send { len } = step else { break };
777 assert!(matches!(
778 device.begin(&ADMIN, &wire[..len], 1, 0, &mut response),
779 Ingress::Dispatch(_)
780 ));
781 let reply = frame::prop_is(&mut frame_buf, 0, prop::CAPS, &[0; 16]).unwrap();
782 let len = device
783 .complete(
784 Produced::fragment(&frame_buf[..reply], 16, 999),
785 &mut response,
786 )
787 .unwrap()
788 .unwrap();
789 step = admin
790 .receive(&response[..len], &mut reassembly, 0, &mut wire)
791 .expect("this exchange's response");
792 }
793 assert_eq!(step, Step::Done(Outcome::Failed(Failure::TooLarge)));
794 }
795
796 #[test]
797 fn an_unknown_critical_option_in_a_response_fails_the_exchange() {
798 let mut buf = [0u8; 8];
799 let frame_len = get(prop::CAPS, &mut buf);
800 let frame = &buf[..frame_len];
801 let mut admin = Admin::new(frame, 0x0102, 0).expect("begin");
802 let mut wire = [0u8; PAYLOAD];
803 admin.poll(0, &mut wire);
804 let token = admin.token();
805
806 let mut response = [0u8; PAYLOAD];
807 response[0] = token[0];
808 response[1] = token[1];
809 let len = {
810 let mut enc = umsh_core::options::OptionEncoder::new(&mut response[2..]);
811 enc.put(5, &[0]).unwrap();
812 enc.end_marker().unwrap();
813 2 + enc.finish()
814 };
815
816 let mut storage = [0u8; 64];
817 let mut reassembly = Reassembly::new(&mut storage);
818 assert_eq!(
819 admin.receive(&response[..len], &mut reassembly, 0, &mut wire),
820 Some(Step::Done(Outcome::Failed(Failure::UnknownCriticalOption(
821 5
822 ))))
823 );
824 }
825
826 #[test]
827 fn a_response_whose_frame_does_not_parse_fails_the_exchange() {
828 let mut buf = [0u8; 8];
829 let frame_len = get(prop::CAPS, &mut buf);
830 let frame = &buf[..frame_len];
831 let mut admin = Admin::new(frame, 3, 0).expect("begin");
832 let mut wire = [0u8; PAYLOAD];
833 admin.poll(0, &mut wire);
834
835 let mut response = [0u8; PAYLOAD];
836 let len = Envelope::new(admin.token(), &[0x00])
837 .encode(&mut response)
838 .unwrap();
839 let mut storage = [0u8; 64];
840 let mut reassembly = Reassembly::new(&mut storage);
841 assert_eq!(
842 admin.receive(&response[..len], &mut reassembly, 0, &mut wire),
843 Some(Step::Done(Outcome::Failed(Failure::Malformed)))
844 );
845 }
846
847 #[test]
848 fn a_finished_exchange_ignores_everything_that_arrives_after() {
849 let mut buf = [0u8; 8];
850 let frame_len = get(prop::CAPS, &mut buf);
851 let frame = &buf[..frame_len];
852 let mut admin = Admin::new(frame, 3, 0).expect("begin");
853 let mut wire = [0u8; PAYLOAD];
854 admin.poll(0, &mut wire);
855
856 let mut response = [0u8; PAYLOAD];
857 let mut frame_buf = [0u8; 16];
858 let reply = frame::prop_is(&mut frame_buf, 0, prop::CAPS, &[9]).unwrap();
859 let len = Envelope::new(admin.token(), &frame_buf[..reply])
860 .encode(&mut response)
861 .unwrap();
862
863 let mut storage = [0u8; 64];
864 let mut reassembly = Reassembly::new(&mut storage);
865 assert!(matches!(
866 admin.receive(&response[..len], &mut reassembly, 0, &mut wire),
867 Some(Step::Done(Outcome::Replied { .. }))
868 ));
869 assert_eq!(
870 admin.receive(&response[..len], &mut reassembly, 0, &mut wire),
871 None
872 );
873 assert!(matches!(
874 admin.poll(1_000_000, &mut wire),
875 Step::Done(Outcome::Replied { .. })
876 ));
877 }
878
879 #[test]
880 fn a_multi_get_reassembles_into_one_are_frame() {
881 let mut buf = [0u8; 16];
882 let len = frame::prop_multi_get(&mut buf, 0, &[prop::CAPS, prop::DEV_ADMINS]).unwrap();
883 let request = &buf[..len];
884
885 let mut device = Device::new(1);
886 let mut admin = Admin::new(request, 9, 0).expect("begin");
887 let mut storage = [0u8; 512];
888 let mut reassembly = Reassembly::new(&mut storage);
889 let mut wire = [0u8; PAYLOAD];
890 let mut response = [0u8; PAYLOAD];
891
892 let mut whole = [0u8; 128];
894 let whole_len = {
895 let mut writer = frame::prop_are(&mut whole, 0).unwrap();
896 for index in 0..4u32 {
897 writer
898 .write_entry(prop::CAPS + index, &[index as u8; 8])
899 .unwrap();
900 }
901 writer.finish()
902 };
903 let entries = &whole[2..whole_len];
905
906 let mut served = 0usize;
907 let mut step = admin.poll(0, &mut wire);
908 while let Step::Send { len } = step {
909 assert!(matches!(
910 device.begin(&ADMIN, &wire[..len], 1, 0, &mut response),
911 Ingress::Dispatch(_)
912 ));
913 let end = (served + 22).min(entries.len());
914 let mut frame_buf = [0u8; 64];
915 let reply = {
916 let mut writer = frame::prop_are(&mut frame_buf, 0).unwrap();
917 writer.write_bytes(&entries[served..end]).unwrap();
918 writer.finish()
919 };
920 let produced = (end - served) as u32;
921 let remaining = (entries.len() - end) as u32;
922 served = end;
923 let len = device
924 .complete(
925 Produced::fragment(&frame_buf[..reply], produced, remaining),
926 &mut response,
927 )
928 .unwrap()
929 .unwrap();
930 step = admin
931 .receive(&response[..len], &mut reassembly, 0, &mut wire)
932 .expect("this exchange's response");
933 }
934
935 assert!(matches!(step, Step::Done(Outcome::Replied { .. })));
936 assert_eq!(reassembly.frame(), &whole[..whole_len]);
937 }
938}