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