diff options
Diffstat (limited to 'src/sys/socket/sockopt.rs')
-rw-r--r-- | src/sys/socket/sockopt.rs | 424 |
1 files changed, 324 insertions, 100 deletions
diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index e2f2caf..fcb4be8 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -1,3 +1,4 @@ +//! Socket options as used by `setsockopt` and `getsockopt`. use cfg_if::cfg_if; use super::{GetSockOpt, SetSockOpt}; use crate::Result; @@ -30,7 +31,7 @@ const TCP_CA_NAME_MAX: usize = 16; /// # 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* +/// * `$level:expr` : 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. @@ -41,7 +42,7 @@ const TCP_CA_NAME_MAX: usize = 16; /// * 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) => { + ($name:ident, $level:expr, $flag:path, $ty:ty, $setter:ty) => { impl SetSockOpt for $name { type Val = $ty; @@ -82,7 +83,7 @@ macro_rules! setsockopt_impl { /// * 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) => { + ($name:ident, $level:expr, $flag:path, $ty:ty, $getter:ty) => { impl GetSockOpt for $name { type Val = $ty; @@ -117,7 +118,7 @@ macro_rules! getsockopt_impl { /// * `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* +/// * `$level:expr` : 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. @@ -128,73 +129,99 @@ macro_rules! getsockopt_impl { /// * `$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); + ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, bool) => { + sockopt_impl!($(#[$attr])* + $name, GetOnly, $level, $flag, bool, GetBool); }; - (GetOnly, $name:ident, $level:path, $flag:path, u8) => { - sockopt_impl!(GetOnly, $name, $level, $flag, u8, GetU8); + ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, u8) => { + sockopt_impl!($(#[$attr])* $name, GetOnly, $level, $flag, u8, GetU8); }; - (GetOnly, $name:ident, $level:path, $flag:path, usize) => { - sockopt_impl!(GetOnly, $name, $level, $flag, usize, GetUsize); + ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, usize) => + { + sockopt_impl!($(#[$attr])* + $name, GetOnly, $level, $flag, usize, GetUsize); }; - (SetOnly, $name:ident, $level:path, $flag:path, bool) => { - sockopt_impl!(SetOnly, $name, $level, $flag, bool, SetBool); + ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, bool) => { + sockopt_impl!($(#[$attr])* + $name, SetOnly, $level, $flag, bool, SetBool); }; - (SetOnly, $name:ident, $level:path, $flag:path, u8) => { - sockopt_impl!(SetOnly, $name, $level, $flag, u8, SetU8); + ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, u8) => { + sockopt_impl!($(#[$attr])* $name, SetOnly, $level, $flag, u8, SetU8); }; - (SetOnly, $name:ident, $level:path, $flag:path, usize) => { - sockopt_impl!(SetOnly, $name, $level, $flag, usize, SetUsize); + ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, usize) => + { + sockopt_impl!($(#[$attr])* + $name, SetOnly, $level, $flag, usize, SetUsize); }; - (Both, $name:ident, $level:path, $flag:path, bool) => { - sockopt_impl!(Both, $name, $level, $flag, bool, GetBool, SetBool); + ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, bool) => { + sockopt_impl!($(#[$attr])* + $name, Both, $level, $flag, bool, GetBool, SetBool); }; - (Both, $name:ident, $level:path, $flag:path, u8) => { - sockopt_impl!(Both, $name, $level, $flag, u8, GetU8, SetU8); + ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, u8) => { + sockopt_impl!($(#[$attr])* + $name, Both, $level, $flag, u8, GetU8, SetU8); }; - (Both, $name:ident, $level:path, $flag:path, usize) => { - sockopt_impl!(Both, $name, $level, $flag, usize, GetUsize, SetUsize); + ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, usize) => { + sockopt_impl!($(#[$attr])* + $name, Both, $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); + ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, + OsString<$array:ty>) => + { + sockopt_impl!($(#[$attr])* + $name, Both, $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>); + ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty) => + { + sockopt_impl!($(#[$attr])* + $name, GetOnly, $level, $flag, $ty, GetStruct<$ty>); }; - (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => { + ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty, + $getter:ty) => + { + $(#[$attr])* #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 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>); + ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty) => + { + sockopt_impl!($(#[$attr])* + $name, SetOnly, $level, $flag, $ty, SetStruct<$ty>); }; - (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => { + ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty, + $setter:ty) => + { + $(#[$attr])* #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct $name; setsockopt_impl!($name, $level, $flag, $ty, $setter); }; - (Both, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty, $setter:ty) => { + ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, $ty:ty, + $getter:ty, $setter:ty) => + { + $(#[$attr])* #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct $name; @@ -202,8 +229,10 @@ macro_rules! sockopt_impl { 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>); + ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, $ty:ty) => { + sockopt_impl!($(#[$attr])* + $name, Both, $level, $flag, $ty, GetStruct<$ty>, + SetStruct<$ty>); }; } @@ -213,17 +242,45 @@ macro_rules! sockopt_impl { * */ -sockopt_impl!(Both, ReuseAddr, libc::SOL_SOCKET, libc::SO_REUSEADDR, bool); +sockopt_impl!( + /// Enables local address reuse + ReuseAddr, Both, libc::SOL_SOCKET, libc::SO_REUSEADDR, bool +); #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] -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); +sockopt_impl!( + /// Permits multiple AF_INET or AF_INET6 sockets to be bound to an + /// identical socket address. + ReusePort, Both, libc::SOL_SOCKET, libc::SO_REUSEPORT, bool); +sockopt_impl!( + /// Under most circumstances, TCP sends data when it is presented; when + /// outstanding data has not yet been acknowledged, it gathers small amounts + /// of output to be sent in a single packet once an acknowledgement is + /// received. For a small number of clients, such as window systems that + /// send a stream of mouse events which receive no replies, this + /// packetization may cause significant delays. The boolean option + /// TCP_NODELAY defeats this algorithm. + TcpNoDelay, Both, libc::IPPROTO_TCP, libc::TCP_NODELAY, bool); +sockopt_impl!( + /// When enabled, a close(2) or shutdown(2) will not return until all + /// queued messages for the socket have been successfully sent or the + /// linger timeout has been reached. + Linger, Both, libc::SOL_SOCKET, libc::SO_LINGER, libc::linger); +sockopt_impl!( + /// Join a multicast group + IpAddMembership, SetOnly, libc::IPPROTO_IP, libc::IP_ADD_MEMBERSHIP, + super::IpMembershipRequest); +sockopt_impl!( + /// Leave a multicast group. + IpDropMembership, SetOnly, 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); + sockopt_impl!( + /// Join an IPv6 multicast group. + Ipv6AddMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_ADD_MEMBERSHIP, super::Ipv6MembershipRequest); + sockopt_impl!( + /// Leave an IPv6 multicast group. + Ipv6DropMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_DROP_MEMBERSHIP, super::Ipv6MembershipRequest); } else if #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "illumos", @@ -232,64 +289,185 @@ cfg_if! { target_os = "netbsd", target_os = "openbsd", target_os = "solaris"))] { - 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!( + /// Join an IPv6 multicast group. + Ipv6AddMembership, SetOnly, libc::IPPROTO_IPV6, + libc::IPV6_JOIN_GROUP, super::Ipv6MembershipRequest); + sockopt_impl!( + /// Leave an IPv6 multicast group. + Ipv6DropMembership, SetOnly, 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!( + /// Set or read the time-to-live value of outgoing multicast packets for + /// this socket. + IpMulticastTtl, Both, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL, u8); +sockopt_impl!( + /// Set or read a boolean integer argument that determines whether sent + /// multicast packets should be looped back to the local sockets. + IpMulticastLoop, Both, libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP, bool); #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] -sockopt_impl!(Both, IpFreebind, libc::IPPROTO_IP, libc::IP_FREEBIND, 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); +sockopt_impl!( + /// If enabled, this boolean option allows binding to an IP address that + /// is nonlocal or does not (yet) exist. + IpFreebind, Both, libc::IPPROTO_IP, libc::IP_FREEBIND, bool); +sockopt_impl!( + /// Specify the receiving timeout until reporting an error. + ReceiveTimeout, Both, libc::SOL_SOCKET, libc::SO_RCVTIMEO, TimeVal); +sockopt_impl!( + /// Specify the sending timeout until reporting an error. + SendTimeout, Both, libc::SOL_SOCKET, libc::SO_SNDTIMEO, TimeVal); +sockopt_impl!( + /// Set or get the broadcast flag. + Broadcast, Both, libc::SOL_SOCKET, libc::SO_BROADCAST, bool); +sockopt_impl!( + /// If this option is enabled, out-of-band data is directly placed into + /// the receive data stream. + OobInline, Both, libc::SOL_SOCKET, libc::SO_OOBINLINE, bool); +sockopt_impl!( + /// Get and clear the pending socket error. + SocketError, GetOnly, libc::SOL_SOCKET, libc::SO_ERROR, i32); +sockopt_impl!( + /// Enable sending of keep-alive messages on connection-oriented sockets. + KeepAlive, Both, libc::SOL_SOCKET, libc::SO_KEEPALIVE, bool); +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "ios" +))] +sockopt_impl!( + /// Get the credentials of the peer process of a connected unix domain + /// socket. + LocalPeerCred, GetOnly, 0, libc::LOCAL_PEERCRED, super::XuCred); #[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!(GetOnly, PeerCredentials, libc::SOL_SOCKET, libc::SO_PEERCRED, super::UnixCredentials); +sockopt_impl!( + /// Return the credentials of the foreign process connected to this socket. + PeerCredentials, GetOnly, 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); +sockopt_impl!( + /// Specify the amount of time, in seconds, that the connection must be idle + /// before keepalive probes (if enabled) are sent. + TcpKeepAlive, Both, 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!( + /// The time (in seconds) the connection needs to remain idle before TCP + /// starts sending keepalive probes + TcpKeepIdle, Both, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, u32); +cfg_if! { + if #[cfg(any(target_os = "android", target_os = "linux"))] { + sockopt_impl!( + /// The maximum segment size for outgoing TCP packets. + TcpMaxSeg, Both, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32); + } else { + sockopt_impl!( + /// The maximum segment size for outgoing TCP packets. + TcpMaxSeg, GetOnly, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32); + } +} #[cfg(not(target_os = "openbsd"))] -sockopt_impl!(Both, TcpKeepCount, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, u32); +sockopt_impl!( + /// The maximum number of keepalive probes TCP should send before + /// dropping the connection. + TcpKeepCount, Both, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, u32); +#[cfg(any(target_os = "android", + target_os = "fuchsia", + target_os = "linux"))] +sockopt_impl!( + #[allow(missing_docs)] + // Not documented by Linux! + TcpRepair, Both, libc::IPPROTO_TCP, libc::TCP_REPAIR, u32); #[cfg(not(target_os = "openbsd"))] -sockopt_impl!(Both, TcpKeepInterval, libc::IPPROTO_TCP, libc::TCP_KEEPINTVL, u32); +sockopt_impl!( + /// The time (in seconds) between individual keepalive probes. + TcpKeepInterval, Both, libc::IPPROTO_TCP, libc::TCP_KEEPINTVL, u32); #[cfg(any(target_os = "fuchsia", target_os = "linux"))] -sockopt_impl!(Both, TcpUserTimeout, libc::IPPROTO_TCP, libc::TCP_USER_TIMEOUT, u32); -sockopt_impl!(Both, RcvBuf, libc::SOL_SOCKET, libc::SO_RCVBUF, usize); -sockopt_impl!(Both, SndBuf, libc::SOL_SOCKET, libc::SO_SNDBUF, usize); +sockopt_impl!( + /// Specifies the maximum amount of time in milliseconds that transmitted + /// data may remain unacknowledged before TCP will forcibly close the + /// corresponding connection + TcpUserTimeout, Both, libc::IPPROTO_TCP, libc::TCP_USER_TIMEOUT, u32); +sockopt_impl!( + /// Sets or gets the maximum socket receive buffer in bytes. + RcvBuf, Both, libc::SOL_SOCKET, libc::SO_RCVBUF, usize); +sockopt_impl!( + /// Sets or gets the maximum socket send buffer in bytes. + SndBuf, Both, libc::SOL_SOCKET, libc::SO_SNDBUF, usize); +#[cfg(any(target_os = "android", target_os = "linux"))] +sockopt_impl!( + /// Using this socket option, a privileged (`CAP_NET_ADMIN`) process can + /// perform the same task as `SO_RCVBUF`, but the `rmem_max limit` can be + /// overridden. + RcvBufForce, SetOnly, libc::SOL_SOCKET, libc::SO_RCVBUFFORCE, usize); #[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!(SetOnly, RcvBufForce, libc::SOL_SOCKET, libc::SO_RCVBUFFORCE, usize); +sockopt_impl!( + /// Using this socket option, a privileged (`CAP_NET_ADMIN`) process can + /// perform the same task as `SO_SNDBUF`, but the `wmem_max` limit can be + /// overridden. + SndBufForce, SetOnly, libc::SOL_SOCKET, libc::SO_SNDBUFFORCE, usize); +sockopt_impl!( + /// Gets the socket type as an integer. + SockType, GetOnly, libc::SOL_SOCKET, libc::SO_TYPE, super::SockType); +sockopt_impl!( + /// Returns a value indicating whether or not this socket has been marked to + /// accept connections with `listen(2)`. + AcceptConn, GetOnly, libc::SOL_SOCKET, libc::SO_ACCEPTCONN, bool); #[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); +sockopt_impl!( + /// Bind this socket to a particular device like “eth0”. + BindToDevice, Both, libc::SOL_SOCKET, libc::SO_BINDTODEVICE, OsString<[u8; libc::IFNAMSIZ]>); #[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!(Both, BindToDevice, libc::SOL_SOCKET, libc::SO_BINDTODEVICE, OsString<[u8; libc::IFNAMSIZ]>); +sockopt_impl!( + #[allow(missing_docs)] + // Not documented by Linux! + OriginalDst, GetOnly, libc::SOL_IP, libc::SO_ORIGINAL_DST, libc::sockaddr_in); #[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); +sockopt_impl!( + #[allow(missing_docs)] + // Not documented by Linux! + Ip6tOriginalDst, GetOnly, libc::SOL_IPV6, libc::IP6T_SO_ORIGINAL_DST, libc::sockaddr_in6); +sockopt_impl!( + /// Enable or disable the receiving of the `SO_TIMESTAMP` control message. + ReceiveTimestamp, Both, libc::SOL_SOCKET, libc::SO_TIMESTAMP, bool); #[cfg(all(target_os = "linux"))] -sockopt_impl!(Both, ReceiveTimestampns, libc::SOL_SOCKET, libc::SO_TIMESTAMPNS, bool); +sockopt_impl!( + /// Enable or disable the receiving of the `SO_TIMESTAMPNS` control message. + ReceiveTimestampns, Both, libc::SOL_SOCKET, libc::SO_TIMESTAMPNS, bool); #[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!(Both, IpTransparent, libc::SOL_IP, libc::IP_TRANSPARENT, bool); +sockopt_impl!( + /// Setting this boolean option enables transparent proxying on this socket. + IpTransparent, Both, libc::SOL_IP, libc::IP_TRANSPARENT, bool); #[cfg(target_os = "openbsd")] -sockopt_impl!(Both, BindAny, libc::SOL_SOCKET, libc::SO_BINDANY, bool); +sockopt_impl!( + /// Allows the socket to be bound to addresses which are not local to the + /// machine, so it can be used to make a transparent proxy. + BindAny, Both, libc::SOL_SOCKET, libc::SO_BINDANY, bool); #[cfg(target_os = "freebsd")] -sockopt_impl!(Both, BindAny, libc::IPPROTO_IP, libc::IP_BINDANY, bool); +sockopt_impl!( + /// Can `bind(2)` to any address, even one not bound to any available + /// network interface in the system. + BindAny, Both, libc::IPPROTO_IP, libc::IP_BINDANY, bool); #[cfg(target_os = "linux")] -sockopt_impl!(Both, Mark, libc::SOL_SOCKET, libc::SO_MARK, u32); +sockopt_impl!( + /// Set the mark for each packet sent through this socket (similar to the + /// netfilter MARK target but socket-based). + Mark, Both, 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); +sockopt_impl!( + /// Enable or disable the receiving of the `SCM_CREDENTIALS` control + /// message. + PassCred, Both, 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]>); +sockopt_impl!( + /// This option allows the caller to set the TCP congestion control + /// algorithm to be used, on a per-socket basis. + TcpCongestion, Both, libc::IPPROTO_TCP, libc::TCP_CONGESTION, OsString<[u8; TCP_CA_NAME_MAX]>); #[cfg(any( target_os = "android", target_os = "ios", @@ -297,7 +475,10 @@ sockopt_impl!(Both, TcpCongestion, libc::IPPROTO_TCP, libc::TCP_CONGESTION, OsSt target_os = "macos", target_os = "netbsd", ))] -sockopt_impl!(Both, Ipv4PacketInfo, libc::IPPROTO_IP, libc::IP_PKTINFO, bool); +sockopt_impl!( + /// Pass an `IP_PKTINFO` ancillary message that contains a pktinfo + /// structure that supplies some information about the incoming packet. + Ipv4PacketInfo, Both, libc::IPPROTO_IP, libc::IP_PKTINFO, bool); #[cfg(any( target_os = "android", target_os = "freebsd", @@ -307,7 +488,10 @@ sockopt_impl!(Both, Ipv4PacketInfo, libc::IPPROTO_IP, libc::IP_PKTINFO, bool); target_os = "netbsd", target_os = "openbsd", ))] -sockopt_impl!(Both, Ipv6RecvPacketInfo, libc::IPPROTO_IPV6, libc::IPV6_RECVPKTINFO, bool); +sockopt_impl!( + /// Set delivery of the `IPV6_PKTINFO` control message on incoming + /// datagrams. + Ipv6RecvPacketInfo, Both, libc::IPPROTO_IPV6, libc::IPV6_RECVPKTINFO, bool); #[cfg(any( target_os = "freebsd", target_os = "ios", @@ -315,7 +499,10 @@ sockopt_impl!(Both, Ipv6RecvPacketInfo, libc::IPPROTO_IPV6, libc::IPV6_RECVPKTIN target_os = "netbsd", target_os = "openbsd", ))] -sockopt_impl!(Both, Ipv4RecvIf, libc::IPPROTO_IP, libc::IP_RECVIF, bool); +sockopt_impl!( + /// The `recvmsg(2)` call returns a `struct sockaddr_dl` corresponding to + /// the interface on which the packet was received. + Ipv4RecvIf, Both, libc::IPPROTO_IP, libc::IP_RECVIF, bool); #[cfg(any( target_os = "freebsd", target_os = "ios", @@ -323,14 +510,49 @@ sockopt_impl!(Both, Ipv4RecvIf, libc::IPPROTO_IP, libc::IP_RECVIF, bool); target_os = "netbsd", target_os = "openbsd", ))] -sockopt_impl!(Both, Ipv4RecvDstAddr, libc::IPPROTO_IP, libc::IP_RECVDSTADDR, bool); +sockopt_impl!( + /// The `recvmsg(2)` call will return the destination IP address for a UDP + /// datagram. + Ipv4RecvDstAddr, Both, libc::IPPROTO_IP, libc::IP_RECVDSTADDR, bool); #[cfg(target_os = "linux")] -sockopt_impl!(Both, UdpGsoSegment, libc::SOL_UDP, libc::UDP_SEGMENT, libc::c_int); +sockopt_impl!( + #[allow(missing_docs)] + // Not documented by Linux! + UdpGsoSegment, Both, libc::SOL_UDP, libc::UDP_SEGMENT, libc::c_int); #[cfg(target_os = "linux")] -sockopt_impl!(Both, UdpGroSegment, libc::IPPROTO_UDP, libc::UDP_GRO, bool); +sockopt_impl!( + #[allow(missing_docs)] + // Not documented by Linux! + UdpGroSegment, Both, libc::IPPROTO_UDP, libc::UDP_GRO, bool); #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] -sockopt_impl!(Both, RxqOvfl, libc::SOL_SOCKET, libc::SO_RXQ_OVFL, libc::c_int); - +sockopt_impl!( + /// Indicates that an unsigned 32-bit value ancillary message (cmsg) should + /// be attached to received skbs indicating the number of packets dropped by + /// the socket since its creation. + RxqOvfl, Both, libc::SOL_SOCKET, libc::SO_RXQ_OVFL, libc::c_int); +sockopt_impl!( + /// The socket is restricted to sending and receiving IPv6 packets only. + Ipv6V6Only, Both, libc::IPPROTO_IPV6, libc::IPV6_V6ONLY, bool); +#[cfg(any(target_os = "android", target_os = "linux"))] +sockopt_impl!( + /// Enable extended reliable error message passing. + Ipv4RecvErr, Both, libc::IPPROTO_IP, libc::IP_RECVERR, bool); +#[cfg(any(target_os = "android", target_os = "linux"))] +sockopt_impl!( + /// Control receiving of asynchronous error options. + Ipv6RecvErr, Both, libc::IPPROTO_IPV6, libc::IPV6_RECVERR, bool); +#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +sockopt_impl!( + /// Set or retrieve the current time-to-live field that is used in every + /// packet sent from this socket. + Ipv4Ttl, Both, libc::IPPROTO_IP, libc::IP_TTL, libc::c_int); +#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +sockopt_impl!( + /// Set the unicast hop limit for the socket. + Ipv6Ttl, Both, libc::IPPROTO_IPV6, libc::IPV6_UNICAST_HOPS, libc::c_int); + +#[allow(missing_docs)] +// Not documented by Linux! #[cfg(any(target_os = "android", target_os = "linux"))] #[derive(Copy, Clone, Debug)] pub struct AlgSetAeadAuthSize; @@ -353,6 +575,8 @@ impl SetSockOpt for AlgSetAeadAuthSize { } } +#[allow(missing_docs)] +// Not documented by Linux! #[cfg(any(target_os = "android", target_os = "linux"))] #[derive(Clone, Debug)] pub struct AlgSetKey<T>(::std::marker::PhantomData<T>); @@ -387,9 +611,9 @@ impl<T> SetSockOpt for AlgSetKey<T> where T: AsRef<[u8]> + Clone { */ /// Helper trait that describes what is expected from a `GetSockOpt` getter. -unsafe trait Get<T> { +trait Get<T> { /// Returns an uninitialized value. - unsafe fn uninit() -> Self; + fn uninit() -> 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; @@ -401,7 +625,7 @@ unsafe trait Get<T> { } /// Helper trait that describes what is expected from a `SetSockOpt` setter. -unsafe trait Set<'a, T> { +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 @@ -418,8 +642,8 @@ struct GetStruct<T> { val: MaybeUninit<T>, } -unsafe impl<T> Get<T> for GetStruct<T> { - unsafe fn uninit() -> Self { +impl<T> Get<T> for GetStruct<T> { + fn uninit() -> Self { GetStruct { len: mem::size_of::<T>() as socklen_t, val: MaybeUninit::uninit(), @@ -445,7 +669,7 @@ struct SetStruct<'a, T: 'static> { ptr: &'a T, } -unsafe impl<'a, T> Set<'a, T> for SetStruct<'a, T> { +impl<'a, T> Set<'a, T> for SetStruct<'a, T> { fn new(ptr: &'a T) -> SetStruct<'a, T> { SetStruct { ptr } } @@ -465,8 +689,8 @@ struct GetBool { val: MaybeUninit<c_int>, } -unsafe impl Get<bool> for GetBool { - unsafe fn uninit() -> Self { +impl Get<bool> for GetBool { + fn uninit() -> Self { GetBool { len: mem::size_of::<c_int>() as socklen_t, val: MaybeUninit::uninit(), @@ -492,7 +716,7 @@ struct SetBool { val: c_int, } -unsafe impl<'a> Set<'a, bool> for SetBool { +impl<'a> Set<'a, bool> for SetBool { fn new(val: &'a bool) -> SetBool { SetBool { val: if *val { 1 } else { 0 } } } @@ -512,8 +736,8 @@ struct GetU8 { val: MaybeUninit<u8>, } -unsafe impl Get<u8> for GetU8 { - unsafe fn uninit() -> Self { +impl Get<u8> for GetU8 { + fn uninit() -> Self { GetU8 { len: mem::size_of::<u8>() as socklen_t, val: MaybeUninit::uninit(), @@ -539,7 +763,7 @@ struct SetU8 { val: u8, } -unsafe impl<'a> Set<'a, u8> for SetU8 { +impl<'a> Set<'a, u8> for SetU8 { fn new(val: &'a u8) -> SetU8 { SetU8 { val: *val as u8 } } @@ -559,8 +783,8 @@ struct GetUsize { val: MaybeUninit<c_int>, } -unsafe impl Get<usize> for GetUsize { - unsafe fn uninit() -> Self { +impl Get<usize> for GetUsize { + fn uninit() -> Self { GetUsize { len: mem::size_of::<c_int>() as socklen_t, val: MaybeUninit::uninit(), @@ -586,7 +810,7 @@ struct SetUsize { val: c_int, } -unsafe impl<'a> Set<'a, usize> for SetUsize { +impl<'a> Set<'a, usize> for SetUsize { fn new(val: &'a usize) -> SetUsize { SetUsize { val: *val as c_int } } @@ -606,8 +830,8 @@ struct GetOsString<T: AsMut<[u8]>> { val: MaybeUninit<T>, } -unsafe impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> { - unsafe fn uninit() -> Self { +impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> { + fn uninit() -> Self { GetOsString { len: mem::size_of::<T>() as socklen_t, val: MaybeUninit::uninit(), @@ -634,7 +858,7 @@ struct SetOsString<'a> { val: &'a OsStr, } -unsafe impl<'a> Set<'a, OsString> for SetOsString<'a> { +impl<'a> Set<'a, OsString> for SetOsString<'a> { fn new(val: &'a OsString) -> SetOsString { SetOsString { val: val.as_os_str() } } |