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

`+

}

`