• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Socket options as used by `setsockopt` and `getsockopt`.
2 use super::{GetSockOpt, SetSockOpt};
3 use crate::errno::Errno;
4 use crate::sys::time::TimeVal;
5 use crate::Result;
6 use cfg_if::cfg_if;
7 use libc::{self, c_int, c_void, socklen_t};
8 use std::ffi::{OsStr, OsString};
9 use std::{
10     convert::TryFrom,
11     mem::{self, MaybeUninit}
12 };
13 #[cfg(target_family = "unix")]
14 use std::os::unix::ffi::OsStrExt;
15 use 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")]
21 const 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.).
45 macro_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.).
90 macro_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)]
146 macro_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 
260 sockopt_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")))]
269 sockopt_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")]
279 sockopt_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 );
294 sockopt_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")]
305 sockopt_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")]
315 sockopt_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 );
324 cfg_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")]
359 sockopt_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")]
370 sockopt_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")]
382 sockopt_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")]
394 sockopt_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")]
406 sockopt_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")]
417 sockopt_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 );
427 sockopt_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 );
435 sockopt_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 );
443 sockopt_impl!(
444     /// Set or get the broadcast flag.
445     Broadcast,
446     Both,
447     libc::SOL_SOCKET,
448     libc::SO_BROADCAST,
449     bool
450 );
451 sockopt_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 );
460 sockopt_impl!(
461     /// Get and clear the pending socket error.
462     SocketError,
463     GetOnly,
464     libc::SOL_SOCKET,
465     libc::SO_ERROR,
466     i32
467 );
468 sockopt_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 );
476 sockopt_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 ))]
490 sockopt_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"))]
500 sockopt_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")]
510 sockopt_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")]
527 sockopt_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 );
537 cfg_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")]
550 sockopt_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"))]
561 sockopt_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")]
572 sockopt_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")]
583 sockopt_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 );
594 sockopt_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 );
602 sockopt_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"))]
611 sockopt_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"))]
622 sockopt_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 );
632 sockopt_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 );
641 sockopt_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"))]
651 sockopt_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")]
661 sockopt_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"))]
672 sockopt_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"))]
682 sockopt_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"))]
692 sockopt_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"))]
701 sockopt_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")]
711 sockopt_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")]
722 sockopt_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")]
734 sockopt_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")]
745 sockopt_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"))]
755 sockopt_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")]
766 sockopt_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")]
784 sockopt_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")]
804 sockopt_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")]
822 sockopt_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")]
840 sockopt_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")]
852 sockopt_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")]
864 sockopt_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")]
876 sockopt_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")]
887 sockopt_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"))]
897 sockopt_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")]
908 sockopt_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"))]
918 sockopt_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"))]
927 sockopt_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"))]
936 sockopt_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"))]
945 sockopt_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"))]
955 sockopt_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")]
965 sockopt_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"))]
976 sockopt_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 ))]
990 sockopt_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)]
1003 pub 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"))]
1008 impl SetSockOpt for AlgSetAeadAuthSize {
1009     type Val = usize;
1010 
set(&self, fd: RawFd, val: &usize) -> Result<()>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)]
1029 pub struct AlgSetKey<T>(::std::marker::PhantomData<T>);
1030 
1031 #[cfg(any(target_os = "android", target_os = "linux"))]
1032 impl<T> Default for AlgSetKey<T> {
default() -> Self1033     fn default() -> Self {
1034         AlgSetKey(Default::default())
1035     }
1036 }
1037 
1038 #[cfg(any(target_os = "android", target_os = "linux"))]
1039 impl<T> SetSockOpt for AlgSetKey<T>
1040 where
1041     T: AsRef<[u8]> + Clone,
1042 {
1043     type Val = T;
1044 
set(&self, fd: RawFd, val: &T) -> Result<()>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.
1066 trait Get<T> {
1067     /// Returns an uninitialized value.
uninit() -> Self1068     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`).
ffi_ptr(&mut self) -> *mut c_void1071     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`).
ffi_len(&mut self) -> *mut socklen_t1074     fn ffi_len(&mut self) -> *mut socklen_t;
1075     /// Returns the hopefully initialized inner value.
assume_init(self) -> T1076     unsafe fn assume_init(self) -> T;
1077 }
1078 
1079 /// Helper trait that describes what is expected from a `SetSockOpt` setter.
1080 trait Set<'a, T> {
1081     /// Initialize the setter with a given value.
new(val: &'a T) -> Self1082     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`).
ffi_ptr(&self) -> *const c_void1085     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`).
ffi_len(&self) -> socklen_t1088     fn ffi_len(&self) -> socklen_t;
1089 }
1090 
1091 /// Getter for an arbitrary `struct`.
1092 struct GetStruct<T> {
1093     len: socklen_t,
1094     val: MaybeUninit<T>,
1095 }
1096 
1097 impl<T> Get<T> for GetStruct<T> {
uninit() -> Self1098     fn uninit() -> Self {
1099         GetStruct {
1100             len: mem::size_of::<T>() as socklen_t,
1101             val: MaybeUninit::uninit(),
1102         }
1103     }
1104 
ffi_ptr(&mut self) -> *mut c_void1105     fn ffi_ptr(&mut self) -> *mut c_void {
1106         self.val.as_mut_ptr() as *mut c_void
1107     }
1108 
ffi_len(&mut self) -> *mut socklen_t1109     fn ffi_len(&mut self) -> *mut socklen_t {
1110         &mut self.len
1111     }
1112 
assume_init(self) -> T1113     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`.
1124 struct SetStruct<'a, T: 'static> {
1125     ptr: &'a T,
1126 }
1127 
1128 impl<'a, T> Set<'a, T> for SetStruct<'a, T> {
new(ptr: &'a T) -> SetStruct<'a, T>1129     fn new(ptr: &'a T) -> SetStruct<'a, T> {
1130         SetStruct { ptr }
1131     }
1132 
ffi_ptr(&self) -> *const c_void1133     fn ffi_ptr(&self) -> *const c_void {
1134         self.ptr as *const T as *const c_void
1135     }
1136 
ffi_len(&self) -> socklen_t1137     fn ffi_len(&self) -> socklen_t {
1138         mem::size_of::<T>() as socklen_t
1139     }
1140 }
1141 
1142 /// Getter for a boolean value.
1143 struct GetBool {
1144     len: socklen_t,
1145     val: MaybeUninit<c_int>,
1146 }
1147 
1148 impl Get<bool> for GetBool {
uninit() -> Self1149     fn uninit() -> Self {
1150         GetBool {
1151             len: mem::size_of::<c_int>() as socklen_t,
1152             val: MaybeUninit::uninit(),
1153         }
1154     }
1155 
ffi_ptr(&mut self) -> *mut c_void1156     fn ffi_ptr(&mut self) -> *mut c_void {
1157         self.val.as_mut_ptr() as *mut c_void
1158     }
1159 
ffi_len(&mut self) -> *mut socklen_t1160     fn ffi_len(&mut self) -> *mut socklen_t {
1161         &mut self.len
1162     }
1163 
assume_init(self) -> bool1164     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.
1175 struct SetBool {
1176     val: c_int,
1177 }
1178 
1179 impl<'a> Set<'a, bool> for SetBool {
new(val: &'a bool) -> SetBool1180     fn new(val: &'a bool) -> SetBool {
1181         SetBool {
1182             val: i32::from(*val),
1183         }
1184     }
1185 
ffi_ptr(&self) -> *const c_void1186     fn ffi_ptr(&self) -> *const c_void {
1187         &self.val as *const c_int as *const c_void
1188     }
1189 
ffi_len(&self) -> socklen_t1190     fn ffi_len(&self) -> socklen_t {
1191         mem::size_of::<c_int>() as socklen_t
1192     }
1193 }
1194 
1195 /// Getter for an `u8` value.
1196 struct GetU8 {
1197     len: socklen_t,
1198     val: MaybeUninit<u8>,
1199 }
1200 
1201 impl Get<u8> for GetU8 {
uninit() -> Self1202     fn uninit() -> Self {
1203         GetU8 {
1204             len: mem::size_of::<u8>() as socklen_t,
1205             val: MaybeUninit::uninit(),
1206         }
1207     }
1208 
ffi_ptr(&mut self) -> *mut c_void1209     fn ffi_ptr(&mut self) -> *mut c_void {
1210         self.val.as_mut_ptr() as *mut c_void
1211     }
1212 
ffi_len(&mut self) -> *mut socklen_t1213     fn ffi_len(&mut self) -> *mut socklen_t {
1214         &mut self.len
1215     }
1216 
assume_init(self) -> u81217     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.
1228 struct SetU8 {
1229     val: u8,
1230 }
1231 
1232 impl<'a> Set<'a, u8> for SetU8 {
new(val: &'a u8) -> SetU81233     fn new(val: &'a u8) -> SetU8 {
1234         SetU8 { val: *val }
1235     }
1236 
ffi_ptr(&self) -> *const c_void1237     fn ffi_ptr(&self) -> *const c_void {
1238         &self.val as *const u8 as *const c_void
1239     }
1240 
ffi_len(&self) -> socklen_t1241     fn ffi_len(&self) -> socklen_t {
1242         mem::size_of::<c_int>() as socklen_t
1243     }
1244 }
1245 
1246 /// Getter for an `usize` value.
1247 struct GetUsize {
1248     len: socklen_t,
1249     val: MaybeUninit<c_int>,
1250 }
1251 
1252 impl Get<usize> for GetUsize {
uninit() -> Self1253     fn uninit() -> Self {
1254         GetUsize {
1255             len: mem::size_of::<c_int>() as socklen_t,
1256             val: MaybeUninit::uninit(),
1257         }
1258     }
1259 
ffi_ptr(&mut self) -> *mut c_void1260     fn ffi_ptr(&mut self) -> *mut c_void {
1261         self.val.as_mut_ptr() as *mut c_void
1262     }
1263 
ffi_len(&mut self) -> *mut socklen_t1264     fn ffi_len(&mut self) -> *mut socklen_t {
1265         &mut self.len
1266     }
1267 
assume_init(self) -> usize1268     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.
1279 struct SetUsize {
1280     val: c_int,
1281 }
1282 
1283 impl<'a> Set<'a, usize> for SetUsize {
new(val: &'a usize) -> SetUsize1284     fn new(val: &'a usize) -> SetUsize {
1285         SetUsize { val: *val as c_int }
1286     }
1287 
ffi_ptr(&self) -> *const c_void1288     fn ffi_ptr(&self) -> *const c_void {
1289         &self.val as *const c_int as *const c_void
1290     }
1291 
ffi_len(&self) -> socklen_t1292     fn ffi_len(&self) -> socklen_t {
1293         mem::size_of::<c_int>() as socklen_t
1294     }
1295 }
1296 
1297 /// Getter for a `OsString` value.
1298 struct GetOsString<T: AsMut<[u8]>> {
1299     len: socklen_t,
1300     val: MaybeUninit<T>,
1301 }
1302 
1303 impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> {
uninit() -> Self1304     fn uninit() -> Self {
1305         GetOsString {
1306             len: mem::size_of::<T>() as socklen_t,
1307             val: MaybeUninit::uninit(),
1308         }
1309     }
1310 
ffi_ptr(&mut self) -> *mut c_void1311     fn ffi_ptr(&mut self) -> *mut c_void {
1312         self.val.as_mut_ptr() as *mut c_void
1313     }
1314 
ffi_len(&mut self) -> *mut socklen_t1315     fn ffi_len(&mut self) -> *mut socklen_t {
1316         &mut self.len
1317     }
1318 
assume_init(self) -> OsString1319     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.
1327 struct SetOsString<'a> {
1328     val: &'a OsStr,
1329 }
1330 
1331 impl<'a> Set<'a, OsString> for SetOsString<'a> {
new(val: &'a OsString) -> SetOsString1332     fn new(val: &'a OsString) -> SetOsString {
1333         SetOsString {
1334             val: val.as_os_str(),
1335         }
1336     }
1337 
ffi_ptr(&self) -> *const c_void1338     fn ffi_ptr(&self) -> *const c_void {
1339         self.val.as_bytes().as_ptr() as *const c_void
1340     }
1341 
ffi_len(&self) -> socklen_t1342     fn ffi_len(&self) -> socklen_t {
1343         self.val.len() as socklen_t
1344     }
1345 }
1346 
1347 #[cfg(test)]
1348 mod test {
1349     #[cfg(any(target_os = "android", target_os = "linux"))]
1350     #[test]
can_get_peercred_on_unix_socket()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]
is_socket_type_unix()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]
is_socket_type_dgram()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]
can_get_listen_on_tcp_socket()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 }
1423