1f4be3606SAlex Crichton use crate::wasi::clocks::monotonic_clock;
2f4be3606SAlex Crichton use crate::wasi::io::poll::{self, Pollable};
3f4be3606SAlex Crichton use crate::wasi::io::streams::{InputStream, OutputStream, StreamError};
4e6a9fa19SDave Bakker use crate::wasi::random;
5f4be3606SAlex Crichton use crate::wasi::sockets::instance_network;
6c91566f6SDave Bakker use crate::wasi::sockets::ip_name_lookup;
7f4be3606SAlex Crichton use crate::wasi::sockets::network::{
8f4be3606SAlex Crichton     ErrorCode, IpAddress, IpAddressFamily, IpSocketAddress, Ipv4SocketAddress, Ipv6SocketAddress,
9f4be3606SAlex Crichton     Network,
10f4be3606SAlex Crichton };
11f4be3606SAlex Crichton use crate::wasi::sockets::tcp::TcpSocket;
12a6a9bdf8SDave Bakker use crate::wasi::sockets::udp::{
13a6a9bdf8SDave Bakker     IncomingDatagram, IncomingDatagramStream, OutgoingDatagram, OutgoingDatagramStream, UdpSocket,
14a6a9bdf8SDave Bakker };
15f4be3606SAlex Crichton use crate::wasi::sockets::{tcp_create_socket, udp_create_socket};
16f4be3606SAlex Crichton use std::ops::Range;
17f4be3606SAlex Crichton 
18f4be3606SAlex Crichton const TIMEOUT_NS: u64 = 1_000_000_000;
19f4be3606SAlex Crichton 
supports_ipv6() -> bool20*62d9b187SAlex Crichton pub fn supports_ipv6() -> bool {
21*62d9b187SAlex Crichton     std::env::var("DISABLE_IPV6").is_err()
22*62d9b187SAlex Crichton }
23*62d9b187SAlex Crichton 
24f4be3606SAlex Crichton impl Pollable {
block_until(&self, timeout: &Pollable) -> Result<(), ErrorCode>25ffdac62dSDave Bakker     pub fn block_until(&self, timeout: &Pollable) -> Result<(), ErrorCode> {
26ddffc7e9SPat Hickey         let ready = poll::poll(&[self, timeout]);
27f4be3606SAlex Crichton         assert!(ready.len() > 0);
28f4be3606SAlex Crichton         match ready[0] {
29f4be3606SAlex Crichton             0 => Ok(()),
30f4be3606SAlex Crichton             1 => Err(ErrorCode::Timeout),
31f4be3606SAlex Crichton             _ => unreachable!(),
32f4be3606SAlex Crichton         }
33f4be3606SAlex Crichton     }
34f4be3606SAlex Crichton }
35f4be3606SAlex Crichton 
36696d19f7SDave Bakker impl InputStream {
blocking_read_to_end(&self) -> Result<Vec<u8>, crate::wasi::io::error::Error>37696d19f7SDave Bakker     pub fn blocking_read_to_end(&self) -> Result<Vec<u8>, crate::wasi::io::error::Error> {
38696d19f7SDave Bakker         let mut data = vec![];
39696d19f7SDave Bakker         loop {
40696d19f7SDave Bakker             match self.blocking_read(1024 * 1024) {
41696d19f7SDave Bakker                 Ok(chunk) => data.extend(chunk),
42696d19f7SDave Bakker                 Err(StreamError::Closed) => return Ok(data),
43696d19f7SDave Bakker                 Err(StreamError::LastOperationFailed(e)) => return Err(e),
44696d19f7SDave Bakker             }
45696d19f7SDave Bakker         }
46696d19f7SDave Bakker     }
47696d19f7SDave Bakker }
48696d19f7SDave Bakker 
49f4be3606SAlex Crichton impl OutputStream {
blocking_write_util(&self, mut bytes: &[u8]) -> Result<(), StreamError>50f4be3606SAlex Crichton     pub fn blocking_write_util(&self, mut bytes: &[u8]) -> Result<(), StreamError> {
51ffdac62dSDave Bakker         let timeout = monotonic_clock::subscribe_duration(TIMEOUT_NS);
52f4be3606SAlex Crichton         let pollable = self.subscribe();
53f4be3606SAlex Crichton 
54f4be3606SAlex Crichton         while !bytes.is_empty() {
55ffdac62dSDave Bakker             pollable.block_until(&timeout).expect("write timed out");
56f4be3606SAlex Crichton 
57f4be3606SAlex Crichton             let permit = self.check_write()?;
58f4be3606SAlex Crichton 
59f4be3606SAlex Crichton             let len = bytes.len().min(permit as usize);
60f4be3606SAlex Crichton             let (chunk, rest) = bytes.split_at(len);
61f4be3606SAlex Crichton 
62f4be3606SAlex Crichton             self.write(chunk)?;
63f4be3606SAlex Crichton 
64f4be3606SAlex Crichton             self.blocking_flush()?;
65f4be3606SAlex Crichton 
66f4be3606SAlex Crichton             bytes = rest;
67f4be3606SAlex Crichton         }
68f4be3606SAlex Crichton         Ok(())
69f4be3606SAlex Crichton     }
70f4be3606SAlex Crichton }
71f4be3606SAlex Crichton 
72f4be3606SAlex Crichton impl Network {
default() -> Network73f4be3606SAlex Crichton     pub fn default() -> Network {
74f4be3606SAlex Crichton         instance_network::instance_network()
75f4be3606SAlex Crichton     }
76c91566f6SDave Bakker 
blocking_resolve_addresses(&self, name: &str) -> Result<Vec<IpAddress>, ErrorCode>77c91566f6SDave Bakker     pub fn blocking_resolve_addresses(&self, name: &str) -> Result<Vec<IpAddress>, ErrorCode> {
78c91566f6SDave Bakker         let stream = ip_name_lookup::resolve_addresses(&self, name)?;
79c91566f6SDave Bakker 
80c91566f6SDave Bakker         let timeout = monotonic_clock::subscribe_duration(TIMEOUT_NS);
81c91566f6SDave Bakker         let pollable = stream.subscribe();
82c91566f6SDave Bakker 
83c91566f6SDave Bakker         let mut addresses = vec![];
84c91566f6SDave Bakker 
85c91566f6SDave Bakker         loop {
86c91566f6SDave Bakker             match stream.resolve_next_address() {
87c91566f6SDave Bakker                 Ok(Some(addr)) => {
88c91566f6SDave Bakker                     addresses.push(addr);
89c91566f6SDave Bakker                 }
90c91566f6SDave Bakker                 Ok(None) => match addresses[..] {
91c91566f6SDave Bakker                     [] => return Err(ErrorCode::NameUnresolvable),
92c91566f6SDave Bakker                     _ => return Ok(addresses),
93c91566f6SDave Bakker                 },
94c91566f6SDave Bakker                 Err(ErrorCode::WouldBlock) => {
95ffdac62dSDave Bakker                     pollable.block_until(&timeout)?;
96c91566f6SDave Bakker                 }
97c91566f6SDave Bakker                 Err(err) => return Err(err),
98c91566f6SDave Bakker             }
99c91566f6SDave Bakker         }
100c91566f6SDave Bakker     }
10182fbd0c0SRyan Levick 
10282fbd0c0SRyan Levick     /// Same as `Network::blocking_resolve_addresses` but ignores post validation errors
10382fbd0c0SRyan Levick     ///
10482fbd0c0SRyan Levick     /// The ignored error codes signal that the input passed validation
10582fbd0c0SRyan Levick     /// and a lookup was actually attempted, but failed. These are ignored to
10682fbd0c0SRyan Levick     /// make the CI tests less flaky.
permissive_blocking_resolve_addresses( &self, name: &str, ) -> Result<Vec<IpAddress>, ErrorCode>10782fbd0c0SRyan Levick     pub fn permissive_blocking_resolve_addresses(
10882fbd0c0SRyan Levick         &self,
10982fbd0c0SRyan Levick         name: &str,
11082fbd0c0SRyan Levick     ) -> Result<Vec<IpAddress>, ErrorCode> {
11182fbd0c0SRyan Levick         match self.blocking_resolve_addresses(name) {
11282fbd0c0SRyan Levick             Err(ErrorCode::NameUnresolvable | ErrorCode::TemporaryResolverFailure) => Ok(vec![]),
11382fbd0c0SRyan Levick             r => r,
11482fbd0c0SRyan Levick         }
11582fbd0c0SRyan Levick     }
116f4be3606SAlex Crichton }
117f4be3606SAlex Crichton 
118f4be3606SAlex Crichton impl TcpSocket {
new(address_family: IpAddressFamily) -> Result<TcpSocket, ErrorCode>119f4be3606SAlex Crichton     pub fn new(address_family: IpAddressFamily) -> Result<TcpSocket, ErrorCode> {
120f4be3606SAlex Crichton         tcp_create_socket::create_tcp_socket(address_family)
121f4be3606SAlex Crichton     }
122f4be3606SAlex Crichton 
blocking_bind( &self, network: &Network, local_address: IpSocketAddress, ) -> Result<(), ErrorCode>123f4be3606SAlex Crichton     pub fn blocking_bind(
124f4be3606SAlex Crichton         &self,
125f4be3606SAlex Crichton         network: &Network,
126f4be3606SAlex Crichton         local_address: IpSocketAddress,
127f4be3606SAlex Crichton     ) -> Result<(), ErrorCode> {
128ffdac62dSDave Bakker         let timeout = monotonic_clock::subscribe_duration(TIMEOUT_NS);
129f4be3606SAlex Crichton         let sub = self.subscribe();
130f4be3606SAlex Crichton 
131f4be3606SAlex Crichton         self.start_bind(&network, local_address)?;
132f4be3606SAlex Crichton 
133f4be3606SAlex Crichton         loop {
134f4be3606SAlex Crichton             match self.finish_bind() {
135ffdac62dSDave Bakker                 Err(ErrorCode::WouldBlock) => sub.block_until(&timeout)?,
136f4be3606SAlex Crichton                 result => return result,
137f4be3606SAlex Crichton             }
138f4be3606SAlex Crichton         }
139f4be3606SAlex Crichton     }
140f4be3606SAlex Crichton 
blocking_listen(&self) -> Result<(), ErrorCode>141f4be3606SAlex Crichton     pub fn blocking_listen(&self) -> Result<(), ErrorCode> {
142ffdac62dSDave Bakker         let timeout = monotonic_clock::subscribe_duration(TIMEOUT_NS);
143f4be3606SAlex Crichton         let sub = self.subscribe();
144f4be3606SAlex Crichton 
145f4be3606SAlex Crichton         self.start_listen()?;
146f4be3606SAlex Crichton 
147f4be3606SAlex Crichton         loop {
148f4be3606SAlex Crichton             match self.finish_listen() {
149ffdac62dSDave Bakker                 Err(ErrorCode::WouldBlock) => sub.block_until(&timeout)?,
150f4be3606SAlex Crichton                 result => return result,
151f4be3606SAlex Crichton             }
152f4be3606SAlex Crichton         }
153f4be3606SAlex Crichton     }
154f4be3606SAlex Crichton 
blocking_connect( &self, network: &Network, remote_address: IpSocketAddress, ) -> Result<(InputStream, OutputStream), ErrorCode>155f4be3606SAlex Crichton     pub fn blocking_connect(
156f4be3606SAlex Crichton         &self,
157f4be3606SAlex Crichton         network: &Network,
158f4be3606SAlex Crichton         remote_address: IpSocketAddress,
159f4be3606SAlex Crichton     ) -> Result<(InputStream, OutputStream), ErrorCode> {
160ffdac62dSDave Bakker         let timeout = monotonic_clock::subscribe_duration(TIMEOUT_NS);
161f4be3606SAlex Crichton         let sub = self.subscribe();
162f4be3606SAlex Crichton 
163f4be3606SAlex Crichton         self.start_connect(&network, remote_address)?;
164f4be3606SAlex Crichton 
165f4be3606SAlex Crichton         loop {
166f4be3606SAlex Crichton             match self.finish_connect() {
167ffdac62dSDave Bakker                 Err(ErrorCode::WouldBlock) => sub.block_until(&timeout)?,
168f4be3606SAlex Crichton                 result => return result,
169f4be3606SAlex Crichton             }
170f4be3606SAlex Crichton         }
171f4be3606SAlex Crichton     }
172f4be3606SAlex Crichton 
blocking_accept(&self) -> Result<(TcpSocket, InputStream, OutputStream), ErrorCode>173f4be3606SAlex Crichton     pub fn blocking_accept(&self) -> Result<(TcpSocket, InputStream, OutputStream), ErrorCode> {
174ffdac62dSDave Bakker         let timeout = monotonic_clock::subscribe_duration(TIMEOUT_NS);
175f4be3606SAlex Crichton         let sub = self.subscribe();
176f4be3606SAlex Crichton 
177f4be3606SAlex Crichton         loop {
178f4be3606SAlex Crichton             match self.accept() {
179ffdac62dSDave Bakker                 Err(ErrorCode::WouldBlock) => sub.block_until(&timeout)?,
180f4be3606SAlex Crichton                 result => return result,
181f4be3606SAlex Crichton             }
182f4be3606SAlex Crichton         }
183f4be3606SAlex Crichton     }
184f4be3606SAlex Crichton }
185f4be3606SAlex Crichton 
186f4be3606SAlex Crichton impl UdpSocket {
new(address_family: IpAddressFamily) -> Result<UdpSocket, ErrorCode>187f4be3606SAlex Crichton     pub fn new(address_family: IpAddressFamily) -> Result<UdpSocket, ErrorCode> {
188f4be3606SAlex Crichton         udp_create_socket::create_udp_socket(address_family)
189f4be3606SAlex Crichton     }
190f4be3606SAlex Crichton 
blocking_bind( &self, network: &Network, local_address: IpSocketAddress, ) -> Result<(), ErrorCode>191f4be3606SAlex Crichton     pub fn blocking_bind(
192f4be3606SAlex Crichton         &self,
193f4be3606SAlex Crichton         network: &Network,
194f4be3606SAlex Crichton         local_address: IpSocketAddress,
195f4be3606SAlex Crichton     ) -> Result<(), ErrorCode> {
196ffdac62dSDave Bakker         let timeout = monotonic_clock::subscribe_duration(TIMEOUT_NS);
197f4be3606SAlex Crichton         let sub = self.subscribe();
198f4be3606SAlex Crichton 
199f4be3606SAlex Crichton         self.start_bind(&network, local_address)?;
200f4be3606SAlex Crichton 
201f4be3606SAlex Crichton         loop {
202f4be3606SAlex Crichton             match self.finish_bind() {
203ffdac62dSDave Bakker                 Err(ErrorCode::WouldBlock) => sub.block_until(&timeout)?,
204f4be3606SAlex Crichton                 result => return result,
205f4be3606SAlex Crichton             }
206f4be3606SAlex Crichton         }
207f4be3606SAlex Crichton     }
208973a34b5SDave Bakker 
blocking_bind_unspecified(&self, network: &Network) -> Result<(), ErrorCode>209973a34b5SDave Bakker     pub fn blocking_bind_unspecified(&self, network: &Network) -> Result<(), ErrorCode> {
210973a34b5SDave Bakker         let ip = IpAddress::new_unspecified(self.address_family());
211973a34b5SDave Bakker         let port = 0;
212973a34b5SDave Bakker 
213973a34b5SDave Bakker         self.blocking_bind(network, IpSocketAddress::new(ip, port))
214973a34b5SDave Bakker     }
215a6a9bdf8SDave Bakker }
216f4be3606SAlex Crichton 
217a6a9bdf8SDave Bakker impl OutgoingDatagramStream {
blocking_check_send(&self, timeout: &Pollable) -> Result<u64, ErrorCode>218a6a9bdf8SDave Bakker     fn blocking_check_send(&self, timeout: &Pollable) -> Result<u64, ErrorCode> {
219f4be3606SAlex Crichton         let sub = self.subscribe();
220f4be3606SAlex Crichton 
221f4be3606SAlex Crichton         loop {
222a6a9bdf8SDave Bakker             match self.check_send() {
223ffdac62dSDave Bakker                 Ok(0) => sub.block_until(timeout)?,
224f4be3606SAlex Crichton                 result => return result,
225f4be3606SAlex Crichton             }
226f4be3606SAlex Crichton         }
227f4be3606SAlex Crichton     }
228f4be3606SAlex Crichton 
blocking_send(&self, mut datagrams: &[OutgoingDatagram]) -> Result<(), ErrorCode>229a6a9bdf8SDave Bakker     pub fn blocking_send(&self, mut datagrams: &[OutgoingDatagram]) -> Result<(), ErrorCode> {
230a841785dSPat Hickey         let timeout = monotonic_clock::subscribe_duration(TIMEOUT_NS);
231f4be3606SAlex Crichton 
232f4be3606SAlex Crichton         while !datagrams.is_empty() {
233a6a9bdf8SDave Bakker             let permit = self.blocking_check_send(&timeout)?;
234a6a9bdf8SDave Bakker             let chunk_len = datagrams.len().min(permit as usize);
235a6a9bdf8SDave Bakker             match self.send(&datagrams[..chunk_len]) {
236a6a9bdf8SDave Bakker                 Ok(0) => {}
237f4be3606SAlex Crichton                 Ok(packets_sent) => {
238a6a9bdf8SDave Bakker                     let packets_sent = packets_sent as usize;
239a6a9bdf8SDave Bakker                     datagrams = &datagrams[packets_sent..];
240f4be3606SAlex Crichton                 }
241f4be3606SAlex Crichton                 Err(err) => return Err(err),
242f4be3606SAlex Crichton             }
243f4be3606SAlex Crichton         }
244f4be3606SAlex Crichton 
245f4be3606SAlex Crichton         Ok(())
246f4be3606SAlex Crichton     }
247a6a9bdf8SDave Bakker }
248f4be3606SAlex Crichton 
249a6a9bdf8SDave Bakker impl IncomingDatagramStream {
blocking_receive(&self, count: Range<u64>) -> Result<Vec<IncomingDatagram>, ErrorCode>250a6a9bdf8SDave Bakker     pub fn blocking_receive(&self, count: Range<u64>) -> Result<Vec<IncomingDatagram>, ErrorCode> {
251a841785dSPat Hickey         let timeout = monotonic_clock::subscribe_duration(TIMEOUT_NS);
252f4be3606SAlex Crichton         let pollable = self.subscribe();
253f4be3606SAlex Crichton         let mut datagrams = vec![];
254f4be3606SAlex Crichton 
255f4be3606SAlex Crichton         loop {
256f4be3606SAlex Crichton             match self.receive(count.end - datagrams.len() as u64) {
257f4be3606SAlex Crichton                 Ok(mut chunk) => {
258f4be3606SAlex Crichton                     datagrams.append(&mut chunk);
259f4be3606SAlex Crichton 
260f4be3606SAlex Crichton                     if datagrams.len() >= count.start as usize {
261f4be3606SAlex Crichton                         return Ok(datagrams);
262f4be3606SAlex Crichton                     } else {
263ffdac62dSDave Bakker                         pollable.block_until(&timeout)?;
264f4be3606SAlex Crichton                     }
265f4be3606SAlex Crichton                 }
266f4be3606SAlex Crichton                 Err(err) => return Err(err),
267f4be3606SAlex Crichton             }
268f4be3606SAlex Crichton         }
269f4be3606SAlex Crichton     }
270f4be3606SAlex Crichton }
271f4be3606SAlex Crichton 
272f4be3606SAlex Crichton impl IpAddress {
273f4be3606SAlex Crichton     pub const IPV4_BROADCAST: IpAddress = IpAddress::Ipv4((255, 255, 255, 255));
274f4be3606SAlex Crichton 
275f4be3606SAlex Crichton     pub const IPV4_LOOPBACK: IpAddress = IpAddress::Ipv4((127, 0, 0, 1));
276f4be3606SAlex Crichton     pub const IPV6_LOOPBACK: IpAddress = IpAddress::Ipv6((0, 0, 0, 0, 0, 0, 0, 1));
277f4be3606SAlex Crichton 
278f4be3606SAlex Crichton     pub const IPV4_UNSPECIFIED: IpAddress = IpAddress::Ipv4((0, 0, 0, 0));
279f4be3606SAlex Crichton     pub const IPV6_UNSPECIFIED: IpAddress = IpAddress::Ipv6((0, 0, 0, 0, 0, 0, 0, 0));
280f4be3606SAlex Crichton 
281f4be3606SAlex Crichton     pub const IPV4_MAPPED_LOOPBACK: IpAddress =
282f4be3606SAlex Crichton         IpAddress::Ipv6((0, 0, 0, 0, 0, 0xFFFF, 0x7F00, 0x0001));
283f4be3606SAlex Crichton 
new_loopback(family: IpAddressFamily) -> IpAddress284f4be3606SAlex Crichton     pub const fn new_loopback(family: IpAddressFamily) -> IpAddress {
285f4be3606SAlex Crichton         match family {
286f4be3606SAlex Crichton             IpAddressFamily::Ipv4 => Self::IPV4_LOOPBACK,
287f4be3606SAlex Crichton             IpAddressFamily::Ipv6 => Self::IPV6_LOOPBACK,
288f4be3606SAlex Crichton         }
289f4be3606SAlex Crichton     }
290f4be3606SAlex Crichton 
new_unspecified(family: IpAddressFamily) -> IpAddress291f4be3606SAlex Crichton     pub const fn new_unspecified(family: IpAddressFamily) -> IpAddress {
292f4be3606SAlex Crichton         match family {
293f4be3606SAlex Crichton             IpAddressFamily::Ipv4 => Self::IPV4_UNSPECIFIED,
294f4be3606SAlex Crichton             IpAddressFamily::Ipv6 => Self::IPV6_UNSPECIFIED,
295f4be3606SAlex Crichton         }
296f4be3606SAlex Crichton     }
297f4be3606SAlex Crichton 
family(&self) -> IpAddressFamily298f4be3606SAlex Crichton     pub const fn family(&self) -> IpAddressFamily {
299f4be3606SAlex Crichton         match self {
300f4be3606SAlex Crichton             IpAddress::Ipv4(_) => IpAddressFamily::Ipv4,
301f4be3606SAlex Crichton             IpAddress::Ipv6(_) => IpAddressFamily::Ipv6,
302f4be3606SAlex Crichton         }
303f4be3606SAlex Crichton     }
304f4be3606SAlex Crichton }
305f4be3606SAlex Crichton 
306f4be3606SAlex Crichton impl PartialEq for IpAddress {
eq(&self, other: &Self) -> bool307f4be3606SAlex Crichton     fn eq(&self, other: &Self) -> bool {
308f4be3606SAlex Crichton         match (self, other) {
309f4be3606SAlex Crichton             (Self::Ipv4(left), Self::Ipv4(right)) => left == right,
310f4be3606SAlex Crichton             (Self::Ipv6(left), Self::Ipv6(right)) => left == right,
311f4be3606SAlex Crichton             _ => false,
312f4be3606SAlex Crichton         }
313f4be3606SAlex Crichton     }
314f4be3606SAlex Crichton }
315f4be3606SAlex Crichton 
316f4be3606SAlex Crichton impl IpSocketAddress {
new(ip: IpAddress, port: u16) -> IpSocketAddress317f4be3606SAlex Crichton     pub const fn new(ip: IpAddress, port: u16) -> IpSocketAddress {
318f4be3606SAlex Crichton         match ip {
319f4be3606SAlex Crichton             IpAddress::Ipv4(addr) => IpSocketAddress::Ipv4(Ipv4SocketAddress {
3208cc276b0SAlex Crichton                 port,
321f4be3606SAlex Crichton                 address: addr,
322f4be3606SAlex Crichton             }),
323f4be3606SAlex Crichton             IpAddress::Ipv6(addr) => IpSocketAddress::Ipv6(Ipv6SocketAddress {
3248cc276b0SAlex Crichton                 port,
325f4be3606SAlex Crichton                 address: addr,
326f4be3606SAlex Crichton                 flow_info: 0,
327f4be3606SAlex Crichton                 scope_id: 0,
328f4be3606SAlex Crichton             }),
329f4be3606SAlex Crichton         }
330f4be3606SAlex Crichton     }
331f4be3606SAlex Crichton 
ip(&self) -> IpAddress332f4be3606SAlex Crichton     pub const fn ip(&self) -> IpAddress {
333f4be3606SAlex Crichton         match self {
334f4be3606SAlex Crichton             IpSocketAddress::Ipv4(addr) => IpAddress::Ipv4(addr.address),
335f4be3606SAlex Crichton             IpSocketAddress::Ipv6(addr) => IpAddress::Ipv6(addr.address),
336f4be3606SAlex Crichton         }
337f4be3606SAlex Crichton     }
338f4be3606SAlex Crichton 
port(&self) -> u16339f4be3606SAlex Crichton     pub const fn port(&self) -> u16 {
340f4be3606SAlex Crichton         match self {
341f4be3606SAlex Crichton             IpSocketAddress::Ipv4(addr) => addr.port,
342f4be3606SAlex Crichton             IpSocketAddress::Ipv6(addr) => addr.port,
343f4be3606SAlex Crichton         }
344f4be3606SAlex Crichton     }
345f4be3606SAlex Crichton 
family(&self) -> IpAddressFamily346f4be3606SAlex Crichton     pub const fn family(&self) -> IpAddressFamily {
347f4be3606SAlex Crichton         match self {
348f4be3606SAlex Crichton             IpSocketAddress::Ipv4(_) => IpAddressFamily::Ipv4,
349f4be3606SAlex Crichton             IpSocketAddress::Ipv6(_) => IpAddressFamily::Ipv6,
350f4be3606SAlex Crichton         }
351f4be3606SAlex Crichton     }
352f4be3606SAlex Crichton }
353f4be3606SAlex Crichton 
354f4be3606SAlex Crichton impl PartialEq for Ipv4SocketAddress {
eq(&self, other: &Self) -> bool355f4be3606SAlex Crichton     fn eq(&self, other: &Self) -> bool {
356f4be3606SAlex Crichton         self.port == other.port && self.address == other.address
357f4be3606SAlex Crichton     }
358f4be3606SAlex Crichton }
359f4be3606SAlex Crichton 
360f4be3606SAlex Crichton impl PartialEq for Ipv6SocketAddress {
eq(&self, other: &Self) -> bool361f4be3606SAlex Crichton     fn eq(&self, other: &Self) -> bool {
362f4be3606SAlex Crichton         self.port == other.port
363f4be3606SAlex Crichton             && self.flow_info == other.flow_info
364f4be3606SAlex Crichton             && self.address == other.address
365f4be3606SAlex Crichton             && self.scope_id == other.scope_id
366f4be3606SAlex Crichton     }
367f4be3606SAlex Crichton }
368f4be3606SAlex Crichton 
369f4be3606SAlex Crichton impl PartialEq for IpSocketAddress {
eq(&self, other: &Self) -> bool370f4be3606SAlex Crichton     fn eq(&self, other: &Self) -> bool {
371f4be3606SAlex Crichton         match (self, other) {
372f4be3606SAlex Crichton             (Self::Ipv4(l0), Self::Ipv4(r0)) => l0 == r0,
373f4be3606SAlex Crichton             (Self::Ipv6(l0), Self::Ipv6(r0)) => l0 == r0,
374f4be3606SAlex Crichton             _ => false,
375f4be3606SAlex Crichton         }
376f4be3606SAlex Crichton     }
377f4be3606SAlex Crichton }
378e6a9fa19SDave Bakker 
generate_random_u16(range: Range<u16>) -> u16379e6a9fa19SDave Bakker fn generate_random_u16(range: Range<u16>) -> u16 {
380e6a9fa19SDave Bakker     let start = range.start as u64;
381e6a9fa19SDave Bakker     let end = range.end as u64;
382e6a9fa19SDave Bakker     let port = start + (random::random::get_random_u64() % (end - start));
383e6a9fa19SDave Bakker     port as u16
384e6a9fa19SDave Bakker }
385e6a9fa19SDave Bakker 
386e6a9fa19SDave Bakker /// Execute the inner function with a randomly generated port.
387e6a9fa19SDave Bakker /// To prevent random failures, we make a few attempts before giving up.
attempt_random_port<F>( local_address: IpAddress, mut f: F, ) -> Result<IpSocketAddress, ErrorCode> where F: FnMut(IpSocketAddress) -> Result<(), ErrorCode>,388e6a9fa19SDave Bakker pub fn attempt_random_port<F>(
389e6a9fa19SDave Bakker     local_address: IpAddress,
390e6a9fa19SDave Bakker     mut f: F,
391e6a9fa19SDave Bakker ) -> Result<IpSocketAddress, ErrorCode>
392e6a9fa19SDave Bakker where
393e6a9fa19SDave Bakker     F: FnMut(IpSocketAddress) -> Result<(), ErrorCode>,
394e6a9fa19SDave Bakker {
395e6a9fa19SDave Bakker     const MAX_ATTEMPTS: u32 = 10;
396e6a9fa19SDave Bakker     let mut i = 0;
397e6a9fa19SDave Bakker     loop {
398e6a9fa19SDave Bakker         i += 1;
399e6a9fa19SDave Bakker 
400e6a9fa19SDave Bakker         let port: u16 = generate_random_u16(1024..u16::MAX);
401e6a9fa19SDave Bakker         let sock_addr = IpSocketAddress::new(local_address, port);
402e6a9fa19SDave Bakker 
403e6a9fa19SDave Bakker         match f(sock_addr) {
404e6a9fa19SDave Bakker             Ok(_) => return Ok(sock_addr),
405e6a9fa19SDave Bakker             Err(e) if i >= MAX_ATTEMPTS => return Err(e),
406e6a9fa19SDave Bakker             // Try again if the port is already taken. This can sometimes show up as `AccessDenied` on Windows.
407e6a9fa19SDave Bakker             Err(ErrorCode::AddressInUse | ErrorCode::AccessDenied) => {}
408e6a9fa19SDave Bakker             Err(e) => return Err(e),
409e6a9fa19SDave Bakker         }
410e6a9fa19SDave Bakker     }
411e6a9fa19SDave Bakker }
412