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`. |
222 | 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 { |
231 | fn from(d: c_int) -> Domain { |
232 | Domain(d) |
233 | } |
234 | } |
235 | |
236 | impl From<Domain> for c_int { |
237 | 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 { |
287 | fn from(t: c_int) -> Type { |
288 | Type(t) |
289 | } |
290 | } |
291 | |
292 | impl From<Type> for c_int { |
293 | 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 { |
352 | fn from(p: c_int) -> Protocol { |
353 | Protocol(p) |
354 | } |
355 | } |
356 | |
357 | impl From<Protocol> for c_int { |
358 | 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" ))] |
381 | 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> { |
393 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
394 | fmt::Debug::fmt(self.0.as_slice(), f: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. |
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 | |
412 | fn deref(&self) -> &[MaybeUninit<u8>] { |
413 | self.0.as_slice() |
414 | } |
415 | } |
416 | |
417 | impl<'a> DerefMut for MaybeUninitSlice<'a> { |
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 | pub const fn new() -> TcpKeepalive { |
459 | TcpKeepalive { |
460 | time: None, |
461 | #[cfg (not(any( |
462 | target_os = "openbsd" , |
463 | target_os = "redox" , |
464 | target_os = "solaris" , |
465 | target_os = "nto" , |
466 | target_os = "espidf" , |
467 | target_os = "vita" , |
468 | target_os = "haiku" , |
469 | )))] |
470 | interval: None, |
471 | #[cfg (not(any( |
472 | target_os = "openbsd" , |
473 | target_os = "redox" , |
474 | target_os = "solaris" , |
475 | target_os = "windows" , |
476 | target_os = "nto" , |
477 | target_os = "espidf" , |
478 | target_os = "vita" , |
479 | target_os = "haiku" , |
480 | )))] |
481 | retries: None, |
482 | } |
483 | } |
484 | |
485 | /// Set the amount of time after which TCP keepalive probes will be sent on |
486 | /// idle connections. |
487 | /// |
488 | /// This will set `TCP_KEEPALIVE` on macOS and iOS, and |
489 | /// `TCP_KEEPIDLE` on all other Unix operating systems, except |
490 | /// OpenBSD and Haiku which don't support any way to set this |
491 | /// option. On Windows, this sets the value of the `tcp_keepalive` |
492 | /// struct's `keepalivetime` field. |
493 | /// |
494 | /// Some platforms specify this value in seconds, so sub-second |
495 | /// specifications may be omitted. |
496 | pub const fn with_time(self, time: Duration) -> Self { |
497 | Self { |
498 | time: Some(time), |
499 | ..self |
500 | } |
501 | } |
502 | |
503 | /// Set the value of the `TCP_KEEPINTVL` option. On Windows, this sets the |
504 | /// value of the `tcp_keepalive` struct's `keepaliveinterval` field. |
505 | /// |
506 | /// Sets the time interval between TCP keepalive probes. |
507 | /// |
508 | /// Some platforms specify this value in seconds, so sub-second |
509 | /// specifications may be omitted. |
510 | #[cfg (any( |
511 | target_os = "android" , |
512 | target_os = "dragonfly" , |
513 | target_os = "freebsd" , |
514 | target_os = "fuchsia" , |
515 | target_os = "illumos" , |
516 | target_os = "ios" , |
517 | target_os = "linux" , |
518 | target_os = "macos" , |
519 | target_os = "netbsd" , |
520 | target_os = "tvos" , |
521 | target_os = "watchos" , |
522 | target_os = "windows" , |
523 | ))] |
524 | #[cfg_attr ( |
525 | docsrs, |
526 | doc(cfg(any( |
527 | target_os = "android" , |
528 | target_os = "dragonfly" , |
529 | target_os = "freebsd" , |
530 | target_os = "fuchsia" , |
531 | target_os = "illumos" , |
532 | target_os = "ios" , |
533 | target_os = "linux" , |
534 | target_os = "macos" , |
535 | target_os = "netbsd" , |
536 | target_os = "tvos" , |
537 | target_os = "watchos" , |
538 | target_os = "windows" , |
539 | ))) |
540 | )] |
541 | pub const fn with_interval(self, interval: Duration) -> Self { |
542 | Self { |
543 | interval: Some(interval), |
544 | ..self |
545 | } |
546 | } |
547 | |
548 | /// Set the value of the `TCP_KEEPCNT` option. |
549 | /// |
550 | /// Set the maximum number of TCP keepalive probes that will be sent before |
551 | /// dropping a connection, if TCP keepalive is enabled on this socket. |
552 | #[cfg (all( |
553 | feature = "all" , |
554 | any( |
555 | target_os = "android" , |
556 | target_os = "dragonfly" , |
557 | target_os = "freebsd" , |
558 | target_os = "fuchsia" , |
559 | target_os = "illumos" , |
560 | target_os = "ios" , |
561 | target_os = "linux" , |
562 | target_os = "macos" , |
563 | target_os = "netbsd" , |
564 | target_os = "tvos" , |
565 | target_os = "watchos" , |
566 | ) |
567 | ))] |
568 | #[cfg_attr ( |
569 | docsrs, |
570 | doc(cfg(all( |
571 | feature = "all" , |
572 | any( |
573 | target_os = "android" , |
574 | target_os = "dragonfly" , |
575 | target_os = "freebsd" , |
576 | target_os = "fuchsia" , |
577 | target_os = "illumos" , |
578 | target_os = "ios" , |
579 | target_os = "linux" , |
580 | target_os = "macos" , |
581 | target_os = "netbsd" , |
582 | target_os = "tvos" , |
583 | target_os = "watchos" , |
584 | ) |
585 | ))) |
586 | )] |
587 | pub const fn with_retries(self, retries: u32) -> Self { |
588 | Self { |
589 | retries: Some(retries), |
590 | ..self |
591 | } |
592 | } |
593 | } |
594 | |
595 | /// Configuration of a `sendmsg(2)` system call. |
596 | /// |
597 | /// This wraps `msghdr` on Unix and `WSAMSG` on Windows. Also see [`MsgHdrMut`] |
598 | /// for the variant used by `recvmsg(2)`. |
599 | #[cfg (not(target_os = "redox" ))] |
600 | pub struct MsgHdr<'addr, 'bufs, 'control> { |
601 | inner: sys::msghdr, |
602 | #[allow (clippy::type_complexity)] |
603 | _lifetimes: PhantomData<(&'addr SockAddr, &'bufs IoSlice<'bufs>, &'control [u8])>, |
604 | } |
605 | |
606 | #[cfg (not(target_os = "redox" ))] |
607 | impl<'addr, 'bufs, 'control> MsgHdr<'addr, 'bufs, 'control> { |
608 | /// Create a new `MsgHdr` with all empty/zero fields. |
609 | #[allow (clippy::new_without_default)] |
610 | pub fn new() -> MsgHdr<'addr, 'bufs, 'control> { |
611 | // SAFETY: all zero is valid for `msghdr` and `WSAMSG`. |
612 | MsgHdr { |
613 | inner: unsafe { mem::zeroed() }, |
614 | _lifetimes: PhantomData, |
615 | } |
616 | } |
617 | |
618 | /// Set the address (name) of the message. |
619 | /// |
620 | /// Corresponds to setting `msg_name` and `msg_namelen` on Unix and `name` |
621 | /// and `namelen` on Windows. |
622 | pub fn with_addr(mut self, addr: &'addr SockAddr) -> Self { |
623 | sys::set_msghdr_name(&mut self.inner, addr); |
624 | self |
625 | } |
626 | |
627 | /// Set the buffer(s) of the message. |
628 | /// |
629 | /// Corresponds to setting `msg_iov` and `msg_iovlen` on Unix and `lpBuffers` |
630 | /// and `dwBufferCount` on Windows. |
631 | pub fn with_buffers(mut self, bufs: &'bufs [IoSlice<'_>]) -> Self { |
632 | let ptr = bufs.as_ptr() as *mut _; |
633 | sys::set_msghdr_iov(&mut self.inner, ptr, bufs.len()); |
634 | self |
635 | } |
636 | |
637 | /// Set the control buffer of the message. |
638 | /// |
639 | /// Corresponds to setting `msg_control` and `msg_controllen` on Unix and |
640 | /// `Control` on Windows. |
641 | pub fn with_control(mut self, buf: &'control [u8]) -> Self { |
642 | let ptr = buf.as_ptr() as *mut _; |
643 | sys::set_msghdr_control(&mut self.inner, ptr, buf.len()); |
644 | self |
645 | } |
646 | |
647 | /// Set the flags of the message. |
648 | /// |
649 | /// Corresponds to setting `msg_flags` on Unix and `dwFlags` on Windows. |
650 | pub fn with_flags(mut self, flags: sys::c_int) -> Self { |
651 | sys::set_msghdr_flags(&mut self.inner, flags); |
652 | self |
653 | } |
654 | } |
655 | |
656 | #[cfg (not(target_os = "redox" ))] |
657 | impl<'name, 'bufs, 'control> fmt::Debug for MsgHdr<'name, 'bufs, 'control> { |
658 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
659 | "MsgHdr" .fmt(fmt) |
660 | } |
661 | } |
662 | |
663 | /// Configuration of a `recvmsg(2)` system call. |
664 | /// |
665 | /// This wraps `msghdr` on Unix and `WSAMSG` on Windows. Also see [`MsgHdr`] for |
666 | /// the variant used by `sendmsg(2)`. |
667 | #[cfg (not(target_os = "redox" ))] |
668 | pub struct MsgHdrMut<'addr, 'bufs, 'control> { |
669 | inner: sys::msghdr, |
670 | #[allow (clippy::type_complexity)] |
671 | _lifetimes: PhantomData<( |
672 | &'addr mut SockAddr, |
673 | &'bufs mut MaybeUninitSlice<'bufs>, |
674 | &'control mut [u8], |
675 | )>, |
676 | } |
677 | |
678 | #[cfg (not(target_os = "redox" ))] |
679 | impl<'addr, 'bufs, 'control> MsgHdrMut<'addr, 'bufs, 'control> { |
680 | /// Create a new `MsgHdrMut` with all empty/zero fields. |
681 | #[allow (clippy::new_without_default)] |
682 | pub fn new() -> MsgHdrMut<'addr, 'bufs, 'control> { |
683 | // SAFETY: all zero is valid for `msghdr` and `WSAMSG`. |
684 | MsgHdrMut { |
685 | inner: unsafe { mem::zeroed() }, |
686 | _lifetimes: PhantomData, |
687 | } |
688 | } |
689 | |
690 | /// Set the mutable address (name) of the message. |
691 | /// |
692 | /// Corresponds to setting `msg_name` and `msg_namelen` on Unix and `name` |
693 | /// and `namelen` on Windows. |
694 | #[allow (clippy::needless_pass_by_ref_mut)] |
695 | pub fn with_addr(mut self, addr: &'addr mut SockAddr) -> Self { |
696 | sys::set_msghdr_name(&mut self.inner, addr); |
697 | self |
698 | } |
699 | |
700 | /// Set the mutable buffer(s) of the message. |
701 | /// |
702 | /// Corresponds to setting `msg_iov` and `msg_iovlen` on Unix and `lpBuffers` |
703 | /// and `dwBufferCount` on Windows. |
704 | pub fn with_buffers(mut self, bufs: &'bufs mut [MaybeUninitSlice<'_>]) -> Self { |
705 | sys::set_msghdr_iov(&mut self.inner, bufs.as_mut_ptr().cast(), bufs.len()); |
706 | self |
707 | } |
708 | |
709 | /// Set the mutable control buffer of the message. |
710 | /// |
711 | /// Corresponds to setting `msg_control` and `msg_controllen` on Unix and |
712 | /// `Control` on Windows. |
713 | pub fn with_control(mut self, buf: &'control mut [MaybeUninit<u8>]) -> Self { |
714 | sys::set_msghdr_control(&mut self.inner, buf.as_mut_ptr().cast(), buf.len()); |
715 | self |
716 | } |
717 | |
718 | /// Returns the flags of the message. |
719 | pub fn flags(&self) -> RecvFlags { |
720 | sys::msghdr_flags(&self.inner) |
721 | } |
722 | } |
723 | |
724 | #[cfg (not(target_os = "redox" ))] |
725 | impl<'name, 'bufs, 'control> fmt::Debug for MsgHdrMut<'name, 'bufs, 'control> { |
726 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
727 | "MsgHdrMut" .fmt(fmt) |
728 | } |
729 | } |
730 | |