nix/sys/socket/
sockopt.rs

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