1 use core::ops::Range;
2
3 use crate::p3::wasi::random;
4 use crate::p3::wasi::sockets::types::{
5 ErrorCode, IpAddress, IpAddressFamily, IpSocketAddress, Ipv4SocketAddress, Ipv6SocketAddress,
6 UdpSocket,
7 };
8
9 impl IpAddress {
10 pub const IPV4_BROADCAST: IpAddress = IpAddress::Ipv4((255, 255, 255, 255));
11
12 pub const IPV4_LOOPBACK: IpAddress = IpAddress::Ipv4((127, 0, 0, 1));
13 pub const IPV6_LOOPBACK: IpAddress = IpAddress::Ipv6((0, 0, 0, 0, 0, 0, 0, 1));
14
15 pub const IPV4_UNSPECIFIED: IpAddress = IpAddress::Ipv4((0, 0, 0, 0));
16 pub const IPV6_UNSPECIFIED: IpAddress = IpAddress::Ipv6((0, 0, 0, 0, 0, 0, 0, 0));
17
18 pub const IPV4_MAPPED_LOOPBACK: IpAddress =
19 IpAddress::Ipv6((0, 0, 0, 0, 0, 0xFFFF, 0x7F00, 0x0001));
20
new_loopback(family: IpAddressFamily) -> IpAddress21 pub const fn new_loopback(family: IpAddressFamily) -> IpAddress {
22 match family {
23 IpAddressFamily::Ipv4 => Self::IPV4_LOOPBACK,
24 IpAddressFamily::Ipv6 => Self::IPV6_LOOPBACK,
25 }
26 }
27
new_unspecified(family: IpAddressFamily) -> IpAddress28 pub const fn new_unspecified(family: IpAddressFamily) -> IpAddress {
29 match family {
30 IpAddressFamily::Ipv4 => Self::IPV4_UNSPECIFIED,
31 IpAddressFamily::Ipv6 => Self::IPV6_UNSPECIFIED,
32 }
33 }
34
family(&self) -> IpAddressFamily35 pub const fn family(&self) -> IpAddressFamily {
36 match self {
37 IpAddress::Ipv4(_) => IpAddressFamily::Ipv4,
38 IpAddress::Ipv6(_) => IpAddressFamily::Ipv6,
39 }
40 }
41 }
42
43 impl PartialEq for IpAddress {
eq(&self, other: &Self) -> bool44 fn eq(&self, other: &Self) -> bool {
45 match (self, other) {
46 (Self::Ipv4(left), Self::Ipv4(right)) => left == right,
47 (Self::Ipv6(left), Self::Ipv6(right)) => left == right,
48 _ => false,
49 }
50 }
51 }
52
53 impl IpSocketAddress {
new(ip: IpAddress, port: u16) -> IpSocketAddress54 pub const fn new(ip: IpAddress, port: u16) -> IpSocketAddress {
55 match ip {
56 IpAddress::Ipv4(addr) => IpSocketAddress::Ipv4(Ipv4SocketAddress {
57 port,
58 address: addr,
59 }),
60 IpAddress::Ipv6(addr) => IpSocketAddress::Ipv6(Ipv6SocketAddress {
61 port,
62 address: addr,
63 flow_info: 0,
64 scope_id: 0,
65 }),
66 }
67 }
68
ip(&self) -> IpAddress69 pub const fn ip(&self) -> IpAddress {
70 match self {
71 IpSocketAddress::Ipv4(addr) => IpAddress::Ipv4(addr.address),
72 IpSocketAddress::Ipv6(addr) => IpAddress::Ipv6(addr.address),
73 }
74 }
75
port(&self) -> u1676 pub const fn port(&self) -> u16 {
77 match self {
78 IpSocketAddress::Ipv4(addr) => addr.port,
79 IpSocketAddress::Ipv6(addr) => addr.port,
80 }
81 }
82
family(&self) -> IpAddressFamily83 pub const fn family(&self) -> IpAddressFamily {
84 match self {
85 IpSocketAddress::Ipv4(_) => IpAddressFamily::Ipv4,
86 IpSocketAddress::Ipv6(_) => IpAddressFamily::Ipv6,
87 }
88 }
89 }
90
91 impl PartialEq for Ipv4SocketAddress {
eq(&self, other: &Self) -> bool92 fn eq(&self, other: &Self) -> bool {
93 self.port == other.port && self.address == other.address
94 }
95 }
96
97 impl PartialEq for Ipv6SocketAddress {
eq(&self, other: &Self) -> bool98 fn eq(&self, other: &Self) -> bool {
99 self.port == other.port
100 && self.flow_info == other.flow_info
101 && self.address == other.address
102 && self.scope_id == other.scope_id
103 }
104 }
105
106 impl PartialEq for IpSocketAddress {
eq(&self, other: &Self) -> bool107 fn eq(&self, other: &Self) -> bool {
108 match (self, other) {
109 (Self::Ipv4(l0), Self::Ipv4(r0)) => l0 == r0,
110 (Self::Ipv6(l0), Self::Ipv6(r0)) => l0 == r0,
111 _ => false,
112 }
113 }
114 }
115
generate_random_u16(range: Range<u16>) -> u16116 fn generate_random_u16(range: Range<u16>) -> u16 {
117 let start = range.start as u64;
118 let end = range.end as u64;
119 let port = start + (random::random::get_random_u64() % (end - start));
120 port as u16
121 }
122
123 /// Execute the inner function with a randomly generated port.
124 /// 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>,125 pub fn attempt_random_port<F>(
126 local_address: IpAddress,
127 mut f: F,
128 ) -> Result<IpSocketAddress, ErrorCode>
129 where
130 F: FnMut(IpSocketAddress) -> Result<(), ErrorCode>,
131 {
132 const MAX_ATTEMPTS: u32 = 10;
133 let mut i = 0;
134 loop {
135 i += 1;
136
137 let port: u16 = generate_random_u16(1024..u16::MAX);
138 let sock_addr = IpSocketAddress::new(local_address, port);
139
140 match f(sock_addr) {
141 Ok(_) => return Ok(sock_addr),
142 Err(e) if i >= MAX_ATTEMPTS => return Err(e),
143 // Try again if the port is already taken. This can sometimes show up as `AccessDenied` on Windows.
144 Err(ErrorCode::AddressInUse | ErrorCode::AccessDenied) => {}
145 Err(e) => return Err(e),
146 }
147 }
148 }
149
150 impl UdpSocket {
bind_unspecified(&self) -> Result<(), ErrorCode>151 pub fn bind_unspecified(&self) -> Result<(), ErrorCode> {
152 let ip = IpAddress::new_unspecified(self.get_address_family());
153 let port = 0;
154
155 self.bind(IpSocketAddress::new(ip, port))
156 }
157 }
158