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