Skip to main content

async_wasi/snapshots/common/net/
mod.rs

1#[cfg(all(unix, feature = "async_tokio"))]
2pub mod async_tokio;
3
4pub use super::vfs::*;
5
6use super::{
7    error::Errno,
8    types::{self as wasi_types, __wasi_subscription_t},
9};
10use std::{
11    future::Future,
12    io::{self, Read, Write},
13    net,
14    time::{Duration, SystemTime},
15};
16use wasi_types::{
17    __wasi_clockid_t::{
18        __WASI_CLOCKID_MONOTONIC as CLOCKID_MONOTONIC, __WASI_CLOCKID_REALTIME as CLOCKID_REALTIME,
19    },
20    __wasi_eventtype_t::{
21        __WASI_EVENTTYPE_CLOCK as CLOCK, __WASI_EVENTTYPE_FD_READ as RD,
22        __WASI_EVENTTYPE_FD_WRITE as WR,
23    },
24};
25
26#[derive(Debug, Clone, Copy, Default)]
27pub enum AddressFamily {
28    #[default]
29    Inet4,
30    Inet6,
31}
32
33#[derive(Debug, Clone, Copy, Default)]
34pub enum SocketType {
35    Datagram,
36    #[default]
37    Stream,
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
41pub enum ConnectState {
42    #[default]
43    Empty,
44    Listening,
45    Connected,
46    Connecting,
47}
48
49#[derive(Debug, Clone, Default)]
50pub struct WasiSocketState {
51    pub sock_type: (AddressFamily, SocketType),
52    pub local_addr: Option<net::SocketAddr>,
53    pub peer_addr: Option<net::SocketAddr>,
54    pub bind_device: Vec<u8>,
55    pub backlog: u32,
56    pub shutdown: Option<net::Shutdown>,
57    pub nonblocking: bool,
58    pub so_reuseaddr: bool,
59    pub so_conn_state: ConnectState,
60    pub so_recv_buf_size: usize,
61    pub so_send_buf_size: usize,
62    pub so_recv_timeout: Option<Duration>,
63    pub so_send_timeout: Option<Duration>,
64    pub fs_rights: WASIRights,
65}
66
67#[derive(Debug, Clone, Copy)]
68pub enum SubscriptionFdType {
69    Read(wasi_types::__wasi_userdata_t),
70    Write(wasi_types::__wasi_userdata_t),
71    Both {
72        read: wasi_types::__wasi_userdata_t,
73        write: wasi_types::__wasi_userdata_t,
74    },
75}
76
77#[derive(Debug, Clone, Copy)]
78pub struct SubscriptionFd {
79    pub fd: wasi_types::__wasi_fd_t,
80    pub type_: SubscriptionFdType,
81}
82
83impl SubscriptionFd {
84    pub fn set_write(&mut self, userdata: wasi_types::__wasi_userdata_t) {
85        let read_userdata = match &mut self.type_ {
86            SubscriptionFdType::Read(v) => *v,
87            SubscriptionFdType::Write(v) => {
88                *v = userdata;
89                return;
90            }
91            SubscriptionFdType::Both { read, write } => {
92                *write = userdata;
93                return;
94            }
95        };
96        self.type_ = SubscriptionFdType::Both {
97            read: read_userdata,
98            write: userdata,
99        };
100    }
101
102    pub fn set_read(&mut self, userdata: wasi_types::__wasi_userdata_t) {
103        let write_userdata = match &mut self.type_ {
104            SubscriptionFdType::Write(v) => *v,
105            SubscriptionFdType::Read(v) => {
106                *v = userdata;
107                return;
108            }
109            SubscriptionFdType::Both { read, write } => {
110                *read = userdata;
111                return;
112            }
113        };
114        self.type_ = SubscriptionFdType::Both {
115            read: userdata,
116            write: write_userdata,
117        };
118    }
119}
120
121#[derive(Debug, Clone, Copy)]
122pub struct SubscriptionClock {
123    pub timeout: Option<SystemTime>,
124    pub userdata: wasi_types::__wasi_userdata_t,
125    pub err: Option<Errno>,
126}
127
128#[derive(Debug, Clone, Copy)]
129pub enum Subscription {
130    FD(SubscriptionFd),
131    RealClock(SubscriptionClock),
132}
133
134impl Subscription {
135    pub fn from(s: &__wasi_subscription_t) -> Result<Subscription, Errno> {
136        let userdata = s.userdata;
137        match s.u.tag {
138            CLOCK => {
139                let clock = unsafe { s.u.u.clock };
140                match clock.id {
141                    CLOCKID_REALTIME | CLOCKID_MONOTONIC => {
142                        if clock.flags == 1 {
143                            if let Some(ddl) = std::time::UNIX_EPOCH
144                                .checked_add(Duration::from_nanos(clock.timeout + clock.precision))
145                            {
146                                Ok(Subscription::RealClock(SubscriptionClock {
147                                    timeout: Some(ddl),
148                                    userdata,
149                                    err: None,
150                                }))
151                            } else {
152                                Ok(Subscription::RealClock(SubscriptionClock {
153                                    timeout: None,
154                                    userdata,
155                                    err: Some(Errno::__WASI_ERRNO_INVAL),
156                                }))
157                            }
158                        } else if clock.timeout == 0 {
159                            Ok(Subscription::RealClock(SubscriptionClock {
160                                timeout: None,
161                                userdata,
162                                err: None,
163                            }))
164                        } else {
165                            let duration = Duration::from_nanos(clock.timeout + clock.precision);
166
167                            let timeout = std::time::SystemTime::now().checked_add(duration);
168
169                            Ok(Subscription::RealClock(SubscriptionClock {
170                                timeout,
171                                userdata,
172                                err: None,
173                            }))
174                        }
175                    }
176
177                    _ => Ok(Subscription::RealClock(SubscriptionClock {
178                        timeout: None,
179                        userdata,
180                        err: Some(Errno::__WASI_ERRNO_NODEV),
181                    })),
182                }
183            }
184            RD => {
185                let fd_read = unsafe { s.u.u.fd_read };
186                Ok(Subscription::FD(SubscriptionFd {
187                    fd: fd_read.file_descriptor,
188                    type_: SubscriptionFdType::Read(userdata),
189                }))
190            }
191            WR => {
192                let fd_read = unsafe { s.u.u.fd_read };
193                Ok(Subscription::FD(SubscriptionFd {
194                    fd: fd_read.file_descriptor,
195                    type_: SubscriptionFdType::Write(userdata),
196                }))
197            }
198            _ => Err(Errno::__WASI_ERRNO_INVAL),
199        }
200    }
201}
202
203#[derive(Debug)]
204pub enum PrePoll {
205    OnlyFd(Vec<SubscriptionFd>),
206    OnlyClock(SubscriptionClock),
207    ClockAndFd(SubscriptionClock, Vec<SubscriptionFd>),
208}
209
210impl PrePoll {
211    pub fn from_wasi_subscription(
212        subs: &[wasi_types::__wasi_subscription_t],
213    ) -> Result<Self, Errno> {
214        use std::collections::HashMap;
215        let mut fds = HashMap::with_capacity(subs.len());
216
217        let mut timeout: Option<SubscriptionClock> = None;
218        for s in subs {
219            let s = Subscription::from(s)?;
220            match s {
221                Subscription::FD(fd) => {
222                    let type_ = fd.type_;
223
224                    fds.entry(fd.fd)
225                        .and_modify(|e: &mut SubscriptionFd| match type_ {
226                            SubscriptionFdType::Read(data) => e.set_read(data),
227                            SubscriptionFdType::Write(data) => e.set_write(data),
228                            SubscriptionFdType::Both { read, write } => {
229                                e.type_ = SubscriptionFdType::Both { read, write };
230                            }
231                        })
232                        .or_insert(fd);
233                }
234                Subscription::RealClock(clock) => {
235                    if clock.err.is_some() {
236                        return Ok(PrePoll::OnlyClock(clock));
237                    }
238                    if clock.timeout.is_none() {
239                        return Ok(PrePoll::OnlyClock(clock));
240                    }
241
242                    if let Some(old_clock) = &mut timeout {
243                        let new_timeout = clock.timeout.unwrap();
244                        let old_timeout = old_clock.timeout.unwrap();
245
246                        if new_timeout < old_timeout {
247                            *old_clock = clock
248                        }
249                    } else {
250                        timeout = Some(clock)
251                    }
252                }
253            }
254        }
255
256        let fd_vec: Vec<SubscriptionFd> = fds.into_values().collect();
257
258        if let Some(clock) = timeout {
259            if fd_vec.is_empty() {
260                Ok(PrePoll::OnlyClock(clock))
261            } else {
262                Ok(PrePoll::ClockAndFd(clock, fd_vec))
263            }
264        } else {
265            Ok(PrePoll::OnlyFd(fd_vec))
266        }
267    }
268}