1use crate::snapshots::{
2 common::{
3 memory::{Memory, WasmPtr},
4 net::{self, AddressFamily, SocketType, WasiSocketState},
5 types::*,
6 },
7 Errno, WasiCtx,
8};
9use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
10
11cfg_if::cfg_if! {
12 if #[cfg(any(
13 target_os = "linux", target_os = "android",
14 target_os = "dragonfly", target_os = "freebsd",
15 target_os = "openbsd", target_os = "netbsd",
16 target_os = "haiku", target_os = "nto"))] {
17 use libc::MSG_NOSIGNAL;
18 } else {
19 const MSG_NOSIGNAL: std::ffi::c_int = 0x0;
20 }
21}
22
23fn parse_wasi_ip<M: Memory>(mem: &M, addr_ptr: WasmPtr<__wasi_address_t>) -> Result<IpAddr, Errno> {
24 let wasi_addr = *(mem.get_data(addr_ptr)?);
25 if wasi_addr.buf_len != 4 && wasi_addr.buf_len != 16 {
26 return Err(Errno::__WASI_ERRNO_INVAL);
27 }
28 let addr_buf_ptr = WasmPtr::<u8>::from(wasi_addr.buf as usize);
29
30 let addr = if wasi_addr.buf_len == 4 {
31 let addr_buf = mem.get_slice(addr_buf_ptr, 4)?;
32 IpAddr::V4(Ipv4Addr::new(
33 addr_buf[0],
34 addr_buf[1],
35 addr_buf[2],
36 addr_buf[3],
37 ))
38 } else {
39 let addr_buf_ref = mem.get_slice(addr_buf_ptr, 16)?;
40 let mut addr_buf = [0u8; 16];
41 addr_buf.copy_from_slice(addr_buf_ref);
42 IpAddr::V6(Ipv6Addr::from(addr_buf))
43 };
44 Ok(addr)
45}
46
47pub fn sock_open<M: Memory>(
48 ctx: &mut WasiCtx,
49 mem: &mut M,
50 af: __wasi_address_family_t::Type,
51 ty: __wasi_sock_type_t::Type,
52 ro_fd_ptr: WasmPtr<__wasi_fd_t>,
53) -> Result<(), Errno> {
54 log::trace!("sock_open ...");
55
56 let mut state = WasiSocketState::default();
57 match af {
58 __wasi_address_family_t::__WASI_ADDRESS_FAMILY_INET4 => {
59 state.sock_type.0 = AddressFamily::Inet4
60 }
61 __wasi_address_family_t::__WASI_ADDRESS_FAMILY_INET6 => {
62 state.sock_type.0 = AddressFamily::Inet6
63 }
64 _ => return Err(Errno::__WASI_ERRNO_INVAL),
65 }
66 match ty {
67 __wasi_sock_type_t::__WASI_SOCK_TYPE_SOCK_DGRAM => {
68 state.sock_type.1 = SocketType::Datagram;
69 }
70 __wasi_sock_type_t::__WASI_SOCK_TYPE_SOCK_STREAM => {
71 state.sock_type.1 = SocketType::Stream;
72 }
73 _ => return Err(Errno::__WASI_ERRNO_INVAL),
74 }
75
76 let s = net::async_tokio::AsyncWasiSocket::open(state)?;
77 let fd = ctx.vfs.insert_socket(s)?;
78 log::trace!("sock_open {fd}");
79
80 mem.write_data(ro_fd_ptr, fd as __wasi_fd_t)?;
81 Ok(())
82}
83
84pub fn sock_bind<M: Memory>(
85 ctx: &mut WasiCtx,
86 mem: &M,
87 fd: __wasi_fd_t,
88 addr_ptr: WasmPtr<__wasi_address_t>,
89 port: u32,
90) -> Result<(), Errno> {
91 log::trace!("sock_bind {fd}");
92
93 let ip = parse_wasi_ip(mem, addr_ptr)?;
94 let addr = SocketAddr::new(ip, port as u16);
95
96 let s = ctx.vfs.get_mut_socket(fd as usize)?;
97 s.bind(addr)?;
98 Ok(())
99}
100
101pub fn sock_listen<M: Memory>(
102 ctx: &mut WasiCtx,
103 _mem: &mut M,
104 fd: __wasi_fd_t,
105 backlog: u32,
106) -> Result<(), Errno> {
107 log::trace!("sock_listen {fd}");
108
109 let s = ctx.vfs.get_mut_socket(fd as usize)?;
110 s.listen(backlog)?;
111 Ok(())
112}
113
114pub async fn sock_accept<M: Memory>(
115 ctx: &mut WasiCtx,
116 mem: &mut M,
117 fd: __wasi_fd_t,
118 ro_fd_ptr: WasmPtr<__wasi_fd_t>,
119) -> Result<(), Errno> {
120 log::trace!("sock_accept {fd}");
121
122 let s = ctx.vfs.get_mut_socket(fd as usize)?;
123 let cs = s.accept().await?;
124 let new_fd = ctx.vfs.insert_socket(cs)?;
125 mem.write_data(ro_fd_ptr, new_fd as __wasi_fd_t)?;
126 Ok(())
127}
128
129pub async fn sock_connect<M: Memory>(
130 ctx: &mut WasiCtx,
131 mem: &M,
132 fd: __wasi_fd_t,
133 addr_ptr: WasmPtr<__wasi_address_t>,
134 port: u32,
135) -> Result<(), Errno> {
136 log::trace!("sock_connect {fd}");
137
138 let ip = parse_wasi_ip(mem, addr_ptr)?;
139 let addr = SocketAddr::new(ip, port as u16);
140
141 ctx.vfs.get_mut_socket(fd as usize)?.connect(addr).await?;
142 Ok(())
143}
144
145pub async fn sock_recv<M: Memory>(
146 ctx: &mut WasiCtx,
147 mem: &mut M,
148 fd: __wasi_fd_t,
149 buf_ptr: WasmPtr<__wasi_iovec_t>,
150 buf_len: __wasi_size_t,
151 flags: __wasi_riflags_t::Type,
152 ro_data_len_ptr: WasmPtr<__wasi_size_t>,
153 ro_flags_ptr: WasmPtr<__wasi_roflags_t::Type>,
154) -> Result<(), Errno> {
155 log::trace!("sock_recv {fd}");
156
157 let s = ctx.vfs.get_mut_socket(fd as usize)?;
158 let mut iovec = mem.mut_iovec(buf_ptr, buf_len)?;
159 let mut native_flags = 0;
160
161 if flags & __wasi_riflags_t::__WASI_RIFLAGS_RECV_PEEK > 0 {
162 native_flags |= libc::MSG_PEEK;
163 }
164 if flags & __wasi_riflags_t::__WASI_RIFLAGS_RECV_WAITALL > 0 {
165 native_flags |= libc::MSG_WAITALL;
166 }
167
168 let (n, trunc) = s.recv(&mut iovec, native_flags).await?;
169 if trunc {
170 mem.write_data(
171 ro_flags_ptr,
172 __wasi_roflags_t::__WASI_ROFLAGS_RECV_DATA_TRUNCATED,
173 )?;
174 }
175
176 s.writable.set_writable();
177 mem.write_data(ro_data_len_ptr, (n as u32).to_le())?;
178 Ok(())
179}
180
181pub async fn sock_recv_from<M: Memory>(
182 ctx: &mut WasiCtx,
183 mem: &mut M,
184 fd: __wasi_fd_t,
185 buf_ptr: WasmPtr<__wasi_iovec_t>,
186 buf_len: __wasi_size_t,
187 wasi_addr_ptr: WasmPtr<__wasi_address_t>,
188 flags: __wasi_riflags_t::Type,
189 port_ptr: WasmPtr<u32>,
190 ro_data_len_ptr: WasmPtr<__wasi_size_t>,
191 ro_flags_ptr: WasmPtr<__wasi_roflags_t::Type>,
192) -> Result<(), Errno> {
193 log::trace!("sock_recv_from {fd}");
194
195 let s = ctx.vfs.get_mut_socket(fd as usize)?;
196
197 let wasi_addr = *(mem.mut_data(wasi_addr_ptr)?);
198 if wasi_addr.buf_len < 128 {
199 return Err(Errno::__WASI_ERRNO_INVAL);
200 }
201
202 let mut iovec = mem.mut_iovec(buf_ptr, buf_len)?;
203 let mut native_flags = 0;
204
205 if flags & __wasi_riflags_t::__WASI_RIFLAGS_RECV_PEEK > 0 {
206 native_flags |= libc::MSG_PEEK;
207 }
208 if flags & __wasi_riflags_t::__WASI_RIFLAGS_RECV_WAITALL > 0 {
209 native_flags |= libc::MSG_WAITALL;
210 }
211
212 let (n, trunc, addr) = s.recv_from(&mut iovec, native_flags).await?;
213
214 match addr {
215 Some(SocketAddr::V4(addrv4)) => {
216 let family_ptr = WasmPtr::<u16>::from(wasi_addr.buf as usize);
217 let wasi_addr_buf_ptr = WasmPtr::<u8>::from(2 + wasi_addr.buf as usize);
218 let wasi_addr_buf = mem.mut_slice(wasi_addr_buf_ptr, 4)?;
219 wasi_addr_buf.copy_from_slice(&addrv4.ip().octets());
220
221 mem.write_data(
222 family_ptr,
223 __wasi_address_family_t::__WASI_ADDRESS_FAMILY_INET4 as u16,
224 )?;
225
226 mem.write_data(port_ptr, (addrv4.port() as u32).to_le())?;
227 }
228 Some(SocketAddr::V6(addrv6)) => {
229 let family_ptr = WasmPtr::<u16>::from(wasi_addr.buf as usize);
230 let wasi_addr_buf_ptr = WasmPtr::<u8>::from(2 + wasi_addr.buf as usize);
231 let wasi_addr_buf = mem.mut_slice(wasi_addr_buf_ptr, 16)?;
232 wasi_addr_buf.copy_from_slice(&addrv6.ip().octets());
233 mem.write_data(
234 family_ptr,
235 __wasi_address_family_t::__WASI_ADDRESS_FAMILY_INET6 as u16,
236 )?;
237 mem.write_data(port_ptr, (addrv6.port() as u32).to_le())?;
238 }
239 None => {}
240 };
241
242 if trunc {
243 mem.write_data(
244 ro_flags_ptr,
245 __wasi_roflags_t::__WASI_ROFLAGS_RECV_DATA_TRUNCATED,
246 )?;
247 }
248
249 s.writable.set_writable();
250 mem.write_data(ro_data_len_ptr, (n as u32).to_le())?;
251 Ok(())
252}
253
254pub async fn sock_send<M: Memory>(
255 ctx: &mut WasiCtx,
256 mem: &mut M,
257 fd: __wasi_fd_t,
258 buf_ptr: WasmPtr<__wasi_ciovec_t>,
259 buf_len: __wasi_size_t,
260 _flags: __wasi_siflags_t,
261 send_len_ptr: WasmPtr<__wasi_size_t>,
262) -> Result<(), Errno> {
263 log::trace!("sock_send {fd}");
264
265 let s = ctx.vfs.get_mut_socket(fd as usize)?;
266 let iovec = mem.get_iovec(buf_ptr, buf_len)?;
267 let n = s.send(&iovec, MSG_NOSIGNAL).await?;
268 s.writable.set_writable();
269 mem.write_data(send_len_ptr, (n as u32).to_le())?;
270 Ok(())
271}
272
273pub async fn sock_send_to<M: Memory>(
274 ctx: &mut WasiCtx,
275 mem: &mut M,
276 fd: __wasi_fd_t,
277 buf_ptr: WasmPtr<__wasi_ciovec_t>,
278 buf_len: __wasi_size_t,
279 wasi_addr_ptr: WasmPtr<__wasi_address_t>,
280 port: u32,
281 _flags: __wasi_siflags_t,
282 send_len_ptr: WasmPtr<__wasi_size_t>,
283) -> Result<(), Errno> {
284 log::trace!("sock_send_to {fd}");
285
286 let s = ctx.vfs.get_mut_socket(fd as usize)?;
287
288 let ip = parse_wasi_ip(mem, wasi_addr_ptr)?;
289 let addr = SocketAddr::new(ip, port as u16);
290 let iovec = mem.get_iovec(buf_ptr, buf_len)?;
291
292 let n = s.send_to(&iovec, addr, MSG_NOSIGNAL).await?;
293 s.writable.set_writable();
294 mem.write_data(send_len_ptr, (n as u32).to_le())?;
295 Ok(())
296}
297
298pub fn sock_shutdown<M: Memory>(
299 ctx: &mut WasiCtx,
300 _mem: &mut M,
301 fd: __wasi_fd_t,
302 how: __wasi_sdflags_t::Type,
303) -> Result<(), Errno> {
304 log::trace!("sock_shutdown {fd}");
305
306 use std::net::Shutdown;
307
308 let s = ctx.vfs.get_mut_socket(fd as usize)?;
309
310 const BOTH: __wasi_sdflags_t::Type =
311 __wasi_sdflags_t::__WASI_SDFLAGS_WR | __wasi_sdflags_t::__WASI_SDFLAGS_RD;
312
313 let how = match how {
314 __wasi_sdflags_t::__WASI_SDFLAGS_RD => Shutdown::Read,
315 __wasi_sdflags_t::__WASI_SDFLAGS_WR => Shutdown::Write,
316 BOTH => Shutdown::Both,
317 _ => return Err(Errno::__WASI_ERRNO_INVAL),
318 };
319
320 s.shutdown(how)?;
321 Ok(())
322}
323
324pub fn sock_getpeeraddr<M: Memory>(
325 ctx: &mut WasiCtx,
326 mem: &mut M,
327 fd: __wasi_fd_t,
328 wasi_addr_ptr: WasmPtr<__wasi_address_t>,
329 addr_type: WasmPtr<u32>,
330 port_ptr: WasmPtr<u32>,
331) -> Result<(), Errno> {
332 log::trace!("sock_getpeeraddr {fd}");
333
334 let s = ctx.vfs.get_mut_socket(fd as usize)?;
335
336 let wasi_addr = *(mem.mut_data(wasi_addr_ptr)?);
337 let addr = s.get_peer()?;
338
339 let addr_len: u32 = match addr {
340 SocketAddr::V4(addrv4) => {
341 let wasi_addr_buf_ptr = WasmPtr::<u8>::from(wasi_addr.buf as usize);
342 let wasi_addr_buf = mem.mut_slice(wasi_addr_buf_ptr, 4)?;
343 wasi_addr_buf.copy_from_slice(&addrv4.ip().octets());
344 mem.write_data(port_ptr, (addrv4.port() as u32).to_le())?;
345 4
346 }
347 SocketAddr::V6(addrv6) => {
348 let wasi_addr_buf_ptr = WasmPtr::<u8>::from(wasi_addr.buf as usize);
349 let wasi_addr_buf = mem.mut_slice(wasi_addr_buf_ptr, 16)?;
350 wasi_addr_buf.copy_from_slice(&addrv6.ip().octets());
351 mem.write_data(port_ptr, (addrv6.port() as u32).to_le())?;
352 16
353 }
354 };
355
356 let wasi_addr = mem.mut_data(wasi_addr_ptr)?;
357 wasi_addr.buf_len = addr_len.to_le();
358 mem.write_data(addr_type, addr_len.to_le())?;
359
360 Ok(())
361}
362
363pub fn sock_getlocaladdr<M: Memory>(
364 ctx: &mut WasiCtx,
365 mem: &mut M,
366 fd: __wasi_fd_t,
367 wasi_addr_ptr: WasmPtr<__wasi_address_t>,
368 addr_type: WasmPtr<u32>,
369 port_ptr: WasmPtr<u32>,
370) -> Result<(), Errno> {
371 log::trace!("sock_getlocaladdr {fd}");
372
373 let s = ctx.vfs.get_mut_socket(fd as usize)?;
374
375 let wasi_addr = *(mem.mut_data(wasi_addr_ptr)?);
376
377 let addr = s.get_local()?;
378
379 let addr_len: u32 = match addr {
380 SocketAddr::V4(addrv4) => {
381 let wasi_addr_buf_ptr = WasmPtr::<u8>::from(wasi_addr.buf as usize);
382 let wasi_addr_buf = mem.mut_slice(wasi_addr_buf_ptr, 4)?;
383 wasi_addr_buf.copy_from_slice(&addrv4.ip().octets());
384 mem.write_data(port_ptr, (addrv4.port() as u32).to_le())?;
385 4
386 }
387 SocketAddr::V6(addrv6) => {
388 let wasi_addr_buf_ptr = WasmPtr::<u8>::from(wasi_addr.buf as usize);
389 let wasi_addr_buf = mem.mut_slice(wasi_addr_buf_ptr, 16)?;
390 wasi_addr_buf.copy_from_slice(&addrv6.ip().octets());
391 mem.write_data(port_ptr, (addrv6.port() as u32).to_le())?;
392 16
393 }
394 };
395
396 let wasi_addr = mem.mut_data(wasi_addr_ptr)?;
397 wasi_addr.buf_len = addr_len.to_le();
398 mem.write_data(addr_type, addr_len.to_le())?;
399
400 Ok(())
401}
402
403pub fn sock_getsockopt<M: Memory>(
404 ctx: &mut WasiCtx,
405 mem: &mut M,
406 fd: __wasi_fd_t,
407 level: __wasi_sock_opt_level_t::Type,
408 name: __wasi_sock_opt_so_t::Type,
409 flag: WasmPtr<i32>,
410 flag_size_ptr: WasmPtr<__wasi_size_t>,
411) -> Result<(), Errno> {
412 log::trace!("sock_getsockopt {fd}");
413
414 let s = ctx.vfs.get_mut_socket(fd as usize)?;
415
416 let flag_size = *(mem.get_data(flag_size_ptr)?);
417 if level != __wasi_sock_opt_level_t::__WASI_SOCK_OPT_LEVEL_SOL_SOCKET {
418 return Err(Errno::__WASI_ERRNO_NOSYS);
419 }
420 let flag_val = match name {
421 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_REUSEADDR => {
422 if (flag_size as usize) != std::mem::size_of::<i32>() {
423 return Err(Errno::__WASI_ERRNO_INVAL);
424 }
425 s.get_so_reuseaddr() as i32
426 }
427 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_TYPE => {
428 if (flag_size as usize) != std::mem::size_of::<i32>() {
429 return Err(Errno::__WASI_ERRNO_INVAL);
430 }
431
432 let (_, t) = s.get_so_type();
433 match t {
434 SocketType::Datagram => __wasi_sock_type_t::__WASI_SOCK_TYPE_SOCK_DGRAM as i32,
435 SocketType::Stream => __wasi_sock_type_t::__WASI_SOCK_TYPE_SOCK_STREAM as i32,
436 }
437 }
438 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_ERROR => {
439 if let Some(e) = s.get_so_error()? {
440 Errno::from(e).0 as i32
441 } else {
442 0
443 }
444 }
445 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_DONTROUTE => {
446 return Err(Errno::__WASI_ERRNO_NOSYS);
447 }
448 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_BROADCAST => {
449 return Err(Errno::__WASI_ERRNO_NOSYS);
450 }
451 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_SNDBUF => {
452 if (flag_size as usize) != std::mem::size_of::<i32>() {
453 return Err(Errno::__WASI_ERRNO_INVAL);
454 }
455 s.get_so_send_buf_size() as i32
456 }
457 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_RCVBUF => {
458 if (flag_size as usize) != std::mem::size_of::<i32>() {
459 return Err(Errno::__WASI_ERRNO_INVAL);
460 }
461 s.get_so_recv_buf_size() as i32
462 }
463 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_KEEPALIVE => {
464 return Err(Errno::__WASI_ERRNO_NOSYS);
465 }
466 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_OOBINLINE => {
467 return Err(Errno::__WASI_ERRNO_NOSYS);
468 }
469 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_LINGER => {
470 return Err(Errno::__WASI_ERRNO_NOSYS);
471 }
472 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_RCVLOWAT => {
473 return Err(Errno::__WASI_ERRNO_NOSYS);
474 }
475 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_RCVTIMEO => {
476 if (flag_size as usize) != std::mem::size_of::<__wasi_timeval>() {
477 return Err(Errno::__WASI_ERRNO_INVAL);
478 }
479
480 let timeval = if let Some(timeout) = s.get_so_recv_timeout() {
481 __wasi_timeval {
482 tv_sec: (timeout.as_secs() as i64).to_le(),
483 tv_usec: (timeout.subsec_nanos() as i64).to_le(),
484 }
485 } else {
486 __wasi_timeval {
487 tv_sec: 0,
488 tv_usec: 0,
489 }
490 };
491
492 let offset = WasmPtr::<__wasi_timeval>::from(flag.0);
493 mem.write_data(offset, timeval)?;
494
495 return Ok(());
496 }
497 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_SNDTIMEO => {
498 if (flag_size as usize) != std::mem::size_of::<__wasi_timeval>() {
499 return Err(Errno::__WASI_ERRNO_INVAL);
500 }
501
502 let timeval = if let Some(timeout) = s.get_so_send_timeout() {
503 __wasi_timeval {
504 tv_sec: (timeout.as_secs() as i64).to_le(),
505 tv_usec: (timeout.subsec_nanos() as i64).to_le(),
506 }
507 } else {
508 __wasi_timeval {
509 tv_sec: 0,
510 tv_usec: 0,
511 }
512 };
513
514 let offset = WasmPtr::<__wasi_timeval>::from(flag.0);
515 mem.write_data(offset, timeval)?;
516
517 return Ok(());
518 }
519 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_ACCEPTCONN => {
520 if (flag_size as usize) != std::mem::size_of::<i32>() {
521 return Err(Errno::__WASI_ERRNO_INVAL);
522 }
523 s.get_so_accept_conn()? as i32
524 }
525 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_BINDTODEVICE => {
526 let device = s.device()?.unwrap_or_default();
527 let offset = WasmPtr::<u8>::from(flag.0);
528 let copy_len = device.len().min((flag_size.wrapping_sub(1)) as usize);
529 if copy_len > 0 {
530 let wasm_buf = mem.mut_slice(offset, copy_len)?;
531 wasm_buf.copy_from_slice(&device[0..copy_len]);
532 mem.write_data(flag_size_ptr, (copy_len + 1) as u32)?;
533 } else {
534 mem.write_data(flag_size_ptr, 0_u32)?;
535 }
536 return Ok(());
537 }
538 _ => {
539 return Err(Errno::__WASI_ERRNO_NOPROTOOPT);
540 }
541 };
542
543 mem.write_data(flag, flag_val)?;
544
545 Ok(())
546}
547
548pub fn sock_setsockopt<M: Memory>(
549 ctx: &mut WasiCtx,
550 mem: &M,
551 fd: __wasi_fd_t,
552 level: __wasi_sock_opt_level_t::Type,
553 name: __wasi_sock_opt_so_t::Type,
554 flag: WasmPtr<i32>,
555 flag_size: __wasi_size_t,
556) -> Result<(), Errno> {
557 log::trace!("sock_setsockopt {fd}");
558
559 let s = ctx.vfs.get_mut_socket(fd as usize)?;
560
561 if level != __wasi_sock_opt_level_t::__WASI_SOCK_OPT_LEVEL_SOL_SOCKET {
562 return Err(Errno::__WASI_ERRNO_NOSYS);
563 }
564
565 match name {
566 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_REUSEADDR => {
567 if (flag_size as usize) != std::mem::size_of::<i32>() {
568 return Err(Errno::__WASI_ERRNO_INVAL);
569 }
570 let flag_val = *(mem.get_data(flag)?) > 0;
571 s.set_so_reuseaddr(flag_val)?;
572 }
573 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_TYPE => return Err(Errno::__WASI_ERRNO_FAULT),
574 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_ERROR => return Err(Errno::__WASI_ERRNO_FAULT),
575 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_DONTROUTE => {
576 return Err(Errno::__WASI_ERRNO_NOSYS);
577 }
578 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_BROADCAST => {
579 return Err(Errno::__WASI_ERRNO_NOSYS);
580 }
581 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_SNDBUF => {
582 if (flag_size as usize) != std::mem::size_of::<i32>() {
583 return Err(Errno::__WASI_ERRNO_INVAL);
584 }
585 let flag_val = *(mem.get_data(flag)?);
586 s.set_so_send_buf_size(flag_val as usize)?;
587 }
588 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_RCVBUF => {
589 if (flag_size as usize) != std::mem::size_of::<i32>() {
590 return Err(Errno::__WASI_ERRNO_INVAL);
591 }
592 let flag_val = *(mem.get_data(flag)?);
593 s.set_so_recv_buf_size(flag_val as usize)?;
594 }
595 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_KEEPALIVE => {
596 return Err(Errno::__WASI_ERRNO_NOSYS);
597 }
598 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_OOBINLINE => {
599 return Err(Errno::__WASI_ERRNO_NOSYS);
600 }
601 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_LINGER => {
602 return Err(Errno::__WASI_ERRNO_NOSYS);
603 }
604 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_RCVLOWAT => {
605 return Err(Errno::__WASI_ERRNO_NOSYS);
606 }
607 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_RCVTIMEO => {
608 if (flag_size as usize) != std::mem::size_of::<__wasi_timeval>() {
609 return Err(Errno::__WASI_ERRNO_INVAL);
610 }
611 let offset = WasmPtr::<__wasi_timeval>::from(flag.0);
612 let timeval = *(mem.get_data(offset)?);
613 let (tv_sec, tv_usec) = (i64::from_le(timeval.tv_sec), i64::from_le(timeval.tv_usec));
614
615 let timeout = if tv_sec == 0 && tv_usec == 0 {
616 None
617 } else {
618 Some(std::time::Duration::new(tv_sec as u64, tv_usec as u32))
619 };
620
621 s.set_so_recv_timeout(timeout)?;
622 }
623 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_SNDTIMEO => {
624 if (flag_size as usize) != std::mem::size_of::<__wasi_timeval>() {
625 return Err(Errno::__WASI_ERRNO_INVAL);
626 }
627 let offset = WasmPtr::<__wasi_timeval>::from(flag.0);
628 let timeval = *(mem.get_data(offset)?);
629 let (tv_sec, tv_usec) = (i64::from_le(timeval.tv_sec), i64::from_le(timeval.tv_usec));
630
631 let timeout = if tv_sec == 0 && tv_usec == 0 {
632 None
633 } else {
634 Some(std::time::Duration::new(tv_sec as u64, tv_usec as u32))
635 };
636
637 s.set_so_send_timeout(timeout)?;
638 }
639 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_ACCEPTCONN => {
640 return Err(Errno::__WASI_ERRNO_FAULT);
641 }
642 __wasi_sock_opt_so_t::__WASI_SOCK_OPT_SO_BINDTODEVICE => {
643 if flag_size == 0 {
644 s.bind_device(None)?;
645 } else {
646 let buf_ptr = WasmPtr::<u8>::from(flag.0);
647 let wasm_buf = mem.get_slice(buf_ptr, flag_size as usize)?;
648 s.bind_device(Some(wasm_buf))?;
649 }
650 return Ok(());
651 }
652 _ => {
653 return Err(Errno::__WASI_ERRNO_NOPROTOOPT);
654 }
655 };
656
657 Ok(())
658}
659
660pub async fn sock_lookup_ip<M: Memory>(
661 _ctx: &mut WasiCtx,
662 mem: &mut M,
663 host_name_ptr: WasmPtr<u8>,
664 host_name_len: __wasi_size_t,
665 lookup_type: __wasi_address_family_t::Type,
666 addr_buf: WasmPtr<u8>,
667 addr_buf_max_len: __wasi_size_t,
668 raddr_num_ptr: WasmPtr<__wasi_size_t>,
669) -> Result<(), Errno> {
670 log::trace!("sock_lookup_ip");
671
672 match lookup_type {
673 __wasi_address_family_t::__WASI_ADDRESS_FAMILY_INET4 => {
674 let host_name_buf = mem.get_slice(host_name_ptr, host_name_len as usize)?;
675 let host_name =
676 std::str::from_utf8(host_name_buf).or(Err(Errno::__WASI_ERRNO_ILSEQ))?;
677 let addrs = tokio::net::lookup_host(format!("{host_name}:0")).await?;
678 let write_buf = mem.mut_slice(addr_buf, addr_buf_max_len as usize)?;
679 let mut i = 0;
680 for addr in addrs {
681 if let SocketAddr::V4(ip) = addr {
682 let buf = ip.ip().octets();
683 if let Some(w_buf) = write_buf.get_mut(i * 4..(i + 1) * 4) {
684 w_buf.copy_from_slice(&buf);
685 i += 1;
686 } else {
687 break;
688 }
689 }
690 }
691 mem.write_data(raddr_num_ptr, i as u32)?;
692 Ok(())
693 }
694 __wasi_address_family_t::__WASI_ADDRESS_FAMILY_INET6 => {
695 let host_name_buf = mem.get_slice(host_name_ptr, host_name_len as usize)?;
696 let host_name =
697 std::str::from_utf8(host_name_buf).or(Err(Errno::__WASI_ERRNO_ILSEQ))?;
698 let addrs = tokio::net::lookup_host(format!("{host_name}:0")).await?;
699 let write_buf = mem.mut_slice(addr_buf, addr_buf_max_len as usize)?;
700 let mut i = 0;
701 for addr in addrs {
702 if let SocketAddr::V6(ip) = addr {
703 let buf = ip.ip().octets();
704 if let Some(w_buf) = write_buf.get_mut(i * 16..(i + 1) * 16) {
705 w_buf.copy_from_slice(&buf);
706 i += 1;
707 } else {
708 break;
709 }
710 }
711 }
712 mem.write_data(raddr_num_ptr, i as u32)?;
713 Ok(())
714 }
715 _ => Err(Errno::__WASI_ERRNO_INVAL),
716 }
717}
718
719pub mod addrinfo {
720 use crate::snapshots::{
721 common::memory::{Memory, WasmPtr},
722 env::Errno,
723 WasiCtx,
724 };
725
726 #[allow(dead_code)]
727 #[derive(Copy, Clone, Debug)]
728 #[repr(u8, align(1))]
729 pub enum AddressFamily {
730 Unspec,
731 Inet4,
732 Inet6,
733 }
734
735 #[derive(Debug, Clone)]
736 #[repr(C)]
737 pub struct WasiSockaddr {
738 pub family: AddressFamily,
739 pub sa_data_len: u32,
740 pub sa_data: u32, }
742
743 #[derive(Debug, Clone)]
744 #[repr(C, packed(4))]
745 pub struct WasiAddrinfo {
746 pub ai_flags: u16,
747 pub ai_family: AddressFamily,
748 pub ai_socktype: u8,
749 pub ai_protocol: u8,
750 pub ai_addrlen: u32,
751 pub ai_addr: u32, pub ai_canonname: u32, pub ai_canonnamelen: u32,
754 pub ai_next: u32, }
756
757 pub fn sock_getaddrinfo<M: Memory>(
758 _ctx: &mut WasiCtx,
759 mem: &mut M,
760 node: WasmPtr<u8>,
761 node_len: u32,
762 _server: WasmPtr<u8>,
763 _server_len: u32,
764 _hint: WasmPtr<()>,
765 res: WasmPtr<u32>, max_len: u32,
767 res_len: WasmPtr<u32>,
768 ) -> Result<(), Errno> {
769 use std::net::ToSocketAddrs;
770 if max_len == 0 {
771 return Err(Errno::__WASI_ERRNO_INVAL);
772 }
773 let node =
774 std::ffi::CString::from_vec_with_nul(mem.get_slice(node, node_len as usize)?.to_vec())
775 .unwrap_or_default();
776 let node = node.to_str().unwrap_or_default();
777
778 let addr = if node.is_empty() {
779 None
780 } else {
781 (node, 0).to_socket_addrs()?.find(|addr| addr.is_ipv4())
782 };
783
784 if let Some(std::net::SocketAddr::V4(ipv4)) = addr {
785 let addr_info_ptr = *mem.get_data(res)?;
786 let addr_info = mem.mut_data(WasmPtr::<WasiAddrinfo>::from(addr_info_ptr as usize))?;
787
788 addr_info.ai_addrlen = 4;
789 let wasi_addr_ptr: WasmPtr<WasiSockaddr> = (addr_info.ai_addr as usize).into();
790 let wasi_addr = mem.mut_data(wasi_addr_ptr)?;
791 wasi_addr.family = AddressFamily::Inet4;
792 let sa_data_ptr: WasmPtr<u8> = (wasi_addr.sa_data as usize).into();
793 let sa_data_len = wasi_addr.sa_data_len;
794 let sa_data = mem.mut_slice(sa_data_ptr, sa_data_len as usize)?;
795 let port_buf = ipv4.port().to_be_bytes();
796 sa_data[0] = port_buf[0];
797 sa_data[1] = port_buf[1];
798 let ip = ipv4.ip().octets();
799 sa_data[2..6].copy_from_slice(&ip);
800 mem.write_data(res_len, 1)?;
801 } else {
802 mem.write_data(res_len, 0)?;
803 }
804
805 Ok(())
806 }
807}