summaryrefslogtreecommitdiffstats
path: root/third_party/rust/nix/src/sys/socket
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/nix/src/sys/socket')
-rw-r--r--third_party/rust/nix/src/sys/socket/addr.rs1408
-rw-r--r--third_party/rust/nix/src/sys/socket/mod.rs1204
-rw-r--r--third_party/rust/nix/src/sys/socket/sockopt.rs631
3 files changed, 3243 insertions, 0 deletions
diff --git a/third_party/rust/nix/src/sys/socket/addr.rs b/third_party/rust/nix/src/sys/socket/addr.rs
new file mode 100644
index 0000000000..9ec668985b
--- /dev/null
+++ b/third_party/rust/nix/src/sys/socket/addr.rs
@@ -0,0 +1,1408 @@
+use super::sa_family_t;
+use {Error, Result, NixPath};
+use errno::Errno;
+use libc;
+use std::{fmt, hash, mem, net, ptr, slice};
+use std::ffi::OsStr;
+use std::path::Path;
+use std::os::unix::ffi::OsStrExt;
+#[cfg(any(target_os = "android", target_os = "linux"))]
+use ::sys::socket::addr::netlink::NetlinkAddr;
+#[cfg(any(target_os = "ios", target_os = "macos"))]
+use std::os::unix::io::RawFd;
+#[cfg(any(target_os = "ios", target_os = "macos"))]
+use ::sys::socket::addr::sys_control::SysControlAddr;
+#[cfg(any(target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+pub use self::datalink::LinkAddr;
+
+/// These constants specify the protocol family to be used
+/// in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html)
+#[repr(i32)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
+pub enum AddressFamily {
+ /// Local communication (see [`unix(7)`](http://man7.org/linux/man-pages/man7/unix.7.html))
+ Unix = libc::AF_UNIX,
+ /// IPv4 Internet protocols (see [`ip(7)`](http://man7.org/linux/man-pages/man7/ip.7.html))
+ Inet = libc::AF_INET,
+ /// IPv6 Internet protocols (see [`ipv6(7)`](http://man7.org/linux/man-pages/man7/ipv6.7.html))
+ Inet6 = libc::AF_INET6,
+ /// Kernel user interface device (see [`netlink(7)`](http://man7.org/linux/man-pages/man7/netlink.7.html))
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Netlink = libc::AF_NETLINK,
+ /// Low level packet interface (see [`packet(7)`](http://man7.org/linux/man-pages/man7/packet.7.html))
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Packet = libc::AF_PACKET,
+ /// KEXT Controls and Notifications
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ System = libc::AF_SYSTEM,
+ /// Amateur radio AX.25 protocol
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Ax25 = libc::AF_AX25,
+ /// IPX - Novell protocols
+ Ipx = libc::AF_IPX,
+ /// AppleTalk
+ AppleTalk = libc::AF_APPLETALK,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ NetRom = libc::AF_NETROM,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Bridge = libc::AF_BRIDGE,
+ /// Access to raw ATM PVCs
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ AtmPvc = libc::AF_ATMPVC,
+ /// ITU-T X.25 / ISO-8208 protocol (see [`x25(7)`](http://man7.org/linux/man-pages/man7/x25.7.html))
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ X25 = libc::AF_X25,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Rose = libc::AF_ROSE,
+ Decnet = libc::AF_DECnet,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ NetBeui = libc::AF_NETBEUI,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Security = libc::AF_SECURITY,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Key = libc::AF_KEY,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Ash = libc::AF_ASH,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Econet = libc::AF_ECONET,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ AtmSvc = libc::AF_ATMSVC,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Rds = libc::AF_RDS,
+ Sna = libc::AF_SNA,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Irda = libc::AF_IRDA,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Pppox = libc::AF_PPPOX,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Wanpipe = libc::AF_WANPIPE,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Llc = libc::AF_LLC,
+ #[cfg(target_os = "linux")]
+ Ib = libc::AF_IB,
+ #[cfg(target_os = "linux")]
+ Mpls = libc::AF_MPLS,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Can = libc::AF_CAN,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Tipc = libc::AF_TIPC,
+ #[cfg(not(any(target_os = "ios", target_os = "macos")))]
+ Bluetooth = libc::AF_BLUETOOTH,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Iucv = libc::AF_IUCV,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ RxRpc = libc::AF_RXRPC,
+ Isdn = libc::AF_ISDN,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Phonet = libc::AF_PHONET,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Ieee802154 = libc::AF_IEEE802154,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Caif = libc::AF_CAIF,
+ /// Interface to kernel crypto API
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Alg = libc::AF_ALG,
+ #[cfg(target_os = "linux")]
+ Nfc = libc::AF_NFC,
+ #[cfg(target_os = "linux")]
+ Vsock = libc::AF_VSOCK,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ ImpLink = libc::AF_IMPLINK,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Pup = libc::AF_PUP,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Chaos = libc::AF_CHAOS,
+ #[cfg(any(target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Ns = libc::AF_NS,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Iso = libc::AF_ISO,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Datakit = libc::AF_DATAKIT,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Ccitt = libc::AF_CCITT,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Dli = libc::AF_DLI,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Lat = libc::AF_LAT,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Hylink = libc::AF_HYLINK,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Link = libc::AF_LINK,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Coip = libc::AF_COIP,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Cnt = libc::AF_CNT,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Natm = libc::AF_NATM,
+ /// Unspecified address family, (see [`getaddrinfo(3)`](http://man7.org/linux/man-pages/man3/getaddrinfo.3.html))
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Unspec = libc::AF_UNSPEC,
+}
+
+impl AddressFamily {
+ /// Create a new `AddressFamily` from an integer value retrieved from `libc`, usually from
+ /// the `sa_family` field of a `sockaddr`.
+ ///
+ /// Currently only supports these address families: Unix, Inet (v4 & v6), Netlink, Link/Packet
+ /// and System. Returns None for unsupported or unknown address families.
+ pub fn from_i32(family: i32) -> Option<AddressFamily> {
+ match family {
+ libc::AF_UNIX => Some(AddressFamily::Unix),
+ libc::AF_INET => Some(AddressFamily::Inet),
+ libc::AF_INET6 => Some(AddressFamily::Inet6),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ libc::AF_NETLINK => Some(AddressFamily::Netlink),
+ #[cfg(any(target_os = "macos", target_os = "macos"))]
+ libc::AF_SYSTEM => Some(AddressFamily::System),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ libc::AF_PACKET => Some(AddressFamily::Packet),
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ libc::AF_LINK => Some(AddressFamily::Link),
+ _ => None
+ }
+ }
+}
+
+#[derive(Copy)]
+pub enum InetAddr {
+ V4(libc::sockaddr_in),
+ V6(libc::sockaddr_in6),
+}
+
+impl InetAddr {
+ pub fn from_std(std: &net::SocketAddr) -> InetAddr {
+ match *std {
+ net::SocketAddr::V4(ref addr) => {
+ InetAddr::V4(libc::sockaddr_in {
+ sin_family: AddressFamily::Inet as sa_family_t,
+ sin_port: addr.port().to_be(), // network byte order
+ sin_addr: Ipv4Addr::from_std(addr.ip()).0,
+ .. unsafe { mem::zeroed() }
+ })
+ }
+ net::SocketAddr::V6(ref addr) => {
+ InetAddr::V6(libc::sockaddr_in6 {
+ sin6_family: AddressFamily::Inet6 as sa_family_t,
+ sin6_port: addr.port().to_be(), // network byte order
+ sin6_addr: Ipv6Addr::from_std(addr.ip()).0,
+ sin6_flowinfo: addr.flowinfo(), // host byte order
+ sin6_scope_id: addr.scope_id(), // host byte order
+ .. unsafe { mem::zeroed() }
+ })
+ }
+ }
+ }
+
+ pub fn new(ip: IpAddr, port: u16) -> InetAddr {
+ match ip {
+ IpAddr::V4(ref ip) => {
+ InetAddr::V4(libc::sockaddr_in {
+ sin_family: AddressFamily::Inet as sa_family_t,
+ sin_port: port.to_be(),
+ sin_addr: ip.0,
+ .. unsafe { mem::zeroed() }
+ })
+ }
+ IpAddr::V6(ref ip) => {
+ InetAddr::V6(libc::sockaddr_in6 {
+ sin6_family: AddressFamily::Inet6 as sa_family_t,
+ sin6_port: port.to_be(),
+ sin6_addr: ip.0,
+ .. unsafe { mem::zeroed() }
+ })
+ }
+ }
+ }
+ /// Gets the IP address associated with this socket address.
+ pub fn ip(&self) -> IpAddr {
+ match *self {
+ InetAddr::V4(ref sa) => IpAddr::V4(Ipv4Addr(sa.sin_addr)),
+ InetAddr::V6(ref sa) => IpAddr::V6(Ipv6Addr(sa.sin6_addr)),
+ }
+ }
+
+ /// Gets the port number associated with this socket address
+ pub fn port(&self) -> u16 {
+ match *self {
+ InetAddr::V6(ref sa) => u16::from_be(sa.sin6_port),
+ InetAddr::V4(ref sa) => u16::from_be(sa.sin_port),
+ }
+ }
+
+ pub fn to_std(&self) -> net::SocketAddr {
+ match *self {
+ InetAddr::V4(ref sa) => net::SocketAddr::V4(
+ net::SocketAddrV4::new(
+ Ipv4Addr(sa.sin_addr).to_std(),
+ self.port())),
+ InetAddr::V6(ref sa) => net::SocketAddr::V6(
+ net::SocketAddrV6::new(
+ Ipv6Addr(sa.sin6_addr).to_std(),
+ self.port(),
+ sa.sin6_flowinfo,
+ sa.sin6_scope_id)),
+ }
+ }
+
+ pub fn to_str(&self) -> String {
+ format!("{}", self)
+ }
+}
+
+impl PartialEq for InetAddr {
+ fn eq(&self, other: &InetAddr) -> bool {
+ match (*self, *other) {
+ (InetAddr::V4(ref a), InetAddr::V4(ref b)) => {
+ a.sin_port == b.sin_port &&
+ a.sin_addr.s_addr == b.sin_addr.s_addr
+ }
+ (InetAddr::V6(ref a), InetAddr::V6(ref b)) => {
+ a.sin6_port == b.sin6_port &&
+ a.sin6_addr.s6_addr == b.sin6_addr.s6_addr &&
+ a.sin6_flowinfo == b.sin6_flowinfo &&
+ a.sin6_scope_id == b.sin6_scope_id
+ }
+ _ => false,
+ }
+ }
+}
+
+impl Eq for InetAddr {
+}
+
+impl hash::Hash for InetAddr {
+ fn hash<H: hash::Hasher>(&self, s: &mut H) {
+ match *self {
+ InetAddr::V4(ref a) => {
+ ( a.sin_family,
+ a.sin_port,
+ a.sin_addr.s_addr ).hash(s)
+ }
+ InetAddr::V6(ref a) => {
+ ( a.sin6_family,
+ a.sin6_port,
+ &a.sin6_addr.s6_addr,
+ a.sin6_flowinfo,
+ a.sin6_scope_id ).hash(s)
+ }
+ }
+ }
+}
+
+impl Clone for InetAddr {
+ fn clone(&self) -> InetAddr {
+ *self
+ }
+}
+
+impl fmt::Display for InetAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ InetAddr::V4(_) => write!(f, "{}:{}", self.ip(), self.port()),
+ InetAddr::V6(_) => write!(f, "[{}]:{}", self.ip(), self.port()),
+ }
+ }
+}
+
+impl fmt::Debug for InetAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+}
+
+/*
+ *
+ * ===== IpAddr =====
+ *
+ */
+#[derive(Clone, Copy)]
+pub enum IpAddr {
+ V4(Ipv4Addr),
+ V6(Ipv6Addr),
+}
+
+impl IpAddr {
+ /// Create a new IpAddr that contains an IPv4 address.
+ ///
+ /// The result will represent the IP address a.b.c.d
+ pub fn new_v4(a: u8, b: u8, c: u8, d: u8) -> IpAddr {
+ IpAddr::V4(Ipv4Addr::new(a, b, c, d))
+ }
+
+ /// Create a new IpAddr that contains an IPv6 address.
+ ///
+ /// The result will represent the IP address a:b:c:d:e:f
+ pub fn new_v6(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> IpAddr {
+ IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h))
+ }
+
+ /*
+ pub fn from_std(std: &net::IpAddr) -> IpAddr {
+ match *std {
+ net::IpAddr::V4(ref std) => IpAddr::V4(Ipv4Addr::from_std(std)),
+ net::IpAddr::V6(ref std) => IpAddr::V6(Ipv6Addr::from_std(std)),
+ }
+ }
+ pub fn to_std(&self) -> net::IpAddr {
+ match *self {
+ IpAddr::V4(ref ip) => net::IpAddr::V4(ip.to_std()),
+ IpAddr::V6(ref ip) => net::IpAddr::V6(ip.to_std()),
+ }
+ }
+ */
+}
+
+impl fmt::Display for IpAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ IpAddr::V4(ref v4) => v4.fmt(f),
+ IpAddr::V6(ref v6) => v6.fmt(f)
+ }
+ }
+}
+
+impl fmt::Debug for IpAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+}
+
+/*
+ *
+ * ===== Ipv4Addr =====
+ *
+ */
+
+#[derive(Copy)]
+pub struct Ipv4Addr(pub libc::in_addr);
+
+impl Ipv4Addr {
+ pub fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
+ let ip = (((a as u32) << 24) |
+ ((b as u32) << 16) |
+ ((c as u32) << 8) |
+ ((d as u32) << 0)).to_be();
+
+ Ipv4Addr(libc::in_addr { s_addr: ip })
+ }
+
+ pub fn from_std(std: &net::Ipv4Addr) -> Ipv4Addr {
+ let bits = std.octets();
+ Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3])
+ }
+
+ pub fn any() -> Ipv4Addr {
+ Ipv4Addr(libc::in_addr { s_addr: libc::INADDR_ANY })
+ }
+
+ pub fn octets(&self) -> [u8; 4] {
+ let bits = u32::from_be(self.0.s_addr);
+ [(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8]
+ }
+
+ pub fn to_std(&self) -> net::Ipv4Addr {
+ let bits = self.octets();
+ net::Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3])
+ }
+}
+
+impl PartialEq for Ipv4Addr {
+ fn eq(&self, other: &Ipv4Addr) -> bool {
+ self.0.s_addr == other.0.s_addr
+ }
+}
+
+impl Eq for Ipv4Addr {
+}
+
+impl hash::Hash for Ipv4Addr {
+ fn hash<H: hash::Hasher>(&self, s: &mut H) {
+ let saddr = self.0.s_addr;
+ saddr.hash(s)
+ }
+}
+
+impl Clone for Ipv4Addr {
+ fn clone(&self) -> Ipv4Addr {
+ *self
+ }
+}
+
+impl fmt::Display for Ipv4Addr {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ let octets = self.octets();
+ write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3])
+ }
+}
+
+impl fmt::Debug for Ipv4Addr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+}
+
+/*
+ *
+ * ===== Ipv6Addr =====
+ *
+ */
+
+#[derive(Clone, Copy)]
+pub struct Ipv6Addr(pub libc::in6_addr);
+
+// Note that IPv6 addresses are stored in big endian order on all architectures.
+// See https://tools.ietf.org/html/rfc1700 or consult your favorite search
+// engine.
+
+macro_rules! to_u8_array {
+ ($($num:ident),*) => {
+ [ $(($num>>8) as u8, ($num&0xff) as u8,)* ]
+ }
+}
+
+macro_rules! to_u16_array {
+ ($slf:ident, $($first:expr, $second:expr),*) => {
+ [$( (($slf.0.s6_addr[$first] as u16) << 8) + $slf.0.s6_addr[$second] as u16,)*]
+ }
+}
+
+impl Ipv6Addr {
+ pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr {
+ let mut in6_addr_var: libc::in6_addr = unsafe{mem::uninitialized()};
+ in6_addr_var.s6_addr = to_u8_array!(a,b,c,d,e,f,g,h);
+ Ipv6Addr(in6_addr_var)
+ }
+
+ pub fn from_std(std: &net::Ipv6Addr) -> Ipv6Addr {
+ let s = std.segments();
+ Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7])
+ }
+
+ /// Return the eight 16-bit segments that make up this address
+ pub fn segments(&self) -> [u16; 8] {
+ to_u16_array!(self, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)
+ }
+
+ pub fn to_std(&self) -> net::Ipv6Addr {
+ let s = self.segments();
+ net::Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7])
+ }
+}
+
+impl fmt::Display for Ipv6Addr {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ self.to_std().fmt(fmt)
+ }
+}
+
+impl fmt::Debug for Ipv6Addr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+}
+
+/*
+ *
+ * ===== UnixAddr =====
+ *
+ */
+
+/// A wrapper around `sockaddr_un`.
+///
+/// This also tracks the length of `sun_path` address (excluding
+/// a terminating null), because it may not be null-terminated. For example,
+/// unconnected and Linux abstract sockets are never null-terminated, and POSIX
+/// does not require that `sun_len` include the terminating null even for normal
+/// sockets. Note that the actual sockaddr length is greater by
+/// `offset_of!(libc::sockaddr_un, sun_path)`
+#[derive(Copy)]
+pub struct UnixAddr(pub libc::sockaddr_un, pub usize);
+
+impl UnixAddr {
+ /// Create a new sockaddr_un representing a filesystem path.
+ pub fn new<P: ?Sized + NixPath>(path: &P) -> Result<UnixAddr> {
+ path.with_nix_path(|cstr| {
+ unsafe {
+ let mut ret = libc::sockaddr_un {
+ sun_family: AddressFamily::Unix as sa_family_t,
+ .. mem::zeroed()
+ };
+
+ let bytes = cstr.to_bytes();
+
+ if bytes.len() > ret.sun_path.len() {
+ return Err(Error::Sys(Errno::ENAMETOOLONG));
+ }
+
+ ptr::copy_nonoverlapping(bytes.as_ptr(),
+ ret.sun_path.as_mut_ptr() as *mut u8,
+ bytes.len());
+
+ Ok(UnixAddr(ret, bytes.len()))
+ }
+ })?
+ }
+
+ /// Create a new `sockaddr_un` representing an address in the "abstract namespace".
+ ///
+ /// The leading null byte for the abstract namespace is automatically added;
+ /// thus the input `path` is expected to be the bare name, not null-prefixed.
+ /// This is a Linux-specific extension, primarily used to allow chrooted
+ /// processes to communicate with processes having a different filesystem view.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ pub fn new_abstract(path: &[u8]) -> Result<UnixAddr> {
+ unsafe {
+ let mut ret = libc::sockaddr_un {
+ sun_family: AddressFamily::Unix as sa_family_t,
+ .. mem::zeroed()
+ };
+
+ if path.len() + 1 > ret.sun_path.len() {
+ return Err(Error::Sys(Errno::ENAMETOOLONG));
+ }
+
+ // Abstract addresses are represented by sun_path[0] ==
+ // b'\0', so copy starting one byte in.
+ ptr::copy_nonoverlapping(path.as_ptr(),
+ ret.sun_path.as_mut_ptr().offset(1) as *mut u8,
+ path.len());
+
+ Ok(UnixAddr(ret, path.len() + 1))
+ }
+ }
+
+ fn sun_path(&self) -> &[u8] {
+ unsafe { slice::from_raw_parts(self.0.sun_path.as_ptr() as *const u8, self.1) }
+ }
+
+ /// If this address represents a filesystem path, return that path.
+ pub fn path(&self) -> Option<&Path> {
+ if self.1 == 0 || self.0.sun_path[0] == 0 {
+ // unnamed or abstract
+ None
+ } else {
+ let p = self.sun_path();
+ // POSIX only requires that `sun_len` be at least long enough to
+ // contain the pathname, and it need not be null-terminated. So we
+ // need to create a string that is the shorter of the
+ // null-terminated length or the full length.
+ let ptr = &self.0.sun_path as *const libc::c_char;
+ let reallen = unsafe { libc::strnlen(ptr, p.len()) };
+ Some(Path::new(<OsStr as OsStrExt>::from_bytes(&p[..reallen])))
+ }
+ }
+
+ /// If this address represents an abstract socket, return its name.
+ ///
+ /// For abstract sockets only the bare name is returned, without the
+ /// leading null byte. `None` is returned for unnamed or path-backed sockets.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ pub fn as_abstract(&self) -> Option<&[u8]> {
+ if self.1 >= 1 && self.0.sun_path[0] == 0 {
+ Some(&self.sun_path()[1..])
+ } else {
+ // unnamed or filesystem path
+ None
+ }
+ }
+}
+
+impl PartialEq for UnixAddr {
+ fn eq(&self, other: &UnixAddr) -> bool {
+ self.sun_path() == other.sun_path()
+ }
+}
+
+impl Eq for UnixAddr {
+}
+
+impl hash::Hash for UnixAddr {
+ fn hash<H: hash::Hasher>(&self, s: &mut H) {
+ ( self.0.sun_family, self.sun_path() ).hash(s)
+ }
+}
+
+impl Clone for UnixAddr {
+ fn clone(&self) -> UnixAddr {
+ *self
+ }
+}
+
+impl fmt::Display for UnixAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ if self.1 == 0 {
+ f.write_str("<unbound UNIX socket>")
+ } else if let Some(path) = self.path() {
+ path.display().fmt(f)
+ } else {
+ let display = String::from_utf8_lossy(&self.sun_path()[1..]);
+ write!(f, "@{}", display)
+ }
+ }
+}
+
+impl fmt::Debug for UnixAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+}
+
+/*
+ *
+ * ===== Sock addr =====
+ *
+ */
+
+/// Represents a socket address
+#[derive(Copy, Debug)]
+pub enum SockAddr {
+ Inet(InetAddr),
+ Unix(UnixAddr),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Netlink(NetlinkAddr),
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ SysControl(SysControlAddr),
+ /// Datalink address (MAC)
+ #[cfg(any(target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Link(LinkAddr)
+}
+
+impl SockAddr {
+ pub fn new_inet(addr: InetAddr) -> SockAddr {
+ SockAddr::Inet(addr)
+ }
+
+ pub fn new_unix<P: ?Sized + NixPath>(path: &P) -> Result<SockAddr> {
+ Ok(SockAddr::Unix(UnixAddr::new(path)?))
+ }
+
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ pub fn new_netlink(pid: u32, groups: u32) -> SockAddr {
+ SockAddr::Netlink(NetlinkAddr::new(pid, groups))
+ }
+
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ pub fn new_sys_control(sockfd: RawFd, name: &str, unit: u32) -> Result<SockAddr> {
+ SysControlAddr::from_name(sockfd, name, unit).map(|a| SockAddr::SysControl(a))
+ }
+
+ pub fn family(&self) -> AddressFamily {
+ match *self {
+ SockAddr::Inet(InetAddr::V4(..)) => AddressFamily::Inet,
+ SockAddr::Inet(InetAddr::V6(..)) => AddressFamily::Inet6,
+ SockAddr::Unix(..) => AddressFamily::Unix,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ SockAddr::Netlink(..) => AddressFamily::Netlink,
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ SockAddr::SysControl(..) => AddressFamily::System,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ SockAddr::Link(..) => AddressFamily::Packet,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ SockAddr::Link(..) => AddressFamily::Link
+ }
+ }
+
+ pub fn to_str(&self) -> String {
+ format!("{}", self)
+ }
+
+ /// Creates a `SockAddr` struct from libc's sockaddr.
+ ///
+ /// Supports only the following address families: Unix, Inet (v4 & v6), Netlink and System.
+ /// Returns None for unsupported families.
+ pub unsafe fn from_libc_sockaddr(addr: *const libc::sockaddr) -> Option<SockAddr> {
+ if addr.is_null() {
+ None
+ } else {
+ match AddressFamily::from_i32((*addr).sa_family as i32) {
+ Some(AddressFamily::Unix) => None,
+ Some(AddressFamily::Inet) => Some(SockAddr::Inet(
+ InetAddr::V4(*(addr as *const libc::sockaddr_in)))),
+ Some(AddressFamily::Inet6) => Some(SockAddr::Inet(
+ InetAddr::V6(*(addr as *const libc::sockaddr_in6)))),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Some(AddressFamily::Netlink) => Some(SockAddr::Netlink(
+ NetlinkAddr(*(addr as *const libc::sockaddr_nl)))),
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ Some(AddressFamily::System) => Some(SockAddr::SysControl(
+ SysControlAddr(*(addr as *const libc::sockaddr_ctl)))),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Some(AddressFamily::Packet) => Some(SockAddr::Link(
+ LinkAddr(*(addr as *const libc::sockaddr_ll)))),
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Some(AddressFamily::Link) => {
+ let ether_addr = LinkAddr(*(addr as *const libc::sockaddr_dl));
+ if ether_addr.is_empty() {
+ None
+ } else {
+ Some(SockAddr::Link(ether_addr))
+ }
+ },
+ // Other address families are currently not supported and simply yield a None
+ // entry instead of a proper conversion to a `SockAddr`.
+ Some(_) | None => None,
+ }
+ }
+ }
+
+ /// Conversion from nix's SockAddr type to the underlying libc sockaddr type.
+ ///
+ /// This is useful for interfacing with other libc functions that don't yet have nix wrappers.
+ /// Returns a reference to the underlying data type (as a sockaddr reference) along
+ /// with the size of the actual data type. sockaddr is commonly used as a proxy for
+ /// a superclass as C doesn't support inheritance, so many functions that take
+ /// a sockaddr * need to take the size of the underlying type as well and then internally cast it back.
+ pub unsafe fn as_ffi_pair(&self) -> (&libc::sockaddr, libc::socklen_t) {
+ match *self {
+ SockAddr::Inet(InetAddr::V4(ref addr)) => (mem::transmute(addr), mem::size_of::<libc::sockaddr_in>() as libc::socklen_t),
+ SockAddr::Inet(InetAddr::V6(ref addr)) => (mem::transmute(addr), mem::size_of::<libc::sockaddr_in6>() as libc::socklen_t),
+ SockAddr::Unix(UnixAddr(ref addr, len)) => (mem::transmute(addr), (len + offset_of!(libc::sockaddr_un, sun_path)) as libc::socklen_t),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ SockAddr::Netlink(NetlinkAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t),
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ SockAddr::SysControl(SysControlAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_ctl>() as libc::socklen_t),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ SockAddr::Link(LinkAddr(ref ether_addr)) => (mem::transmute(ether_addr), mem::size_of::<libc::sockaddr_ll>() as libc::socklen_t),
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ SockAddr::Link(LinkAddr(ref ether_addr)) => (mem::transmute(ether_addr), mem::size_of::<libc::sockaddr_dl>() as libc::socklen_t),
+ }
+ }
+}
+
+impl PartialEq for SockAddr {
+ fn eq(&self, other: &SockAddr) -> bool {
+ match (*self, *other) {
+ (SockAddr::Inet(ref a), SockAddr::Inet(ref b)) => {
+ a == b
+ }
+ (SockAddr::Unix(ref a), SockAddr::Unix(ref b)) => {
+ a == b
+ }
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ (SockAddr::Netlink(ref a), SockAddr::Netlink(ref b)) => {
+ a == b
+ }
+ #[cfg(any(target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ (SockAddr::Link(ref a), SockAddr::Link(ref b)) => {
+ a == b
+ }
+ _ => false,
+ }
+ }
+}
+
+impl Eq for SockAddr {
+}
+
+impl hash::Hash for SockAddr {
+ fn hash<H: hash::Hasher>(&self, s: &mut H) {
+ match *self {
+ SockAddr::Inet(ref a) => a.hash(s),
+ SockAddr::Unix(ref a) => a.hash(s),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ SockAddr::Netlink(ref a) => a.hash(s),
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ SockAddr::SysControl(ref a) => a.hash(s),
+ #[cfg(any(target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ SockAddr::Link(ref ether_addr) => ether_addr.hash(s)
+ }
+ }
+}
+
+impl Clone for SockAddr {
+ fn clone(&self) -> SockAddr {
+ *self
+ }
+}
+
+impl fmt::Display for SockAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ SockAddr::Inet(ref inet) => inet.fmt(f),
+ SockAddr::Unix(ref unix) => unix.fmt(f),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ SockAddr::Netlink(ref nl) => nl.fmt(f),
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ SockAddr::SysControl(ref sc) => sc.fmt(f),
+ #[cfg(any(target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ SockAddr::Link(ref ether_addr) => ether_addr.fmt(f)
+ }
+ }
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+pub mod netlink {
+ use ::sys::socket::addr::AddressFamily;
+ use libc::{sa_family_t, sockaddr_nl};
+ use std::{fmt, mem};
+ use std::hash::{Hash, Hasher};
+
+ #[derive(Copy, Clone)]
+ pub struct NetlinkAddr(pub sockaddr_nl);
+
+ // , PartialEq, Eq, Debug, Hash
+ impl PartialEq for NetlinkAddr {
+ fn eq(&self, other: &Self) -> bool {
+ let (inner, other) = (self.0, other.0);
+ (inner.nl_family, inner.nl_pid, inner.nl_groups) ==
+ (other.nl_family, other.nl_pid, other.nl_groups)
+ }
+ }
+
+ impl Eq for NetlinkAddr {}
+
+ impl Hash for NetlinkAddr {
+ fn hash<H: Hasher>(&self, s: &mut H) {
+ let inner = self.0;
+ (inner.nl_family, inner.nl_pid, inner.nl_groups).hash(s);
+ }
+ }
+
+
+ impl NetlinkAddr {
+ pub fn new(pid: u32, groups: u32) -> NetlinkAddr {
+ let mut addr: sockaddr_nl = unsafe { mem::zeroed() };
+ addr.nl_family = AddressFamily::Netlink as sa_family_t;
+ addr.nl_pid = pid;
+ addr.nl_groups = groups;
+
+ NetlinkAddr(addr)
+ }
+
+ pub fn pid(&self) -> u32 {
+ self.0.nl_pid
+ }
+
+ pub fn groups(&self) -> u32 {
+ self.0.nl_groups
+ }
+ }
+
+ impl fmt::Display for NetlinkAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "pid: {} groups: {}", self.pid(), self.groups())
+ }
+ }
+
+ impl fmt::Debug for NetlinkAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+ }
+}
+
+#[cfg(any(target_os = "ios", target_os = "macos"))]
+pub mod sys_control {
+ use ::sys::socket::addr::AddressFamily;
+ use libc::{self, c_uchar};
+ use std::{fmt, mem};
+ use std::hash::{Hash, Hasher};
+ use std::os::unix::io::RawFd;
+ use {Errno, Error, Result};
+
+ #[repr(C)]
+ pub struct ctl_ioc_info {
+ pub ctl_id: u32,
+ pub ctl_name: [c_uchar; MAX_KCTL_NAME],
+ }
+
+ const CTL_IOC_MAGIC: u8 = 'N' as u8;
+ const CTL_IOC_INFO: u8 = 3;
+ const MAX_KCTL_NAME: usize = 96;
+
+ ioctl_readwrite!(ctl_info, CTL_IOC_MAGIC, CTL_IOC_INFO, ctl_ioc_info);
+
+ #[derive(Copy, Clone)]
+ #[repr(C)]
+ pub struct SysControlAddr(pub libc::sockaddr_ctl);
+
+ impl PartialEq for SysControlAddr {
+ fn eq(&self, other: &Self) -> bool {
+ let (inner, other) = (self.0, other.0);
+ (inner.sc_id, inner.sc_unit) ==
+ (other.sc_id, other.sc_unit)
+ }
+ }
+
+ impl Eq for SysControlAddr {}
+
+ impl Hash for SysControlAddr {
+ fn hash<H: Hasher>(&self, s: &mut H) {
+ let inner = self.0;
+ (inner.sc_id, inner.sc_unit).hash(s);
+ }
+ }
+
+
+ impl SysControlAddr {
+ pub fn new(id: u32, unit: u32) -> SysControlAddr {
+ let addr = libc::sockaddr_ctl {
+ sc_len: mem::size_of::<libc::sockaddr_ctl>() as c_uchar,
+ sc_family: AddressFamily::System as c_uchar,
+ ss_sysaddr: libc::AF_SYS_CONTROL as u16,
+ sc_id: id,
+ sc_unit: unit,
+ sc_reserved: [0; 5]
+ };
+
+ SysControlAddr(addr)
+ }
+
+ pub fn from_name(sockfd: RawFd, name: &str, unit: u32) -> Result<SysControlAddr> {
+ if name.len() > MAX_KCTL_NAME {
+ return Err(Error::Sys(Errno::ENAMETOOLONG));
+ }
+
+ let mut ctl_name = [0; MAX_KCTL_NAME];
+ ctl_name[..name.len()].clone_from_slice(name.as_bytes());
+ let mut info = ctl_ioc_info { ctl_id: 0, ctl_name: ctl_name };
+
+ unsafe { ctl_info(sockfd, &mut info)?; }
+
+ Ok(SysControlAddr::new(info.ctl_id, unit))
+ }
+
+ pub fn id(&self) -> u32 {
+ self.0.sc_id
+ }
+
+ pub fn unit(&self) -> u32 {
+ self.0.sc_unit
+ }
+ }
+
+ impl fmt::Display for SysControlAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(self, f)
+ }
+ }
+
+ impl fmt::Debug for SysControlAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("SysControlAddr")
+ .field("sc_len", &self.0.sc_len)
+ .field("sc_family", &self.0.sc_family)
+ .field("ss_sysaddr", &self.0.ss_sysaddr)
+ .field("sc_id", &self.0.sc_id)
+ .field("sc_unit", &self.0.sc_unit)
+ .finish()
+ }
+ }
+}
+
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+mod datalink {
+ use super::{libc, hash, fmt, AddressFamily};
+
+ /// Hardware Address
+ #[derive(Clone, Copy)]
+ pub struct LinkAddr(pub libc::sockaddr_ll);
+
+ impl LinkAddr {
+ /// Always AF_PACKET
+ pub fn family(&self) -> AddressFamily {
+ assert_eq!(self.0.sll_family as i32, libc::AF_PACKET);
+ AddressFamily::Packet
+ }
+
+ /// Physical-layer protocol
+ pub fn protocol(&self) -> u16 {
+ self.0.sll_protocol
+ }
+
+ /// Interface number
+ pub fn ifindex(&self) -> usize {
+ self.0.sll_ifindex as usize
+ }
+
+ /// ARP hardware type
+ pub fn hatype(&self) -> u16 {
+ self.0.sll_hatype
+ }
+
+ /// Packet type
+ pub fn pkttype(&self) -> u8 {
+ self.0.sll_pkttype
+ }
+
+ /// Length of MAC address
+ pub fn halen(&self) -> usize {
+ self.0.sll_halen as usize
+ }
+
+ /// Physical-layer address (MAC)
+ pub fn addr(&self) -> [u8; 6] {
+ let a = self.0.sll_addr[0] as u8;
+ let b = self.0.sll_addr[1] as u8;
+ let c = self.0.sll_addr[2] as u8;
+ let d = self.0.sll_addr[3] as u8;
+ let e = self.0.sll_addr[4] as u8;
+ let f = self.0.sll_addr[5] as u8;
+
+ [a, b, c, d, e, f]
+ }
+ }
+
+ impl Eq for LinkAddr {}
+
+ impl PartialEq for LinkAddr {
+ fn eq(&self, other: &Self) -> bool {
+ let (a, b) = (self.0, other.0);
+ (a.sll_family, a.sll_protocol, a.sll_ifindex, a.sll_hatype,
+ a.sll_pkttype, a.sll_halen, a.sll_addr) ==
+ (b.sll_family, b.sll_protocol, b.sll_ifindex, b.sll_hatype,
+ b.sll_pkttype, b.sll_halen, b.sll_addr)
+ }
+ }
+
+ impl hash::Hash for LinkAddr {
+ fn hash<H: hash::Hasher>(&self, s: &mut H) {
+ let a = self.0;
+ (a.sll_family, a.sll_protocol, a.sll_ifindex, a.sll_hatype,
+ a.sll_pkttype, a.sll_halen, a.sll_addr).hash(s);
+ }
+ }
+
+ impl fmt::Display for LinkAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let addr = self.addr();
+ write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
+ addr[0],
+ addr[1],
+ addr[2],
+ addr[3],
+ addr[4],
+ addr[5])
+ }
+ }
+
+ impl fmt::Debug for LinkAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+ }
+}
+
+#[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+mod datalink {
+ use super::{libc, hash, fmt, AddressFamily};
+
+ /// Hardware Address
+ #[derive(Clone, Copy)]
+ pub struct LinkAddr(pub libc::sockaddr_dl);
+
+ impl LinkAddr {
+ /// Total length of sockaddr
+ pub fn len(&self) -> usize {
+ self.0.sdl_len as usize
+ }
+
+ /// always == AF_LINK
+ pub fn family(&self) -> AddressFamily {
+ assert_eq!(self.0.sdl_family as i32, libc::AF_LINK);
+ AddressFamily::Link
+ }
+
+ /// interface index, if != 0, system given index for interface
+ pub fn ifindex(&self) -> usize {
+ self.0.sdl_index as usize
+ }
+
+ /// Datalink type
+ pub fn datalink_type(&self) -> u8 {
+ self.0.sdl_type
+ }
+
+ // MAC address start position
+ pub fn nlen(&self) -> usize {
+ self.0.sdl_nlen as usize
+ }
+
+ /// link level address length
+ pub fn alen(&self) -> usize {
+ self.0.sdl_alen as usize
+ }
+
+ /// link layer selector length
+ pub fn slen(&self) -> usize {
+ self.0.sdl_slen as usize
+ }
+
+ /// if link level address length == 0,
+ /// or `sdl_data` not be larger.
+ pub fn is_empty(&self) -> bool {
+ let nlen = self.nlen();
+ let alen = self.alen();
+ let data_len = self.0.sdl_data.len();
+
+ if alen > 0 && nlen + alen < data_len {
+ false
+ } else {
+ true
+ }
+ }
+
+ /// Physical-layer address (MAC)
+ pub fn addr(&self) -> [u8; 6] {
+ let nlen = self.nlen();
+ let data = self.0.sdl_data;
+
+ assert!(!self.is_empty());
+
+ let a = data[nlen] as u8;
+ let b = data[nlen + 1] as u8;
+ let c = data[nlen + 2] as u8;
+ let d = data[nlen + 3] as u8;
+ let e = data[nlen + 4] as u8;
+ let f = data[nlen + 5] as u8;
+
+ [a, b, c, d, e, f]
+ }
+ }
+
+ impl Eq for LinkAddr {}
+
+ impl PartialEq for LinkAddr {
+ #[cfg(any(target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ fn eq(&self, other: &Self) -> bool {
+ let (a, b) = (self.0, other.0);
+ (a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type,
+ a.sdl_nlen, a.sdl_alen, a.sdl_slen, &a.sdl_data[..]) ==
+ (b.sdl_len, b.sdl_family, b.sdl_index, b.sdl_type,
+ b.sdl_nlen, b.sdl_alen, b.sdl_slen, &b.sdl_data[..])
+ }
+
+ #[cfg(target_os = "dragonfly")]
+ fn eq(&self, other: &Self) -> bool {
+ let (a, b) = (self.0, other.0);
+ (a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type, a.sdl_nlen,
+ a.sdl_alen, a.sdl_slen, a.sdl_data, a.sdl_rcf, a.sdl_route) ==
+ (b.sdl_len, b.sdl_family, b.sdl_index, b.sdl_type, b.sdl_nlen,
+ b.sdl_alen, b.sdl_slen, b.sdl_data, b.sdl_rcf, b.sdl_route)
+ }
+ }
+
+ impl hash::Hash for LinkAddr {
+ #[cfg(any(target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ fn hash<H: hash::Hasher>(&self, s: &mut H) {
+ let a = self.0;
+ (a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type,
+ a.sdl_nlen, a.sdl_alen, a.sdl_slen, &a.sdl_data[..]).hash(s);
+ }
+
+ #[cfg(target_os = "dragonfly")]
+ fn hash<H: hash::Hasher>(&self, s: &mut H) {
+ let a = self.0;
+ (a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type, a.sdl_nlen,
+ a.sdl_alen, a.sdl_slen, a.sdl_data, a.sdl_rcf, a.sdl_route).hash(s);
+ }
+ }
+
+ impl fmt::Display for LinkAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let addr = self.addr();
+ write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
+ addr[0],
+ addr[1],
+ addr[2],
+ addr[3],
+ addr[4],
+ addr[5])
+ }
+ }
+
+ impl fmt::Debug for LinkAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ use super::*;
+
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ #[test]
+ fn test_macos_loopback_datalink_addr() {
+ let bytes = [20i8, 18, 1, 0, 24, 3, 0, 0, 108, 111, 48, 0, 0, 0, 0, 0];
+ let sa = bytes.as_ptr() as *const libc::sockaddr;
+ let _sock_addr = unsafe { SockAddr::from_libc_sockaddr(sa) };
+ assert!(_sock_addr.is_none());
+ }
+
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ #[test]
+ fn test_macos_tap_datalink_addr() {
+ let bytes = [20i8, 18, 7, 0, 6, 3, 6, 0, 101, 110, 48, 24, 101, -112, -35, 76, -80];
+ let ptr = bytes.as_ptr();
+ let sa = ptr as *const libc::sockaddr;
+ let _sock_addr = unsafe { SockAddr::from_libc_sockaddr(sa) };
+
+ assert!(_sock_addr.is_some());
+
+ let sock_addr = _sock_addr.unwrap();
+
+ assert_eq!(sock_addr.family(), AddressFamily::Link);
+
+ match sock_addr {
+ SockAddr::Link(ether_addr) => {
+ assert_eq!(ether_addr.addr(), [24u8, 101, 144, 221, 76, 176]);
+ },
+ _ => { unreachable!() }
+ };
+ }
+}
diff --git a/third_party/rust/nix/src/sys/socket/mod.rs b/third_party/rust/nix/src/sys/socket/mod.rs
new file mode 100644
index 0000000000..62c0ea7412
--- /dev/null
+++ b/third_party/rust/nix/src/sys/socket/mod.rs
@@ -0,0 +1,1204 @@
+//! Socket interface functions
+//!
+//! [Further reading](http://man7.org/linux/man-pages/man7/socket.7.html)
+use {Error, Result};
+use errno::Errno;
+use libc::{self, c_void, c_int, socklen_t, size_t};
+use std::{fmt, mem, ptr, slice};
+use std::os::unix::io::RawFd;
+use sys::time::TimeVal;
+use sys::uio::IoVec;
+
+mod addr;
+pub mod sockopt;
+
+/*
+ *
+ * ===== Re-exports =====
+ *
+ */
+
+pub use self::addr::{
+ AddressFamily,
+ SockAddr,
+ InetAddr,
+ UnixAddr,
+ IpAddr,
+ Ipv4Addr,
+ Ipv6Addr,
+ LinkAddr,
+};
+#[cfg(any(target_os = "android", target_os = "linux"))]
+pub use ::sys::socket::addr::netlink::NetlinkAddr;
+
+pub use libc::{
+ cmsghdr,
+ msghdr,
+ sa_family_t,
+ sockaddr,
+ sockaddr_in,
+ sockaddr_in6,
+ sockaddr_storage,
+ sockaddr_un,
+};
+
+/// These constants are used to specify the communication semantics
+/// when creating a socket with [`socket()`](fn.socket.html)
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+#[repr(i32)]
+pub enum SockType {
+ /// Provides sequenced, reliable, two-way, connection-
+ /// based byte streams. An out-of-band data transmission
+ /// mechanism may be supported.
+ Stream = libc::SOCK_STREAM,
+ /// Supports datagrams (connectionless, unreliable
+ /// messages of a fixed maximum length).
+ Datagram = libc::SOCK_DGRAM,
+ /// Provides a sequenced, reliable, two-way connection-
+ /// based data transmission path for datagrams of fixed
+ /// maximum length; a consumer is required to read an
+ /// entire packet with each input system call.
+ SeqPacket = libc::SOCK_SEQPACKET,
+ /// Provides raw network protocol access.
+ Raw = libc::SOCK_RAW,
+ /// Provides a reliable datagram layer that does not
+ /// guarantee ordering.
+ Rdm = libc::SOCK_RDM,
+}
+
+/// Constants used in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html)
+/// to specify the protocol to use.
+#[repr(i32)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+pub enum SockProtocol {
+ /// TCP protocol ([ip(7)](http://man7.org/linux/man-pages/man7/ip.7.html))
+ Tcp = libc::IPPROTO_TCP,
+ /// UDP protocol ([ip(7)](http://man7.org/linux/man-pages/man7/ip.7.html))
+ Udp = libc::IPPROTO_UDP,
+ /// Allows applications and other KEXTs to be notified when certain kernel events occur
+ /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html))
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ KextEvent = libc::SYSPROTO_EVENT,
+ /// Allows applications to configure and control a KEXT
+ /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html))
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ KextControl = libc::SYSPROTO_CONTROL,
+}
+
+libc_bitflags!{
+ /// Additional socket options
+ pub struct SockFlag: c_int {
+ /// Set non-blocking mode on the new socket
+ #[cfg(any(target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ SOCK_NONBLOCK;
+ /// Set close-on-exec on the new descriptor
+ #[cfg(any(target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ SOCK_CLOEXEC;
+ /// Return `EPIPE` instead of raising `SIGPIPE`
+ #[cfg(target_os = "netbsd")]
+ SOCK_NOSIGPIPE;
+ /// For domains `AF_INET(6)`, only allow `connect(2)`, `sendto(2)`, or `sendmsg(2)`
+ /// to the DNS port (typically 53)
+ #[cfg(target_os = "openbsd")]
+ SOCK_DNS;
+ }
+}
+
+libc_bitflags!{
+ /// Flags for send/recv and their relatives
+ pub struct MsgFlags: c_int {
+ /// Sends or requests out-of-band data on sockets that support this notion
+ /// (e.g., of type [`Stream`](enum.SockType.html)); the underlying protocol must also
+ /// support out-of-band data.
+ MSG_OOB;
+ /// Peeks at an incoming message. The data is treated as unread and the next
+ /// [`recv()`](fn.recv.html)
+ /// or similar function shall still return this data.
+ MSG_PEEK;
+ /// Enables nonblocking operation; if the operation would block,
+ /// `EAGAIN` or `EWOULDBLOCK` is returned. This provides similar
+ /// behavior to setting the `O_NONBLOCK` flag
+ /// (via the [`fcntl`](../../fcntl/fn.fcntl.html)
+ /// `F_SETFL` operation), but differs in that `MSG_DONTWAIT` is a per-
+ /// call option, whereas `O_NONBLOCK` is a setting on the open file
+ /// description (see [open(2)](http://man7.org/linux/man-pages/man2/open.2.html)),
+ /// which will affect all threads in
+ /// the calling process and as well as other processes that hold
+ /// file descriptors referring to the same open file description.
+ MSG_DONTWAIT;
+ /// Receive flags: Control Data was discarded (buffer too small)
+ MSG_CTRUNC;
+ /// For raw ([`Packet`](addr/enum.AddressFamily.html)), Internet datagram
+ /// (since Linux 2.4.27/2.6.8),
+ /// netlink (since Linux 2.6.22) and UNIX datagram (since Linux 3.4)
+ /// sockets: return the real length of the packet or datagram, even
+ /// when it was longer than the passed buffer. Not implemented for UNIX
+ /// domain ([unix(7)](https://linux.die.net/man/7/unix)) sockets.
+ ///
+ /// For use with Internet stream sockets, see [tcp(7)](https://linux.die.net/man/7/tcp).
+ MSG_TRUNC;
+ /// Terminates a record (when this notion is supported, as for
+ /// sockets of type [`SeqPacket`](enum.SockType.html)).
+ MSG_EOR;
+ /// This flag specifies that queued errors should be received from
+ /// the socket error queue. (For more details, see
+ /// [recvfrom(2)](https://linux.die.net/man/2/recvfrom))
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ MSG_ERRQUEUE;
+ /// Set the `close-on-exec` flag for the file descriptor received via a UNIX domain
+ /// file descriptor using the `SCM_RIGHTS` operation (described in
+ /// [unix(7)](https://linux.die.net/man/7/unix)).
+ /// This flag is useful for the same reasons as the `O_CLOEXEC` flag of
+ /// [open(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html).
+ ///
+ /// Only used in [`recvmsg`](fn.recvmsg.html) function.
+ #[cfg(any(target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ MSG_CMSG_CLOEXEC;
+ }
+}
+
+cfg_if! {
+ if #[cfg(any(target_os = "android", target_os = "linux"))] {
+ /// Unix credentials of the sending process.
+ ///
+ /// This struct is used with the `SO_PEERCRED` ancillary message for UNIX sockets.
+ #[repr(C)]
+ #[derive(Clone, Copy)]
+ pub struct UnixCredentials(libc::ucred);
+
+ impl UnixCredentials {
+ /// Returns the process identifier
+ pub fn pid(&self) -> libc::pid_t {
+ self.0.pid
+ }
+
+ /// Returns the user identifier
+ pub fn uid(&self) -> libc::uid_t {
+ self.0.uid
+ }
+
+ /// Returns the group identifier
+ pub fn gid(&self) -> libc::gid_t {
+ self.0.gid
+ }
+ }
+
+ impl PartialEq for UnixCredentials {
+ fn eq(&self, other: &Self) -> bool {
+ self.0.pid == other.0.pid && self.0.uid == other.0.uid && self.0.gid == other.0.gid
+ }
+ }
+ impl Eq for UnixCredentials {}
+
+ impl From<libc::ucred> for UnixCredentials {
+ fn from(cred: libc::ucred) -> Self {
+ UnixCredentials(cred)
+ }
+ }
+
+ impl Into<libc::ucred> for UnixCredentials {
+ fn into(self) -> libc::ucred {
+ self.0
+ }
+ }
+
+ impl fmt::Debug for UnixCredentials {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("UnixCredentials")
+ .field("pid", &self.0.pid)
+ .field("uid", &self.0.uid)
+ .field("gid", &self.0.gid)
+ .finish()
+ }
+ }
+ }
+}
+
+/// Request for multicast socket operations
+///
+/// This is a wrapper type around `ip_mreq`.
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub struct IpMembershipRequest(libc::ip_mreq);
+
+impl IpMembershipRequest {
+ /// Instantiate a new `IpMembershipRequest`
+ ///
+ /// If `interface` is `None`, then `Ipv4Addr::any()` will be used for the interface.
+ pub fn new(group: Ipv4Addr, interface: Option<Ipv4Addr>) -> Self {
+ IpMembershipRequest(libc::ip_mreq {
+ imr_multiaddr: group.0,
+ imr_interface: interface.unwrap_or_else(Ipv4Addr::any).0,
+ })
+ }
+}
+
+impl PartialEq for IpMembershipRequest {
+ fn eq(&self, other: &Self) -> bool {
+ self.0.imr_multiaddr.s_addr == other.0.imr_multiaddr.s_addr
+ && self.0.imr_interface.s_addr == other.0.imr_interface.s_addr
+ }
+}
+impl Eq for IpMembershipRequest {}
+
+impl fmt::Debug for IpMembershipRequest {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let mref = &self.0.imr_multiaddr;
+ let maddr = mref.s_addr;
+ let iref = &self.0.imr_interface;
+ let ifaddr = iref.s_addr;
+ f.debug_struct("IpMembershipRequest")
+ .field("imr_multiaddr", &maddr)
+ .field("imr_interface", &ifaddr)
+ .finish()
+ }
+}
+
+/// Request for ipv6 multicast socket operations
+///
+/// This is a wrapper type around `ipv6_mreq`.
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub struct Ipv6MembershipRequest(libc::ipv6_mreq);
+
+impl Ipv6MembershipRequest {
+ /// Instantiate a new `Ipv6MembershipRequest`
+ pub fn new(group: Ipv6Addr) -> Self {
+ Ipv6MembershipRequest(libc::ipv6_mreq {
+ ipv6mr_multiaddr: group.0,
+ ipv6mr_interface: 0,
+ })
+ }
+}
+
+impl PartialEq for Ipv6MembershipRequest {
+ fn eq(&self, other: &Self) -> bool {
+ self.0.ipv6mr_multiaddr.s6_addr == other.0.ipv6mr_multiaddr.s6_addr &&
+ self.0.ipv6mr_interface == other.0.ipv6mr_interface
+ }
+}
+impl Eq for Ipv6MembershipRequest {}
+
+impl fmt::Debug for Ipv6MembershipRequest {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("Ipv6MembershipRequest")
+ .field("ipv6mr_multiaddr", &self.0.ipv6mr_multiaddr.s6_addr)
+ .field("ipv6mr_interface", &self.0.ipv6mr_interface)
+ .finish()
+ }
+}
+
+/// Copy the in-memory representation of `src` into the byte slice `dst`.
+///
+/// Returns the remainder of `dst`.
+///
+/// Panics when `dst` is too small for `src` (more precisely, panics if
+/// `mem::size_of_val(src) >= dst.len()`).
+///
+/// Unsafe because it transmutes `src` to raw bytes, which is only safe for some
+/// types `T`. Refer to the [Rustonomicon] for details.
+///
+/// [Rustonomicon]: https://doc.rust-lang.org/nomicon/transmutes.html
+unsafe fn copy_bytes<'a, T: ?Sized>(src: &T, dst: &'a mut [u8]) -> &'a mut [u8] {
+ let srclen = mem::size_of_val(src);
+ ptr::copy_nonoverlapping(
+ src as *const T as *const u8,
+ dst[..srclen].as_mut_ptr(),
+ srclen
+ );
+
+ &mut dst[srclen..]
+}
+
+/// Fills `dst` with `len` zero bytes and returns the remainder of the slice.
+///
+/// Panics when `len >= dst.len()`.
+fn pad_bytes(len: usize, dst: &mut [u8]) -> &mut [u8] {
+ for pad in &mut dst[..len] {
+ *pad = 0;
+ }
+
+ &mut dst[len..]
+}
+
+cfg_if! {
+ // Darwin and DragonFly BSD always align struct cmsghdr to 32-bit only.
+ if #[cfg(any(target_os = "dragonfly", target_os = "ios", target_os = "macos"))] {
+ type align_of_cmsg_data = u32;
+ } else {
+ type align_of_cmsg_data = size_t;
+ }
+}
+
+/// A structure used to make room in a cmsghdr passed to recvmsg. The
+/// size and alignment match that of a cmsghdr followed by a T, but the
+/// fields are not accessible, as the actual types will change on a call
+/// to recvmsg.
+///
+/// To make room for multiple messages, nest the type parameter with
+/// tuples:
+///
+/// ```
+/// use std::os::unix::io::RawFd;
+/// use nix::sys::socket::CmsgSpace;
+/// let cmsg: CmsgSpace<([RawFd; 3], CmsgSpace<[RawFd; 2]>)> = CmsgSpace::new();
+/// ```
+#[repr(C)]
+#[allow(missing_debug_implementations)]
+pub struct CmsgSpace<T> {
+ _hdr: cmsghdr,
+ _pad: [align_of_cmsg_data; 0],
+ _data: T,
+}
+
+impl<T> CmsgSpace<T> {
+ /// Create a CmsgSpace<T>. The structure is used only for space, so
+ /// the fields are uninitialized.
+ pub fn new() -> Self {
+ // Safe because the fields themselves aren't accessible.
+ unsafe { mem::uninitialized() }
+ }
+}
+
+#[derive(Debug)]
+pub struct RecvMsg<'a> {
+ // The number of bytes received.
+ pub bytes: usize,
+ cmsg_buffer: &'a [u8],
+ pub address: Option<SockAddr>,
+ pub flags: MsgFlags,
+}
+
+impl<'a> RecvMsg<'a> {
+ /// Iterate over the valid control messages pointed to by this
+ /// msghdr.
+ pub fn cmsgs(&self) -> CmsgIterator {
+ CmsgIterator {
+ buf: self.cmsg_buffer,
+ }
+ }
+}
+
+#[derive(Debug)]
+pub struct CmsgIterator<'a> {
+ /// Control message buffer to decode from. Must adhere to cmsg alignment.
+ buf: &'a [u8],
+}
+
+impl<'a> Iterator for CmsgIterator<'a> {
+ type Item = ControlMessage<'a>;
+
+ // The implementation loosely follows CMSG_FIRSTHDR / CMSG_NXTHDR,
+ // although we handle the invariants in slightly different places to
+ // get a better iterator interface.
+ fn next(&mut self) -> Option<ControlMessage<'a>> {
+ if self.buf.len() == 0 {
+ // The iterator assumes that `self.buf` always contains exactly the
+ // bytes we need, so we're at the end when the buffer is empty.
+ return None;
+ }
+
+ // Safe if: `self.buf` is `cmsghdr`-aligned.
+ let cmsg: &'a cmsghdr = unsafe {
+ &*(self.buf[..mem::size_of::<cmsghdr>()].as_ptr() as *const cmsghdr)
+ };
+
+ let cmsg_len = cmsg.cmsg_len as usize;
+
+ // Advance our internal pointer.
+ let cmsg_data = &self.buf[cmsg_align(mem::size_of::<cmsghdr>())..cmsg_len];
+ self.buf = &self.buf[cmsg_align(cmsg_len)..];
+
+ // Safe if: `cmsg_data` contains the expected (amount of) content. This
+ // is verified by the kernel.
+ unsafe {
+ Some(ControlMessage::decode_from(cmsg, cmsg_data))
+ }
+ }
+}
+
+/// A type-safe wrapper around a single control message. More types may
+/// be added to this enum; do not exhaustively pattern-match it.
+/// [Further reading](http://man7.org/linux/man-pages/man3/cmsg.3.html)
+#[allow(missing_debug_implementations)]
+pub enum ControlMessage<'a> {
+ /// A message of type `SCM_RIGHTS`, containing an array of file
+ /// descriptors passed between processes.
+ ///
+ /// See the description in the "Ancillary messages" section of the
+ /// [unix(7) man page](http://man7.org/linux/man-pages/man7/unix.7.html).
+ ///
+ /// Using multiple `ScmRights` messages for a single `sendmsg` call isn't recommended since it
+ /// causes platform-dependent behaviour: It might swallow all but the first `ScmRights` message
+ /// or fail with `EINVAL`. Instead, you can put all fds to be passed into a single `ScmRights`
+ /// message.
+ ScmRights(&'a [RawFd]),
+ /// A message of type `SCM_CREDENTIALS`, containing the pid, uid and gid of
+ /// a process connected to the socket.
+ ///
+ /// This is similar to the socket option `SO_PEERCRED`, but requires a
+ /// process to explicitly send its credentials. A process running as root is
+ /// allowed to specify any credentials, while credentials sent by other
+ /// processes are verified by the kernel.
+ ///
+ /// For further information, please refer to the
+ /// [`unix(7)`](http://man7.org/linux/man-pages/man7/unix.7.html) man page.
+ // FIXME: When `#[repr(transparent)]` is stable, use it on `UnixCredentials`
+ // and put that in here instead of a raw ucred.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ ScmCredentials(&'a libc::ucred),
+ /// A message of type `SCM_TIMESTAMP`, containing the time the
+ /// packet was received by the kernel.
+ ///
+ /// See the kernel's explanation in "SO_TIMESTAMP" of
+ /// [networking/timestamping](https://www.kernel.org/doc/Documentation/networking/timestamping.txt).
+ ///
+ /// # Examples
+ ///
+ // Disable this test on FreeBSD i386
+ // https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=222039
+ #[cfg_attr(not(all(target_os = "freebsd", target_arch = "x86")), doc = " ```")]
+ #[cfg_attr(all(target_os = "freebsd", target_arch = "x86"), doc = " ```no_run")]
+ /// use nix::sys::socket::*;
+ /// use nix::sys::uio::IoVec;
+ /// use nix::sys::time::*;
+ /// use std::time::*;
+ ///
+ /// // Set up
+ /// let message = "Ohayō!".as_bytes();
+ /// let in_socket = socket(
+ /// AddressFamily::Inet,
+ /// SockType::Datagram,
+ /// SockFlag::empty(),
+ /// None).unwrap();
+ /// setsockopt(in_socket, sockopt::ReceiveTimestamp, &true).unwrap();
+ /// let localhost = InetAddr::new(IpAddr::new_v4(127, 0, 0, 1), 0);
+ /// bind(in_socket, &SockAddr::new_inet(localhost)).unwrap();
+ /// let address = getsockname(in_socket).unwrap();
+ /// // Get initial time
+ /// let time0 = SystemTime::now();
+ /// // Send the message
+ /// let iov = [IoVec::from_slice(message)];
+ /// let flags = MsgFlags::empty();
+ /// let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap();
+ /// assert_eq!(message.len(), l);
+ /// // Receive the message
+ /// let mut buffer = vec![0u8; message.len()];
+ /// let mut cmsgspace: CmsgSpace<TimeVal> = CmsgSpace::new();
+ /// let iov = [IoVec::from_mut_slice(&mut buffer)];
+ /// let r = recvmsg(in_socket, &iov, Some(&mut cmsgspace), flags).unwrap();
+ /// let rtime = match r.cmsgs().next() {
+ /// Some(ControlMessage::ScmTimestamp(&rtime)) => rtime,
+ /// Some(_) => panic!("Unexpected control message"),
+ /// None => panic!("No control message")
+ /// };
+ /// // Check the final time
+ /// let time1 = SystemTime::now();
+ /// // the packet's received timestamp should lie in-between the two system
+ /// // times, unless the system clock was adjusted in the meantime.
+ /// let rduration = Duration::new(rtime.tv_sec() as u64,
+ /// rtime.tv_usec() as u32 * 1000);
+ /// assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration);
+ /// assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap());
+ /// // Close socket
+ /// nix::unistd::close(in_socket).unwrap();
+ /// ```
+ ScmTimestamp(&'a TimeVal),
+
+ #[cfg(any(
+ target_os = "android",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"
+ ))]
+ Ipv4PacketInfo(&'a libc::in_pktinfo),
+ #[cfg(any(
+ target_os = "android",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"
+ ))]
+ Ipv6PacketInfo(&'a libc::in6_pktinfo),
+
+ /// Catch-all variant for unimplemented cmsg types.
+ #[doc(hidden)]
+ Unknown(UnknownCmsg<'a>),
+}
+
+// An opaque structure used to prevent cmsghdr from being a public type
+#[doc(hidden)]
+#[allow(missing_debug_implementations)]
+pub struct UnknownCmsg<'a>(&'a cmsghdr, &'a [u8]);
+
+// Round `len` up to meet the platform's required alignment for
+// `cmsghdr`s and trailing `cmsghdr` data. This should match the
+// behaviour of CMSG_ALIGN from the Linux headers and do the correct
+// thing on other platforms that don't usually provide CMSG_ALIGN.
+#[inline]
+fn cmsg_align(len: usize) -> usize {
+ let align_bytes = mem::size_of::<align_of_cmsg_data>() - 1;
+ (len + align_bytes) & !align_bytes
+}
+
+impl<'a> ControlMessage<'a> {
+ /// The value of CMSG_SPACE on this message.
+ fn space(&self) -> usize {
+ cmsg_align(self.len())
+ }
+
+ /// The value of CMSG_LEN on this message.
+ fn len(&self) -> usize {
+ cmsg_align(mem::size_of::<cmsghdr>()) + match *self {
+ ControlMessage::ScmRights(fds) => {
+ mem::size_of_val(fds)
+ },
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ ControlMessage::ScmCredentials(creds) => {
+ mem::size_of_val(creds)
+ }
+ ControlMessage::ScmTimestamp(t) => {
+ mem::size_of_val(t)
+ },
+ #[cfg(any(
+ target_os = "android",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"
+ ))]
+ ControlMessage::Ipv4PacketInfo(pktinfo) => {
+ mem::size_of_val(pktinfo)
+ },
+ #[cfg(any(
+ target_os = "android",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"
+ ))]
+ ControlMessage::Ipv6PacketInfo(pktinfo) => {
+ mem::size_of_val(pktinfo)
+ },
+ ControlMessage::Unknown(UnknownCmsg(_, bytes)) => {
+ mem::size_of_val(bytes)
+ }
+ }
+ }
+
+ /// Returns the value to put into the `cmsg_level` field of the header.
+ fn cmsg_level(&self) -> libc::c_int {
+ match *self {
+ ControlMessage::ScmRights(_) => libc::SOL_SOCKET,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ ControlMessage::ScmCredentials(_) => libc::SOL_SOCKET,
+ ControlMessage::ScmTimestamp(_) => libc::SOL_SOCKET,
+ #[cfg(any(
+ target_os = "android",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"
+ ))]
+ ControlMessage::Ipv4PacketInfo(_) => libc::IPPROTO_IP,
+ #[cfg(any(
+ target_os = "android",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"
+ ))]
+ ControlMessage::Ipv6PacketInfo(_) => libc::IPPROTO_IPV6,
+ ControlMessage::Unknown(ref cmsg) => cmsg.0.cmsg_level,
+ }
+ }
+
+ /// Returns the value to put into the `cmsg_type` field of the header.
+ fn cmsg_type(&self) -> libc::c_int {
+ match *self {
+ ControlMessage::ScmRights(_) => libc::SCM_RIGHTS,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ ControlMessage::ScmCredentials(_) => libc::SCM_CREDENTIALS,
+ ControlMessage::ScmTimestamp(_) => libc::SCM_TIMESTAMP,
+ #[cfg(any(
+ target_os = "android",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"
+ ))]
+ ControlMessage::Ipv4PacketInfo(_) => libc::IP_PKTINFO,
+ #[cfg(any(
+ target_os = "android",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"
+ ))]
+ ControlMessage::Ipv6PacketInfo(_) => libc::IPV6_PKTINFO,
+ ControlMessage::Unknown(ref cmsg) => cmsg.0.cmsg_type,
+ }
+ }
+
+ // Unsafe: start and end of buffer must be cmsg_align'd. Updates
+ // the provided slice; panics if the buffer is too small.
+ unsafe fn encode_into(&self, buf: &mut [u8]) {
+ let final_buf = if let ControlMessage::Unknown(ref cmsg) = *self {
+ let &UnknownCmsg(orig_cmsg, bytes) = cmsg;
+
+ let buf = copy_bytes(orig_cmsg, buf);
+
+ let padlen = cmsg_align(mem::size_of_val(&orig_cmsg)) -
+ mem::size_of_val(&orig_cmsg);
+ let buf = pad_bytes(padlen, buf);
+
+ copy_bytes(bytes, buf)
+ } else {
+ let cmsg = cmsghdr {
+ cmsg_len: self.len() as _,
+ cmsg_level: self.cmsg_level(),
+ cmsg_type: self.cmsg_type(),
+ ..mem::zeroed() // zero out platform-dependent padding fields
+ };
+ let buf = copy_bytes(&cmsg, buf);
+
+ let padlen = cmsg_align(mem::size_of_val(&cmsg)) -
+ mem::size_of_val(&cmsg);
+ let buf = pad_bytes(padlen, buf);
+
+ match *self {
+ ControlMessage::ScmRights(fds) => {
+ copy_bytes(fds, buf)
+ },
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ ControlMessage::ScmCredentials(creds) => {
+ copy_bytes(creds, buf)
+ },
+ ControlMessage::ScmTimestamp(t) => {
+ copy_bytes(t, buf)
+ },
+ #[cfg(any(
+ target_os = "android",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"
+ ))]
+ ControlMessage::Ipv4PacketInfo(pktinfo) => {
+ copy_bytes(pktinfo, buf)
+ },
+ #[cfg(any(
+ target_os = "android",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"
+ ))]
+ ControlMessage::Ipv6PacketInfo(pktinfo) => {
+ copy_bytes(pktinfo, buf)
+ }
+ ControlMessage::Unknown(_) => unreachable!(),
+ }
+ };
+
+ let padlen = self.space() - self.len();
+ pad_bytes(padlen, final_buf);
+ }
+
+ /// Decodes a `ControlMessage` from raw bytes.
+ ///
+ /// This is only safe to call if the data is correct for the message type
+ /// specified in the header. Normally, the kernel ensures that this is the
+ /// case. "Correct" in this case includes correct length, alignment and
+ /// actual content.
+ unsafe fn decode_from(header: &'a cmsghdr, data: &'a [u8]) -> ControlMessage<'a> {
+ match (header.cmsg_level, header.cmsg_type) {
+ (libc::SOL_SOCKET, libc::SCM_RIGHTS) => {
+ ControlMessage::ScmRights(
+ slice::from_raw_parts(data.as_ptr() as *const _,
+ data.len() / mem::size_of::<RawFd>()))
+ },
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ (libc::SOL_SOCKET, libc::SCM_CREDENTIALS) => {
+ ControlMessage::ScmCredentials(
+ &*(data.as_ptr() as *const _)
+ )
+ }
+ (libc::SOL_SOCKET, libc::SCM_TIMESTAMP) => {
+ ControlMessage::ScmTimestamp(
+ &*(data.as_ptr() as *const _))
+ },
+ #[cfg(any(
+ target_os = "android",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"
+ ))]
+ (libc::IPPROTO_IPV6, libc::IPV6_PKTINFO) => {
+ ControlMessage::Ipv6PacketInfo(
+ &*(data.as_ptr() as *const _))
+ }
+ #[cfg(any(
+ target_os = "android",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"
+ ))]
+ (libc::IPPROTO_IP, libc::IP_PKTINFO) => {
+ ControlMessage::Ipv4PacketInfo(
+ &*(data.as_ptr() as *const _))
+ }
+
+ (_, _) => {
+ ControlMessage::Unknown(UnknownCmsg(header, data))
+ }
+ }
+ }
+}
+
+
+/// Send data in scatter-gather vectors to a socket, possibly accompanied
+/// by ancillary data. Optionally direct the message at the given address,
+/// as with sendto.
+///
+/// Allocates if cmsgs is nonempty.
+pub fn sendmsg<'a>(fd: RawFd, iov: &[IoVec<&'a [u8]>], cmsgs: &[ControlMessage<'a>], flags: MsgFlags, addr: Option<&'a SockAddr>) -> Result<usize> {
+ let mut capacity = 0;
+ for cmsg in cmsgs {
+ capacity += cmsg.space();
+ }
+ // Note that the resulting vector claims to have length == capacity,
+ // so it's presently uninitialized.
+ let mut cmsg_buffer = unsafe {
+ let mut vec = Vec::<u8>::with_capacity(capacity);
+ vec.set_len(capacity);
+ vec
+ };
+ {
+ let mut ofs = 0;
+ for cmsg in cmsgs {
+ let ptr = &mut cmsg_buffer[ofs..];
+ unsafe {
+ cmsg.encode_into(ptr);
+ }
+ ofs += cmsg.space();
+ }
+ }
+
+ let (name, namelen) = match addr {
+ Some(addr) => { let (x, y) = unsafe { addr.as_ffi_pair() }; (x as *const _, y) }
+ None => (ptr::null(), 0),
+ };
+
+ let cmsg_ptr = if capacity > 0 {
+ cmsg_buffer.as_ptr() as *const c_void
+ } else {
+ ptr::null()
+ };
+
+ let mhdr = unsafe {
+ let mut mhdr: msghdr = mem::uninitialized();
+ mhdr.msg_name = name as *mut _;
+ mhdr.msg_namelen = namelen;
+ mhdr.msg_iov = iov.as_ptr() as *mut _;
+ mhdr.msg_iovlen = iov.len() as _;
+ mhdr.msg_control = cmsg_ptr as *mut _;
+ mhdr.msg_controllen = capacity as _;
+ mhdr.msg_flags = 0;
+ mhdr
+ };
+ let ret = unsafe { libc::sendmsg(fd, &mhdr, flags.bits()) };
+
+ Errno::result(ret).map(|r| r as usize)
+}
+
+/// Receive message in scatter-gather vectors from a socket, and
+/// optionally receive ancillary data into the provided buffer.
+/// If no ancillary data is desired, use () as the type parameter.
+pub fn recvmsg<'a, T>(fd: RawFd, iov: &[IoVec<&mut [u8]>], cmsg_buffer: Option<&'a mut CmsgSpace<T>>, flags: MsgFlags) -> Result<RecvMsg<'a>> {
+ let mut address: sockaddr_storage = unsafe { mem::uninitialized() };
+ let (msg_control, msg_controllen) = match cmsg_buffer {
+ Some(cmsg_buffer) => (cmsg_buffer as *mut _, mem::size_of_val(cmsg_buffer)),
+ None => (ptr::null_mut(), 0),
+ };
+ let mut mhdr = unsafe {
+ let mut mhdr: msghdr = mem::uninitialized();
+ mhdr.msg_name = &mut address as *mut _ as *mut _;
+ mhdr.msg_namelen = mem::size_of::<sockaddr_storage>() as socklen_t;
+ mhdr.msg_iov = iov.as_ptr() as *mut _;
+ mhdr.msg_iovlen = iov.len() as _;
+ mhdr.msg_control = msg_control as *mut _;
+ mhdr.msg_controllen = msg_controllen as _;
+ mhdr.msg_flags = 0;
+ mhdr
+ };
+ let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) };
+
+ let cmsg_buffer = if msg_controllen > 0 {
+ // got control message(s)
+ debug_assert!(!mhdr.msg_control.is_null());
+ unsafe {
+ // Safe: The pointer is not null and the length is correct as part of `recvmsg`s
+ // contract.
+ slice::from_raw_parts(mhdr.msg_control as *const u8,
+ mhdr.msg_controllen as usize)
+ }
+ } else {
+ // No control message, create an empty buffer to avoid creating a slice from a null pointer
+ &[]
+ };
+
+ Ok(unsafe { RecvMsg {
+ bytes: Errno::result(ret)? as usize,
+ cmsg_buffer,
+ address: sockaddr_storage_to_addr(&address,
+ mhdr.msg_namelen as usize).ok(),
+ flags: MsgFlags::from_bits_truncate(mhdr.msg_flags),
+ } })
+}
+
+
+/// Create an endpoint for communication
+///
+/// The `protocol` specifies a particular protocol to be used with the
+/// socket. Normally only a single protocol exists to support a
+/// particular socket type within a given protocol family, in which case
+/// protocol can be specified as `None`. However, it is possible that many
+/// protocols may exist, in which case a particular protocol must be
+/// specified in this manner.
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html)
+pub fn socket<T: Into<Option<SockProtocol>>>(domain: AddressFamily, ty: SockType, flags: SockFlag, protocol: T) -> Result<RawFd> {
+ let protocol = match protocol.into() {
+ None => 0,
+ Some(p) => p as c_int,
+ };
+
+ // SockFlags are usually embedded into `ty`, but we don't do that in `nix` because it's a
+ // little easier to understand by separating it out. So we have to merge these bitfields
+ // here.
+ let mut ty = ty as c_int;
+ ty |= flags.bits();
+
+ let res = unsafe { libc::socket(domain as c_int, ty, protocol) };
+
+ Errno::result(res)
+}
+
+/// Create a pair of connected sockets
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/socketpair.html)
+pub fn socketpair<T: Into<Option<SockProtocol>>>(domain: AddressFamily, ty: SockType, protocol: T,
+ flags: SockFlag) -> Result<(RawFd, RawFd)> {
+ let protocol = match protocol.into() {
+ None => 0,
+ Some(p) => p as c_int,
+ };
+
+ // SockFlags are usually embedded into `ty`, but we don't do that in `nix` because it's a
+ // little easier to understand by separating it out. So we have to merge these bitfields
+ // here.
+ let mut ty = ty as c_int;
+ ty |= flags.bits();
+
+ let mut fds = [-1, -1];
+
+ let res = unsafe { libc::socketpair(domain as c_int, ty, protocol, fds.as_mut_ptr()) };
+ Errno::result(res)?;
+
+ Ok((fds[0], fds[1]))
+}
+
+/// Listen for connections on a socket
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html)
+pub fn listen(sockfd: RawFd, backlog: usize) -> Result<()> {
+ let res = unsafe { libc::listen(sockfd, backlog as c_int) };
+
+ Errno::result(res).map(drop)
+}
+
+/// Bind a name to a socket
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html)
+pub fn bind(fd: RawFd, addr: &SockAddr) -> Result<()> {
+ let res = unsafe {
+ let (ptr, len) = addr.as_ffi_pair();
+ libc::bind(fd, ptr, len)
+ };
+
+ Errno::result(res).map(drop)
+}
+
+/// Accept a connection on a socket
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html)
+pub fn accept(sockfd: RawFd) -> Result<RawFd> {
+ let res = unsafe { libc::accept(sockfd, ptr::null_mut(), ptr::null_mut()) };
+
+ Errno::result(res)
+}
+
+/// Accept a connection on a socket
+///
+/// [Further reading](http://man7.org/linux/man-pages/man2/accept.2.html)
+#[cfg(any(target_os = "android",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "openbsd"))]
+pub fn accept4(sockfd: RawFd, flags: SockFlag) -> Result<RawFd> {
+ let res = unsafe { libc::accept4(sockfd, ptr::null_mut(), ptr::null_mut(), flags.bits()) };
+
+ Errno::result(res)
+}
+
+/// Initiate a connection on a socket
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html)
+pub fn connect(fd: RawFd, addr: &SockAddr) -> Result<()> {
+ let res = unsafe {
+ let (ptr, len) = addr.as_ffi_pair();
+ libc::connect(fd, ptr, len)
+ };
+
+ Errno::result(res).map(drop)
+}
+
+/// Receive data from a connection-oriented socket. Returns the number of
+/// bytes read
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html)
+pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize> {
+ unsafe {
+ let ret = libc::recv(
+ sockfd,
+ buf.as_ptr() as *mut c_void,
+ buf.len() as size_t,
+ flags.bits());
+
+ Errno::result(ret).map(|r| r as usize)
+ }
+}
+
+/// Receive data from a connectionless or connection-oriented socket. Returns
+/// the number of bytes read and the socket address of the sender.
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html)
+pub fn recvfrom(sockfd: RawFd, buf: &mut [u8]) -> Result<(usize, SockAddr)> {
+ unsafe {
+ let addr: sockaddr_storage = mem::zeroed();
+ let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
+
+ let ret = Errno::result(libc::recvfrom(
+ sockfd,
+ buf.as_ptr() as *mut c_void,
+ buf.len() as size_t,
+ 0,
+ mem::transmute(&addr),
+ &mut len as *mut socklen_t))?;
+
+ sockaddr_storage_to_addr(&addr, len as usize)
+ .map(|addr| (ret as usize, addr))
+ }
+}
+
+/// Send a message to a socket
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html)
+pub fn sendto(fd: RawFd, buf: &[u8], addr: &SockAddr, flags: MsgFlags) -> Result<usize> {
+ let ret = unsafe {
+ let (ptr, len) = addr.as_ffi_pair();
+ libc::sendto(fd, buf.as_ptr() as *const c_void, buf.len() as size_t, flags.bits(), ptr, len)
+ };
+
+ Errno::result(ret).map(|r| r as usize)
+}
+
+/// Send data to a connection-oriented socket. Returns the number of bytes read
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html)
+pub fn send(fd: RawFd, buf: &[u8], flags: MsgFlags) -> Result<usize> {
+ let ret = unsafe {
+ libc::send(fd, buf.as_ptr() as *const c_void, buf.len() as size_t, flags.bits())
+ };
+
+ Errno::result(ret).map(|r| r as usize)
+}
+
+/*
+ *
+ * ===== Socket Options =====
+ *
+ */
+
+/// The protocol level at which to get / set socket options. Used as an
+/// argument to `getsockopt` and `setsockopt`.
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html)
+#[repr(i32)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+pub enum SockLevel {
+ Socket = libc::SOL_SOCKET,
+ Tcp = libc::IPPROTO_TCP,
+ Ip = libc::IPPROTO_IP,
+ Ipv6 = libc::IPPROTO_IPV6,
+ Udp = libc::IPPROTO_UDP,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Netlink = libc::SOL_NETLINK,
+}
+
+/// Represents a socket option that can be accessed or set. Used as an argument
+/// to `getsockopt`
+pub trait GetSockOpt : Copy {
+ type Val;
+
+ #[doc(hidden)]
+ fn get(&self, fd: RawFd) -> Result<Self::Val>;
+}
+
+/// Represents a socket option that can be accessed or set. Used as an argument
+/// to `setsockopt`
+pub trait SetSockOpt : Copy {
+ type Val;
+
+ #[doc(hidden)]
+ fn set(&self, fd: RawFd, val: &Self::Val) -> Result<()>;
+}
+
+/// Get the current value for the requested socket option
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html)
+pub fn getsockopt<O: GetSockOpt>(fd: RawFd, opt: O) -> Result<O::Val> {
+ opt.get(fd)
+}
+
+/// Sets the value for the requested socket option
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html)
+///
+/// # Examples
+///
+/// ```
+/// use nix::sys::socket::setsockopt;
+/// use nix::sys::socket::sockopt::KeepAlive;
+/// use std::net::TcpListener;
+/// use std::os::unix::io::AsRawFd;
+///
+/// let listener = TcpListener::bind("0.0.0.0:0").unwrap();
+/// let fd = listener.as_raw_fd();
+/// let res = setsockopt(fd, KeepAlive, &true);
+/// assert!(res.is_ok());
+/// ```
+pub fn setsockopt<O: SetSockOpt>(fd: RawFd, opt: O, val: &O::Val) -> Result<()> {
+ opt.set(fd, val)
+}
+
+/// Get the address of the peer connected to the socket `fd`.
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html)
+pub fn getpeername(fd: RawFd) -> Result<SockAddr> {
+ unsafe {
+ let addr: sockaddr_storage = mem::uninitialized();
+ let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
+
+ let ret = libc::getpeername(fd, mem::transmute(&addr), &mut len);
+
+ Errno::result(ret)?;
+
+ sockaddr_storage_to_addr(&addr, len as usize)
+ }
+}
+
+/// Get the current address to which the socket `fd` is bound.
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html)
+pub fn getsockname(fd: RawFd) -> Result<SockAddr> {
+ unsafe {
+ let addr: sockaddr_storage = mem::uninitialized();
+ let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
+
+ let ret = libc::getsockname(fd, mem::transmute(&addr), &mut len);
+
+ Errno::result(ret)?;
+
+ sockaddr_storage_to_addr(&addr, len as usize)
+ }
+}
+
+/// Return the appropriate `SockAddr` type from a `sockaddr_storage` of a certain
+/// size. In C this would usually be done by casting. The `len` argument
+/// should be the number of bytes in the `sockaddr_storage` that are actually
+/// allocated and valid. It must be at least as large as all the useful parts
+/// of the structure. Note that in the case of a `sockaddr_un`, `len` need not
+/// include the terminating null.
+pub unsafe fn sockaddr_storage_to_addr(
+ addr: &sockaddr_storage,
+ len: usize) -> Result<SockAddr> {
+
+ if len < mem::size_of_val(&addr.ss_family) {
+ return Err(Error::Sys(Errno::ENOTCONN));
+ }
+
+ match addr.ss_family as c_int {
+ libc::AF_INET => {
+ assert!(len as usize == mem::size_of::<sockaddr_in>());
+ let ret = *(addr as *const _ as *const sockaddr_in);
+ Ok(SockAddr::Inet(InetAddr::V4(ret)))
+ }
+ libc::AF_INET6 => {
+ assert!(len as usize == mem::size_of::<sockaddr_in6>());
+ Ok(SockAddr::Inet(InetAddr::V6(*(addr as *const _ as *const sockaddr_in6))))
+ }
+ libc::AF_UNIX => {
+ let sun = *(addr as *const _ as *const sockaddr_un);
+ let pathlen = len - offset_of!(sockaddr_un, sun_path);
+ Ok(SockAddr::Unix(UnixAddr(sun, pathlen)))
+ }
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ libc::AF_NETLINK => {
+ use libc::sockaddr_nl;
+ Ok(SockAddr::Netlink(NetlinkAddr(*(addr as *const _ as *const sockaddr_nl))))
+ }
+ af => panic!("unexpected address family {}", af),
+ }
+}
+
+
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+pub enum Shutdown {
+ /// Further receptions will be disallowed.
+ Read,
+ /// Further transmissions will be disallowed.
+ Write,
+ /// Further receptions and transmissions will be disallowed.
+ Both,
+}
+
+/// Shut down part of a full-duplex connection.
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/shutdown.html)
+pub fn shutdown(df: RawFd, how: Shutdown) -> Result<()> {
+ unsafe {
+ use libc::shutdown;
+
+ let how = match how {
+ Shutdown::Read => libc::SHUT_RD,
+ Shutdown::Write => libc::SHUT_WR,
+ Shutdown::Both => libc::SHUT_RDWR,
+ };
+
+ Errno::result(shutdown(df, how)).map(drop)
+ }
+}
diff --git a/third_party/rust/nix/src/sys/socket/sockopt.rs b/third_party/rust/nix/src/sys/socket/sockopt.rs
new file mode 100644
index 0000000000..6c5f450dff
--- /dev/null
+++ b/third_party/rust/nix/src/sys/socket/sockopt.rs
@@ -0,0 +1,631 @@
+use super::{GetSockOpt, SetSockOpt};
+use Result;
+use errno::Errno;
+use sys::time::TimeVal;
+use libc::{self, c_int, c_void, socklen_t};
+use std::mem;
+use std::os::unix::io::RawFd;
+use std::ffi::{OsStr, OsString};
+#[cfg(target_family = "unix")]
+use std::os::unix::ffi::OsStrExt;
+
+// Constants
+// TCP_CA_NAME_MAX isn't defined in user space include files
+#[cfg(any(target_os = "freebsd", target_os = "linux"))]
+const TCP_CA_NAME_MAX: usize = 16;
+
+/// Helper for implementing `SetSockOpt` for a given socket option. See
+/// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html).
+///
+/// This macro aims to help implementing `SetSockOpt` for different socket options that accept
+/// different kinds of data to be used with `setsockopt`.
+///
+/// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option
+/// you are implementing represents a simple type.
+///
+/// # Arguments
+///
+/// * `$name:ident`: name of the type you want to implement `SetSockOpt` for.
+/// * `$level:path` : socket layer, or a `protocol level`: could be *raw sockets*
+/// (`libc::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`),
+/// and more. Please refer to your system manual for more options. Will be passed as the second
+/// argument (`level`) to the `setsockopt` call.
+/// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`,
+/// `libc::IP_ADD_MEMBERSHIP` and others. Will be passed as the third argument (`option_name`)
+/// to the `setsockopt` call.
+/// * Type of the value that you are going to set.
+/// * Type that implements the `Set` trait for the type from the previous item (like `SetBool` for
+/// `bool`, `SetUsize` for `usize`, etc.).
+macro_rules! setsockopt_impl {
+ ($name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => {
+ impl SetSockOpt for $name {
+ type Val = $ty;
+
+ fn set(&self, fd: RawFd, val: &$ty) -> Result<()> {
+ unsafe {
+ let setter: $setter = Set::new(val);
+
+ let res = libc::setsockopt(fd, $level, $flag,
+ setter.ffi_ptr(),
+ setter.ffi_len());
+ Errno::result(res).map(drop)
+ }
+ }
+ }
+ }
+}
+
+/// Helper for implementing `GetSockOpt` for a given socket option. See
+/// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html).
+///
+/// This macro aims to help implementing `GetSockOpt` for different socket options that accept
+/// different kinds of data to be use with `getsockopt`.
+///
+/// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option
+/// you are implementing represents a simple type.
+///
+/// # Arguments
+///
+/// * Name of the type you want to implement `GetSockOpt` for.
+/// * Socket layer, or a `protocol level`: could be *raw sockets* (`lic::SOL_SOCKET`), *ip
+/// protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`), and more. Please refer
+/// to your system manual for more options. Will be passed as the second argument (`level`) to
+/// the `getsockopt` call.
+/// * A flag to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`,
+/// `libc::SO_ORIGINAL_DST` and others. Will be passed as the third argument (`option_name`) to
+/// the `getsockopt` call.
+/// * Type of the value that you are going to get.
+/// * Type that implements the `Get` trait for the type from the previous item (`GetBool` for
+/// `bool`, `GetUsize` for `usize`, etc.).
+macro_rules! getsockopt_impl {
+ ($name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => {
+ impl GetSockOpt for $name {
+ type Val = $ty;
+
+ fn get(&self, fd: RawFd) -> Result<$ty> {
+ unsafe {
+ let mut getter: $getter = Get::blank();
+
+ let res = libc::getsockopt(fd, $level, $flag,
+ getter.ffi_ptr(),
+ getter.ffi_len());
+ Errno::result(res)?;
+
+ Ok(getter.unwrap())
+ }
+ }
+ }
+ }
+}
+
+/// Helper to generate the sockopt accessors. See
+/// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html) and
+/// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html).
+///
+/// This macro aims to help implementing `GetSockOpt` and `SetSockOpt` for different socket options
+/// that accept different kinds of data to be use with `getsockopt` and `setsockopt` respectively.
+///
+/// Basically this macro wraps up the [`getsockopt_impl!`](macro.getsockopt_impl.html) and
+/// [`setsockopt_impl!`](macro.setsockopt_impl.html) macros.
+///
+/// # Arguments
+///
+/// * `GetOnly`, `SetOnly` or `Both`: whether you want to implement only getter, only setter or
+/// both of them.
+/// * `$name:ident`: name of type `GetSockOpt`/`SetSockOpt` will be implemented for.
+/// * `$level:path` : socket layer, or a `protocol level`: could be *raw sockets*
+/// (`lic::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`),
+/// and more. Please refer to your system manual for more options. Will be passed as the second
+/// argument (`level`) to the `getsockopt`/`setsockopt` call.
+/// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`,
+/// `libc::IP_ADD_MEMBERSHIP` and others. Will be passed as the third argument (`option_name`)
+/// to the `setsockopt`/`getsockopt` call.
+/// * `$ty:ty`: type of the value that will be get/set.
+/// * `$getter:ty`: `Get` implementation; optional; only for `GetOnly` and `Both`.
+/// * `$setter:ty`: `Set` implementation; optional; only for `SetOnly` and `Both`.
+macro_rules! sockopt_impl {
+ (GetOnly, $name:ident, $level:path, $flag:path, bool) => {
+ sockopt_impl!(GetOnly, $name, $level, $flag, bool, GetBool);
+ };
+
+ (GetOnly, $name:ident, $level:path, $flag:path, u8) => {
+ sockopt_impl!(GetOnly, $name, $level, $flag, u8, GetU8);
+ };
+
+ (GetOnly, $name:ident, $level:path, $flag:path, usize) => {
+ sockopt_impl!(GetOnly, $name, $level, $flag, usize, GetUsize);
+ };
+
+ (SetOnly, $name:ident, $level:path, $flag:path, bool) => {
+ sockopt_impl!(SetOnly, $name, $level, $flag, bool, SetBool);
+ };
+
+ (SetOnly, $name:ident, $level:path, $flag:path, u8) => {
+ sockopt_impl!(SetOnly, $name, $level, $flag, u8, SetU8);
+ };
+
+ (SetOnly, $name:ident, $level:path, $flag:path, usize) => {
+ sockopt_impl!(SetOnly, $name, $level, $flag, usize, SetUsize);
+ };
+
+ (Both, $name:ident, $level:path, $flag:path, bool) => {
+ sockopt_impl!(Both, $name, $level, $flag, bool, GetBool, SetBool);
+ };
+
+ (Both, $name:ident, $level:path, $flag:path, u8) => {
+ sockopt_impl!(Both, $name, $level, $flag, u8, GetU8, SetU8);
+ };
+
+ (Both, $name:ident, $level:path, $flag:path, usize) => {
+ sockopt_impl!(Both, $name, $level, $flag, usize, GetUsize, SetUsize);
+ };
+
+ (Both, $name:ident, $level:path, $flag:path, OsString<$array:ty>) => {
+ sockopt_impl!(Both, $name, $level, $flag, OsString, GetOsString<$array>, SetOsString);
+ };
+
+ /*
+ * Matchers with generic getter types must be placed at the end, so
+ * they'll only match _after_ specialized matchers fail
+ */
+ (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => {
+ sockopt_impl!(GetOnly, $name, $level, $flag, $ty, GetStruct<$ty>);
+ };
+
+ (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => {
+ #[derive(Copy, Clone, Debug)]
+ pub struct $name;
+
+ getsockopt_impl!($name, $level, $flag, $ty, $getter);
+ };
+
+ (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => {
+ sockopt_impl!(SetOnly, $name, $level, $flag, $ty, SetStruct<$ty>);
+ };
+
+ (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => {
+ #[derive(Copy, Clone, Debug)]
+ pub struct $name;
+
+ setsockopt_impl!($name, $level, $flag, $ty, $setter);
+ };
+
+ (Both, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty, $setter:ty) => {
+ #[derive(Copy, Clone, Debug)]
+ pub struct $name;
+
+ setsockopt_impl!($name, $level, $flag, $ty, $setter);
+ getsockopt_impl!($name, $level, $flag, $ty, $getter);
+ };
+
+ (Both, $name:ident, $level:path, $flag:path, $ty:ty) => {
+ sockopt_impl!(Both, $name, $level, $flag, $ty, GetStruct<$ty>, SetStruct<$ty>);
+ };
+}
+
+/*
+ *
+ * ===== Define sockopts =====
+ *
+ */
+
+sockopt_impl!(Both, ReuseAddr, libc::SOL_SOCKET, libc::SO_REUSEADDR, bool);
+sockopt_impl!(Both, ReusePort, libc::SOL_SOCKET, libc::SO_REUSEPORT, bool);
+sockopt_impl!(Both, TcpNoDelay, libc::IPPROTO_TCP, libc::TCP_NODELAY, bool);
+sockopt_impl!(Both, Linger, libc::SOL_SOCKET, libc::SO_LINGER, libc::linger);
+sockopt_impl!(SetOnly, IpAddMembership, libc::IPPROTO_IP, libc::IP_ADD_MEMBERSHIP, super::IpMembershipRequest);
+sockopt_impl!(SetOnly, IpDropMembership, libc::IPPROTO_IP, libc::IP_DROP_MEMBERSHIP, super::IpMembershipRequest);
+cfg_if! {
+ if #[cfg(any(target_os = "android", target_os = "linux"))] {
+ sockopt_impl!(SetOnly, Ipv6AddMembership, libc::IPPROTO_IPV6, libc::IPV6_ADD_MEMBERSHIP, super::Ipv6MembershipRequest);
+ sockopt_impl!(SetOnly, Ipv6DropMembership, libc::IPPROTO_IPV6, libc::IPV6_DROP_MEMBERSHIP, super::Ipv6MembershipRequest);
+ } else if #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))] {
+ sockopt_impl!(SetOnly, Ipv6AddMembership, libc::IPPROTO_IPV6, libc::IPV6_JOIN_GROUP, super::Ipv6MembershipRequest);
+ sockopt_impl!(SetOnly, Ipv6DropMembership, libc::IPPROTO_IPV6, libc::IPV6_LEAVE_GROUP, super::Ipv6MembershipRequest);
+ }
+}
+sockopt_impl!(Both, IpMulticastTtl, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL, u8);
+sockopt_impl!(Both, IpMulticastLoop, libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP, bool);
+sockopt_impl!(Both, ReceiveTimeout, libc::SOL_SOCKET, libc::SO_RCVTIMEO, TimeVal);
+sockopt_impl!(Both, SendTimeout, libc::SOL_SOCKET, libc::SO_SNDTIMEO, TimeVal);
+sockopt_impl!(Both, Broadcast, libc::SOL_SOCKET, libc::SO_BROADCAST, bool);
+sockopt_impl!(Both, OobInline, libc::SOL_SOCKET, libc::SO_OOBINLINE, bool);
+sockopt_impl!(GetOnly, SocketError, libc::SOL_SOCKET, libc::SO_ERROR, i32);
+sockopt_impl!(Both, KeepAlive, libc::SOL_SOCKET, libc::SO_KEEPALIVE, bool);
+#[cfg(any(target_os = "android", target_os = "linux"))]
+sockopt_impl!(GetOnly, PeerCredentials, libc::SOL_SOCKET, libc::SO_PEERCRED, super::UnixCredentials);
+#[cfg(any(target_os = "ios",
+ target_os = "macos"))]
+sockopt_impl!(Both, TcpKeepAlive, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE, u32);
+#[cfg(any(target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "nacl"))]
+sockopt_impl!(Both, TcpKeepIdle, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, u32);
+sockopt_impl!(Both, RcvBuf, libc::SOL_SOCKET, libc::SO_RCVBUF, usize);
+sockopt_impl!(Both, SndBuf, libc::SOL_SOCKET, libc::SO_SNDBUF, usize);
+#[cfg(any(target_os = "android", target_os = "linux"))]
+sockopt_impl!(SetOnly, RcvBufForce, libc::SOL_SOCKET, libc::SO_RCVBUFFORCE, usize);
+#[cfg(any(target_os = "android", target_os = "linux"))]
+sockopt_impl!(SetOnly, SndBufForce, libc::SOL_SOCKET, libc::SO_SNDBUFFORCE, usize);
+sockopt_impl!(GetOnly, SockType, libc::SOL_SOCKET, libc::SO_TYPE, super::SockType);
+sockopt_impl!(GetOnly, AcceptConn, libc::SOL_SOCKET, libc::SO_ACCEPTCONN, bool);
+#[cfg(any(target_os = "android", target_os = "linux"))]
+sockopt_impl!(GetOnly, OriginalDst, libc::SOL_IP, libc::SO_ORIGINAL_DST, libc::sockaddr_in);
+sockopt_impl!(Both, ReceiveTimestamp, libc::SOL_SOCKET, libc::SO_TIMESTAMP, bool);
+#[cfg(any(target_os = "android", target_os = "linux"))]
+sockopt_impl!(Both, IpTransparent, libc::SOL_IP, libc::IP_TRANSPARENT, bool);
+#[cfg(target_os = "openbsd")]
+sockopt_impl!(Both, BindAny, libc::SOL_SOCKET, libc::SO_BINDANY, bool);
+#[cfg(target_os = "freebsd")]
+sockopt_impl!(Both, BindAny, libc::IPPROTO_IP, libc::IP_BINDANY, bool);
+#[cfg(target_os = "linux")]
+sockopt_impl!(Both, Mark, libc::SOL_SOCKET, libc::SO_MARK, u32);
+#[cfg(any(target_os = "android", target_os = "linux"))]
+sockopt_impl!(Both, PassCred, libc::SOL_SOCKET, libc::SO_PASSCRED, bool);
+#[cfg(any(target_os = "freebsd", target_os = "linux"))]
+sockopt_impl!(Both, TcpCongestion, libc::IPPROTO_TCP, libc::TCP_CONGESTION, OsString<[u8; TCP_CA_NAME_MAX]>);
+#[cfg(any(
+ target_os = "android",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"
+))]
+sockopt_impl!(Both, Ipv4PacketInfo, libc::IPPROTO_IP, libc::IP_PKTINFO, bool);
+#[cfg(any(
+ target_os = "android",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"
+))]
+sockopt_impl!(Both, Ipv6RecvPacketInfo, libc::IPPROTO_IPV6, libc::IPV6_RECVPKTINFO, bool);
+
+
+/*
+ *
+ * ===== Accessor helpers =====
+ *
+ */
+
+/// Helper trait that describes what is expected from a `GetSockOpt` getter.
+unsafe trait Get<T> {
+ /// Returns an empty value.
+ unsafe fn blank() -> Self;
+ /// Returns a pointer to the stored value. This pointer will be passed to the system's
+ /// `getsockopt` call (`man 3p getsockopt`, argument `option_value`).
+ fn ffi_ptr(&mut self) -> *mut c_void;
+ /// Returns length of the stored value. This pointer will be passed to the system's
+ /// `getsockopt` call (`man 3p getsockopt`, argument `option_len`).
+ fn ffi_len(&mut self) -> *mut socklen_t;
+ /// Returns the stored value.
+ unsafe fn unwrap(self) -> T;
+}
+
+/// Helper trait that describes what is expected from a `SetSockOpt` setter.
+unsafe trait Set<'a, T> {
+ /// Initialize the setter with a given value.
+ fn new(val: &'a T) -> Self;
+ /// Returns a pointer to the stored value. This pointer will be passed to the system's
+ /// `setsockopt` call (`man 3p setsockopt`, argument `option_value`).
+ fn ffi_ptr(&self) -> *const c_void;
+ /// Returns length of the stored value. This pointer will be passed to the system's
+ /// `setsockopt` call (`man 3p setsockopt`, argument `option_len`).
+ fn ffi_len(&self) -> socklen_t;
+}
+
+/// Getter for an arbitrary `struct`.
+struct GetStruct<T> {
+ len: socklen_t,
+ val: T,
+}
+
+unsafe impl<T> Get<T> for GetStruct<T> {
+ unsafe fn blank() -> Self {
+ GetStruct {
+ len: mem::size_of::<T>() as socklen_t,
+ val: mem::zeroed(),
+ }
+ }
+
+ fn ffi_ptr(&mut self) -> *mut c_void {
+ &mut self.val as *mut T as *mut c_void
+ }
+
+ fn ffi_len(&mut self) -> *mut socklen_t {
+ &mut self.len
+ }
+
+ unsafe fn unwrap(self) -> T {
+ assert!(self.len as usize == mem::size_of::<T>(), "invalid getsockopt implementation");
+ self.val
+ }
+}
+
+/// Setter for an arbitrary `struct`.
+struct SetStruct<'a, T: 'static> {
+ ptr: &'a T,
+}
+
+unsafe impl<'a, T> Set<'a, T> for SetStruct<'a, T> {
+ fn new(ptr: &'a T) -> SetStruct<'a, T> {
+ SetStruct { ptr: ptr }
+ }
+
+ fn ffi_ptr(&self) -> *const c_void {
+ self.ptr as *const T as *const c_void
+ }
+
+ fn ffi_len(&self) -> socklen_t {
+ mem::size_of::<T>() as socklen_t
+ }
+}
+
+/// Getter for a boolean value.
+struct GetBool {
+ len: socklen_t,
+ val: c_int,
+}
+
+unsafe impl Get<bool> for GetBool {
+ unsafe fn blank() -> Self {
+ GetBool {
+ len: mem::size_of::<c_int>() as socklen_t,
+ val: mem::zeroed(),
+ }
+ }
+
+ fn ffi_ptr(&mut self) -> *mut c_void {
+ &mut self.val as *mut c_int as *mut c_void
+ }
+
+ fn ffi_len(&mut self) -> *mut socklen_t {
+ &mut self.len
+ }
+
+ unsafe fn unwrap(self) -> bool {
+ assert!(self.len as usize == mem::size_of::<c_int>(), "invalid getsockopt implementation");
+ self.val != 0
+ }
+}
+
+/// Setter for a boolean value.
+struct SetBool {
+ val: c_int,
+}
+
+unsafe impl<'a> Set<'a, bool> for SetBool {
+ fn new(val: &'a bool) -> SetBool {
+ SetBool { val: if *val { 1 } else { 0 } }
+ }
+
+ fn ffi_ptr(&self) -> *const c_void {
+ &self.val as *const c_int as *const c_void
+ }
+
+ fn ffi_len(&self) -> socklen_t {
+ mem::size_of::<c_int>() as socklen_t
+ }
+}
+
+/// Getter for an `u8` value.
+struct GetU8 {
+ len: socklen_t,
+ val: u8,
+}
+
+unsafe impl Get<u8> for GetU8 {
+ unsafe fn blank() -> Self {
+ GetU8 {
+ len: mem::size_of::<u8>() as socklen_t,
+ val: mem::zeroed(),
+ }
+ }
+
+ fn ffi_ptr(&mut self) -> *mut c_void {
+ &mut self.val as *mut u8 as *mut c_void
+ }
+
+ fn ffi_len(&mut self) -> *mut socklen_t {
+ &mut self.len
+ }
+
+ unsafe fn unwrap(self) -> u8 {
+ assert!(self.len as usize == mem::size_of::<u8>(), "invalid getsockopt implementation");
+ self.val as u8
+ }
+}
+
+/// Setter for an `u8` value.
+struct SetU8 {
+ val: u8,
+}
+
+unsafe impl<'a> Set<'a, u8> for SetU8 {
+ fn new(val: &'a u8) -> SetU8 {
+ SetU8 { val: *val as u8 }
+ }
+
+ fn ffi_ptr(&self) -> *const c_void {
+ &self.val as *const u8 as *const c_void
+ }
+
+ fn ffi_len(&self) -> socklen_t {
+ mem::size_of::<c_int>() as socklen_t
+ }
+}
+
+/// Getter for an `usize` value.
+struct GetUsize {
+ len: socklen_t,
+ val: c_int,
+}
+
+unsafe impl Get<usize> for GetUsize {
+ unsafe fn blank() -> Self {
+ GetUsize {
+ len: mem::size_of::<c_int>() as socklen_t,
+ val: mem::zeroed(),
+ }
+ }
+
+ fn ffi_ptr(&mut self) -> *mut c_void {
+ &mut self.val as *mut c_int as *mut c_void
+ }
+
+ fn ffi_len(&mut self) -> *mut socklen_t {
+ &mut self.len
+ }
+
+ unsafe fn unwrap(self) -> usize {
+ assert!(self.len as usize == mem::size_of::<c_int>(), "invalid getsockopt implementation");
+ self.val as usize
+ }
+}
+
+/// Setter for an `usize` value.
+struct SetUsize {
+ val: c_int,
+}
+
+unsafe impl<'a> Set<'a, usize> for SetUsize {
+ fn new(val: &'a usize) -> SetUsize {
+ SetUsize { val: *val as c_int }
+ }
+
+ fn ffi_ptr(&self) -> *const c_void {
+ &self.val as *const c_int as *const c_void
+ }
+
+ fn ffi_len(&self) -> socklen_t {
+ mem::size_of::<c_int>() as socklen_t
+ }
+}
+
+/// Getter for a `OsString` value.
+struct GetOsString<T: AsMut<[u8]>> {
+ len: socklen_t,
+ val: T,
+}
+
+unsafe impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> {
+ unsafe fn blank() -> Self {
+ GetOsString {
+ len: mem::size_of::<T>() as socklen_t,
+ val: mem::zeroed(),
+ }
+ }
+
+ fn ffi_ptr(&mut self) -> *mut c_void {
+ &mut self.val as *mut T as *mut c_void
+ }
+
+ fn ffi_len(&mut self) -> *mut socklen_t {
+ &mut self.len
+ }
+
+ unsafe fn unwrap(mut self) -> OsString {
+ OsStr::from_bytes(self.val.as_mut()).to_owned()
+ }
+}
+
+/// Setter for a `OsString` value.
+struct SetOsString<'a> {
+ val: &'a OsStr,
+}
+
+unsafe impl<'a> Set<'a, OsString> for SetOsString<'a> {
+ fn new(val: &'a OsString) -> SetOsString {
+ SetOsString { val: val.as_os_str() }
+ }
+
+ fn ffi_ptr(&self) -> *const c_void {
+ self.val.as_bytes().as_ptr() as *const c_void
+ }
+
+ fn ffi_len(&self) -> socklen_t {
+ self.val.len() as socklen_t
+ }
+}
+
+
+#[cfg(test)]
+mod test {
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[test]
+ fn can_get_peercred_on_unix_socket() {
+ use super::super::*;
+
+ let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap();
+ let a_cred = getsockopt(a, super::PeerCredentials).unwrap();
+ let b_cred = getsockopt(b, super::PeerCredentials).unwrap();
+ assert_eq!(a_cred, b_cred);
+ assert!(a_cred.pid() != 0);
+ }
+
+ #[test]
+ fn is_socket_type_unix() {
+ use super::super::*;
+ use ::unistd::close;
+
+ let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap();
+ let a_type = getsockopt(a, super::SockType).unwrap();
+ assert!(a_type == SockType::Stream);
+ close(a).unwrap();
+ close(b).unwrap();
+ }
+
+ #[test]
+ fn is_socket_type_dgram() {
+ use super::super::*;
+ use ::unistd::close;
+
+ let s = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None).unwrap();
+ let s_type = getsockopt(s, super::SockType).unwrap();
+ assert!(s_type == SockType::Datagram);
+ close(s).unwrap();
+ }
+
+ #[cfg(any(target_os = "freebsd",
+ target_os = "linux",
+ target_os = "nacl"))]
+ #[test]
+ fn can_get_listen_on_tcp_socket() {
+ use super::super::*;
+ use ::unistd::close;
+
+ let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap();
+ let s_listening = getsockopt(s, super::AcceptConn).unwrap();
+ assert!(!s_listening);
+ listen(s, 10).unwrap();
+ let s_listening2 = getsockopt(s, super::AcceptConn).unwrap();
+ assert!(s_listening2);
+ close(s).unwrap();
+ }
+
+ #[cfg(target_os = "linux")]
+ #[test]
+ fn is_so_mark_functional() {
+ use super::super::*;
+ use ::unistd::Uid;
+ use ::std::io::{self, Write};
+
+ if !Uid::current().is_root() {
+ let stderr = io::stderr();
+ let mut handle = stderr.lock();
+ writeln!(handle, "SO_MARK requires root privileges. Skipping test.").unwrap();
+ return;
+ }
+
+ let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap();
+ setsockopt(s, super::Mark, &1337).unwrap();
+ let mark = getsockopt(s, super::Mark).unwrap();
+ assert_eq!(mark, 1337);
+ }
+}