async_wasi/snapshots/preview_1/
async_socket.rs

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, //*mut u8,
741    }
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,      //*mut WasiSockaddr,
752        pub ai_canonname: u32, //*mut u8,
753        pub ai_canonnamelen: u32,
754        pub ai_next: u32, //*mut WasiAddrinfo,
755    }
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>, // WasmPtr<WasmPtr<WasiAddrinfo>>
766        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}