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