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