1 use test_programs::wasi::sockets::network::{
2     ErrorCode, IpAddress, IpAddressFamily, IpSocketAddress, Network,
3 };
4 use test_programs::wasi::sockets::udp::UdpSocket;
5 
6 const SOME_PORT: u16 = 47; // If the tests pass, this will never actually be connected to.
7 
8 fn test_udp_connect_disconnect_reconnect(net: &Network, family: IpAddressFamily) {
9     let unspecified_addr = IpSocketAddress::new(IpAddress::new_unspecified(family), 0);
10     let remote1 = IpSocketAddress::new(IpAddress::new_loopback(family), 4321);
11     let remote2 = IpSocketAddress::new(IpAddress::new_loopback(family), 4320);
12 
13     let client = UdpSocket::new(family).unwrap();
14     client.blocking_bind(&net, unspecified_addr).unwrap();
15 
16     _ = client.stream(None).unwrap();
17     assert_eq!(client.remote_address(), Err(ErrorCode::InvalidState));
18 
19     _ = client.stream(None).unwrap();
20     assert_eq!(client.remote_address(), Err(ErrorCode::InvalidState));
21 
22     _ = client.stream(Some(remote1)).unwrap();
23     assert_eq!(client.remote_address(), Ok(remote1));
24 
25     _ = client.stream(Some(remote1)).unwrap();
26     assert_eq!(client.remote_address(), Ok(remote1));
27 
28     _ = client.stream(Some(remote2)).unwrap();
29     assert_eq!(client.remote_address(), Ok(remote2));
30 
31     _ = client.stream(None).unwrap();
32     assert_eq!(client.remote_address(), Err(ErrorCode::InvalidState));
33 
34     _ = client.stream(Some(remote1)).unwrap();
35     assert_eq!(client.remote_address(), Ok(remote1));
36 }
37 
38 /// `0.0.0.0` / `::` is not a valid remote address in WASI.
39 fn test_udp_connect_unspec(net: &Network, family: IpAddressFamily) {
40     let addr = IpSocketAddress::new(IpAddress::new_unspecified(family), SOME_PORT);
41     let sock = UdpSocket::new(family).unwrap();
42     sock.blocking_bind_unspecified(&net).unwrap();
43 
44     assert!(matches!(
45         sock.stream(Some(addr)),
46         Err(ErrorCode::InvalidArgument)
47     ));
48 }
49 
50 /// 0 is not a valid remote port.
51 fn test_udp_connect_port_0(net: &Network, family: IpAddressFamily) {
52     let addr = IpSocketAddress::new(IpAddress::new_loopback(family), 0);
53     let sock = UdpSocket::new(family).unwrap();
54     sock.blocking_bind_unspecified(&net).unwrap();
55 
56     assert!(matches!(
57         sock.stream(Some(addr)),
58         Err(ErrorCode::InvalidArgument)
59     ));
60 }
61 
62 /// Connect should validate the address family.
63 fn test_udp_connect_wrong_family(net: &Network, family: IpAddressFamily) {
64     let wrong_ip = match family {
65         IpAddressFamily::Ipv4 => IpAddress::IPV6_LOOPBACK,
66         IpAddressFamily::Ipv6 => IpAddress::IPV4_LOOPBACK,
67     };
68     let remote_addr = IpSocketAddress::new(wrong_ip, SOME_PORT);
69 
70     let sock = UdpSocket::new(family).unwrap();
71     sock.blocking_bind_unspecified(&net).unwrap();
72 
73     assert!(matches!(
74         sock.stream(Some(remote_addr)),
75         Err(ErrorCode::InvalidArgument)
76     ));
77 }
78 
79 fn test_udp_connect_dual_stack(net: &Network) {
80     // Set-up:
81     let v4_server = UdpSocket::new(IpAddressFamily::Ipv4).unwrap();
82     v4_server
83         .blocking_bind(&net, IpSocketAddress::new(IpAddress::IPV4_LOOPBACK, 0))
84         .unwrap();
85 
86     let v4_server_addr = v4_server.local_address().unwrap();
87     let v6_server_addr =
88         IpSocketAddress::new(IpAddress::IPV4_MAPPED_LOOPBACK, v4_server_addr.port());
89 
90     // Tests:
91     let v6_client = UdpSocket::new(IpAddressFamily::Ipv6).unwrap();
92 
93     v6_client.blocking_bind_unspecified(&net).unwrap();
94 
95     // Connecting to an IPv4 address on an IPv6 socket should fail:
96     assert!(matches!(
97         v6_client.stream(Some(v4_server_addr)),
98         Err(ErrorCode::InvalidArgument)
99     ));
100 
101     // Connecting to an IPv4-mapped-IPv6 address on an IPv6 socket should fail:
102     assert!(matches!(
103         v6_client.stream(Some(v6_server_addr)),
104         Err(ErrorCode::InvalidArgument)
105     ));
106 }
107 
108 fn main() {
109     let net = Network::default();
110 
111     test_udp_connect_disconnect_reconnect(&net, IpAddressFamily::Ipv4);
112     test_udp_connect_disconnect_reconnect(&net, IpAddressFamily::Ipv6);
113 
114     test_udp_connect_unspec(&net, IpAddressFamily::Ipv4);
115     test_udp_connect_unspec(&net, IpAddressFamily::Ipv6);
116 
117     test_udp_connect_port_0(&net, IpAddressFamily::Ipv4);
118     test_udp_connect_port_0(&net, IpAddressFamily::Ipv6);
119 
120     test_udp_connect_wrong_family(&net, IpAddressFamily::Ipv4);
121     test_udp_connect_wrong_family(&net, IpAddressFamily::Ipv6);
122 
123     test_udp_connect_dual_stack(&net);
124 }
125