wasmer_wasix/syscalls/wasix/
sock_accept.rs

1use std::task::Waker;
2
3use super::*;
4use crate::{net::socket::TimeType, syscalls::*};
5
6/// ### `sock_accept()`
7/// Accept a new incoming connection.
8/// Note: This is similar to `accept` in POSIX.
9///
10/// ## Parameters
11///
12/// * `fd` - The listening socket.
13/// * `flags` - The desired values of the file descriptor flags.
14///
15/// ## Return
16///
17/// New socket connection
18#[instrument(level = "trace", skip_all, fields(%sock, fd = field::Empty), ret)]
19pub fn sock_accept<M: MemorySize>(
20    mut ctx: FunctionEnvMut<'_, WasiEnv>,
21    sock: WasiFd,
22    fd_flags: Fdflags,
23    ro_fd: WasmPtr<WasiFd, M>,
24) -> Result<Errno, WasiError> {
25    WasiEnv::do_pending_operations(&mut ctx)?;
26
27    ctx = wasi_try_ok!(maybe_snapshot::<M>(ctx)?);
28
29    let env = ctx.data();
30    let (memory, state, _) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) };
31
32    let nonblocking = fd_flags.contains(Fdflags::NONBLOCK);
33
34    let (fd, _, _) = wasi_try_ok!(sock_accept_internal(
35        env,
36        sock,
37        fd_flags,
38        nonblocking,
39        None
40    )?);
41
42    wasi_try_mem_ok!(ro_fd.write(&memory, fd));
43
44    Ok(Errno::Success)
45}
46
47/// ### `sock_accept_v2()`
48/// Accept a new incoming connection.
49/// Note: This is similar to `accept` in POSIX.
50///
51/// ## Parameters
52///
53/// * `fd` - The listening socket.
54/// * `flags` - The desired values of the file descriptor flags.
55/// * `ro_addr` - Returns the address and port of the client
56///
57/// ## Return
58///
59/// New socket connection
60#[instrument(level = "trace", skip_all, fields(%sock, fd = field::Empty), ret)]
61pub fn sock_accept_v2<M: MemorySize>(
62    mut ctx: FunctionEnvMut<'_, WasiEnv>,
63    sock: WasiFd,
64    fd_flags: Fdflags,
65    ro_fd: WasmPtr<WasiFd, M>,
66    ro_addr: WasmPtr<__wasi_addr_port_t, M>,
67) -> Result<Errno, WasiError> {
68    WasiEnv::do_pending_operations(&mut ctx)?;
69
70    let env = ctx.data();
71    let (memory, state, _) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) };
72
73    let nonblocking = fd_flags.contains(Fdflags::NONBLOCK);
74
75    let (fd, local_addr, peer_addr) = wasi_try_ok!(sock_accept_internal(
76        env,
77        sock,
78        fd_flags,
79        nonblocking,
80        None
81    )?);
82
83    #[cfg(feature = "journal")]
84    if ctx.data().enable_journal {
85        JournalEffector::save_sock_accepted(
86            &mut ctx,
87            sock,
88            fd,
89            local_addr,
90            peer_addr,
91            fd_flags,
92            nonblocking,
93        )
94        .map_err(|err| {
95            tracing::error!("failed to save sock_accepted event - {}", err);
96            WasiError::Exit(ExitCode::from(Errno::Fault))
97        })?;
98    }
99
100    let env = ctx.data();
101    let (memory, state, _) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) };
102    wasi_try_mem_ok!(ro_fd.write(&memory, fd));
103    wasi_try_ok!(crate::net::write_ip_port(
104        &memory,
105        ro_addr,
106        peer_addr.ip(),
107        peer_addr.port()
108    ));
109
110    Ok(Errno::Success)
111}
112
113pub(crate) fn sock_accept_internal(
114    env: &WasiEnv,
115    sock: WasiFd,
116    mut fd_flags: Fdflags,
117    mut nonblocking: bool,
118    with_fd: Option<WasiFd>,
119) -> Result<Result<(WasiFd, SocketAddr, SocketAddr), Errno>, WasiError> {
120    let state = env.state();
121    let inodes = &state.inodes;
122
123    let tasks = env.tasks().clone();
124    let (child, local_addr, peer_addr, fd_flags) = wasi_try_ok_ok!(__sock_asyncify(
125        env,
126        sock,
127        Rights::SOCK_ACCEPT,
128        move |socket, fd| async move {
129            if fd.inner.flags.contains(Fdflags::NONBLOCK) {
130                fd_flags.set(Fdflags::NONBLOCK, true);
131                nonblocking = true;
132            }
133            let timeout = socket
134                .opt_time(TimeType::AcceptTimeout)
135                .ok()
136                .flatten()
137                .unwrap_or(Duration::from_secs(30));
138            let local_addr = socket.addr_local()?;
139            socket
140                .accept(tasks.deref(), nonblocking, Some(timeout))
141                .await
142                .map(|a| (a.0, local_addr, a.1, fd_flags))
143        },
144    ));
145
146    let kind = Kind::Socket {
147        socket: InodeSocket::new(InodeSocketKind::TcpStream {
148            socket: child,
149            write_timeout: None,
150            read_timeout: None,
151        }),
152    };
153    let inode = state
154        .fs
155        .create_inode_with_default_stat(inodes, kind, false, "socket".into());
156
157    let mut new_flags = Fdflags::empty();
158    if fd_flags.contains(Fdflags::NONBLOCK) {
159        new_flags.set(Fdflags::NONBLOCK, true);
160    }
161
162    let mut new_flags = Fdflags::empty();
163    if fd_flags.contains(Fdflags::NONBLOCK) {
164        new_flags.set(Fdflags::NONBLOCK, true);
165    }
166
167    let rights = Rights::all_socket();
168    let fd = wasi_try_ok_ok!(if let Some(fd) = with_fd {
169        state
170            .fs
171            .with_fd(rights, rights, new_flags, Fdflagsext::empty(), 0, inode, fd)
172            .map(|_| fd)
173    } else {
174        state
175            .fs
176            .create_fd(rights, rights, new_flags, Fdflagsext::empty(), 0, inode)
177    });
178    Span::current().record("fd", fd);
179
180    Ok(Ok((fd, local_addr, peer_addr)))
181}