diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1f8e67e8..6fb41acb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -105,6 +105,7 @@ jobs: - x86_64-unknown-netbsd - x86_64-unknown-openbsd - x86_64-unknown-redox + - wasm32-wasip2 steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@nightly diff --git a/Cargo.toml b/Cargo.toml index 68238cd7..f99f0eeb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,7 @@ targets = [ [package.metadata.playground] features = ["all"] -[target."cfg(unix)".dependencies] +[target.'cfg(any(unix, target_os = "wasi"))'.dependencies] libc = "0.2.172" [target.'cfg(windows)'.dependencies.windows-sys] diff --git a/src/lib.rs b/src/lib.rs index 81b36114..b846288f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,11 +61,11 @@ #![doc(test(attr(deny(warnings))))] use std::fmt; -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] use std::io::IoSlice; -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] use std::marker::PhantomData; -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] use std::mem; use std::mem::MaybeUninit; use std::net::SocketAddr; @@ -109,7 +109,7 @@ macro_rules! from { ($from: ty, $for: ty) => { impl From<$from> for $for { fn from(socket: $from) -> $for { - #[cfg(unix)] + #[cfg(any(unix, all(target_os = "wasi", not(target_env = "p1"))))] unsafe { <$for>::from_raw_fd(socket.into_raw_fd()) } @@ -176,11 +176,14 @@ mod sockaddr; mod socket; mod sockref; -#[cfg_attr(unix, path = "sys/unix.rs")] +#[cfg_attr( + any(unix, all(target_os = "wasi", not(target_env = "p1"))), + path = "sys/unix.rs" +)] #[cfg_attr(windows, path = "sys/windows.rs")] mod sys; -#[cfg(not(any(windows, unix)))] +#[cfg(not(any(windows, unix, all(target_os = "wasi", not(target_env = "p1")))))] compile_error!("Socket2 doesn't support the compile target"); use sys::c_int; @@ -192,6 +195,7 @@ pub use sockaddr::{sa_family_t, socklen_t, SockAddr, SockAddrStorage}; target_os = "netbsd", target_os = "redox", target_os = "solaris", + target_os = "wasi", )))] pub use socket::InterfaceIndexOrAddress; pub use socket::Socket; @@ -221,6 +225,7 @@ impl Domain { pub const IPV6: Domain = Domain(sys::AF_INET6); /// Domain for Unix socket communication, corresponding to `AF_UNIX`. + #[cfg(not(target_os = "wasi"))] pub const UNIX: Domain = Domain(sys::AF_UNIX); /// Returns the correct domain for `address`. @@ -274,11 +279,14 @@ impl Type { pub const DCCP: Type = Type(sys::SOCK_DCCP); /// Type corresponding to `SOCK_SEQPACKET`. - #[cfg(all(feature = "all", not(target_os = "espidf")))] + #[cfg(all(feature = "all", not(any(target_os = "espidf", target_os = "wasi"))))] pub const SEQPACKET: Type = Type(sys::SOCK_SEQPACKET); /// Type corresponding to `SOCK_RAW`. - #[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))] + #[cfg(all( + feature = "all", + not(any(target_os = "redox", target_os = "espidf", target_os = "wasi")) + ))] pub const RAW: Type = Type(sys::SOCK_RAW); } @@ -306,9 +314,11 @@ pub struct Protocol(c_int); impl Protocol { /// Protocol corresponding to `ICMPv4`. + #[cfg(not(target_os = "wasi"))] pub const ICMPV4: Protocol = Protocol(sys::IPPROTO_ICMP); /// Protocol corresponding to `ICMPv6`. + #[cfg(not(target_os = "wasi"))] pub const ICMPV6: Protocol = Protocol(sys::IPPROTO_ICMPV6); /// Protocol corresponding to `TCP`. @@ -361,11 +371,11 @@ impl From for c_int { /// Flags for incoming messages. /// /// Flags provide additional information about incoming messages. -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] #[derive(Copy, Clone, Eq, PartialEq)] pub struct RecvFlags(c_int); -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] impl RecvFlags { /// Check if the message contains a truncated datagram. /// @@ -518,6 +528,7 @@ impl TcpKeepalive { target_os = "watchos", target_os = "windows", target_os = "cygwin", + all(target_os = "wasi", not(target_env = "p1")), ))] pub const fn with_interval(self, interval: Duration) -> Self { Self { @@ -547,6 +558,7 @@ impl TcpKeepalive { target_os = "watchos", target_os = "cygwin", target_os = "windows", + all(target_os = "wasi", not(target_env = "p1")), ) ))] pub const fn with_retries(self, retries: u32) -> Self { @@ -561,7 +573,7 @@ impl TcpKeepalive { /// /// This wraps `msghdr` on Unix and `WSAMSG` on Windows. Also see [`MsgHdrMut`] /// for the variant used by `recvmsg(2)`. -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] #[repr(transparent)] pub struct MsgHdr<'addr, 'bufs, 'control> { inner: sys::msghdr, @@ -569,7 +581,7 @@ pub struct MsgHdr<'addr, 'bufs, 'control> { _lifetimes: PhantomData<(&'addr SockAddr, &'bufs IoSlice<'bufs>, &'control [u8])>, } -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] impl<'addr, 'bufs, 'control> MsgHdr<'addr, 'bufs, 'control> { /// Create a new `MsgHdr` with all empty/zero fields. #[allow(clippy::new_without_default)] @@ -619,7 +631,7 @@ impl<'addr, 'bufs, 'control> MsgHdr<'addr, 'bufs, 'control> { } } -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] impl<'name, 'bufs, 'control> fmt::Debug for MsgHdr<'name, 'bufs, 'control> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { "MsgHdr".fmt(fmt) @@ -630,7 +642,7 @@ impl<'name, 'bufs, 'control> fmt::Debug for MsgHdr<'name, 'bufs, 'control> { /// /// This wraps `msghdr` on Unix and `WSAMSG` on Windows. Also see [`MsgHdr`] for /// the variant used by `sendmsg(2)`. -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] #[repr(transparent)] pub struct MsgHdrMut<'addr, 'bufs, 'control> { inner: sys::msghdr, @@ -642,7 +654,7 @@ pub struct MsgHdrMut<'addr, 'bufs, 'control> { )>, } -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] impl<'addr, 'bufs, 'control> MsgHdrMut<'addr, 'bufs, 'control> { /// Create a new `MsgHdrMut` with all empty/zero fields. #[allow(clippy::new_without_default)] @@ -697,7 +709,7 @@ impl<'addr, 'bufs, 'control> MsgHdrMut<'addr, 'bufs, 'control> { } } -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] impl<'name, 'bufs, 'control> fmt::Debug for MsgHdrMut<'name, 'bufs, 'control> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { "MsgHdrMut".fmt(fmt) diff --git a/src/sockaddr.rs b/src/sockaddr.rs index cec97b65..120a5466 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -1,13 +1,16 @@ use std::hash::Hash; use std::mem::{self, size_of}; use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6}; +#[cfg(not(target_os = "wasi"))] use std::path::Path; use std::{fmt, io, ptr}; #[cfg(windows)] use windows_sys::Win32::Networking::WinSock::SOCKADDR_IN6_0; -use crate::sys::{c_int, sockaddr_in, sockaddr_in6, sockaddr_storage, AF_INET, AF_INET6, AF_UNIX}; +#[cfg(not(target_os = "wasi"))] +use crate::sys::AF_UNIX; +use crate::sys::{c_int, sockaddr_in, sockaddr_in6, sockaddr_storage, AF_INET, AF_INET6}; use crate::Domain; /// The integer type used with `getsockname` on this platform. @@ -212,6 +215,7 @@ impl SockAddr { /// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path. /// /// Returns an error if the path is longer than `SUN_LEN`. + #[cfg(not(target_os = "wasi"))] pub fn unix

(path: P) -> io::Result where P: AsRef, @@ -269,6 +273,7 @@ impl SockAddr { /// Returns true if this address is of a unix socket (for local interprocess communication), /// i.e. it is from the `AF_UNIX` family, false otherwise. + #[cfg(not(target_os = "wasi"))] pub fn is_unix(&self) -> bool { self.storage.ss_family == AF_UNIX as sa_family_t } @@ -293,7 +298,7 @@ impl SockAddr { ip, port, addr.sin6_flowinfo, - #[cfg(unix)] + #[cfg(any(unix, all(target_os = "wasi", not(target_env = "p1"))))] addr.sin6_scope_id, #[cfg(windows)] unsafe { @@ -350,7 +355,10 @@ impl From for SockAddr { storage.sin_family = AF_INET as sa_family_t; storage.sin_port = addr.port().to_be(); storage.sin_addr = crate::sys::to_in_addr(addr.ip()); - storage.sin_zero = Default::default(); + #[cfg(not(target_os = "wasi"))] + { + storage.sin_zero = Default::default(); + } mem::size_of::() as socklen_t }; #[cfg(any( @@ -385,7 +393,7 @@ impl From for SockAddr { storage.sin6_port = addr.port().to_be(); storage.sin6_addr = crate::sys::to_in6_addr(addr.ip()); storage.sin6_flowinfo = addr.flowinfo(); - #[cfg(unix)] + #[cfg(any(unix, all(target_os = "wasi", not(target_env = "p1"))))] { storage.sin6_scope_id = addr.scope_id(); } @@ -469,6 +477,7 @@ mod tests { let addr = SockAddr::from(std); assert!(addr.is_ipv4()); assert!(!addr.is_ipv6()); + #[cfg(not(target_os = "wasi"))] assert!(!addr.is_unix()); assert_eq!(addr.family(), AF_INET as sa_family_t); assert_eq!(addr.domain(), Domain::IPV4); @@ -483,7 +492,7 @@ mod tests { assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std))); assert_eq!(addr.as_socket_ipv4(), Some(std)); assert!(addr.as_socket_ipv6().is_none()); - #[cfg(unix)] + #[cfg(all(unix, not(target_os = "wasi")))] { assert!(addr.as_pathname().is_none()); assert!(addr.as_abstract_namespace().is_none()); @@ -497,6 +506,7 @@ mod tests { let addr = SockAddr::from(std); assert!(addr.is_ipv6()); assert!(!addr.is_ipv4()); + #[cfg(not(target_os = "wasi"))] assert!(!addr.is_unix()); assert_eq!(addr.family(), AF_INET6 as sa_family_t); assert_eq!(addr.domain(), Domain::IPV6); @@ -511,7 +521,7 @@ mod tests { assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std))); assert!(addr.as_socket_ipv4().is_none()); assert_eq!(addr.as_socket_ipv6(), Some(std)); - #[cfg(unix)] + #[cfg(all(unix, not(target_os = "wasi")))] { assert!(addr.as_pathname().is_none()); assert!(addr.as_abstract_namespace().is_none()); diff --git a/src/socket.rs b/src/socket.rs index 69e617ae..ce65226b 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -8,13 +8,13 @@ use std::fmt; use std::io::{self, Read, Write}; -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] use std::io::{IoSlice, IoSliceMut}; use std::mem::MaybeUninit; #[cfg(not(target_os = "nto"))] use std::net::Ipv6Addr; use std::net::{self, Ipv4Addr, Shutdown}; -#[cfg(unix)] +#[cfg(any(unix, all(target_os = "wasi", not(target_env = "p1"))))] use std::os::fd::{FromRawFd, IntoRawFd}; #[cfg(windows)] use std::os::windows::io::{FromRawSocket, IntoRawSocket}; @@ -24,7 +24,7 @@ use crate::sys::{self, c_int, getsockopt, setsockopt, Bool}; #[cfg(all(unix, not(target_os = "redox")))] use crate::MsgHdrMut; use crate::{Domain, Protocol, SockAddr, TcpKeepalive, Type}; -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] use crate::{MaybeUninitSlice, MsgHdr, RecvFlags}; /// Owned wrapper around a system socket. @@ -220,7 +220,7 @@ impl Socket { match res { Ok(()) => return Ok(()), Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {} - #[cfg(unix)] + #[cfg(any(unix, all(target_os = "wasi", not(target_env = "p1"))))] Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {} Err(e) => return Err(e), } @@ -352,6 +352,7 @@ impl Socket { /// On Windows this can **not** be used function cannot be used on a /// QOS-enabled socket, see /// . + #[cfg(not(target_os = "wasi"))] pub fn try_clone(&self) -> io::Result { sys::try_clone(self.as_raw()).map(Socket::from_raw) } @@ -364,7 +365,10 @@ impl Socket { /// `O_NONBLOCK`. /// /// On Windows it is not possible retrieve the nonblocking mode status. - #[cfg(all(feature = "all", unix))] + #[cfg(all( + feature = "all", + any(unix, all(target_os = "wasi", not(target_env = "p1"))) + ))] pub fn nonblocking(&self) -> io::Result { sys::nonblocking(self.as_raw()) } @@ -423,6 +427,7 @@ impl Socket { /// [`recv`]: Socket::recv /// [`out_of_band_inline`]: Socket::out_of_band_inline #[cfg_attr(target_os = "redox", allow(rustdoc::broken_intra_doc_links))] + #[cfg(not(target_os = "wasi"))] pub fn recv_out_of_band(&self, buf: &mut [MaybeUninit]) -> io::Result { self.recv_with_flags(buf, sys::MSG_OOB) } @@ -465,7 +470,7 @@ impl Socket { /// Note that the [`io::Read::read_vectored`] implementation calls this /// function with `buf`s of type `&mut [IoSliceMut]`, allowing initialised /// buffers to be used without using `unsafe`. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "wasi")))] pub fn recv_vectored( &self, bufs: &mut [MaybeUninitSlice<'_>], @@ -484,7 +489,7 @@ impl Socket { /// as [`recv_vectored`]. /// /// [`recv_vectored`]: Socket::recv_vectored - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "wasi")))] pub fn recv_vectored_with_flags( &self, bufs: &mut [MaybeUninitSlice<'_>], @@ -549,7 +554,7 @@ impl Socket { /// as [`recv_vectored`]. /// /// [`recv_vectored`]: Socket::recv_vectored - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "wasi")))] pub fn recv_from_vectored( &self, bufs: &mut [MaybeUninitSlice<'_>], @@ -568,7 +573,7 @@ impl Socket { /// as [`recv_vectored`]. /// /// [`recv_vectored`]: Socket::recv_vectored - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "wasi")))] pub fn recv_from_vectored_with_flags( &self, bufs: &mut [MaybeUninitSlice<'_>], @@ -652,7 +657,7 @@ impl Socket { } /// Send data to the connected peer. Returns the amount of bytes written. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "wasi")))] pub fn send_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { self.send_vectored_with_flags(bufs, 0) } @@ -662,7 +667,7 @@ impl Socket { #[doc = man_links!(sendmsg(2))] /// /// [`send_vectored`]: Socket::send_vectored - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "wasi")))] pub fn send_vectored_with_flags( &self, bufs: &[IoSlice<'_>], @@ -679,6 +684,7 @@ impl Socket { /// [`send`]: Socket::send /// [`out_of_band_inline`]: Socket::out_of_band_inline #[cfg_attr(target_os = "redox", allow(rustdoc::broken_intra_doc_links))] + #[cfg(not(target_os = "wasi"))] pub fn send_out_of_band(&self, buf: &[u8]) -> io::Result { self.send_with_flags(buf, sys::MSG_OOB) } @@ -708,7 +714,7 @@ impl Socket { /// Send data to a peer listening on `addr`. Returns the amount of bytes /// written. #[doc = man_links!(sendmsg(2))] - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "wasi")))] pub fn send_to_vectored(&self, bufs: &[IoSlice<'_>], addr: &SockAddr) -> io::Result { self.send_to_vectored_with_flags(bufs, addr, 0) } @@ -717,7 +723,7 @@ impl Socket { /// arbitrary flags to the underlying `sendmsg`/`WSASendTo` call. /// /// [`send_to_vectored`]: Socket::send_to_vectored - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "wasi")))] pub fn send_to_vectored_with_flags( &self, bufs: &[IoSlice<'_>], @@ -729,7 +735,7 @@ impl Socket { /// Send a message on a socket using a message structure. #[doc = man_links!(sendmsg(2))] - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "wasi")))] pub fn sendmsg(&self, msg: &MsgHdr<'_, '_, '_>, flags: sys::c_int) -> io::Result { sys::sendmsg(self.as_raw(), msg, flags) } @@ -848,6 +854,7 @@ fn set_common_accept_flags(socket: Socket) -> io::Result { target_os = "netbsd", target_os = "redox", target_os = "solaris", + target_os = "wasi", )))] #[derive(Debug, Copy, Clone)] pub enum InterfaceIndexOrAddress { @@ -965,7 +972,7 @@ impl Socket { /// For more information about this option, see [`set_out_of_band_inline`]. /// /// [`set_out_of_band_inline`]: Socket::set_out_of_band_inline - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "wasi")))] pub fn out_of_band_inline(&self) -> io::Result { unsafe { getsockopt::(self.as_raw(), sys::SOL_SOCKET, sys::SO_OOBINLINE) @@ -979,7 +986,7 @@ impl Socket { /// receive data stream. Otherwise, out-of-band data is passed only when the /// `MSG_OOB` flag is set during receiving. As per RFC6093, TCP sockets /// using the Urgent mechanism are encouraged to set this flag. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "wasi")))] pub fn set_out_of_band_inline(&self, oob_inline: bool) -> io::Result<()> { unsafe { setsockopt( @@ -1202,7 +1209,10 @@ impl Socket { /// For more information about this option, see [`set_header_included_v4`]. /// /// [`set_header_included_v4`]: Socket::set_header_included_v4 - #[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))] + #[cfg(all( + feature = "all", + not(any(target_os = "redox", target_os = "espidf", target_os = "wasi")) + ))] pub fn header_included_v4(&self) -> io::Result { unsafe { getsockopt::(self.as_raw(), sys::IPPROTO_IP, sys::IP_HDRINCL) @@ -1225,7 +1235,10 @@ impl Socket { any(target_os = "fuchsia", target_os = "illumos", target_os = "solaris"), allow(rustdoc::broken_intra_doc_links) )] - #[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))] + #[cfg(all( + feature = "all", + not(any(target_os = "redox", target_os = "espidf", target_os = "wasi")) + ))] pub fn set_header_included_v4(&self, included: bool) -> io::Result<()> { unsafe { setsockopt( @@ -1330,6 +1343,7 @@ impl Socket { target_os = "espidf", target_os = "vita", target_os = "cygwin", + target_os = "wasi", )))] pub fn join_multicast_v4_n( &self, @@ -1364,6 +1378,7 @@ impl Socket { target_os = "espidf", target_os = "vita", target_os = "cygwin", + target_os = "wasi", )))] pub fn leave_multicast_v4_n( &self, @@ -1399,6 +1414,7 @@ impl Socket { target_os = "nto", target_os = "espidf", target_os = "vita", + target_os = "wasi", )))] pub fn join_ssm_v4( &self, @@ -1437,6 +1453,7 @@ impl Socket { target_os = "nto", target_os = "espidf", target_os = "vita", + target_os = "wasi", )))] pub fn leave_ssm_v4( &self, @@ -1499,6 +1516,7 @@ impl Socket { /// For more information about this option, see [`set_multicast_if_v4`]. /// /// [`set_multicast_if_v4`]: Socket::set_multicast_if_v4 + #[cfg(not(target_os = "wasi"))] pub fn multicast_if_v4(&self) -> io::Result { unsafe { getsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_IF).map(sys::from_in_addr) @@ -1508,6 +1526,7 @@ impl Socket { /// Set the value of the `IP_MULTICAST_IF` option for this socket. /// /// Specifies the interface to use for routing multicast packets. + #[cfg(not(target_os = "wasi"))] pub fn set_multicast_if_v4(&self, interface: &Ipv4Addr) -> io::Result<()> { let interface = sys::to_in_addr(interface); unsafe { @@ -1609,6 +1628,7 @@ impl Socket { target_os = "solaris", target_os = "illumos", target_os = "haiku", + target_os = "wasi", )))] pub fn set_tos_v4(&self, tos: u32) -> io::Result<()> { unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_TOS, tos as c_int) } @@ -1628,6 +1648,7 @@ impl Socket { target_os = "solaris", target_os = "illumos", target_os = "haiku", + target_os = "wasi", )))] pub fn tos_v4(&self) -> io::Result { unsafe { @@ -1655,6 +1676,7 @@ impl Socket { target_os = "espidf", target_os = "vita", target_os = "cygwin", + target_os = "wasi", )))] pub fn set_recv_tos_v4(&self, recv_tos: bool) -> io::Result<()> { unsafe { @@ -1687,6 +1709,7 @@ impl Socket { target_os = "espidf", target_os = "vita", target_os = "cygwin", + target_os = "wasi", )))] pub fn recv_tos_v4(&self) -> io::Result { unsafe { @@ -1729,7 +1752,8 @@ impl Socket { target_os = "openbsd", target_os = "freebsd", target_os = "dragonfly", - target_os = "netbsd" + target_os = "netbsd", + target_os = "wasi", )) ))] pub fn header_included_v6(&self) -> io::Result { @@ -1759,7 +1783,8 @@ impl Socket { target_os = "openbsd", target_os = "freebsd", target_os = "dragonfly", - target_os = "netbsd" + target_os = "netbsd", + target_os = "wasi", )) ))] pub fn set_header_included_v6(&self, included: bool) -> io::Result<()> { @@ -1829,6 +1854,7 @@ impl Socket { /// For more information about this option, see [`set_multicast_hops_v6`]. /// /// [`set_multicast_hops_v6`]: Socket::set_multicast_hops_v6 + #[cfg(not(target_os = "wasi"))] pub fn multicast_hops_v6(&self) -> io::Result { unsafe { getsockopt::(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_HOPS) @@ -1841,6 +1867,7 @@ impl Socket { /// Indicates the number of "routers" multicast packets will transit for /// this socket. The default value is 1 which means that multicast packets /// don't leave the local network unless explicitly requested. + #[cfg(not(target_os = "wasi"))] pub fn set_multicast_hops_v6(&self, hops: u32) -> io::Result<()> { unsafe { setsockopt( @@ -1892,6 +1919,7 @@ impl Socket { /// For more information about this option, see [`set_multicast_if_v6`]. /// /// [`set_multicast_if_v6`]: Socket::set_multicast_if_v6 + #[cfg(not(target_os = "wasi"))] pub fn multicast_if_v6(&self) -> io::Result { unsafe { getsockopt::(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_IF) @@ -1904,6 +1932,7 @@ impl Socket { /// Specifies the interface to use for routing multicast packets. Unlike /// ipv4, this is generally required in ipv6 contexts where network routing /// prefixes may overlap. + #[cfg(not(target_os = "wasi"))] pub fn set_multicast_if_v6(&self, interface: u32) -> io::Result<()> { unsafe { setsockopt( @@ -2014,6 +2043,7 @@ impl Socket { target_os = "hurd", target_os = "espidf", target_os = "vita", + target_os = "wasi", )))] pub fn recv_tclass_v6(&self) -> io::Result { unsafe { @@ -2039,6 +2069,7 @@ impl Socket { target_os = "hurd", target_os = "espidf", target_os = "vita", + target_os = "wasi", )))] pub fn set_recv_tclass_v6(&self, recv_tclass: bool) -> io::Result<()> { unsafe { @@ -2072,6 +2103,7 @@ impl Socket { target_os = "espidf", target_os = "vita", target_os = "cygwin", + target_os = "wasi", )) ))] pub fn recv_hoplimit_v6(&self) -> io::Result { @@ -2101,6 +2133,7 @@ impl Socket { target_os = "espidf", target_os = "vita", target_os = "cygwin", + target_os = "wasi", )) ))] pub fn set_recv_hoplimit_v6(&self, recv_hoplimit: bool) -> io::Result<()> { @@ -2168,6 +2201,7 @@ impl Socket { target_os = "tvos", target_os = "watchos", target_os = "cygwin", + all(target_os = "wasi", not(target_env = "p1")), ) ))] pub fn tcp_keepalive_interval(&self) -> io::Result { @@ -2199,6 +2233,7 @@ impl Socket { target_os = "watchos", target_os = "cygwin", target_os = "windows", + all(target_os = "wasi", not(target_env = "p1")), ) ))] pub fn tcp_keepalive_retries(&self) -> io::Result { @@ -2298,7 +2333,7 @@ impl Read for Socket { self.recv(buf) } - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "wasi")))] fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { // Safety: both `IoSliceMut` and `MaybeUninitSlice` promise to have the // same layout, that of `iovec`/`WSABUF`. Furthermore, `recv_vectored` @@ -2316,7 +2351,7 @@ impl<'a> Read for &'a Socket { self.recv(buf) } - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "wasi")))] fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { // Safety: see other `Read::read` impl. let bufs = unsafe { &mut *(bufs as *mut [IoSliceMut<'_>] as *mut [MaybeUninitSlice<'_>]) }; @@ -2329,7 +2364,7 @@ impl Write for Socket { self.send(buf) } - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "wasi")))] fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { self.send_vectored(bufs) } @@ -2344,7 +2379,7 @@ impl<'a> Write for &'a Socket { self.send(buf) } - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "wasi")))] fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { self.send_vectored(bufs) } diff --git a/src/sockref.rs b/src/sockref.rs index dbffc5d2..b07a031f 100644 --- a/src/sockref.rs +++ b/src/sockref.rs @@ -2,7 +2,7 @@ use std::fmt; use std::marker::PhantomData; use std::mem::ManuallyDrop; use std::ops::Deref; -#[cfg(unix)] +#[cfg(any(unix, all(target_os = "wasi", not(target_env = "p1"))))] use std::os::fd::{AsFd, AsRawFd, FromRawFd}; #[cfg(windows)] use std::os::windows::io::{AsRawSocket, AsSocket, FromRawSocket}; @@ -77,7 +77,7 @@ impl<'s> Deref for SockRef<'s> { } /// On Windows, a corresponding `From<&impl AsSocket>` implementation exists. -#[cfg(unix)] +#[cfg(any(unix, all(target_os = "wasi", not(target_env = "p1"))))] impl<'s, S> From<&'s S> for SockRef<'s> where S: AsFd, diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 3a60ada3..0c2f7eb7 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -7,8 +7,9 @@ // except according to those terms. use std::cmp::min; +#[cfg(not(target_os = "wasi"))] use std::ffi::OsStr; -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] use std::io::IoSlice; use std::marker::PhantomData; use std::mem::{self, size_of, MaybeUninit}; @@ -45,9 +46,11 @@ use std::num::NonZeroU32; ))] use std::num::NonZeroUsize; use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; +#[cfg(not(target_os = "wasi"))] use std::os::unix::ffi::OsStrExt; -#[cfg(feature = "all")] +#[cfg(all(feature = "all", unix))] use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream}; +#[cfg(not(target_os = "wasi"))] use std::path::Path; use std::ptr; use std::time::{Duration, Instant}; @@ -64,20 +67,27 @@ use std::{io, slice}; use libc::ssize_t; use libc::{in6_addr, in_addr}; -use crate::{Domain, Protocol, SockAddr, SockAddrStorage, TcpKeepalive, Type}; -#[cfg(not(target_os = "redox"))] +#[cfg(not(target_os = "wasi"))] +use crate::SockAddrStorage; +use crate::{Domain, Protocol, SockAddr, TcpKeepalive, Type}; +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] use crate::{MsgHdr, MsgHdrMut, RecvFlags}; pub(crate) use std::ffi::c_int; // Used in `Domain`. -pub(crate) use libc::{AF_INET, AF_INET6, AF_UNIX}; +#[cfg(not(target_os = "wasi"))] +pub(crate) use libc::AF_UNIX; +pub(crate) use libc::{AF_INET, AF_INET6}; // Used in `Type`. #[cfg(all(feature = "all", target_os = "linux"))] pub(crate) use libc::SOCK_DCCP; -#[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))] +#[cfg(all( + feature = "all", + not(any(target_os = "redox", target_os = "espidf", target_os = "wasi")) +))] pub(crate) use libc::SOCK_RAW; -#[cfg(all(feature = "all", not(target_os = "espidf")))] +#[cfg(all(feature = "all", not(any(target_os = "espidf", target_os = "wasi"))))] pub(crate) use libc::SOCK_SEQPACKET; pub(crate) use libc::{SOCK_DGRAM, SOCK_STREAM}; // Used in `Protocol`. @@ -97,7 +107,9 @@ pub(crate) use libc::IPPROTO_SCTP; ) ))] pub(crate) use libc::IPPROTO_UDPLITE; -pub(crate) use libc::{IPPROTO_ICMP, IPPROTO_ICMPV6, IPPROTO_TCP, IPPROTO_UDP}; +#[cfg(not(target_os = "wasi"))] +pub(crate) use libc::{IPPROTO_ICMP, IPPROTO_ICMPV6}; +pub(crate) use libc::{IPPROTO_TCP, IPPROTO_UDP}; // Used in `SockAddr`. #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "openbsd")))] pub(crate) use libc::IPPROTO_DIVERT; @@ -105,9 +117,9 @@ pub(crate) use libc::{ sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t, }; // Used in `RecvFlags`. -#[cfg(not(any(target_os = "redox", target_os = "espidf")))] +#[cfg(not(any(target_os = "redox", target_os = "espidf", target_os = "wasi")))] pub(crate) use libc::MSG_TRUNC; -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] pub(crate) use libc::SO_OOBINLINE; // Used in `Socket`. #[cfg(not(target_os = "nto"))] @@ -128,6 +140,7 @@ pub(crate) use libc::IPV6_HDRINCL; target_os = "haiku", target_os = "espidf", target_os = "vita", + target_os = "wasi", target_os = "cygwin", )) ))] @@ -144,9 +157,13 @@ pub(crate) use libc::IPV6_RECVHOPLIMIT; target_os = "haiku", target_os = "espidf", target_os = "vita", + target_os = "wasi", )))] pub(crate) use libc::IPV6_RECVTCLASS; -#[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))] +#[cfg(all( + feature = "all", + not(any(target_os = "redox", target_os = "espidf", target_os = "wasi")) +))] pub(crate) use libc::IP_HDRINCL; #[cfg(not(any( target_os = "aix", @@ -162,6 +179,7 @@ pub(crate) use libc::IP_HDRINCL; target_os = "nto", target_os = "espidf", target_os = "vita", + target_os = "wasi", target_os = "cygwin", )))] pub(crate) use libc::IP_RECVTOS; @@ -171,6 +189,7 @@ pub(crate) use libc::IP_RECVTOS; target_os = "solaris", target_os = "haiku", target_os = "illumos", + target_os = "wasi", )))] pub(crate) use libc::IP_TOS; #[cfg(not(any( @@ -197,11 +216,10 @@ pub(crate) use libc::SO_PASSCRED; ))] pub(crate) use libc::SO_PRIORITY; pub(crate) use libc::{ - ip_mreq as IpMreq, linger, IPPROTO_IP, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, IPV6_MULTICAST_IF, - IPV6_MULTICAST_LOOP, IPV6_UNICAST_HOPS, IPV6_V6ONLY, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, - IP_MULTICAST_IF, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_TTL, MSG_OOB, MSG_PEEK, SOL_SOCKET, - SO_BROADCAST, SO_ERROR, SO_KEEPALIVE, SO_RCVBUF, SO_RCVTIMEO, SO_REUSEADDR, SO_SNDBUF, - SO_SNDTIMEO, SO_TYPE, TCP_NODELAY, + ip_mreq as IpMreq, linger, IPPROTO_IP, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, IPV6_UNICAST_HOPS, + IPV6_V6ONLY, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, + IP_TTL, MSG_PEEK, SOL_SOCKET, SO_BROADCAST, SO_ERROR, SO_KEEPALIVE, SO_RCVBUF, SO_RCVTIMEO, + SO_REUSEADDR, SO_SNDBUF, SO_SNDTIMEO, SO_TYPE, TCP_NODELAY, }; #[cfg(not(any( target_os = "dragonfly", @@ -214,6 +232,7 @@ pub(crate) use libc::{ target_os = "nto", target_os = "espidf", target_os = "vita", + target_os = "wasi", )))] pub(crate) use libc::{ ip_mreq_source as IpMreqSource, IP_ADD_SOURCE_MEMBERSHIP, IP_DROP_SOURCE_MEMBERSHIP, @@ -232,6 +251,7 @@ pub(crate) use libc::{ target_os = "solaris", target_os = "tvos", target_os = "watchos", + target_os = "wasi", )))] pub(crate) use libc::{IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP}; #[cfg(any( @@ -247,10 +267,13 @@ pub(crate) use libc::{IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP}; target_os = "solaris", target_os = "tvos", target_os = "watchos", + all(target_os = "wasi", not(target_env = "p1")), ))] pub(crate) use libc::{ IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP, IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP, }; +#[cfg(not(target_os = "wasi"))] +pub(crate) use libc::{IPV6_MULTICAST_HOPS, IPV6_MULTICAST_IF, IP_MULTICAST_IF, MSG_OOB}; #[cfg(all( feature = "all", any( @@ -267,6 +290,7 @@ pub(crate) use libc::{ target_os = "tvos", target_os = "watchos", target_os = "cygwin", + all(target_os = "wasi", not(target_env = "p1")), ) ))] pub(crate) use libc::{TCP_KEEPCNT, TCP_KEEPINTVL}; @@ -403,6 +427,7 @@ impl_debug!( Domain, libc::AF_INET, libc::AF_INET6, + #[cfg(not(target_os = "wasi"))] libc::AF_UNIX, #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] libc::AF_PACKET, @@ -426,6 +451,7 @@ impl Type { target_os = "netbsd", target_os = "openbsd", target_os = "cygwin", + all(target_os = "wasi", not(target_env = "p1")), ) ))] pub const fn nonblocking(self) -> Type { @@ -479,11 +505,16 @@ impl_debug!( libc::SOCK_DGRAM, #[cfg(all(feature = "all", target_os = "linux"))] libc::SOCK_DCCP, - #[cfg(not(any(target_os = "redox", target_os = "espidf")))] + #[cfg(not(any(target_os = "redox", target_os = "espidf", target_os = "wasi")))] libc::SOCK_RAW, - #[cfg(not(any(target_os = "redox", target_os = "haiku", target_os = "espidf")))] + #[cfg(not(any( + target_os = "redox", + target_os = "haiku", + target_os = "espidf", + target_os = "wasi" + )))] libc::SOCK_RDM, - #[cfg(not(target_os = "espidf"))] + #[cfg(not(any(target_os = "espidf", target_os = "wasi")))] libc::SOCK_SEQPACKET, /* TODO: add these optional bit OR-ed flags: #[cfg(any( @@ -511,7 +542,9 @@ impl_debug!( impl_debug!( Protocol, + #[cfg(not(target_os = "wasi"))] libc::IPPROTO_ICMP, + #[cfg(not(target_os = "wasi"))] libc::IPPROTO_ICMPV6, libc::IPPROTO_TCP, libc::IPPROTO_UDP, @@ -536,7 +569,7 @@ impl_debug!( ); /// Unix-only API. -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] impl RecvFlags { /// Check if the message terminates a record. /// @@ -589,7 +622,7 @@ impl RecvFlags { } } -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] impl std::fmt::Debug for RecvFlags { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut s = f.debug_struct("RecvFlags"); @@ -640,12 +673,14 @@ impl<'a> MaybeUninitSlice<'a> { } /// Returns the offset of the `sun_path` member of the passed unix socket address. +#[cfg(not(target_os = "wasi"))] pub(crate) fn offset_of_path(storage: &libc::sockaddr_un) -> usize { let base = storage as *const _ as usize; let path = ptr::addr_of!(storage.sun_path) as usize; path - base } +#[cfg(not(target_os = "wasi"))] #[allow(unsafe_op_in_unsafe_fn)] pub(crate) fn unix_sockaddr(path: &Path) -> io::Result { let mut storage = SockAddrStorage::zeroed(); @@ -692,39 +727,39 @@ pub(crate) fn unix_sockaddr(path: &Path) -> io::Result { } // Used in `MsgHdr`. -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] pub(crate) use libc::msghdr; -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] pub(crate) fn set_msghdr_name(msg: &mut msghdr, name: &SockAddr) { msg.msg_name = name.as_ptr() as *mut _; msg.msg_namelen = name.len(); } -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] #[allow(clippy::unnecessary_cast)] // IovLen type can be `usize`. pub(crate) fn set_msghdr_iov(msg: &mut msghdr, ptr: *mut libc::iovec, len: usize) { msg.msg_iov = ptr; msg.msg_iovlen = min(len, IovLen::MAX as usize) as IovLen; } -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] pub(crate) fn set_msghdr_control(msg: &mut msghdr, ptr: *mut libc::c_void, len: usize) { msg.msg_control = ptr; msg.msg_controllen = len as _; } -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] pub(crate) fn set_msghdr_flags(msg: &mut msghdr, flags: c_int) { msg.msg_flags = flags; } -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] pub(crate) fn msghdr_flags(msg: &msghdr) -> RecvFlags { RecvFlags(msg.msg_flags) } -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] pub(crate) fn msghdr_control_len(msg: &msghdr) -> usize { msg.msg_controllen as _ } @@ -763,7 +798,11 @@ impl SockAddr { None } } +} +/// Unix only API (not available on WASI). +#[cfg(not(target_os = "wasi"))] +impl SockAddr { /// Returns true if this address is an unnamed address from the `AF_UNIX` family (for local /// interprocess communication), false otherwise. pub fn is_unnamed(&self) -> bool { @@ -955,11 +994,16 @@ pub(crate) fn getpeername(fd: RawSocket) -> io::Result { .map(|(_, addr)| addr) } +#[cfg(not(target_os = "wasi"))] pub(crate) fn try_clone(fd: RawSocket) -> io::Result { syscall!(fcntl(fd, libc::F_DUPFD_CLOEXEC, 0)) } -#[cfg(all(feature = "all", unix, not(target_os = "vita")))] +#[cfg(all( + feature = "all", + any(unix, all(target_os = "wasi", not(target_env = "p1"))), + not(target_os = "vita") +))] pub(crate) fn nonblocking(fd: RawSocket) -> io::Result { let file_status_flags = fcntl_get(fd, libc::F_GETFL)?; Ok((file_status_flags & libc::O_NONBLOCK) != 0) @@ -1042,7 +1086,7 @@ pub(crate) fn peek_sender(fd: RawSocket) -> io::Result { Ok(sender) } -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] pub(crate) fn recv_vectored( fd: RawSocket, bufs: &mut [crate::MaybeUninitSlice<'_>], @@ -1053,7 +1097,7 @@ pub(crate) fn recv_vectored( Ok((n, msg.flags())) } -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] pub(crate) fn recv_from_vectored( fd: RawSocket, bufs: &mut [crate::MaybeUninitSlice<'_>], @@ -1075,7 +1119,7 @@ pub(crate) fn recv_from_vectored( Ok((n, msg.flags(), addr)) } -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] pub(crate) fn recvmsg( fd: RawSocket, msg: &mut MsgHdrMut<'_, '_, '_>, @@ -1094,7 +1138,7 @@ pub(crate) fn send(fd: RawSocket, buf: &[u8], flags: c_int) -> io::Result .map(|n| n as usize) } -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] pub(crate) fn send_vectored( fd: RawSocket, bufs: &[IoSlice<'_>], @@ -1121,7 +1165,7 @@ pub(crate) fn send_to( .map(|n| n as usize) } -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] pub(crate) fn send_to_vectored( fd: RawSocket, bufs: &[IoSlice<'_>], @@ -1132,7 +1176,7 @@ pub(crate) fn send_to_vectored( sendmsg(fd, &msg, flags) } -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] pub(crate) fn sendmsg(fd: RawSocket, msg: &MsgHdr<'_, '_, '_>, flags: c_int) -> io::Result { syscall!(sendmsg(fd, &msg.inner, flags)).map(|n| n as usize) } @@ -1218,6 +1262,7 @@ pub(crate) fn set_tcp_keepalive(fd: RawSocket, keepalive: &TcpKeepalive) -> io:: target_os = "tvos", target_os = "watchos", target_os = "cygwin", + all(target_os = "wasi", not(target_env = "p1")), ))] { if let Some(interval) = keepalive.interval { @@ -1352,6 +1397,7 @@ pub(crate) fn from_in6_addr(addr: in6_addr) -> Ipv6Addr { target_os = "espidf", target_os = "vita", target_os = "cygwin", + target_os = "wasi", )))] pub(crate) const fn to_mreqn( multiaddr: &Ipv4Addr, @@ -1472,7 +1518,8 @@ impl crate::Socket { target_os = "visionos", target_os = "macos", target_os = "tvos", - target_os = "watchos" + target_os = "watchos", + target_os = "wasi", ), allow(rustdoc::broken_intra_doc_links) )] @@ -1563,7 +1610,7 @@ impl crate::Socket { /// For more information about this option, see [`set_tcp_mss`]. /// /// [`set_tcp_mss`]: crate::Socket::set_tcp_mss - #[cfg(all(feature = "all", not(target_os = "redox")))] + #[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "wasi"))))] pub fn tcp_mss(&self) -> io::Result { unsafe { getsockopt::(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_MAXSEG) @@ -1575,7 +1622,7 @@ impl crate::Socket { /// /// The `TCP_MAXSEG` option denotes the TCP Maximum Segment Size and is only /// available on TCP sockets. - #[cfg(all(feature = "all", not(target_os = "redox")))] + #[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "wasi"))))] pub fn set_tcp_mss(&self, mss: u32) -> io::Result<()> { unsafe { setsockopt( @@ -2124,7 +2171,12 @@ impl crate::Socket { /// [`set_reuse_port`]: crate::Socket::set_reuse_port #[cfg(all( feature = "all", - not(any(target_os = "solaris", target_os = "illumos", target_os = "cygwin")) + not(any( + target_os = "solaris", + target_os = "illumos", + target_os = "cygwin", + target_os = "wasi" + )) ))] pub fn reuse_port(&self) -> io::Result { unsafe { @@ -2140,7 +2192,12 @@ impl crate::Socket { /// there's a socket already listening on this port. #[cfg(all( feature = "all", - not(any(target_os = "solaris", target_os = "illumos", target_os = "cygwin")) + not(any( + target_os = "solaris", + target_os = "illumos", + target_os = "cygwin", + target_os = "wasi" + )) ))] pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> { unsafe { @@ -2956,17 +3013,17 @@ impl FromRawFd for crate::Socket { } } -#[cfg(feature = "all")] +#[cfg(all(feature = "all", unix))] from!(UnixStream, crate::Socket); -#[cfg(feature = "all")] +#[cfg(all(feature = "all", unix))] from!(UnixListener, crate::Socket); -#[cfg(feature = "all")] +#[cfg(all(feature = "all", unix))] from!(UnixDatagram, crate::Socket); -#[cfg(feature = "all")] +#[cfg(all(feature = "all", unix))] from!(crate::Socket, UnixStream); -#[cfg(feature = "all")] +#[cfg(all(feature = "all", unix))] from!(crate::Socket, UnixListener); -#[cfg(feature = "all")] +#[cfg(all(feature = "all", unix))] from!(crate::Socket, UnixDatagram); #[test] diff --git a/tests/socket.rs b/tests/socket.rs index 7066cf5c..7adfbeed 100644 --- a/tests/socket.rs +++ b/tests/socket.rs @@ -14,7 +14,7 @@ ))] use std::fs::File; use std::io; -#[cfg(not(any(target_os = "redox", target_os = "vita")))] +#[cfg(not(any(target_os = "redox", target_os = "vita", target_os = "wasi")))] use std::io::IoSlice; use std::io::Read; use std::io::Write; @@ -38,6 +38,8 @@ use std::net::{Ipv6Addr, SocketAddrV6}; ) ))] use std::num::NonZeroUsize; +#[cfg(target_os = "wasi")] +use std::os::fd::AsRawFd; #[cfg(unix)] use std::os::unix::io::AsRawFd; #[cfg(windows)] @@ -53,7 +55,7 @@ use std::{env, fs}; #[cfg(windows)] use windows_sys::Win32::Foundation::{GetHandleInformation, HANDLE_FLAG_INHERIT}; -#[cfg(not(any(target_os = "redox", target_os = "vita")))] +#[cfg(not(any(target_os = "redox", target_os = "vita", target_os = "wasi")))] use socket2::MaybeUninitSlice; #[cfg(not(target_os = "vita"))] use socket2::TcpKeepalive; @@ -75,6 +77,7 @@ fn domain_fmt_debug() { let tests = &[ (Domain::IPV4, "AF_INET"), (Domain::IPV6, "AF_INET6"), + #[cfg(not(target_os = "wasi"))] (Domain::UNIX, "AF_UNIX"), #[cfg(all(feature = "all", any(target_os = "fuchsia", target_os = "linux")))] (Domain::PACKET, "AF_PACKET"), @@ -98,9 +101,9 @@ fn type_fmt_debug() { let tests = &[ (Type::STREAM, "SOCK_STREAM"), (Type::DGRAM, "SOCK_DGRAM"), - #[cfg(feature = "all")] + #[cfg(all(feature = "all", not(target_os = "wasi")))] (Type::SEQPACKET, "SOCK_SEQPACKET"), - #[cfg(all(feature = "all", not(target_os = "redox")))] + #[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "wasi"))))] (Type::RAW, "SOCK_RAW"), (500.into(), "500"), ]; @@ -117,7 +120,9 @@ fn type_fmt_debug() { #[test] fn protocol_fmt_debug() { let tests = &[ + #[cfg(not(target_os = "wasi"))] (Protocol::ICMPV4, "IPPROTO_ICMP"), + #[cfg(not(target_os = "wasi"))] (Protocol::ICMPV6, "IPPROTO_ICMPV6"), (Protocol::TCP, "IPPROTO_TCP"), (Protocol::UDP, "IPPROTO_UDP"), @@ -148,6 +153,7 @@ fn from_invalid_raw_fd_should_panic() { } #[test] +#[cfg(not(target_os = "wasi"))] fn socket_address_unix() { let string = "/tmp/socket"; let addr = SockAddr::unix(string).unwrap(); @@ -168,6 +174,7 @@ fn socket_address_unix() { } #[test] +#[cfg(not(target_os = "wasi"))] fn socket_address_unix_unnamed() { let addr = SockAddr::unix("").unwrap(); assert!(addr.as_socket_ipv4().is_none()); @@ -214,6 +221,7 @@ fn socket_address_vsock() { } #[test] +#[cfg(not(target_os = "wasi"))] // All WASI sockets are always non-blocking by design. fn set_nonblocking() { let socket = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap(); assert_nonblocking(&socket, false); @@ -297,13 +305,16 @@ fn type_nonblocking() { } /// Assert that `NONBLOCK` is set on `socket`. -#[cfg(unix)] +#[cfg(any(unix, target_os = "wasi"))] #[track_caller] pub fn assert_nonblocking(socket: &Socket, want: bool) { - #[cfg(all(feature = "all", unix))] + #[cfg(all(feature = "all", any(unix, target_os = "wasi")))] assert_eq!(socket.nonblocking().unwrap(), want, "non-blocking option"); - #[cfg(not(any(all(feature = "all", unix), target_os = "vita")))] + #[cfg(not(any( + all(feature = "all", any(unix, target_os = "wasi")), + target_os = "vita" + )))] { let flags = unsafe { libc::fcntl(socket.as_raw_fd(), libc::F_GETFL) }; assert_eq!(flags & libc::O_NONBLOCK != 0, want, "non-blocking option"); @@ -517,6 +528,7 @@ where const DATA: &[u8] = b"hello world"; #[test] +#[cfg(not(target_os = "wasi"))] // WASI uses start-connect/finish-connect, no connect_timeout. fn connect_timeout_unrouteable() { // This IP is unroutable, so connections should always time out. let addr = "10.255.255.1:80".parse::().unwrap().into(); @@ -530,7 +542,9 @@ fn connect_timeout_unrouteable() { } #[test] -#[cfg(not(target_os = "vita"))] // Loopback has special behavior on vita +// Loopback has special behavior on vita. +// WASI uses start-connect/finish-connect, no connect_timeout. +#[cfg(not(any(target_os = "vita", target_os = "wasi")))] fn connect_timeout_unbound() { // Bind and drop a socket to track down a "probably unassigned" port. let socket = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap(); @@ -550,6 +564,7 @@ fn connect_timeout_unbound() { } #[test] +#[cfg(not(target_os = "wasi"))] // WASI uses start-connect/finish-connect, no connect_timeout. fn connect_timeout_valid() { let socket = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap(); socket @@ -576,6 +591,7 @@ fn pair() { assert_eq!(&buf[..n], DATA); } +#[cfg(not(target_os = "wasi"))] fn unix_sockets_supported() -> bool { #[cfg(windows)] { @@ -600,6 +616,7 @@ fn unix_sockets_supported() -> bool { } #[test] +#[cfg(not(target_os = "wasi"))] fn unix() { if !unix_sockets_supported() { return; @@ -632,6 +649,7 @@ fn unix() { } #[test] +#[cfg(not(target_os = "wasi"))] fn unix_accept() { if !unix_sockets_supported() { return; @@ -679,7 +697,7 @@ fn vsock() { } #[test] -#[cfg(not(target_os = "vita"))] // Vita does not support OOB +#[cfg(not(any(target_os = "vita", target_os = "wasi")))] // Vita and WASI do not support OOB fn out_of_band() { let listener = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap(); listener.bind(&any_ipv4()).unwrap(); @@ -710,7 +728,7 @@ fn out_of_band() { } #[test] -#[cfg(not(any(target_os = "redox", target_os = "vita")))] +#[cfg(not(any(target_os = "redox", target_os = "vita", target_os = "wasi")))] // WASI: SO_RCVTIMEO excluded, used in test setup. fn udp_peek_sender() { let (socket_a, socket_b) = udp_pair_unconnected(); @@ -725,7 +743,7 @@ fn udp_peek_sender() { } #[test] -#[cfg(not(any(target_os = "redox", target_os = "vita")))] +#[cfg(not(any(target_os = "redox", target_os = "vita", target_os = "wasi")))] fn send_recv_vectored() { let (socket_a, socket_b) = udp_pair_connected(); @@ -772,7 +790,7 @@ fn send_recv_vectored() { } #[test] -#[cfg(not(any(target_os = "redox", target_os = "vita")))] +#[cfg(not(any(target_os = "redox", target_os = "vita", target_os = "wasi")))] fn send_from_recv_to_vectored() { let (socket_a, socket_b) = udp_pair_unconnected(); let addr_a = socket_a.local_addr().unwrap(); @@ -825,7 +843,7 @@ fn send_from_recv_to_vectored() { } #[test] -#[cfg(not(any(target_os = "redox", target_os = "vita")))] +#[cfg(not(any(target_os = "redox", target_os = "vita", target_os = "wasi")))] fn sendmsg() { let (socket_a, socket_b) = udp_pair_unconnected(); @@ -843,7 +861,7 @@ fn sendmsg() { } #[test] -#[cfg(not(any(target_os = "redox", target_os = "vita")))] +#[cfg(not(any(target_os = "redox", target_os = "vita", target_os = "wasi")))] fn recv_vectored_truncated() { let (socket_a, socket_b) = udp_pair_connected(); @@ -863,7 +881,7 @@ fn recv_vectored_truncated() { } #[test] -#[cfg(not(any(target_os = "redox", target_os = "vita")))] +#[cfg(not(any(target_os = "redox", target_os = "vita", target_os = "wasi")))] fn recv_from_vectored_truncated() { let (socket_a, socket_b) = udp_pair_unconnected(); let addr_a = socket_a.local_addr().unwrap(); @@ -1430,7 +1448,7 @@ test!( set_send_buffer_size(SET_BUF_SIZE), GET_BUF_SIZE ); -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] test!(out_of_band_inline, set_out_of_band_inline(true)); test!(reuse_address, set_reuse_address(true)); #[cfg(all( @@ -1440,6 +1458,7 @@ test!(reuse_address, set_reuse_address(true)); target_os = "solaris", target_os = "illumos", target_os = "cygwin", + target_os = "wasi", )) ))] test!(reuse_port, set_reuse_port(true)); @@ -1484,6 +1503,7 @@ test!(tcp_quickack, set_tcp_quickack(false)); test!(tcp_thin_linear_timeouts, set_tcp_thin_linear_timeouts(true)); #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))] test!(tcp_notsent_lowat, set_tcp_notsent_lowat(16 * 1024)); +#[cfg(not(target_os = "wasi"))] // WASI: SO_LINGER not yet included (https://github.com/WebAssembly/WASI/issues/709). test!(linger, set_linger(Some(Duration::from_secs(10)))); test!( read_timeout, @@ -1504,6 +1524,7 @@ test!(IPv4 ttl_v4, set_ttl_v4(40)); target_os = "illumos", target_os = "haiku", target_os = "cygwin", + target_os = "wasi", )))] test!(IPv4 tos_v4, set_tos_v4(96)); @@ -1520,10 +1541,11 @@ test!(IPv4 tos_v4, set_tos_v4(96)); target_os = "vita", target_os = "haiku", target_os = "cygwin", + target_os = "wasi", )))] test!(IPv4 recv_tos_v4, set_recv_tos_v4(true)); -#[cfg(not(any(windows, target_os = "cygwin")))] // TODO: returns `WSAENOPROTOOPT` (10042) on Windows. +#[cfg(not(any(windows, target_os = "cygwin", target_os = "wasi")))] // TODO: returns `WSAENOPROTOOPT` (10042) on Windows. WASI: SO_BROADCAST not yet included (https://github.com/WebAssembly/WASI/issues/721). test!(IPv4 broadcast, set_broadcast(true)); #[cfg(not(target_os = "vita"))] @@ -1536,6 +1558,7 @@ test!(IPv6 unicast_hops_v6, set_unicast_hops_v6(20)); target_os = "openbsd", target_os = "vita", target_os = "cygwin", + target_os = "wasi", // IPV6_V6ONLY always true in WASI, setter not exposed (https://github.com/WebAssembly/WASI/issues/747). )))] test!(IPv6 only_v6, set_only_v6(true)); // IPv6 socket are already IPv6 only on FreeBSD and Windows. @@ -1570,6 +1593,7 @@ test!(IPv6 tclass_v6, set_tclass_v6(96)); target_os = "vita", target_os = "haiku", target_os = "cygwin", + target_os = "wasi", )))] test!(IPv6 recv_tclass_v6, set_recv_tclass_v6(true)); @@ -1588,6 +1612,7 @@ test!(IPv6 recv_tclass_v6, set_recv_tclass_v6(true)); target_os = "vita", target_os = "haiku", target_os = "cygwin", + target_os = "wasi", )) ))] test!(IPv6 recv_hoplimit_v6, set_recv_hoplimit_v6(true)); @@ -1616,6 +1641,7 @@ test!(IPv6 multicast_all_v6, set_multicast_all_v6(false)); target_os = "solaris", target_os = "vita", target_os = "cygwin", + target_os = "wasi", )))] fn join_leave_multicast_v4_n() { let socket = Socket::new(Domain::IPV4, Type::DGRAM, None).unwrap(); @@ -1647,6 +1673,7 @@ fn join_leave_multicast_v4_n() { target_os = "redox", target_os = "fuchsia", target_os = "vita", + target_os = "wasi", )))] fn join_leave_ssm_v4() { let socket = Socket::new(Domain::IPV4, Type::DGRAM, None).unwrap(); @@ -1658,7 +1685,7 @@ fn join_leave_ssm_v4() { } #[test] -#[cfg(all(feature = "all", not(target_os = "redox")))] +#[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "wasi"))))] fn header_included() { let socket = match Socket::new(Domain::IPV4, Type::RAW, None) { Ok(socket) => socket, @@ -1690,7 +1717,8 @@ fn header_included() { target_os = "openbsd", target_os = "freebsd", target_os = "dragonfly", - target_os = "netbsd" + target_os = "netbsd", + target_os = "wasi", )) ))] fn header_included_ipv6() {