17074afb6SRoman Volosatovs use core::ops::Range;
27074afb6SRoman Volosatovs 
37074afb6SRoman Volosatovs use crate::p3::wasi::random;
47074afb6SRoman Volosatovs use crate::p3::wasi::sockets::types::{
57074afb6SRoman Volosatovs     ErrorCode, IpAddress, IpAddressFamily, IpSocketAddress, Ipv4SocketAddress, Ipv6SocketAddress,
67074afb6SRoman Volosatovs     UdpSocket,
77074afb6SRoman Volosatovs };
87074afb6SRoman Volosatovs 
97074afb6SRoman Volosatovs impl IpAddress {
107074afb6SRoman Volosatovs     pub const IPV4_BROADCAST: IpAddress = IpAddress::Ipv4((255, 255, 255, 255));
117074afb6SRoman Volosatovs 
127074afb6SRoman Volosatovs     pub const IPV4_LOOPBACK: IpAddress = IpAddress::Ipv4((127, 0, 0, 1));
137074afb6SRoman Volosatovs     pub const IPV6_LOOPBACK: IpAddress = IpAddress::Ipv6((0, 0, 0, 0, 0, 0, 0, 1));
147074afb6SRoman Volosatovs 
157074afb6SRoman Volosatovs     pub const IPV4_UNSPECIFIED: IpAddress = IpAddress::Ipv4((0, 0, 0, 0));
167074afb6SRoman Volosatovs     pub const IPV6_UNSPECIFIED: IpAddress = IpAddress::Ipv6((0, 0, 0, 0, 0, 0, 0, 0));
177074afb6SRoman Volosatovs 
187074afb6SRoman Volosatovs     pub const IPV4_MAPPED_LOOPBACK: IpAddress =
197074afb6SRoman Volosatovs         IpAddress::Ipv6((0, 0, 0, 0, 0, 0xFFFF, 0x7F00, 0x0001));
207074afb6SRoman Volosatovs 
new_loopback(family: IpAddressFamily) -> IpAddress217074afb6SRoman Volosatovs     pub const fn new_loopback(family: IpAddressFamily) -> IpAddress {
227074afb6SRoman Volosatovs         match family {
237074afb6SRoman Volosatovs             IpAddressFamily::Ipv4 => Self::IPV4_LOOPBACK,
247074afb6SRoman Volosatovs             IpAddressFamily::Ipv6 => Self::IPV6_LOOPBACK,
257074afb6SRoman Volosatovs         }
267074afb6SRoman Volosatovs     }
277074afb6SRoman Volosatovs 
new_unspecified(family: IpAddressFamily) -> IpAddress287074afb6SRoman Volosatovs     pub const fn new_unspecified(family: IpAddressFamily) -> IpAddress {
297074afb6SRoman Volosatovs         match family {
307074afb6SRoman Volosatovs             IpAddressFamily::Ipv4 => Self::IPV4_UNSPECIFIED,
317074afb6SRoman Volosatovs             IpAddressFamily::Ipv6 => Self::IPV6_UNSPECIFIED,
327074afb6SRoman Volosatovs         }
337074afb6SRoman Volosatovs     }
347074afb6SRoman Volosatovs 
family(&self) -> IpAddressFamily357074afb6SRoman Volosatovs     pub const fn family(&self) -> IpAddressFamily {
367074afb6SRoman Volosatovs         match self {
377074afb6SRoman Volosatovs             IpAddress::Ipv4(_) => IpAddressFamily::Ipv4,
387074afb6SRoman Volosatovs             IpAddress::Ipv6(_) => IpAddressFamily::Ipv6,
397074afb6SRoman Volosatovs         }
407074afb6SRoman Volosatovs     }
417074afb6SRoman Volosatovs }
427074afb6SRoman Volosatovs 
437074afb6SRoman Volosatovs impl PartialEq for IpAddress {
eq(&self, other: &Self) -> bool447074afb6SRoman Volosatovs     fn eq(&self, other: &Self) -> bool {
457074afb6SRoman Volosatovs         match (self, other) {
467074afb6SRoman Volosatovs             (Self::Ipv4(left), Self::Ipv4(right)) => left == right,
477074afb6SRoman Volosatovs             (Self::Ipv6(left), Self::Ipv6(right)) => left == right,
487074afb6SRoman Volosatovs             _ => false,
497074afb6SRoman Volosatovs         }
507074afb6SRoman Volosatovs     }
517074afb6SRoman Volosatovs }
527074afb6SRoman Volosatovs 
537074afb6SRoman Volosatovs impl IpSocketAddress {
new(ip: IpAddress, port: u16) -> IpSocketAddress547074afb6SRoman Volosatovs     pub const fn new(ip: IpAddress, port: u16) -> IpSocketAddress {
557074afb6SRoman Volosatovs         match ip {
567074afb6SRoman Volosatovs             IpAddress::Ipv4(addr) => IpSocketAddress::Ipv4(Ipv4SocketAddress {
577074afb6SRoman Volosatovs                 port,
587074afb6SRoman Volosatovs                 address: addr,
597074afb6SRoman Volosatovs             }),
607074afb6SRoman Volosatovs             IpAddress::Ipv6(addr) => IpSocketAddress::Ipv6(Ipv6SocketAddress {
617074afb6SRoman Volosatovs                 port,
627074afb6SRoman Volosatovs                 address: addr,
637074afb6SRoman Volosatovs                 flow_info: 0,
647074afb6SRoman Volosatovs                 scope_id: 0,
657074afb6SRoman Volosatovs             }),
667074afb6SRoman Volosatovs         }
677074afb6SRoman Volosatovs     }
687074afb6SRoman Volosatovs 
ip(&self) -> IpAddress697074afb6SRoman Volosatovs     pub const fn ip(&self) -> IpAddress {
707074afb6SRoman Volosatovs         match self {
717074afb6SRoman Volosatovs             IpSocketAddress::Ipv4(addr) => IpAddress::Ipv4(addr.address),
727074afb6SRoman Volosatovs             IpSocketAddress::Ipv6(addr) => IpAddress::Ipv6(addr.address),
737074afb6SRoman Volosatovs         }
747074afb6SRoman Volosatovs     }
757074afb6SRoman Volosatovs 
port(&self) -> u16767074afb6SRoman Volosatovs     pub const fn port(&self) -> u16 {
777074afb6SRoman Volosatovs         match self {
787074afb6SRoman Volosatovs             IpSocketAddress::Ipv4(addr) => addr.port,
797074afb6SRoman Volosatovs             IpSocketAddress::Ipv6(addr) => addr.port,
807074afb6SRoman Volosatovs         }
817074afb6SRoman Volosatovs     }
827074afb6SRoman Volosatovs 
family(&self) -> IpAddressFamily837074afb6SRoman Volosatovs     pub const fn family(&self) -> IpAddressFamily {
847074afb6SRoman Volosatovs         match self {
857074afb6SRoman Volosatovs             IpSocketAddress::Ipv4(_) => IpAddressFamily::Ipv4,
867074afb6SRoman Volosatovs             IpSocketAddress::Ipv6(_) => IpAddressFamily::Ipv6,
877074afb6SRoman Volosatovs         }
887074afb6SRoman Volosatovs     }
897074afb6SRoman Volosatovs }
907074afb6SRoman Volosatovs 
917074afb6SRoman Volosatovs impl PartialEq for Ipv4SocketAddress {
eq(&self, other: &Self) -> bool927074afb6SRoman Volosatovs     fn eq(&self, other: &Self) -> bool {
937074afb6SRoman Volosatovs         self.port == other.port && self.address == other.address
947074afb6SRoman Volosatovs     }
957074afb6SRoman Volosatovs }
967074afb6SRoman Volosatovs 
977074afb6SRoman Volosatovs impl PartialEq for Ipv6SocketAddress {
eq(&self, other: &Self) -> bool987074afb6SRoman Volosatovs     fn eq(&self, other: &Self) -> bool {
997074afb6SRoman Volosatovs         self.port == other.port
1007074afb6SRoman Volosatovs             && self.flow_info == other.flow_info
1017074afb6SRoman Volosatovs             && self.address == other.address
1027074afb6SRoman Volosatovs             && self.scope_id == other.scope_id
1037074afb6SRoman Volosatovs     }
1047074afb6SRoman Volosatovs }
1057074afb6SRoman Volosatovs 
1067074afb6SRoman Volosatovs impl PartialEq for IpSocketAddress {
eq(&self, other: &Self) -> bool1077074afb6SRoman Volosatovs     fn eq(&self, other: &Self) -> bool {
1087074afb6SRoman Volosatovs         match (self, other) {
1097074afb6SRoman Volosatovs             (Self::Ipv4(l0), Self::Ipv4(r0)) => l0 == r0,
1107074afb6SRoman Volosatovs             (Self::Ipv6(l0), Self::Ipv6(r0)) => l0 == r0,
1117074afb6SRoman Volosatovs             _ => false,
1127074afb6SRoman Volosatovs         }
1137074afb6SRoman Volosatovs     }
1147074afb6SRoman Volosatovs }
1157074afb6SRoman Volosatovs 
generate_random_u16(range: Range<u16>) -> u161167074afb6SRoman Volosatovs fn generate_random_u16(range: Range<u16>) -> u16 {
1177074afb6SRoman Volosatovs     let start = range.start as u64;
1187074afb6SRoman Volosatovs     let end = range.end as u64;
1197074afb6SRoman Volosatovs     let port = start + (random::random::get_random_u64() % (end - start));
1207074afb6SRoman Volosatovs     port as u16
1217074afb6SRoman Volosatovs }
1227074afb6SRoman Volosatovs 
1237074afb6SRoman Volosatovs /// Execute the inner function with a randomly generated port.
1247074afb6SRoman Volosatovs /// 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>,1257074afb6SRoman Volosatovs pub fn attempt_random_port<F>(
1267074afb6SRoman Volosatovs     local_address: IpAddress,
1277074afb6SRoman Volosatovs     mut f: F,
1287074afb6SRoman Volosatovs ) -> Result<IpSocketAddress, ErrorCode>
1297074afb6SRoman Volosatovs where
1307074afb6SRoman Volosatovs     F: FnMut(IpSocketAddress) -> Result<(), ErrorCode>,
1317074afb6SRoman Volosatovs {
1327074afb6SRoman Volosatovs     const MAX_ATTEMPTS: u32 = 10;
1337074afb6SRoman Volosatovs     let mut i = 0;
1347074afb6SRoman Volosatovs     loop {
1357074afb6SRoman Volosatovs         i += 1;
1367074afb6SRoman Volosatovs 
1377074afb6SRoman Volosatovs         let port: u16 = generate_random_u16(1024..u16::MAX);
1387074afb6SRoman Volosatovs         let sock_addr = IpSocketAddress::new(local_address, port);
1397074afb6SRoman Volosatovs 
1407074afb6SRoman Volosatovs         match f(sock_addr) {
1417074afb6SRoman Volosatovs             Ok(_) => return Ok(sock_addr),
1427074afb6SRoman Volosatovs             Err(e) if i >= MAX_ATTEMPTS => return Err(e),
1437074afb6SRoman Volosatovs             // Try again if the port is already taken. This can sometimes show up as `AccessDenied` on Windows.
1447074afb6SRoman Volosatovs             Err(ErrorCode::AddressInUse | ErrorCode::AccessDenied) => {}
1457074afb6SRoman Volosatovs             Err(e) => return Err(e),
1467074afb6SRoman Volosatovs         }
1477074afb6SRoman Volosatovs     }
1487074afb6SRoman Volosatovs }
1497074afb6SRoman Volosatovs 
1507074afb6SRoman Volosatovs impl UdpSocket {
bind_unspecified(&self) -> Result<(), ErrorCode>1517074afb6SRoman Volosatovs     pub fn bind_unspecified(&self) -> Result<(), ErrorCode> {
152*7c9f88daSAlex Crichton         let ip = IpAddress::new_unspecified(self.get_address_family());
1537074afb6SRoman Volosatovs         let port = 0;
1547074afb6SRoman Volosatovs 
1557074afb6SRoman Volosatovs         self.bind(IpSocketAddress::new(ip, port))
1567074afb6SRoman Volosatovs     }
1577074afb6SRoman Volosatovs }
158