wasmtime_wasi/p2/host/
network.rs

1use crate::p2::SocketError;
2use crate::p2::bindings::sockets::network::{
3    self, ErrorCode, IpAddress, IpAddressFamily, IpSocketAddress, Ipv4SocketAddress,
4    Ipv6SocketAddress,
5};
6use crate::sockets::WasiSocketsCtxView;
7use crate::sockets::util::{from_ipv4_addr, from_ipv6_addr, to_ipv4_addr, to_ipv6_addr};
8use anyhow::Error;
9use rustix::io::Errno;
10use std::io;
11use wasmtime::component::Resource;
12
13impl network::Host for WasiSocketsCtxView<'_> {
14    fn convert_error_code(&mut self, error: SocketError) -> anyhow::Result<ErrorCode> {
15        error.downcast()
16    }
17
18    fn network_error_code(&mut self, err: Resource<Error>) -> anyhow::Result<Option<ErrorCode>> {
19        let err = self.table.get(&err)?;
20
21        if let Some(err) = err.downcast_ref::<std::io::Error>() {
22            return Ok(Some(ErrorCode::from(err)));
23        }
24
25        Ok(None)
26    }
27}
28
29impl crate::p2::bindings::sockets::network::HostNetwork for WasiSocketsCtxView<'_> {
30    fn drop(&mut self, this: Resource<network::Network>) -> Result<(), anyhow::Error> {
31        self.table.delete(this)?;
32
33        Ok(())
34    }
35}
36
37impl From<io::Error> for ErrorCode {
38    fn from(value: io::Error) -> Self {
39        (&value).into()
40    }
41}
42
43impl From<&io::Error> for ErrorCode {
44    fn from(value: &io::Error) -> Self {
45        // Attempt the more detailed native error code first:
46        if let Some(errno) = Errno::from_io_error(value) {
47            return errno.into();
48        }
49
50        match value.kind() {
51            std::io::ErrorKind::AddrInUse => ErrorCode::AddressInUse,
52            std::io::ErrorKind::AddrNotAvailable => ErrorCode::AddressNotBindable,
53            std::io::ErrorKind::ConnectionAborted => ErrorCode::ConnectionAborted,
54            std::io::ErrorKind::ConnectionRefused => ErrorCode::ConnectionRefused,
55            std::io::ErrorKind::ConnectionReset => ErrorCode::ConnectionReset,
56            std::io::ErrorKind::Interrupted => ErrorCode::WouldBlock,
57            std::io::ErrorKind::InvalidInput => ErrorCode::InvalidArgument,
58            std::io::ErrorKind::NotConnected => ErrorCode::InvalidState,
59            std::io::ErrorKind::OutOfMemory => ErrorCode::OutOfMemory,
60            std::io::ErrorKind::PermissionDenied => ErrorCode::AccessDenied,
61            std::io::ErrorKind::TimedOut => ErrorCode::Timeout,
62            std::io::ErrorKind::Unsupported => ErrorCode::NotSupported,
63            std::io::ErrorKind::WouldBlock => ErrorCode::WouldBlock,
64
65            _ => {
66                tracing::debug!("unknown I/O error: {value}");
67                ErrorCode::Unknown
68            }
69        }
70    }
71}
72
73impl From<Errno> for ErrorCode {
74    fn from(value: Errno) -> Self {
75        (&value).into()
76    }
77}
78
79impl From<&Errno> for ErrorCode {
80    fn from(value: &Errno) -> Self {
81        match *value {
82            Errno::WOULDBLOCK => ErrorCode::WouldBlock,
83            #[allow(
84                unreachable_patterns,
85                reason = "EWOULDBLOCK and EAGAIN can have the same value"
86            )]
87            Errno::AGAIN => ErrorCode::WouldBlock,
88            Errno::INTR => ErrorCode::WouldBlock,
89            #[cfg(not(windows))]
90            Errno::PERM => ErrorCode::AccessDenied,
91            Errno::ACCESS => ErrorCode::AccessDenied,
92            Errno::ADDRINUSE => ErrorCode::AddressInUse,
93            Errno::ADDRNOTAVAIL => ErrorCode::AddressNotBindable,
94            Errno::ALREADY => ErrorCode::ConcurrencyConflict,
95            Errno::TIMEDOUT => ErrorCode::Timeout,
96            Errno::CONNREFUSED => ErrorCode::ConnectionRefused,
97            Errno::CONNRESET => ErrorCode::ConnectionReset,
98            Errno::CONNABORTED => ErrorCode::ConnectionAborted,
99            Errno::INVAL => ErrorCode::InvalidArgument,
100            Errno::HOSTUNREACH => ErrorCode::RemoteUnreachable,
101            Errno::HOSTDOWN => ErrorCode::RemoteUnreachable,
102            Errno::NETDOWN => ErrorCode::RemoteUnreachable,
103            Errno::NETUNREACH => ErrorCode::RemoteUnreachable,
104            #[cfg(target_os = "linux")]
105            Errno::NONET => ErrorCode::RemoteUnreachable,
106            Errno::ISCONN => ErrorCode::InvalidState,
107            Errno::NOTCONN => ErrorCode::InvalidState,
108            Errno::DESTADDRREQ => ErrorCode::InvalidState,
109            #[cfg(not(windows))]
110            Errno::NFILE => ErrorCode::NewSocketLimit,
111            Errno::MFILE => ErrorCode::NewSocketLimit,
112            Errno::MSGSIZE => ErrorCode::DatagramTooLarge,
113            #[cfg(not(windows))]
114            Errno::NOMEM => ErrorCode::OutOfMemory,
115            Errno::NOBUFS => ErrorCode::OutOfMemory,
116            Errno::OPNOTSUPP => ErrorCode::NotSupported,
117            Errno::NOPROTOOPT => ErrorCode::NotSupported,
118            Errno::PFNOSUPPORT => ErrorCode::NotSupported,
119            Errno::PROTONOSUPPORT => ErrorCode::NotSupported,
120            Errno::PROTOTYPE => ErrorCode::NotSupported,
121            Errno::SOCKTNOSUPPORT => ErrorCode::NotSupported,
122            Errno::AFNOSUPPORT => ErrorCode::NotSupported,
123
124            // FYI, EINPROGRESS should have already been handled by connect.
125            _ => {
126                tracing::debug!("unknown I/O error: {value}");
127                ErrorCode::Unknown
128            }
129        }
130    }
131}
132
133impl From<std::net::IpAddr> for IpAddress {
134    fn from(addr: std::net::IpAddr) -> Self {
135        match addr {
136            std::net::IpAddr::V4(v4) => Self::Ipv4(from_ipv4_addr(v4)),
137            std::net::IpAddr::V6(v6) => Self::Ipv6(from_ipv6_addr(v6)),
138        }
139    }
140}
141
142impl From<IpSocketAddress> for std::net::SocketAddr {
143    fn from(addr: IpSocketAddress) -> Self {
144        match addr {
145            IpSocketAddress::Ipv4(ipv4) => Self::V4(ipv4.into()),
146            IpSocketAddress::Ipv6(ipv6) => Self::V6(ipv6.into()),
147        }
148    }
149}
150
151impl From<std::net::SocketAddr> for IpSocketAddress {
152    fn from(addr: std::net::SocketAddr) -> Self {
153        match addr {
154            std::net::SocketAddr::V4(v4) => Self::Ipv4(v4.into()),
155            std::net::SocketAddr::V6(v6) => Self::Ipv6(v6.into()),
156        }
157    }
158}
159
160impl From<Ipv4SocketAddress> for std::net::SocketAddrV4 {
161    fn from(addr: Ipv4SocketAddress) -> Self {
162        Self::new(to_ipv4_addr(addr.address), addr.port)
163    }
164}
165
166impl From<std::net::SocketAddrV4> for Ipv4SocketAddress {
167    fn from(addr: std::net::SocketAddrV4) -> Self {
168        Self {
169            address: from_ipv4_addr(*addr.ip()),
170            port: addr.port(),
171        }
172    }
173}
174
175impl From<Ipv6SocketAddress> for std::net::SocketAddrV6 {
176    fn from(addr: Ipv6SocketAddress) -> Self {
177        Self::new(
178            to_ipv6_addr(addr.address),
179            addr.port,
180            addr.flow_info,
181            addr.scope_id,
182        )
183    }
184}
185
186impl From<std::net::SocketAddrV6> for Ipv6SocketAddress {
187    fn from(addr: std::net::SocketAddrV6) -> Self {
188        Self {
189            address: from_ipv6_addr(*addr.ip()),
190            port: addr.port(),
191            flow_info: addr.flowinfo(),
192            scope_id: addr.scope_id(),
193        }
194    }
195}
196
197impl std::net::ToSocketAddrs for IpSocketAddress {
198    type Iter = <std::net::SocketAddr as std::net::ToSocketAddrs>::Iter;
199
200    fn to_socket_addrs(&self) -> io::Result<Self::Iter> {
201        std::net::SocketAddr::from(*self).to_socket_addrs()
202    }
203}
204
205impl std::net::ToSocketAddrs for Ipv4SocketAddress {
206    type Iter = <std::net::SocketAddrV4 as std::net::ToSocketAddrs>::Iter;
207
208    fn to_socket_addrs(&self) -> io::Result<Self::Iter> {
209        std::net::SocketAddrV4::from(*self).to_socket_addrs()
210    }
211}
212
213impl std::net::ToSocketAddrs for Ipv6SocketAddress {
214    type Iter = <std::net::SocketAddrV6 as std::net::ToSocketAddrs>::Iter;
215
216    fn to_socket_addrs(&self) -> io::Result<Self::Iter> {
217        std::net::SocketAddrV6::from(*self).to_socket_addrs()
218    }
219}
220
221impl From<IpAddressFamily> for cap_net_ext::AddressFamily {
222    fn from(family: IpAddressFamily) -> Self {
223        match family {
224            IpAddressFamily::Ipv4 => cap_net_ext::AddressFamily::Ipv4,
225            IpAddressFamily::Ipv6 => cap_net_ext::AddressFamily::Ipv6,
226        }
227    }
228}
229
230impl From<cap_net_ext::AddressFamily> for IpAddressFamily {
231    fn from(family: cap_net_ext::AddressFamily) -> Self {
232        match family {
233            cap_net_ext::AddressFamily::Ipv4 => IpAddressFamily::Ipv4,
234            cap_net_ext::AddressFamily::Ipv6 => IpAddressFamily::Ipv6,
235        }
236    }
237}