Skip to content

Commit

Permalink
Add cmsg PKTINFO for IPv4 and IPv6.
Browse files Browse the repository at this point in the history
ignore pktinfo tests on qemu mips,mips64,powerpc64
Original work by @mcginty.
  • Loading branch information
pusateri committed Dec 15, 2018
1 parent 5a3ac8d commit 940a8de
Show file tree
Hide file tree
Showing 4 changed files with 374 additions and 7 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]
- Added PKTINFO(V4) & V6PKTINFO cmsg support - Android/FreeBSD/iOS/Linux/MacOS.
([#990](https://github.com/nix-rust/nix/pull/990))
### Added
- Added support of CString type in `setsockopt`.
([#972](https://github.com/nix-rust/nix/pull/972))
Expand Down
128 changes: 123 additions & 5 deletions src/sys/socket/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub use self::addr::{
Ipv6Addr,
LinkAddr,
};
#[cfg(any(target_os = "linux", target_os = "android"))]
#[cfg(any(target_os = "android", target_os = "linux"))]
pub use ::sys::socket::addr::netlink::NetlinkAddr;

pub use libc::{
Expand Down Expand Up @@ -153,7 +153,7 @@ libc_bitflags!{
/// 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 = "linux", target_os = "android"))]
#[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
Expand Down Expand Up @@ -526,6 +526,23 @@ pub enum ControlMessage<'a> {
/// 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>),
Expand Down Expand Up @@ -565,19 +582,79 @@ impl<'a> ControlMessage<'a> {
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,
}
}
Expand All @@ -598,7 +675,7 @@ impl<'a> ControlMessage<'a> {
} else {
let cmsg = cmsghdr {
cmsg_len: self.len() as _,
cmsg_level: libc::SOL_SOCKET,
cmsg_level: self.cmsg_level(),
cmsg_type: self.cmsg_type(),
..mem::zeroed() // zero out platform-dependent padding fields
};
Expand All @@ -615,10 +692,29 @@ impl<'a> ControlMessage<'a> {
#[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!(),
}
};
Expand Down Expand Up @@ -650,6 +746,28 @@ impl<'a> ControlMessage<'a> {
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))
}
Expand Down Expand Up @@ -1055,7 +1173,7 @@ pub unsafe fn sockaddr_storage_to_addr(
let pathlen = len - offset_of!(sockaddr_un, sun_path);
Ok(SockAddr::Unix(UnixAddr(sun, pathlen)))
}
#[cfg(any(target_os = "linux", target_os = "android"))]
#[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))))
Expand Down
16 changes: 16 additions & 0 deletions src/sys/socket/sockopt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,22 @@ sockopt_impl!(Both, Mark, libc::SOL_SOCKET, libc::SO_MARK, u32);
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);


/*
*
Expand Down
Loading

0 comments on commit 940a8de

Please sign in to comment.