1 use test_programs::sockets::{attempt_random_port, supports_ipv6};
2 use test_programs::wasi::sockets::network::{
3     ErrorCode, IpAddress, IpAddressFamily, IpSocketAddress, Network,
4 };
5 use test_programs::wasi::sockets::tcp::TcpSocket;
6 
7 /// Bind a socket and let the system determine a port.
test_tcp_bind_ephemeral_port(net: &Network, ip: IpAddress)8 fn test_tcp_bind_ephemeral_port(net: &Network, ip: IpAddress) {
9     let bind_addr = IpSocketAddress::new(ip, 0);
10 
11     let sock = TcpSocket::new(ip.family()).unwrap();
12     sock.blocking_bind(net, bind_addr).unwrap();
13 
14     let bound_addr = sock.local_address().unwrap();
15 
16     assert_eq!(bind_addr.ip(), bound_addr.ip());
17     assert_ne!(bind_addr.port(), bound_addr.port());
18 }
19 
20 /// Bind a socket on a specified port.
test_tcp_bind_specific_port(net: &Network, ip: IpAddress)21 fn test_tcp_bind_specific_port(net: &Network, ip: IpAddress) {
22     let sock = TcpSocket::new(ip.family()).unwrap();
23 
24     let bind_addr =
25         attempt_random_port(ip, |bind_addr| sock.blocking_bind(net, bind_addr)).unwrap();
26 
27     let bound_addr = sock.local_address().unwrap();
28 
29     assert_eq!(bind_addr.ip(), bound_addr.ip());
30     assert_eq!(bind_addr.port(), bound_addr.port());
31 }
32 
33 /// Two sockets may not be actively bound to the same address at the same time.
test_tcp_bind_addrinuse(net: &Network, ip: IpAddress)34 fn test_tcp_bind_addrinuse(net: &Network, ip: IpAddress) {
35     let bind_addr = IpSocketAddress::new(ip, 0);
36 
37     let sock1 = TcpSocket::new(ip.family()).unwrap();
38     sock1.blocking_bind(net, bind_addr).unwrap();
39     sock1.blocking_listen().unwrap();
40 
41     let bound_addr = sock1.local_address().unwrap();
42 
43     let sock2 = TcpSocket::new(ip.family()).unwrap();
44     assert_eq!(
45         sock2.blocking_bind(net, bound_addr),
46         Err(ErrorCode::AddressInUse)
47     );
48 }
49 
50 // The WASI runtime should set SO_REUSEADDR for us
test_tcp_bind_reuseaddr(net: &Network, ip: IpAddress)51 fn test_tcp_bind_reuseaddr(net: &Network, ip: IpAddress) {
52     let client = TcpSocket::new(ip.family()).unwrap();
53 
54     let bind_addr = {
55         let listener1 = TcpSocket::new(ip.family()).unwrap();
56 
57         let bind_addr =
58             attempt_random_port(ip, |bind_addr| listener1.blocking_bind(net, bind_addr)).unwrap();
59 
60         listener1.blocking_listen().unwrap();
61 
62         let connect_addr =
63             IpSocketAddress::new(IpAddress::new_loopback(ip.family()), bind_addr.port());
64         client.blocking_connect(net, connect_addr).unwrap();
65 
66         let (accepted_connection, accepted_input, accepted_output) =
67             listener1.blocking_accept().unwrap();
68         accepted_output.blocking_write_zeroes_and_flush(10).unwrap();
69         drop(accepted_input);
70         drop(accepted_output);
71         drop(accepted_connection);
72         drop(listener1);
73 
74         bind_addr
75     };
76 
77     {
78         let listener2 = TcpSocket::new(ip.family()).unwrap();
79 
80         // If SO_REUSEADDR was configured correctly, the following lines shouldn't be
81         // affected by the TIME_WAIT state of the just closed `listener1` socket:
82         listener2.blocking_bind(net, bind_addr).unwrap();
83         listener2.blocking_listen().unwrap();
84     }
85 
86     drop(client);
87 }
88 
89 // Try binding to an address that is not configured on the system.
test_tcp_bind_addrnotavail(net: &Network, ip: IpAddress)90 fn test_tcp_bind_addrnotavail(net: &Network, ip: IpAddress) {
91     let bind_addr = IpSocketAddress::new(ip, 0);
92 
93     let sock = TcpSocket::new(ip.family()).unwrap();
94 
95     assert_eq!(
96         sock.blocking_bind(net, bind_addr),
97         Err(ErrorCode::AddressNotBindable)
98     );
99 }
100 
101 /// Bind should validate the address family.
test_tcp_bind_wrong_family(net: &Network, family: IpAddressFamily)102 fn test_tcp_bind_wrong_family(net: &Network, family: IpAddressFamily) {
103     let wrong_ip = match family {
104         IpAddressFamily::Ipv4 => IpAddress::IPV6_LOOPBACK,
105         IpAddressFamily::Ipv6 => IpAddress::IPV4_LOOPBACK,
106     };
107 
108     let sock = TcpSocket::new(family).unwrap();
109     let result = sock.blocking_bind(net, IpSocketAddress::new(wrong_ip, 0));
110 
111     assert!(matches!(result, Err(ErrorCode::InvalidArgument)));
112 }
113 
114 /// Bind only works on unicast addresses.
test_tcp_bind_non_unicast(net: &Network)115 fn test_tcp_bind_non_unicast(net: &Network) {
116     let ipv4_broadcast = IpSocketAddress::new(IpAddress::IPV4_BROADCAST, 0);
117     let ipv4_multicast = IpSocketAddress::new(IpAddress::Ipv4((224, 254, 0, 0)), 0);
118     let ipv6_multicast = IpSocketAddress::new(IpAddress::Ipv6((0xff00, 0, 0, 0, 0, 0, 0, 0)), 0);
119 
120     let sock_v4 = TcpSocket::new(IpAddressFamily::Ipv4).unwrap();
121     let sock_v6 = TcpSocket::new(IpAddressFamily::Ipv6).unwrap();
122 
123     assert!(matches!(
124         sock_v4.blocking_bind(net, ipv4_broadcast),
125         Err(ErrorCode::InvalidArgument)
126     ));
127     assert!(matches!(
128         sock_v4.blocking_bind(net, ipv4_multicast),
129         Err(ErrorCode::InvalidArgument)
130     ));
131     assert!(matches!(
132         sock_v6.blocking_bind(net, ipv6_multicast),
133         Err(ErrorCode::InvalidArgument)
134     ));
135 }
136 
test_tcp_bind_dual_stack(net: &Network)137 fn test_tcp_bind_dual_stack(net: &Network) {
138     let sock = TcpSocket::new(IpAddressFamily::Ipv6).unwrap();
139     let addr = IpSocketAddress::new(IpAddress::IPV4_MAPPED_LOOPBACK, 0);
140 
141     // Binding an IPv4-mapped-IPv6 address on a ipv6-only socket should fail:
142     assert!(matches!(
143         sock.blocking_bind(net, addr),
144         Err(ErrorCode::InvalidArgument)
145     ));
146 }
147 
main()148 fn main() {
149     const RESERVED_IPV4_ADDRESS: IpAddress = IpAddress::Ipv4((192, 0, 2, 0)); // Reserved for documentation and examples.
150     const RESERVED_IPV6_ADDRESS: IpAddress = IpAddress::Ipv6((0x2001, 0x0db8, 0, 0, 0, 0, 0, 0)); // Reserved for documentation and examples.
151 
152     let net = Network::default();
153 
154     test_tcp_bind_ephemeral_port(&net, IpAddress::IPV4_LOOPBACK);
155     test_tcp_bind_ephemeral_port(&net, IpAddress::IPV4_UNSPECIFIED);
156     test_tcp_bind_specific_port(&net, IpAddress::IPV4_LOOPBACK);
157     test_tcp_bind_specific_port(&net, IpAddress::IPV4_UNSPECIFIED);
158     test_tcp_bind_reuseaddr(&net, IpAddress::IPV4_LOOPBACK);
159     test_tcp_bind_addrinuse(&net, IpAddress::IPV4_LOOPBACK);
160     test_tcp_bind_addrinuse(&net, IpAddress::IPV4_UNSPECIFIED);
161     test_tcp_bind_addrnotavail(&net, RESERVED_IPV4_ADDRESS);
162     test_tcp_bind_wrong_family(&net, IpAddressFamily::Ipv4);
163 
164     if supports_ipv6() {
165         test_tcp_bind_ephemeral_port(&net, IpAddress::IPV6_LOOPBACK);
166         test_tcp_bind_ephemeral_port(&net, IpAddress::IPV6_UNSPECIFIED);
167         test_tcp_bind_specific_port(&net, IpAddress::IPV6_LOOPBACK);
168         test_tcp_bind_specific_port(&net, IpAddress::IPV6_UNSPECIFIED);
169         test_tcp_bind_reuseaddr(&net, IpAddress::IPV6_LOOPBACK);
170         test_tcp_bind_addrinuse(&net, IpAddress::IPV6_LOOPBACK);
171         test_tcp_bind_addrinuse(&net, IpAddress::IPV6_UNSPECIFIED);
172         test_tcp_bind_addrnotavail(&net, RESERVED_IPV6_ADDRESS);
173         test_tcp_bind_wrong_family(&net, IpAddressFamily::Ipv6);
174         test_tcp_bind_non_unicast(&net);
175         test_tcp_bind_dual_stack(&net);
176     }
177 }
178