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