diff --git a/Cargo.toml b/Cargo.toml index f95929e7..47e96264 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,24 +1,24 @@ [package] -name = "socket2" -version = "0.6.5" -authors = [ +name = "socket2" +version = "0.6.5" +authors = [ "Alex Crichton ", - "Thomas de Zeeuw " + "Thomas de Zeeuw ", ] -license = "MIT OR Apache-2.0" -readme = "README.md" -repository = "https://github.com/rust-lang/socket2" -homepage = "https://github.com/rust-lang/socket2" +license = "MIT OR Apache-2.0" +readme = "README.md" +repository = "https://github.com/rust-lang/socket2" +homepage = "https://github.com/rust-lang/socket2" documentation = "https://docs.rs/socket2" description = """ Utilities for handling networking sockets with a maximal amount of configuration possible intended. """ -keywords = ["io", "socket", "network"] -categories = ["api-bindings", "network-programming"] -edition = "2021" -rust-version = "1.70" -include = [ +keywords = ["io", "socket", "network"] +categories = ["api-bindings", "network-programming"] +edition = "2021" +rust-version = "1.70" +include = [ "Cargo.toml", "LICENSE-APACHE", "LICENSE-MIT", @@ -64,15 +64,16 @@ features = [ [features] # Enable all API, even ones not available on all OSs. +default = ["all"] all = [] [package.metadata.cargo_check_external_types] allowed_external_types = [ # Referenced via a type alias. "libc::socklen_t", - "libc::*::socklen_t", # libc::socklen_t isn't always detected. + "libc::*::socklen_t", # libc::socklen_t isn't always detected. "libc::sa_family_t", - "libc::*::sa_family_t", # libc::sa_family_t is always detected. + "libc::*::sa_family_t", # libc::sa_family_t is always detected. "windows_sys::Win32::Networking::WinSock::socklen_t", "windows_sys::Win32::Networking::WinSock::ADDRESS_FAMILY", ] diff --git a/src/lib.rs b/src/lib.rs index 30eedd62..3d1a75dd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -224,6 +224,14 @@ impl Domain { /// Domain for IPv6 communication, corresponding to `AF_INET6`. pub const IPV6: Domain = Domain(sys::AF_INET6); + /// Domain for IUCV socket communication, corresponding to `AF_IUCV`. + #[cfg(all( + feature = "all", + any(target_arch = "x86_64", target_arch = "s390x"), + target_env = "gnu" + ))] + pub const IUCV: Domain = Domain(sys::AF_IUCV); + /// Domain for Unix socket communication, corresponding to `AF_UNIX`. #[cfg(not(target_os = "wasi"))] pub const UNIX: Domain = Domain(sys::AF_UNIX); diff --git a/src/sockaddr.rs b/src/sockaddr.rs index 120a5466..0b0189a3 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -223,6 +223,19 @@ impl SockAddr { crate::sys::unix_sockaddr(path.as_ref()) } + /// Constructs a `SockAddr` with the family `AF_IUCV` and the provided + /// components. + /// + /// Returns an error if the path is too long. + #[cfg(all( + feature = "all", + any(target_arch = "x86_64", target_arch = "s390x"), + target_env = "gnu" + ))] + pub fn iucv(userid: &str, name: &str) -> io::Result { + crate::sys::iucv_sockaddr(userid, name) + } + /// Set the length of the address. /// /// # Safety @@ -278,6 +291,16 @@ impl SockAddr { self.storage.ss_family == AF_UNIX as sa_family_t } + /// Returns true if this address is of an IUCV socket, false otherwise + #[cfg(all( + feature = "all", + any(target_arch = "x86_64", target_arch = "s390x"), + target_env = "gnu" + ))] + pub const fn is_iucv(&self) -> bool { + self.storage.ss_family == libc::AF_IUCV as sa_family_t + } + /// Returns this address as a `SocketAddr` if it is in the `AF_INET` (IPv4) /// or `AF_INET6` (IPv6) family, otherwise returns `None`. pub fn as_socket(&self) -> Option { diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 65e494bc..9cb0462e 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -79,6 +79,14 @@ pub(crate) use std::ffi::c_int; #[cfg(not(target_os = "wasi"))] pub(crate) use libc::AF_UNIX; pub(crate) use libc::{AF_INET, AF_INET6}; + +#[cfg(all( + feature = "all", + any(target_arch = "x86_64", target_arch = "s390x"), + target_env = "gnu" +))] +pub(crate) use libc::AF_IUCV; + // Used in `Type`. #[cfg(all(feature = "all", target_os = "linux"))] pub(crate) use libc::SOCK_DCCP; @@ -765,6 +773,51 @@ pub(crate) fn unix_sockaddr(path: &Path) -> io::Result { Ok(unsafe { SockAddr::new(storage, len as socklen_t) }) } +#[cfg(all( + feature = "all", + any(target_arch = "x86_64", target_arch = "s390x"), + target_env = "gnu" +))] +fn copy_and_pad_with_spaces(src: &str, target: &mut [libc::c_char; 8]) -> io::Result<()> { + let bytes = src.as_bytes(); + if bytes.len() > target.len() { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "IUCV address component is too long", + )); + } + let mut bytes_iter = bytes.iter(); + for c in target { + if let Some(b) = bytes_iter.next() { + *c = *b as libc::c_char; + } else { + *c = b' ' as libc::c_char; + } + } + Ok(()) +} + +#[cfg(all( + feature = "all", + any(target_arch = "x86_64", target_arch = "s390x"), + target_env = "gnu" +))] +pub(crate) fn iucv_sockaddr(userid: &str, name: &str) -> io::Result { + let mut storage = SockAddrStorage::zeroed(); + { + // SAFETY: sockaddr_iucv is one of the sockaddr_* types defined by this platform. + let storage = unsafe { storage.view_as::() }; + + storage.siucv_family = libc::AF_IUCV as sa_family_t; + // Note that storage.siucv_port is initialized to zero above, which is required for the reserved field + // Note that storage.siucv_addr is initialized to zero above, which is required for the reserved field + storage.siucv_nodeid = [b' ' as libc::c_char; 8]; // Required for the reserved field + copy_and_pad_with_spaces(userid, &mut storage.siucv_user_id)?; + copy_and_pad_with_spaces(name, &mut storage.siucv_name)?; + } + Ok(unsafe { SockAddr::new(storage, mem::size_of::() as socklen_t) }) +} + // Used in `MsgHdr`. #[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))] pub(crate) use libc::msghdr;