Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What libc versions is required as a minimum?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The minimum libc version for the WASI socket2-specific types is 0.2.162 (added in libc PR #3981, which was created specifically for socket2's wasip2 support). The version wasn't changed by this PR — it was already 0.2.172 on master.


[target.'cfg(windows)'.dependencies.windows-sys]
Expand Down
44 changes: 28 additions & 16 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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())
}
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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`.
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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`.
Expand Down Expand Up @@ -361,11 +371,11 @@ impl From<Protocol> 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.
///
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand All @@ -561,15 +573,15 @@ 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,
#[allow(clippy::type_complexity)]
_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)]
Expand Down Expand Up @@ -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)
Expand All @@ -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,
Expand All @@ -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)]
Expand Down Expand Up @@ -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)
Expand Down
22 changes: 16 additions & 6 deletions src/sockaddr.rs
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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<P>(path: P) -> io::Result<SockAddr>
where
P: AsRef<Path>,
Expand Down Expand Up @@ -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
}
Expand All @@ -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 {
Expand Down Expand Up @@ -350,7 +355,10 @@ impl From<SocketAddrV4> 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::<sockaddr_in>() as socklen_t
};
#[cfg(any(
Expand Down Expand Up @@ -385,7 +393,7 @@ impl From<SocketAddrV6> 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();
}
Expand Down Expand Up @@ -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);
Expand All @@ -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());
Expand All @@ -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);
Expand All @@ -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());
Expand Down
Loading