Path: blob/main/crates/test-programs/src/p3/sockets.rs
1693 views
use core::ops::Range;12use crate::p3::wasi::random;3use crate::p3::wasi::sockets::types::{4ErrorCode, IpAddress, IpAddressFamily, IpSocketAddress, Ipv4SocketAddress, Ipv6SocketAddress,5UdpSocket,6};78impl IpAddress {9pub const IPV4_BROADCAST: IpAddress = IpAddress::Ipv4((255, 255, 255, 255));1011pub const IPV4_LOOPBACK: IpAddress = IpAddress::Ipv4((127, 0, 0, 1));12pub const IPV6_LOOPBACK: IpAddress = IpAddress::Ipv6((0, 0, 0, 0, 0, 0, 0, 1));1314pub const IPV4_UNSPECIFIED: IpAddress = IpAddress::Ipv4((0, 0, 0, 0));15pub const IPV6_UNSPECIFIED: IpAddress = IpAddress::Ipv6((0, 0, 0, 0, 0, 0, 0, 0));1617pub const IPV4_MAPPED_LOOPBACK: IpAddress =18IpAddress::Ipv6((0, 0, 0, 0, 0, 0xFFFF, 0x7F00, 0x0001));1920pub const fn new_loopback(family: IpAddressFamily) -> IpAddress {21match family {22IpAddressFamily::Ipv4 => Self::IPV4_LOOPBACK,23IpAddressFamily::Ipv6 => Self::IPV6_LOOPBACK,24}25}2627pub const fn new_unspecified(family: IpAddressFamily) -> IpAddress {28match family {29IpAddressFamily::Ipv4 => Self::IPV4_UNSPECIFIED,30IpAddressFamily::Ipv6 => Self::IPV6_UNSPECIFIED,31}32}3334pub const fn family(&self) -> IpAddressFamily {35match self {36IpAddress::Ipv4(_) => IpAddressFamily::Ipv4,37IpAddress::Ipv6(_) => IpAddressFamily::Ipv6,38}39}40}4142impl PartialEq for IpAddress {43fn eq(&self, other: &Self) -> bool {44match (self, other) {45(Self::Ipv4(left), Self::Ipv4(right)) => left == right,46(Self::Ipv6(left), Self::Ipv6(right)) => left == right,47_ => false,48}49}50}5152impl IpSocketAddress {53pub const fn new(ip: IpAddress, port: u16) -> IpSocketAddress {54match ip {55IpAddress::Ipv4(addr) => IpSocketAddress::Ipv4(Ipv4SocketAddress {56port,57address: addr,58}),59IpAddress::Ipv6(addr) => IpSocketAddress::Ipv6(Ipv6SocketAddress {60port,61address: addr,62flow_info: 0,63scope_id: 0,64}),65}66}6768pub const fn ip(&self) -> IpAddress {69match self {70IpSocketAddress::Ipv4(addr) => IpAddress::Ipv4(addr.address),71IpSocketAddress::Ipv6(addr) => IpAddress::Ipv6(addr.address),72}73}7475pub const fn port(&self) -> u16 {76match self {77IpSocketAddress::Ipv4(addr) => addr.port,78IpSocketAddress::Ipv6(addr) => addr.port,79}80}8182pub const fn family(&self) -> IpAddressFamily {83match self {84IpSocketAddress::Ipv4(_) => IpAddressFamily::Ipv4,85IpSocketAddress::Ipv6(_) => IpAddressFamily::Ipv6,86}87}88}8990impl PartialEq for Ipv4SocketAddress {91fn eq(&self, other: &Self) -> bool {92self.port == other.port && self.address == other.address93}94}9596impl PartialEq for Ipv6SocketAddress {97fn eq(&self, other: &Self) -> bool {98self.port == other.port99&& self.flow_info == other.flow_info100&& self.address == other.address101&& self.scope_id == other.scope_id102}103}104105impl PartialEq for IpSocketAddress {106fn eq(&self, other: &Self) -> bool {107match (self, other) {108(Self::Ipv4(l0), Self::Ipv4(r0)) => l0 == r0,109(Self::Ipv6(l0), Self::Ipv6(r0)) => l0 == r0,110_ => false,111}112}113}114115fn generate_random_u16(range: Range<u16>) -> u16 {116let start = range.start as u64;117let end = range.end as u64;118let port = start + (random::random::get_random_u64() % (end - start));119port as u16120}121122/// Execute the inner function with a randomly generated port.123/// To prevent random failures, we make a few attempts before giving up.124pub fn attempt_random_port<F>(125local_address: IpAddress,126mut f: F,127) -> Result<IpSocketAddress, ErrorCode>128where129F: FnMut(IpSocketAddress) -> Result<(), ErrorCode>,130{131const MAX_ATTEMPTS: u32 = 10;132let mut i = 0;133loop {134i += 1;135136let port: u16 = generate_random_u16(1024..u16::MAX);137let sock_addr = IpSocketAddress::new(local_address, port);138139match f(sock_addr) {140Ok(_) => return Ok(sock_addr),141Err(e) if i >= MAX_ATTEMPTS => return Err(e),142// Try again if the port is already taken. This can sometimes show up as `AccessDenied` on Windows.143Err(ErrorCode::AddressInUse | ErrorCode::AccessDenied) => {}144Err(e) => return Err(e),145}146}147}148149impl UdpSocket {150pub fn bind_unspecified(&self) -> Result<(), ErrorCode> {151let ip = IpAddress::new_unspecified(self.get_address_family());152let port = 0;153154self.bind(IpSocketAddress::new(ip, port))155}156}157158159