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. 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. 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. 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 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. 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. 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. 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 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 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