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