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