Skip to main content

nix/sys/socket/
sockopt.rs

1//! Socket options as used by `setsockopt` and `getsockopt`.
2#[cfg(any(linux_android, target_os = "illumos"))]
3use super::SetSockOpt;
4use crate::sys::time::TimeVal;
5#[cfg(any(linux_android, target_os = "illumos"))]
6use crate::{errno::Errno, Result};
7use cfg_if::cfg_if;
8use libc::{self, c_int, c_void, socklen_t};
9#[cfg(apple_targets)]
10use std::ffi::CString;
11use std::ffi::{CStr, OsStr, OsString};
12use std::mem::{self, MaybeUninit};
13use std::os::fd::OwnedFd;
14use std::os::unix::ffi::OsStrExt;
15#[cfg(any(linux_android, target_os = "illumos"))]
16use std::os::unix::io::{AsFd, AsRawFd};
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!`](crate::sockopt_impl),
31/// especially if the option 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 
45///   (like `SetBool` for `bool`, `SetUsize` for `usize`, etc.).
46#[macro_export]
47macro_rules! setsockopt_impl {
48    ($name:ident, $level:expr, $flag:path, $ty:ty, $setter:ty) => {
49        #[allow(deprecated)] // to allow we have deprecated socket option
50        impl $crate::sys::socket::SetSockOpt for $name {
51            type Val = $ty;
52
53            fn set<F: std::os::unix::io::AsFd>(
54                &self,
55                fd: &F,
56                val: &$ty,
57            ) -> $crate::Result<()> {
58                use std::os::fd::AsRawFd;
59                use $crate::sys::socket::sockopt::Set;
60                let setter: $setter = Set::new(val);
61                let level = $level;
62                let flag = $flag;
63                let res = unsafe {
64                    libc::setsockopt(
65                        fd.as_fd().as_raw_fd(),
66                        level,
67                        flag,
68                        setter.ffi_ptr(),
69                        setter.ffi_len(),
70                    )
71                };
72                $crate::errno::Errno::result(res).map(drop)
73            }
74        }
75    };
76}
77
78/// Helper for implementing `GetSockOpt` for a given socket option. See
79/// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html).
80///
81/// This macro aims to help implementing `GetSockOpt` for different socket options that accept
82/// different kinds of data to be use with `getsockopt`.
83///
84/// Instead of using this macro directly consider using [`sockopt_impl!`](crate::sockopt_impl),
85/// especially if the option you are implementing represents a simple type.
86///
87/// # Arguments
88///
89/// * Name of the type you want to implement `GetSockOpt` for.
90/// * Socket layer, or a `protocol level`: could be *raw sockets* (`lic::SOL_SOCKET`),  *ip
91///   protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`),  and more. Please refer
92///   to your system manual for more options. Will be passed as the second argument (`level`) to
93///   the `getsockopt` call.
94/// * A flag to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`,
95///   `libc::SO_ORIGINAL_DST` and others. Will be passed as the third argument (`option_name`) to
96///   the `getsockopt` call.
97/// * Type of the value that you are going to get.
98/// * Type that implements the `Get` trait for the type from the previous item (`GetBool` for
99///   `bool`, `GetUsize` for `usize`, etc.).
100#[macro_export]
101macro_rules! getsockopt_impl {
102    ($name:ident, $level:expr, $flag:path, $ty:ty, $getter:ty) => {
103        #[allow(deprecated)] // to allow we have deprecated socket option
104        impl $crate::sys::socket::GetSockOpt for $name {
105            type Val = $ty;
106
107            fn get<F: std::os::unix::io::AsFd>(
108                &self,
109                fd: &F,
110            ) -> $crate::Result<$ty> {
111                use std::os::fd::AsRawFd;
112                use $crate::sys::socket::sockopt::Get;
113                let mut getter: $getter = Get::uninit();
114                let level = $level;
115                let flag = $flag;
116                let res = unsafe {
117                    libc::getsockopt(
118                        fd.as_fd().as_raw_fd(),
119                        level,
120                        flag,
121                        getter.ffi_ptr(),
122                        getter.ffi_len(),
123                    )
124                };
125                $crate::errno::Errno::result(res)?;
126
127                // getter is definitely initialized now
128                let gotten = unsafe { getter.assume_init() };
129                match <$ty>::try_from(gotten) {
130                    // In most `getsockopt_impl!` implementations, `assume_init()`
131                    // returns `$ty`, so calling `$ty`::try_from($ty) will always
132                    // succeed. which makes the following `Err(_)` branch
133                    // unreachable.
134                    //
135                    // However, there is indeed one exception, `sockopt::SockType`,
136                    // `assume_init()` returns an `i32`, but `$ty` is `super::SockType`,
137                    // this exception necessitates the use of that `try_from()`,
138                    // and we have to allow the unreachable pattern wraning.
139                    //
140                    // For the reason why we are using `i32` as the underlying
141                    // buffer type for this socket option, see issue:
142                    // https://github.com/nix-rust/nix/issues/1819
143                    #[allow(unreachable_patterns)]
144                    Err(_) => Err($crate::errno::Errno::EINVAL),
145                    Ok(r) => Ok(r),
146                }
147            }
148        }
149    };
150}
151
152/// Helper to generate the sockopt accessors. See
153/// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html) and
154/// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html).
155///
156/// This macro aims to help implementing `GetSockOpt` and `SetSockOpt` for different socket options
157/// that accept different kinds of data to be use with `getsockopt` and `setsockopt` respectively.
158///
159/// Basically this macro wraps up the [`getsockopt_impl!`](macro.getsockopt_impl.html) and
160/// [`setsockopt_impl!`](macro.setsockopt_impl.html) macros.
161///
162/// # Arguments
163///
164/// * `GetOnly`, `SetOnly` or `Both`: whether you want to implement only getter, only setter or
165///   both of them.
166/// * `$name:ident`: name of type `GetSockOpt`/`SetSockOpt` will be implemented for.
167/// * `$level:expr` : socket layer, or a `protocol level`: could be *raw sockets*
168///   (`libc::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`),
169///   and more. Please refer to your system manual for more options. Will be passed as the second
170///   argument (`level`) to the `getsockopt`/`setsockopt` call.
171/// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`,
172///   `libc::IP_ADD_MEMBERSHIP` and others. Will be passed as the third argument (`option_name`)
173///   to the `setsockopt`/`getsockopt` call.
174/// * `$ty:ty`: type of the value that will be get/set.
175/// * `$getter:ty`: `Get` implementation; optional; only for `GetOnly` and `Both`.
176/// * `$setter:ty`: `Set` implementation; optional; only for `SetOnly` and `Both`.
177// Some targets don't use all rules.
178#[allow(unused_macro_rules)]
179#[macro_export]
180macro_rules! sockopt_impl {
181    ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, bool) => {
182        sockopt_impl!($(#[$attr])*
183                      $name, GetOnly, $level, $flag, bool, $crate::sys::socket::sockopt::GetBool);
184    };
185
186    ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, u8) => {
187        sockopt_impl!($(#[$attr])* $name, GetOnly, $level, $flag, u8, $crate::sys::socket::sockopt::GetU8);
188    };
189
190    ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, usize) =>
191    {
192        sockopt_impl!($(#[$attr])*
193                      $name, GetOnly, $level, $flag, usize, $crate::sys::socket::sockopt::GetUsize);
194    };
195
196    ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, OwnedFd) =>
197    {
198        sockopt_impl!($(#[$attr])*
199                      $name, GetOnly, $level, $flag, OwnedFd, $crate::sys::socket::sockopt::GetOwnedFd);
200    };
201
202    ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, bool) => {
203        sockopt_impl!($(#[$attr])*
204                      $name, SetOnly, $level, $flag, bool, $crate::sys::socket::sockopt::SetBool);
205    };
206
207    ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, u8) => {
208        sockopt_impl!($(#[$attr])* $name, SetOnly, $level, $flag, u8, $crate::sys::socket::sockopt::SetU8);
209    };
210
211    ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, usize) =>
212    {
213        sockopt_impl!($(#[$attr])*
214                      $name, SetOnly, $level, $flag, usize, $crate::sys::socket::sockopt::SetUsize);
215    };
216
217    ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, OwnedFd) =>
218    {
219        sockopt_impl!($(#[$attr])*
220                      $name, SetOnly, $level, $flag, OwnedFd, $crate::sys::socket::sockopt::SetOwnedFd);
221    };
222
223    ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, bool) => {
224        sockopt_impl!($(#[$attr])*
225                      $name, Both, $level, $flag, bool, $crate::sys::socket::sockopt::GetBool, $crate::sys::socket::sockopt::SetBool);
226    };
227
228    ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, u8) => {
229        sockopt_impl!($(#[$attr])*
230                      $name, Both, $level, $flag, u8, $crate::sys::socket::sockopt::GetU8, $crate::sys::socket::sockopt::SetU8);
231    };
232
233    ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, usize) => {
234        sockopt_impl!($(#[$attr])*
235                      $name, Both, $level, $flag, usize, $crate::sys::socket::sockopt::GetUsize, $crate::sys::socket::sockopt::SetUsize);
236    };
237
238    ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, OwnedFd) => {
239        sockopt_impl!($(#[$attr])*
240                      $name, Both, $level, $flag, OwnedFd, $crate::sys::socket::sockopt::GetOwnedFd, $crate::sys::socket::sockopt::SetOwnedFd);
241    };
242
243    ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path,
244     OsString<$array:ty>) =>
245    {
246        sockopt_impl!($(#[$attr])*
247                      $name, Both, $level, $flag, std::ffi::OsString, $crate::sys::socket::sockopt::GetOsString<$array>,
248                      $crate::sys::socket::sockopt::SetOsString);
249    };
250
251    /*
252     * Matchers with generic getter types must be placed at the end, so
253     * they'll only match _after_ specialized matchers fail
254     */
255    ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty) =>
256    {
257        sockopt_impl!($(#[$attr])*
258                      $name, GetOnly, $level, $flag, $ty, $crate::sys::socket::sockopt::GetStruct<$ty>);
259    };
260
261    ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty,
262     $getter:ty) =>
263    {
264        $(#[$attr])*
265        #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
266        pub struct $name;
267
268        getsockopt_impl!($name, $level, $flag, $ty, $getter);
269    };
270
271    ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty) =>
272    {
273        sockopt_impl!($(#[$attr])*
274                      $name, SetOnly, $level, $flag, $ty, $crate::sys::socket::sockopt::SetStruct<$ty>);
275    };
276
277    ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty,
278     $setter:ty) =>
279    {
280        $(#[$attr])*
281        #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
282        pub struct $name;
283
284        setsockopt_impl!($name, $level, $flag, $ty, $setter);
285    };
286
287    ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, $ty:ty,
288     $getter:ty, $setter:ty) =>
289    {
290        $(#[$attr])*
291        #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
292        pub struct $name;
293
294        setsockopt_impl!($name, $level, $flag, $ty, $setter);
295        getsockopt_impl!($name, $level, $flag, $ty, $getter);
296    };
297
298    ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, $ty:ty) => {
299        sockopt_impl!($(#[$attr])*
300                      $name, Both, $level, $flag, $ty, $crate::sys::socket::sockopt::GetStruct<$ty>,
301                      $crate::sys::socket::sockopt::SetStruct<$ty>);
302    };
303}
304
305/*
306 *
307 * ===== Define sockopts =====
308 *
309 */
310
311sockopt_impl!(
312    /// Enables local address reuse
313    ReuseAddr,
314    Both,
315    libc::SOL_SOCKET,
316    libc::SO_REUSEADDR,
317    bool
318);
319#[cfg(not(any(solarish, target_os = "cygwin")))]
320sockopt_impl!(
321    /// Permits multiple AF_INET or AF_INET6 sockets to be bound to an
322    /// identical socket address.
323    ReusePort,
324    Both,
325    libc::SOL_SOCKET,
326    libc::SO_REUSEPORT,
327    bool
328);
329#[cfg(target_os = "freebsd")]
330sockopt_impl!(
331    /// Enables incoming connections to be distributed among N sockets (up to 256)
332    /// via a Load-Balancing hash based algorithm.
333    ReusePortLb,
334    Both,
335    libc::SOL_SOCKET,
336    libc::SO_REUSEPORT_LB,
337    bool
338);
339#[cfg(target_os = "freebsd")]
340#[cfg(feature = "net")]
341sockopt_impl!(
342    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
343    /// Select or query the set of functions that TCP will use for this connection.  This allows a
344    /// user to select an alternate TCP stack.
345    TcpFunctionBlk,
346    Both,
347    libc::IPPROTO_TCP,
348    libc::TCP_FUNCTION_BLK,
349    libc::tcp_function_set
350);
351#[cfg(target_os = "freebsd")]
352#[cfg(feature = "net")]
353sockopt_impl!(
354    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
355    /// Query the alias name of the set of function of the socket's TCP stack.
356    /// Uses the same field for the main name when getting from TCP_FUNCTION_BLK.
357    /// Empty if no alias.
358    TcpFunctionAlias,
359    GetOnly,
360    libc::IPPROTO_TCP,
361    libc::TCP_FUNCTION_ALIAS,
362    libc::tcp_function_set
363);
364sockopt_impl!(
365    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
366    /// Used to disable Nagle's algorithm.
367    /// 
368    /// Nagle's algorithm:
369    /// 
370    /// Under most circumstances, TCP sends data when it is presented; when
371    /// outstanding data has not yet been acknowledged, it gathers small amounts
372    /// of output to be sent in a single packet once an acknowledgement is
373    /// received.  For a small number of clients, such as window systems that
374    /// send a stream of mouse events which receive no replies, this
375    /// packetization may cause significant delays.  The boolean option, when
376    /// enabled, defeats this algorithm.
377    TcpNoDelay,
378    Both,
379    libc::IPPROTO_TCP,
380    libc::TCP_NODELAY,
381    bool
382);
383sockopt_impl!(
384    /// When enabled, a close(2) or shutdown(2) will not return until all
385    /// queued messages for the socket have been successfully sent or the
386    /// linger timeout has been reached.
387    Linger,
388    Both,
389    libc::SOL_SOCKET,
390    libc::SO_LINGER,
391    libc::linger
392);
393#[cfg(apple_targets)]
394sockopt_impl!(
395    /// Same as `SO_LINGER`, but the duration is in seconds rather than kernel ticks.
396    LingerSec,
397    Both,
398    libc::SOL_SOCKET,
399    libc::SO_LINGER_SEC,
400    libc::linger
401);
402#[cfg(feature = "net")]
403sockopt_impl!(
404    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
405    /// Join a multicast group
406    IpAddMembership,
407    SetOnly,
408    libc::IPPROTO_IP,
409    libc::IP_ADD_MEMBERSHIP,
410    super::IpMembershipRequest
411);
412#[cfg(feature = "net")]
413sockopt_impl!(
414    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
415    /// Leave a multicast group.
416    IpDropMembership,
417    SetOnly,
418    libc::IPPROTO_IP,
419    libc::IP_DROP_MEMBERSHIP,
420    super::IpMembershipRequest
421);
422cfg_if! {
423    if #[cfg(linux_android)] {
424        #[cfg(feature = "net")]
425        sockopt_impl!(
426            #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
427            /// Join an IPv6 multicast group.
428            Ipv6AddMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_ADD_MEMBERSHIP, super::Ipv6MembershipRequest);
429        #[cfg(feature = "net")]
430        sockopt_impl!(
431            #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
432            /// Leave an IPv6 multicast group.
433            Ipv6DropMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_DROP_MEMBERSHIP, super::Ipv6MembershipRequest);
434    } else if #[cfg(any(bsd, solarish))] {
435        #[cfg(feature = "net")]
436        sockopt_impl!(
437            #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
438            /// Join an IPv6 multicast group.
439            Ipv6AddMembership, SetOnly, libc::IPPROTO_IPV6,
440            libc::IPV6_JOIN_GROUP, super::Ipv6MembershipRequest);
441        #[cfg(feature = "net")]
442        sockopt_impl!(
443            #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
444            /// Leave an IPv6 multicast group.
445            Ipv6DropMembership, SetOnly, libc::IPPROTO_IPV6,
446            libc::IPV6_LEAVE_GROUP, super::Ipv6MembershipRequest);
447    }
448}
449#[cfg(feature = "net")]
450sockopt_impl!(
451    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
452    /// Set or read the time-to-live value of outgoing multicast packets for
453    /// this socket.
454    IpMulticastTtl,
455    Both,
456    libc::IPPROTO_IP,
457    libc::IP_MULTICAST_TTL,
458    u8
459);
460#[cfg(feature = "net")]
461sockopt_impl!(
462    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
463    /// Set or read the hop limit value of outgoing IPv6 multicast packets for
464    /// this socket.
465    Ipv6MulticastHops,
466    Both,
467    libc::IPPROTO_IPV6,
468    libc::IPV6_MULTICAST_HOPS,
469    libc::c_int
470);
471#[cfg(feature = "net")]
472sockopt_impl!(
473    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
474    /// Set or read a boolean integer argument that determines whether sent
475    /// multicast packets should be looped back to the local sockets.
476    IpMulticastLoop,
477    Both,
478    libc::IPPROTO_IP,
479    libc::IP_MULTICAST_LOOP,
480    bool
481);
482#[cfg(target_os = "linux")]
483#[cfg(feature = "net")]
484sockopt_impl!(
485    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
486    /// Set the protocol-defined priority for all packets to be
487    /// sent on this socket
488    Priority,
489    Both,
490    libc::SOL_SOCKET,
491    libc::SO_PRIORITY,
492    libc::c_int
493);
494#[cfg(any(linux_android, target_os = "freebsd"))]
495#[cfg(feature = "net")]
496sockopt_impl!(
497    #[deprecated(since = "0.30.0", note = "Use Ipv4Tos instead")]
498    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
499    /// Set or receive the Type-Of-Service (TOS) field that is
500    /// sent with every IP packet originating from this socket
501    IpTos,
502    Both,
503    libc::IPPROTO_IP,
504    libc::IP_TOS,
505    libc::c_int
506);
507#[cfg(any(linux_android, target_os = "freebsd"))]
508#[cfg(feature = "net")]
509sockopt_impl!(
510    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
511    /// Set or receive the Type-Of-Service (TOS) field that is
512    /// sent with every IP packet originating from this socket
513    Ipv4Tos,
514    Both,
515    libc::IPPROTO_IP,
516    libc::IP_TOS,
517    libc::c_int
518);
519#[cfg(any(linux_android, target_os = "freebsd"))]
520#[cfg(feature = "net")]
521sockopt_impl!(
522    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
523    /// If enabled, the IP_TOS ancillary message is passed with incoming packets.
524    IpRecvTos,
525    Both,
526    libc::IPPROTO_IP,
527    libc::IP_RECVTOS,
528    bool
529);
530#[cfg(any(linux_android, target_os = "freebsd"))]
531#[cfg(feature = "net")]
532sockopt_impl!(
533    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
534    /// Set the traffic class associated with outgoing packets.
535    Ipv6TClass,
536    Both,
537    libc::IPPROTO_IPV6,
538    libc::IPV6_TCLASS,
539    libc::c_int
540);
541#[cfg(any(linux_android, target_os = "freebsd"))]
542#[cfg(feature = "net")]
543sockopt_impl!(
544    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
545    /// If enabled, the IPV6_TCLASS ancillary message is passed with incoming packets.
546    Ipv6RecvTClass,
547    Both,
548    libc::IPPROTO_IPV6,
549    libc::IPV6_RECVTCLASS,
550    bool
551);
552#[cfg(any(linux_android, target_os = "fuchsia"))]
553#[cfg(feature = "net")]
554sockopt_impl!(
555    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
556    /// If enabled, this boolean option allows binding to an IP address that
557    /// is nonlocal or does not (yet) exist.
558    IpFreebind,
559    Both,
560    libc::IPPROTO_IP,
561    libc::IP_FREEBIND,
562    bool
563);
564#[cfg(linux_android)]
565#[cfg(feature = "net")]
566#[cfg(not(target_env = "uclibc"))]
567sockopt_impl!(
568    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
569    /// If enabled, the kernel will not reserve an ephemeral port when binding
570    /// socket with a port number of 0. The port will later be automatically
571    /// chosen at connect time, in a way that allows sharing a source port as
572    /// long as the 4-tuple is unique.
573    IpBindAddressNoPort,
574    Both,
575    libc::IPPROTO_IP,
576    libc::IP_BIND_ADDRESS_NO_PORT,
577    bool
578);
579sockopt_impl!(
580    /// Specify the receiving timeout until reporting an error.
581    ReceiveTimeout,
582    Both,
583    libc::SOL_SOCKET,
584    libc::SO_RCVTIMEO,
585    TimeVal
586);
587sockopt_impl!(
588    /// Specify the sending timeout until reporting an error.
589    SendTimeout,
590    Both,
591    libc::SOL_SOCKET,
592    libc::SO_SNDTIMEO,
593    TimeVal
594);
595sockopt_impl!(
596    /// Set or get the broadcast flag.
597    Broadcast,
598    Both,
599    libc::SOL_SOCKET,
600    libc::SO_BROADCAST,
601    bool
602);
603sockopt_impl!(
604    /// If this option is enabled, out-of-band data is directly placed into
605    /// the receive data stream.
606    OobInline,
607    Both,
608    libc::SOL_SOCKET,
609    libc::SO_OOBINLINE,
610    bool
611);
612sockopt_impl!(
613    /// Get and clear the pending socket error.
614    SocketError,
615    GetOnly,
616    libc::SOL_SOCKET,
617    libc::SO_ERROR,
618    i32
619);
620sockopt_impl!(
621    /// Set or get the don't route flag.
622    DontRoute,
623    Both,
624    libc::SOL_SOCKET,
625    libc::SO_DONTROUTE,
626    bool
627);
628sockopt_impl!(
629    /// Enable sending of keep-alive messages on connection-oriented sockets.
630    KeepAlive,
631    Both,
632    libc::SOL_SOCKET,
633    libc::SO_KEEPALIVE,
634    bool
635);
636#[cfg(freebsdlike)]
637sockopt_impl!(
638    /// Get the credentials of the peer process of a connected unix domain
639    /// socket.
640    LocalPeerCred,
641    GetOnly,
642    0,
643    libc::LOCAL_PEERCRED,
644    super::XuCred
645);
646#[cfg(apple_targets)]
647sockopt_impl!(
648    /// Get the credentials of the peer process of a connected unix domain
649    /// socket.
650    LocalPeerCred,
651    GetOnly,
652    libc::SOL_LOCAL,
653    libc::LOCAL_PEERCRED,
654    super::XuCred
655);
656#[cfg(apple_targets)]
657sockopt_impl!(
658    /// Get the PID of the peer process of a connected unix domain socket.
659    LocalPeerPid,
660    GetOnly,
661    libc::SOL_LOCAL,
662    libc::LOCAL_PEERPID,
663    libc::c_int
664);
665#[cfg(apple_targets)]
666sockopt_impl!(
667    /// Get the audit token of the peer process of a connected unix domain
668    /// socket.
669    LocalPeerToken,
670    GetOnly,
671    libc::SOL_LOCAL,
672    libc::LOCAL_PEERTOKEN,
673    super::audit_token_t
674);
675#[cfg(linux_android)]
676sockopt_impl!(
677    /// Return the credentials of the foreign process connected to this socket.
678    PeerCredentials,
679    GetOnly,
680    libc::SOL_SOCKET,
681    libc::SO_PEERCRED,
682    super::UnixCredentials
683);
684#[cfg(target_os = "linux")]
685sockopt_impl!(
686    /// Return the pidfd of the foreign process connected to this socket.
687    PeerPidfd,
688    GetOnly,
689    libc::SOL_SOCKET,
690    libc::SO_PEERPIDFD,
691    OwnedFd
692);
693#[cfg(target_os = "freebsd")]
694#[cfg(feature = "net")]
695sockopt_impl!(
696    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
697    /// Get backlog limit of the socket
698    ListenQLimit,
699    GetOnly,
700    libc::SOL_SOCKET,
701    libc::SO_LISTENQLIMIT,
702    u32
703);
704#[cfg(apple_targets)]
705#[cfg(feature = "net")]
706sockopt_impl!(
707    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
708    /// Specify the amount of time, in seconds, that the connection must be idle
709    /// before keepalive probes (if enabled) are sent.
710    TcpKeepAlive,
711    Both,
712    libc::IPPROTO_TCP,
713    libc::TCP_KEEPALIVE,
714    u32
715);
716#[cfg(any(freebsdlike, linux_android))]
717#[cfg(feature = "net")]
718sockopt_impl!(
719    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
720    /// The time (in seconds) the connection needs to remain idle before TCP
721    /// starts sending keepalive probes
722    TcpKeepIdle,
723    Both,
724    libc::IPPROTO_TCP,
725    libc::TCP_KEEPIDLE,
726    u32
727);
728cfg_if! {
729    if #[cfg(any(linux_android, apple_targets))] {
730        sockopt_impl!(
731            /// The maximum segment size for outgoing TCP packets.
732            TcpMaxSeg, Both, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32);
733    } else if #[cfg(not(target_os = "redox"))] {
734        sockopt_impl!(
735            /// The maximum segment size for outgoing TCP packets.
736            TcpMaxSeg, GetOnly, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32);
737    }
738}
739#[cfg(not(any(
740    target_os = "openbsd",
741    target_os = "haiku",
742    target_os = "redox"
743)))]
744#[cfg(feature = "net")]
745sockopt_impl!(
746    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
747    /// The maximum number of keepalive probes TCP should send before
748    /// dropping the connection.
749    TcpKeepCount,
750    Both,
751    libc::IPPROTO_TCP,
752    libc::TCP_KEEPCNT,
753    u32
754);
755#[cfg(any(linux_android, target_os = "fuchsia"))]
756sockopt_impl!(
757    #[allow(missing_docs)]
758    // Not documented by Linux!
759    TcpRepair,
760    Both,
761    libc::IPPROTO_TCP,
762    libc::TCP_REPAIR,
763    u32
764);
765#[cfg(not(any(
766    target_os = "openbsd",
767    target_os = "haiku",
768    target_os = "redox"
769)))]
770#[cfg(feature = "net")]
771sockopt_impl!(
772    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
773    /// The time (in seconds) between individual keepalive probes.
774    TcpKeepInterval,
775    Both,
776    libc::IPPROTO_TCP,
777    libc::TCP_KEEPINTVL,
778    u32
779);
780#[cfg(any(target_os = "fuchsia", target_os = "linux"))]
781#[cfg(feature = "net")]
782sockopt_impl!(
783    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
784    /// Specifies the maximum amount of time in milliseconds that transmitted
785    /// data may remain unacknowledged before TCP will forcibly close the
786    /// corresponding connection
787    TcpUserTimeout,
788    Both,
789    libc::IPPROTO_TCP,
790    libc::TCP_USER_TIMEOUT,
791    u32
792);
793#[cfg(linux_android)]
794#[cfg(feature = "net")]
795sockopt_impl!(
796    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
797    /// Enables TCP Fast Open (RFC 7413) on a connecting socket. If a fast open
798    /// cookie is not available (first attempt to connect), `connect` syscall
799    /// will behave as usual, except for internally trying to solicit a cookie
800    /// from remote peer. When cookie is available, the next `connect` syscall
801    /// will immediately succeed without actually establishing TCP connection.
802    /// The connection establishment will be defered till the next `write` or
803    /// `sendmsg` syscalls on the socket, allowing TCP prtocol to establish
804    /// connection and send data in the same packets. Note: calling `read` right
805    /// after `connect` without `write` on the socket will cause the blocking
806    /// socket to be blocked forever.
807    TcpFastOpenConnect,
808    Both,
809    libc::IPPROTO_TCP,
810    libc::TCP_FASTOPEN_CONNECT,
811    bool
812);
813sockopt_impl!(
814    /// Sets or gets the maximum socket receive buffer in bytes.
815    RcvBuf,
816    Both,
817    libc::SOL_SOCKET,
818    libc::SO_RCVBUF,
819    usize
820);
821sockopt_impl!(
822    /// Sets or gets the maximum socket send buffer in bytes.
823    SndBuf,
824    Both,
825    libc::SOL_SOCKET,
826    libc::SO_SNDBUF,
827    usize
828);
829#[cfg(linux_android)]
830sockopt_impl!(
831    /// Using this socket option, a privileged (`CAP_NET_ADMIN`) process can
832    /// perform the same task as `SO_RCVBUF`, but the `rmem_max limit` can be
833    /// overridden.
834    RcvBufForce,
835    SetOnly,
836    libc::SOL_SOCKET,
837    libc::SO_RCVBUFFORCE,
838    usize
839);
840#[cfg(linux_android)]
841sockopt_impl!(
842    /// Using this socket option, a privileged (`CAP_NET_ADMIN`)  process can
843    /// perform the same task as `SO_SNDBUF`, but the `wmem_max` limit can be
844    /// overridden.
845    SndBufForce,
846    SetOnly,
847    libc::SOL_SOCKET,
848    libc::SO_SNDBUFFORCE,
849    usize
850);
851sockopt_impl!(
852    /// Gets the socket type as an integer.
853    SockType,
854    GetOnly,
855    libc::SOL_SOCKET,
856    libc::SO_TYPE,
857    super::SockType,
858    GetStruct<i32>
859);
860sockopt_impl!(
861    /// Returns a value indicating whether or not this socket has been marked to
862    /// accept connections with `listen(2)`.
863    AcceptConn,
864    GetOnly,
865    libc::SOL_SOCKET,
866    libc::SO_ACCEPTCONN,
867    bool
868);
869#[cfg(linux_android)]
870sockopt_impl!(
871    /// Bind this socket to a particular device like “eth0”.
872    BindToDevice,
873    Both,
874    libc::SOL_SOCKET,
875    libc::SO_BINDTODEVICE,
876    OsString<[u8; libc::IFNAMSIZ]>
877);
878#[cfg(linux_android)]
879#[cfg(feature = "net")]
880sockopt_impl!(
881    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
882    #[allow(missing_docs)]
883    // Not documented by Linux!
884    OriginalDst,
885    GetOnly,
886    libc::SOL_IP,
887    libc::SO_ORIGINAL_DST,
888    libc::sockaddr_in
889);
890#[cfg(linux_android)]
891sockopt_impl!(
892    #[allow(missing_docs)]
893    // Not documented by Linux!
894    Ip6tOriginalDst,
895    GetOnly,
896    libc::SOL_IPV6,
897    libc::IP6T_SO_ORIGINAL_DST,
898    libc::sockaddr_in6
899);
900#[cfg(linux_android)]
901sockopt_impl!(
902    /// Specifies exact type of timestamping information collected by the kernel
903    /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html)
904    Timestamping,
905    Both,
906    libc::SOL_SOCKET,
907    libc::SO_TIMESTAMPING,
908    super::TimestampingFlag
909);
910#[cfg(not(any(
911    target_os = "aix",
912    target_os = "haiku",
913    target_os = "hurd",
914    target_os = "redox",
915    target_os = "cygwin"
916)))]
917sockopt_impl!(
918    /// Enable or disable the receiving of the `SO_TIMESTAMP` control message.
919    ReceiveTimestamp,
920    Both,
921    libc::SOL_SOCKET,
922    libc::SO_TIMESTAMP,
923    bool
924);
925#[cfg(linux_android)]
926sockopt_impl!(
927    /// Enable or disable the receiving of the `SO_TIMESTAMPNS` control message.
928    ReceiveTimestampns,
929    Both,
930    libc::SOL_SOCKET,
931    libc::SO_TIMESTAMPNS,
932    bool
933);
934#[cfg(target_os = "freebsd")]
935sockopt_impl!(
936    /// Sets a specific timestamp format instead of the classic `SCM_TIMESTAMP`,
937    /// to follow up after `SO_TIMESTAMP` is set.
938    TsClock,
939    Both,
940    libc::SOL_SOCKET,
941    libc::SO_TS_CLOCK,
942    super::SocketTimestamp
943);
944#[cfg(linux_android)]
945#[cfg(feature = "net")]
946sockopt_impl!(
947    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
948    /// Setting this boolean option enables transparent proxying on this socket.
949    IpTransparent,
950    Both,
951    libc::SOL_IP,
952    libc::IP_TRANSPARENT,
953    bool
954);
955#[cfg(target_os = "openbsd")]
956#[cfg(feature = "net")]
957sockopt_impl!(
958    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
959    /// Allows the socket to be bound to addresses which are not local to the
960    /// machine, so it can be used to make a transparent proxy.
961    BindAny,
962    Both,
963    libc::SOL_SOCKET,
964    libc::SO_BINDANY,
965    bool
966);
967#[cfg(target_os = "freebsd")]
968#[cfg(feature = "net")]
969sockopt_impl!(
970    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
971    /// Can `bind(2)` to any address, even one not bound to any available
972    /// network interface in the system.
973    BindAny,
974    Both,
975    libc::IPPROTO_IP,
976    libc::IP_BINDANY,
977    bool
978);
979#[cfg(target_os = "freebsd")]
980sockopt_impl!(
981    /// Set the route table (FIB) for this socket up to the `net.fibs` OID limit
982    /// (more specific than the setfib command line/call which are process based).
983    Fib,
984    SetOnly,
985    libc::SOL_SOCKET,
986    libc::SO_SETFIB,
987    i32
988);
989#[cfg(target_os = "freebsd")]
990sockopt_impl!(
991    /// Set `so_user_cookie` for this socket allowing network traffic based
992    /// upon it, similar to Linux's netfilter MARK.
993    UserCookie,
994    SetOnly,
995    libc::SOL_SOCKET,
996    libc::SO_USER_COOKIE,
997    u32
998);
999#[cfg(target_os = "openbsd")]
1000sockopt_impl!(
1001    /// Set the route table for this socket, needs a privileged user if
1002    /// the process/socket had been set to the non default route.
1003    Rtable,
1004    SetOnly,
1005    libc::SOL_SOCKET,
1006    libc::SO_RTABLE,
1007    i32
1008);
1009#[cfg(any(target_os = "freebsd", target_os = "netbsd"))]
1010sockopt_impl!(
1011    /// Get/set a filter on this socket before accepting connections similarly
1012    /// to Linux's TCP_DEFER_ACCEPT but after the listen's call.
1013    AcceptFilter,
1014    Both,
1015    libc::SOL_SOCKET,
1016    libc::SO_ACCEPTFILTER,
1017    libc::accept_filter_arg
1018);
1019#[cfg(target_os = "linux")]
1020sockopt_impl!(
1021    /// Set the mark for each packet sent through this socket (similar to the
1022    /// netfilter MARK target but socket-based).
1023    Mark,
1024    Both,
1025    libc::SOL_SOCKET,
1026    libc::SO_MARK,
1027    u32
1028);
1029#[cfg(linux_android)]
1030sockopt_impl!(
1031    /// Enable or disable the receiving of the `SCM_CREDENTIALS` control
1032    /// message.
1033    PassCred,
1034    Both,
1035    libc::SOL_SOCKET,
1036    libc::SO_PASSCRED,
1037    bool
1038);
1039#[cfg(any(target_os = "freebsd", target_os = "linux"))]
1040#[cfg(feature = "net")]
1041sockopt_impl!(
1042    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1043    /// This option allows the caller to set the TCP congestion control
1044    /// algorithm to be used,  on a per-socket basis.
1045    TcpCongestion,
1046    Both,
1047    libc::IPPROTO_TCP,
1048    libc::TCP_CONGESTION,
1049    OsString<[u8; TCP_CA_NAME_MAX]>
1050);
1051#[cfg(any(linux_android, apple_targets, target_os = "netbsd"))]
1052#[cfg(feature = "net")]
1053sockopt_impl!(
1054    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1055    /// Pass an `IP_PKTINFO` ancillary message that contains a pktinfo
1056    /// structure that supplies some information about the incoming packet.
1057    Ipv4PacketInfo,
1058    Both,
1059    libc::IPPROTO_IP,
1060    libc::IP_PKTINFO,
1061    bool
1062);
1063#[cfg(any(linux_android, bsd))]
1064#[cfg(feature = "net")]
1065sockopt_impl!(
1066    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1067    /// Set delivery of the `IPV6_PKTINFO` control message on incoming
1068    /// datagrams.
1069    Ipv6RecvPacketInfo,
1070    Both,
1071    libc::IPPROTO_IPV6,
1072    libc::IPV6_RECVPKTINFO,
1073    bool
1074);
1075
1076#[cfg(any(linux_android, bsd))]
1077#[cfg(feature = "net")]
1078sockopt_impl!(
1079    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1080    /// Pass an `IPV6_PKTINFO` ancillary message that contains a in6_pktinfo
1081    /// structure that supplies some information about the incoming packet.
1082    Ipv6PacketInfo,
1083    Both,
1084    libc::IPPROTO_IPV6,
1085    libc::IPV6_PKTINFO,
1086    bool
1087);
1088#[cfg(bsd)]
1089#[cfg(feature = "net")]
1090sockopt_impl!(
1091    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1092    /// The `recvmsg(2)` call returns a `struct sockaddr_dl` corresponding to
1093    /// the interface on which the packet was received.
1094    Ipv4RecvIf,
1095    Both,
1096    libc::IPPROTO_IP,
1097    libc::IP_RECVIF,
1098    bool
1099);
1100#[cfg(bsd)]
1101#[cfg(feature = "net")]
1102sockopt_impl!(
1103    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1104    /// The `recvmsg(2)` call will return the destination IP address for a UDP
1105    /// datagram.
1106    Ipv4RecvDstAddr,
1107    Both,
1108    libc::IPPROTO_IP,
1109    libc::IP_RECVDSTADDR,
1110    bool
1111);
1112#[cfg(any(linux_android, target_os = "freebsd"))]
1113#[cfg(feature = "net")]
1114sockopt_impl!(
1115    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1116    /// The `recvmsg(2)` call will return the destination IP address for a UDP
1117    /// datagram.
1118    Ipv4OrigDstAddr,
1119    Both,
1120    libc::IPPROTO_IP,
1121    libc::IP_ORIGDSTADDR,
1122    bool
1123);
1124#[cfg(linux_android)]
1125#[cfg(feature = "net")]
1126sockopt_impl!(
1127    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1128    #[allow(missing_docs)]
1129    // Not documented by Linux!
1130    UdpGsoSegment,
1131    Both,
1132    libc::SOL_UDP,
1133    libc::UDP_SEGMENT,
1134    libc::c_int
1135);
1136#[cfg(linux_android)]
1137#[cfg(feature = "net")]
1138sockopt_impl!(
1139    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1140    #[allow(missing_docs)]
1141    // Not documented by Linux!
1142    UdpGroSegment,
1143    Both,
1144    libc::IPPROTO_UDP,
1145    libc::UDP_GRO,
1146    bool
1147);
1148#[cfg(target_os = "linux")]
1149sockopt_impl!(
1150    /// Configures the behavior of time-based transmission of packets, for use
1151    /// with the `TxTime` control message.
1152    TxTime,
1153    Both,
1154    libc::SOL_SOCKET,
1155    libc::SO_TXTIME,
1156    libc::sock_txtime
1157);
1158#[cfg(any(linux_android, target_os = "fuchsia"))]
1159sockopt_impl!(
1160    /// Indicates that an unsigned 32-bit value ancillary message (cmsg) should
1161    /// be attached to received skbs indicating the number of packets dropped by
1162    /// the socket since its creation.
1163    RxqOvfl,
1164    Both,
1165    libc::SOL_SOCKET,
1166    libc::SO_RXQ_OVFL,
1167    libc::c_int
1168);
1169#[cfg(feature = "net")]
1170sockopt_impl!(
1171    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1172    /// The socket is restricted to sending and receiving IPv6 packets only.
1173    Ipv6V6Only,
1174    Both,
1175    libc::IPPROTO_IPV6,
1176    libc::IPV6_V6ONLY,
1177    bool
1178);
1179#[cfg(linux_android)]
1180sockopt_impl!(
1181    /// Enable extended reliable error message passing.
1182    Ipv4RecvErr,
1183    Both,
1184    libc::IPPROTO_IP,
1185    libc::IP_RECVERR,
1186    bool
1187);
1188#[cfg(linux_android)]
1189sockopt_impl!(
1190    /// Control receiving of asynchronous error options.
1191    Ipv6RecvErr,
1192    Both,
1193    libc::IPPROTO_IPV6,
1194    libc::IPV6_RECVERR,
1195    bool
1196);
1197#[cfg(linux_android)]
1198sockopt_impl!(
1199    /// Fetch the current system-estimated Path MTU.
1200    IpMtu,
1201    GetOnly,
1202    libc::IPPROTO_IP,
1203    libc::IP_MTU,
1204    libc::c_int
1205);
1206#[cfg(any(linux_android, target_os = "freebsd"))]
1207sockopt_impl!(
1208    /// Set or retrieve the current time-to-live field that is used in every
1209    /// packet sent from this socket.
1210    Ipv4Ttl,
1211    Both,
1212    libc::IPPROTO_IP,
1213    libc::IP_TTL,
1214    libc::c_int
1215);
1216#[cfg(any(linux_android, target_os = "freebsd"))]
1217#[cfg(feature = "net")]
1218sockopt_impl!(
1219    /// Enables a receiving socket to retrieve the Time-to-Live (TTL) field 
1220    /// from incoming IPv4 packets.
1221    Ipv4RecvTtl,
1222    Both,
1223    libc::IPPROTO_IP,
1224    libc::IP_RECVTTL,
1225    bool
1226);
1227#[cfg(any(apple_targets, linux_android, target_os = "freebsd"))]
1228sockopt_impl!(
1229    /// Set the unicast hop limit for the socket.
1230    Ipv6Ttl,
1231    Both,
1232    libc::IPPROTO_IPV6,
1233    libc::IPV6_UNICAST_HOPS,
1234    libc::c_int
1235);
1236#[cfg(any(linux_android, target_os = "freebsd"))]
1237#[cfg(feature = "net")]
1238sockopt_impl!(
1239    /// Enables a receiving socket to retrieve the Hop Limit field 
1240    /// (similar to TTL in IPv4) from incoming IPv6 packets.
1241    Ipv6RecvHopLimit,
1242    Both,
1243    libc::IPPROTO_IPV6,
1244    libc::IPV6_RECVHOPLIMIT,
1245    bool
1246);
1247#[cfg(any(
1248    all(linux_android, not(target_env = "uclibc")),
1249    target_os = "freebsd"
1250))]
1251#[cfg(feature = "net")]
1252sockopt_impl!(
1253    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1254    /// The `recvmsg(2)` call will return the destination IP address for a UDP
1255    /// datagram.
1256    Ipv6OrigDstAddr,
1257    Both,
1258    libc::IPPROTO_IPV6,
1259    libc::IPV6_ORIGDSTADDR,
1260    bool
1261);
1262#[cfg(apple_targets)]
1263sockopt_impl!(
1264    /// Set "don't fragment packet" flag on the IP packet.
1265    IpDontFrag,
1266    Both,
1267    libc::IPPROTO_IP,
1268    libc::IP_DONTFRAG,
1269    bool
1270);
1271#[cfg(any(
1272    all(linux_android, not(target_env = "uclibc")),
1273    apple_targets
1274))]
1275sockopt_impl!(
1276    /// Set "don't fragment packet" flag on the IPv6 packet.
1277    Ipv6DontFrag,
1278    Both,
1279    libc::IPPROTO_IPV6,
1280    libc::IPV6_DONTFRAG,
1281    bool
1282);
1283#[cfg(apple_targets)]
1284#[cfg(feature = "net")]
1285sockopt_impl!(
1286    /// Get the utun interface name.
1287    UtunIfname,
1288    GetOnly,
1289    libc::SYSPROTO_CONTROL,
1290    libc::UTUN_OPT_IFNAME,
1291    CString,
1292    GetCString<[u8; libc::IFNAMSIZ]>
1293);
1294
1295#[cfg(solarish)]
1296sockopt_impl!(
1297    /// Enable/disable exclusive binding.
1298    /// Prevent multiple sockets to bind to the same
1299    /// address:port, neutralizing `SO_REUSEADDR` effect.
1300    ExclBind,
1301    Both,
1302    libc::SOL_SOCKET,
1303    libc::SO_EXCLBIND,
1304    bool
1305);
1306#[cfg(target_os = "linux")]
1307sockopt_impl!(
1308    /// To be used with `ReusePort`,
1309    /// we can then attach a BPF (classic)
1310    /// to set how the packets are assigned
1311    /// to the socket (e.g. cpu distribution).
1312    AttachReusePortCbpf,
1313    SetOnly,
1314    libc::SOL_SOCKET,
1315    libc::SO_ATTACH_REUSEPORT_CBPF,
1316    libc::sock_fprog
1317);
1318
1319#[allow(missing_docs)]
1320// Not documented by Linux!
1321#[cfg(linux_android)]
1322#[derive(Copy, Clone, Debug)]
1323pub struct AlgSetAeadAuthSize;
1324
1325// ALG_SET_AEAD_AUTH_SIZE read the length from passed `option_len`
1326// See https://elixir.bootlin.com/linux/v4.4/source/crypto/af_alg.c#L222
1327#[cfg(linux_android)]
1328impl SetSockOpt for AlgSetAeadAuthSize {
1329    type Val = usize;
1330
1331    fn set<F: AsFd>(&self, fd: &F, val: &usize) -> Result<()> {
1332        unsafe {
1333            let res = libc::setsockopt(
1334                fd.as_fd().as_raw_fd(),
1335                libc::SOL_ALG,
1336                libc::ALG_SET_AEAD_AUTHSIZE,
1337                ::std::ptr::null(),
1338                *val as libc::socklen_t,
1339            );
1340            Errno::result(res).map(drop)
1341        }
1342    }
1343}
1344
1345#[allow(missing_docs)]
1346// Not documented by Linux!
1347#[cfg(linux_android)]
1348#[derive(Clone, Debug)]
1349pub struct AlgSetKey<T>(::std::marker::PhantomData<T>);
1350
1351#[cfg(linux_android)]
1352impl<T> Default for AlgSetKey<T> {
1353    fn default() -> Self {
1354        AlgSetKey(Default::default())
1355    }
1356}
1357
1358#[cfg(linux_android)]
1359impl<T> SetSockOpt for AlgSetKey<T>
1360where
1361    T: AsRef<[u8]> + Clone,
1362{
1363    type Val = T;
1364
1365    fn set<F: AsFd>(&self, fd: &F, val: &T) -> Result<()> {
1366        unsafe {
1367            let res = libc::setsockopt(
1368                fd.as_fd().as_raw_fd(),
1369                libc::SOL_ALG,
1370                libc::ALG_SET_KEY,
1371                val.as_ref().as_ptr().cast(),
1372                val.as_ref().len() as libc::socklen_t,
1373            );
1374            Errno::result(res).map(drop)
1375        }
1376    }
1377}
1378
1379/// Set the Upper Layer Protocol (ULP) on the TCP socket.
1380///
1381/// For example, to enable the TLS ULP on a socket, the C function call would be:
1382///
1383/// ```c
1384/// setsockopt(sock, SOL_TCP, TCP_ULP, "tls", sizeof("tls"));
1385/// ```
1386///
1387/// ... and the `nix` equivalent is:
1388///
1389/// ```ignore,rust
1390/// setsockopt(sock, TcpUlp::default(), b"tls");
1391/// ```
1392///
1393/// Note that the ULP name does not need a trailing NUL terminator (`\0`).
1394#[cfg(linux_android)]
1395#[derive(Clone, Debug)]
1396pub struct TcpUlp<T>(::std::marker::PhantomData<T>);
1397
1398#[cfg(linux_android)]
1399impl<T> Default for TcpUlp<T> {
1400    fn default() -> Self {
1401        TcpUlp(Default::default())
1402    }
1403}
1404
1405#[cfg(linux_android)]
1406impl<T> SetSockOpt for TcpUlp<T>
1407where
1408    T: AsRef<[u8]> + Clone,
1409{
1410    type Val = T;
1411
1412    fn set<F: AsFd>(&self, fd: &F, val: &Self::Val) -> Result<()> {
1413        unsafe {
1414            let res = libc::setsockopt(
1415                fd.as_fd().as_raw_fd(),
1416                libc::SOL_TCP,
1417                libc::TCP_ULP,
1418                val.as_ref().as_ptr().cast(),
1419                val.as_ref().len() as libc::socklen_t,
1420            );
1421            Errno::result(res).map(drop)
1422        }
1423    }
1424}
1425
1426/// Value used with the [`TcpTlsTx`] and [`TcpTlsRx`] socket options.
1427#[cfg(target_os = "linux")]
1428#[derive(Copy, Clone, Debug)]
1429pub enum TlsCryptoInfo {
1430    /// AES-128-GCM
1431    Aes128Gcm(libc::tls12_crypto_info_aes_gcm_128),
1432
1433    /// AES-256-GCM
1434    Aes256Gcm(libc::tls12_crypto_info_aes_gcm_256),
1435
1436    /// CHACHA20-POLY1305
1437    Chacha20Poly1305(libc::tls12_crypto_info_chacha20_poly1305),
1438}
1439
1440/// Set the Kernel TLS write parameters on the TCP socket.
1441///
1442/// For example, the C function call would be:
1443///
1444/// ```c
1445/// setsockopt(sock, SOL_TLS, TLS_TX, &crypto_info, sizeof(crypto_info));
1446/// ```
1447///
1448/// ... and the `nix` equivalent is:
1449///
1450/// ```ignore,rust
1451/// setsockopt(sock, TcpTlsTx, &crypto_info);
1452/// ```
1453#[cfg(target_os = "linux")]
1454#[derive(Copy, Clone, Debug)]
1455pub struct TcpTlsTx;
1456
1457#[cfg(target_os = "linux")]
1458impl SetSockOpt for TcpTlsTx {
1459    type Val = TlsCryptoInfo;
1460
1461    fn set<F: AsFd>(&self, fd: &F, val: &Self::Val) -> Result<()> {
1462        let (ffi_ptr, ffi_len) = match val {
1463            TlsCryptoInfo::Aes128Gcm(crypto_info) => {
1464                (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
1465            }
1466            TlsCryptoInfo::Aes256Gcm(crypto_info) => {
1467                (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
1468            }
1469            TlsCryptoInfo::Chacha20Poly1305(crypto_info) => {
1470                (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
1471            }
1472        };
1473        unsafe {
1474            let res = libc::setsockopt(
1475                fd.as_fd().as_raw_fd(),
1476                libc::SOL_TLS,
1477                libc::TLS_TX,
1478                ffi_ptr,
1479                ffi_len as libc::socklen_t,
1480            );
1481            Errno::result(res).map(drop)
1482        }
1483    }
1484}
1485
1486/// Set the Kernel TLS read parameters on the TCP socket.
1487///
1488/// For example, the C function call would be:
1489///
1490/// ```c
1491/// setsockopt(sock, SOL_TLS, TLS_RX, &crypto_info, sizeof(crypto_info));
1492/// ```
1493///
1494/// ... and the `nix` equivalent is:
1495///
1496/// ```ignore,rust
1497/// setsockopt(sock, TcpTlsRx, &crypto_info);
1498/// ```
1499#[cfg(target_os = "linux")]
1500#[derive(Copy, Clone, Debug)]
1501pub struct TcpTlsRx;
1502
1503#[cfg(target_os = "linux")]
1504impl SetSockOpt for TcpTlsRx {
1505    type Val = TlsCryptoInfo;
1506
1507    fn set<F: AsFd>(&self, fd: &F, val: &Self::Val) -> Result<()> {
1508        let (ffi_ptr, ffi_len) = match val {
1509            TlsCryptoInfo::Aes128Gcm(crypto_info) => {
1510                (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
1511            }
1512            TlsCryptoInfo::Aes256Gcm(crypto_info) => {
1513                (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
1514            }
1515            TlsCryptoInfo::Chacha20Poly1305(crypto_info) => {
1516                (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
1517            }
1518        };
1519        unsafe {
1520            let res = libc::setsockopt(
1521                fd.as_fd().as_raw_fd(),
1522                libc::SOL_TLS,
1523                libc::TLS_RX,
1524                ffi_ptr,
1525                ffi_len as libc::socklen_t,
1526            );
1527            Errno::result(res).map(drop)
1528        }
1529    }
1530}
1531
1532#[cfg(target_os = "illumos")]
1533#[derive(Copy, Clone, Debug)]
1534/// Attach a named filter to this socket to be able to
1535/// defer when anough byte had been buffered by the kernel
1536pub struct FilterAttach;
1537
1538#[cfg(target_os = "illumos")]
1539impl SetSockOpt for FilterAttach {
1540    type Val = OsStr;
1541
1542    fn set<F: AsFd>(&self, fd: &F, val: &Self::Val) -> Result<()> {
1543        if val.len() > libc::FILNAME_MAX as usize {
1544            return Err(Errno::EINVAL);
1545        }
1546        unsafe {
1547            let res = libc::setsockopt(
1548                fd.as_fd().as_raw_fd(),
1549                libc::SOL_FILTER,
1550                libc::FIL_ATTACH,
1551                val.as_bytes().as_ptr().cast(),
1552                val.len() as libc::socklen_t,
1553            );
1554            Errno::result(res).map(drop)
1555        }
1556    }
1557}
1558
1559#[cfg(target_os = "illumos")]
1560#[derive(Copy, Clone, Debug)]
1561/// Detach a socket filter previously attached with FIL_ATTACH
1562pub struct FilterDetach;
1563
1564#[cfg(target_os = "illumos")]
1565impl SetSockOpt for FilterDetach {
1566    type Val = OsStr;
1567
1568    fn set<F: AsFd>(&self, fd: &F, val: &Self::Val) -> Result<()> {
1569        if val.len() > libc::FILNAME_MAX as usize {
1570            return Err(Errno::EINVAL);
1571        }
1572        unsafe {
1573            let res = libc::setsockopt(
1574                fd.as_fd().as_raw_fd(),
1575                libc::SOL_FILTER,
1576                libc::FIL_DETACH,
1577                val.as_bytes().as_ptr().cast(),
1578                val.len() as libc::socklen_t,
1579            );
1580            Errno::result(res).map(drop)
1581        }
1582    }
1583}
1584/*
1585 *
1586 * ===== Accessor helpers =====
1587 *
1588 */
1589
1590/// Helper trait that describes what is expected from a `GetSockOpt` getter.
1591// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1592#[doc(hidden)]
1593pub trait Get<T> {
1594    /// Returns an uninitialized value.
1595    fn uninit() -> Self;
1596    /// Returns a pointer to the stored value. This pointer will be passed to the system's
1597    /// `getsockopt` call (`man 3p getsockopt`, argument `option_value`).
1598    fn ffi_ptr(&mut self) -> *mut c_void;
1599    /// Returns length of the stored value. This pointer will be passed to the system's
1600    /// `getsockopt` call (`man 3p getsockopt`, argument `option_len`).
1601    fn ffi_len(&mut self) -> *mut socklen_t;
1602    /// Returns the hopefully initialized inner value.
1603    unsafe fn assume_init(self) -> T;
1604}
1605
1606/// Helper trait that describes what is expected from a `SetSockOpt` setter.
1607// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1608#[doc(hidden)]
1609pub trait Set<'a, T> {
1610    /// Initialize the setter with a given value.
1611    fn new(val: &'a T) -> Self;
1612    /// Returns a pointer to the stored value. This pointer will be passed to the system's
1613    /// `setsockopt` call (`man 3p setsockopt`, argument `option_value`).
1614    fn ffi_ptr(&self) -> *const c_void;
1615    /// Returns length of the stored value. This pointer will be passed to the system's
1616    /// `setsockopt` call (`man 3p setsockopt`, argument `option_len`).
1617    fn ffi_len(&self) -> socklen_t;
1618}
1619
1620/// Getter for an arbitrary `struct`.
1621// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1622#[doc(hidden)]
1623#[derive(Debug)]
1624pub struct GetStruct<T> {
1625    len: socklen_t,
1626    val: MaybeUninit<T>,
1627}
1628
1629impl<T> Get<T> for GetStruct<T> {
1630    fn uninit() -> Self {
1631        GetStruct {
1632            len: mem::size_of::<T>() as socklen_t,
1633            val: MaybeUninit::uninit(),
1634        }
1635    }
1636
1637    fn ffi_ptr(&mut self) -> *mut c_void {
1638        self.val.as_mut_ptr().cast()
1639    }
1640
1641    fn ffi_len(&mut self) -> *mut socklen_t {
1642        &mut self.len
1643    }
1644
1645    unsafe fn assume_init(self) -> T {
1646        assert_eq!(
1647            self.len as usize,
1648            mem::size_of::<T>(),
1649            "invalid getsockopt implementation"
1650        );
1651        unsafe { self.val.assume_init() }
1652    }
1653}
1654
1655/// Setter for an arbitrary `struct`.
1656// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1657#[doc(hidden)]
1658#[derive(Debug)]
1659pub struct SetStruct<'a, T: 'static> {
1660    ptr: &'a T,
1661}
1662
1663impl<'a, T> Set<'a, T> for SetStruct<'a, T> {
1664    fn new(ptr: &'a T) -> SetStruct<'a, T> {
1665        SetStruct { ptr }
1666    }
1667
1668    fn ffi_ptr(&self) -> *const c_void {
1669        self.ptr as *const T as *const c_void
1670    }
1671
1672    fn ffi_len(&self) -> socklen_t {
1673        mem::size_of::<T>() as socklen_t
1674    }
1675}
1676
1677/// Getter for a boolean value.
1678// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1679#[doc(hidden)]
1680#[derive(Clone, Copy, Debug)]
1681pub struct GetBool {
1682    len: socklen_t,
1683    val: MaybeUninit<c_int>,
1684}
1685
1686impl Get<bool> for GetBool {
1687    fn uninit() -> Self {
1688        GetBool {
1689            len: mem::size_of::<c_int>() as socklen_t,
1690            val: MaybeUninit::uninit(),
1691        }
1692    }
1693
1694    fn ffi_ptr(&mut self) -> *mut c_void {
1695        self.val.as_mut_ptr().cast()
1696    }
1697
1698    fn ffi_len(&mut self) -> *mut socklen_t {
1699        &mut self.len
1700    }
1701
1702    unsafe fn assume_init(self) -> bool {
1703        assert_eq!(
1704            self.len as usize,
1705            mem::size_of::<c_int>(),
1706            "invalid getsockopt implementation"
1707        );
1708        unsafe { self.val.assume_init() != 0 }
1709    }
1710}
1711
1712/// Setter for a boolean value.
1713// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1714#[doc(hidden)]
1715#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1716pub struct SetBool {
1717    val: c_int,
1718}
1719
1720impl<'a> Set<'a, bool> for SetBool {
1721    fn new(val: &'a bool) -> SetBool {
1722        SetBool {
1723            val: i32::from(*val),
1724        }
1725    }
1726
1727    fn ffi_ptr(&self) -> *const c_void {
1728        &self.val as *const c_int as *const c_void
1729    }
1730
1731    fn ffi_len(&self) -> socklen_t {
1732        mem::size_of_val(&self.val) as socklen_t
1733    }
1734}
1735
1736/// Getter for an `u8` value.
1737#[cfg(feature = "net")]
1738// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1739#[doc(hidden)]
1740#[derive(Clone, Copy, Debug)]
1741pub struct GetU8 {
1742    len: socklen_t,
1743    val: MaybeUninit<u8>,
1744}
1745
1746#[cfg(feature = "net")]
1747impl Get<u8> for GetU8 {
1748    fn uninit() -> Self {
1749        GetU8 {
1750            len: mem::size_of::<u8>() as socklen_t,
1751            val: MaybeUninit::uninit(),
1752        }
1753    }
1754
1755    fn ffi_ptr(&mut self) -> *mut c_void {
1756        self.val.as_mut_ptr().cast()
1757    }
1758
1759    fn ffi_len(&mut self) -> *mut socklen_t {
1760        &mut self.len
1761    }
1762
1763    unsafe fn assume_init(self) -> u8 {
1764        assert_eq!(
1765            self.len as usize,
1766            mem::size_of::<u8>(),
1767            "invalid getsockopt implementation"
1768        );
1769        unsafe { self.val.assume_init() }
1770    }
1771}
1772
1773/// Setter for an `u8` value.
1774// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1775#[doc(hidden)]
1776#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1777pub struct SetU8 {
1778    val: u8,
1779}
1780
1781#[cfg(feature = "net")]
1782impl<'a> Set<'a, u8> for SetU8 {
1783    fn new(val: &'a u8) -> SetU8 {
1784        SetU8 { val: *val }
1785    }
1786
1787    fn ffi_ptr(&self) -> *const c_void {
1788        &self.val as *const u8 as *const c_void
1789    }
1790
1791    fn ffi_len(&self) -> socklen_t {
1792        mem::size_of_val(&self.val) as socklen_t
1793    }
1794}
1795
1796/// Getter for an `usize` value.
1797// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1798#[doc(hidden)]
1799#[derive(Clone, Copy, Debug)]
1800pub struct GetUsize {
1801    len: socklen_t,
1802    val: MaybeUninit<c_int>,
1803}
1804
1805impl Get<usize> for GetUsize {
1806    fn uninit() -> Self {
1807        GetUsize {
1808            len: mem::size_of::<c_int>() as socklen_t,
1809            val: MaybeUninit::uninit(),
1810        }
1811    }
1812
1813    fn ffi_ptr(&mut self) -> *mut c_void {
1814        self.val.as_mut_ptr().cast()
1815    }
1816
1817    fn ffi_len(&mut self) -> *mut socklen_t {
1818        &mut self.len
1819    }
1820
1821    unsafe fn assume_init(self) -> usize {
1822        assert_eq!(
1823            self.len as usize,
1824            mem::size_of::<c_int>(),
1825            "invalid getsockopt implementation"
1826        );
1827        unsafe { self.val.assume_init() as usize }
1828    }
1829}
1830
1831/// Setter for an `usize` value.
1832// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1833#[doc(hidden)]
1834#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1835pub struct SetUsize {
1836    val: c_int,
1837}
1838
1839impl<'a> Set<'a, usize> for SetUsize {
1840    fn new(val: &'a usize) -> SetUsize {
1841        SetUsize { val: *val as c_int }
1842    }
1843
1844    fn ffi_ptr(&self) -> *const c_void {
1845        &self.val as *const c_int as *const c_void
1846    }
1847
1848    fn ffi_len(&self) -> socklen_t {
1849        mem::size_of_val(&self.val) as socklen_t
1850    }
1851}
1852
1853
1854/// Getter for a `OwnedFd` value.
1855// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1856#[doc(hidden)]
1857#[derive(Clone, Copy, Debug)]
1858pub struct GetOwnedFd {
1859    len: socklen_t,
1860    val: MaybeUninit<c_int>,
1861}
1862
1863impl Get<OwnedFd> for GetOwnedFd {
1864    fn uninit() -> Self {
1865        GetOwnedFd {
1866            len: mem::size_of::<c_int>() as socklen_t,
1867            val: MaybeUninit::uninit(),
1868        }
1869    }
1870
1871    fn ffi_ptr(&mut self) -> *mut c_void {
1872        self.val.as_mut_ptr().cast()
1873    }
1874
1875    fn ffi_len(&mut self) -> *mut socklen_t {
1876        &mut self.len
1877    }
1878
1879    unsafe fn assume_init(self) -> OwnedFd {
1880        use std::os::fd::{FromRawFd, RawFd};
1881
1882        assert_eq!(
1883            self.len as usize,
1884            mem::size_of::<c_int>(),
1885            "invalid getsockopt implementation"
1886        );
1887        unsafe { OwnedFd::from_raw_fd(self.val.assume_init() as RawFd) }
1888    }
1889}
1890
1891/// Setter for an `OwnedFd` value.
1892// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1893#[doc(hidden)]
1894#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1895pub struct SetOwnedFd {
1896    val: c_int,
1897}
1898
1899impl<'a> Set<'a, OwnedFd> for SetOwnedFd {
1900    fn new(val: &'a OwnedFd) -> SetOwnedFd {
1901        use std::os::fd::AsRawFd;
1902
1903        SetOwnedFd { val: val.as_raw_fd() as c_int }
1904    }
1905
1906    fn ffi_ptr(&self) -> *const c_void {
1907        &self.val as *const c_int as *const c_void
1908    }
1909
1910    fn ffi_len(&self) -> socklen_t {
1911        mem::size_of_val(&self.val) as socklen_t
1912    }
1913}
1914
1915/// Getter for a `OsString` value.
1916// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1917#[doc(hidden)]
1918#[derive(Debug)]
1919pub struct GetOsString<T: AsMut<[u8]>> {
1920    len: socklen_t,
1921    val: MaybeUninit<T>,
1922}
1923
1924impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> {
1925    fn uninit() -> Self {
1926        GetOsString {
1927            len: mem::size_of::<T>() as socklen_t,
1928            val: MaybeUninit::uninit(),
1929        }
1930    }
1931
1932    fn ffi_ptr(&mut self) -> *mut c_void {
1933        self.val.as_mut_ptr().cast()
1934    }
1935
1936    fn ffi_len(&mut self) -> *mut socklen_t {
1937        &mut self.len
1938    }
1939
1940    unsafe fn assume_init(self) -> OsString {
1941        let len = self.len as usize;
1942        let mut v = unsafe { self.val.assume_init() };
1943        if let Ok(cs) = CStr::from_bytes_until_nul(&v.as_mut()[0..len]) {
1944            // It's legal for the kernel to return any number of NULs at the
1945            // end of the string.  C applications don't care, after all.
1946            OsStr::from_bytes(cs.to_bytes())
1947        } else {
1948            // Even zero NULs is possible.
1949            OsStr::from_bytes(&v.as_mut()[0..len])
1950        }
1951        .to_owned()
1952    }
1953}
1954
1955/// Setter for a `OsString` value.
1956// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1957#[doc(hidden)]
1958#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1959pub struct SetOsString<'a> {
1960    val: &'a OsStr,
1961}
1962
1963#[cfg(any(target_os = "freebsd", linux_android, target_os = "illumos"))]
1964impl<'a> Set<'a, OsString> for SetOsString<'a> {
1965    fn new(val: &OsString) -> SetOsString<'_> {
1966        SetOsString {
1967            val: val.as_os_str(),
1968        }
1969    }
1970
1971    fn ffi_ptr(&self) -> *const c_void {
1972        self.val.as_bytes().as_ptr().cast()
1973    }
1974
1975    fn ffi_len(&self) -> socklen_t {
1976        self.val.len() as socklen_t
1977    }
1978}
1979
1980/// Getter for a `CString` value.
1981#[cfg(apple_targets)]
1982#[cfg(feature = "net")]
1983struct GetCString<T: AsMut<[u8]>> {
1984    len: socklen_t,
1985    val: MaybeUninit<T>,
1986}
1987
1988#[cfg(apple_targets)]
1989#[cfg(feature = "net")]
1990impl<T: AsMut<[u8]>> Get<CString> for GetCString<T> {
1991    fn uninit() -> Self {
1992        GetCString {
1993            len: mem::size_of::<T>() as socklen_t,
1994            val: MaybeUninit::uninit(),
1995        }
1996    }
1997
1998    fn ffi_ptr(&mut self) -> *mut c_void {
1999        self.val.as_mut_ptr().cast()
2000    }
2001
2002    fn ffi_len(&mut self) -> *mut socklen_t {
2003        &mut self.len
2004    }
2005
2006    unsafe fn assume_init(self) -> CString {
2007        let mut v = unsafe { self.val.assume_init() };
2008        CStr::from_bytes_until_nul(v.as_mut())
2009            .expect("string should be null-terminated")
2010            .to_owned()
2011    }
2012}