nix/sys/socket/
sockopt.rs

1//! Socket options as used by `setsockopt` and `getsockopt`.
2use cfg_if::cfg_if;
3use super::{GetSockOpt, SetSockOpt};
4use crate::Result;
5use crate::errno::Errno;
6use crate::sys::time::TimeVal;
7use libc::{self, c_int, c_void, socklen_t};
8use std::convert::TryFrom;
9use std::mem::{
10    self,
11    MaybeUninit
12};
13use std::os::unix::io::RawFd;
14use std::ffi::{OsStr, OsString};
15#[cfg(target_family = "unix")]
16use std::os::unix::ffi::OsStrExt;
17
18// Constants
19// TCP_CA_NAME_MAX isn't defined in user space include files
20#[cfg(any(target_os = "freebsd", target_os = "linux"))]
21#[cfg(feature = "net")]
22const TCP_CA_NAME_MAX: usize = 16;
23
24/// Helper for implementing `SetSockOpt` for a given socket option. See
25/// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html).
26///
27/// This macro aims to help implementing `SetSockOpt` for different socket options that accept
28/// different kinds of data to be used with `setsockopt`.
29///
30/// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option
31/// you are implementing represents a simple type.
32///
33/// # Arguments
34///
35/// * `$name:ident`: name of the type you want to implement `SetSockOpt` for.
36/// * `$level:expr` : socket layer, or a `protocol level`: could be *raw sockets*
37///    (`libc::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`),
38///    and more. Please refer to your system manual for more options. Will be passed as the second
39///    argument (`level`) to the `setsockopt` call.
40/// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`,
41///    `libc::IP_ADD_MEMBERSHIP` and others. Will be passed as the third argument (`option_name`)
42///    to the `setsockopt` call.
43/// * Type of the value that you are going to set.
44/// * Type that implements the `Set` trait for the type from the previous item (like `SetBool` for
45///    `bool`, `SetUsize` for `usize`, etc.).
46macro_rules! setsockopt_impl {
47    ($name:ident, $level:expr, $flag:path, $ty:ty, $setter:ty) => {
48        impl SetSockOpt for $name {
49            type Val = $ty;
50
51            fn set(&self, fd: RawFd, val: &$ty) -> Result<()> {
52                unsafe {
53                    let setter: $setter = Set::new(val);
54
55                    let res = libc::setsockopt(fd, $level, $flag,
56                                               setter.ffi_ptr(),
57                                               setter.ffi_len());
58                    Errno::result(res).map(drop)
59                }
60            }
61        }
62    }
63}
64
65/// Helper for implementing `GetSockOpt` for a given socket option. See
66/// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html).
67///
68/// This macro aims to help implementing `GetSockOpt` for different socket options that accept
69/// different kinds of data to be use with `getsockopt`.
70///
71/// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option
72/// you are implementing represents a simple type.
73///
74/// # Arguments
75///
76/// * Name of the type you want to implement `GetSockOpt` for.
77/// * Socket layer, or a `protocol level`: could be *raw sockets* (`lic::SOL_SOCKET`),  *ip
78///    protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`),  and more. Please refer
79///    to your system manual for more options. Will be passed as the second argument (`level`) to
80///    the `getsockopt` call.
81/// * A flag to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`,
82///    `libc::SO_ORIGINAL_DST` and others. Will be passed as the third argument (`option_name`) to
83///    the `getsockopt` call.
84/// * Type of the value that you are going to get.
85/// * Type that implements the `Get` trait for the type from the previous item (`GetBool` for
86///    `bool`, `GetUsize` for `usize`, etc.).
87macro_rules! getsockopt_impl {
88    ($name:ident, $level:expr, $flag:path, $ty:ty, $getter:ty) => {
89        impl GetSockOpt for $name {
90            type Val = $ty;
91
92            fn get(&self, fd: RawFd) -> Result<$ty> {
93                unsafe {
94                    let mut getter: $getter = Get::uninit();
95
96                    let res = libc::getsockopt(fd, $level, $flag,
97                                               getter.ffi_ptr(),
98                                               getter.ffi_len());
99                    Errno::result(res)?;
100
101                    match <$ty>::try_from(getter.assume_init()) {
102                        Err(_) => Err(Errno::EINVAL),
103                        Ok(r) => Ok(r)
104                    }
105                }
106            }
107        }
108    }
109}
110
111/// Helper to generate the sockopt accessors. See
112/// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html) and
113/// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html).
114///
115/// This macro aims to help implementing `GetSockOpt` and `SetSockOpt` for different socket options
116/// that accept different kinds of data to be use with `getsockopt` and `setsockopt` respectively.
117///
118/// Basically this macro wraps up the [`getsockopt_impl!`](macro.getsockopt_impl.html) and
119/// [`setsockopt_impl!`](macro.setsockopt_impl.html) macros.
120///
121/// # Arguments
122///
123/// * `GetOnly`, `SetOnly` or `Both`: whether you want to implement only getter, only setter or
124///    both of them.
125/// * `$name:ident`: name of type `GetSockOpt`/`SetSockOpt` will be implemented for.
126/// * `$level:expr` : socket layer, or a `protocol level`: could be *raw sockets*
127///    (`lic::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`),
128///    and more. Please refer to your system manual for more options. Will be passed as the second
129///    argument (`level`) to the `getsockopt`/`setsockopt` call.
130/// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`,
131///    `libc::IP_ADD_MEMBERSHIP` and others. Will be passed as the third argument (`option_name`)
132///    to the `setsockopt`/`getsockopt` call.
133/// * `$ty:ty`: type of the value that will be get/set.
134/// * `$getter:ty`: `Get` implementation; optional; only for `GetOnly` and `Both`.
135/// * `$setter:ty`: `Set` implementation; optional; only for `SetOnly` and `Both`.
136// Some targets don't use all rules.
137#[allow(unknown_lints)]
138#[allow(unused_macro_rules)]
139macro_rules! sockopt_impl {
140    ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, bool) => {
141        sockopt_impl!($(#[$attr])*
142                      $name, GetOnly, $level, $flag, bool, GetBool);
143    };
144
145    ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, u8) => {
146        sockopt_impl!($(#[$attr])* $name, GetOnly, $level, $flag, u8, GetU8);
147    };
148
149    ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, usize) =>
150    {
151        sockopt_impl!($(#[$attr])*
152                      $name, GetOnly, $level, $flag, usize, GetUsize);
153    };
154
155    ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, bool) => {
156        sockopt_impl!($(#[$attr])*
157                      $name, SetOnly, $level, $flag, bool, SetBool);
158    };
159
160    ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, u8) => {
161        sockopt_impl!($(#[$attr])* $name, SetOnly, $level, $flag, u8, SetU8);
162    };
163
164    ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, usize) =>
165    {
166        sockopt_impl!($(#[$attr])*
167                      $name, SetOnly, $level, $flag, usize, SetUsize);
168    };
169
170    ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, bool) => {
171        sockopt_impl!($(#[$attr])*
172                      $name, Both, $level, $flag, bool, GetBool, SetBool);
173    };
174
175    ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, u8) => {
176        sockopt_impl!($(#[$attr])*
177                      $name, Both, $level, $flag, u8, GetU8, SetU8);
178    };
179
180    ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, usize) => {
181        sockopt_impl!($(#[$attr])*
182                      $name, Both, $level, $flag, usize, GetUsize, SetUsize);
183    };
184
185    ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path,
186     OsString<$array:ty>) =>
187    {
188        sockopt_impl!($(#[$attr])*
189                      $name, Both, $level, $flag, OsString, GetOsString<$array>,
190                      SetOsString);
191    };
192
193    /*
194     * Matchers with generic getter types must be placed at the end, so
195     * they'll only match _after_ specialized matchers fail
196     */
197    ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty) =>
198    {
199        sockopt_impl!($(#[$attr])*
200                      $name, GetOnly, $level, $flag, $ty, GetStruct<$ty>);
201    };
202
203    ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty,
204     $getter:ty) =>
205    {
206        $(#[$attr])*
207        #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
208        pub struct $name;
209
210        getsockopt_impl!($name, $level, $flag, $ty, $getter);
211    };
212
213    ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty) =>
214    {
215        sockopt_impl!($(#[$attr])*
216                      $name, SetOnly, $level, $flag, $ty, SetStruct<$ty>);
217    };
218
219    ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty,
220     $setter:ty) =>
221    {
222        $(#[$attr])*
223        #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
224        pub struct $name;
225
226        setsockopt_impl!($name, $level, $flag, $ty, $setter);
227    };
228
229    ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, $ty:ty,
230     $getter:ty, $setter:ty) =>
231    {
232        $(#[$attr])*
233        #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
234        pub struct $name;
235
236        setsockopt_impl!($name, $level, $flag, $ty, $setter);
237        getsockopt_impl!($name, $level, $flag, $ty, $getter);
238    };
239
240    ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, $ty:ty) => {
241        sockopt_impl!($(#[$attr])*
242                      $name, Both, $level, $flag, $ty, GetStruct<$ty>,
243                      SetStruct<$ty>);
244    };
245}
246
247/*
248 *
249 * ===== Define sockopts =====
250 *
251 */
252
253sockopt_impl!(
254    /// Enables local address reuse
255    ReuseAddr, Both, libc::SOL_SOCKET, libc::SO_REUSEADDR, bool
256);
257#[cfg(not(any(target_os = "illumos", target_os = "solaris")))]
258sockopt_impl!(
259    /// Permits multiple AF_INET or AF_INET6 sockets to be bound to an
260    /// identical socket address.
261    ReusePort, Both, libc::SOL_SOCKET, libc::SO_REUSEPORT, bool);
262#[cfg(feature = "net")]
263sockopt_impl!(
264    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
265    /// Under most circumstances, TCP sends data when it is presented; when
266    /// outstanding data has not yet been acknowledged, it gathers small amounts
267    /// of output to be sent in a single packet once an acknowledgement is
268    /// received.  For a small number of clients, such as window systems that
269    /// send a stream of mouse events which receive no replies, this
270    /// packetization may cause significant delays.  The boolean option
271    /// TCP_NODELAY defeats this algorithm.
272    TcpNoDelay, Both, libc::IPPROTO_TCP, libc::TCP_NODELAY, bool);
273sockopt_impl!(
274    /// When enabled,  a close(2) or shutdown(2) will not return until all
275    /// queued messages for the socket have been successfully sent or the
276    /// linger timeout has been reached.
277    Linger, Both, libc::SOL_SOCKET, libc::SO_LINGER, libc::linger);
278#[cfg(feature = "net")]
279sockopt_impl!(
280    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
281    /// Join a multicast group
282    IpAddMembership, SetOnly, libc::IPPROTO_IP, libc::IP_ADD_MEMBERSHIP,
283    super::IpMembershipRequest);
284#[cfg(feature = "net")]
285sockopt_impl!(
286    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
287    /// Leave a multicast group.
288    IpDropMembership, SetOnly, libc::IPPROTO_IP, libc::IP_DROP_MEMBERSHIP,
289    super::IpMembershipRequest);
290cfg_if! {
291    if #[cfg(any(target_os = "android", target_os = "linux"))] {
292        #[cfg(feature = "net")]
293        sockopt_impl!(
294            #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
295            /// Join an IPv6 multicast group.
296            Ipv6AddMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_ADD_MEMBERSHIP, super::Ipv6MembershipRequest);
297        #[cfg(feature = "net")]
298        sockopt_impl!(
299            #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
300            /// Leave an IPv6 multicast group.
301            Ipv6DropMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_DROP_MEMBERSHIP, super::Ipv6MembershipRequest);
302    } else if #[cfg(any(target_os = "dragonfly",
303                        target_os = "freebsd",
304                        target_os = "illumos",
305                        target_os = "ios",
306                        target_os = "macos",
307                        target_os = "netbsd",
308                        target_os = "openbsd",
309                        target_os = "solaris"))] {
310        #[cfg(feature = "net")]
311        sockopt_impl!(
312            #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
313            /// Join an IPv6 multicast group.
314            Ipv6AddMembership, SetOnly, libc::IPPROTO_IPV6,
315            libc::IPV6_JOIN_GROUP, super::Ipv6MembershipRequest);
316        #[cfg(feature = "net")]
317        sockopt_impl!(
318            #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
319            /// Leave an IPv6 multicast group.
320            Ipv6DropMembership, SetOnly, libc::IPPROTO_IPV6,
321            libc::IPV6_LEAVE_GROUP, super::Ipv6MembershipRequest);
322    }
323}
324#[cfg(feature = "net")]
325sockopt_impl!(
326    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
327    /// Set or read the time-to-live value of outgoing multicast packets for
328    /// this socket.
329    IpMulticastTtl, Both, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL, u8);
330#[cfg(feature = "net")]
331sockopt_impl!(
332    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
333    /// Set or read a boolean integer argument that determines whether sent
334    /// multicast packets should be looped back to the local sockets.
335    IpMulticastLoop, Both, libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP, bool);
336#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
337#[cfg(feature = "net")]
338sockopt_impl!(
339    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
340    /// If enabled, this boolean option allows binding to an IP address that
341    /// is nonlocal or does not (yet) exist.
342    IpFreebind, Both, libc::IPPROTO_IP, libc::IP_FREEBIND, bool);
343sockopt_impl!(
344    /// Specify the receiving timeout until reporting an error.
345    ReceiveTimeout, Both, libc::SOL_SOCKET, libc::SO_RCVTIMEO, TimeVal);
346sockopt_impl!(
347    /// Specify the sending timeout until reporting an error.
348    SendTimeout, Both, libc::SOL_SOCKET, libc::SO_SNDTIMEO, TimeVal);
349sockopt_impl!(
350    /// Set or get the broadcast flag.
351    Broadcast, Both, libc::SOL_SOCKET, libc::SO_BROADCAST, bool);
352sockopt_impl!(
353    /// If this option is enabled, out-of-band data is directly placed into
354    /// the receive data stream.
355    OobInline, Both, libc::SOL_SOCKET, libc::SO_OOBINLINE, bool);
356sockopt_impl!(
357    /// Get and clear the pending socket error.
358    SocketError, GetOnly, libc::SOL_SOCKET, libc::SO_ERROR, i32);
359sockopt_impl!(
360    /// Enable sending of keep-alive messages on connection-oriented sockets.
361    KeepAlive, Both, libc::SOL_SOCKET, libc::SO_KEEPALIVE, bool);
362#[cfg(any(
363        target_os = "dragonfly",
364        target_os = "freebsd",
365        target_os = "macos",
366        target_os = "ios"
367))]
368sockopt_impl!(
369    /// Get the credentials of the peer process of a connected unix domain
370    /// socket.
371    LocalPeerCred, GetOnly, 0, libc::LOCAL_PEERCRED, super::XuCred);
372#[cfg(any(target_os = "android", target_os = "linux"))]
373sockopt_impl!(
374    /// Return the credentials of the foreign process connected to this socket.
375    PeerCredentials, GetOnly, libc::SOL_SOCKET, libc::SO_PEERCRED, super::UnixCredentials);
376#[cfg(any(target_os = "ios",
377          target_os = "macos"))]
378#[cfg(feature = "net")]
379sockopt_impl!(
380    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
381    /// Specify the amount of time, in seconds, that the connection must be idle
382    /// before keepalive probes (if enabled) are sent.
383    TcpKeepAlive, Both, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE, u32);
384#[cfg(any(target_os = "android",
385          target_os = "dragonfly",
386          target_os = "freebsd",
387          target_os = "linux",
388          target_os = "nacl"))]
389#[cfg(feature = "net")]
390sockopt_impl!(
391    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
392    /// The time (in seconds) the connection needs to remain idle before TCP
393    /// starts sending keepalive probes
394    TcpKeepIdle, Both, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, u32);
395cfg_if! {
396    if #[cfg(any(target_os = "android", target_os = "linux"))] {
397        sockopt_impl!(
398            /// The maximum segment size for outgoing TCP packets.
399            TcpMaxSeg, Both, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32);
400    } else {
401        sockopt_impl!(
402            /// The maximum segment size for outgoing TCP packets.
403            TcpMaxSeg, GetOnly, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32);
404    }
405}
406#[cfg(not(target_os = "openbsd"))]
407#[cfg(feature = "net")]
408sockopt_impl!(
409    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
410    /// The maximum number of keepalive probes TCP should send before
411    /// dropping the connection.
412    TcpKeepCount, Both, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, u32);
413#[cfg(any(target_os = "android",
414          target_os = "fuchsia",
415          target_os = "linux"))]
416sockopt_impl!(
417    #[allow(missing_docs)]
418    // Not documented by Linux!
419    TcpRepair, Both, libc::IPPROTO_TCP, libc::TCP_REPAIR, u32);
420#[cfg(not(target_os = "openbsd"))]
421#[cfg(feature = "net")]
422sockopt_impl!(
423    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
424    /// The time (in seconds) between individual keepalive probes.
425    TcpKeepInterval, Both, libc::IPPROTO_TCP, libc::TCP_KEEPINTVL, u32);
426#[cfg(any(target_os = "fuchsia", target_os = "linux"))]
427#[cfg(feature = "net")]
428sockopt_impl!(
429    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
430    /// Specifies the maximum amount of time in milliseconds that transmitted
431    /// data may remain unacknowledged before TCP will forcibly close the
432    /// corresponding connection
433    TcpUserTimeout, Both, libc::IPPROTO_TCP, libc::TCP_USER_TIMEOUT, u32);
434sockopt_impl!(
435    /// Sets or gets the maximum socket receive buffer in bytes.
436    RcvBuf, Both, libc::SOL_SOCKET, libc::SO_RCVBUF, usize);
437sockopt_impl!(
438    /// Sets or gets the maximum socket send buffer in bytes.
439    SndBuf, Both, libc::SOL_SOCKET, libc::SO_SNDBUF, usize);
440#[cfg(any(target_os = "android", target_os = "linux"))]
441sockopt_impl!(
442    /// Using this socket option, a privileged (`CAP_NET_ADMIN`) process can
443    /// perform the same task as `SO_RCVBUF`, but the `rmem_max limit` can be
444    /// overridden.
445    RcvBufForce, SetOnly, libc::SOL_SOCKET, libc::SO_RCVBUFFORCE, usize);
446#[cfg(any(target_os = "android", target_os = "linux"))]
447sockopt_impl!(
448    /// Using this socket option, a privileged (`CAP_NET_ADMIN`)  process can
449    /// perform the same task as `SO_SNDBUF`, but the `wmem_max` limit can be
450    /// overridden.
451    SndBufForce, SetOnly, libc::SOL_SOCKET, libc::SO_SNDBUFFORCE, usize);
452sockopt_impl!(
453    /// Gets the socket type as an integer.
454    SockType, GetOnly, libc::SOL_SOCKET, libc::SO_TYPE, super::SockType, GetStruct<i32>);
455sockopt_impl!(
456    /// Returns a value indicating whether or not this socket has been marked to
457    /// accept connections with `listen(2)`.
458    AcceptConn, GetOnly, libc::SOL_SOCKET, libc::SO_ACCEPTCONN, bool);
459#[cfg(any(target_os = "android", target_os = "linux"))]
460sockopt_impl!(
461    /// Bind this socket to a particular device like “eth0”.
462    BindToDevice, Both, libc::SOL_SOCKET, libc::SO_BINDTODEVICE, OsString<[u8; libc::IFNAMSIZ]>);
463#[cfg(any(target_os = "android", target_os = "linux"))]
464#[cfg(feature = "net")]
465sockopt_impl!(
466    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
467    #[allow(missing_docs)]
468    // Not documented by Linux!
469    OriginalDst, GetOnly, libc::SOL_IP, libc::SO_ORIGINAL_DST, libc::sockaddr_in);
470#[cfg(any(target_os = "android", target_os = "linux"))]
471sockopt_impl!(
472    #[allow(missing_docs)]
473    // Not documented by Linux!
474    Ip6tOriginalDst, GetOnly, libc::SOL_IPV6, libc::IP6T_SO_ORIGINAL_DST, libc::sockaddr_in6);
475#[cfg(any(target_os = "linux"))]
476sockopt_impl!(
477    /// Specifies exact type of timestamping information collected by the kernel
478    /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html)
479    Timestamping, Both, libc::SOL_SOCKET, libc::SO_TIMESTAMPING, super::TimestampingFlag);
480sockopt_impl!(
481    /// Enable or disable the receiving of the `SO_TIMESTAMP` control message.
482    ReceiveTimestamp, Both, libc::SOL_SOCKET, libc::SO_TIMESTAMP, bool);
483#[cfg(all(target_os = "linux"))]
484sockopt_impl!(
485    /// Enable or disable the receiving of the `SO_TIMESTAMPNS` control message.
486    ReceiveTimestampns, Both, libc::SOL_SOCKET, libc::SO_TIMESTAMPNS, bool);
487#[cfg(any(target_os = "android", target_os = "linux"))]
488#[cfg(feature = "net")]
489sockopt_impl!(
490    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
491    /// Setting this boolean option enables transparent proxying on this socket.
492    IpTransparent, Both, libc::SOL_IP, libc::IP_TRANSPARENT, bool);
493#[cfg(target_os = "openbsd")]
494#[cfg(feature = "net")]
495sockopt_impl!(
496    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
497    /// Allows the socket to be bound to addresses which are not local to the
498    /// machine, so it can be used to make a transparent proxy.
499    BindAny, Both, libc::SOL_SOCKET, libc::SO_BINDANY, bool);
500#[cfg(target_os = "freebsd")]
501#[cfg(feature = "net")]
502sockopt_impl!(
503    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
504    /// Can `bind(2)` to any address, even one not bound to any available
505    /// network interface in the system.
506    BindAny, Both, libc::IPPROTO_IP, libc::IP_BINDANY, bool);
507#[cfg(target_os = "linux")]
508sockopt_impl!(
509    /// Set the mark for each packet sent through this socket (similar to the
510    /// netfilter MARK target but socket-based).
511    Mark, Both, libc::SOL_SOCKET, libc::SO_MARK, u32);
512#[cfg(any(target_os = "android", target_os = "linux"))]
513sockopt_impl!(
514    /// Enable or disable the receiving of the `SCM_CREDENTIALS` control
515    /// message.
516    PassCred, Both, libc::SOL_SOCKET, libc::SO_PASSCRED, bool);
517#[cfg(any(target_os = "freebsd", target_os = "linux"))]
518#[cfg(feature = "net")]
519sockopt_impl!(
520    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
521    /// This option allows the caller to set the TCP congestion control
522    /// algorithm to be used,  on a per-socket basis.
523    TcpCongestion, Both, libc::IPPROTO_TCP, libc::TCP_CONGESTION, OsString<[u8; TCP_CA_NAME_MAX]>);
524#[cfg(any(
525    target_os = "android",
526    target_os = "ios",
527    target_os = "linux",
528    target_os = "macos",
529    target_os = "netbsd",
530))]
531#[cfg(feature = "net")]
532sockopt_impl!(
533    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
534    /// Pass an `IP_PKTINFO` ancillary message that contains a pktinfo
535    /// structure that supplies some information about the incoming packet.
536    Ipv4PacketInfo, Both, libc::IPPROTO_IP, libc::IP_PKTINFO, bool);
537#[cfg(any(
538    target_os = "android",
539    target_os = "freebsd",
540    target_os = "ios",
541    target_os = "linux",
542    target_os = "macos",
543    target_os = "netbsd",
544    target_os = "openbsd",
545))]
546#[cfg(feature = "net")]
547sockopt_impl!(
548    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
549    /// Set delivery of the `IPV6_PKTINFO` control message on incoming
550    /// datagrams.
551    Ipv6RecvPacketInfo, Both, libc::IPPROTO_IPV6, libc::IPV6_RECVPKTINFO, bool);
552#[cfg(any(
553    target_os = "freebsd",
554    target_os = "ios",
555    target_os = "macos",
556    target_os = "netbsd",
557    target_os = "openbsd",
558))]
559#[cfg(feature = "net")]
560sockopt_impl!(
561    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
562    /// The `recvmsg(2)` call returns a `struct sockaddr_dl` corresponding to
563    /// the interface on which the packet was received.
564    Ipv4RecvIf, Both, libc::IPPROTO_IP, libc::IP_RECVIF, bool);
565#[cfg(any(
566    target_os = "freebsd",
567    target_os = "ios",
568    target_os = "macos",
569    target_os = "netbsd",
570    target_os = "openbsd",
571))]
572#[cfg(feature = "net")]
573sockopt_impl!(
574    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
575    /// The `recvmsg(2)` call will return the destination IP address for a UDP
576    /// datagram.
577    Ipv4RecvDstAddr, Both, libc::IPPROTO_IP, libc::IP_RECVDSTADDR, bool);
578#[cfg(target_os = "linux")]
579#[cfg(feature = "net")]
580sockopt_impl!(
581    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
582    #[allow(missing_docs)]
583    // Not documented by Linux!
584    UdpGsoSegment, Both, libc::SOL_UDP, libc::UDP_SEGMENT, libc::c_int);
585#[cfg(target_os = "linux")]
586#[cfg(feature = "net")]
587sockopt_impl!(
588    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
589    #[allow(missing_docs)]
590    // Not documented by Linux!
591    UdpGroSegment, Both, libc::IPPROTO_UDP, libc::UDP_GRO, bool);
592#[cfg(target_os = "linux")]
593sockopt_impl!(
594    /// Configures the behavior of time-based transmission of packets, for use
595    /// with the `TxTime` control message.
596    TxTime, Both, libc::SOL_SOCKET, libc::SO_TXTIME, libc::sock_txtime);
597#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
598sockopt_impl!(
599    /// Indicates that an unsigned 32-bit value ancillary message (cmsg) should
600    /// be attached to received skbs indicating the number of packets dropped by
601    /// the socket since its creation.
602    RxqOvfl, Both, libc::SOL_SOCKET, libc::SO_RXQ_OVFL, libc::c_int);
603#[cfg(feature = "net")]
604sockopt_impl!(
605    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
606    /// The socket is restricted to sending and receiving IPv6 packets only.
607    Ipv6V6Only, Both, libc::IPPROTO_IPV6, libc::IPV6_V6ONLY, bool);
608#[cfg(any(target_os = "android", target_os = "linux"))]
609sockopt_impl!(
610    /// Enable extended reliable error message passing.
611    Ipv4RecvErr, Both, libc::IPPROTO_IP, libc::IP_RECVERR, bool);
612#[cfg(any(target_os = "android", target_os = "linux"))]
613sockopt_impl!(
614    /// Control receiving of asynchronous error options.
615    Ipv6RecvErr, Both, libc::IPPROTO_IPV6, libc::IPV6_RECVERR, bool);
616#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
617sockopt_impl!(
618    /// Set or retrieve the current time-to-live field that is used in every
619    /// packet sent from this socket.
620    Ipv4Ttl, Both, libc::IPPROTO_IP, libc::IP_TTL, libc::c_int);
621#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
622sockopt_impl!(
623    /// Set the unicast hop limit for the socket.
624    Ipv6Ttl, Both, libc::IPPROTO_IPV6, libc::IPV6_UNICAST_HOPS, libc::c_int);
625#[cfg(any(target_os = "ios", target_os = "macos"))]
626sockopt_impl!(
627    /// Set "don't fragment packet" flag on the IP packet.
628    IpDontFrag, Both, libc::IPPROTO_IP, libc::IP_DONTFRAG, bool);
629#[cfg(any(
630    target_os = "android",
631    target_os = "ios",
632    target_os = "linux",
633    target_os = "macos",
634))]
635sockopt_impl!(
636    /// Set "don't fragment packet" flag on the IPv6 packet.
637    Ipv6DontFrag, Both, libc::IPPROTO_IPV6, libc::IPV6_DONTFRAG, bool);
638
639#[allow(missing_docs)]
640// Not documented by Linux!
641#[cfg(any(target_os = "android", target_os = "linux"))]
642#[derive(Copy, Clone, Debug)]
643pub struct AlgSetAeadAuthSize;
644
645// ALG_SET_AEAD_AUTH_SIZE read the length from passed `option_len`
646// See https://elixir.bootlin.com/linux/v4.4/source/crypto/af_alg.c#L222
647#[cfg(any(target_os = "android", target_os = "linux"))]
648impl SetSockOpt for AlgSetAeadAuthSize {
649    type Val = usize;
650
651    fn set(&self, fd: RawFd, val: &usize) -> Result<()> {
652        unsafe {
653            let res = libc::setsockopt(fd,
654                                       libc::SOL_ALG,
655                                       libc::ALG_SET_AEAD_AUTHSIZE,
656                                       ::std::ptr::null(),
657                                       *val as libc::socklen_t);
658            Errno::result(res).map(drop)
659        }
660    }
661}
662
663#[allow(missing_docs)]
664// Not documented by Linux!
665#[cfg(any(target_os = "android", target_os = "linux"))]
666#[derive(Clone, Debug)]
667pub struct AlgSetKey<T>(::std::marker::PhantomData<T>);
668
669#[cfg(any(target_os = "android", target_os = "linux"))]
670impl<T> Default for AlgSetKey<T> {
671    fn default() -> Self {
672        AlgSetKey(Default::default())
673    }
674}
675
676#[cfg(any(target_os = "android", target_os = "linux"))]
677impl<T> SetSockOpt for AlgSetKey<T> where T: AsRef<[u8]> + Clone {
678    type Val = T;
679
680    fn set(&self, fd: RawFd, val: &T) -> Result<()> {
681        unsafe {
682            let res = libc::setsockopt(fd,
683                                       libc::SOL_ALG,
684                                       libc::ALG_SET_KEY,
685                                       val.as_ref().as_ptr() as *const _,
686                                       val.as_ref().len() as libc::socklen_t);
687            Errno::result(res).map(drop)
688        }
689    }
690}
691
692/*
693 *
694 * ===== Accessor helpers =====
695 *
696 */
697
698/// Helper trait that describes what is expected from a `GetSockOpt` getter.
699trait Get<T> {
700    /// Returns an uninitialized value.
701    fn uninit() -> Self;
702    /// Returns a pointer to the stored value. This pointer will be passed to the system's
703    /// `getsockopt` call (`man 3p getsockopt`, argument `option_value`).
704    fn ffi_ptr(&mut self) -> *mut c_void;
705    /// Returns length of the stored value. This pointer will be passed to the system's
706    /// `getsockopt` call (`man 3p getsockopt`, argument `option_len`).
707    fn ffi_len(&mut self) -> *mut socklen_t;
708    /// Returns the hopefully initialized inner value.
709    unsafe fn assume_init(self) -> T;
710}
711
712/// Helper trait that describes what is expected from a `SetSockOpt` setter.
713trait Set<'a, T> {
714    /// Initialize the setter with a given value.
715    fn new(val: &'a T) -> Self;
716    /// Returns a pointer to the stored value. This pointer will be passed to the system's
717    /// `setsockopt` call (`man 3p setsockopt`, argument `option_value`).
718    fn ffi_ptr(&self) -> *const c_void;
719    /// Returns length of the stored value. This pointer will be passed to the system's
720    /// `setsockopt` call (`man 3p setsockopt`, argument `option_len`).
721    fn ffi_len(&self) -> socklen_t;
722}
723
724/// Getter for an arbitrary `struct`.
725struct GetStruct<T> {
726    len: socklen_t,
727    val: MaybeUninit<T>,
728}
729
730impl<T> Get<T> for GetStruct<T> {
731    fn uninit() -> Self {
732        GetStruct {
733            len: mem::size_of::<T>() as socklen_t,
734            val: MaybeUninit::uninit(),
735        }
736    }
737
738    fn ffi_ptr(&mut self) -> *mut c_void {
739        self.val.as_mut_ptr() as *mut c_void
740    }
741
742    fn ffi_len(&mut self) -> *mut socklen_t {
743        &mut self.len
744    }
745
746    unsafe fn assume_init(self) -> T {
747        assert_eq!(self.len as usize, mem::size_of::<T>(), "invalid getsockopt implementation");
748        self.val.assume_init()
749    }
750}
751
752/// Setter for an arbitrary `struct`.
753struct SetStruct<'a, T: 'static> {
754    ptr: &'a T,
755}
756
757impl<'a, T> Set<'a, T> for SetStruct<'a, T> {
758    fn new(ptr: &'a T) -> SetStruct<'a, T> {
759        SetStruct { ptr }
760    }
761
762    fn ffi_ptr(&self) -> *const c_void {
763        self.ptr as *const T as *const c_void
764    }
765
766    fn ffi_len(&self) -> socklen_t {
767        mem::size_of::<T>() as socklen_t
768    }
769}
770
771/// Getter for a boolean value.
772struct GetBool {
773    len: socklen_t,
774    val: MaybeUninit<c_int>,
775}
776
777impl Get<bool> for GetBool {
778    fn uninit() -> Self {
779        GetBool {
780            len: mem::size_of::<c_int>() as socklen_t,
781            val: MaybeUninit::uninit(),
782        }
783    }
784
785    fn ffi_ptr(&mut self) -> *mut c_void {
786        self.val.as_mut_ptr() as *mut c_void
787    }
788
789    fn ffi_len(&mut self) -> *mut socklen_t {
790        &mut self.len
791    }
792
793    unsafe fn assume_init(self) -> bool {
794        assert_eq!(self.len as usize, mem::size_of::<c_int>(), "invalid getsockopt implementation");
795        self.val.assume_init() != 0
796    }
797}
798
799/// Setter for a boolean value.
800struct SetBool {
801    val: c_int,
802}
803
804impl<'a> Set<'a, bool> for SetBool {
805    fn new(val: &'a bool) -> SetBool {
806        SetBool { val: i32::from(*val) }
807    }
808
809    fn ffi_ptr(&self) -> *const c_void {
810        &self.val as *const c_int as *const c_void
811    }
812
813    fn ffi_len(&self) -> socklen_t {
814        mem::size_of::<c_int>() as socklen_t
815    }
816}
817
818/// Getter for an `u8` value.
819struct GetU8 {
820    len: socklen_t,
821    val: MaybeUninit<u8>,
822}
823
824impl Get<u8> for GetU8 {
825    fn uninit() -> Self {
826        GetU8 {
827            len: mem::size_of::<u8>() as socklen_t,
828            val: MaybeUninit::uninit(),
829        }
830    }
831
832    fn ffi_ptr(&mut self) -> *mut c_void {
833        self.val.as_mut_ptr() as *mut c_void
834    }
835
836    fn ffi_len(&mut self) -> *mut socklen_t {
837        &mut self.len
838    }
839
840    unsafe fn assume_init(self) -> u8 {
841        assert_eq!(self.len as usize, mem::size_of::<u8>(), "invalid getsockopt implementation");
842        self.val.assume_init()
843    }
844}
845
846/// Setter for an `u8` value.
847struct SetU8 {
848    val: u8,
849}
850
851impl<'a> Set<'a, u8> for SetU8 {
852    fn new(val: &'a u8) -> SetU8 {
853        SetU8 { val: *val }
854    }
855
856    fn ffi_ptr(&self) -> *const c_void {
857        &self.val as *const u8 as *const c_void
858    }
859
860    fn ffi_len(&self) -> socklen_t {
861        mem::size_of::<c_int>() as socklen_t
862    }
863}
864
865/// Getter for an `usize` value.
866struct GetUsize {
867    len: socklen_t,
868    val: MaybeUninit<c_int>,
869}
870
871impl Get<usize> for GetUsize {
872    fn uninit() -> Self {
873        GetUsize {
874            len: mem::size_of::<c_int>() as socklen_t,
875            val: MaybeUninit::uninit(),
876        }
877    }
878
879    fn ffi_ptr(&mut self) -> *mut c_void {
880        self.val.as_mut_ptr() as *mut c_void
881    }
882
883    fn ffi_len(&mut self) -> *mut socklen_t {
884        &mut self.len
885    }
886
887    unsafe fn assume_init(self) -> usize {
888        assert_eq!(self.len as usize, mem::size_of::<c_int>(), "invalid getsockopt implementation");
889        self.val.assume_init() as usize
890    }
891}
892
893/// Setter for an `usize` value.
894struct SetUsize {
895    val: c_int,
896}
897
898impl<'a> Set<'a, usize> for SetUsize {
899    fn new(val: &'a usize) -> SetUsize {
900        SetUsize { val: *val as c_int }
901    }
902
903    fn ffi_ptr(&self) -> *const c_void {
904        &self.val as *const c_int as *const c_void
905    }
906
907    fn ffi_len(&self) -> socklen_t {
908        mem::size_of::<c_int>() as socklen_t
909    }
910}
911
912/// Getter for a `OsString` value.
913struct GetOsString<T: AsMut<[u8]>> {
914    len: socklen_t,
915    val: MaybeUninit<T>,
916}
917
918impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> {
919    fn uninit() -> Self {
920        GetOsString {
921            len: mem::size_of::<T>() as socklen_t,
922            val: MaybeUninit::uninit(),
923        }
924    }
925
926    fn ffi_ptr(&mut self) -> *mut c_void {
927        self.val.as_mut_ptr() as *mut c_void
928    }
929
930    fn ffi_len(&mut self) -> *mut socklen_t {
931        &mut self.len
932    }
933
934    unsafe fn assume_init(self) -> OsString {
935        let len = self.len as usize;
936        let mut v = self.val.assume_init();
937        OsStr::from_bytes(&v.as_mut()[0..len]).to_owned()
938    }
939}
940
941/// Setter for a `OsString` value.
942struct SetOsString<'a> {
943    val: &'a OsStr,
944}
945
946impl<'a> Set<'a, OsString> for SetOsString<'a> {
947    fn new(val: &'a OsString) -> SetOsString {
948        SetOsString { val: val.as_os_str() }
949    }
950
951    fn ffi_ptr(&self) -> *const c_void {
952        self.val.as_bytes().as_ptr() as *const c_void
953    }
954
955    fn ffi_len(&self) -> socklen_t {
956        self.val.len() as socklen_t
957    }
958}
959
960
961#[cfg(test)]
962mod test {
963    #[cfg(any(target_os = "android", target_os = "linux"))]
964    #[test]
965    fn can_get_peercred_on_unix_socket() {
966        use super::super::*;
967
968        let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap();
969        let a_cred = getsockopt(a, super::PeerCredentials).unwrap();
970        let b_cred = getsockopt(b, super::PeerCredentials).unwrap();
971        assert_eq!(a_cred, b_cred);
972        assert!(a_cred.pid() != 0);
973    }
974
975    #[test]
976    fn is_socket_type_unix() {
977        use super::super::*;
978        use crate::unistd::close;
979
980        let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap();
981        let a_type = getsockopt(a, super::SockType).unwrap();
982        assert_eq!(a_type, SockType::Stream);
983        close(a).unwrap();
984        close(b).unwrap();
985    }
986
987    #[test]
988    fn is_socket_type_dgram() {
989        use super::super::*;
990        use crate::unistd::close;
991
992        let s = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None).unwrap();
993        let s_type = getsockopt(s, super::SockType).unwrap();
994        assert_eq!(s_type, SockType::Datagram);
995        close(s).unwrap();
996    }
997
998    #[cfg(any(target_os = "freebsd",
999              target_os = "linux",
1000              target_os = "nacl"))]
1001    #[test]
1002    fn can_get_listen_on_tcp_socket() {
1003        use super::super::*;
1004        use crate::unistd::close;
1005
1006        let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap();
1007        let s_listening = getsockopt(s, super::AcceptConn).unwrap();
1008        assert!(!s_listening);
1009        listen(s, 10).unwrap();
1010        let s_listening2 = getsockopt(s, super::AcceptConn).unwrap();
1011        assert!(s_listening2);
1012        close(s).unwrap();
1013    }
1014
1015}