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