1 use crate::p2::SocketError;
2 use crate::p2::bindings::sockets::network::{
3     self, ErrorCode, IpAddress, IpAddressFamily, IpSocketAddress, Ipv4SocketAddress,
4     Ipv6SocketAddress,
5 };
6 use crate::sockets::WasiSocketsCtxView;
7 use crate::sockets::util::{from_ipv4_addr, from_ipv6_addr, to_ipv4_addr, to_ipv6_addr};
8 use rustix::io::Errno;
9 use std::io;
10 use wasmtime::Error;
11 use wasmtime::component::Resource;
12 
13 impl network::Host for WasiSocketsCtxView<'_> {
convert_error_code(&mut self, error: SocketError) -> wasmtime::Result<ErrorCode>14     fn convert_error_code(&mut self, error: SocketError) -> wasmtime::Result<ErrorCode> {
15         error.downcast()
16     }
17 
network_error_code(&mut self, err: Resource<Error>) -> wasmtime::Result<Option<ErrorCode>>18     fn network_error_code(&mut self, err: Resource<Error>) -> wasmtime::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 
29 impl crate::p2::bindings::sockets::network::HostNetwork for WasiSocketsCtxView<'_> {
drop(&mut self, this: Resource<network::Network>) -> Result<(), wasmtime::Error>30     fn drop(&mut self, this: Resource<network::Network>) -> Result<(), wasmtime::Error> {
31         self.table.delete(this)?;
32 
33         Ok(())
34     }
35 }
36 
37 impl From<io::Error> for ErrorCode {
from(value: io::Error) -> Self38     fn from(value: io::Error) -> Self {
39         (&value).into()
40     }
41 }
42 
43 impl From<&io::Error> for ErrorCode {
from(value: &io::Error) -> Self44     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 
73 impl From<Errno> for ErrorCode {
from(value: Errno) -> Self74     fn from(value: Errno) -> Self {
75         (&value).into()
76     }
77 }
78 
79 impl From<&Errno> for ErrorCode {
from(value: &Errno) -> Self80     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 
133 impl From<std::net::IpAddr> for IpAddress {
from(addr: std::net::IpAddr) -> Self134     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 
142 impl From<IpSocketAddress> for std::net::SocketAddr {
from(addr: IpSocketAddress) -> Self143     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 
151 impl From<std::net::SocketAddr> for IpSocketAddress {
from(addr: std::net::SocketAddr) -> Self152     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 
160 impl From<Ipv4SocketAddress> for std::net::SocketAddrV4 {
from(addr: Ipv4SocketAddress) -> Self161     fn from(addr: Ipv4SocketAddress) -> Self {
162         Self::new(to_ipv4_addr(addr.address), addr.port)
163     }
164 }
165 
166 impl From<std::net::SocketAddrV4> for Ipv4SocketAddress {
from(addr: std::net::SocketAddrV4) -> Self167     fn from(addr: std::net::SocketAddrV4) -> Self {
168         Self {
169             address: from_ipv4_addr(*addr.ip()),
170             port: addr.port(),
171         }
172     }
173 }
174 
175 impl From<Ipv6SocketAddress> for std::net::SocketAddrV6 {
from(addr: Ipv6SocketAddress) -> Self176     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 
186 impl From<std::net::SocketAddrV6> for Ipv6SocketAddress {
from(addr: std::net::SocketAddrV6) -> Self187     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 
197 impl std::net::ToSocketAddrs for IpSocketAddress {
198     type Iter = <std::net::SocketAddr as std::net::ToSocketAddrs>::Iter;
199 
to_socket_addrs(&self) -> io::Result<Self::Iter>200     fn to_socket_addrs(&self) -> io::Result<Self::Iter> {
201         std::net::SocketAddr::from(*self).to_socket_addrs()
202     }
203 }
204 
205 impl std::net::ToSocketAddrs for Ipv4SocketAddress {
206     type Iter = <std::net::SocketAddrV4 as std::net::ToSocketAddrs>::Iter;
207 
to_socket_addrs(&self) -> io::Result<Self::Iter>208     fn to_socket_addrs(&self) -> io::Result<Self::Iter> {
209         std::net::SocketAddrV4::from(*self).to_socket_addrs()
210     }
211 }
212 
213 impl std::net::ToSocketAddrs for Ipv6SocketAddress {
214     type Iter = <std::net::SocketAddrV6 as std::net::ToSocketAddrs>::Iter;
215 
to_socket_addrs(&self) -> io::Result<Self::Iter>216     fn to_socket_addrs(&self) -> io::Result<Self::Iter> {
217         std::net::SocketAddrV6::from(*self).to_socket_addrs()
218     }
219 }
220 
221 impl From<IpAddressFamily> for cap_net_ext::AddressFamily {
from(family: IpAddressFamily) -> Self222     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 
230 impl From<cap_net_ext::AddressFamily> for IpAddressFamily {
from(family: cap_net_ext::AddressFamily) -> Self231     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 }
238