| use crate::io::prelude::*; | 
 | use crate::io::{BorrowedBuf, IoSlice, IoSliceMut}; | 
 | use crate::mem::MaybeUninit; | 
 | use crate::net::test::{next_test_ip4, next_test_ip6}; | 
 | use crate::net::*; | 
 | use crate::sync::mpsc::channel; | 
 | use crate::time::{Duration, Instant}; | 
 | use crate::{fmt, thread}; | 
 |  | 
 | fn each_ip(f: &mut dyn FnMut(SocketAddr)) { | 
 |     f(next_test_ip4()); | 
 |     f(next_test_ip6()); | 
 | } | 
 |  | 
 | macro_rules! t { | 
 |     ($e:expr) => { | 
 |         match $e { | 
 |             Ok(t) => t, | 
 |             Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), | 
 |         } | 
 |     }; | 
 | } | 
 |  | 
 | #[test] | 
 | fn bind_error() { | 
 |     match TcpListener::bind("1.1.1.1:9999") { | 
 |         Ok(..) => panic!(), | 
 |         Err(e) => assert_eq!(e.kind(), ErrorKind::AddrNotAvailable), | 
 |     } | 
 | } | 
 |  | 
 | #[test] | 
 | fn connect_error() { | 
 |     match TcpStream::connect("0.0.0.0:1") { | 
 |         Ok(..) => panic!(), | 
 |         Err(e) => assert!( | 
 |             e.kind() == ErrorKind::ConnectionRefused | 
 |                 || e.kind() == ErrorKind::InvalidInput | 
 |                 || e.kind() == ErrorKind::AddrInUse | 
 |                 || e.kind() == ErrorKind::AddrNotAvailable, | 
 |             "bad error: {} {:?}", | 
 |             e, | 
 |             e.kind() | 
 |         ), | 
 |     } | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 | 
 | fn connect_timeout_error() { | 
 |     let socket_addr = next_test_ip4(); | 
 |     let result = TcpStream::connect_timeout(&socket_addr, Duration::MAX); | 
 |     assert!(!matches!(result, Err(e) if e.kind() == ErrorKind::TimedOut)); | 
 |  | 
 |     let _listener = TcpListener::bind(&socket_addr).unwrap(); | 
 |     assert!(TcpStream::connect_timeout(&socket_addr, Duration::MAX).is_ok()); | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg_attr(target_os = "wasi", ignore)] // no threads | 
 | fn listen_localhost() { | 
 |     let socket_addr = next_test_ip4(); | 
 |     let listener = t!(TcpListener::bind(&socket_addr)); | 
 |  | 
 |     let _t = thread::spawn(move || { | 
 |         let mut stream = t!(TcpStream::connect(&("localhost", socket_addr.port()))); | 
 |         t!(stream.write(&[144])); | 
 |     }); | 
 |  | 
 |     let mut stream = t!(listener.accept()).0; | 
 |     let mut buf = [0]; | 
 |     t!(stream.read(&mut buf)); | 
 |     assert!(buf[0] == 144); | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg_attr(target_os = "wasi", ignore)] // no threads | 
 | fn connect_loopback() { | 
 |     each_ip(&mut |addr| { | 
 |         let acceptor = t!(TcpListener::bind(&addr)); | 
 |  | 
 |         let _t = thread::spawn(move || { | 
 |             let host = match addr { | 
 |                 SocketAddr::V4(..) => "127.0.0.1", | 
 |                 SocketAddr::V6(..) => "::1", | 
 |             }; | 
 |             let mut stream = t!(TcpStream::connect(&(host, addr.port()))); | 
 |             t!(stream.write(&[66])); | 
 |         }); | 
 |  | 
 |         let mut stream = t!(acceptor.accept()).0; | 
 |         let mut buf = [0]; | 
 |         t!(stream.read(&mut buf)); | 
 |         assert!(buf[0] == 66); | 
 |     }) | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg_attr(target_os = "wasi", ignore)] // no threads | 
 | fn smoke_test() { | 
 |     each_ip(&mut |addr| { | 
 |         let acceptor = t!(TcpListener::bind(&addr)); | 
 |  | 
 |         let (tx, rx) = channel(); | 
 |         let _t = thread::spawn(move || { | 
 |             let mut stream = t!(TcpStream::connect(&addr)); | 
 |             t!(stream.write(&[99])); | 
 |             tx.send(t!(stream.local_addr())).unwrap(); | 
 |         }); | 
 |  | 
 |         let (mut stream, addr) = t!(acceptor.accept()); | 
 |         let mut buf = [0]; | 
 |         t!(stream.read(&mut buf)); | 
 |         assert!(buf[0] == 99); | 
 |         assert_eq!(addr, t!(rx.recv())); | 
 |     }) | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg_attr(target_os = "wasi", ignore)] // no threads | 
 | fn read_eof() { | 
 |     each_ip(&mut |addr| { | 
 |         let acceptor = t!(TcpListener::bind(&addr)); | 
 |  | 
 |         let _t = thread::spawn(move || { | 
 |             let _stream = t!(TcpStream::connect(&addr)); | 
 |             // Close | 
 |         }); | 
 |  | 
 |         let mut stream = t!(acceptor.accept()).0; | 
 |         let mut buf = [0]; | 
 |         let nread = t!(stream.read(&mut buf)); | 
 |         assert_eq!(nread, 0); | 
 |         let nread = t!(stream.read(&mut buf)); | 
 |         assert_eq!(nread, 0); | 
 |     }) | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg_attr(target_os = "wasi", ignore)] // no threads | 
 | fn write_close() { | 
 |     each_ip(&mut |addr| { | 
 |         let acceptor = t!(TcpListener::bind(&addr)); | 
 |  | 
 |         let (tx, rx) = channel(); | 
 |         let _t = thread::spawn(move || { | 
 |             drop(t!(TcpStream::connect(&addr))); | 
 |             tx.send(()).unwrap(); | 
 |         }); | 
 |  | 
 |         let mut stream = t!(acceptor.accept()).0; | 
 |         rx.recv().unwrap(); | 
 |         let buf = [0]; | 
 |         match stream.write(&buf) { | 
 |             Ok(..) => {} | 
 |             Err(e) => { | 
 |                 assert!( | 
 |                     e.kind() == ErrorKind::ConnectionReset | 
 |                         || e.kind() == ErrorKind::BrokenPipe | 
 |                         || e.kind() == ErrorKind::ConnectionAborted, | 
 |                     "unknown error: {e}" | 
 |                 ); | 
 |             } | 
 |         } | 
 |     }) | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg_attr(target_os = "wasi", ignore)] // no threads | 
 | fn multiple_connect_serial() { | 
 |     each_ip(&mut |addr| { | 
 |         let max = 10; | 
 |         let acceptor = t!(TcpListener::bind(&addr)); | 
 |  | 
 |         let _t = thread::spawn(move || { | 
 |             for _ in 0..max { | 
 |                 let mut stream = t!(TcpStream::connect(&addr)); | 
 |                 t!(stream.write(&[99])); | 
 |             } | 
 |         }); | 
 |  | 
 |         for stream in acceptor.incoming().take(max) { | 
 |             let mut stream = t!(stream); | 
 |             let mut buf = [0]; | 
 |             t!(stream.read(&mut buf)); | 
 |             assert_eq!(buf[0], 99); | 
 |         } | 
 |     }) | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg_attr(target_os = "wasi", ignore)] // no threads | 
 | fn multiple_connect_interleaved_greedy_schedule() { | 
 |     const MAX: usize = 10; | 
 |     each_ip(&mut |addr| { | 
 |         let acceptor = t!(TcpListener::bind(&addr)); | 
 |  | 
 |         let _t = thread::spawn(move || { | 
 |             let acceptor = acceptor; | 
 |             for (i, stream) in acceptor.incoming().enumerate().take(MAX) { | 
 |                 // Start another thread to handle the connection | 
 |                 let _t = thread::spawn(move || { | 
 |                     let mut stream = t!(stream); | 
 |                     let mut buf = [0]; | 
 |                     t!(stream.read(&mut buf)); | 
 |                     assert!(buf[0] == i as u8); | 
 |                 }); | 
 |             } | 
 |         }); | 
 |  | 
 |         connect(0, addr); | 
 |     }); | 
 |  | 
 |     fn connect(i: usize, addr: SocketAddr) { | 
 |         if i == MAX { | 
 |             return; | 
 |         } | 
 |  | 
 |         let t = thread::spawn(move || { | 
 |             let mut stream = t!(TcpStream::connect(&addr)); | 
 |             // Connect again before writing | 
 |             connect(i + 1, addr); | 
 |             t!(stream.write(&[i as u8])); | 
 |         }); | 
 |         t.join().ok().expect("thread panicked"); | 
 |     } | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg_attr(target_os = "wasi", ignore)] // no threads | 
 | fn multiple_connect_interleaved_lazy_schedule() { | 
 |     const MAX: usize = 10; | 
 |     each_ip(&mut |addr| { | 
 |         let acceptor = t!(TcpListener::bind(&addr)); | 
 |  | 
 |         let _t = thread::spawn(move || { | 
 |             for stream in acceptor.incoming().take(MAX) { | 
 |                 // Start another thread to handle the connection | 
 |                 let _t = thread::spawn(move || { | 
 |                     let mut stream = t!(stream); | 
 |                     let mut buf = [0]; | 
 |                     t!(stream.read(&mut buf)); | 
 |                     assert!(buf[0] == 99); | 
 |                 }); | 
 |             } | 
 |         }); | 
 |  | 
 |         connect(0, addr); | 
 |     }); | 
 |  | 
 |     fn connect(i: usize, addr: SocketAddr) { | 
 |         if i == MAX { | 
 |             return; | 
 |         } | 
 |  | 
 |         let t = thread::spawn(move || { | 
 |             let mut stream = t!(TcpStream::connect(&addr)); | 
 |             connect(i + 1, addr); | 
 |             t!(stream.write(&[99])); | 
 |         }); | 
 |         t.join().ok().expect("thread panicked"); | 
 |     } | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg_attr(target_os = "wasi", ignore)] // no threads | 
 | fn socket_and_peer_name() { | 
 |     each_ip(&mut |addr| { | 
 |         let listener = t!(TcpListener::bind(&addr)); | 
 |         let so_name = t!(listener.local_addr()); | 
 |         assert_eq!(addr, so_name); | 
 |         let _t = thread::spawn(move || { | 
 |             t!(listener.accept()); | 
 |         }); | 
 |  | 
 |         let stream = t!(TcpStream::connect(&addr)); | 
 |         assert_eq!(addr, t!(stream.peer_addr())); | 
 |     }) | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg_attr(target_os = "wasi", ignore)] // no threads | 
 | fn partial_read() { | 
 |     each_ip(&mut |addr| { | 
 |         let (tx, rx) = channel(); | 
 |         let srv = t!(TcpListener::bind(&addr)); | 
 |         let _t = thread::spawn(move || { | 
 |             let mut cl = t!(srv.accept()).0; | 
 |             cl.write(&[10]).unwrap(); | 
 |             let mut b = [0]; | 
 |             t!(cl.read(&mut b)); | 
 |             tx.send(()).unwrap(); | 
 |         }); | 
 |  | 
 |         let mut c = t!(TcpStream::connect(&addr)); | 
 |         let mut b = [0; 10]; | 
 |         assert_eq!(c.read(&mut b).unwrap(), 1); | 
 |         t!(c.write(&[1])); | 
 |         rx.recv().unwrap(); | 
 |     }) | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg_attr(target_os = "wasi", ignore)] // no threads | 
 | fn read_buf() { | 
 |     each_ip(&mut |addr| { | 
 |         let srv = t!(TcpListener::bind(&addr)); | 
 |         let t = thread::spawn(move || { | 
 |             let mut s = t!(TcpStream::connect(&addr)); | 
 |             s.write_all(&[1, 2, 3, 4]).unwrap(); | 
 |         }); | 
 |  | 
 |         let mut s = t!(srv.accept()).0; | 
 |         let mut buf: [MaybeUninit<u8>; 128] = [MaybeUninit::uninit(); 128]; | 
 |         let mut buf = BorrowedBuf::from(buf.as_mut_slice()); | 
 |         t!(s.read_buf(buf.unfilled())); | 
 |         assert_eq!(buf.filled(), &[1, 2, 3, 4]); | 
 |         // TcpStream::read_buf should omit buffer initialization. | 
 |         assert_eq!(buf.init_len(), 4); | 
 |  | 
 |         t.join().ok().expect("thread panicked"); | 
 |     }) | 
 | } | 
 |  | 
 | #[test] | 
 | fn read_vectored() { | 
 |     each_ip(&mut |addr| { | 
 |         let srv = t!(TcpListener::bind(&addr)); | 
 |         let mut s1 = t!(TcpStream::connect(&addr)); | 
 |         let mut s2 = t!(srv.accept()).0; | 
 |  | 
 |         let len = s1.write(&[10, 11, 12]).unwrap(); | 
 |         assert_eq!(len, 3); | 
 |  | 
 |         let mut a = []; | 
 |         let mut b = [0]; | 
 |         let mut c = [0; 3]; | 
 |         let len = t!(s2.read_vectored(&mut [ | 
 |             IoSliceMut::new(&mut a), | 
 |             IoSliceMut::new(&mut b), | 
 |             IoSliceMut::new(&mut c) | 
 |         ],)); | 
 |         assert!(len > 0); | 
 |         assert_eq!(b, [10]); | 
 |         // some implementations don't support readv, so we may only fill the first buffer | 
 |         assert!(len == 1 || c == [11, 12, 0]); | 
 |     }) | 
 | } | 
 |  | 
 | #[test] | 
 | fn write_vectored() { | 
 |     each_ip(&mut |addr| { | 
 |         let srv = t!(TcpListener::bind(&addr)); | 
 |         let mut s1 = t!(TcpStream::connect(&addr)); | 
 |         let mut s2 = t!(srv.accept()).0; | 
 |  | 
 |         let a = []; | 
 |         let b = [10]; | 
 |         let c = [11, 12]; | 
 |         t!(s1.write_vectored(&[IoSlice::new(&a), IoSlice::new(&b), IoSlice::new(&c)])); | 
 |  | 
 |         let mut buf = [0; 4]; | 
 |         let len = t!(s2.read(&mut buf)); | 
 |         // some implementations don't support writev, so we may only write the first buffer | 
 |         if len == 1 { | 
 |             assert_eq!(buf, [10, 0, 0, 0]); | 
 |         } else { | 
 |             assert_eq!(len, 3); | 
 |             assert_eq!(buf, [10, 11, 12, 0]); | 
 |         } | 
 |     }) | 
 | } | 
 |  | 
 | #[test] | 
 | fn double_bind() { | 
 |     each_ip(&mut |addr| { | 
 |         let listener1 = t!(TcpListener::bind(&addr)); | 
 |         match TcpListener::bind(&addr) { | 
 |             Ok(listener2) => panic!( | 
 |                 "This system (perhaps due to options set by TcpListener::bind) \ | 
 |                  permits double binding: {:?} and {:?}", | 
 |                 listener1, listener2 | 
 |             ), | 
 |             Err(e) => { | 
 |                 assert!( | 
 |                     e.kind() == ErrorKind::ConnectionRefused | 
 |                         || e.kind() == ErrorKind::Uncategorized | 
 |                         || e.kind() == ErrorKind::AddrInUse, | 
 |                     "unknown error: {} {:?}", | 
 |                     e, | 
 |                     e.kind() | 
 |                 ); | 
 |             } | 
 |         } | 
 |     }) | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg_attr(target_os = "wasi", ignore)] // no threads | 
 | fn tcp_clone_smoke() { | 
 |     each_ip(&mut |addr| { | 
 |         let acceptor = t!(TcpListener::bind(&addr)); | 
 |  | 
 |         let _t = thread::spawn(move || { | 
 |             let mut s = t!(TcpStream::connect(&addr)); | 
 |             let mut buf = [0, 0]; | 
 |             assert_eq!(s.read(&mut buf).unwrap(), 1); | 
 |             assert_eq!(buf[0], 1); | 
 |             t!(s.write(&[2])); | 
 |         }); | 
 |  | 
 |         let mut s1 = t!(acceptor.accept()).0; | 
 |         let s2 = t!(s1.try_clone()); | 
 |  | 
 |         let (tx1, rx1) = channel(); | 
 |         let (tx2, rx2) = channel(); | 
 |         let _t = thread::spawn(move || { | 
 |             let mut s2 = s2; | 
 |             rx1.recv().unwrap(); | 
 |             t!(s2.write(&[1])); | 
 |             tx2.send(()).unwrap(); | 
 |         }); | 
 |         tx1.send(()).unwrap(); | 
 |         let mut buf = [0, 0]; | 
 |         assert_eq!(s1.read(&mut buf).unwrap(), 1); | 
 |         rx2.recv().unwrap(); | 
 |     }) | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg_attr(target_os = "wasi", ignore)] // no threads | 
 | fn tcp_clone_two_read() { | 
 |     each_ip(&mut |addr| { | 
 |         let acceptor = t!(TcpListener::bind(&addr)); | 
 |         let (tx1, rx) = channel(); | 
 |         let tx2 = tx1.clone(); | 
 |  | 
 |         let _t = thread::spawn(move || { | 
 |             let mut s = t!(TcpStream::connect(&addr)); | 
 |             t!(s.write(&[1])); | 
 |             rx.recv().unwrap(); | 
 |             t!(s.write(&[2])); | 
 |             rx.recv().unwrap(); | 
 |         }); | 
 |  | 
 |         let mut s1 = t!(acceptor.accept()).0; | 
 |         let s2 = t!(s1.try_clone()); | 
 |  | 
 |         let (done, rx) = channel(); | 
 |         let _t = thread::spawn(move || { | 
 |             let mut s2 = s2; | 
 |             let mut buf = [0, 0]; | 
 |             t!(s2.read(&mut buf)); | 
 |             tx2.send(()).unwrap(); | 
 |             done.send(()).unwrap(); | 
 |         }); | 
 |         let mut buf = [0, 0]; | 
 |         t!(s1.read(&mut buf)); | 
 |         tx1.send(()).unwrap(); | 
 |  | 
 |         rx.recv().unwrap(); | 
 |     }) | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg_attr(target_os = "wasi", ignore)] // no threads | 
 | fn tcp_clone_two_write() { | 
 |     each_ip(&mut |addr| { | 
 |         let acceptor = t!(TcpListener::bind(&addr)); | 
 |  | 
 |         let _t = thread::spawn(move || { | 
 |             let mut s = t!(TcpStream::connect(&addr)); | 
 |             let mut buf = [0, 1]; | 
 |             t!(s.read(&mut buf)); | 
 |             t!(s.read(&mut buf)); | 
 |         }); | 
 |  | 
 |         let mut s1 = t!(acceptor.accept()).0; | 
 |         let s2 = t!(s1.try_clone()); | 
 |  | 
 |         let (done, rx) = channel(); | 
 |         let _t = thread::spawn(move || { | 
 |             let mut s2 = s2; | 
 |             t!(s2.write(&[1])); | 
 |             done.send(()).unwrap(); | 
 |         }); | 
 |         t!(s1.write(&[2])); | 
 |  | 
 |         rx.recv().unwrap(); | 
 |     }) | 
 | } | 
 |  | 
 | #[test] | 
 | // FIXME: https://github.com/fortanix/rust-sgx/issues/110 | 
 | #[cfg_attr(target_env = "sgx", ignore)] | 
 | #[cfg_attr(target_os = "wasi", ignore)] // no threads | 
 | fn shutdown_smoke() { | 
 |     each_ip(&mut |addr| { | 
 |         let a = t!(TcpListener::bind(&addr)); | 
 |         let _t = thread::spawn(move || { | 
 |             let mut c = t!(a.accept()).0; | 
 |             let mut b = [0]; | 
 |             assert_eq!(c.read(&mut b).unwrap(), 0); | 
 |             t!(c.write(&[1])); | 
 |         }); | 
 |  | 
 |         let mut s = t!(TcpStream::connect(&addr)); | 
 |         t!(s.shutdown(Shutdown::Write)); | 
 |         assert!(s.write(&[1]).is_err()); | 
 |         let mut b = [0, 0]; | 
 |         assert_eq!(t!(s.read(&mut b)), 1); | 
 |         assert_eq!(b[0], 1); | 
 |     }) | 
 | } | 
 |  | 
 | #[test] | 
 | // FIXME: https://github.com/fortanix/rust-sgx/issues/110 | 
 | #[cfg_attr(target_env = "sgx", ignore)] | 
 | #[cfg_attr(target_os = "wasi", ignore)] // no threads | 
 | fn close_readwrite_smoke() { | 
 |     each_ip(&mut |addr| { | 
 |         let a = t!(TcpListener::bind(&addr)); | 
 |         let (tx, rx) = channel::<()>(); | 
 |         let _t = thread::spawn(move || { | 
 |             let _s = t!(a.accept()); | 
 |             let _ = rx.recv(); | 
 |         }); | 
 |  | 
 |         let mut b = [0]; | 
 |         let mut s = t!(TcpStream::connect(&addr)); | 
 |         let mut s2 = t!(s.try_clone()); | 
 |  | 
 |         // closing should prevent reads/writes | 
 |         t!(s.shutdown(Shutdown::Write)); | 
 |         assert!(s.write(&[0]).is_err()); | 
 |         t!(s.shutdown(Shutdown::Read)); | 
 |         assert_eq!(s.read(&mut b).unwrap(), 0); | 
 |  | 
 |         // closing should affect previous handles | 
 |         assert!(s2.write(&[0]).is_err()); | 
 |         assert_eq!(s2.read(&mut b).unwrap(), 0); | 
 |  | 
 |         // closing should affect new handles | 
 |         let mut s3 = t!(s.try_clone()); | 
 |         assert!(s3.write(&[0]).is_err()); | 
 |         assert_eq!(s3.read(&mut b).unwrap(), 0); | 
 |  | 
 |         // make sure these don't die | 
 |         let _ = s2.shutdown(Shutdown::Read); | 
 |         let _ = s2.shutdown(Shutdown::Write); | 
 |         let _ = s3.shutdown(Shutdown::Read); | 
 |         let _ = s3.shutdown(Shutdown::Write); | 
 |         drop(tx); | 
 |     }) | 
 | } | 
 |  | 
 | #[test] | 
 | // FIXME: https://github.com/fortanix/rust-sgx/issues/110 | 
 | #[cfg_attr(target_env = "sgx", ignore)] | 
 | // On windows, shutdown will not wake up blocking I/O operations. | 
 | #[cfg_attr(windows, ignore)] | 
 | #[cfg_attr(target_os = "wasi", ignore)] // no threads | 
 | fn close_read_wakes_up() { | 
 |     each_ip(&mut |addr| { | 
 |         let listener = t!(TcpListener::bind(&addr)); | 
 |         let _t = thread::spawn(move || { | 
 |             let (stream, _) = t!(listener.accept()); | 
 |             stream | 
 |         }); | 
 |  | 
 |         let mut stream = t!(TcpStream::connect(&addr)); | 
 |         let stream2 = t!(stream.try_clone()); | 
 |  | 
 |         let _t = thread::spawn(move || { | 
 |             let stream2 = stream2; | 
 |  | 
 |             // to make it more likely that `read` happens before `shutdown` | 
 |             thread::sleep(Duration::from_millis(1000)); | 
 |  | 
 |             // this should wake up the reader up | 
 |             t!(stream2.shutdown(Shutdown::Read)); | 
 |         }); | 
 |  | 
 |         // this `read` should get interrupted by `shutdown` | 
 |         assert_eq!(t!(stream.read(&mut [0])), 0); | 
 |     }) | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg_attr(target_os = "wasi", ignore)] // no threads | 
 | fn clone_while_reading() { | 
 |     each_ip(&mut |addr| { | 
 |         let accept = t!(TcpListener::bind(&addr)); | 
 |  | 
 |         // Enqueue a thread to write to a socket | 
 |         let (tx, rx) = channel(); | 
 |         let (txdone, rxdone) = channel(); | 
 |         let txdone2 = txdone.clone(); | 
 |         let _t = thread::spawn(move || { | 
 |             let mut tcp = t!(TcpStream::connect(&addr)); | 
 |             rx.recv().unwrap(); | 
 |             t!(tcp.write(&[0])); | 
 |             txdone2.send(()).unwrap(); | 
 |         }); | 
 |  | 
 |         // Spawn off a reading clone | 
 |         let tcp = t!(accept.accept()).0; | 
 |         let tcp2 = t!(tcp.try_clone()); | 
 |         let txdone3 = txdone.clone(); | 
 |         let _t = thread::spawn(move || { | 
 |             let mut tcp2 = tcp2; | 
 |             t!(tcp2.read(&mut [0])); | 
 |             txdone3.send(()).unwrap(); | 
 |         }); | 
 |  | 
 |         // Try to ensure that the reading clone is indeed reading | 
 |         for _ in 0..50 { | 
 |             thread::yield_now(); | 
 |         } | 
 |  | 
 |         // clone the handle again while it's reading, then let it finish the | 
 |         // read. | 
 |         let _ = t!(tcp.try_clone()); | 
 |         tx.send(()).unwrap(); | 
 |         rxdone.recv().unwrap(); | 
 |         rxdone.recv().unwrap(); | 
 |     }) | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg_attr(target_os = "wasi", ignore)] // no threads | 
 | fn clone_accept_smoke() { | 
 |     each_ip(&mut |addr| { | 
 |         let a = t!(TcpListener::bind(&addr)); | 
 |         let a2 = t!(a.try_clone()); | 
 |  | 
 |         let _t = thread::spawn(move || { | 
 |             let _ = TcpStream::connect(&addr); | 
 |         }); | 
 |         let _t = thread::spawn(move || { | 
 |             let _ = TcpStream::connect(&addr); | 
 |         }); | 
 |  | 
 |         t!(a.accept()); | 
 |         t!(a2.accept()); | 
 |     }) | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg_attr(target_os = "wasi", ignore)] // no threads | 
 | fn clone_accept_concurrent() { | 
 |     each_ip(&mut |addr| { | 
 |         let a = t!(TcpListener::bind(&addr)); | 
 |         let a2 = t!(a.try_clone()); | 
 |  | 
 |         let (tx, rx) = channel(); | 
 |         let tx2 = tx.clone(); | 
 |  | 
 |         let _t = thread::spawn(move || { | 
 |             tx.send(t!(a.accept())).unwrap(); | 
 |         }); | 
 |         let _t = thread::spawn(move || { | 
 |             tx2.send(t!(a2.accept())).unwrap(); | 
 |         }); | 
 |  | 
 |         let _t = thread::spawn(move || { | 
 |             let _ = TcpStream::connect(&addr); | 
 |         }); | 
 |         let _t = thread::spawn(move || { | 
 |             let _ = TcpStream::connect(&addr); | 
 |         }); | 
 |  | 
 |         rx.recv().unwrap(); | 
 |         rx.recv().unwrap(); | 
 |     }) | 
 | } | 
 |  | 
 | #[test] | 
 | fn debug() { | 
 |     #[cfg(not(target_env = "sgx"))] | 
 |     fn render_socket_addr<'a>(addr: &'a SocketAddr) -> impl fmt::Debug + 'a { | 
 |         addr | 
 |     } | 
 |     #[cfg(target_env = "sgx")] | 
 |     fn render_socket_addr<'a>(addr: &'a SocketAddr) -> impl fmt::Debug + 'a { | 
 |         addr.to_string() | 
 |     } | 
 |  | 
 |     #[cfg(any(unix, target_os = "wasi"))] | 
 |     use crate::os::fd::AsRawFd; | 
 |     #[cfg(target_env = "sgx")] | 
 |     use crate::os::fortanix_sgx::io::AsRawFd; | 
 |     #[cfg(not(windows))] | 
 |     fn render_inner(addr: &dyn AsRawFd) -> impl fmt::Debug { | 
 |         addr.as_raw_fd() | 
 |     } | 
 |     #[cfg(windows)] | 
 |     fn render_inner(addr: &dyn crate::os::windows::io::AsRawSocket) -> impl fmt::Debug { | 
 |         addr.as_raw_socket() | 
 |     } | 
 |  | 
 |     let inner_name = if cfg!(windows) { "socket" } else { "fd" }; | 
 |     let socket_addr = next_test_ip4(); | 
 |  | 
 |     let listener = t!(TcpListener::bind(&socket_addr)); | 
 |     let compare = format!( | 
 |         "TcpListener {{ addr: {:?}, {}: {:?} }}", | 
 |         render_socket_addr(&socket_addr), | 
 |         inner_name, | 
 |         render_inner(&listener) | 
 |     ); | 
 |     assert_eq!(format!("{listener:?}"), compare); | 
 |  | 
 |     let stream = t!(TcpStream::connect(&("localhost", socket_addr.port()))); | 
 |     let compare = format!( | 
 |         "TcpStream {{ addr: {:?}, peer: {:?}, {}: {:?} }}", | 
 |         render_socket_addr(&stream.local_addr().unwrap()), | 
 |         render_socket_addr(&stream.peer_addr().unwrap()), | 
 |         inner_name, | 
 |         render_inner(&stream) | 
 |     ); | 
 |     assert_eq!(format!("{stream:?}"), compare); | 
 | } | 
 |  | 
 | // FIXME: re-enabled openbsd tests once their socket timeout code | 
 | //        no longer has rounding errors. | 
 | // VxWorks ignores SO_SNDTIMEO. | 
 | #[cfg_attr( | 
 |     any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks", target_os = "nto"), | 
 |     ignore | 
 | )] | 
 | #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 | 
 | #[cfg_attr(target_os = "wasi", ignore)] // timeout not supported | 
 | #[test] | 
 | fn timeouts() { | 
 |     let addr = next_test_ip4(); | 
 |     let listener = t!(TcpListener::bind(&addr)); | 
 |  | 
 |     let stream = t!(TcpStream::connect(&("localhost", addr.port()))); | 
 |     let dur = Duration::new(15410, 0); | 
 |  | 
 |     assert_eq!(None, t!(stream.read_timeout())); | 
 |  | 
 |     t!(stream.set_read_timeout(Some(dur))); | 
 |     assert_eq!(Some(dur), t!(stream.read_timeout())); | 
 |  | 
 |     assert_eq!(None, t!(stream.write_timeout())); | 
 |  | 
 |     t!(stream.set_write_timeout(Some(dur))); | 
 |     assert_eq!(Some(dur), t!(stream.write_timeout())); | 
 |  | 
 |     t!(stream.set_read_timeout(None)); | 
 |     assert_eq!(None, t!(stream.read_timeout())); | 
 |  | 
 |     t!(stream.set_write_timeout(None)); | 
 |     assert_eq!(None, t!(stream.write_timeout())); | 
 |     drop(listener); | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 | 
 | #[cfg_attr(target_os = "wasi", ignore)] // timeout not supported | 
 | fn test_read_timeout() { | 
 |     let addr = next_test_ip4(); | 
 |     let listener = t!(TcpListener::bind(&addr)); | 
 |  | 
 |     let mut stream = t!(TcpStream::connect(&("localhost", addr.port()))); | 
 |     t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); | 
 |  | 
 |     let mut buf = [0; 10]; | 
 |     let start = Instant::now(); | 
 |     let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); | 
 |     assert!( | 
 |         kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, | 
 |         "unexpected_error: {:?}", | 
 |         kind | 
 |     ); | 
 |     assert!(start.elapsed() > Duration::from_millis(400)); | 
 |     drop(listener); | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 | 
 | #[cfg_attr(target_os = "wasi", ignore)] // timeout not supported | 
 | fn test_read_with_timeout() { | 
 |     let addr = next_test_ip4(); | 
 |     let listener = t!(TcpListener::bind(&addr)); | 
 |  | 
 |     let mut stream = t!(TcpStream::connect(&("localhost", addr.port()))); | 
 |     t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); | 
 |  | 
 |     let mut other_end = t!(listener.accept()).0; | 
 |     t!(other_end.write_all(b"hello world")); | 
 |  | 
 |     let mut buf = [0; 11]; | 
 |     t!(stream.read(&mut buf)); | 
 |     assert_eq!(b"hello world", &buf[..]); | 
 |  | 
 |     let start = Instant::now(); | 
 |     let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); | 
 |     assert!( | 
 |         kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, | 
 |         "unexpected_error: {:?}", | 
 |         kind | 
 |     ); | 
 |     assert!(start.elapsed() > Duration::from_millis(400)); | 
 |     drop(listener); | 
 | } | 
 |  | 
 | // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors | 
 | // when passed zero Durations | 
 | #[test] | 
 | fn test_timeout_zero_duration() { | 
 |     let addr = next_test_ip4(); | 
 |  | 
 |     let listener = t!(TcpListener::bind(&addr)); | 
 |     let stream = t!(TcpStream::connect(&addr)); | 
 |  | 
 |     let result = stream.set_write_timeout(Some(Duration::new(0, 0))); | 
 |     let err = result.unwrap_err(); | 
 |     assert_eq!(err.kind(), ErrorKind::InvalidInput); | 
 |  | 
 |     let result = stream.set_read_timeout(Some(Duration::new(0, 0))); | 
 |     let err = result.unwrap_err(); | 
 |     assert_eq!(err.kind(), ErrorKind::InvalidInput); | 
 |  | 
 |     drop(listener); | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg_attr(target_env = "sgx", ignore)] | 
 | #[cfg_attr(target_os = "wasi", ignore)] // linger not supported | 
 | fn linger() { | 
 |     let addr = next_test_ip4(); | 
 |     let _listener = t!(TcpListener::bind(&addr)); | 
 |  | 
 |     let stream = t!(TcpStream::connect(&("localhost", addr.port()))); | 
 |  | 
 |     assert_eq!(None, t!(stream.linger())); | 
 |     t!(stream.set_linger(Some(Duration::from_secs(1)))); | 
 |     assert_eq!(Some(Duration::from_secs(1)), t!(stream.linger())); | 
 |     t!(stream.set_linger(None)); | 
 |     assert_eq!(None, t!(stream.linger())); | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg_attr(target_env = "sgx", ignore)] | 
 | fn nodelay() { | 
 |     let addr = next_test_ip4(); | 
 |     let _listener = t!(TcpListener::bind(&addr)); | 
 |  | 
 |     let stream = t!(TcpStream::connect(&("localhost", addr.port()))); | 
 |  | 
 |     assert_eq!(false, t!(stream.nodelay())); | 
 |     t!(stream.set_nodelay(true)); | 
 |     assert_eq!(true, t!(stream.nodelay())); | 
 |     t!(stream.set_nodelay(false)); | 
 |     assert_eq!(false, t!(stream.nodelay())); | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg_attr(target_env = "sgx", ignore)] | 
 | fn ttl() { | 
 |     let ttl = 100; | 
 |  | 
 |     let addr = next_test_ip4(); | 
 |     let listener = t!(TcpListener::bind(&addr)); | 
 |  | 
 |     t!(listener.set_ttl(ttl)); | 
 |     assert_eq!(ttl, t!(listener.ttl())); | 
 |  | 
 |     let stream = t!(TcpStream::connect(&("localhost", addr.port()))); | 
 |  | 
 |     t!(stream.set_ttl(ttl)); | 
 |     assert_eq!(ttl, t!(stream.ttl())); | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg_attr(target_env = "sgx", ignore)] | 
 | fn set_nonblocking() { | 
 |     let addr = next_test_ip4(); | 
 |     let listener = t!(TcpListener::bind(&addr)); | 
 |  | 
 |     t!(listener.set_nonblocking(true)); | 
 |     t!(listener.set_nonblocking(false)); | 
 |  | 
 |     let mut stream = t!(TcpStream::connect(&("localhost", addr.port()))); | 
 |  | 
 |     t!(stream.set_nonblocking(false)); | 
 |     t!(stream.set_nonblocking(true)); | 
 |  | 
 |     let mut buf = [0]; | 
 |     match stream.read(&mut buf) { | 
 |         Ok(_) => panic!("expected error"), | 
 |         Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} | 
 |         Err(e) => panic!("unexpected error {e}"), | 
 |     } | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 | 
 | #[cfg_attr(target_os = "wasi", ignore)] // no threads | 
 | fn peek() { | 
 |     each_ip(&mut |addr| { | 
 |         let (txdone, rxdone) = channel(); | 
 |  | 
 |         let srv = t!(TcpListener::bind(&addr)); | 
 |         let _t = thread::spawn(move || { | 
 |             let mut cl = t!(srv.accept()).0; | 
 |             cl.write(&[1, 3, 3, 7]).unwrap(); | 
 |             t!(rxdone.recv()); | 
 |         }); | 
 |  | 
 |         let mut c = t!(TcpStream::connect(&addr)); | 
 |         let mut b = [0; 10]; | 
 |         for _ in 1..3 { | 
 |             let len = c.peek(&mut b).unwrap(); | 
 |             assert_eq!(len, 4); | 
 |         } | 
 |         let len = c.read(&mut b).unwrap(); | 
 |         assert_eq!(len, 4); | 
 |  | 
 |         t!(c.set_nonblocking(true)); | 
 |         match c.peek(&mut b) { | 
 |             Ok(_) => panic!("expected error"), | 
 |             Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} | 
 |             Err(e) => panic!("unexpected error {e}"), | 
 |         } | 
 |         t!(txdone.send(())); | 
 |     }) | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 | 
 | fn connect_timeout_valid() { | 
 |     let listener = TcpListener::bind("127.0.0.1:0").unwrap(); | 
 |     let addr = listener.local_addr().unwrap(); | 
 |     TcpStream::connect_timeout(&addr, Duration::from_secs(2)).unwrap(); | 
 | } |