Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/test-programs/src/p3/sockets.rs
1693 views
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
21
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
28
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
35
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 {
44
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 {
54
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
69
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
76
pub const fn port(&self) -> u16 {
77
match self {
78
IpSocketAddress::Ipv4(addr) => addr.port,
79
IpSocketAddress::Ipv6(addr) => addr.port,
80
}
81
}
82
83
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 {
92
fn eq(&self, other: &Self) -> bool {
93
self.port == other.port && self.address == other.address
94
}
95
}
96
97
impl PartialEq for Ipv6SocketAddress {
98
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 {
107
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
116
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.
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 {
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
159