#[cfg(unix)]
use std::os::fd::AsRawFd;
#[cfg(windows)]
use std::os::windows::io::AsRawSocket;
use std::{
cell::Cell,
future::poll_fn,
io::{self, Read, Write},
net::Shutdown,
pin::{Pin, pin},
sync::Arc,
task::Poll,
thread,
};
use futures::{
AsyncReadExt, AsyncWriteExt, StreamExt,
executor::block_on,
future::{join, poll_immediate},
io::{AsyncWrite, copy},
};
use ntest::timeout;
use socket2::SockRef;
#[cfg(any(target_os = "linux", target_os = "android"))]
use super::listener_with_room_for_one;
use super::{DELAY, RefusedPort, after, counting_polls, in_both_modes, loopback, pattern};
use crate::{
Local, Mode, Runtime, Shared, SharedRuntime,
net::{Incoming, TcpListener, TcpStream},
};
in_both_modes! {
fn a_connection_echoes_both_ways<M>() {
let runtime = Runtime::<M>::new().unwrap();
let listener = TcpListener::bind(&runtime, loopback()).unwrap();
let address = listener.local_addr().unwrap();
runtime.block_on(async {
let mut client = TcpStream::connect(&runtime, address).await.unwrap();
let (mut server, peer) = listener.accept().await.unwrap();
client.write_all(b"ping").await.unwrap();
let mut received = [0; 4];
server.read_exact(&mut received).await.unwrap();
assert_eq!(&received, b"ping");
server.write_all(b"pong").await.unwrap();
client.read_exact(&mut received).await.unwrap();
assert_eq!(&received, b"pong");
assert_eq!(client.peer_addr().unwrap(), address);
assert_eq!(server.local_addr().unwrap(), address);
assert_eq!(server.peer_addr().unwrap(), client.local_addr().unwrap());
assert_eq!(peer, client.local_addr().unwrap());
});
}
}
in_both_modes! {
fn a_refused_connection_reports_connection_refused<M>() {
let runtime = Runtime::<M>::new().unwrap();
let refused = RefusedPort::new();
let error = runtime
.block_on(TcpStream::connect(&runtime, refused.address()))
.unwrap_err();
assert_eq!(error.kind(), io::ErrorKind::ConnectionRefused);
}
}
in_both_modes! {
#[cfg(any(target_os = "linux", target_os = "android"))]
fn a_pending_connect_resolves_once_accepted<M>() {
let runtime = Runtime::<M>::new().unwrap();
let (listener, address) = listener_with_room_for_one();
runtime.block_on(async {
let _queued = TcpStream::connect(&runtime, address).await.unwrap();
let mut pending = pin!(TcpStream::connect(&runtime, address));
assert!(
poll_immediate(pending.as_mut()).await.is_none(),
"the connection was reported before the listener had room for it",
);
let (_accepted, _) = listener.accept().unwrap();
let stream = pending.await.unwrap();
assert_eq!(stream.peer_addr().unwrap(), address);
});
}
}
in_both_modes! {
#[cfg(any(target_os = "linux", target_os = "android"))]
fn a_connect_that_waits_and_then_fails_reports_the_failure<M>() {
let runtime = Runtime::<M>::new().unwrap();
let (listener, address) = listener_with_room_for_one();
runtime.block_on(async {
let _queued = TcpStream::connect(&runtime, address).await.unwrap();
let mut pending = pin!(TcpStream::connect(&runtime, address));
assert!(
poll_immediate(pending.as_mut()).await.is_none(),
"the connection was reported before the listener had room for it",
);
drop(listener);
let error = pending.await.unwrap_err();
assert_eq!(error.kind(), io::ErrorKind::ConnectionRefused);
});
}
}
in_both_modes! {
fn an_accepted_stream_is_non_blocking<M>() {
let runtime = Runtime::<M>::new().unwrap();
let listener = TcpListener::bind(&runtime, loopback()).unwrap();
let address = listener.local_addr().unwrap();
runtime.block_on(async {
let mut client = TcpStream::connect(&runtime, address).await.unwrap();
let (mut server, _) = listener.accept().await.unwrap();
let mut received = [0; 4];
let (written, read) = join(
after(&runtime, client.write_all(b"late")),
server.read_exact(&mut received),
)
.await;
written.unwrap();
read.unwrap();
assert_eq!(&received, b"late");
});
}
}
in_both_modes! {
fn from_std_makes_a_blocking_listener_non_blocking<M>() {
let runtime = Runtime::<M>::new().unwrap();
let std_listener = std::net::TcpListener::bind(loopback()).unwrap();
let address = std_listener.local_addr().unwrap();
let listener = TcpListener::from_std(&runtime, std_listener).unwrap();
runtime.block_on(async {
let (accepted, client) = join(
listener.accept(),
after(&runtime, TcpStream::connect(&runtime, address)),
)
.await;
let (_server, peer) = accepted.unwrap();
assert_eq!(peer, client.unwrap().local_addr().unwrap());
});
}
}
in_both_modes! {
fn from_std_makes_a_blocking_stream_non_blocking<M>() {
let runtime = Runtime::<M>::new().unwrap();
let std_listener = std::net::TcpListener::bind(loopback()).unwrap();
let mut peer = std::net::TcpStream::connect(std_listener.local_addr().unwrap()).unwrap();
let (accepted, _) = std_listener.accept().unwrap();
let mut stream = TcpStream::from_std(&runtime, accepted).unwrap();
runtime.block_on(async {
let mut received = [0; 4];
let (written, read) = join(
after(&runtime, async { peer.write_all(b"late") }),
stream.read_exact(&mut received),
)
.await;
written.unwrap();
read.unwrap();
assert_eq!(&received, b"late");
});
}
}
in_both_modes! {
fn into_std_hands_back_the_same_connection_in_non_blocking_mode<M>() {
let runtime = Runtime::<M>::new().unwrap();
runtime.block_on(async {
let (client, mut server) = connected(&runtime).await;
let local = client.local_addr().unwrap();
let peer = client.peer_addr().unwrap();
let mut std_client = client.into_std();
assert_eq!(std_client.local_addr().unwrap(), local);
assert_eq!(std_client.peer_addr().unwrap(), peer);
assert_eq!(server.peer_addr().unwrap(), local);
let error = std_client.read(&mut [0; 1]).unwrap_err();
assert_eq!(error.kind(), io::ErrorKind::WouldBlock);
server.write_all(b"ping").await.unwrap();
std_client.set_nonblocking(false).unwrap();
let mut received = [0; 4];
std_client.read_exact(&mut received).unwrap();
assert_eq!(&received, b"ping");
std_client.write_all(b"pong").unwrap();
server.read_exact(&mut received).await.unwrap();
assert_eq!(&received, b"pong");
});
}
}
in_both_modes! {
fn into_std_leaves_the_bytes_that_arrived_for_the_std_stream<M>() {
let runtime = Runtime::<M>::new().unwrap();
runtime.block_on(async {
let (client, mut server) = connected(&runtime).await;
server.write_all(b"early").await.unwrap();
let mut peeked = [0; 5];
let peeked_len = client.peek(&mut peeked).await.unwrap();
assert!(peeked_len > 0);
let mut std_client = client.into_std();
let mut received = vec![0; peeked_len];
std_client.read_exact(&mut received).unwrap();
assert_eq!(received[..], b"early"[..peeked_len]);
});
}
}
in_both_modes! {
fn a_socket_handed_back_by_into_std_can_be_taken_up_again<M>() {
let runtime = Runtime::<M>::new().unwrap();
runtime.block_on(async {
let (client, mut server) = connected(&runtime).await;
let std_client = client.into_std();
let mut client = TcpStream::from_std(&runtime, std_client).unwrap();
let mut received = [0; 4];
let (written, read) = join(
after(&runtime, server.write_all(b"late")),
client.read_exact(&mut received),
)
.await;
written.unwrap();
read.unwrap();
assert_eq!(&received, b"late");
client.write_all(b"back").await.unwrap();
server.read_exact(&mut received).await.unwrap();
assert_eq!(&received, b"back");
});
}
}
in_both_modes! {
fn close_makes_the_peer_read_the_end_of_the_stream<M>() {
let runtime = Runtime::<M>::new().unwrap();
runtime.block_on(async {
let (mut client, mut server) = connected(&runtime).await;
client.write_all(b"bye").await.unwrap();
client.close().await.unwrap();
let mut received = Vec::new();
server.read_to_end(&mut received).await.unwrap();
assert_eq!(received, b"bye");
server.write_all(b"ack").await.unwrap();
let mut answer = [0; 3];
client.read_exact(&mut answer).await.unwrap();
assert_eq!(&answer, b"ack");
client.close().await.unwrap();
});
}
}
in_both_modes! {
fn closing_a_stream_again_leaves_its_read_half_open<M>() {
let runtime = Runtime::<M>::new().unwrap();
runtime.block_on(async {
let (mut client, mut server) = connected(&runtime).await;
client.close().await.unwrap();
let mut received = Vec::new();
server.read_to_end(&mut received).await.unwrap();
assert!(received.is_empty());
client.close().await.unwrap();
server.write_all(b"still open").await.unwrap();
let mut answer = [0; 10];
client.read_exact(&mut answer).await.unwrap();
assert_eq!(&answer, b"still open");
});
}
}
in_both_modes! {
fn closing_through_a_reference_closes_the_stream_for_every_handle<M>() {
let runtime = Runtime::<M>::new().unwrap();
runtime.block_on(async {
let (mut client, mut server) = connected(&runtime).await;
(&client).close().await.unwrap();
assert!(client.write_all(b"too late").await.is_err());
let mut received = Vec::new();
server.read_to_end(&mut received).await.unwrap();
assert!(received.is_empty());
});
}
}
in_both_modes! {
#[cfg(any(target_os = "linux", target_os = "android"))]
fn closing_a_stream_whose_connection_was_reset_succeeds<M>() {
let runtime = Runtime::<M>::new().unwrap();
runtime.block_on(async {
let (mut client, server) = connected(&runtime).await;
client.write_all(b"unread").await.unwrap();
server.peek(&mut [0; 1]).await.unwrap();
drop(server);
let error = client.read(&mut [0; 1]).await.unwrap_err();
assert_eq!(error.kind(), io::ErrorKind::ConnectionReset);
client.close().await.unwrap();
});
}
}
in_both_modes! {
fn shutdown_of_the_write_half_makes_the_peer_read_the_end<M>() {
let runtime = Runtime::<M>::new().unwrap();
runtime.block_on(async {
let (mut client, mut server) = connected(&runtime).await;
client.write_all(b"last words").await.unwrap();
client.shutdown(Shutdown::Write).unwrap();
let mut received = Vec::new();
server.read_to_end(&mut received).await.unwrap();
assert_eq!(received, b"last words");
});
}
}
in_both_modes! {
fn a_reader_and_a_writer_share_a_stream<M>() {
let runtime = Runtime::<M>::new().unwrap();
runtime.block_on(async {
let (client, server) = connected(&runtime).await;
let data = pattern(1 << 20);
let writer = async {
(&client).write_all(&data).await.unwrap();
(&client).close().await.unwrap();
};
let reader = async {
let mut echoed = Vec::new();
(&client).read_to_end(&mut echoed).await.unwrap();
echoed
};
let echo = async {
copy(&server, &mut &server).await.unwrap();
(&server).close().await.unwrap();
};
let (((), echoed), ()) = join(join(writer, reader), echo).await;
assert_eq!(echoed.len(), data.len());
assert!(echoed == data, "the echo differs from what was sent");
});
}
}
in_both_modes! {
fn a_write_that_waits_resumes_once_the_peer_reads<M>() {
let runtime = Runtime::<M>::new().unwrap();
let std_listener = std::net::TcpListener::bind(loopback()).unwrap();
let address = std_listener.local_addr().unwrap();
let chunk = pattern(64 * 1024);
runtime.block_on(async {
let client = TcpStream::connect(&runtime, address).await.unwrap();
let (mut peer, _) = std_listener.accept().unwrap();
let mut writer = &client;
let mut filled = 0;
poll_fn(|cx| loop {
match Pin::new(&mut writer).poll_write(cx, &chunk) {
Poll::Ready(written) => filled += written.unwrap(),
Poll::Pending => break Poll::Ready(()),
}
})
.await;
let total = filled + chunk.len();
let reading = thread::spawn(move || {
thread::sleep(DELAY);
peer.read_exact(&mut vec![0; total]).unwrap();
});
writer.write_all(&chunk).await.unwrap();
reading.join().unwrap();
});
}
}
in_both_modes! {
fn a_peek_or_a_read_that_waits_does_not_spin<M>() {
let runtime = Runtime::<M>::new().unwrap();
runtime.block_on(async {
let (mut client, mut server) = connected(&runtime).await;
let mut buffer = [0; 1];
let peek_polls = Cell::new(0);
let (peeked, written) = join(
counting_polls(&peek_polls, server.peek(&mut buffer)),
after(&runtime, client.write_all(b"1")),
)
.await;
assert_eq!(peeked.unwrap(), 1);
written.unwrap();
assert!(peek_polls.get() <= 10, "the peek was polled {} times", peek_polls.get());
server.read_exact(&mut buffer).await.unwrap();
let read_polls = Cell::new(0);
let (read, written) = join(
counting_polls(&read_polls, server.read_exact(&mut buffer)),
after(&runtime, client.write_all(b"2")),
)
.await;
read.unwrap();
written.unwrap();
assert!(read_polls.get() <= 10, "the read was polled {} times", read_polls.get());
});
}
}
in_both_modes! {
fn a_dropped_accept_loses_no_connection<M>() {
let runtime = Runtime::<M>::new().unwrap();
let listener = TcpListener::bind(&runtime, loopback()).unwrap();
let address = listener.local_addr().unwrap();
runtime.block_on(async {
let client = {
let mut accept = pin!(listener.accept());
assert!(poll_immediate(accept.as_mut()).await.is_none());
let client = TcpStream::connect(&runtime, address).await.unwrap();
runtime.sleep(DELAY).await;
client
};
let (_server, peer) = listener.accept().await.unwrap();
assert_eq!(peer, client.local_addr().unwrap());
});
}
}
in_both_modes! {
fn incoming_yields_one_stream_per_connection<M>() {
let runtime = Runtime::<M>::new().unwrap();
let listener = TcpListener::bind(&runtime, loopback()).unwrap();
let address = listener.local_addr().unwrap();
runtime.block_on(async {
let mut incoming = listener.incoming();
assert!(poll_immediate(incoming.next()).await.is_none());
let (first_accepted, first) = join(
incoming.next(),
after(&runtime, TcpStream::connect(&runtime, address)),
)
.await;
let first_accepted = first_accepted.expect("the stream never ends").unwrap();
let first = first.unwrap();
let second = TcpStream::connect(&runtime, address).await.unwrap();
let third = TcpStream::connect(&runtime, address).await.unwrap();
let second_accepted = incoming.next().await.expect("the stream never ends").unwrap();
let third_accepted = incoming.next().await.expect("the stream never ends").unwrap();
assert_eq!(first_accepted.peer_addr().unwrap(), first.local_addr().unwrap());
assert_eq!(second_accepted.peer_addr().unwrap(), second.local_addr().unwrap());
assert_eq!(third_accepted.peer_addr().unwrap(), third.local_addr().unwrap());
});
}
}
in_both_modes! {
fn peek_leaves_the_bytes_for_the_next_read<M>() {
let runtime = Runtime::<M>::new().unwrap();
runtime.block_on(async {
let (mut client, mut server) = connected(&runtime).await;
let mut peeked = [0; 16];
let (written, peeked_len) = join(
after(&runtime, client.write_all(b"peeked")),
server.peek(&mut peeked),
)
.await;
written.unwrap();
let peeked_len = peeked_len.unwrap();
assert!(peeked_len > 0);
assert_eq!(peeked[..peeked_len], b"peeked"[..peeked_len]);
let mut read = [0; 6];
server.read_exact(&mut read).await.unwrap();
assert_eq!(&read, b"peeked");
});
}
}
in_both_modes! {
fn ttl_and_nodelay_read_back_what_was_set<M>() {
let runtime = Runtime::<M>::new().unwrap();
let listener = TcpListener::bind(&runtime, loopback()).unwrap();
let address = listener.local_addr().unwrap();
listener.set_ttl(42).unwrap();
assert_eq!(listener.ttl().unwrap(), 42);
runtime.block_on(async {
let stream = TcpStream::connect(&runtime, address).await.unwrap();
stream.set_ttl(43).unwrap();
assert_eq!(stream.ttl().unwrap(), 43);
stream.set_nodelay(true).unwrap();
assert!(stream.nodelay().unwrap());
stream.set_nodelay(false).unwrap();
assert!(!stream.nodelay().unwrap());
});
}
}
#[test]
#[timeout(15000)]
fn a_shared_stream_crosses_threads() {
let runtime = SharedRuntime::new().unwrap();
let (client, mut server) = runtime.block_on(connected(&runtime));
let user = thread::spawn({
let runtime = runtime.clone();
move || {
runtime.block_on(async move {
let mut client = client;
let mut request = [0; 5];
client.read_exact(&mut request).await.unwrap();
client
.write_all(&request.to_ascii_uppercase())
.await
.unwrap();
});
}
});
thread::sleep(DELAY);
block_on(server.write_all(b"hello")).unwrap();
user.join().unwrap();
let mut response = [0; 5];
runtime.block_on(server.read_exact(&mut response)).unwrap();
assert_eq!(&response, b"HELLO");
}
#[test]
#[timeout(15000)]
fn shared_tasks_use_sockets() {
let runtime = SharedRuntime::new().unwrap();
let listener = TcpListener::bind(&runtime, loopback()).unwrap();
let address = listener.local_addr().unwrap();
runtime.block_on(async {
let server = runtime.spawn("an echo server", async move {
let (stream, _) = listener.accept().await.unwrap();
copy(&stream, &mut &stream).await.unwrap();
(&stream).close().await.unwrap();
});
let client = runtime.spawn("a client", {
let runtime = runtime.clone();
async move {
let mut stream = TcpStream::connect(&runtime, address).await.unwrap();
stream.write_all(b"hello").await.unwrap();
stream.close().await.unwrap();
let mut echoed = Vec::new();
stream.read_to_end(&mut echoed).await.unwrap();
echoed
}
});
assert_eq!(client.await.unwrap(), b"hello");
server.await.unwrap();
});
}
#[test]
#[timeout(15000)]
fn several_tasks_accept_from_one_listener() {
let runtime = SharedRuntime::new().unwrap();
let listener = Arc::new(TcpListener::bind(&runtime, loopback()).unwrap());
let address = listener.local_addr().unwrap();
runtime.block_on(async {
let acceptors: Vec<_> = (0..3)
.map(|_| {
let listener = listener.clone();
runtime.spawn("an acceptor", async move {
let (_stream, peer) = listener.accept().await.unwrap();
peer
})
})
.collect();
runtime.sleep(DELAY).await;
let mut clients = Vec::new();
for _ in 0..3 {
clients.push(TcpStream::connect(&runtime, address).await.unwrap());
}
let mut accepted = Vec::new();
for acceptor in acceptors {
accepted.push(acceptor.await.unwrap());
}
accepted.sort();
let mut made: Vec<_> = clients
.iter()
.map(|client| client.local_addr().unwrap())
.collect();
made.sort();
assert_eq!(accepted, made);
});
}
#[test]
#[timeout(15000)]
fn accept_and_incoming_wait_together() {
let runtime = SharedRuntime::new().unwrap();
let listener = Arc::new(TcpListener::bind(&runtime, loopback()).unwrap());
let address = listener.local_addr().unwrap();
runtime.block_on(async {
let acceptor = runtime.spawn("an acceptor", {
let listener = listener.clone();
async move {
let (_stream, peer) = listener.accept().await.unwrap();
peer
}
});
let streamer = runtime.spawn("an incoming stream", {
let listener = listener.clone();
async move {
let stream = listener
.incoming()
.next()
.await
.expect("the stream never ends")
.unwrap();
stream.peer_addr().unwrap()
}
});
runtime.sleep(DELAY).await;
let first = TcpStream::connect(&runtime, address).await.unwrap();
let second = TcpStream::connect(&runtime, address).await.unwrap();
let mut accepted = [acceptor.await.unwrap(), streamer.await.unwrap()];
accepted.sort();
let mut made = [first.local_addr().unwrap(), second.local_addr().unwrap()];
made.sort();
assert_eq!(accepted, made);
});
}
#[test]
#[timeout(15000)]
fn several_tasks_peek_at_one_stream() {
let runtime = SharedRuntime::new().unwrap();
runtime.block_on(async {
let (mut client, server) = connected(&runtime).await;
let server = Arc::new(server);
let peekers: Vec<_> = (0..2)
.map(|_| {
let server = server.clone();
runtime.spawn("a peeker", async move {
let mut peeked = [0; 16];
let len = server.peek(&mut peeked).await.unwrap();
peeked[..len].to_vec()
})
})
.collect();
runtime.sleep(DELAY).await;
client.write_all(b"peeked").await.unwrap();
for peeker in peekers {
let peeked = peeker.await.unwrap();
assert!(!peeked.is_empty() && b"peeked".starts_with(&peeked));
}
});
}
in_both_modes! {
fn sockets_print_and_expose_the_descriptors_of_the_std_sockets_they_wrap<M>() {
let runtime = Runtime::<M>::new().unwrap();
let std_listener = std::net::TcpListener::bind(loopback()).unwrap();
let address = std_listener.local_addr().unwrap();
let std_stream = std::net::TcpStream::connect(address).unwrap();
let printed_listener = format!("{std_listener:?}");
let printed_stream = format!("{std_stream:?}");
#[cfg(unix)]
let (raw_listener, raw_stream) = (std_listener.as_raw_fd(), std_stream.as_raw_fd());
#[cfg(windows)]
let (raw_listener, raw_stream) =
(std_listener.as_raw_socket(), std_stream.as_raw_socket());
let listener = TcpListener::from_std(&runtime, std_listener).unwrap();
let stream = TcpStream::from_std(&runtime, std_stream).unwrap();
assert_eq!(format!("{listener:?}"), printed_listener);
assert_eq!(format!("{stream:?}"), printed_stream);
assert_eq!(
format!("{:?}", listener.incoming()),
format!("Incoming {{ listener: {printed_listener} }}"),
);
#[cfg(unix)]
{
assert_eq!(listener.as_raw_fd(), raw_listener);
assert_eq!(stream.as_raw_fd(), raw_stream);
}
#[cfg(windows)]
{
assert_eq!(listener.as_raw_socket(), raw_listener);
assert_eq!(stream.as_raw_socket(), raw_stream);
}
let listener_address = SockRef::from(&listener).local_addr().unwrap();
assert_eq!(listener_address.as_socket(), Some(address));
let stream_peer = SockRef::from(&stream).peer_addr().unwrap();
assert_eq!(stream_peer.as_socket(), Some(address));
}
}
#[test]
#[timeout(15000)]
fn shared_sockets_are_send_sync_and_unpin() {
fn sent_and_shared<T>()
where
T: Send + Sync + Unpin,
{
}
sent_and_shared::<TcpListener<Shared>>();
sent_and_shared::<TcpStream<Shared>>();
sent_and_shared::<Incoming<'static, Shared>>();
}
#[test]
#[timeout(15000)]
fn local_sockets_are_unpin() {
fn unpin<T>()
where
T: Unpin,
{
}
unpin::<TcpListener<Local>>();
unpin::<TcpStream<Local>>();
unpin::<Incoming<'static, Local>>();
}
async fn connected<M>(runtime: &Runtime<M>) -> (TcpStream<M>, TcpStream<M>)
where
M: Mode,
{
let listener = TcpListener::bind(runtime, loopback()).unwrap();
let client = TcpStream::connect(runtime, listener.local_addr().unwrap())
.await
.unwrap();
let (server, _) = listener.accept().await.unwrap();
(client, server)
}