Hook up std::net to wasi-libc on wasm32-wasip2 target · qinheping/verify-rust-std@b0cc902 (original) (raw)
``
1
`+
#![deny(unsafe_op_in_unsafe_fn)]
`
``
2
+
``
3
`+
use libc::{c_int, c_void, size_t};
`
``
4
+
``
5
`+
use super::fd::WasiFd;
`
``
6
`+
use crate::ffi::CStr;
`
``
7
`+
use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut};
`
``
8
`+
use crate:🥅:{Shutdown, SocketAddr};
`
``
9
`+
use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
`
``
10
`+
use crate::sys::unsupported;
`
``
11
`+
use crate::sys_common:🥅:{TcpListener, getsockopt, setsockopt, sockaddr_to_addr};
`
``
12
`+
use crate::sys_common::{AsInner, FromInner, IntoInner};
`
``
13
`+
use crate::time::{Duration, Instant};
`
``
14
`+
use crate::{cmp, mem, str};
`
``
15
+
``
16
`+
pub extern crate libc as netc;
`
``
17
+
``
18
`+
#[allow(non_camel_case_types)]
`
``
19
`+
pub type wrlen_t = size_t;
`
``
20
+
``
21
`+
#[doc(hidden)]
`
``
22
`+
pub trait IsMinusOne {
`
``
23
`+
fn is_minus_one(&self) -> bool;
`
``
24
`+
}
`
``
25
+
``
26
`+
macro_rules! impl_is_minus_one {
`
``
27
`+
($($t:ident)*) => ($(impl IsMinusOne for $t {
`
``
28
`+
fn is_minus_one(&self) -> bool {
`
``
29
`+
*self == -1
`
``
30
`+
}
`
``
31
`+
})*)
`
``
32
`+
}
`
``
33
+
``
34
`+
impl_is_minus_one! { i8 i16 i32 i64 isize }
`
``
35
+
``
36
`+
pub fn cvt<T: IsMinusOne>(t: T) -> crate::io::Result {
`
``
37
`+
if t.is_minus_one() { Err(crate::io::Error::last_os_error()) } else { Ok(t) }
`
``
38
`+
}
`
``
39
+
``
40
`+
pub fn cvt_r<T, F>(mut f: F) -> crate::io::Result
`
``
41
`+
where
`
``
42
`+
T: IsMinusOne,
`
``
43
`+
F: FnMut() -> T,
`
``
44
`+
{
`
``
45
`+
loop {
`
``
46
`+
match cvt(f()) {
`
``
47
`+
Err(ref e) if e.is_interrupted() => {}
`
``
48
`+
other => return other,
`
``
49
`+
}
`
``
50
`+
}
`
``
51
`+
}
`
``
52
+
``
53
`+
pub fn cvt_gai(err: c_int) -> io::Result<()> {
`
``
54
`+
if err == 0 {
`
``
55
`+
return Ok(());
`
``
56
`+
}
`
``
57
+
``
58
`+
if err == netc::EAI_SYSTEM {
`
``
59
`+
return Err(io::Error::last_os_error());
`
``
60
`+
}
`
``
61
+
``
62
`+
let detail = unsafe {
`
``
63
`+
str::from_utf8(CStr::from_ptr(netc::gai_strerror(err)).to_bytes()).unwrap().to_owned()
`
``
64
`+
};
`
``
65
+
``
66
`+
Err(io::Error::new(
`
``
67
`+
io::ErrorKind::Uncategorized,
`
``
68
`+
&format!("failed to lookup address information: {detail}")[..],
`
``
69
`+
))
`
``
70
`+
}
`
``
71
+
``
72
`+
pub fn init() {}
`
``
73
+
``
74
`+
pub struct Socket(WasiFd);
`
``
75
+
``
76
`+
impl Socket {
`
``
77
`+
pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result {
`
``
78
`+
let fam = match *addr {
`
``
79
`+
SocketAddr::V4(..) => netc::AF_INET,
`
``
80
`+
SocketAddr::V6(..) => netc::AF_INET6,
`
``
81
`+
};
`
``
82
`+
Socket::new_raw(fam, ty)
`
``
83
`+
}
`
``
84
+
``
85
`+
pub fn new_raw(fam: c_int, ty: c_int) -> io::Result {
`
``
86
`+
let fd = cvt(unsafe { netc::socket(fam, ty, 0) })?;
`
``
87
`+
Ok(unsafe { Self::from_raw_fd(fd) })
`
``
88
`+
}
`
``
89
+
``
90
`+
pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> {
`
``
91
`+
let (addr, len) = addr.into_inner();
`
``
92
`+
cvt_r(|| unsafe { netc::connect(self.as_raw_fd(), addr.as_ptr(), len) })?;
`
``
93
`+
Ok(())
`
``
94
`+
}
`
``
95
+
``
96
`+
pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
`
``
97
`+
self.set_nonblocking(true)?;
`
``
98
`+
let r = self.connect(addr);
`
``
99
`+
self.set_nonblocking(false)?;
`
``
100
+
``
101
`+
match r {
`
``
102
`+
Ok(_) => return Ok(()),
`
``
103
`+
// there's no ErrorKind for EINPROGRESS
`
``
104
`+
Err(ref e) if e.raw_os_error() == Some(netc::EINPROGRESS) => {}
`
``
105
`+
Err(e) => return Err(e),
`
``
106
`+
}
`
``
107
+
``
108
`+
let mut pollfd = netc::pollfd { fd: self.as_raw_fd(), events: netc::POLLOUT, revents: 0 };
`
``
109
+
``
110
`+
if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
`
``
111
`+
return Err(io::Error::ZERO_TIMEOUT);
`
``
112
`+
}
`
``
113
+
``
114
`+
let start = Instant::now();
`
``
115
+
``
116
`+
loop {
`
``
117
`+
let elapsed = start.elapsed();
`
``
118
`+
if elapsed >= timeout {
`
``
119
`+
return Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out"));
`
``
120
`+
}
`
``
121
+
``
122
`+
let timeout = timeout - elapsed;
`
``
123
`+
let mut timeout = timeout
`
``
124
`+
.as_secs()
`
``
125
`+
.saturating_mul(1_000)
`
``
126
`+
.saturating_add(timeout.subsec_nanos() as u64 / 1_000_000);
`
``
127
`+
if timeout == 0 {
`
``
128
`+
timeout = 1;
`
``
129
`+
}
`
``
130
+
``
131
`+
let timeout = cmp::min(timeout, c_int::MAX as u64) as c_int;
`
``
132
+
``
133
`+
match unsafe { netc::poll(&mut pollfd, 1, timeout) } {
`
``
134
`+
-1 => {
`
``
135
`+
let err = io::Error::last_os_error();
`
``
136
`+
if !err.is_interrupted() {
`
``
137
`+
return Err(err);
`
``
138
`+
}
`
``
139
`+
}
`
``
140
`+
0 => {}
`
``
141
`+
_ => {
`
``
142
`+
// WASI poll does not return POLLHUP or POLLERR in revents. Check if the
`
``
143
`+
// connnection actually succeeded and return ok only when the socket is
`
``
144
`+
// ready and no errors were found.
`
``
145
`+
if let Some(e) = self.take_error()? {
`
``
146
`+
return Err(e);
`
``
147
`+
}
`
``
148
+
``
149
`+
return Ok(());
`
``
150
`+
}
`
``
151
`+
}
`
``
152
`+
}
`
``
153
`+
}
`
``
154
+
``
155
`+
pub fn accept(
`
``
156
`+
&self,
`
``
157
`+
storage: *mut netc::sockaddr,
`
``
158
`+
len: *mut netc::socklen_t,
`
``
159
`+
) -> io::Result {
`
``
160
`+
let fd = cvt_r(|| unsafe { netc::accept(self.as_raw_fd(), storage, len) })?;
`
``
161
`+
Ok(unsafe { Self::from_raw_fd(fd) })
`
``
162
`+
}
`
``
163
+
``
164
`+
pub fn duplicate(&self) -> io::Result {
`
``
165
`+
unsupported()
`
``
166
`+
}
`
``
167
+
``
168
`+
fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Result<()> {
`
``
169
`+
let ret = cvt(unsafe {
`
``
170
`+
netc::recv(
`
``
171
`+
self.as_raw_fd(),
`
``
172
`+
buf.as_mut().as_mut_ptr() as *mut c_void,
`
``
173
`+
buf.capacity(),
`
``
174
`+
flags,
`
``
175
`+
)
`
``
176
`+
})?;
`
``
177
`+
unsafe {
`
``
178
`+
buf.advance_unchecked(ret as usize);
`
``
179
`+
}
`
``
180
`+
Ok(())
`
``
181
`+
}
`
``
182
+
``
183
`+
pub fn read(&self, buf: &mut [u8]) -> io::Result {
`
``
184
`+
let mut buf = BorrowedBuf::from(buf);
`
``
185
`+
self.recv_with_flags(buf.unfilled(), 0)?;
`
``
186
`+
Ok(buf.len())
`
``
187
`+
}
`
``
188
+
``
189
`+
pub fn peek(&self, buf: &mut [u8]) -> io::Result {
`
``
190
`+
let mut buf = BorrowedBuf::from(buf);
`
``
191
`+
self.recv_with_flags(buf.unfilled(), netc::MSG_PEEK)?;
`
``
192
`+
Ok(buf.len())
`
``
193
`+
}
`
``
194
+
``
195
`+
pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> {
`
``
196
`+
self.recv_with_flags(buf, 0)
`
``
197
`+
}
`
``
198
+
``
199
`+
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result {
`
``
200
`+
io::default_read_vectored(|b| self.read(b), bufs)
`
``
201
`+
}
`
``
202
+
``
203
`+
#[inline]
`
``
204
`+
pub fn is_read_vectored(&self) -> bool {
`
``
205
`+
false
`
``
206
`+
}
`
``
207
+
``
208
`+
fn recv_from_with_flags(
`
``
209
`+
&self,
`
``
210
`+
buf: &mut [u8],
`
``
211
`+
flags: c_int,
`
``
212
`+
) -> io::Result<(usize, SocketAddr)> {
`
``
213
`+
let mut storage: netc::sockaddr_storage = unsafe { mem::zeroed() };
`
``
214
`+
let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t;
`
``
215
+
``
216
`+
let n = cvt(unsafe {
`
``
217
`+
netc::recvfrom(
`
``
218
`+
self.as_raw_fd(),
`
``
219
`+
buf.as_mut_ptr() as *mut c_void,
`
``
220
`+
buf.len(),
`
``
221
`+
flags,
`
``
222
`+
core::ptr::addr_of_mut!(storage) as *mut _,
`
``
223
`+
&mut addrlen,
`
``
224
`+
)
`
``
225
`+
})?;
`
``
226
`+
Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?))
`
``
227
`+
}
`
``
228
+
``
229
`+
pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
`
``
230
`+
self.recv_from_with_flags(buf, 0)
`
``
231
`+
}
`
``
232
+
``
233
`+
pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
`
``
234
`+
self.recv_from_with_flags(buf, netc::MSG_PEEK)
`
``
235
`+
}
`
``
236
+
``
237
`+
fn write(&self, buf: &[u8]) -> io::Result {
`
``
238
`+
let len = cmp::min(buf.len(), ::MAX as usize) as wrlen_t;
`
``
239
`+
let ret = cvt(unsafe {
`
``
240
`+
netc::send(self.as_raw(), buf.as_ptr() as *const c_void, len, netc::MSG_NOSIGNAL)
`
``
241
`+
})?;
`
``
242
`+
Ok(ret as usize)
`
``
243
`+
}
`
``
244
+
``
245
`+
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result {
`
``
246
`+
io::default_write_vectored(|b| self.write(b), bufs)
`
``
247
`+
}
`
``
248
+
``
249
`+
#[inline]
`
``
250
`+
pub fn is_write_vectored(&self) -> bool {
`
``
251
`+
false
`
``
252
`+
}
`
``
253
+
``
254
`+
pub fn set_timeout(&self, dur: Option, kind: c_int) -> io::Result<()> {
`
``
255
`+
let timeout = match dur {
`
``
256
`+
Some(dur) => {
`
``
257
`+
if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
`
``
258
`+
return Err(io::Error::ZERO_TIMEOUT);
`
``
259
`+
}
`
``
260
+
``
261
`+
let secs = dur.as_secs().try_into().unwrap_or(netc::time_t::MAX);
`
``
262
`+
let mut timeout = netc::timeval {
`
``
263
`+
tv_sec: secs,
`
``
264
`+
tv_usec: dur.subsec_micros() as netc::suseconds_t,
`
``
265
`+
};
`
``
266
`+
if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
`
``
267
`+
timeout.tv_usec = 1;
`
``
268
`+
}
`
``
269
`+
timeout
`
``
270
`+
}
`
``
271
`+
None => netc::timeval { tv_sec: 0, tv_usec: 0 },
`
``
272
`+
};
`
``
273
`+
setsockopt(self, netc::SOL_SOCKET, kind, timeout)
`
``
274
`+
}
`
``
275
+
``
276
`+
pub fn timeout(&self, kind: c_int) -> io::Result<Option> {
`
``
277
`+
let raw: netc::timeval = getsockopt(self, netc::SOL_SOCKET, kind)?;
`
``
278
`+
if raw.tv_sec == 0 && raw.tv_usec == 0 {
`
``
279
`+
Ok(None)
`
``
280
`+
} else {
`
``
281
`+
let sec = raw.tv_sec as u64;
`
``
282
`+
let nsec = (raw.tv_usec as u32) * 1000;
`
``
283
`+
Ok(Some(Duration::new(sec, nsec)))
`
``
284
`+
}
`
``
285
`+
}
`
``
286
+
``
287
`+
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
`
``
288
`+
let how = match how {
`
``
289
`+
Shutdown::Write => netc::SHUT_WR,
`
``
290
`+
Shutdown::Read => netc::SHUT_RD,
`
``
291
`+
Shutdown::Both => netc::SHUT_RDWR,
`
``
292
`+
};
`
``
293
`+
cvt(unsafe { netc::shutdown(self.as_raw_fd(), how) })?;
`
``
294
`+
Ok(())
`
``
295
`+
}
`
``
296
+
``
297
`+
pub fn set_linger(&self, _linger: Option) -> io::Result<()> {
`
``
298
`+
unsupported()
`
``
299
`+
}
`
``
300
+
``
301
`+
pub fn linger(&self) -> io::Result<Option> {
`
``
302
`+
unsupported()
`
``
303
`+
}
`
``
304
+
``
305
`+
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
`
``
306
`+
setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, nodelay as c_int)
`
``
307
`+
}
`
``
308
+
``
309
`+
pub fn nodelay(&self) -> io::Result {
`
``
310
`+
let raw: c_int = getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)?;
`
``
311
`+
Ok(raw != 0)
`
``
312
`+
}
`
``
313
+
``
314
`+
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
`
``
315
`+
let mut nonblocking = nonblocking as c_int;
`
``
316
`+
cvt(unsafe { netc::ioctl(self.as_raw_fd(), netc::FIONBIO, &mut nonblocking) }).map(drop)
`
``
317
`+
}
`
``
318
+
``
319
`+
pub fn take_error(&self) -> io::Result<Optionio::Error> {
`
``
320
`+
let raw: c_int = getsockopt(self, netc::SOL_SOCKET, netc::SO_ERROR)?;
`
``
321
`+
if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) }
`
``
322
`+
}
`
``
323
+
``
324
`+
// This is used by sys_common code to abstract over Windows and Unix.
`
``
325
`+
pub fn as_raw(&self) -> RawFd {
`
``
326
`+
self.as_raw_fd()
`
``
327
`+
}
`
``
328
`+
}
`
``
329
+
``
330
`+
impl AsInner for Socket {
`
``
331
`+
#[inline]
`
``
332
`+
fn as_inner(&self) -> &WasiFd {
`
``
333
`+
&self.0
`
``
334
`+
}
`
``
335
`+
}
`
``
336
+
``
337
`+
impl IntoInner for Socket {
`
``
338
`+
fn into_inner(self) -> WasiFd {
`
``
339
`+
self.0
`
``
340
`+
}
`
``
341
`+
}
`
``
342
+
``
343
`+
impl FromInner for Socket {
`
``
344
`+
fn from_inner(inner: WasiFd) -> Socket {
`
``
345
`+
Socket(inner)
`
``
346
`+
}
`
``
347
`+
}
`
``
348
+
``
349
`+
impl AsFd for Socket {
`
``
350
`+
fn as_fd(&self) -> BorrowedFd<'_> {
`
``
351
`+
self.0.as_fd()
`
``
352
`+
}
`
``
353
`+
}
`
``
354
+
``
355
`+
impl AsRawFd for Socket {
`
``
356
`+
#[inline]
`
``
357
`+
fn as_raw_fd(&self) -> RawFd {
`
``
358
`+
self.0.as_raw_fd()
`
``
359
`+
}
`
``
360
`+
}
`
``
361
+
``
362
`+
impl IntoRawFd for Socket {
`
``
363
`+
fn into_raw_fd(self) -> RawFd {
`
``
364
`+
self.0.into_raw_fd()
`
``
365
`+
}
`
``
366
`+
}
`
``
367
+
``
368
`+
impl FromRawFd for Socket {
`
``
369
`+
unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
`
``
370
`+
unsafe { Self(FromRawFd::from_raw_fd(raw_fd)) }
`
``
371
`+
}
`
``
372
`+
}
`
``
373
+
``
374
`+
impl AsInner for TcpListener {
`
``
375
`+
#[inline]
`
``
376
`+
fn as_inner(&self) -> &Socket {
`
``
377
`+
&self.socket()
`
``
378
`+
}
`
``
379
`+
}
`