#[cfg(unix)]
use std::os::fd::AsRawFd;
#[cfg(windows)]
use std::os::windows::io::AsRawSocket;
use std::{
cell::Cell,
future::Future,
io,
net::{Ipv4Addr, Ipv6Addr, SocketAddrV4},
pin::pin,
sync::Arc,
thread,
};
use futures::{
executor::block_on,
future::{join, poll_immediate},
};
use ntest::timeout;
use socket2::SockRef;
use super::{DELAY, after, counting_polls, in_both_modes, loopback};
use crate::{Local, Mode, Runtime, Shared, SharedRuntime, net::UdpSocket};
in_both_modes! {
fn a_datagram_goes_from_one_socket_to_another<M>() {
let runtime = Runtime::<M>::new().unwrap();
let (client, server) = pair(&runtime);
let client_address = client.local_addr().unwrap();
let server_address = server.local_addr().unwrap();
runtime.block_on(async {
assert_eq!(client.send_to(b"ping", server_address).await.unwrap(), 4);
let mut received = [0; 16];
let (len, from) = server.recv_from(&mut received).await.unwrap();
assert_eq!(&received[..len], b"ping");
assert_eq!(from, client_address);
assert_eq!(server.send_to(b"pong", from).await.unwrap(), 4);
let (len, from) = client.recv_from(&mut received).await.unwrap();
assert_eq!(&received[..len], b"pong");
assert_eq!(from, server_address);
});
}
}
in_both_modes! {
fn a_connected_socket_sends_and_receives_without_addresses<M>() {
let runtime = Runtime::<M>::new().unwrap();
let (first, second) = pair(&runtime);
let first_address = first.local_addr().unwrap();
let second_address = second.local_addr().unwrap();
assert_eq!(first.peer_addr().unwrap_err().kind(), io::ErrorKind::NotConnected);
runtime.block_on(async {
assert!(first.send(b"nowhere").await.is_err());
});
first.connect(second_address).unwrap();
second.connect(first_address).unwrap();
assert_eq!(first.peer_addr().unwrap(), second_address);
assert_eq!(second.peer_addr().unwrap(), first_address);
runtime.block_on(async {
assert_eq!(first.send(b"ping").await.unwrap(), 4);
let mut received = [0; 16];
let len = second.recv(&mut received).await.unwrap();
assert_eq!(&received[..len], b"ping");
assert_eq!(second.send(b"pong").await.unwrap(), 4);
let len = first.recv(&mut received).await.unwrap();
assert_eq!(&received[..len], b"pong");
});
}
}
in_both_modes! {
fn peek_from_leaves_the_datagram_for_the_next_receive<M>() {
let runtime = Runtime::<M>::new().unwrap();
let (client, server) = pair(&runtime);
let client_address = client.local_addr().unwrap();
let server_address = server.local_addr().unwrap();
runtime.block_on(async {
let mut peeked = [0; 16];
let (peek, sent) = join(
server.peek_from(&mut peeked),
after(&runtime, client.send_to(b"peeked", server_address)),
)
.await;
sent.unwrap();
let (peeked_len, peeked_from) = peek.unwrap();
assert_eq!(&peeked[..peeked_len], b"peeked");
assert_eq!(peeked_from, client_address);
let mut received = [0; 16];
let (len, from) = poll_immediate(server.recv_from(&mut received))
.await
.expect("the peeked datagram is still on the socket")
.unwrap();
assert_eq!(&received[..len], b"peeked");
assert_eq!(from, client_address);
});
}
}
in_both_modes! {
fn peek_leaves_the_datagram_for_the_next_receive<M>() {
let runtime = Runtime::<M>::new().unwrap();
let (client, server) = connected_pair(&runtime);
runtime.block_on(async {
let mut peeked = [0; 16];
let (peek, sent) = join(
server.peek(&mut peeked),
after(&runtime, client.send(b"peeked")),
)
.await;
sent.unwrap();
let peeked_len = peek.unwrap();
assert_eq!(&peeked[..peeked_len], b"peeked");
let mut received = [0; 16];
let len = poll_immediate(server.recv(&mut received))
.await
.expect("the peeked datagram is still on the socket")
.unwrap();
assert_eq!(&received[..len], b"peeked");
});
}
}
in_both_modes! {
fn a_receive_waits_for_a_datagram_without_blocking_the_thread<M>() {
let runtime = Runtime::<M>::new().unwrap();
let (client, server) = pair(&runtime);
let client_address = client.local_addr().unwrap();
let server_address = server.local_addr().unwrap();
runtime.block_on(async {
let mut received = [0; 16];
let (received_from, sent) = join(
server.recv_from(&mut received),
after(&runtime, client.send_to(b"late", server_address)),
)
.await;
let (len, from) = received_from.unwrap();
sent.unwrap();
assert_eq!(&received[..len], b"late");
assert_eq!(from, client_address);
});
}
}
in_both_modes! {
fn a_receive_that_waits_does_not_spin<M>() {
let runtime = Runtime::<M>::new().unwrap();
let (client, server) = connected_pair(&runtime);
let mut buffer = [0; 16];
runtime.block_on(async {
let (received, polls) =
polls_while_waiting(&runtime, &client, server.recv_from(&mut buffer)).await;
received.unwrap();
assert!(polls <= 10, "`recv_from` was polled {polls} times");
let (received, polls) =
polls_while_waiting(&runtime, &client, server.recv(&mut buffer)).await;
received.unwrap();
assert!(polls <= 10, "`recv` was polled {polls} times");
let (peeked, polls) =
polls_while_waiting(&runtime, &client, server.peek_from(&mut buffer)).await;
peeked.unwrap();
assert!(polls <= 10, "`peek_from` was polled {polls} times");
server.recv(&mut buffer).await.unwrap();
let (peeked, polls) =
polls_while_waiting(&runtime, &client, server.peek(&mut buffer)).await;
peeked.unwrap();
assert!(polls <= 10, "`peek` was polled {polls} times");
server.recv(&mut buffer).await.unwrap();
});
}
}
in_both_modes! {
fn a_dropped_receive_loses_no_datagram<M>() {
let runtime = Runtime::<M>::new().unwrap();
let (client, server) = pair(&runtime);
let server_address = server.local_addr().unwrap();
runtime.block_on(async {
let mut buffer = [0; 16];
{
let mut abandoned = pin!(server.recv_from(&mut buffer));
assert!(poll_immediate(abandoned.as_mut()).await.is_none());
}
let (received, sent) = join(
server.recv_from(&mut buffer),
after(&runtime, client.send_to(b"kept", server_address)),
)
.await;
sent.unwrap();
let (len, _) = received.unwrap();
assert_eq!(&buffer[..len], b"kept");
});
}
}
in_both_modes! {
fn addresses_are_taken_as_pairs_and_as_socket_addresses<M>() {
let runtime = Runtime::<M>::new().unwrap();
let by_pair = UdpSocket::bind(&runtime, (Ipv4Addr::LOCALHOST, 0)).unwrap();
let by_address =
UdpSocket::bind(&runtime, SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0)).unwrap();
let pair_port = by_pair.local_addr().unwrap().port();
let address_port = by_address.local_addr().unwrap().port();
runtime.block_on(async {
by_pair
.send_to(b"to an address", SocketAddrV4::new(Ipv4Addr::LOCALHOST, address_port))
.await
.unwrap();
by_address
.send_to(b"to a pair", (Ipv4Addr::LOCALHOST, pair_port))
.await
.unwrap();
let mut received = [0; 16];
let (len, from) = by_address.recv_from(&mut received).await.unwrap();
assert_eq!(&received[..len], b"to an address");
assert_eq!(from.port(), pair_port);
let (len, from) = by_pair.recv_from(&mut received).await.unwrap();
assert_eq!(&received[..len], b"to a pair");
assert_eq!(from.port(), address_port);
});
by_pair
.connect(SocketAddrV4::new(Ipv4Addr::LOCALHOST, address_port))
.unwrap();
by_address
.connect((Ipv4Addr::LOCALHOST, pair_port))
.unwrap();
assert_eq!(by_pair.peer_addr().unwrap().port(), address_port);
assert_eq!(by_address.peer_addr().unwrap().port(), pair_port);
}
}
in_both_modes! {
fn from_std_makes_a_blocking_socket_non_blocking<M>() {
let runtime = Runtime::<M>::new().unwrap();
let std_socket = std::net::UdpSocket::bind(loopback()).unwrap();
let address = std_socket.local_addr().unwrap();
let peer = std::net::UdpSocket::bind(loopback()).unwrap();
let peer_address = peer.local_addr().unwrap();
let socket = UdpSocket::from_std(&runtime, std_socket).unwrap();
runtime.block_on(async {
let mut received = [0; 16];
let (received_from, sent) = join(
socket.recv_from(&mut received),
after(&runtime, async { peer.send_to(b"late", address) }),
)
.await;
let (len, from) = received_from.unwrap();
sent.unwrap();
assert_eq!(&received[..len], b"late");
assert_eq!(from, peer_address);
});
}
}
in_both_modes! {
fn ttl_and_broadcast_read_back_what_was_set<M>() {
let runtime = Runtime::<M>::new().unwrap();
let socket = UdpSocket::bind(&runtime, loopback()).unwrap();
socket.set_ttl(42).unwrap();
assert_eq!(socket.ttl().unwrap(), 42);
socket.set_broadcast(true).unwrap();
assert!(socket.broadcast().unwrap());
socket.set_broadcast(false).unwrap();
assert!(!socket.broadcast().unwrap());
}
}
in_both_modes! {
fn the_ipv4_multicast_options_read_back_what_was_set<M>() {
let runtime = Runtime::<M>::new().unwrap();
let socket = UdpSocket::bind(&runtime, loopback()).unwrap();
socket.set_multicast_loop_v4(false).unwrap();
assert!(!socket.multicast_loop_v4().unwrap());
socket.set_multicast_loop_v4(true).unwrap();
assert!(socket.multicast_loop_v4().unwrap());
socket.set_multicast_ttl_v4(7).unwrap();
assert_eq!(socket.multicast_ttl_v4().unwrap(), 7);
}
}
in_both_modes! {
#[cfg(target_os = "linux")]
fn a_socket_joins_and_leaves_an_ipv4_multicast_group<M>() {
let runtime = Runtime::<M>::new().unwrap();
let socket = UdpSocket::bind(&runtime, loopback()).unwrap();
let group = Ipv4Addr::new(239, 255, 0, 1);
socket.join_multicast_v4(group, Ipv4Addr::LOCALHOST).unwrap();
socket.leave_multicast_v4(group, Ipv4Addr::LOCALHOST).unwrap();
assert!(socket.leave_multicast_v4(group, Ipv4Addr::LOCALHOST).is_err());
}
}
in_both_modes! {
fn the_ipv6_multicast_options_read_back_what_was_set<M>() {
if std::net::UdpSocket::bind((Ipv6Addr::LOCALHOST, 0)).is_err() {
return;
}
let runtime = Runtime::<M>::new().unwrap();
let socket = UdpSocket::bind(&runtime, (Ipv6Addr::UNSPECIFIED, 0)).unwrap();
socket.set_multicast_loop_v6(false).unwrap();
assert!(!socket.multicast_loop_v6().unwrap());
socket.set_multicast_loop_v6(true).unwrap();
assert!(socket.multicast_loop_v6().unwrap());
let group = Ipv6Addr::new(0xff02, 0, 0, 0, 0, 0, 0, 0x1234);
if socket.join_multicast_v6(&group, 0).is_ok() {
socket.leave_multicast_v6(&group, 0).unwrap();
}
}
}
#[test]
#[timeout(15000)]
fn a_shared_socket_crosses_threads() {
let runtime = SharedRuntime::new().unwrap();
let (client, server) = runtime.block_on(async { pair(&runtime) });
let server_address = server.local_addr().unwrap();
let user = thread::spawn({
let runtime = runtime.clone();
move || {
runtime.block_on(async move {
let mut request = [0; 16];
let (len, from) = server.recv_from(&mut request).await.unwrap();
server
.send_to(&request[..len].to_ascii_uppercase(), from)
.await
.unwrap();
});
}
});
thread::sleep(DELAY);
block_on(client.send_to(b"hello", server_address)).unwrap();
user.join().unwrap();
let mut response = [0; 16];
let (len, from) = runtime.block_on(client.recv_from(&mut response)).unwrap();
assert_eq!(&response[..len], b"HELLO");
assert_eq!(from, server_address);
}
#[test]
#[timeout(15000)]
fn shared_tasks_use_sockets() {
let runtime = SharedRuntime::new().unwrap();
let (client, server) = pair(&runtime);
let server_address = server.local_addr().unwrap();
runtime.block_on(async {
let echo = runtime.spawn("an echo server", async move {
let mut buffer = [0; 16];
let (len, from) = server.recv_from(&mut buffer).await.unwrap();
server.send_to(&buffer[..len], from).await.unwrap();
});
let asker = runtime.spawn("a client", async move {
client.send_to(b"hello", server_address).await.unwrap();
let mut answer = [0; 16];
let (len, _) = client.recv_from(&mut answer).await.unwrap();
answer[..len].to_vec()
});
assert_eq!(asker.await.unwrap(), b"hello");
echo.await.unwrap();
});
}
#[test]
#[timeout(15000)]
fn a_receive_is_woken_after_another_task_gave_up_its_own() {
let runtime = SharedRuntime::new().unwrap();
let (client, server) = pair(&runtime);
let server_address = server.local_addr().unwrap();
let server = Arc::new(server);
runtime.block_on(async {
let first = runtime.spawn("a receiver that gives up", {
let server = server.clone();
async move { server.recv_from(&mut [0; 16]).await }
});
runtime.sleep(DELAY).await;
drop(first);
let second = runtime.spawn("a receiver", {
let server = server.clone();
async move {
let mut buffer = [0; 16];
let (len, _) = server.recv_from(&mut buffer).await.unwrap();
buffer[..len].to_vec()
}
});
runtime.sleep(DELAY).await;
client.send_to(b"kept", server_address).await.unwrap();
assert_eq!(second.await.unwrap(), b"kept");
});
}
#[test]
#[timeout(15000)]
fn several_tasks_receive_on_one_socket() {
let runtime = SharedRuntime::new().unwrap();
let (client, server) = pair(&runtime);
let server_address = server.local_addr().unwrap();
let server = Arc::new(server);
runtime.block_on(async {
let receivers: Vec<_> = (0..2)
.map(|_| {
let server = server.clone();
runtime.spawn("a receiver", async move {
let mut buffer = [0; 16];
let (len, _) = server.recv_from(&mut buffer).await.unwrap();
buffer[..len].to_vec()
})
})
.collect();
runtime.sleep(DELAY).await;
client.send_to(b"first", server_address).await.unwrap();
client.send_to(b"second", server_address).await.unwrap();
let mut received = Vec::new();
for receiver in receivers {
received.push(receiver.await.unwrap());
}
received.sort();
assert_eq!(received, [b"first".to_vec(), b"second".to_vec()]);
});
}
in_both_modes! {
fn a_socket_prints_and_exposes_the_descriptor_of_the_std_socket_it_wraps<M>() {
let runtime = Runtime::<M>::new().unwrap();
let std_socket = std::net::UdpSocket::bind(loopback()).unwrap();
let address = std_socket.local_addr().unwrap();
let printed = format!("{std_socket:?}");
#[cfg(unix)]
let raw = std_socket.as_raw_fd();
#[cfg(windows)]
let raw = std_socket.as_raw_socket();
let socket = UdpSocket::from_std(&runtime, std_socket).unwrap();
assert_eq!(format!("{socket:?}"), printed);
#[cfg(unix)]
assert_eq!(socket.as_raw_fd(), raw);
#[cfg(windows)]
assert_eq!(socket.as_raw_socket(), raw);
let found = SockRef::from(&socket).local_addr().unwrap();
assert_eq!(found.as_socket(), Some(address));
}
}
#[test]
#[timeout(15000)]
fn sockets_are_unpin_and_shared_ones_are_send_and_sync() {
fn sent_and_shared<T>()
where
T: Send + Sync + Unpin,
{
}
fn unpin<T>()
where
T: Unpin,
{
}
sent_and_shared::<UdpSocket<Shared>>();
unpin::<UdpSocket<Local>>();
}
fn pair<M>(runtime: &Runtime<M>) -> (UdpSocket<M>, UdpSocket<M>)
where
M: Mode,
{
let first = UdpSocket::bind(runtime, loopback()).unwrap();
let second = UdpSocket::bind(runtime, loopback()).unwrap();
(first, second)
}
fn connected_pair<M>(runtime: &Runtime<M>) -> (UdpSocket<M>, UdpSocket<M>)
where
M: Mode,
{
let (first, second) = pair(runtime);
first.connect(second.local_addr().unwrap()).unwrap();
second.connect(first.local_addr().unwrap()).unwrap();
(first, second)
}
async fn polls_while_waiting<M, F>(
runtime: &Runtime<M>,
sender: &UdpSocket<M>,
receive: F,
) -> (F::Output, usize)
where
M: Mode,
F: Future,
{
let polls = Cell::new(0);
let (output, sent) = join(
counting_polls(&polls, receive),
after(runtime, sender.send(b"1")),
)
.await;
sent.unwrap();
(output, polls.get())
}