use crate::io::ErrorKind; use crate::net::test::{next_test_ip4, next_test_ip6}; use crate::net::*; use crate::sync::mpsc::channel; use crate::thread; use crate::time::{Duration, Instant}; fn each_ip(f: &mut dyn FnMut(SocketAddr, SocketAddr)) { f(next_test_ip4(), next_test_ip4()); f(next_test_ip6(), 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 UdpSocket::bind("1.1.1.1:9999") { Ok(..) => panic!(), Err(e) => assert_eq!(e.kind(), ErrorKind::AddrNotAvailable), } } #[test] fn socket_smoke_test_ip4() { each_ip(&mut |server_ip, client_ip| { let (tx1, rx1) = channel(); let (tx2, rx2) = channel(); let _t = thread::spawn(move || { let client = t!(UdpSocket::bind(&client_ip)); rx1.recv().unwrap(); t!(client.send_to(&[99], &server_ip)); tx2.send(()).unwrap(); }); let server = t!(UdpSocket::bind(&server_ip)); tx1.send(()).unwrap(); let mut buf = [0]; let (nread, src) = t!(server.recv_from(&mut buf)); assert_eq!(nread, 1); assert_eq!(buf[0], 99); assert_eq!(src, client_ip); rx2.recv().unwrap(); }) } #[test] fn socket_name() { each_ip(&mut |addr, _| { let server = t!(UdpSocket::bind(&addr)); assert_eq!(addr, t!(server.local_addr())); }) } #[test] fn socket_peer() { each_ip(&mut |addr1, addr2| { let server = t!(UdpSocket::bind(&addr1)); assert_eq!(server.peer_addr().unwrap_err().kind(), ErrorKind::NotConnected); t!(server.connect(&addr2)); assert_eq!(addr2, t!(server.peer_addr())); }) } #[test] fn udp_clone_smoke() { each_ip(&mut |addr1, addr2| { let sock1 = t!(UdpSocket::bind(&addr1)); let sock2 = t!(UdpSocket::bind(&addr2)); let _t = thread::spawn(move || { let mut buf = [0, 0]; assert_eq!(sock2.recv_from(&mut buf).unwrap(), (1, addr1)); assert_eq!(buf[0], 1); t!(sock2.send_to(&[2], &addr1)); }); let sock3 = t!(sock1.try_clone()); let (tx1, rx1) = channel(); let (tx2, rx2) = channel(); let _t = thread::spawn(move || { rx1.recv().unwrap(); t!(sock3.send_to(&[1], &addr2)); tx2.send(()).unwrap(); }); tx1.send(()).unwrap(); let mut buf = [0, 0]; assert_eq!(sock1.recv_from(&mut buf).unwrap(), (1, addr2)); rx2.recv().unwrap(); }) } #[test] fn udp_clone_two_read() { each_ip(&mut |addr1, addr2| { let sock1 = t!(UdpSocket::bind(&addr1)); let sock2 = t!(UdpSocket::bind(&addr2)); let (tx1, rx) = channel(); let tx2 = tx1.clone(); let _t = thread::spawn(move || { t!(sock2.send_to(&[1], &addr1)); rx.recv().unwrap(); t!(sock2.send_to(&[2], &addr1)); rx.recv().unwrap(); }); let sock3 = t!(sock1.try_clone()); let (done, rx) = channel(); let _t = thread::spawn(move || { let mut buf = [0, 0]; t!(sock3.recv_from(&mut buf)); tx2.send(()).unwrap(); done.send(()).unwrap(); }); let mut buf = [0, 0]; t!(sock1.recv_from(&mut buf)); tx1.send(()).unwrap(); rx.recv().unwrap(); }) } #[test] fn udp_clone_two_write() { each_ip(&mut |addr1, addr2| { let sock1 = t!(UdpSocket::bind(&addr1)); let sock2 = t!(UdpSocket::bind(&addr2)); let (tx, rx) = channel(); let (serv_tx, serv_rx) = channel(); let _t = thread::spawn(move || { let mut buf = [0, 1]; rx.recv().unwrap(); t!(sock2.recv_from(&mut buf)); serv_tx.send(()).unwrap(); }); let sock3 = t!(sock1.try_clone()); let (done, rx) = channel(); let tx2 = tx.clone(); let _t = thread::spawn(move || { if sock3.send_to(&[1], &addr2).is_ok() { let _ = tx2.send(()); } done.send(()).unwrap(); }); if sock1.send_to(&[2], &addr2).is_ok() { let _ = tx.send(()); } drop(tx); rx.recv().unwrap(); serv_rx.recv().unwrap(); }) } #[test] fn debug() { let name = if cfg!(windows) { "socket" } else { "fd" }; let socket_addr = next_test_ip4(); let udpsock = t!(UdpSocket::bind(&socket_addr)); let udpsock_inner = udpsock.0.socket().as_raw(); let compare = format!("UdpSocket {{ addr: {socket_addr:?}, {name}: {udpsock_inner:?} }}"); assert_eq!(format!("{udpsock:?}"), compare); } // FIXME: re-enabled openbsd/netbsd 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"), ignore)] #[test] fn timeouts() { let addr = next_test_ip4(); let stream = t!(UdpSocket::bind(&addr)); 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())); } #[test] fn test_read_timeout() { let addr = next_test_ip4(); let stream = t!(UdpSocket::bind(&addr)); t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); let mut buf = [0; 10]; let start = Instant::now(); loop { let kind = stream.recv_from(&mut buf).err().expect("expected error").kind(); if kind != ErrorKind::Interrupted { assert!( kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, "unexpected_error: {:?}", kind ); break; } } assert!(start.elapsed() > Duration::from_millis(400)); } #[test] fn test_read_with_timeout() { let addr = next_test_ip4(); let stream = t!(UdpSocket::bind(&addr)); t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); t!(stream.send_to(b"hello world", &addr)); let mut buf = [0; 11]; t!(stream.recv_from(&mut buf)); assert_eq!(b"hello world", &buf[..]); let start = Instant::now(); loop { let kind = stream.recv_from(&mut buf).err().expect("expected error").kind(); if kind != ErrorKind::Interrupted { assert!( kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, "unexpected_error: {:?}", kind ); break; } } assert!(start.elapsed() > Duration::from_millis(400)); } // 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 socket = t!(UdpSocket::bind(&addr)); let result = socket.set_write_timeout(Some(Duration::new(0, 0))); let err = result.unwrap_err(); assert_eq!(err.kind(), ErrorKind::InvalidInput); let result = socket.set_read_timeout(Some(Duration::new(0, 0))); let err = result.unwrap_err(); assert_eq!(err.kind(), ErrorKind::InvalidInput); } #[test] fn connect_send_recv() { let addr = next_test_ip4(); let socket = t!(UdpSocket::bind(&addr)); t!(socket.connect(addr)); t!(socket.send(b"hello world")); let mut buf = [0; 11]; t!(socket.recv(&mut buf)); assert_eq!(b"hello world", &buf[..]); } #[test] fn connect_send_peek_recv() { each_ip(&mut |addr, _| { let socket = t!(UdpSocket::bind(&addr)); t!(socket.connect(addr)); t!(socket.send(b"hello world")); for _ in 1..3 { let mut buf = [0; 11]; let size = t!(socket.peek(&mut buf)); assert_eq!(b"hello world", &buf[..]); assert_eq!(size, 11); } let mut buf = [0; 11]; let size = t!(socket.recv(&mut buf)); assert_eq!(b"hello world", &buf[..]); assert_eq!(size, 11); }) } #[test] fn peek_from() { each_ip(&mut |addr, _| { let socket = t!(UdpSocket::bind(&addr)); t!(socket.send_to(b"hello world", &addr)); for _ in 1..3 { let mut buf = [0; 11]; let (size, _) = t!(socket.peek_from(&mut buf)); assert_eq!(b"hello world", &buf[..]); assert_eq!(size, 11); } let mut buf = [0; 11]; let (size, _) = t!(socket.recv_from(&mut buf)); assert_eq!(b"hello world", &buf[..]); assert_eq!(size, 11); }) } #[test] fn ttl() { let ttl = 100; let addr = next_test_ip4(); let stream = t!(UdpSocket::bind(&addr)); t!(stream.set_ttl(ttl)); assert_eq!(ttl, t!(stream.ttl())); } #[test] fn set_nonblocking() { each_ip(&mut |addr, _| { let socket = t!(UdpSocket::bind(&addr)); t!(socket.set_nonblocking(true)); t!(socket.set_nonblocking(false)); t!(socket.connect(addr)); t!(socket.set_nonblocking(false)); t!(socket.set_nonblocking(true)); let mut buf = [0]; match socket.recv(&mut buf) { Ok(_) => panic!("expected error"), Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} Err(e) => panic!("unexpected error {e}"), } }) }