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