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