1 // Copyright 2015 The Rust Project Developers. 2 // 3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or 4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license 5 // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your 6 // option. This file may not be copied, modified, or distributed 7 // except according to those terms. 8 9 //! Utilities for creating and using sockets. 10 //! 11 //! The goal of this crate is to create and use a socket using advanced 12 //! configuration options (those that are not available in the types in the 13 //! standard library) without using any unsafe code. 14 //! 15 //! This crate provides as direct as possible access to the system's 16 //! functionality for sockets, this means little effort to provide 17 //! cross-platform utilities. It is up to the user to know how to use sockets 18 //! when using this crate. *If you don't know how to create a socket using 19 //! libc/system calls then this crate is not for you*. Most, if not all, 20 //! functions directly relate to the equivalent system call with no error 21 //! handling applied, so no handling errors such as [`EINTR`]. As a result using 22 //! this crate can be a little wordy, but it should give you maximal flexibility 23 //! over configuration of sockets. 24 //! 25 //! [`EINTR`]: std::io::ErrorKind::Interrupted 26 //! 27 //! # Examples 28 //! 29 //! ```no_run 30 //! # fn main() -> std::io::Result<()> { 31 //! use std::net::{SocketAddr, TcpListener}; 32 //! use socket2::{Socket, Domain, Type}; 33 //! 34 //! // Create a TCP listener bound to two addresses. 35 //! let socket = Socket::new(Domain::IPV6, Type::STREAM, None)?; 36 //! 37 //! socket.set_only_v6(false)?; 38 //! let address: SocketAddr = "[::1]:12345".parse().unwrap(); 39 //! socket.bind(&address.into())?; 40 //! socket.listen(128)?; 41 //! 42 //! let listener: TcpListener = socket.into(); 43 //! // ... 44 //! # drop(listener); 45 //! # Ok(()) } 46 //! ``` 47 //! 48 //! ## Features 49 //! 50 //! This crate has a single feature `all`, which enables all functions even ones 51 //! that are not available on all OSs. 52 53 #![deny(missing_docs, missing_debug_implementations, rust_2018_idioms)] 54 // Show required OS/features on docs.rs. 55 #![cfg_attr(docsrs, feature(doc_cfg))] 56 // Disallow warnings when running tests. 57 #![cfg_attr(test, deny(warnings))] 58 // Disallow warnings in examples. 59 #![doc(test(attr(deny(warnings))))] 60 61 use std::fmt; 62 #[cfg(not(target_os = "redox"))] 63 use std::io::IoSlice; 64 #[cfg(not(target_os = "redox"))] 65 use std::marker::PhantomData; 66 #[cfg(not(target_os = "redox"))] 67 use std::mem; 68 use std::mem::MaybeUninit; 69 use std::net::SocketAddr; 70 use std::ops::{Deref, DerefMut}; 71 use std::time::Duration; 72 73 /// Macro to implement `fmt::Debug` for a type, printing the constant names 74 /// rather than a number. 75 /// 76 /// Note this is used in the `sys` module and thus must be defined before 77 /// defining the modules. 78 macro_rules! impl_debug { 79 ( 80 // Type name for which to implement `fmt::Debug`. 81 $type: path, 82 $( 83 $(#[$target: meta])* 84 // The flag(s) to check. 85 // Need to specific the libc crate because Windows doesn't use 86 // `libc` but `windows_sys`. 87 $libc: ident :: $flag: ident 88 ),+ $(,)* 89 ) => { 90 impl std::fmt::Debug for $type { 91 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 92 let string = match self.0 { 93 $( 94 $(#[$target])* 95 $libc :: $flag => stringify!($flag), 96 )+ 97 n => return write!(f, "{n}"), 98 }; 99 f.write_str(string) 100 } 101 } 102 }; 103 } 104 105 /// Macro to convert from one network type to another. 106 macro_rules! from { 107 ($from: ty, $for: ty) => { 108 impl From<$from> for $for { 109 fn from(socket: $from) -> $for { 110 #[cfg(unix)] 111 unsafe { 112 <$for>::from_raw_fd(socket.into_raw_fd()) 113 } 114 #[cfg(windows)] 115 unsafe { 116 <$for>::from_raw_socket(socket.into_raw_socket()) 117 } 118 } 119 } 120 }; 121 } 122 123 /// Link to online documentation for (almost) all supported OSs. 124 #[rustfmt::skip] 125 macro_rules! man_links { 126 // Links to all OSs. 127 ($syscall: tt ( $section: tt ) ) => { 128 concat!( 129 man_links!(__ intro), 130 man_links!(__ unix $syscall($section)), 131 man_links!(__ windows $syscall($section)), 132 ) 133 }; 134 // Links to Unix-like OSs. 135 (unix: $syscall: tt ( $section: tt ) ) => { 136 concat!( 137 man_links!(__ intro), 138 man_links!(__ unix $syscall($section)), 139 ) 140 }; 141 // Links to Windows only. 142 (windows: $syscall: tt ( $section: tt ) ) => { 143 concat!( 144 man_links!(__ intro), 145 man_links!(__ windows $syscall($section)), 146 ) 147 }; 148 // Internals. 149 (__ intro) => { 150 "\n\nAdditional documentation can be found in manual of the OS:\n\n" 151 }; 152 // List for Unix-like OSs. 153 (__ unix $syscall: tt ( $section: tt ) ) => { 154 concat!( 155 " * DragonFly BSD: <https://man.dragonflybsd.org/?command=", stringify!($syscall), "§ion=", stringify!($section), ">\n", 156 " * FreeBSD: <https://www.freebsd.org/cgi/man.cgi?query=", stringify!($syscall), "&sektion=", stringify!($section), ">\n", 157 " * Linux: <https://man7.org/linux/man-pages/man", stringify!($section), "/", stringify!($syscall), ".", stringify!($section), ".html>\n", 158 " * macOS: <https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/", stringify!($syscall), ".", stringify!($section), ".html> (archived, actually for iOS)\n", 159 " * NetBSD: <https://man.netbsd.org/", stringify!($syscall), ".", stringify!($section), ">\n", 160 " * OpenBSD: <https://man.openbsd.org/", stringify!($syscall), ".", stringify!($section), ">\n", 161 " * iOS: <https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/", stringify!($syscall), ".", stringify!($section), ".html> (archived)\n", 162 " * illumos: <https://illumos.org/man/3SOCKET/", stringify!($syscall), ">\n", 163 ) 164 }; 165 // List for Window (so just Windows). 166 (__ windows $syscall: tt ( $section: tt ) ) => { 167 concat!( 168 " * Windows: <https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-", stringify!($syscall), ">\n", 169 ) 170 }; 171 } 172 173 mod sockaddr; 174 mod socket; 175 mod sockref; 176 177 #[cfg_attr(unix, path = "sys/unix.rs")] 178 #[cfg_attr(windows, path = "sys/windows.rs")] 179 mod sys; 180 181 #[cfg(not(any(windows, unix)))] 182 compile_error!("Socket2 doesn't support the compile target"); 183 184 use sys::c_int; 185 186 pub use sockaddr::SockAddr; 187 pub use socket::Socket; 188 pub use sockref::SockRef; 189 190 #[cfg(not(any( 191 target_os = "haiku", 192 target_os = "illumos", 193 target_os = "netbsd", 194 target_os = "redox", 195 target_os = "solaris", 196 )))] 197 pub use socket::InterfaceIndexOrAddress; 198 199 /// Specification of the communication domain for a socket. 200 /// 201 /// This is a newtype wrapper around an integer which provides a nicer API in 202 /// addition to an injection point for documentation. Convenience constants such 203 /// as [`Domain::IPV4`], [`Domain::IPV6`], etc, are provided to avoid reaching 204 /// into libc for various constants. 205 /// 206 /// This type is freely interconvertible with C's `int` type, however, if a raw 207 /// value needs to be provided. 208 #[derive(Copy, Clone, Eq, PartialEq)] 209 pub struct Domain(c_int); 210 211 impl Domain { 212 /// Domain for IPv4 communication, corresponding to `AF_INET`. 213 pub const IPV4: Domain = Domain(sys::AF_INET); 214 215 /// Domain for IPv6 communication, corresponding to `AF_INET6`. 216 pub const IPV6: Domain = Domain(sys::AF_INET6); 217 218 /// Domain for Unix socket communication, corresponding to `AF_UNIX`. 219 pub const UNIX: Domain = Domain(sys::AF_UNIX); 220 221 /// Returns the correct domain for `address`. for_address(address: SocketAddr) -> Domain222 pub const fn for_address(address: SocketAddr) -> Domain { 223 match address { 224 SocketAddr::V4(_) => Domain::IPV4, 225 SocketAddr::V6(_) => Domain::IPV6, 226 } 227 } 228 } 229 230 impl From<c_int> for Domain { from(d: c_int) -> Domain231 fn from(d: c_int) -> Domain { 232 Domain(d) 233 } 234 } 235 236 impl From<Domain> for c_int { from(d: Domain) -> c_int237 fn from(d: Domain) -> c_int { 238 d.0 239 } 240 } 241 242 /// Specification of communication semantics on a socket. 243 /// 244 /// This is a newtype wrapper around an integer which provides a nicer API in 245 /// addition to an injection point for documentation. Convenience constants such 246 /// as [`Type::STREAM`], [`Type::DGRAM`], etc, are provided to avoid reaching 247 /// into libc for various constants. 248 /// 249 /// This type is freely interconvertible with C's `int` type, however, if a raw 250 /// value needs to be provided. 251 #[derive(Copy, Clone, Eq, PartialEq)] 252 pub struct Type(c_int); 253 254 impl Type { 255 /// Type corresponding to `SOCK_STREAM`. 256 /// 257 /// Used for protocols such as TCP. 258 pub const STREAM: Type = Type(sys::SOCK_STREAM); 259 260 /// Type corresponding to `SOCK_DGRAM`. 261 /// 262 /// Used for protocols such as UDP. 263 pub const DGRAM: Type = Type(sys::SOCK_DGRAM); 264 265 /// Type corresponding to `SOCK_DCCP`. 266 /// 267 /// Used for the DCCP protocol. 268 #[cfg(all(feature = "all", target_os = "linux"))] 269 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] 270 pub const DCCP: Type = Type(sys::SOCK_DCCP); 271 272 /// Type corresponding to `SOCK_SEQPACKET`. 273 #[cfg(all(feature = "all", not(target_os = "espidf")))] 274 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", not(target_os = "espidf")))))] 275 pub const SEQPACKET: Type = Type(sys::SOCK_SEQPACKET); 276 277 /// Type corresponding to `SOCK_RAW`. 278 #[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))] 279 #[cfg_attr( 280 docsrs, 281 doc(cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))) 282 )] 283 pub const RAW: Type = Type(sys::SOCK_RAW); 284 } 285 286 impl From<c_int> for Type { from(t: c_int) -> Type287 fn from(t: c_int) -> Type { 288 Type(t) 289 } 290 } 291 292 impl From<Type> for c_int { from(t: Type) -> c_int293 fn from(t: Type) -> c_int { 294 t.0 295 } 296 } 297 298 /// Protocol specification used for creating sockets via `Socket::new`. 299 /// 300 /// This is a newtype wrapper around an integer which provides a nicer API in 301 /// addition to an injection point for documentation. 302 /// 303 /// This type is freely interconvertible with C's `int` type, however, if a raw 304 /// value needs to be provided. 305 #[derive(Copy, Clone, Eq, PartialEq)] 306 pub struct Protocol(c_int); 307 308 impl Protocol { 309 /// Protocol corresponding to `ICMPv4`. 310 pub const ICMPV4: Protocol = Protocol(sys::IPPROTO_ICMP); 311 312 /// Protocol corresponding to `ICMPv6`. 313 pub const ICMPV6: Protocol = Protocol(sys::IPPROTO_ICMPV6); 314 315 /// Protocol corresponding to `TCP`. 316 pub const TCP: Protocol = Protocol(sys::IPPROTO_TCP); 317 318 /// Protocol corresponding to `UDP`. 319 pub const UDP: Protocol = Protocol(sys::IPPROTO_UDP); 320 321 #[cfg(target_os = "linux")] 322 /// Protocol corresponding to `MPTCP`. 323 pub const MPTCP: Protocol = Protocol(sys::IPPROTO_MPTCP); 324 325 /// Protocol corresponding to `DCCP`. 326 #[cfg(all(feature = "all", target_os = "linux"))] 327 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] 328 pub const DCCP: Protocol = Protocol(sys::IPPROTO_DCCP); 329 330 /// Protocol corresponding to `SCTP`. 331 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))] 332 pub const SCTP: Protocol = Protocol(sys::IPPROTO_SCTP); 333 334 /// Protocol corresponding to `UDPLITE`. 335 #[cfg(all( 336 feature = "all", 337 any( 338 target_os = "android", 339 target_os = "freebsd", 340 target_os = "fuchsia", 341 target_os = "linux", 342 ) 343 ))] 344 pub const UDPLITE: Protocol = Protocol(sys::IPPROTO_UDPLITE); 345 346 /// Protocol corresponding to `DIVERT`. 347 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "openbsd")))] 348 pub const DIVERT: Protocol = Protocol(sys::IPPROTO_DIVERT); 349 } 350 351 impl From<c_int> for Protocol { from(p: c_int) -> Protocol352 fn from(p: c_int) -> Protocol { 353 Protocol(p) 354 } 355 } 356 357 impl From<Protocol> for c_int { from(p: Protocol) -> c_int358 fn from(p: Protocol) -> c_int { 359 p.0 360 } 361 } 362 363 /// Flags for incoming messages. 364 /// 365 /// Flags provide additional information about incoming messages. 366 #[cfg(not(target_os = "redox"))] 367 #[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))] 368 #[derive(Copy, Clone, Eq, PartialEq)] 369 pub struct RecvFlags(c_int); 370 371 #[cfg(not(target_os = "redox"))] 372 impl RecvFlags { 373 /// Check if the message contains a truncated datagram. 374 /// 375 /// This flag is only used for datagram-based sockets, 376 /// not for stream sockets. 377 /// 378 /// On Unix this corresponds to the `MSG_TRUNC` flag. 379 /// On Windows this corresponds to the `WSAEMSGSIZE` error code. 380 #[cfg(not(target_os = "espidf"))] is_truncated(self) -> bool381 pub const fn is_truncated(self) -> bool { 382 self.0 & sys::MSG_TRUNC != 0 383 } 384 } 385 386 /// A version of [`IoSliceMut`] that allows the buffer to be uninitialised. 387 /// 388 /// [`IoSliceMut`]: std::io::IoSliceMut 389 #[repr(transparent)] 390 pub struct MaybeUninitSlice<'a>(sys::MaybeUninitSlice<'a>); 391 392 impl<'a> fmt::Debug for MaybeUninitSlice<'a> { fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result393 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 394 fmt::Debug::fmt(self.0.as_slice(), fmt) 395 } 396 } 397 398 impl<'a> MaybeUninitSlice<'a> { 399 /// Creates a new `MaybeUninitSlice` wrapping a byte slice. 400 /// 401 /// # Panics 402 /// 403 /// Panics on Windows if the slice is larger than 4GB. new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a>404 pub fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> { 405 MaybeUninitSlice(sys::MaybeUninitSlice::new(buf)) 406 } 407 } 408 409 impl<'a> Deref for MaybeUninitSlice<'a> { 410 type Target = [MaybeUninit<u8>]; 411 deref(&self) -> &[MaybeUninit<u8>]412 fn deref(&self) -> &[MaybeUninit<u8>] { 413 self.0.as_slice() 414 } 415 } 416 417 impl<'a> DerefMut for MaybeUninitSlice<'a> { deref_mut(&mut self) -> &mut [MaybeUninit<u8>]418 fn deref_mut(&mut self) -> &mut [MaybeUninit<u8>] { 419 self.0.as_mut_slice() 420 } 421 } 422 423 /// Configures a socket's TCP keepalive parameters. 424 /// 425 /// See [`Socket::set_tcp_keepalive`]. 426 #[derive(Debug, Clone)] 427 pub struct TcpKeepalive { 428 #[cfg_attr( 429 any(target_os = "openbsd", target_os = "haiku", target_os = "vita"), 430 allow(dead_code) 431 )] 432 time: Option<Duration>, 433 #[cfg(not(any( 434 target_os = "openbsd", 435 target_os = "redox", 436 target_os = "solaris", 437 target_os = "nto", 438 target_os = "espidf", 439 target_os = "vita", 440 target_os = "haiku", 441 )))] 442 interval: Option<Duration>, 443 #[cfg(not(any( 444 target_os = "openbsd", 445 target_os = "redox", 446 target_os = "solaris", 447 target_os = "windows", 448 target_os = "nto", 449 target_os = "espidf", 450 target_os = "vita", 451 target_os = "haiku", 452 )))] 453 retries: Option<u32>, 454 } 455 456 impl TcpKeepalive { 457 /// Returns a new, empty set of TCP keepalive parameters. 458 #[allow(clippy::new_without_default)] new() -> TcpKeepalive459 pub const fn new() -> TcpKeepalive { 460 TcpKeepalive { 461 time: None, 462 #[cfg(not(any( 463 target_os = "openbsd", 464 target_os = "redox", 465 target_os = "solaris", 466 target_os = "nto", 467 target_os = "espidf", 468 target_os = "vita", 469 target_os = "haiku", 470 )))] 471 interval: None, 472 #[cfg(not(any( 473 target_os = "openbsd", 474 target_os = "redox", 475 target_os = "solaris", 476 target_os = "windows", 477 target_os = "nto", 478 target_os = "espidf", 479 target_os = "vita", 480 target_os = "haiku", 481 )))] 482 retries: None, 483 } 484 } 485 486 /// Set the amount of time after which TCP keepalive probes will be sent on 487 /// idle connections. 488 /// 489 /// This will set `TCP_KEEPALIVE` on macOS and iOS, and 490 /// `TCP_KEEPIDLE` on all other Unix operating systems, except 491 /// OpenBSD and Haiku which don't support any way to set this 492 /// option. On Windows, this sets the value of the `tcp_keepalive` 493 /// struct's `keepalivetime` field. 494 /// 495 /// Some platforms specify this value in seconds, so sub-second 496 /// specifications may be omitted. with_time(self, time: Duration) -> Self497 pub const fn with_time(self, time: Duration) -> Self { 498 Self { 499 time: Some(time), 500 ..self 501 } 502 } 503 504 /// Set the value of the `TCP_KEEPINTVL` option. On Windows, this sets the 505 /// value of the `tcp_keepalive` struct's `keepaliveinterval` field. 506 /// 507 /// Sets the time interval between TCP keepalive probes. 508 /// 509 /// Some platforms specify this value in seconds, so sub-second 510 /// specifications may be omitted. 511 #[cfg(any( 512 target_os = "android", 513 target_os = "dragonfly", 514 target_os = "freebsd", 515 target_os = "fuchsia", 516 target_os = "illumos", 517 target_os = "ios", 518 target_os = "visionos", 519 target_os = "linux", 520 target_os = "macos", 521 target_os = "netbsd", 522 target_os = "tvos", 523 target_os = "watchos", 524 target_os = "windows", 525 ))] 526 #[cfg_attr( 527 docsrs, 528 doc(cfg(any( 529 target_os = "android", 530 target_os = "dragonfly", 531 target_os = "freebsd", 532 target_os = "fuchsia", 533 target_os = "illumos", 534 target_os = "ios", 535 target_os = "visionos", 536 target_os = "linux", 537 target_os = "macos", 538 target_os = "netbsd", 539 target_os = "tvos", 540 target_os = "watchos", 541 target_os = "windows", 542 ))) 543 )] with_interval(self, interval: Duration) -> Self544 pub const fn with_interval(self, interval: Duration) -> Self { 545 Self { 546 interval: Some(interval), 547 ..self 548 } 549 } 550 551 /// Set the value of the `TCP_KEEPCNT` option. 552 /// 553 /// Set the maximum number of TCP keepalive probes that will be sent before 554 /// dropping a connection, if TCP keepalive is enabled on this socket. 555 #[cfg(all( 556 feature = "all", 557 any( 558 target_os = "android", 559 target_os = "dragonfly", 560 target_os = "freebsd", 561 target_os = "fuchsia", 562 target_os = "illumos", 563 target_os = "ios", 564 target_os = "visionos", 565 target_os = "linux", 566 target_os = "macos", 567 target_os = "netbsd", 568 target_os = "tvos", 569 target_os = "watchos", 570 ) 571 ))] 572 #[cfg_attr( 573 docsrs, 574 doc(cfg(all( 575 feature = "all", 576 any( 577 target_os = "android", 578 target_os = "dragonfly", 579 target_os = "freebsd", 580 target_os = "fuchsia", 581 target_os = "illumos", 582 target_os = "ios", 583 target_os = "visionos", 584 target_os = "linux", 585 target_os = "macos", 586 target_os = "netbsd", 587 target_os = "tvos", 588 target_os = "watchos", 589 ) 590 ))) 591 )] with_retries(self, retries: u32) -> Self592 pub const fn with_retries(self, retries: u32) -> Self { 593 Self { 594 retries: Some(retries), 595 ..self 596 } 597 } 598 } 599 600 /// Configuration of a `sendmsg(2)` system call. 601 /// 602 /// This wraps `msghdr` on Unix and `WSAMSG` on Windows. Also see [`MsgHdrMut`] 603 /// for the variant used by `recvmsg(2)`. 604 #[cfg(not(target_os = "redox"))] 605 pub struct MsgHdr<'addr, 'bufs, 'control> { 606 inner: sys::msghdr, 607 #[allow(clippy::type_complexity)] 608 _lifetimes: PhantomData<(&'addr SockAddr, &'bufs IoSlice<'bufs>, &'control [u8])>, 609 } 610 611 #[cfg(not(target_os = "redox"))] 612 impl<'addr, 'bufs, 'control> MsgHdr<'addr, 'bufs, 'control> { 613 /// Create a new `MsgHdr` with all empty/zero fields. 614 #[allow(clippy::new_without_default)] new() -> MsgHdr<'addr, 'bufs, 'control>615 pub fn new() -> MsgHdr<'addr, 'bufs, 'control> { 616 // SAFETY: all zero is valid for `msghdr` and `WSAMSG`. 617 MsgHdr { 618 inner: unsafe { mem::zeroed() }, 619 _lifetimes: PhantomData, 620 } 621 } 622 623 /// Set the address (name) of the message. 624 /// 625 /// Corresponds to setting `msg_name` and `msg_namelen` on Unix and `name` 626 /// and `namelen` on Windows. with_addr(mut self, addr: &'addr SockAddr) -> Self627 pub fn with_addr(mut self, addr: &'addr SockAddr) -> Self { 628 sys::set_msghdr_name(&mut self.inner, addr); 629 self 630 } 631 632 /// Set the buffer(s) of the message. 633 /// 634 /// Corresponds to setting `msg_iov` and `msg_iovlen` on Unix and `lpBuffers` 635 /// and `dwBufferCount` on Windows. with_buffers(mut self, bufs: &'bufs [IoSlice<'_>]) -> Self636 pub fn with_buffers(mut self, bufs: &'bufs [IoSlice<'_>]) -> Self { 637 let ptr = bufs.as_ptr() as *mut _; 638 sys::set_msghdr_iov(&mut self.inner, ptr, bufs.len()); 639 self 640 } 641 642 /// Set the control buffer of the message. 643 /// 644 /// Corresponds to setting `msg_control` and `msg_controllen` on Unix and 645 /// `Control` on Windows. with_control(mut self, buf: &'control [u8]) -> Self646 pub fn with_control(mut self, buf: &'control [u8]) -> Self { 647 let ptr = buf.as_ptr() as *mut _; 648 sys::set_msghdr_control(&mut self.inner, ptr, buf.len()); 649 self 650 } 651 652 /// Set the flags of the message. 653 /// 654 /// Corresponds to setting `msg_flags` on Unix and `dwFlags` on Windows. with_flags(mut self, flags: sys::c_int) -> Self655 pub fn with_flags(mut self, flags: sys::c_int) -> Self { 656 sys::set_msghdr_flags(&mut self.inner, flags); 657 self 658 } 659 } 660 661 #[cfg(not(target_os = "redox"))] 662 impl<'name, 'bufs, 'control> fmt::Debug for MsgHdr<'name, 'bufs, 'control> { fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result663 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 664 "MsgHdr".fmt(fmt) 665 } 666 } 667 668 /// Configuration of a `recvmsg(2)` system call. 669 /// 670 /// This wraps `msghdr` on Unix and `WSAMSG` on Windows. Also see [`MsgHdr`] for 671 /// the variant used by `sendmsg(2)`. 672 #[cfg(not(target_os = "redox"))] 673 pub struct MsgHdrMut<'addr, 'bufs, 'control> { 674 inner: sys::msghdr, 675 #[allow(clippy::type_complexity)] 676 _lifetimes: PhantomData<( 677 &'addr mut SockAddr, 678 &'bufs mut MaybeUninitSlice<'bufs>, 679 &'control mut [u8], 680 )>, 681 } 682 683 #[cfg(not(target_os = "redox"))] 684 impl<'addr, 'bufs, 'control> MsgHdrMut<'addr, 'bufs, 'control> { 685 /// Create a new `MsgHdrMut` with all empty/zero fields. 686 #[allow(clippy::new_without_default)] new() -> MsgHdrMut<'addr, 'bufs, 'control>687 pub fn new() -> MsgHdrMut<'addr, 'bufs, 'control> { 688 // SAFETY: all zero is valid for `msghdr` and `WSAMSG`. 689 MsgHdrMut { 690 inner: unsafe { mem::zeroed() }, 691 _lifetimes: PhantomData, 692 } 693 } 694 695 /// Set the mutable address (name) of the message. 696 /// 697 /// Corresponds to setting `msg_name` and `msg_namelen` on Unix and `name` 698 /// and `namelen` on Windows. 699 #[allow(clippy::needless_pass_by_ref_mut)] with_addr(mut self, addr: &'addr mut SockAddr) -> Self700 pub fn with_addr(mut self, addr: &'addr mut SockAddr) -> Self { 701 sys::set_msghdr_name(&mut self.inner, addr); 702 self 703 } 704 705 /// Set the mutable buffer(s) of the message. 706 /// 707 /// Corresponds to setting `msg_iov` and `msg_iovlen` on Unix and `lpBuffers` 708 /// and `dwBufferCount` on Windows. with_buffers(mut self, bufs: &'bufs mut [MaybeUninitSlice<'_>]) -> Self709 pub fn with_buffers(mut self, bufs: &'bufs mut [MaybeUninitSlice<'_>]) -> Self { 710 sys::set_msghdr_iov(&mut self.inner, bufs.as_mut_ptr().cast(), bufs.len()); 711 self 712 } 713 714 /// Set the mutable control buffer of the message. 715 /// 716 /// Corresponds to setting `msg_control` and `msg_controllen` on Unix and 717 /// `Control` on Windows. with_control(mut self, buf: &'control mut [MaybeUninit<u8>]) -> Self718 pub fn with_control(mut self, buf: &'control mut [MaybeUninit<u8>]) -> Self { 719 sys::set_msghdr_control(&mut self.inner, buf.as_mut_ptr().cast(), buf.len()); 720 self 721 } 722 723 /// Returns the flags of the message. flags(&self) -> RecvFlags724 pub fn flags(&self) -> RecvFlags { 725 sys::msghdr_flags(&self.inner) 726 } 727 728 /// Gets the length of the control buffer. 729 /// 730 /// Can be used to determine how much, if any, of the control buffer was filled by `recvmsg`. 731 /// 732 /// Corresponds to `msg_controllen` on Unix and `Control.len` on Windows. control_len(&self) -> usize733 pub fn control_len(&self) -> usize { 734 sys::msghdr_control_len(&self.inner) 735 } 736 } 737 738 #[cfg(not(target_os = "redox"))] 739 impl<'name, 'bufs, 'control> fmt::Debug for MsgHdrMut<'name, 'bufs, 'control> { fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result740 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 741 "MsgHdrMut".fmt(fmt) 742 } 743 } 744