1*b315a0a8SYosh use test_programs::sockets::attempt_random_port;
2*b315a0a8SYosh use test_programs::sockets::supports_ipv6;
3*b315a0a8SYosh use test_programs::wasi::sockets::network::{
4*b315a0a8SYosh ErrorCode, IpAddress, IpAddressFamily, IpSocketAddress, Network,
5*b315a0a8SYosh };
6*b315a0a8SYosh use test_programs::wasi::sockets::udp::UdpSocket;
7*b315a0a8SYosh
8*b315a0a8SYosh /// Bind a socket and let the system determine a port.
test_udp_bind_ephemeral_port(net: &Network, ip: IpAddress)9*b315a0a8SYosh fn test_udp_bind_ephemeral_port(net: &Network, ip: IpAddress) {
10*b315a0a8SYosh let bind_addr = IpSocketAddress::new(ip, 0);
11*b315a0a8SYosh
12*b315a0a8SYosh let sock = UdpSocket::new(ip.family()).unwrap();
13*b315a0a8SYosh sock.blocking_bind(net, bind_addr).unwrap();
14*b315a0a8SYosh
15*b315a0a8SYosh let bound_addr = sock.local_address().unwrap();
16*b315a0a8SYosh
17*b315a0a8SYosh assert_eq!(bind_addr.ip(), bound_addr.ip());
18*b315a0a8SYosh assert_ne!(bind_addr.port(), bound_addr.port());
19*b315a0a8SYosh }
20*b315a0a8SYosh
21*b315a0a8SYosh /// Bind a socket on a specified port.
test_udp_bind_specific_port(net: &Network, ip: IpAddress)22*b315a0a8SYosh fn test_udp_bind_specific_port(net: &Network, ip: IpAddress) {
23*b315a0a8SYosh let sock = UdpSocket::new(ip.family()).unwrap();
24*b315a0a8SYosh
25*b315a0a8SYosh let bind_addr =
26*b315a0a8SYosh attempt_random_port(ip, |bind_addr| sock.blocking_bind(net, bind_addr)).unwrap();
27*b315a0a8SYosh
28*b315a0a8SYosh let bound_addr = sock.local_address().unwrap();
29*b315a0a8SYosh
30*b315a0a8SYosh assert_eq!(bind_addr.ip(), bound_addr.ip());
31*b315a0a8SYosh assert_eq!(bind_addr.port(), bound_addr.port());
32*b315a0a8SYosh }
33*b315a0a8SYosh
34*b315a0a8SYosh /// Two sockets may not be actively bound to the same address at the same time.
test_udp_bind_addrinuse(net: &Network, ip: IpAddress)35*b315a0a8SYosh fn test_udp_bind_addrinuse(net: &Network, ip: IpAddress) {
36*b315a0a8SYosh let bind_addr = IpSocketAddress::new(ip, 0);
37*b315a0a8SYosh
38*b315a0a8SYosh let sock1 = UdpSocket::new(ip.family()).unwrap();
39*b315a0a8SYosh sock1.blocking_bind(net, bind_addr).unwrap();
40*b315a0a8SYosh
41*b315a0a8SYosh let bound_addr = sock1.local_address().unwrap();
42*b315a0a8SYosh
43*b315a0a8SYosh let sock2 = UdpSocket::new(ip.family()).unwrap();
44*b315a0a8SYosh assert!(matches!(
45*b315a0a8SYosh sock2.blocking_bind(net, bound_addr),
46*b315a0a8SYosh Err(ErrorCode::AddressInUse)
47*b315a0a8SYosh ));
48*b315a0a8SYosh }
49*b315a0a8SYosh
50*b315a0a8SYosh // Try binding to an address that is not configured on the system.
test_udp_bind_addrnotavail(net: &Network, ip: IpAddress)51*b315a0a8SYosh fn test_udp_bind_addrnotavail(net: &Network, ip: IpAddress) {
52*b315a0a8SYosh let bind_addr = IpSocketAddress::new(ip, 0);
53*b315a0a8SYosh
54*b315a0a8SYosh let sock = UdpSocket::new(ip.family()).unwrap();
55*b315a0a8SYosh
56*b315a0a8SYosh assert!(matches!(
57*b315a0a8SYosh sock.blocking_bind(net, bind_addr),
58*b315a0a8SYosh Err(ErrorCode::AddressNotBindable)
59*b315a0a8SYosh ));
60*b315a0a8SYosh }
61*b315a0a8SYosh
62*b315a0a8SYosh /// Bind should validate the address family.
test_udp_bind_wrong_family(net: &Network, family: IpAddressFamily)63*b315a0a8SYosh fn test_udp_bind_wrong_family(net: &Network, family: IpAddressFamily) {
64*b315a0a8SYosh let wrong_ip = match family {
65*b315a0a8SYosh IpAddressFamily::Ipv4 => IpAddress::IPV6_LOOPBACK,
66*b315a0a8SYosh IpAddressFamily::Ipv6 => IpAddress::IPV4_LOOPBACK,
67*b315a0a8SYosh };
68*b315a0a8SYosh
69*b315a0a8SYosh let sock = UdpSocket::new(family).unwrap();
70*b315a0a8SYosh let result = sock.blocking_bind(net, IpSocketAddress::new(wrong_ip, 0));
71*b315a0a8SYosh
72*b315a0a8SYosh assert!(matches!(result, Err(ErrorCode::InvalidArgument)));
73*b315a0a8SYosh }
74*b315a0a8SYosh
test_udp_bind_dual_stack(net: &Network)75*b315a0a8SYosh fn test_udp_bind_dual_stack(net: &Network) {
76*b315a0a8SYosh let sock = UdpSocket::new(IpAddressFamily::Ipv6).unwrap();
77*b315a0a8SYosh let addr = IpSocketAddress::new(IpAddress::IPV4_MAPPED_LOOPBACK, 0);
78*b315a0a8SYosh
79*b315a0a8SYosh // Binding an IPv4-mapped-IPv6 address on a ipv6-only socket should fail:
80*b315a0a8SYosh assert!(matches!(
81*b315a0a8SYosh sock.blocking_bind(net, addr),
82*b315a0a8SYosh Err(ErrorCode::InvalidArgument)
83*b315a0a8SYosh ));
84*b315a0a8SYosh }
85*b315a0a8SYosh
main()86*b315a0a8SYosh fn main() {
87*b315a0a8SYosh const RESERVED_IPV4_ADDRESS: IpAddress = IpAddress::Ipv4((192, 0, 2, 0)); // Reserved for documentation and examples.
88*b315a0a8SYosh const RESERVED_IPV6_ADDRESS: IpAddress = IpAddress::Ipv6((0x2001, 0x0db8, 0, 0, 0, 0, 0, 0)); // Reserved for documentation and examples.
89*b315a0a8SYosh
90*b315a0a8SYosh let net = Network::default();
91*b315a0a8SYosh
92*b315a0a8SYosh test_udp_bind_ephemeral_port(&net, IpAddress::IPV4_LOOPBACK);
93*b315a0a8SYosh test_udp_bind_ephemeral_port(&net, IpAddress::IPV4_UNSPECIFIED);
94*b315a0a8SYosh
95*b315a0a8SYosh test_udp_bind_specific_port(&net, IpAddress::IPV4_LOOPBACK);
96*b315a0a8SYosh test_udp_bind_specific_port(&net, IpAddress::IPV4_UNSPECIFIED);
97*b315a0a8SYosh
98*b315a0a8SYosh test_udp_bind_addrinuse(&net, IpAddress::IPV4_LOOPBACK);
99*b315a0a8SYosh test_udp_bind_addrinuse(&net, IpAddress::IPV4_UNSPECIFIED);
100*b315a0a8SYosh
101*b315a0a8SYosh test_udp_bind_addrnotavail(&net, RESERVED_IPV4_ADDRESS);
102*b315a0a8SYosh
103*b315a0a8SYosh test_udp_bind_wrong_family(&net, IpAddressFamily::Ipv4);
104*b315a0a8SYosh test_udp_bind_wrong_family(&net, IpAddressFamily::Ipv6);
105*b315a0a8SYosh
106*b315a0a8SYosh if supports_ipv6() {
107*b315a0a8SYosh test_udp_bind_ephemeral_port(&net, IpAddress::IPV6_LOOPBACK);
108*b315a0a8SYosh test_udp_bind_ephemeral_port(&net, IpAddress::IPV6_UNSPECIFIED);
109*b315a0a8SYosh
110*b315a0a8SYosh test_udp_bind_specific_port(&net, IpAddress::IPV6_LOOPBACK);
111*b315a0a8SYosh test_udp_bind_specific_port(&net, IpAddress::IPV6_UNSPECIFIED);
112*b315a0a8SYosh
113*b315a0a8SYosh test_udp_bind_addrinuse(&net, IpAddress::IPV6_LOOPBACK);
114*b315a0a8SYosh test_udp_bind_addrinuse(&net, IpAddress::IPV6_UNSPECIFIED);
115*b315a0a8SYosh
116*b315a0a8SYosh test_udp_bind_addrnotavail(&net, RESERVED_IPV6_ADDRESS);
117*b315a0a8SYosh
118*b315a0a8SYosh test_udp_bind_dual_stack(&net);
119*b315a0a8SYosh }
120*b315a0a8SYosh }
121