Skip to content

Commit

Permalink
Test UDP layer in isolation
Browse files Browse the repository at this point in the history
  • Loading branch information
Ralith committed Dec 29, 2023
1 parent 7b6a448 commit 55234e1
Showing 1 changed file with 143 additions and 0 deletions.
143 changes: 143 additions & 0 deletions quinn-udp/tests/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
use std::{
io::IoSliceMut,
net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, UdpSocket},
slice,
};

use bytes::Bytes;
use quinn_udp::{EcnCodepoint, RecvMeta, Transmit, UdpSocketState};
use socket2::Socket;

#[test]
fn basic() {
let send = UdpSocket::bind("[::1]:0").unwrap();
let recv = UdpSocket::bind("[::1]:0").unwrap();
let dst_addr = recv.local_addr().unwrap();
test_send_recv(
&send.into(),
&recv.into(),
Transmit {
destination: dst_addr,
ecn: None,
contents: Bytes::from_static(b"hello"),
segment_size: None,
src_ip: None,
},
);
}

#[test]
#[cfg_attr(windows, ignore)]
fn ecn_v6() {
let recv = socket2::Socket::new(
socket2::Domain::IPV6,
socket2::Type::DGRAM,
Some(socket2::Protocol::UDP),
)
.unwrap();
recv.set_only_v6(false).unwrap();
// We must use the unspecified address here, rather than a local address, to support dual-stack
// mode
recv.bind(&socket2::SockAddr::from(
"[::]:0".parse::<SocketAddr>().unwrap(),
))
.unwrap();
let recv_v6 = SocketAddr::V6(SocketAddrV6::new(
Ipv6Addr::LOCALHOST,
recv.local_addr().unwrap().as_socket().unwrap().port(),
0,
0,
));
let recv_v4 = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, recv_v6.port()));
for (src, dst) in [("[::1]:0", recv_v6), ("127.0.0.1:0", recv_v4)] {
dbg!(src, dst);
let send = UdpSocket::bind(src).unwrap();
let send = Socket::from(send);
for codepoint in [EcnCodepoint::Ect0, EcnCodepoint::Ect1, EcnCodepoint::Ce] {
test_send_recv(
&send,
&recv,
Transmit {
destination: dst,
ecn: Some(codepoint),
contents: Bytes::from_static(b"hello"),
segment_size: None,
src_ip: None,
},
);
}
}
}

#[test]
#[cfg_attr(windows, ignore)]
fn ecn_v4() {
let send = Socket::from(UdpSocket::bind("127.0.0.1:0").unwrap());
let recv = Socket::from(UdpSocket::bind("127.0.0.1:0").unwrap());
for codepoint in [EcnCodepoint::Ect0, EcnCodepoint::Ect1, EcnCodepoint::Ce] {
test_send_recv(
&send,
&recv,
Transmit {
destination: recv.local_addr().unwrap().as_socket().unwrap(),
ecn: Some(codepoint),
contents: Bytes::from_static(b"hello"),
segment_size: None,
src_ip: None,
},
);
}
}

fn test_send_recv(send: &Socket, recv: &Socket, transmit: Transmit) {
let send_state = UdpSocketState::new(send.into()).unwrap();
let recv_state = UdpSocketState::new(recv.into()).unwrap();

// Reverse non-blocking flag set by `UdpSocketState` to make the test non-racy
recv.set_nonblocking(false).unwrap();

send_state
.send((&send).into(), slice::from_ref(&transmit))
.unwrap();

let mut buf = [0; 1024];
let mut meta = RecvMeta::default();
let n = recv_state
.recv(
recv.into(),
&mut [IoSliceMut::new(&mut buf)],
slice::from_mut(&mut meta),
)
.unwrap();

let send_v6 = send.local_addr().unwrap().as_socket().unwrap().is_ipv6();
let recv_v6 = recv.local_addr().unwrap().as_socket().unwrap().is_ipv6();

assert_eq!(n, 1);
match send_v6 == recv_v6 {
true => assert_eq!(meta.addr, send.local_addr().unwrap().as_socket().unwrap()),
false => assert_eq!(
meta.addr,
to_v6_mapped(send.local_addr().unwrap().as_socket().unwrap())
),
}
assert_eq!(&buf[..meta.len], transmit.contents);
assert_eq!(meta.stride, meta.len);
assert_eq!(meta.ecn, transmit.ecn);
#[cfg(unix)]
{
let dst = meta.dst_ip.unwrap();
match (send_v6, recv_v6) {
(_, false) => assert_eq!(dst, Ipv4Addr::LOCALHOST),
(false, true) => assert_eq!(dst, Ipv4Addr::LOCALHOST.to_ipv6_mapped()),
(true, true) => assert_eq!(dst, Ipv6Addr::LOCALHOST),
}
}
}

fn to_v6_mapped(x: SocketAddr) -> SocketAddr {
match x {
SocketAddr::V4(x) => SocketAddrV6::new(x.ip().to_ipv6_mapped(), x.port(), 0, 0).into(),
SocketAddr::V6(_) => x,
}
}

0 comments on commit 55234e1

Please sign in to comment.