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")]
566sockopt_impl!(
567    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
568    /// If enabled, the kernel will not reserve an ephemeral port when binding
569    /// socket with a port number of 0. The port will later be automatically
570    /// chosen at connect time, in a way that allows sharing a source port as
571    /// long as the 4-tuple is unique.
572    IpBindAddressNoPort,
573    Both,
574    libc::IPPROTO_IP,
575    libc::IP_BIND_ADDRESS_NO_PORT,
576    bool
577);
578sockopt_impl!(
579    /// Specify the receiving timeout until reporting an error.
580    ReceiveTimeout,
581    Both,
582    libc::SOL_SOCKET,
583    libc::SO_RCVTIMEO,
584    TimeVal
585);
586sockopt_impl!(
587    /// Specify the sending timeout until reporting an error.
588    SendTimeout,
589    Both,
590    libc::SOL_SOCKET,
591    libc::SO_SNDTIMEO,
592    TimeVal
593);
594sockopt_impl!(
595    /// Set or get the broadcast flag.
596    Broadcast,
597    Both,
598    libc::SOL_SOCKET,
599    libc::SO_BROADCAST,
600    bool
601);
602sockopt_impl!(
603    /// If this option is enabled, out-of-band data is directly placed into
604    /// the receive data stream.
605    OobInline,
606    Both,
607    libc::SOL_SOCKET,
608    libc::SO_OOBINLINE,
609    bool
610);
611sockopt_impl!(
612    /// Get and clear the pending socket error.
613    SocketError,
614    GetOnly,
615    libc::SOL_SOCKET,
616    libc::SO_ERROR,
617    i32
618);
619sockopt_impl!(
620    /// Set or get the don't route flag.
621    DontRoute,
622    Both,
623    libc::SOL_SOCKET,
624    libc::SO_DONTROUTE,
625    bool
626);
627sockopt_impl!(
628    /// Enable sending of keep-alive messages on connection-oriented sockets.
629    KeepAlive,
630    Both,
631    libc::SOL_SOCKET,
632    libc::SO_KEEPALIVE,
633    bool
634);
635#[cfg(freebsdlike)]
636sockopt_impl!(
637    /// Get the credentials of the peer process of a connected unix domain
638    /// socket.
639    LocalPeerCred,
640    GetOnly,
641    0,
642    libc::LOCAL_PEERCRED,
643    super::XuCred
644);
645#[cfg(apple_targets)]
646sockopt_impl!(
647    /// Get the credentials of the peer process of a connected unix domain
648    /// socket.
649    LocalPeerCred,
650    GetOnly,
651    libc::SOL_LOCAL,
652    libc::LOCAL_PEERCRED,
653    super::XuCred
654);
655#[cfg(apple_targets)]
656sockopt_impl!(
657    /// Get the PID of the peer process of a connected unix domain socket.
658    LocalPeerPid,
659    GetOnly,
660    libc::SOL_LOCAL,
661    libc::LOCAL_PEERPID,
662    libc::c_int
663);
664#[cfg(apple_targets)]
665sockopt_impl!(
666    /// Get the audit token of the peer process of a connected unix domain
667    /// socket.
668    LocalPeerToken,
669    GetOnly,
670    libc::SOL_LOCAL,
671    libc::LOCAL_PEERTOKEN,
672    super::audit_token_t
673);
674#[cfg(linux_android)]
675sockopt_impl!(
676    /// Return the credentials of the foreign process connected to this socket.
677    PeerCredentials,
678    GetOnly,
679    libc::SOL_SOCKET,
680    libc::SO_PEERCRED,
681    super::UnixCredentials
682);
683#[cfg(target_os = "linux")]
684sockopt_impl!(
685    /// Return the pidfd of the foreign process connected to this socket.
686    PeerPidfd,
687    GetOnly,
688    libc::SOL_SOCKET,
689    libc::SO_PEERPIDFD,
690    OwnedFd
691);
692#[cfg(target_os = "freebsd")]
693#[cfg(feature = "net")]
694sockopt_impl!(
695    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
696    /// Get backlog limit of the socket
697    ListenQLimit,
698    GetOnly,
699    libc::SOL_SOCKET,
700    libc::SO_LISTENQLIMIT,
701    u32
702);
703#[cfg(apple_targets)]
704#[cfg(feature = "net")]
705sockopt_impl!(
706    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
707    /// Specify the amount of time, in seconds, that the connection must be idle
708    /// before keepalive probes (if enabled) are sent.
709    TcpKeepAlive,
710    Both,
711    libc::IPPROTO_TCP,
712    libc::TCP_KEEPALIVE,
713    u32
714);
715#[cfg(any(freebsdlike, linux_android))]
716#[cfg(feature = "net")]
717sockopt_impl!(
718    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
719    /// The time (in seconds) the connection needs to remain idle before TCP
720    /// starts sending keepalive probes
721    TcpKeepIdle,
722    Both,
723    libc::IPPROTO_TCP,
724    libc::TCP_KEEPIDLE,
725    u32
726);
727cfg_if! {
728    if #[cfg(any(linux_android, apple_targets))] {
729        sockopt_impl!(
730            /// The maximum segment size for outgoing TCP packets.
731            TcpMaxSeg, Both, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32);
732    } else if #[cfg(not(target_os = "redox"))] {
733        sockopt_impl!(
734            /// The maximum segment size for outgoing TCP packets.
735            TcpMaxSeg, GetOnly, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32);
736    }
737}
738#[cfg(not(any(
739    target_os = "openbsd",
740    target_os = "haiku",
741    target_os = "redox"
742)))]
743#[cfg(feature = "net")]
744sockopt_impl!(
745    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
746    /// The maximum number of keepalive probes TCP should send before
747    /// dropping the connection.
748    TcpKeepCount,
749    Both,
750    libc::IPPROTO_TCP,
751    libc::TCP_KEEPCNT,
752    u32
753);
754#[cfg(any(linux_android, target_os = "fuchsia"))]
755sockopt_impl!(
756    #[allow(missing_docs)]
757    // Not documented by Linux!
758    TcpRepair,
759    Both,
760    libc::IPPROTO_TCP,
761    libc::TCP_REPAIR,
762    u32
763);
764#[cfg(not(any(
765    target_os = "openbsd",
766    target_os = "haiku",
767    target_os = "redox"
768)))]
769#[cfg(feature = "net")]
770sockopt_impl!(
771    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
772    /// The time (in seconds) between individual keepalive probes.
773    TcpKeepInterval,
774    Both,
775    libc::IPPROTO_TCP,
776    libc::TCP_KEEPINTVL,
777    u32
778);
779#[cfg(any(target_os = "fuchsia", target_os = "linux"))]
780#[cfg(feature = "net")]
781sockopt_impl!(
782    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
783    /// Specifies the maximum amount of time in milliseconds that transmitted
784    /// data may remain unacknowledged before TCP will forcibly close the
785    /// corresponding connection
786    TcpUserTimeout,
787    Both,
788    libc::IPPROTO_TCP,
789    libc::TCP_USER_TIMEOUT,
790    u32
791);
792#[cfg(linux_android)]
793#[cfg(feature = "net")]
794sockopt_impl!(
795    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
796    /// Enables TCP Fast Open (RFC 7413) on a connecting socket. If a fast open
797    /// cookie is not available (first attempt to connect), `connect` syscall
798    /// will behave as usual, except for internally trying to solicit a cookie
799    /// from remote peer. When cookie is available, the next `connect` syscall
800    /// will immediately succeed without actually establishing TCP connection.
801    /// The connection establishment will be defered till the next `write` or
802    /// `sendmsg` syscalls on the socket, allowing TCP prtocol to establish
803    /// connection and send data in the same packets. Note: calling `read` right
804    /// after `connect` without `write` on the socket will cause the blocking
805    /// socket to be blocked forever.
806    TcpFastOpenConnect,
807    Both,
808    libc::IPPROTO_TCP,
809    libc::TCP_FASTOPEN_CONNECT,
810    bool
811);
812sockopt_impl!(
813    /// Sets or gets the maximum socket receive buffer in bytes.
814    RcvBuf,
815    Both,
816    libc::SOL_SOCKET,
817    libc::SO_RCVBUF,
818    usize
819);
820sockopt_impl!(
821    /// Sets or gets the maximum socket send buffer in bytes.
822    SndBuf,
823    Both,
824    libc::SOL_SOCKET,
825    libc::SO_SNDBUF,
826    usize
827);
828#[cfg(linux_android)]
829sockopt_impl!(
830    /// Using this socket option, a privileged (`CAP_NET_ADMIN`) process can
831    /// perform the same task as `SO_RCVBUF`, but the `rmem_max limit` can be
832    /// overridden.
833    RcvBufForce,
834    SetOnly,
835    libc::SOL_SOCKET,
836    libc::SO_RCVBUFFORCE,
837    usize
838);
839#[cfg(linux_android)]
840sockopt_impl!(
841    /// Using this socket option, a privileged (`CAP_NET_ADMIN`)  process can
842    /// perform the same task as `SO_SNDBUF`, but the `wmem_max` limit can be
843    /// overridden.
844    SndBufForce,
845    SetOnly,
846    libc::SOL_SOCKET,
847    libc::SO_SNDBUFFORCE,
848    usize
849);
850sockopt_impl!(
851    /// Gets the socket type as an integer.
852    SockType,
853    GetOnly,
854    libc::SOL_SOCKET,
855    libc::SO_TYPE,
856    super::SockType,
857    GetStruct<i32>
858);
859sockopt_impl!(
860    /// Returns a value indicating whether or not this socket has been marked to
861    /// accept connections with `listen(2)`.
862    AcceptConn,
863    GetOnly,
864    libc::SOL_SOCKET,
865    libc::SO_ACCEPTCONN,
866    bool
867);
868#[cfg(linux_android)]
869sockopt_impl!(
870    /// Bind this socket to a particular device like “eth0”.
871    BindToDevice,
872    Both,
873    libc::SOL_SOCKET,
874    libc::SO_BINDTODEVICE,
875    OsString<[u8; libc::IFNAMSIZ]>
876);
877#[cfg(linux_android)]
878#[cfg(feature = "net")]
879sockopt_impl!(
880    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
881    #[allow(missing_docs)]
882    // Not documented by Linux!
883    OriginalDst,
884    GetOnly,
885    libc::SOL_IP,
886    libc::SO_ORIGINAL_DST,
887    libc::sockaddr_in
888);
889#[cfg(linux_android)]
890sockopt_impl!(
891    #[allow(missing_docs)]
892    // Not documented by Linux!
893    Ip6tOriginalDst,
894    GetOnly,
895    libc::SOL_IPV6,
896    libc::IP6T_SO_ORIGINAL_DST,
897    libc::sockaddr_in6
898);
899#[cfg(linux_android)]
900sockopt_impl!(
901    /// Specifies exact type of timestamping information collected by the kernel
902    /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html)
903    Timestamping,
904    Both,
905    libc::SOL_SOCKET,
906    libc::SO_TIMESTAMPING,
907    super::TimestampingFlag
908);
909#[cfg(not(any(
910    target_os = "aix",
911    target_os = "haiku",
912    target_os = "hurd",
913    target_os = "redox",
914    target_os = "cygwin"
915)))]
916sockopt_impl!(
917    /// Enable or disable the receiving of the `SO_TIMESTAMP` control message.
918    ReceiveTimestamp,
919    Both,
920    libc::SOL_SOCKET,
921    libc::SO_TIMESTAMP,
922    bool
923);
924#[cfg(linux_android)]
925sockopt_impl!(
926    /// Enable or disable the receiving of the `SO_TIMESTAMPNS` control message.
927    ReceiveTimestampns,
928    Both,
929    libc::SOL_SOCKET,
930    libc::SO_TIMESTAMPNS,
931    bool
932);
933#[cfg(target_os = "freebsd")]
934sockopt_impl!(
935    /// Sets a specific timestamp format instead of the classic `SCM_TIMESTAMP`,
936    /// to follow up after `SO_TIMESTAMP` is set.
937    TsClock,
938    Both,
939    libc::SOL_SOCKET,
940    libc::SO_TS_CLOCK,
941    super::SocketTimestamp
942);
943#[cfg(linux_android)]
944#[cfg(feature = "net")]
945sockopt_impl!(
946    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
947    /// Setting this boolean option enables transparent proxying on this socket.
948    IpTransparent,
949    Both,
950    libc::SOL_IP,
951    libc::IP_TRANSPARENT,
952    bool
953);
954#[cfg(target_os = "openbsd")]
955#[cfg(feature = "net")]
956sockopt_impl!(
957    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
958    /// Allows the socket to be bound to addresses which are not local to the
959    /// machine, so it can be used to make a transparent proxy.
960    BindAny,
961    Both,
962    libc::SOL_SOCKET,
963    libc::SO_BINDANY,
964    bool
965);
966#[cfg(target_os = "freebsd")]
967#[cfg(feature = "net")]
968sockopt_impl!(
969    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
970    /// Can `bind(2)` to any address, even one not bound to any available
971    /// network interface in the system.
972    BindAny,
973    Both,
974    libc::IPPROTO_IP,
975    libc::IP_BINDANY,
976    bool
977);
978#[cfg(target_os = "freebsd")]
979sockopt_impl!(
980    /// Set the route table (FIB) for this socket up to the `net.fibs` OID limit
981    /// (more specific than the setfib command line/call which are process based).
982    Fib,
983    SetOnly,
984    libc::SOL_SOCKET,
985    libc::SO_SETFIB,
986    i32
987);
988#[cfg(target_os = "freebsd")]
989sockopt_impl!(
990    /// Set `so_user_cookie` for this socket allowing network traffic based
991    /// upon it, similar to Linux's netfilter MARK.
992    UserCookie,
993    SetOnly,
994    libc::SOL_SOCKET,
995    libc::SO_USER_COOKIE,
996    u32
997);
998#[cfg(target_os = "openbsd")]
999sockopt_impl!(
1000    /// Set the route table for this socket, needs a privileged user if
1001    /// the process/socket had been set to the non default route.
1002    Rtable,
1003    SetOnly,
1004    libc::SOL_SOCKET,
1005    libc::SO_RTABLE,
1006    i32
1007);
1008#[cfg(any(target_os = "freebsd", target_os = "netbsd"))]
1009sockopt_impl!(
1010    /// Get/set a filter on this socket before accepting connections similarly
1011    /// to Linux's TCP_DEFER_ACCEPT but after the listen's call.
1012    AcceptFilter,
1013    Both,
1014    libc::SOL_SOCKET,
1015    libc::SO_ACCEPTFILTER,
1016    libc::accept_filter_arg
1017);
1018#[cfg(target_os = "linux")]
1019sockopt_impl!(
1020    /// Set the mark for each packet sent through this socket (similar to the
1021    /// netfilter MARK target but socket-based).
1022    Mark,
1023    Both,
1024    libc::SOL_SOCKET,
1025    libc::SO_MARK,
1026    u32
1027);
1028#[cfg(linux_android)]
1029sockopt_impl!(
1030    /// Enable or disable the receiving of the `SCM_CREDENTIALS` control
1031    /// message.
1032    PassCred,
1033    Both,
1034    libc::SOL_SOCKET,
1035    libc::SO_PASSCRED,
1036    bool
1037);
1038#[cfg(any(target_os = "freebsd", target_os = "linux"))]
1039#[cfg(feature = "net")]
1040sockopt_impl!(
1041    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1042    /// This option allows the caller to set the TCP congestion control
1043    /// algorithm to be used,  on a per-socket basis.
1044    TcpCongestion,
1045    Both,
1046    libc::IPPROTO_TCP,
1047    libc::TCP_CONGESTION,
1048    OsString<[u8; TCP_CA_NAME_MAX]>
1049);
1050#[cfg(any(linux_android, apple_targets, target_os = "netbsd"))]
1051#[cfg(feature = "net")]
1052sockopt_impl!(
1053    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1054    /// Pass an `IP_PKTINFO` ancillary message that contains a pktinfo
1055    /// structure that supplies some information about the incoming packet.
1056    Ipv4PacketInfo,
1057    Both,
1058    libc::IPPROTO_IP,
1059    libc::IP_PKTINFO,
1060    bool
1061);
1062#[cfg(any(linux_android, bsd))]
1063#[cfg(feature = "net")]
1064sockopt_impl!(
1065    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1066    /// Set delivery of the `IPV6_PKTINFO` control message on incoming
1067    /// datagrams.
1068    Ipv6RecvPacketInfo,
1069    Both,
1070    libc::IPPROTO_IPV6,
1071    libc::IPV6_RECVPKTINFO,
1072    bool
1073);
1074
1075#[cfg(any(linux_android, bsd))]
1076#[cfg(feature = "net")]
1077sockopt_impl!(
1078    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1079    /// Pass an `IPV6_PKTINFO` ancillary message that contains a in6_pktinfo
1080    /// structure that supplies some information about the incoming packet.
1081    Ipv6PacketInfo,
1082    Both,
1083    libc::IPPROTO_IPV6,
1084    libc::IPV6_PKTINFO,
1085    bool
1086);
1087#[cfg(bsd)]
1088#[cfg(feature = "net")]
1089sockopt_impl!(
1090    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1091    /// The `recvmsg(2)` call returns a `struct sockaddr_dl` corresponding to
1092    /// the interface on which the packet was received.
1093    Ipv4RecvIf,
1094    Both,
1095    libc::IPPROTO_IP,
1096    libc::IP_RECVIF,
1097    bool
1098);
1099#[cfg(bsd)]
1100#[cfg(feature = "net")]
1101sockopt_impl!(
1102    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1103    /// The `recvmsg(2)` call will return the destination IP address for a UDP
1104    /// datagram.
1105    Ipv4RecvDstAddr,
1106    Both,
1107    libc::IPPROTO_IP,
1108    libc::IP_RECVDSTADDR,
1109    bool
1110);
1111#[cfg(any(linux_android, target_os = "freebsd"))]
1112#[cfg(feature = "net")]
1113sockopt_impl!(
1114    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1115    /// The `recvmsg(2)` call will return the destination IP address for a UDP
1116    /// datagram.
1117    Ipv4OrigDstAddr,
1118    Both,
1119    libc::IPPROTO_IP,
1120    libc::IP_ORIGDSTADDR,
1121    bool
1122);
1123#[cfg(target_os = "linux")]
1124#[cfg(feature = "net")]
1125sockopt_impl!(
1126    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1127    #[allow(missing_docs)]
1128    // Not documented by Linux!
1129    UdpGsoSegment,
1130    Both,
1131    libc::SOL_UDP,
1132    libc::UDP_SEGMENT,
1133    libc::c_int
1134);
1135#[cfg(target_os = "linux")]
1136#[cfg(feature = "net")]
1137sockopt_impl!(
1138    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1139    #[allow(missing_docs)]
1140    // Not documented by Linux!
1141    UdpGroSegment,
1142    Both,
1143    libc::IPPROTO_UDP,
1144    libc::UDP_GRO,
1145    bool
1146);
1147#[cfg(target_os = "linux")]
1148sockopt_impl!(
1149    /// Configures the behavior of time-based transmission of packets, for use
1150    /// with the `TxTime` control message.
1151    TxTime,
1152    Both,
1153    libc::SOL_SOCKET,
1154    libc::SO_TXTIME,
1155    libc::sock_txtime
1156);
1157#[cfg(any(linux_android, target_os = "fuchsia"))]
1158sockopt_impl!(
1159    /// Indicates that an unsigned 32-bit value ancillary message (cmsg) should
1160    /// be attached to received skbs indicating the number of packets dropped by
1161    /// the socket since its creation.
1162    RxqOvfl,
1163    Both,
1164    libc::SOL_SOCKET,
1165    libc::SO_RXQ_OVFL,
1166    libc::c_int
1167);
1168#[cfg(feature = "net")]
1169sockopt_impl!(
1170    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1171    /// The socket is restricted to sending and receiving IPv6 packets only.
1172    Ipv6V6Only,
1173    Both,
1174    libc::IPPROTO_IPV6,
1175    libc::IPV6_V6ONLY,
1176    bool
1177);
1178#[cfg(linux_android)]
1179sockopt_impl!(
1180    /// Enable extended reliable error message passing.
1181    Ipv4RecvErr,
1182    Both,
1183    libc::IPPROTO_IP,
1184    libc::IP_RECVERR,
1185    bool
1186);
1187#[cfg(linux_android)]
1188sockopt_impl!(
1189    /// Control receiving of asynchronous error options.
1190    Ipv6RecvErr,
1191    Both,
1192    libc::IPPROTO_IPV6,
1193    libc::IPV6_RECVERR,
1194    bool
1195);
1196#[cfg(linux_android)]
1197sockopt_impl!(
1198    /// Fetch the current system-estimated Path MTU.
1199    IpMtu,
1200    GetOnly,
1201    libc::IPPROTO_IP,
1202    libc::IP_MTU,
1203    libc::c_int
1204);
1205#[cfg(any(linux_android, target_os = "freebsd"))]
1206sockopt_impl!(
1207    /// Set or retrieve the current time-to-live field that is used in every
1208    /// packet sent from this socket.
1209    Ipv4Ttl,
1210    Both,
1211    libc::IPPROTO_IP,
1212    libc::IP_TTL,
1213    libc::c_int
1214);
1215#[cfg(any(linux_android, target_os = "freebsd"))]
1216#[cfg(feature = "net")]
1217sockopt_impl!(
1218    /// Enables a receiving socket to retrieve the Time-to-Live (TTL) field 
1219    /// from incoming IPv4 packets.
1220    Ipv4RecvTtl,
1221    Both,
1222    libc::IPPROTO_IP,
1223    libc::IP_RECVTTL,
1224    bool
1225);
1226#[cfg(any(apple_targets, linux_android, target_os = "freebsd"))]
1227sockopt_impl!(
1228    /// Set the unicast hop limit for the socket.
1229    Ipv6Ttl,
1230    Both,
1231    libc::IPPROTO_IPV6,
1232    libc::IPV6_UNICAST_HOPS,
1233    libc::c_int
1234);
1235#[cfg(any(linux_android, target_os = "freebsd"))]
1236#[cfg(feature = "net")]
1237sockopt_impl!(
1238    /// Enables a receiving socket to retrieve the Hop Limit field 
1239    /// (similar to TTL in IPv4) from incoming IPv6 packets.
1240    Ipv6RecvHopLimit,
1241    Both,
1242    libc::IPPROTO_IPV6,
1243    libc::IPV6_RECVHOPLIMIT,
1244    bool
1245);
1246#[cfg(any(linux_android, target_os = "freebsd"))]
1247#[cfg(feature = "net")]
1248sockopt_impl!(
1249    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1250    /// The `recvmsg(2)` call will return the destination IP address for a UDP
1251    /// datagram.
1252    Ipv6OrigDstAddr,
1253    Both,
1254    libc::IPPROTO_IPV6,
1255    libc::IPV6_ORIGDSTADDR,
1256    bool
1257);
1258#[cfg(apple_targets)]
1259sockopt_impl!(
1260    /// Set "don't fragment packet" flag on the IP packet.
1261    IpDontFrag,
1262    Both,
1263    libc::IPPROTO_IP,
1264    libc::IP_DONTFRAG,
1265    bool
1266);
1267#[cfg(any(linux_android, apple_targets))]
1268sockopt_impl!(
1269    /// Set "don't fragment packet" flag on the IPv6 packet.
1270    Ipv6DontFrag,
1271    Both,
1272    libc::IPPROTO_IPV6,
1273    libc::IPV6_DONTFRAG,
1274    bool
1275);
1276#[cfg(apple_targets)]
1277#[cfg(feature = "net")]
1278sockopt_impl!(
1279    /// Get the utun interface name.
1280    UtunIfname,
1281    GetOnly,
1282    libc::SYSPROTO_CONTROL,
1283    libc::UTUN_OPT_IFNAME,
1284    CString,
1285    GetCString<[u8; libc::IFNAMSIZ]>
1286);
1287
1288#[cfg(solarish)]
1289sockopt_impl!(
1290    /// Enable/disable exclusive binding.
1291    /// Prevent multiple sockets to bind to the same
1292    /// address:port, neutralizing `SO_REUSEADDR` effect.
1293    ExclBind,
1294    Both,
1295    libc::SOL_SOCKET,
1296    libc::SO_EXCLBIND,
1297    bool
1298);
1299#[cfg(target_os = "linux")]
1300sockopt_impl!(
1301    /// To be used with `ReusePort`,
1302    /// we can then attach a BPF (classic)
1303    /// to set how the packets are assigned
1304    /// to the socket (e.g. cpu distribution).
1305    AttachReusePortCbpf,
1306    SetOnly,
1307    libc::SOL_SOCKET,
1308    libc::SO_ATTACH_REUSEPORT_CBPF,
1309    libc::sock_fprog
1310);
1311
1312#[allow(missing_docs)]
1313// Not documented by Linux!
1314#[cfg(linux_android)]
1315#[derive(Copy, Clone, Debug)]
1316pub struct AlgSetAeadAuthSize;
1317
1318// ALG_SET_AEAD_AUTH_SIZE read the length from passed `option_len`
1319// See https://elixir.bootlin.com/linux/v4.4/source/crypto/af_alg.c#L222
1320#[cfg(linux_android)]
1321impl SetSockOpt for AlgSetAeadAuthSize {
1322    type Val = usize;
1323
1324    fn set<F: AsFd>(&self, fd: &F, val: &usize) -> Result<()> {
1325        unsafe {
1326            let res = libc::setsockopt(
1327                fd.as_fd().as_raw_fd(),
1328                libc::SOL_ALG,
1329                libc::ALG_SET_AEAD_AUTHSIZE,
1330                ::std::ptr::null(),
1331                *val as libc::socklen_t,
1332            );
1333            Errno::result(res).map(drop)
1334        }
1335    }
1336}
1337
1338#[allow(missing_docs)]
1339// Not documented by Linux!
1340#[cfg(linux_android)]
1341#[derive(Clone, Debug)]
1342pub struct AlgSetKey<T>(::std::marker::PhantomData<T>);
1343
1344#[cfg(linux_android)]
1345impl<T> Default for AlgSetKey<T> {
1346    fn default() -> Self {
1347        AlgSetKey(Default::default())
1348    }
1349}
1350
1351#[cfg(linux_android)]
1352impl<T> SetSockOpt for AlgSetKey<T>
1353where
1354    T: AsRef<[u8]> + Clone,
1355{
1356    type Val = T;
1357
1358    fn set<F: AsFd>(&self, fd: &F, val: &T) -> Result<()> {
1359        unsafe {
1360            let res = libc::setsockopt(
1361                fd.as_fd().as_raw_fd(),
1362                libc::SOL_ALG,
1363                libc::ALG_SET_KEY,
1364                val.as_ref().as_ptr().cast(),
1365                val.as_ref().len() as libc::socklen_t,
1366            );
1367            Errno::result(res).map(drop)
1368        }
1369    }
1370}
1371
1372/// Set the Upper Layer Protocol (ULP) on the TCP socket.
1373///
1374/// For example, to enable the TLS ULP on a socket, the C function call would be:
1375///
1376/// ```c
1377/// setsockopt(sock, SOL_TCP, TCP_ULP, "tls", sizeof("tls"));
1378/// ```
1379///
1380/// ... and the `nix` equivalent is:
1381///
1382/// ```ignore,rust
1383/// setsockopt(sock, TcpUlp::default(), b"tls");
1384/// ```
1385///
1386/// Note that the ULP name does not need a trailing NUL terminator (`\0`).
1387#[cfg(linux_android)]
1388#[derive(Clone, Debug)]
1389pub struct TcpUlp<T>(::std::marker::PhantomData<T>);
1390
1391#[cfg(linux_android)]
1392impl<T> Default for TcpUlp<T> {
1393    fn default() -> Self {
1394        TcpUlp(Default::default())
1395    }
1396}
1397
1398#[cfg(linux_android)]
1399impl<T> SetSockOpt for TcpUlp<T>
1400where
1401    T: AsRef<[u8]> + Clone,
1402{
1403    type Val = T;
1404
1405    fn set<F: AsFd>(&self, fd: &F, val: &Self::Val) -> Result<()> {
1406        unsafe {
1407            let res = libc::setsockopt(
1408                fd.as_fd().as_raw_fd(),
1409                libc::SOL_TCP,
1410                libc::TCP_ULP,
1411                val.as_ref().as_ptr().cast(),
1412                val.as_ref().len() as libc::socklen_t,
1413            );
1414            Errno::result(res).map(drop)
1415        }
1416    }
1417}
1418
1419/// Value used with the [`TcpTlsTx`] and [`TcpTlsRx`] socket options.
1420#[cfg(target_os = "linux")]
1421#[derive(Copy, Clone, Debug)]
1422pub enum TlsCryptoInfo {
1423    /// AES-128-GCM
1424    Aes128Gcm(libc::tls12_crypto_info_aes_gcm_128),
1425
1426    /// AES-256-GCM
1427    Aes256Gcm(libc::tls12_crypto_info_aes_gcm_256),
1428
1429    /// CHACHA20-POLY1305
1430    Chacha20Poly1305(libc::tls12_crypto_info_chacha20_poly1305),
1431}
1432
1433/// Set the Kernel TLS write parameters on the TCP socket.
1434///
1435/// For example, the C function call would be:
1436///
1437/// ```c
1438/// setsockopt(sock, SOL_TLS, TLS_TX, &crypto_info, sizeof(crypto_info));
1439/// ```
1440///
1441/// ... and the `nix` equivalent is:
1442///
1443/// ```ignore,rust
1444/// setsockopt(sock, TcpTlsTx, &crypto_info);
1445/// ```
1446#[cfg(target_os = "linux")]
1447#[derive(Copy, Clone, Debug)]
1448pub struct TcpTlsTx;
1449
1450#[cfg(target_os = "linux")]
1451impl SetSockOpt for TcpTlsTx {
1452    type Val = TlsCryptoInfo;
1453
1454    fn set<F: AsFd>(&self, fd: &F, val: &Self::Val) -> Result<()> {
1455        let (ffi_ptr, ffi_len) = match val {
1456            TlsCryptoInfo::Aes128Gcm(crypto_info) => {
1457                (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
1458            }
1459            TlsCryptoInfo::Aes256Gcm(crypto_info) => {
1460                (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
1461            }
1462            TlsCryptoInfo::Chacha20Poly1305(crypto_info) => {
1463                (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
1464            }
1465        };
1466        unsafe {
1467            let res = libc::setsockopt(
1468                fd.as_fd().as_raw_fd(),
1469                libc::SOL_TLS,
1470                libc::TLS_TX,
1471                ffi_ptr,
1472                ffi_len as libc::socklen_t,
1473            );
1474            Errno::result(res).map(drop)
1475        }
1476    }
1477}
1478
1479/// Set the Kernel TLS read parameters on the TCP socket.
1480///
1481/// For example, the C function call would be:
1482///
1483/// ```c
1484/// setsockopt(sock, SOL_TLS, TLS_RX, &crypto_info, sizeof(crypto_info));
1485/// ```
1486///
1487/// ... and the `nix` equivalent is:
1488///
1489/// ```ignore,rust
1490/// setsockopt(sock, TcpTlsRx, &crypto_info);
1491/// ```
1492#[cfg(target_os = "linux")]
1493#[derive(Copy, Clone, Debug)]
1494pub struct TcpTlsRx;
1495
1496#[cfg(target_os = "linux")]
1497impl SetSockOpt for TcpTlsRx {
1498    type Val = TlsCryptoInfo;
1499
1500    fn set<F: AsFd>(&self, fd: &F, val: &Self::Val) -> Result<()> {
1501        let (ffi_ptr, ffi_len) = match val {
1502            TlsCryptoInfo::Aes128Gcm(crypto_info) => {
1503                (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
1504            }
1505            TlsCryptoInfo::Aes256Gcm(crypto_info) => {
1506                (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
1507            }
1508            TlsCryptoInfo::Chacha20Poly1305(crypto_info) => {
1509                (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
1510            }
1511        };
1512        unsafe {
1513            let res = libc::setsockopt(
1514                fd.as_fd().as_raw_fd(),
1515                libc::SOL_TLS,
1516                libc::TLS_RX,
1517                ffi_ptr,
1518                ffi_len as libc::socklen_t,
1519            );
1520            Errno::result(res).map(drop)
1521        }
1522    }
1523}
1524
1525#[cfg(target_os = "illumos")]
1526#[derive(Copy, Clone, Debug)]
1527/// Attach a named filter to this socket to be able to
1528/// defer when anough byte had been buffered by the kernel
1529pub struct FilterAttach;
1530
1531#[cfg(target_os = "illumos")]
1532impl SetSockOpt for FilterAttach {
1533    type Val = OsStr;
1534
1535    fn set<F: AsFd>(&self, fd: &F, val: &Self::Val) -> Result<()> {
1536        if val.len() > libc::FILNAME_MAX as usize {
1537            return Err(Errno::EINVAL);
1538        }
1539        unsafe {
1540            let res = libc::setsockopt(
1541                fd.as_fd().as_raw_fd(),
1542                libc::SOL_FILTER,
1543                libc::FIL_ATTACH,
1544                val.as_bytes().as_ptr().cast(),
1545                val.len() as libc::socklen_t,
1546            );
1547            Errno::result(res).map(drop)
1548        }
1549    }
1550}
1551
1552#[cfg(target_os = "illumos")]
1553#[derive(Copy, Clone, Debug)]
1554/// Detach a socket filter previously attached with FIL_ATTACH
1555pub struct FilterDetach;
1556
1557#[cfg(target_os = "illumos")]
1558impl SetSockOpt for FilterDetach {
1559    type Val = OsStr;
1560
1561    fn set<F: AsFd>(&self, fd: &F, val: &Self::Val) -> Result<()> {
1562        if val.len() > libc::FILNAME_MAX as usize {
1563            return Err(Errno::EINVAL);
1564        }
1565        unsafe {
1566            let res = libc::setsockopt(
1567                fd.as_fd().as_raw_fd(),
1568                libc::SOL_FILTER,
1569                libc::FIL_DETACH,
1570                val.as_bytes().as_ptr().cast(),
1571                val.len() as libc::socklen_t,
1572            );
1573            Errno::result(res).map(drop)
1574        }
1575    }
1576}
1577/*
1578 *
1579 * ===== Accessor helpers =====
1580 *
1581 */
1582
1583/// Helper trait that describes what is expected from a `GetSockOpt` getter.
1584// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1585#[doc(hidden)]
1586pub trait Get<T> {
1587    /// Returns an uninitialized value.
1588    fn uninit() -> Self;
1589    /// Returns a pointer to the stored value. This pointer will be passed to the system's
1590    /// `getsockopt` call (`man 3p getsockopt`, argument `option_value`).
1591    fn ffi_ptr(&mut self) -> *mut c_void;
1592    /// Returns length of the stored value. This pointer will be passed to the system's
1593    /// `getsockopt` call (`man 3p getsockopt`, argument `option_len`).
1594    fn ffi_len(&mut self) -> *mut socklen_t;
1595    /// Returns the hopefully initialized inner value.
1596    unsafe fn assume_init(self) -> T;
1597}
1598
1599/// Helper trait that describes what is expected from a `SetSockOpt` setter.
1600// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1601#[doc(hidden)]
1602pub trait Set<'a, T> {
1603    /// Initialize the setter with a given value.
1604    fn new(val: &'a T) -> Self;
1605    /// Returns a pointer to the stored value. This pointer will be passed to the system's
1606    /// `setsockopt` call (`man 3p setsockopt`, argument `option_value`).
1607    fn ffi_ptr(&self) -> *const c_void;
1608    /// Returns length of the stored value. This pointer will be passed to the system's
1609    /// `setsockopt` call (`man 3p setsockopt`, argument `option_len`).
1610    fn ffi_len(&self) -> socklen_t;
1611}
1612
1613/// Getter for an arbitrary `struct`.
1614// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1615#[doc(hidden)]
1616#[derive(Debug)]
1617pub struct GetStruct<T> {
1618    len: socklen_t,
1619    val: MaybeUninit<T>,
1620}
1621
1622impl<T> Get<T> for GetStruct<T> {
1623    fn uninit() -> Self {
1624        GetStruct {
1625            len: mem::size_of::<T>() as socklen_t,
1626            val: MaybeUninit::uninit(),
1627        }
1628    }
1629
1630    fn ffi_ptr(&mut self) -> *mut c_void {
1631        self.val.as_mut_ptr().cast()
1632    }
1633
1634    fn ffi_len(&mut self) -> *mut socklen_t {
1635        &mut self.len
1636    }
1637
1638    unsafe fn assume_init(self) -> T {
1639        assert_eq!(
1640            self.len as usize,
1641            mem::size_of::<T>(),
1642            "invalid getsockopt implementation"
1643        );
1644        unsafe { self.val.assume_init() }
1645    }
1646}
1647
1648/// Setter for an arbitrary `struct`.
1649// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1650#[doc(hidden)]
1651#[derive(Debug)]
1652pub struct SetStruct<'a, T: 'static> {
1653    ptr: &'a T,
1654}
1655
1656impl<'a, T> Set<'a, T> for SetStruct<'a, T> {
1657    fn new(ptr: &'a T) -> SetStruct<'a, T> {
1658        SetStruct { ptr }
1659    }
1660
1661    fn ffi_ptr(&self) -> *const c_void {
1662        self.ptr as *const T as *const c_void
1663    }
1664
1665    fn ffi_len(&self) -> socklen_t {
1666        mem::size_of::<T>() as socklen_t
1667    }
1668}
1669
1670/// Getter for a boolean value.
1671// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1672#[doc(hidden)]
1673#[derive(Clone, Copy, Debug)]
1674pub struct GetBool {
1675    len: socklen_t,
1676    val: MaybeUninit<c_int>,
1677}
1678
1679impl Get<bool> for GetBool {
1680    fn uninit() -> Self {
1681        GetBool {
1682            len: mem::size_of::<c_int>() as socklen_t,
1683            val: MaybeUninit::uninit(),
1684        }
1685    }
1686
1687    fn ffi_ptr(&mut self) -> *mut c_void {
1688        self.val.as_mut_ptr().cast()
1689    }
1690
1691    fn ffi_len(&mut self) -> *mut socklen_t {
1692        &mut self.len
1693    }
1694
1695    unsafe fn assume_init(self) -> bool {
1696        assert_eq!(
1697            self.len as usize,
1698            mem::size_of::<c_int>(),
1699            "invalid getsockopt implementation"
1700        );
1701        unsafe { self.val.assume_init() != 0 }
1702    }
1703}
1704
1705/// Setter for a boolean value.
1706// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1707#[doc(hidden)]
1708#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1709pub struct SetBool {
1710    val: c_int,
1711}
1712
1713impl<'a> Set<'a, bool> for SetBool {
1714    fn new(val: &'a bool) -> SetBool {
1715        SetBool {
1716            val: i32::from(*val),
1717        }
1718    }
1719
1720    fn ffi_ptr(&self) -> *const c_void {
1721        &self.val as *const c_int as *const c_void
1722    }
1723
1724    fn ffi_len(&self) -> socklen_t {
1725        mem::size_of_val(&self.val) as socklen_t
1726    }
1727}
1728
1729/// Getter for an `u8` value.
1730#[cfg(feature = "net")]
1731// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1732#[doc(hidden)]
1733#[derive(Clone, Copy, Debug)]
1734pub struct GetU8 {
1735    len: socklen_t,
1736    val: MaybeUninit<u8>,
1737}
1738
1739#[cfg(feature = "net")]
1740impl Get<u8> for GetU8 {
1741    fn uninit() -> Self {
1742        GetU8 {
1743            len: mem::size_of::<u8>() as socklen_t,
1744            val: MaybeUninit::uninit(),
1745        }
1746    }
1747
1748    fn ffi_ptr(&mut self) -> *mut c_void {
1749        self.val.as_mut_ptr().cast()
1750    }
1751
1752    fn ffi_len(&mut self) -> *mut socklen_t {
1753        &mut self.len
1754    }
1755
1756    unsafe fn assume_init(self) -> u8 {
1757        assert_eq!(
1758            self.len as usize,
1759            mem::size_of::<u8>(),
1760            "invalid getsockopt implementation"
1761        );
1762        unsafe { self.val.assume_init() }
1763    }
1764}
1765
1766/// Setter for an `u8` value.
1767// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1768#[doc(hidden)]
1769#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1770pub struct SetU8 {
1771    val: u8,
1772}
1773
1774#[cfg(feature = "net")]
1775impl<'a> Set<'a, u8> for SetU8 {
1776    fn new(val: &'a u8) -> SetU8 {
1777        SetU8 { val: *val }
1778    }
1779
1780    fn ffi_ptr(&self) -> *const c_void {
1781        &self.val as *const u8 as *const c_void
1782    }
1783
1784    fn ffi_len(&self) -> socklen_t {
1785        mem::size_of_val(&self.val) as socklen_t
1786    }
1787}
1788
1789/// Getter for an `usize` value.
1790// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1791#[doc(hidden)]
1792#[derive(Clone, Copy, Debug)]
1793pub struct GetUsize {
1794    len: socklen_t,
1795    val: MaybeUninit<c_int>,
1796}
1797
1798impl Get<usize> for GetUsize {
1799    fn uninit() -> Self {
1800        GetUsize {
1801            len: mem::size_of::<c_int>() as socklen_t,
1802            val: MaybeUninit::uninit(),
1803        }
1804    }
1805
1806    fn ffi_ptr(&mut self) -> *mut c_void {
1807        self.val.as_mut_ptr().cast()
1808    }
1809
1810    fn ffi_len(&mut self) -> *mut socklen_t {
1811        &mut self.len
1812    }
1813
1814    unsafe fn assume_init(self) -> usize {
1815        assert_eq!(
1816            self.len as usize,
1817            mem::size_of::<c_int>(),
1818            "invalid getsockopt implementation"
1819        );
1820        unsafe { self.val.assume_init() as usize }
1821    }
1822}
1823
1824/// Setter for an `usize` value.
1825// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1826#[doc(hidden)]
1827#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1828pub struct SetUsize {
1829    val: c_int,
1830}
1831
1832impl<'a> Set<'a, usize> for SetUsize {
1833    fn new(val: &'a usize) -> SetUsize {
1834        SetUsize { val: *val as c_int }
1835    }
1836
1837    fn ffi_ptr(&self) -> *const c_void {
1838        &self.val as *const c_int as *const c_void
1839    }
1840
1841    fn ffi_len(&self) -> socklen_t {
1842        mem::size_of_val(&self.val) as socklen_t
1843    }
1844}
1845
1846
1847/// Getter for a `OwnedFd` value.
1848// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1849#[doc(hidden)]
1850#[derive(Clone, Copy, Debug)]
1851pub struct GetOwnedFd {
1852    len: socklen_t,
1853    val: MaybeUninit<c_int>,
1854}
1855
1856impl Get<OwnedFd> for GetOwnedFd {
1857    fn uninit() -> Self {
1858        GetOwnedFd {
1859            len: mem::size_of::<c_int>() as socklen_t,
1860            val: MaybeUninit::uninit(),
1861        }
1862    }
1863
1864    fn ffi_ptr(&mut self) -> *mut c_void {
1865        self.val.as_mut_ptr().cast()
1866    }
1867
1868    fn ffi_len(&mut self) -> *mut socklen_t {
1869        &mut self.len
1870    }
1871
1872    unsafe fn assume_init(self) -> OwnedFd {
1873        use std::os::fd::{FromRawFd, RawFd};
1874
1875        assert_eq!(
1876            self.len as usize,
1877            mem::size_of::<c_int>(),
1878            "invalid getsockopt implementation"
1879        );
1880        unsafe { OwnedFd::from_raw_fd(self.val.assume_init() as RawFd) }
1881    }
1882}
1883
1884/// Setter for an `OwnedFd` value.
1885// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1886#[doc(hidden)]
1887#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1888pub struct SetOwnedFd {
1889    val: c_int,
1890}
1891
1892impl<'a> Set<'a, OwnedFd> for SetOwnedFd {
1893    fn new(val: &'a OwnedFd) -> SetOwnedFd {
1894        use std::os::fd::AsRawFd;
1895
1896        SetOwnedFd { val: val.as_raw_fd() as c_int }
1897    }
1898
1899    fn ffi_ptr(&self) -> *const c_void {
1900        &self.val as *const c_int as *const c_void
1901    }
1902
1903    fn ffi_len(&self) -> socklen_t {
1904        mem::size_of_val(&self.val) as socklen_t
1905    }
1906}
1907
1908/// Getter for a `OsString` value.
1909// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1910#[doc(hidden)]
1911#[derive(Debug)]
1912pub struct GetOsString<T: AsMut<[u8]>> {
1913    len: socklen_t,
1914    val: MaybeUninit<T>,
1915}
1916
1917impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> {
1918    fn uninit() -> Self {
1919        GetOsString {
1920            len: mem::size_of::<T>() as socklen_t,
1921            val: MaybeUninit::uninit(),
1922        }
1923    }
1924
1925    fn ffi_ptr(&mut self) -> *mut c_void {
1926        self.val.as_mut_ptr().cast()
1927    }
1928
1929    fn ffi_len(&mut self) -> *mut socklen_t {
1930        &mut self.len
1931    }
1932
1933    unsafe fn assume_init(self) -> OsString {
1934        let len = self.len as usize;
1935        let mut v = unsafe { self.val.assume_init() };
1936        if let Ok(cs) = CStr::from_bytes_until_nul(&v.as_mut()[0..len]) {
1937            // It's legal for the kernel to return any number of NULs at the
1938            // end of the string.  C applications don't care, after all.
1939            OsStr::from_bytes(cs.to_bytes())
1940        } else {
1941            // Even zero NULs is possible.
1942            OsStr::from_bytes(&v.as_mut()[0..len])
1943        }
1944        .to_owned()
1945    }
1946}
1947
1948/// Setter for a `OsString` value.
1949// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1950#[doc(hidden)]
1951#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1952pub struct SetOsString<'a> {
1953    val: &'a OsStr,
1954}
1955
1956#[cfg(any(target_os = "freebsd", linux_android, target_os = "illumos"))]
1957impl<'a> Set<'a, OsString> for SetOsString<'a> {
1958    fn new(val: &OsString) -> SetOsString {
1959        SetOsString {
1960            val: val.as_os_str(),
1961        }
1962    }
1963
1964    fn ffi_ptr(&self) -> *const c_void {
1965        self.val.as_bytes().as_ptr().cast()
1966    }
1967
1968    fn ffi_len(&self) -> socklen_t {
1969        self.val.len() as socklen_t
1970    }
1971}
1972
1973/// Getter for a `CString` value.
1974#[cfg(apple_targets)]
1975struct GetCString<T: AsMut<[u8]>> {
1976    len: socklen_t,
1977    val: MaybeUninit<T>,
1978}
1979
1980#[cfg(apple_targets)]
1981impl<T: AsMut<[u8]>> Get<CString> for GetCString<T> {
1982    fn uninit() -> Self {
1983        GetCString {
1984            len: mem::size_of::<T>() as socklen_t,
1985            val: MaybeUninit::uninit(),
1986        }
1987    }
1988
1989    fn ffi_ptr(&mut self) -> *mut c_void {
1990        self.val.as_mut_ptr().cast()
1991    }
1992
1993    fn ffi_len(&mut self) -> *mut socklen_t {
1994        &mut self.len
1995    }
1996
1997    unsafe fn assume_init(self) -> CString {
1998        let mut v = unsafe { self.val.assume_init() };
1999        CStr::from_bytes_until_nul(v.as_mut())
2000            .expect("string should be null-terminated")
2001            .to_owned()
2002    }
2003}