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