#[cfg(any(linux_android, target_os = "illumos"))]
use super::SetSockOpt;
use crate::sys::time::TimeVal;
#[cfg(any(linux_android, target_os = "illumos"))]
use crate::{errno::Errno, Result};
use cfg_if::cfg_if;
use libc::{self, c_int, c_void, socklen_t};
#[cfg(apple_targets)]
use std::ffi::CString;
use std::ffi::{CStr, OsStr, OsString};
use std::mem::{self, MaybeUninit};
use std::os::fd::OwnedFd;
use std::os::unix::ffi::OsStrExt;
#[cfg(any(linux_android, target_os = "illumos"))]
use std::os::unix::io::{AsFd, AsRawFd};
#[cfg(any(target_os = "freebsd", target_os = "linux"))]
#[cfg(feature = "net")]
const TCP_CA_NAME_MAX: usize = 16;
#[macro_export]
macro_rules! setsockopt_impl {
($name:ident, $level:expr, $flag:path, $ty:ty, $setter:ty) => {
#[allow(deprecated)] impl $crate::sys::socket::SetSockOpt for $name {
type Val = $ty;
fn set<F: std::os::unix::io::AsFd>(
&self,
fd: &F,
val: &$ty,
) -> $crate::Result<()> {
use std::os::fd::AsRawFd;
use $crate::sys::socket::sockopt::Set;
let setter: $setter = Set::new(val);
let level = $level;
let flag = $flag;
let res = unsafe {
libc::setsockopt(
fd.as_fd().as_raw_fd(),
level,
flag,
setter.ffi_ptr(),
setter.ffi_len(),
)
};
$crate::errno::Errno::result(res).map(drop)
}
}
};
}
#[macro_export]
macro_rules! getsockopt_impl {
($name:ident, $level:expr, $flag:path, $ty:ty, $getter:ty) => {
#[allow(deprecated)] impl $crate::sys::socket::GetSockOpt for $name {
type Val = $ty;
fn get<F: std::os::unix::io::AsFd>(
&self,
fd: &F,
) -> $crate::Result<$ty> {
use std::os::fd::AsRawFd;
use $crate::sys::socket::sockopt::Get;
let mut getter: $getter = Get::uninit();
let level = $level;
let flag = $flag;
let res = unsafe {
libc::getsockopt(
fd.as_fd().as_raw_fd(),
level,
flag,
getter.ffi_ptr(),
getter.ffi_len(),
)
};
$crate::errno::Errno::result(res)?;
let gotten = unsafe { getter.assume_init() };
match <$ty>::try_from(gotten) {
#[allow(unreachable_patterns)]
Err(_) => Err($crate::errno::Errno::EINVAL),
Ok(r) => Ok(r),
}
}
}
};
}
#[allow(unused_macro_rules)]
#[macro_export]
macro_rules! sockopt_impl {
($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, bool) => {
sockopt_impl!($(#[$attr])*
$name, GetOnly, $level, $flag, bool, $crate::sys::socket::sockopt::GetBool);
};
($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, u8) => {
sockopt_impl!($(#[$attr])* $name, GetOnly, $level, $flag, u8, $crate::sys::socket::sockopt::GetU8);
};
($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, usize) =>
{
sockopt_impl!($(#[$attr])*
$name, GetOnly, $level, $flag, usize, $crate::sys::socket::sockopt::GetUsize);
};
($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, OwnedFd) =>
{
sockopt_impl!($(#[$attr])*
$name, GetOnly, $level, $flag, OwnedFd, $crate::sys::socket::sockopt::GetOwnedFd);
};
($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, bool) => {
sockopt_impl!($(#[$attr])*
$name, SetOnly, $level, $flag, bool, $crate::sys::socket::sockopt::SetBool);
};
($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, u8) => {
sockopt_impl!($(#[$attr])* $name, SetOnly, $level, $flag, u8, $crate::sys::socket::sockopt::SetU8);
};
($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, usize) =>
{
sockopt_impl!($(#[$attr])*
$name, SetOnly, $level, $flag, usize, $crate::sys::socket::sockopt::SetUsize);
};
($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, OwnedFd) =>
{
sockopt_impl!($(#[$attr])*
$name, SetOnly, $level, $flag, OwnedFd, $crate::sys::socket::sockopt::SetOwnedFd);
};
($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, bool) => {
sockopt_impl!($(#[$attr])*
$name, Both, $level, $flag, bool, $crate::sys::socket::sockopt::GetBool, $crate::sys::socket::sockopt::SetBool);
};
($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, u8) => {
sockopt_impl!($(#[$attr])*
$name, Both, $level, $flag, u8, $crate::sys::socket::sockopt::GetU8, $crate::sys::socket::sockopt::SetU8);
};
($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, usize) => {
sockopt_impl!($(#[$attr])*
$name, Both, $level, $flag, usize, $crate::sys::socket::sockopt::GetUsize, $crate::sys::socket::sockopt::SetUsize);
};
($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, OwnedFd) => {
sockopt_impl!($(#[$attr])*
$name, Both, $level, $flag, OwnedFd, $crate::sys::socket::sockopt::GetOwnedFd, $crate::sys::socket::sockopt::SetOwnedFd);
};
($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path,
OsString<$array:ty>) =>
{
sockopt_impl!($(#[$attr])*
$name, Both, $level, $flag, std::ffi::OsString, $crate::sys::socket::sockopt::GetOsString<$array>,
$crate::sys::socket::sockopt::SetOsString);
};
($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty) =>
{
sockopt_impl!($(#[$attr])*
$name, GetOnly, $level, $flag, $ty, $crate::sys::socket::sockopt::GetStruct<$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);
};
($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty) =>
{
sockopt_impl!($(#[$attr])*
$name, SetOnly, $level, $flag, $ty, $crate::sys::socket::sockopt::SetStruct<$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);
};
($(#[$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;
setsockopt_impl!($name, $level, $flag, $ty, $setter);
getsockopt_impl!($name, $level, $flag, $ty, $getter);
};
($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, $ty:ty) => {
sockopt_impl!($(#[$attr])*
$name, Both, $level, $flag, $ty, $crate::sys::socket::sockopt::GetStruct<$ty>,
$crate::sys::socket::sockopt::SetStruct<$ty>);
};
}
sockopt_impl!(
ReuseAddr,
Both,
libc::SOL_SOCKET,
libc::SO_REUSEADDR,
bool
);
#[cfg(not(any(solarish, target_os = "cygwin")))]
sockopt_impl!(
ReusePort,
Both,
libc::SOL_SOCKET,
libc::SO_REUSEPORT,
bool
);
#[cfg(target_os = "freebsd")]
sockopt_impl!(
ReusePortLb,
Both,
libc::SOL_SOCKET,
libc::SO_REUSEPORT_LB,
bool
);
#[cfg(target_os = "freebsd")]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
TcpFunctionBlk,
Both,
libc::IPPROTO_TCP,
libc::TCP_FUNCTION_BLK,
libc::tcp_function_set
);
#[cfg(target_os = "freebsd")]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
TcpFunctionAlias,
GetOnly,
libc::IPPROTO_TCP,
libc::TCP_FUNCTION_ALIAS,
libc::tcp_function_set
);
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
TcpNoDelay,
Both,
libc::IPPROTO_TCP,
libc::TCP_NODELAY,
bool
);
sockopt_impl!(
Linger,
Both,
libc::SOL_SOCKET,
libc::SO_LINGER,
libc::linger
);
#[cfg(apple_targets)]
sockopt_impl!(
LingerSec,
Both,
libc::SOL_SOCKET,
libc::SO_LINGER_SEC,
libc::linger
);
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
IpAddMembership,
SetOnly,
libc::IPPROTO_IP,
libc::IP_ADD_MEMBERSHIP,
super::IpMembershipRequest
);
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
IpDropMembership,
SetOnly,
libc::IPPROTO_IP,
libc::IP_DROP_MEMBERSHIP,
super::IpMembershipRequest
);
cfg_if! {
if #[cfg(linux_android)] {
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv6AddMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_ADD_MEMBERSHIP, super::Ipv6MembershipRequest);
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv6DropMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_DROP_MEMBERSHIP, super::Ipv6MembershipRequest);
} else if #[cfg(any(bsd, solarish))] {
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv6AddMembership, SetOnly, libc::IPPROTO_IPV6,
libc::IPV6_JOIN_GROUP, super::Ipv6MembershipRequest);
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv6DropMembership, SetOnly, libc::IPPROTO_IPV6,
libc::IPV6_LEAVE_GROUP, super::Ipv6MembershipRequest);
}
}
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
IpMulticastTtl,
Both,
libc::IPPROTO_IP,
libc::IP_MULTICAST_TTL,
u8
);
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv6MulticastHops,
Both,
libc::IPPROTO_IPV6,
libc::IPV6_MULTICAST_HOPS,
libc::c_int
);
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
IpMulticastLoop,
Both,
libc::IPPROTO_IP,
libc::IP_MULTICAST_LOOP,
bool
);
#[cfg(target_os = "linux")]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Priority,
Both,
libc::SOL_SOCKET,
libc::SO_PRIORITY,
libc::c_int
);
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
sockopt_impl!(
#[deprecated(since = "0.30.0", note = "Use Ipv4Tos instead")]
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
IpTos,
Both,
libc::IPPROTO_IP,
libc::IP_TOS,
libc::c_int
);
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv4Tos,
Both,
libc::IPPROTO_IP,
libc::IP_TOS,
libc::c_int
);
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
IpRecvTos,
Both,
libc::IPPROTO_IP,
libc::IP_RECVTOS,
bool
);
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv6TClass,
Both,
libc::IPPROTO_IPV6,
libc::IPV6_TCLASS,
libc::c_int
);
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv6RecvTClass,
Both,
libc::IPPROTO_IPV6,
libc::IPV6_RECVTCLASS,
bool
);
#[cfg(any(linux_android, target_os = "fuchsia"))]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
IpFreebind,
Both,
libc::IPPROTO_IP,
libc::IP_FREEBIND,
bool
);
#[cfg(linux_android)]
#[cfg(feature = "net")]
#[cfg(not(target_env = "uclibc"))]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
IpBindAddressNoPort,
Both,
libc::IPPROTO_IP,
libc::IP_BIND_ADDRESS_NO_PORT,
bool
);
sockopt_impl!(
ReceiveTimeout,
Both,
libc::SOL_SOCKET,
libc::SO_RCVTIMEO,
TimeVal
);
sockopt_impl!(
SendTimeout,
Both,
libc::SOL_SOCKET,
libc::SO_SNDTIMEO,
TimeVal
);
sockopt_impl!(
Broadcast,
Both,
libc::SOL_SOCKET,
libc::SO_BROADCAST,
bool
);
sockopt_impl!(
OobInline,
Both,
libc::SOL_SOCKET,
libc::SO_OOBINLINE,
bool
);
sockopt_impl!(
SocketError,
GetOnly,
libc::SOL_SOCKET,
libc::SO_ERROR,
i32
);
sockopt_impl!(
DontRoute,
Both,
libc::SOL_SOCKET,
libc::SO_DONTROUTE,
bool
);
sockopt_impl!(
KeepAlive,
Both,
libc::SOL_SOCKET,
libc::SO_KEEPALIVE,
bool
);
#[cfg(freebsdlike)]
sockopt_impl!(
LocalPeerCred,
GetOnly,
0,
libc::LOCAL_PEERCRED,
super::XuCred
);
#[cfg(apple_targets)]
sockopt_impl!(
LocalPeerCred,
GetOnly,
libc::SOL_LOCAL,
libc::LOCAL_PEERCRED,
super::XuCred
);
#[cfg(apple_targets)]
sockopt_impl!(
LocalPeerPid,
GetOnly,
libc::SOL_LOCAL,
libc::LOCAL_PEERPID,
libc::c_int
);
#[cfg(apple_targets)]
sockopt_impl!(
LocalPeerToken,
GetOnly,
libc::SOL_LOCAL,
libc::LOCAL_PEERTOKEN,
super::audit_token_t
);
#[cfg(linux_android)]
sockopt_impl!(
PeerCredentials,
GetOnly,
libc::SOL_SOCKET,
libc::SO_PEERCRED,
super::UnixCredentials
);
#[cfg(target_os = "linux")]
sockopt_impl!(
PeerPidfd,
GetOnly,
libc::SOL_SOCKET,
libc::SO_PEERPIDFD,
OwnedFd
);
#[cfg(target_os = "freebsd")]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
ListenQLimit,
GetOnly,
libc::SOL_SOCKET,
libc::SO_LISTENQLIMIT,
u32
);
#[cfg(apple_targets)]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
TcpKeepAlive,
Both,
libc::IPPROTO_TCP,
libc::TCP_KEEPALIVE,
u32
);
#[cfg(any(freebsdlike, linux_android))]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
TcpKeepIdle,
Both,
libc::IPPROTO_TCP,
libc::TCP_KEEPIDLE,
u32
);
cfg_if! {
if #[cfg(any(linux_android, apple_targets))] {
sockopt_impl!(
TcpMaxSeg, Both, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32);
} else if #[cfg(not(target_os = "redox"))] {
sockopt_impl!(
TcpMaxSeg, GetOnly, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32);
}
}
#[cfg(not(any(
target_os = "openbsd",
target_os = "haiku",
target_os = "redox"
)))]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
TcpKeepCount,
Both,
libc::IPPROTO_TCP,
libc::TCP_KEEPCNT,
u32
);
#[cfg(any(linux_android, target_os = "fuchsia"))]
sockopt_impl!(
#[allow(missing_docs)]
TcpRepair,
Both,
libc::IPPROTO_TCP,
libc::TCP_REPAIR,
u32
);
#[cfg(not(any(
target_os = "openbsd",
target_os = "haiku",
target_os = "redox"
)))]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
TcpKeepInterval,
Both,
libc::IPPROTO_TCP,
libc::TCP_KEEPINTVL,
u32
);
#[cfg(any(target_os = "fuchsia", target_os = "linux"))]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
TcpUserTimeout,
Both,
libc::IPPROTO_TCP,
libc::TCP_USER_TIMEOUT,
u32
);
#[cfg(linux_android)]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
TcpFastOpenConnect,
Both,
libc::IPPROTO_TCP,
libc::TCP_FASTOPEN_CONNECT,
bool
);
sockopt_impl!(
RcvBuf,
Both,
libc::SOL_SOCKET,
libc::SO_RCVBUF,
usize
);
sockopt_impl!(
SndBuf,
Both,
libc::SOL_SOCKET,
libc::SO_SNDBUF,
usize
);
#[cfg(linux_android)]
sockopt_impl!(
RcvBufForce,
SetOnly,
libc::SOL_SOCKET,
libc::SO_RCVBUFFORCE,
usize
);
#[cfg(linux_android)]
sockopt_impl!(
SndBufForce,
SetOnly,
libc::SOL_SOCKET,
libc::SO_SNDBUFFORCE,
usize
);
sockopt_impl!(
SockType,
GetOnly,
libc::SOL_SOCKET,
libc::SO_TYPE,
super::SockType,
GetStruct<i32>
);
sockopt_impl!(
AcceptConn,
GetOnly,
libc::SOL_SOCKET,
libc::SO_ACCEPTCONN,
bool
);
#[cfg(linux_android)]
sockopt_impl!(
BindToDevice,
Both,
libc::SOL_SOCKET,
libc::SO_BINDTODEVICE,
OsString<[u8; libc::IFNAMSIZ]>
);
#[cfg(linux_android)]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
#[allow(missing_docs)]
OriginalDst,
GetOnly,
libc::SOL_IP,
libc::SO_ORIGINAL_DST,
libc::sockaddr_in
);
#[cfg(linux_android)]
sockopt_impl!(
#[allow(missing_docs)]
Ip6tOriginalDst,
GetOnly,
libc::SOL_IPV6,
libc::IP6T_SO_ORIGINAL_DST,
libc::sockaddr_in6
);
#[cfg(linux_android)]
sockopt_impl!(
Timestamping,
Both,
libc::SOL_SOCKET,
libc::SO_TIMESTAMPING,
super::TimestampingFlag
);
#[cfg(not(any(
target_os = "aix",
target_os = "haiku",
target_os = "hurd",
target_os = "redox",
target_os = "cygwin"
)))]
sockopt_impl!(
ReceiveTimestamp,
Both,
libc::SOL_SOCKET,
libc::SO_TIMESTAMP,
bool
);
#[cfg(linux_android)]
sockopt_impl!(
ReceiveTimestampns,
Both,
libc::SOL_SOCKET,
libc::SO_TIMESTAMPNS,
bool
);
#[cfg(target_os = "freebsd")]
sockopt_impl!(
TsClock,
Both,
libc::SOL_SOCKET,
libc::SO_TS_CLOCK,
super::SocketTimestamp
);
#[cfg(linux_android)]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
IpTransparent,
Both,
libc::SOL_IP,
libc::IP_TRANSPARENT,
bool
);
#[cfg(target_os = "openbsd")]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
BindAny,
Both,
libc::SOL_SOCKET,
libc::SO_BINDANY,
bool
);
#[cfg(target_os = "freebsd")]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
BindAny,
Both,
libc::IPPROTO_IP,
libc::IP_BINDANY,
bool
);
#[cfg(target_os = "freebsd")]
sockopt_impl!(
Fib,
SetOnly,
libc::SOL_SOCKET,
libc::SO_SETFIB,
i32
);
#[cfg(target_os = "freebsd")]
sockopt_impl!(
UserCookie,
SetOnly,
libc::SOL_SOCKET,
libc::SO_USER_COOKIE,
u32
);
#[cfg(target_os = "openbsd")]
sockopt_impl!(
Rtable,
SetOnly,
libc::SOL_SOCKET,
libc::SO_RTABLE,
i32
);
#[cfg(any(target_os = "freebsd", target_os = "netbsd"))]
sockopt_impl!(
AcceptFilter,
Both,
libc::SOL_SOCKET,
libc::SO_ACCEPTFILTER,
libc::accept_filter_arg
);
#[cfg(target_os = "linux")]
sockopt_impl!(
Mark,
Both,
libc::SOL_SOCKET,
libc::SO_MARK,
u32
);
#[cfg(linux_android)]
sockopt_impl!(
PassCred,
Both,
libc::SOL_SOCKET,
libc::SO_PASSCRED,
bool
);
#[cfg(any(target_os = "freebsd", target_os = "linux"))]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
TcpCongestion,
Both,
libc::IPPROTO_TCP,
libc::TCP_CONGESTION,
OsString<[u8; TCP_CA_NAME_MAX]>
);
#[cfg(any(linux_android, apple_targets, target_os = "netbsd"))]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv4PacketInfo,
Both,
libc::IPPROTO_IP,
libc::IP_PKTINFO,
bool
);
#[cfg(any(linux_android, bsd))]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv6RecvPacketInfo,
Both,
libc::IPPROTO_IPV6,
libc::IPV6_RECVPKTINFO,
bool
);
#[cfg(any(linux_android, bsd))]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv6PacketInfo,
Both,
libc::IPPROTO_IPV6,
libc::IPV6_PKTINFO,
bool
);
#[cfg(bsd)]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv4RecvIf,
Both,
libc::IPPROTO_IP,
libc::IP_RECVIF,
bool
);
#[cfg(bsd)]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv4RecvDstAddr,
Both,
libc::IPPROTO_IP,
libc::IP_RECVDSTADDR,
bool
);
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv4OrigDstAddr,
Both,
libc::IPPROTO_IP,
libc::IP_ORIGDSTADDR,
bool
);
#[cfg(linux_android)]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
#[allow(missing_docs)]
UdpGsoSegment,
Both,
libc::SOL_UDP,
libc::UDP_SEGMENT,
libc::c_int
);
#[cfg(linux_android)]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
#[allow(missing_docs)]
UdpGroSegment,
Both,
libc::IPPROTO_UDP,
libc::UDP_GRO,
bool
);
#[cfg(target_os = "linux")]
sockopt_impl!(
TxTime,
Both,
libc::SOL_SOCKET,
libc::SO_TXTIME,
libc::sock_txtime
);
#[cfg(any(linux_android, target_os = "fuchsia"))]
sockopt_impl!(
RxqOvfl,
Both,
libc::SOL_SOCKET,
libc::SO_RXQ_OVFL,
libc::c_int
);
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv6V6Only,
Both,
libc::IPPROTO_IPV6,
libc::IPV6_V6ONLY,
bool
);
#[cfg(linux_android)]
sockopt_impl!(
Ipv4RecvErr,
Both,
libc::IPPROTO_IP,
libc::IP_RECVERR,
bool
);
#[cfg(linux_android)]
sockopt_impl!(
Ipv6RecvErr,
Both,
libc::IPPROTO_IPV6,
libc::IPV6_RECVERR,
bool
);
#[cfg(linux_android)]
sockopt_impl!(
IpMtu,
GetOnly,
libc::IPPROTO_IP,
libc::IP_MTU,
libc::c_int
);
#[cfg(any(linux_android, target_os = "freebsd"))]
sockopt_impl!(
Ipv4Ttl,
Both,
libc::IPPROTO_IP,
libc::IP_TTL,
libc::c_int
);
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
sockopt_impl!(
Ipv4RecvTtl,
Both,
libc::IPPROTO_IP,
libc::IP_RECVTTL,
bool
);
#[cfg(any(apple_targets, linux_android, target_os = "freebsd"))]
sockopt_impl!(
Ipv6Ttl,
Both,
libc::IPPROTO_IPV6,
libc::IPV6_UNICAST_HOPS,
libc::c_int
);
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
sockopt_impl!(
Ipv6RecvHopLimit,
Both,
libc::IPPROTO_IPV6,
libc::IPV6_RECVHOPLIMIT,
bool
);
#[cfg(any(
all(linux_android, not(target_env = "uclibc")),
target_os = "freebsd"
))]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv6OrigDstAddr,
Both,
libc::IPPROTO_IPV6,
libc::IPV6_ORIGDSTADDR,
bool
);
#[cfg(apple_targets)]
sockopt_impl!(
IpDontFrag,
Both,
libc::IPPROTO_IP,
libc::IP_DONTFRAG,
bool
);
#[cfg(any(
all(linux_android, not(target_env = "uclibc")),
apple_targets
))]
sockopt_impl!(
Ipv6DontFrag,
Both,
libc::IPPROTO_IPV6,
libc::IPV6_DONTFRAG,
bool
);
#[cfg(apple_targets)]
#[cfg(feature = "net")]
sockopt_impl!(
UtunIfname,
GetOnly,
libc::SYSPROTO_CONTROL,
libc::UTUN_OPT_IFNAME,
CString,
GetCString<[u8; libc::IFNAMSIZ]>
);
#[cfg(solarish)]
sockopt_impl!(
ExclBind,
Both,
libc::SOL_SOCKET,
libc::SO_EXCLBIND,
bool
);
#[cfg(target_os = "linux")]
sockopt_impl!(
AttachReusePortCbpf,
SetOnly,
libc::SOL_SOCKET,
libc::SO_ATTACH_REUSEPORT_CBPF,
libc::sock_fprog
);
#[allow(missing_docs)]
#[cfg(linux_android)]
#[derive(Copy, Clone, Debug)]
pub struct AlgSetAeadAuthSize;
#[cfg(linux_android)]
impl SetSockOpt for AlgSetAeadAuthSize {
type Val = usize;
fn set<F: AsFd>(&self, fd: &F, val: &usize) -> Result<()> {
unsafe {
let res = libc::setsockopt(
fd.as_fd().as_raw_fd(),
libc::SOL_ALG,
libc::ALG_SET_AEAD_AUTHSIZE,
::std::ptr::null(),
*val as libc::socklen_t,
);
Errno::result(res).map(drop)
}
}
}
#[allow(missing_docs)]
#[cfg(linux_android)]
#[derive(Clone, Debug)]
pub struct AlgSetKey<T>(::std::marker::PhantomData<T>);
#[cfg(linux_android)]
impl<T> Default for AlgSetKey<T> {
fn default() -> Self {
AlgSetKey(Default::default())
}
}
#[cfg(linux_android)]
impl<T> SetSockOpt for AlgSetKey<T>
where
T: AsRef<[u8]> + Clone,
{
type Val = T;
fn set<F: AsFd>(&self, fd: &F, val: &T) -> Result<()> {
unsafe {
let res = libc::setsockopt(
fd.as_fd().as_raw_fd(),
libc::SOL_ALG,
libc::ALG_SET_KEY,
val.as_ref().as_ptr().cast(),
val.as_ref().len() as libc::socklen_t,
);
Errno::result(res).map(drop)
}
}
}
#[cfg(linux_android)]
#[derive(Clone, Debug)]
pub struct TcpUlp<T>(::std::marker::PhantomData<T>);
#[cfg(linux_android)]
impl<T> Default for TcpUlp<T> {
fn default() -> Self {
TcpUlp(Default::default())
}
}
#[cfg(linux_android)]
impl<T> SetSockOpt for TcpUlp<T>
where
T: AsRef<[u8]> + Clone,
{
type Val = T;
fn set<F: AsFd>(&self, fd: &F, val: &Self::Val) -> Result<()> {
unsafe {
let res = libc::setsockopt(
fd.as_fd().as_raw_fd(),
libc::SOL_TCP,
libc::TCP_ULP,
val.as_ref().as_ptr().cast(),
val.as_ref().len() as libc::socklen_t,
);
Errno::result(res).map(drop)
}
}
}
#[cfg(target_os = "linux")]
#[derive(Copy, Clone, Debug)]
pub enum TlsCryptoInfo {
Aes128Gcm(libc::tls12_crypto_info_aes_gcm_128),
Aes256Gcm(libc::tls12_crypto_info_aes_gcm_256),
Chacha20Poly1305(libc::tls12_crypto_info_chacha20_poly1305),
}
#[cfg(target_os = "linux")]
#[derive(Copy, Clone, Debug)]
pub struct TcpTlsTx;
#[cfg(target_os = "linux")]
impl SetSockOpt for TcpTlsTx {
type Val = TlsCryptoInfo;
fn set<F: AsFd>(&self, fd: &F, val: &Self::Val) -> Result<()> {
let (ffi_ptr, ffi_len) = match val {
TlsCryptoInfo::Aes128Gcm(crypto_info) => {
(<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
}
TlsCryptoInfo::Aes256Gcm(crypto_info) => {
(<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
}
TlsCryptoInfo::Chacha20Poly1305(crypto_info) => {
(<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
}
};
unsafe {
let res = libc::setsockopt(
fd.as_fd().as_raw_fd(),
libc::SOL_TLS,
libc::TLS_TX,
ffi_ptr,
ffi_len as libc::socklen_t,
);
Errno::result(res).map(drop)
}
}
}
#[cfg(target_os = "linux")]
#[derive(Copy, Clone, Debug)]
pub struct TcpTlsRx;
#[cfg(target_os = "linux")]
impl SetSockOpt for TcpTlsRx {
type Val = TlsCryptoInfo;
fn set<F: AsFd>(&self, fd: &F, val: &Self::Val) -> Result<()> {
let (ffi_ptr, ffi_len) = match val {
TlsCryptoInfo::Aes128Gcm(crypto_info) => {
(<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
}
TlsCryptoInfo::Aes256Gcm(crypto_info) => {
(<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
}
TlsCryptoInfo::Chacha20Poly1305(crypto_info) => {
(<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
}
};
unsafe {
let res = libc::setsockopt(
fd.as_fd().as_raw_fd(),
libc::SOL_TLS,
libc::TLS_RX,
ffi_ptr,
ffi_len as libc::socklen_t,
);
Errno::result(res).map(drop)
}
}
}
#[cfg(target_os = "illumos")]
#[derive(Copy, Clone, Debug)]
pub struct FilterAttach;
#[cfg(target_os = "illumos")]
impl SetSockOpt for FilterAttach {
type Val = OsStr;
fn set<F: AsFd>(&self, fd: &F, val: &Self::Val) -> Result<()> {
if val.len() > libc::FILNAME_MAX as usize {
return Err(Errno::EINVAL);
}
unsafe {
let res = libc::setsockopt(
fd.as_fd().as_raw_fd(),
libc::SOL_FILTER,
libc::FIL_ATTACH,
val.as_bytes().as_ptr().cast(),
val.len() as libc::socklen_t,
);
Errno::result(res).map(drop)
}
}
}
#[cfg(target_os = "illumos")]
#[derive(Copy, Clone, Debug)]
pub struct FilterDetach;
#[cfg(target_os = "illumos")]
impl SetSockOpt for FilterDetach {
type Val = OsStr;
fn set<F: AsFd>(&self, fd: &F, val: &Self::Val) -> Result<()> {
if val.len() > libc::FILNAME_MAX as usize {
return Err(Errno::EINVAL);
}
unsafe {
let res = libc::setsockopt(
fd.as_fd().as_raw_fd(),
libc::SOL_FILTER,
libc::FIL_DETACH,
val.as_bytes().as_ptr().cast(),
val.len() as libc::socklen_t,
);
Errno::result(res).map(drop)
}
}
}
#[doc(hidden)]
pub trait Get<T> {
fn uninit() -> Self;
fn ffi_ptr(&mut self) -> *mut c_void;
fn ffi_len(&mut self) -> *mut socklen_t;
unsafe fn assume_init(self) -> T;
}
#[doc(hidden)]
pub trait Set<'a, T> {
fn new(val: &'a T) -> Self;
fn ffi_ptr(&self) -> *const c_void;
fn ffi_len(&self) -> socklen_t;
}
#[doc(hidden)]
#[derive(Debug)]
pub struct GetStruct<T> {
len: socklen_t,
val: MaybeUninit<T>,
}
impl<T> Get<T> for GetStruct<T> {
fn uninit() -> Self {
GetStruct {
len: mem::size_of::<T>() as socklen_t,
val: MaybeUninit::uninit(),
}
}
fn ffi_ptr(&mut self) -> *mut c_void {
self.val.as_mut_ptr().cast()
}
fn ffi_len(&mut self) -> *mut socklen_t {
&mut self.len
}
unsafe fn assume_init(self) -> T {
assert_eq!(
self.len as usize,
mem::size_of::<T>(),
"invalid getsockopt implementation"
);
unsafe { self.val.assume_init() }
}
}
#[doc(hidden)]
#[derive(Debug)]
pub struct SetStruct<'a, T: 'static> {
ptr: &'a T,
}
impl<'a, T> Set<'a, T> for SetStruct<'a, T> {
fn new(ptr: &'a T) -> SetStruct<'a, T> {
SetStruct { 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
}
}
#[doc(hidden)]
#[derive(Clone, Copy, Debug)]
pub struct GetBool {
len: socklen_t,
val: MaybeUninit<c_int>,
}
impl Get<bool> for GetBool {
fn uninit() -> Self {
GetBool {
len: mem::size_of::<c_int>() as socklen_t,
val: MaybeUninit::uninit(),
}
}
fn ffi_ptr(&mut self) -> *mut c_void {
self.val.as_mut_ptr().cast()
}
fn ffi_len(&mut self) -> *mut socklen_t {
&mut self.len
}
unsafe fn assume_init(self) -> bool {
assert_eq!(
self.len as usize,
mem::size_of::<c_int>(),
"invalid getsockopt implementation"
);
unsafe { self.val.assume_init() != 0 }
}
}
#[doc(hidden)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct SetBool {
val: c_int,
}
impl<'a> Set<'a, bool> for SetBool {
fn new(val: &'a bool) -> SetBool {
SetBool {
val: i32::from(*val),
}
}
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_val(&self.val) as socklen_t
}
}
#[cfg(feature = "net")]
#[doc(hidden)]
#[derive(Clone, Copy, Debug)]
pub struct GetU8 {
len: socklen_t,
val: MaybeUninit<u8>,
}
#[cfg(feature = "net")]
impl Get<u8> for GetU8 {
fn uninit() -> Self {
GetU8 {
len: mem::size_of::<u8>() as socklen_t,
val: MaybeUninit::uninit(),
}
}
fn ffi_ptr(&mut self) -> *mut c_void {
self.val.as_mut_ptr().cast()
}
fn ffi_len(&mut self) -> *mut socklen_t {
&mut self.len
}
unsafe fn assume_init(self) -> u8 {
assert_eq!(
self.len as usize,
mem::size_of::<u8>(),
"invalid getsockopt implementation"
);
unsafe { self.val.assume_init() }
}
}
#[doc(hidden)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct SetU8 {
val: u8,
}
#[cfg(feature = "net")]
impl<'a> Set<'a, u8> for SetU8 {
fn new(val: &'a u8) -> SetU8 {
SetU8 { val: *val }
}
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_val(&self.val) as socklen_t
}
}
#[doc(hidden)]
#[derive(Clone, Copy, Debug)]
pub struct GetUsize {
len: socklen_t,
val: MaybeUninit<c_int>,
}
impl Get<usize> for GetUsize {
fn uninit() -> Self {
GetUsize {
len: mem::size_of::<c_int>() as socklen_t,
val: MaybeUninit::uninit(),
}
}
fn ffi_ptr(&mut self) -> *mut c_void {
self.val.as_mut_ptr().cast()
}
fn ffi_len(&mut self) -> *mut socklen_t {
&mut self.len
}
unsafe fn assume_init(self) -> usize {
assert_eq!(
self.len as usize,
mem::size_of::<c_int>(),
"invalid getsockopt implementation"
);
unsafe { self.val.assume_init() as usize }
}
}
#[doc(hidden)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct SetUsize {
val: c_int,
}
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_val(&self.val) as socklen_t
}
}
#[doc(hidden)]
#[derive(Clone, Copy, Debug)]
pub struct GetOwnedFd {
len: socklen_t,
val: MaybeUninit<c_int>,
}
impl Get<OwnedFd> for GetOwnedFd {
fn uninit() -> Self {
GetOwnedFd {
len: mem::size_of::<c_int>() as socklen_t,
val: MaybeUninit::uninit(),
}
}
fn ffi_ptr(&mut self) -> *mut c_void {
self.val.as_mut_ptr().cast()
}
fn ffi_len(&mut self) -> *mut socklen_t {
&mut self.len
}
unsafe fn assume_init(self) -> OwnedFd {
use std::os::fd::{FromRawFd, RawFd};
assert_eq!(
self.len as usize,
mem::size_of::<c_int>(),
"invalid getsockopt implementation"
);
unsafe { OwnedFd::from_raw_fd(self.val.assume_init() as RawFd) }
}
}
#[doc(hidden)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct SetOwnedFd {
val: c_int,
}
impl<'a> Set<'a, OwnedFd> for SetOwnedFd {
fn new(val: &'a OwnedFd) -> SetOwnedFd {
use std::os::fd::AsRawFd;
SetOwnedFd { val: val.as_raw_fd() 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_val(&self.val) as socklen_t
}
}
#[doc(hidden)]
#[derive(Debug)]
pub struct GetOsString<T: AsMut<[u8]>> {
len: socklen_t,
val: MaybeUninit<T>,
}
impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> {
fn uninit() -> Self {
GetOsString {
len: mem::size_of::<T>() as socklen_t,
val: MaybeUninit::uninit(),
}
}
fn ffi_ptr(&mut self) -> *mut c_void {
self.val.as_mut_ptr().cast()
}
fn ffi_len(&mut self) -> *mut socklen_t {
&mut self.len
}
unsafe fn assume_init(self) -> OsString {
let len = self.len as usize;
let mut v = unsafe { self.val.assume_init() };
if let Ok(cs) = CStr::from_bytes_until_nul(&v.as_mut()[0..len]) {
OsStr::from_bytes(cs.to_bytes())
} else {
OsStr::from_bytes(&v.as_mut()[0..len])
}
.to_owned()
}
}
#[doc(hidden)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct SetOsString<'a> {
val: &'a OsStr,
}
#[cfg(any(target_os = "freebsd", linux_android, target_os = "illumos"))]
impl<'a> Set<'a, OsString> for SetOsString<'a> {
fn new(val: &OsString) -> SetOsString<'_> {
SetOsString {
val: val.as_os_str(),
}
}
fn ffi_ptr(&self) -> *const c_void {
self.val.as_bytes().as_ptr().cast()
}
fn ffi_len(&self) -> socklen_t {
self.val.len() as socklen_t
}
}
#[cfg(apple_targets)]
#[cfg(feature = "net")]
struct GetCString<T: AsMut<[u8]>> {
len: socklen_t,
val: MaybeUninit<T>,
}
#[cfg(apple_targets)]
#[cfg(feature = "net")]
impl<T: AsMut<[u8]>> Get<CString> for GetCString<T> {
fn uninit() -> Self {
GetCString {
len: mem::size_of::<T>() as socklen_t,
val: MaybeUninit::uninit(),
}
}
fn ffi_ptr(&mut self) -> *mut c_void {
self.val.as_mut_ptr().cast()
}
fn ffi_len(&mut self) -> *mut socklen_t {
&mut self.len
}
unsafe fn assume_init(self) -> CString {
let mut v = unsafe { self.val.assume_init() };
CStr::from_bytes_until_nul(v.as_mut())
.expect("string should be null-terminated")
.to_owned()
}
}