Skip to content

Commit

Permalink
Merge #990
Browse files Browse the repository at this point in the history
990: Add cmsg PKTINFO for IPv4 and IPv6. r=asomers a=pusateri

Replaces #891 and attempts to address all previous concerns.

Co-authored-by: Tom Pusateri <pusateri@bangj.com>
  • Loading branch information
bors[bot] and pusateri committed Dec 17, 2018
2 parents 51bd085 + 940a8de commit f404d9d
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 f404d9d

Please sign in to comment.