1use super::io::check_deadline;
7use super::{DEFAULT_WRITE_TIMEOUT, Read, Write};
8use std::fmt;
9use std::io;
10use std::sync::{Arc, Condvar, Mutex};
11use std::time::{Duration, Instant};
12use tracing::debug;
13
14pub struct Stream<R: Read, W: Write> {
33 io: Option<(R, W)>, closer: Closer,
35 timeout: Duration, }
37
38impl<R: Read, W: Write> Stream<R, W> {
39 pub fn new(reader: R, writer: W, shutdown: impl FnOnce() + Send + 'static) -> Self {
41 Self {
42 io: Some((reader, writer)),
43 closer: Closer::new(shutdown),
44 timeout: DEFAULT_WRITE_TIMEOUT,
45 }
46 }
47
48 pub fn set_write_timeout(mut self, timeout: Duration) -> Self {
58 self.timeout = timeout;
59 self
60 }
61
62 pub fn closer(&self) -> Closer {
64 self.closer.clone()
65 }
66
67 pub fn close(&self) {
70 self.closer.close();
71 }
72
73 pub(crate) fn into_parts(mut self) -> (R, W, Closer, Duration) {
75 let (reader, writer) = self.io.take().expect("stream consumed once");
76 (reader, writer, self.closer.clone(), self.timeout)
77 }
78}
79
80impl<R: Read, W: Write> Drop for Stream<R, W> {
81 fn drop(&mut self) {
82 if self.io.is_some() {
83 self.close();
84 }
85 }
86}
87
88impl<R: Read, W: Write> fmt::Debug for Stream<R, W> {
89 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 f.debug_struct("Stream")
92 .field("timeout", &self.timeout)
93 .field("closer", &self.closer)
94 .finish_non_exhaustive()
95 }
96}
97
98#[derive(Clone)]
100pub struct Closer(Arc<Shutdown>);
101
102struct Shutdown {
106 state: Mutex<State>,
107 changed: Condvar,
108}
109
110#[derive(Clone, Copy, Debug, PartialEq, Eq)]
113enum Phase {
114 Open,
116 Closing,
118 Closed,
120}
121
122struct State {
126 phase: Phase,
127 active: usize, action: Option<Box<dyn FnOnce() + Send>>,
129}
130
131impl Closer {
132 pub(super) fn new(shutdown: impl FnOnce() + Send + 'static) -> Self {
134 Self(Arc::new(Shutdown {
135 state: Mutex::new(State {
136 phase: Phase::Open,
137 active: 0,
138 action: Some(Box::new(shutdown)),
139 }),
140 changed: Condvar::new(),
141 }))
142 }
143
144 pub fn close(&self) {
154 let action = {
156 let mut state = self.0.state.lock().expect("stream state not poisoned");
157 loop {
158 match state.phase {
159 Phase::Closed => return,
161
162 Phase::Closing => {
164 state = self
165 .0
166 .changed
167 .wait(state)
168 .expect("stream state not poisoned");
169 }
170
171 Phase::Open => {
173 debug!("closing wire stream");
174 state.phase = Phase::Closing;
175 break state.action.take().expect("shutdown called once");
176 }
177 }
178 }
179 };
180
181 action();
183
184 let mut state = self.0.state.lock().expect("stream state not poisoned");
186 while state.active != 0 {
187 state = self
188 .0
189 .changed
190 .wait(state)
191 .expect("stream state not poisoned");
192 }
193
194 state.phase = Phase::Closed;
196 self.0.changed.notify_all();
197 }
198
199 fn enter(&self) -> Option<Activity<'_>> {
201 let mut state = self.0.state.lock().expect("stream state not poisoned");
202 if state.phase != Phase::Open {
203 return None;
204 }
205 state.active += 1;
206 Some(Activity(self))
207 }
208}
209
210impl fmt::Debug for Closer {
211 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214 let mut closer = f.debug_struct("Closer");
215 match self.0.state.try_lock() {
216 Ok(state) => closer
217 .field("phase", &state.phase)
218 .field("active", &state.active),
219 Err(_) => closer.field("state", &format_args!("<locked>")),
220 };
221 closer.finish()
222 }
223}
224
225struct Activity<'a>(&'a Closer);
228
229impl Drop for Activity<'_> {
230 fn drop(&mut self) {
231 let mut state = self.0.0.state.lock().expect("stream state not poisoned");
232 state.active -= 1;
233 if state.active == 0 {
234 self.0.0.changed.notify_all();
235 }
236 }
237}
238
239pub(super) struct ReadHalf<R> {
241 pub(super) inner: R,
242 pub(super) closer: Closer,
243}
244
245impl<R: Read> ReadHalf<R> {
246 pub(super) fn read(&mut self, buf: &mut [u8], deadline: Option<Instant>) -> io::Result<usize> {
251 loop {
252 if let Some(deadline) = deadline {
254 check_deadline(deadline)?;
255 }
256 let result = {
258 let Some(_active) = self.closer.enter() else {
259 return Ok(0);
260 };
261 self.inner.set_read_deadline(deadline)?;
262 self.inner.read(buf)
263 };
264 match result {
266 Err(err)
267 if matches!(
268 err.kind(),
269 io::ErrorKind::TimedOut | io::ErrorKind::Interrupted
270 ) =>
271 {
272 continue;
273 }
274 result => return result,
275 }
276 }
277 }
278}
279
280pub(super) struct WriteHalf<W> {
282 pub(super) inner: W,
283 pub(super) closer: Closer,
284}
285
286impl<W: Write> WriteHalf<W> {
287 pub(super) fn write(&mut self, mut bytes: &[u8], deadline: Instant) -> io::Result<()> {
297 check_deadline(deadline)?;
299
300 {
302 let _active = self
303 .closer
304 .enter()
305 .ok_or_else(|| io::Error::new(io::ErrorKind::NotConnected, "stream closed"))?;
306 self.inner.set_write_deadline(deadline)?;
307 }
308 while !bytes.is_empty() {
310 check_deadline(deadline)?;
312
313 let result = {
315 let _active = self
316 .closer
317 .enter()
318 .ok_or_else(|| io::Error::new(io::ErrorKind::NotConnected, "stream closed"))?;
319 self.inner.write(bytes)
320 };
321 match result {
322 Ok(0) => return Err(io::ErrorKind::WriteZero.into()),
323 Ok(n) => bytes = &bytes[n..],
324 Err(err) if err.kind() == io::ErrorKind::Interrupted => continue,
325 Err(err) => return Err(err),
326 }
327 }
328 check_deadline(deadline)?;
330
331 let _active = self
332 .closer
333 .enter()
334 .ok_or_else(|| io::Error::new(io::ErrorKind::NotConnected, "stream closed"))?;
335 self.inner.flush()
336 }
337}
338
339#[cfg(test)]
340#[cfg_attr(coverage_nightly, coverage(off))]
341mod tests {
342 use super::*;
343 use crate::transport::Client;
344 use crate::transport::testing::Memory;
345 use std::sync::atomic::{AtomicUsize, Ordering};
346 use std::sync::mpsc;
347 use std::thread;
348 use std::time::Duration;
349
350 const PATIENCE: Duration = Duration::from_secs(5);
351
352 #[test]
355 fn test_debug_capabilities() {
356 use crate::transport::{Attestation, Event, Roots, Sender, Server};
357
358 fn printable<T: fmt::Debug>() {}
360 printable::<Stream<Box<dyn Read>, Box<dyn Write>>>();
361 printable::<Closer>();
362 printable::<Client<Box<dyn Read>, Box<dyn Write>>>();
363 printable::<Server<Box<dyn Read>, Box<dyn Write>, Attestation>>();
364 printable::<Sender<Box<dyn Write>>>();
365 printable::<Event<Box<dyn Write>>>();
366 printable::<Attestation>();
367 printable::<Roots<'static>>();
368 }
369
370 #[test]
373 fn test_memory_reader_keeps_transport_deadline() {
374 let (host, ark) = crate::memory::duplex(4);
375 let (_ark_read, mut ark_write) = ark.into_halves();
376 std::io::Write::write_all(&mut ark_write, b"abc").unwrap();
377 let (reader, _writer, closer, _) = host.into_parts();
378 let mut reader = ReadHalf {
379 inner: reader,
380 closer,
381 };
382 let mut bytes = [0; 3];
383 assert_eq!(
384 reader
385 .read(&mut bytes, Some(Instant::now()))
386 .unwrap_err()
387 .kind(),
388 io::ErrorKind::TimedOut
389 );
390 assert_eq!(bytes, [0; 3]);
391 assert_eq!(reader.read(&mut bytes, None).unwrap(), 3);
392 assert_eq!(&bytes, b"abc");
393 }
394
395 struct Adapter {
398 entered: mpsc::Sender<()>,
399 released: mpsc::Receiver<()>,
400 fails: bool,
401 deadline: Option<Instant>,
402 }
403
404 impl Adapter {
405 fn wait(&self, deadline: Option<Instant>) -> io::Result<()> {
407 self.entered.send(()).unwrap();
408 match deadline {
409 Some(deadline) => self
410 .released
411 .recv_timeout(deadline.saturating_duration_since(Instant::now())),
412 None => self
413 .released
414 .recv()
415 .map_err(|_| mpsc::RecvTimeoutError::Disconnected),
416 }
417 .map_err(|_| io::Error::from(io::ErrorKind::TimedOut))?;
418 if self.fails {
419 Err(io::Error::other("adapter failure"))
420 } else {
421 Ok(())
422 }
423 }
424 }
425
426 impl Read for Adapter {
427 fn set_read_deadline(&mut self, deadline: Option<Instant>) -> io::Result<()> {
428 self.deadline = deadline;
429 Ok(())
430 }
431 }
432
433 impl io::Read for Adapter {
434 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
435 self.wait(self.deadline)?;
436 buf[0] = 0x5a;
437 Ok(1)
438 }
439 }
440
441 impl Write for Adapter {
442 fn set_write_deadline(&mut self, deadline: Instant) -> io::Result<()> {
443 self.deadline = Some(deadline);
444 Ok(())
445 }
446 }
447
448 impl io::Write for Adapter {
449 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
450 self.wait(Some(self.deadline.expect("write deadline installed")))?;
451 Ok(buf.len())
452 }
453
454 fn flush(&mut self) -> io::Result<()> {
455 self.wait(Some(self.deadline.expect("write deadline installed")))
456 }
457 }
458
459 fn during_shutdown(
461 fails: bool,
462 operation: impl FnOnce(Adapter, Closer) -> io::Result<()> + Send + 'static,
463 ) {
464 let (entered, entries) = mpsc::channel();
465 let (release, released) = mpsc::channel();
466 let closer = Closer::new(move || release.send(()).unwrap());
467 let io = thread::spawn({
468 let closer = closer.clone();
469 move || {
470 operation(
471 Adapter {
472 entered,
473 released,
474 fails,
475 deadline: None,
476 },
477 closer,
478 )
479 }
480 });
481 entries.recv_timeout(PATIENCE).unwrap();
482 closer.close();
483 let result = io.join().unwrap();
484 if fails {
485 let err = result.unwrap_err();
486 assert_eq!(err.kind(), io::ErrorKind::Other);
487 assert_eq!(err.to_string(), "adapter failure");
488 } else {
489 result.unwrap();
490 }
491 }
492
493 #[test]
497 fn test_admitted_io_preserves_results_during_shutdown() {
498 for fails in [false, true] {
499 during_shutdown(fails, |inner, closer| {
500 let mut buf = [0];
501 assert_eq!(ReadHalf { inner, closer }.read(&mut buf, None)?, 1);
502 assert_eq!(buf, [0x5a]);
503 Ok(())
504 });
505 during_shutdown(fails, move |inner, closer| {
506 let result =
507 WriteHalf { inner, closer }.write(&[1, 2, 3], Instant::now() + PATIENCE);
508 if fails {
509 result
510 } else {
511 assert_eq!(result.unwrap_err().kind(), io::ErrorKind::NotConnected);
512 Ok(())
513 }
514 });
515 during_shutdown(fails, |inner, closer| {
516 WriteHalf { inner, closer }.write(&[], Instant::now() + PATIENCE)
517 });
518 }
519 }
520
521 #[test]
525 fn test_ownership_and_repeated_close() {
526 let calls = Arc::new(AtomicUsize::new(0));
527 let stream = Stream::new(Memory::new(io::empty()), Memory::new(io::sink()), {
528 let calls = calls.clone();
529 move || {
530 calls.fetch_add(1, Ordering::SeqCst);
531 }
532 });
533 let closer = stream.closer();
534 let client = Client::new(stream);
535 assert_eq!(
536 calls.load(Ordering::SeqCst),
537 0,
538 "handoff must keep the stream open"
539 );
540 drop(client);
541 assert_eq!(calls.load(Ordering::SeqCst), 1);
542 closer.close();
543 drop(closer.clone());
544 assert_eq!(calls.load(Ordering::SeqCst), 1);
545
546 let stream = Stream::new(Memory::new(io::empty()), Memory::new(io::sink()), {
547 let calls = calls.clone();
548 move || {
549 calls.fetch_add(1, Ordering::SeqCst);
550 }
551 });
552 drop(stream);
553 assert_eq!(
554 calls.load(Ordering::SeqCst),
555 2,
556 "unclaimed streams also close on drop"
557 );
558 }
559
560 #[test]
564 fn test_every_closer_waits_for_the_shutdown_callback() {
565 let (entered, callback) = mpsc::channel();
566 let (release, released) = mpsc::channel();
567 let stream = Stream::new(
568 Memory::new(io::empty()),
569 Memory::new(io::sink()),
570 move || {
571 entered.send(()).unwrap();
572 released.recv_timeout(PATIENCE).unwrap();
573 },
574 );
575 let closer = stream.closer();
576 let (finished, finishes) = mpsc::channel();
577 let first = thread::spawn({
578 let closer = closer.clone();
579 let finished = finished.clone();
580 move || {
581 closer.close();
582 finished.send(()).unwrap();
583 }
584 });
585 callback.recv_timeout(PATIENCE).unwrap();
586
587 let (started, starts) = mpsc::channel();
588 let second = thread::spawn({
589 let closer = closer.clone();
590 let started = started.clone();
591 let finished = finished.clone();
592 move || {
593 started.send(()).unwrap();
594 closer.close();
595 finished.send(()).unwrap();
596 }
597 });
598 let owner = thread::spawn(move || {
599 started.send(()).unwrap();
600 drop(stream);
601 finished.send(()).unwrap();
602 });
603 starts.recv_timeout(PATIENCE).unwrap();
604 starts.recv_timeout(PATIENCE).unwrap();
605 assert!(finishes.recv_timeout(Duration::from_millis(50)).is_err());
606 release.send(()).unwrap();
607 finishes.recv_timeout(PATIENCE).unwrap();
608 finishes.recv_timeout(PATIENCE).unwrap();
609 finishes.recv_timeout(PATIENCE).unwrap();
610 first.join().unwrap();
611 second.join().unwrap();
612 owner.join().unwrap();
613 }
614
615 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
617 enum BlockAt {
618 Read,
620 Write,
622 Flush,
624 }
625
626 struct Gate {
629 at: BlockAt,
630 entered: mpsc::Sender<()>,
631 released: Mutex<bool>,
632 changed: Condvar,
633 calls: AtomicUsize,
634 }
635
636 impl Gate {
637 fn call(&self, at: BlockAt, deadline: Option<Instant>) -> io::Result<()> {
639 self.calls.fetch_add(1, Ordering::SeqCst);
640 if at == self.at {
641 self.entered.send(()).unwrap();
642 let released = self.released.lock().unwrap();
643 let released = match deadline {
644 Some(deadline) => {
645 self.changed
646 .wait_timeout_while(
647 released,
648 deadline.saturating_duration_since(Instant::now()),
649 |released| !*released,
650 )
651 .unwrap()
652 .0
653 }
654 None => self
655 .changed
656 .wait_while(released, |released| !*released)
657 .unwrap(),
658 };
659 if !*released {
660 return Err(io::ErrorKind::TimedOut.into());
661 }
662 }
663 Ok(())
664 }
665
666 fn release(&self) {
668 *self.released.lock().unwrap() = true;
669 self.changed.notify_all();
670 }
671 }
672
673 struct GatedAdapter {
675 gate: Arc<Gate>,
676 deadline: Option<Instant>,
677 }
678
679 impl Read for GatedAdapter {
680 fn set_read_deadline(&mut self, deadline: Option<Instant>) -> io::Result<()> {
681 self.deadline = deadline;
682 Ok(())
683 }
684 }
685
686 impl io::Read for GatedAdapter {
687 fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
688 self.gate.call(BlockAt::Read, self.deadline)?;
689 Ok(0)
690 }
691 }
692
693 impl Write for GatedAdapter {
694 fn set_write_deadline(&mut self, deadline: Instant) -> io::Result<()> {
695 self.deadline = Some(deadline);
696 Ok(())
697 }
698 }
699
700 impl io::Write for GatedAdapter {
701 fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
702 self.gate.call(
703 BlockAt::Write,
704 Some(self.deadline.expect("write deadline installed")),
705 )?;
706 Ok(bytes.len())
707 }
708
709 fn flush(&mut self) -> io::Result<()> {
710 self.gate.call(
711 BlockAt::Flush,
712 Some(self.deadline.expect("write deadline installed")),
713 )
714 }
715 }
716
717 #[test]
721 fn test_every_closer_waits_for_active_io_and_refuses_new_io() {
722 for at in [BlockAt::Read, BlockAt::Write, BlockAt::Flush] {
723 let (entered, entries) = mpsc::channel();
724 let gate = Arc::new(Gate {
725 at,
726 entered,
727 released: Mutex::new(false),
728 changed: Condvar::new(),
729 calls: AtomicUsize::new(0),
730 });
731 let (requested, requests) = mpsc::channel();
732 let stream = Stream::new(
733 GatedAdapter {
734 gate: gate.clone(),
735 deadline: None,
736 },
737 GatedAdapter {
738 gate: gate.clone(),
739 deadline: None,
740 },
741 move || {
742 requested.send(()).unwrap();
743 },
744 );
745 let (reader, writer, closer, _) = stream.into_parts();
746 let io_closer = closer.clone();
747 let io = thread::spawn(move || {
748 let mut reader = ReadHalf {
749 inner: reader,
750 closer: io_closer.clone(),
751 };
752 let mut writer = WriteHalf {
753 inner: writer,
754 closer: io_closer,
755 };
756 let deadline = Instant::now() + PATIENCE;
757 match at {
758 BlockAt::Read => assert_eq!(reader.read(&mut [0], None).unwrap(), 0),
759 BlockAt::Write => assert_eq!(
760 writer.write(&[1], deadline).unwrap_err().kind(),
761 io::ErrorKind::NotConnected
762 ),
763 BlockAt::Flush => writer.write(&[], deadline).unwrap(),
764 }
765 (reader, writer)
766 });
767 entries.recv_timeout(PATIENCE).unwrap();
768 let (finished, finishes) = mpsc::channel();
769 let closing = thread::spawn({
770 let closer = closer.clone();
771 move || {
772 closer.close();
773 finished.send(()).unwrap();
774 }
775 });
776 requests.recv_timeout(PATIENCE).unwrap();
777 assert!(finishes.recv_timeout(Duration::from_millis(20)).is_err());
778
779 gate.release();
780 finishes.recv_timeout(PATIENCE).unwrap();
781 closing.join().unwrap();
782 let (mut reader, mut writer) = io.join().unwrap();
783 let calls = gate.calls.load(Ordering::SeqCst);
784 assert_eq!(reader.read(&mut [0], None).unwrap(), 0);
785 assert!(matches!(
786 writer.write(&[1], Instant::now() + PATIENCE),
787 Err(err) if err.kind() == io::ErrorKind::NotConnected
788 ));
789 assert_eq!(gate.calls.load(Ordering::SeqCst), calls);
790 closer.close();
791 assert!(requests.try_recv().is_err(), "shutdown called twice");
792 }
793 }
794
795 struct BudgetWriter {
798 bytes: Vec<u8>,
799 deadlines: Vec<Instant>,
800 stall_flush: bool,
801 deadline: Option<Instant>,
802 settings: usize,
803 }
804
805 impl Write for BudgetWriter {
806 fn set_write_deadline(&mut self, deadline: Instant) -> io::Result<()> {
807 self.deadline = Some(deadline);
808 self.settings += 1;
809 Ok(())
810 }
811 }
812
813 impl io::Write for BudgetWriter {
814 fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
815 let deadline = self.deadline.expect("write deadline installed");
816 check_deadline(deadline)?;
817 self.deadlines.push(deadline);
818 self.bytes.push(bytes[0]);
819 Ok(1)
820 }
821
822 fn flush(&mut self) -> io::Result<()> {
823 let deadline = self.deadline.expect("write deadline installed");
824 self.deadlines.push(deadline);
825 if self.stall_flush {
826 thread::sleep(deadline.saturating_duration_since(Instant::now()));
827 return Err(io::ErrorKind::TimedOut.into());
828 }
829 check_deadline(deadline)
830 }
831 }
832
833 #[test]
836 fn test_output_deadline_and_reuse() {
837 let timeout = Duration::from_millis(40);
838 let stream = Stream::new(
839 Memory::new(io::empty()),
840 BudgetWriter {
841 bytes: Vec::new(),
842 deadlines: Vec::new(),
843 stall_flush: true,
844 deadline: None,
845 settings: 0,
846 },
847 || {},
848 )
849 .set_write_timeout(timeout);
850 let (_, inner, closer, configured) = stream.into_parts();
851 assert_eq!(configured, timeout);
852 let mut writer = WriteHalf { inner, closer };
853 let deadline = Instant::now() + configured;
854 assert_eq!(
855 writer.write(b"abc", deadline).unwrap_err().kind(),
856 io::ErrorKind::TimedOut
857 );
858 assert_eq!(writer.inner.deadlines, vec![deadline; 4]);
859 assert_eq!(writer.inner.settings, 1);
860
861 writer.inner.stall_flush = false;
862 let deadline = Instant::now() + PATIENCE;
863 writer.write(b"d", deadline).unwrap();
864 assert_eq!(writer.inner.bytes, b"abcd");
865 assert_eq!(writer.inner.settings, 2);
866
867 let calls = writer.inner.deadlines.len();
868 let deadline = Instant::now();
869 assert!(matches!(
870 writer.write(b"e", deadline),
871 Err(err) if err.kind() == io::ErrorKind::TimedOut
872 ));
873 assert_eq!(writer.inner.deadlines.len(), calls);
874 assert_eq!(writer.inner.settings, 2);
875 writer.closer.close();
876 }
877
878 #[test]
882 fn test_partial_write_retries_and_failures() {
883 struct Script {
885 results: std::collections::VecDeque<io::Result<usize>>,
886 offered: Vec<Vec<u8>>,
887 accepted: Vec<u8>,
888 interrupted_flush: bool,
889 flushes: usize,
890 settings: usize,
891 deadline: Option<Instant>,
892 }
893
894 impl Write for Script {
895 fn set_write_deadline(&mut self, deadline: Instant) -> io::Result<()> {
896 self.settings += 1;
897 self.deadline = Some(deadline);
898 Ok(())
899 }
900 }
901
902 impl io::Write for Script {
903 fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
904 check_deadline(self.deadline.expect("write deadline installed"))?;
905 self.offered.push(bytes.to_vec());
906 let result = self.results.pop_front().expect("unexpected write");
907 if let Ok(size) = &result {
908 self.accepted.extend_from_slice(&bytes[..*size]);
909 }
910 result
911 }
912
913 fn flush(&mut self) -> io::Result<()> {
914 check_deadline(self.deadline.expect("write deadline installed"))?;
915 self.flushes += 1;
916 assert_eq!(self.flushes, 1, "flush retried");
917 if self.interrupted_flush {
918 Err(io::ErrorKind::Interrupted.into())
919 } else {
920 Ok(())
921 }
922 }
923 }
924
925 for (stalls, interrupted_flush) in [(false, false), (true, false), (false, true)] {
926 let mut writer = WriteHalf {
927 inner: Script {
928 results: [
929 Err(io::ErrorKind::Interrupted.into()),
930 Ok(1),
931 Ok(usize::from(!stalls)),
932 ]
933 .into(),
934 offered: Vec::new(),
935 accepted: Vec::new(),
936 interrupted_flush,
937 flushes: 0,
938 settings: 0,
939 deadline: None,
940 },
941 closer: Closer::new(|| {}),
942 };
943 let result = writer.write(b"ab", Instant::now() + PATIENCE);
944 if stalls {
945 assert_eq!(result.unwrap_err().kind(), io::ErrorKind::WriteZero);
946 } else if interrupted_flush {
947 assert_eq!(result.unwrap_err().kind(), io::ErrorKind::Interrupted);
948 } else {
949 result.unwrap();
950 }
951 assert_eq!(
952 writer.inner.offered,
953 [b"ab".to_vec(), b"ab".to_vec(), b"b".to_vec()]
954 );
955 assert_eq!(
956 writer.inner.accepted,
957 if stalls { &b"a"[..] } else { &b"ab"[..] }
958 );
959 assert_eq!(writer.inner.flushes, usize::from(!stalls));
960 assert_eq!(writer.inner.settings, 1);
961 writer.closer.close();
962 }
963 }
964
965 #[test]
969 fn test_deadline_setter_failure_prevents_io() {
970 struct Refused {
972 settings: usize,
973 kind: io::ErrorKind,
974 }
975
976 impl Refused {
977 fn reject(&mut self) -> io::Result<()> {
979 self.settings += 1;
980 assert_eq!(self.settings, 1, "deadline setter failure retried");
981 Err(io::Error::new(self.kind, "deadline refused"))
982 }
983 }
984
985 impl Read for Refused {
986 fn set_read_deadline(&mut self, _: Option<Instant>) -> io::Result<()> {
987 self.reject()
988 }
989 }
990
991 impl io::Read for Refused {
992 fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
993 panic!("read after deadline setter failed")
994 }
995 }
996
997 impl Write for Refused {
998 fn set_write_deadline(&mut self, _: Instant) -> io::Result<()> {
999 self.reject()
1000 }
1001 }
1002
1003 impl io::Write for Refused {
1004 fn write(&mut self, _: &[u8]) -> io::Result<usize> {
1005 panic!("write after deadline setter failed")
1006 }
1007
1008 fn flush(&mut self) -> io::Result<()> {
1009 panic!("flush after deadline setter failed")
1010 }
1011 }
1012
1013 for kind in [io::ErrorKind::Interrupted, io::ErrorKind::TimedOut] {
1014 let closer = Closer::new(|| {});
1015 let mut reader = ReadHalf {
1016 inner: Refused { settings: 0, kind },
1017 closer: closer.clone(),
1018 };
1019 let err = reader.read(&mut [0], None).unwrap_err();
1020 assert_eq!(err.kind(), kind);
1021 assert_eq!(err.to_string(), "deadline refused");
1022 let mut writer = WriteHalf {
1023 inner: Refused { settings: 0, kind },
1024 closer: closer.clone(),
1025 };
1026 assert!(matches!(
1027 writer.write(&[1], Instant::now() + PATIENCE),
1028 Err(err) if err.kind() == kind && err.to_string() == "deadline refused"
1029 ));
1030
1031 closer.close();
1032 assert_eq!(reader.read(&mut [0], None).unwrap(), 0);
1033 assert!(matches!(
1034 writer.write(&[1], Instant::now() + PATIENCE),
1035 Err(err) if err.kind() == io::ErrorKind::NotConnected
1036 ));
1037 assert_eq!(reader.inner.settings, 1);
1038 assert_eq!(writer.inner.settings, 1);
1039 }
1040 }
1041
1042 #[test]
1046 fn test_late_write_preserves_progress() {
1047 #[derive(Default)]
1049 struct LateWriter {
1050 deadline: Option<Instant>,
1051 bytes: Vec<u8>,
1052 }
1053
1054 impl Write for LateWriter {
1055 fn set_write_deadline(&mut self, deadline: Instant) -> io::Result<()> {
1056 self.deadline = Some(deadline);
1057 Ok(())
1058 }
1059 }
1060
1061 impl io::Write for LateWriter {
1062 fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
1063 self.bytes.push(bytes[0]);
1064 thread::sleep(
1065 self.deadline
1066 .expect("write deadline installed")
1067 .saturating_duration_since(Instant::now()),
1068 );
1069 Ok(1)
1070 }
1071
1072 fn flush(&mut self) -> io::Result<()> {
1073 panic!("flush admitted after deadline expired")
1074 }
1075 }
1076
1077 for bytes in [&b"a"[..], &b"ab"[..]] {
1078 let mut writer = WriteHalf {
1079 inner: LateWriter::default(),
1080 closer: Closer::new(|| {}),
1081 };
1082 let deadline = Instant::now() + Duration::from_millis(40);
1083 assert_eq!(
1084 writer.write(bytes, deadline).unwrap_err().kind(),
1085 io::ErrorKind::TimedOut
1086 );
1087 assert_eq!(writer.inner.bytes, b"a");
1088 writer.closer.close();
1089 }
1090 }
1091}