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