socket2/socket.rs
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
9use std::fmt;
10use std::io::{self, Read, Write};
11#[cfg(not(target_os = "redox"))]
12use std::io::{IoSlice, IoSliceMut};
13use std::mem::MaybeUninit;
14#[cfg(not(target_os = "nto"))]
15use std::net::Ipv6Addr;
16use std::net::{self, Ipv4Addr, Shutdown};
17#[cfg(unix)]
18use std::os::unix::io::{FromRawFd, IntoRawFd};
19#[cfg(windows)]
20use std::os::windows::io::{FromRawSocket, IntoRawSocket};
21use std::time::Duration;
22
23use crate::sys::{self, c_int, getsockopt, setsockopt, Bool};
24#[cfg(all(unix, not(target_os = "redox")))]
25use crate::MsgHdrMut;
26use crate::{Domain, Protocol, SockAddr, TcpKeepalive, Type};
27#[cfg(not(target_os = "redox"))]
28use crate::{MaybeUninitSlice, MsgHdr, RecvFlags};
29
30/// Owned wrapper around a system socket.
31///
32/// This type simply wraps an instance of a file descriptor (`c_int`) on Unix
33/// and an instance of `SOCKET` on Windows. This is the main type exported by
34/// this crate and is intended to mirror the raw semantics of sockets on
35/// platforms as closely as possible. Almost all methods correspond to
36/// precisely one libc or OS API call which is essentially just a "Rustic
37/// translation" of what's below.
38///
39/// ## Converting to and from other types
40///
41/// This type can be freely converted into the network primitives provided by
42/// the standard library, such as [`TcpStream`] or [`UdpSocket`], using the
43/// [`From`] trait, see the example below.
44///
45/// [`TcpStream`]: std::net::TcpStream
46/// [`UdpSocket`]: std::net::UdpSocket
47///
48/// # Notes
49///
50/// Some methods that set options on `Socket` require two system calls to set
51/// their options without overwriting previously set options. We do this by
52/// first getting the current settings, applying the desired changes, and then
53/// updating the settings. This means that the operation is **not** atomic. This
54/// can lead to a data race when two threads are changing options in parallel.
55///
56/// # Examples
57/// ```no_run
58/// # fn main() -> std::io::Result<()> {
59/// use std::net::{SocketAddr, TcpListener};
60/// use socket2::{Socket, Domain, Type};
61///
62/// // create a TCP listener
63/// let socket = Socket::new(Domain::IPV6, Type::STREAM, None)?;
64///
65/// let address: SocketAddr = "[::1]:12345".parse().unwrap();
66/// let address = address.into();
67/// socket.bind(&address)?;
68/// socket.listen(128)?;
69///
70/// let listener: TcpListener = socket.into();
71/// // ...
72/// # drop(listener);
73/// # Ok(()) }
74/// ```
75pub struct Socket {
76 inner: Inner,
77}
78
79/// Store a `TcpStream` internally to take advantage of its niche optimizations on Unix platforms.
80pub(crate) type Inner = std::net::TcpStream;
81
82impl Socket {
83 /// # Safety
84 ///
85 /// The caller must ensure `raw` is a valid file descriptor/socket. NOTE:
86 /// this should really be marked `unsafe`, but this being an internal
87 /// function, often passed as mapping function, it's makes it very
88 /// inconvenient to mark it as `unsafe`.
89 pub(crate) fn from_raw(raw: sys::Socket) -> Socket {
90 Socket {
91 inner: unsafe {
92 // SAFETY: the caller must ensure that `raw` is a valid file
93 // descriptor, but when it isn't it could return I/O errors, or
94 // potentially close a fd it doesn't own. All of that isn't
95 // memory unsafe, so it's not desired but never memory unsafe or
96 // causes UB.
97 //
98 // However there is one exception. We use `TcpStream` to
99 // represent the `Socket` internally (see `Inner` type),
100 // `TcpStream` has a layout optimisation that doesn't allow for
101 // negative file descriptors (as those are always invalid).
102 // Violating this assumption (fd never negative) causes UB,
103 // something we don't want. So check for that we have this
104 // `assert!`.
105 #[cfg(unix)]
106 assert!(raw >= 0, "tried to create a `Socket` with an invalid fd");
107 sys::socket_from_raw(raw)
108 },
109 }
110 }
111
112 pub(crate) fn as_raw(&self) -> sys::Socket {
113 sys::socket_as_raw(&self.inner)
114 }
115
116 pub(crate) fn into_raw(self) -> sys::Socket {
117 sys::socket_into_raw(self.inner)
118 }
119
120 /// Creates a new socket and sets common flags.
121 ///
122 /// This function corresponds to `socket(2)` on Unix and `WSASocketW` on
123 /// Windows.
124 ///
125 /// On Unix-like systems, the close-on-exec flag is set on the new socket.
126 /// Additionally, on Apple platforms `SOCK_NOSIGPIPE` is set. On Windows,
127 /// the socket is made non-inheritable.
128 ///
129 /// [`Socket::new_raw`] can be used if you don't want these flags to be set.
130 #[doc = man_links!(socket(2))]
131 pub fn new(domain: Domain, ty: Type, protocol: Option<Protocol>) -> io::Result<Socket> {
132 let ty = set_common_type(ty);
133 Socket::new_raw(domain, ty, protocol).and_then(set_common_flags)
134 }
135
136 /// Creates a new socket ready to be configured.
137 ///
138 /// This function corresponds to `socket(2)` on Unix and `WSASocketW` on
139 /// Windows and simply creates a new socket, no other configuration is done.
140 pub fn new_raw(domain: Domain, ty: Type, protocol: Option<Protocol>) -> io::Result<Socket> {
141 let protocol = protocol.map_or(0, |p| p.0);
142 sys::socket(domain.0, ty.0, protocol).map(Socket::from_raw)
143 }
144
145 /// Creates a pair of sockets which are connected to each other.
146 ///
147 /// This function corresponds to `socketpair(2)`.
148 ///
149 /// This function sets the same flags as in done for [`Socket::new`],
150 /// [`Socket::pair_raw`] can be used if you don't want to set those flags.
151 #[doc = man_links!(unix: socketpair(2))]
152 #[cfg(all(feature = "all", unix))]
153 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix))))]
154 pub fn pair(
155 domain: Domain,
156 ty: Type,
157 protocol: Option<Protocol>,
158 ) -> io::Result<(Socket, Socket)> {
159 let ty = set_common_type(ty);
160 let (a, b) = Socket::pair_raw(domain, ty, protocol)?;
161 let a = set_common_flags(a)?;
162 let b = set_common_flags(b)?;
163 Ok((a, b))
164 }
165
166 /// Creates a pair of sockets which are connected to each other.
167 ///
168 /// This function corresponds to `socketpair(2)`.
169 #[cfg(all(feature = "all", unix))]
170 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix))))]
171 pub fn pair_raw(
172 domain: Domain,
173 ty: Type,
174 protocol: Option<Protocol>,
175 ) -> io::Result<(Socket, Socket)> {
176 let protocol = protocol.map_or(0, |p| p.0);
177 sys::socketpair(domain.0, ty.0, protocol)
178 .map(|[a, b]| (Socket::from_raw(a), Socket::from_raw(b)))
179 }
180
181 /// Binds this socket to the specified address.
182 ///
183 /// This function directly corresponds to the `bind(2)` function on Windows
184 /// and Unix.
185 #[doc = man_links!(bind(2))]
186 pub fn bind(&self, address: &SockAddr) -> io::Result<()> {
187 sys::bind(self.as_raw(), address)
188 }
189
190 /// Initiate a connection on this socket to the specified address.
191 ///
192 /// This function directly corresponds to the `connect(2)` function on
193 /// Windows and Unix.
194 ///
195 /// An error will be returned if `listen` or `connect` has already been
196 /// called on this builder.
197 #[doc = man_links!(connect(2))]
198 ///
199 /// # Notes
200 ///
201 /// When using a non-blocking connect (by setting the socket into
202 /// non-blocking mode before calling this function), socket option can't be
203 /// set *while connecting*. This will cause errors on Windows. Socket
204 /// options can be safely set before and after connecting the socket.
205 ///
206 /// On Cygwin, a Unix domain socket connect blocks until the server accepts
207 /// it. If the behavior is not expected, try [`Socket::set_no_peercred`]
208 /// (Cygwin only).
209 #[allow(rustdoc::broken_intra_doc_links)] // Socket::set_no_peercred
210 pub fn connect(&self, address: &SockAddr) -> io::Result<()> {
211 sys::connect(self.as_raw(), address)
212 }
213
214 /// Initiate a connection on this socket to the specified address, only
215 /// only waiting for a certain period of time for the connection to be
216 /// established.
217 ///
218 /// Unlike many other methods on `Socket`, this does *not* correspond to a
219 /// single C function. It sets the socket to nonblocking mode, connects via
220 /// connect(2), and then waits for the connection to complete with poll(2)
221 /// on Unix and select on Windows. When the connection is complete, the
222 /// socket is set back to blocking mode. On Unix, this will loop over
223 /// `EINTR` errors.
224 ///
225 /// # Warnings
226 ///
227 /// The non-blocking state of the socket is overridden by this function -
228 /// it will be returned in blocking mode on success, and in an indeterminate
229 /// state on failure.
230 ///
231 /// If the connection request times out, it may still be processing in the
232 /// background - a second call to `connect` or `connect_timeout` may fail.
233 pub fn connect_timeout(&self, addr: &SockAddr, timeout: Duration) -> io::Result<()> {
234 self.set_nonblocking(true)?;
235 let res = self.connect(addr);
236 self.set_nonblocking(false)?;
237
238 match res {
239 Ok(()) => return Ok(()),
240 Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {}
241 #[cfg(unix)]
242 Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {}
243 Err(e) => return Err(e),
244 }
245
246 sys::poll_connect(self, timeout)
247 }
248
249 /// Mark a socket as ready to accept incoming connection requests using
250 /// [`Socket::accept()`].
251 ///
252 /// This function directly corresponds to the `listen(2)` function on
253 /// Windows and Unix.
254 ///
255 /// An error will be returned if `listen` or `connect` has already been
256 /// called on this builder.
257 #[doc = man_links!(listen(2))]
258 pub fn listen(&self, backlog: c_int) -> io::Result<()> {
259 sys::listen(self.as_raw(), backlog)
260 }
261
262 /// Accept a new incoming connection from this listener.
263 ///
264 /// This function uses `accept4(2)` on platforms that support it and
265 /// `accept(2)` platforms that do not.
266 ///
267 /// This function sets the same flags as in done for [`Socket::new`],
268 /// [`Socket::accept_raw`] can be used if you don't want to set those flags.
269 #[doc = man_links!(accept(2))]
270 ///
271 /// # Notes
272 ///
273 /// On Cygwin, a Unix domain socket connect blocks until the server accepts
274 /// it. If the behavior is not expected, try [`Socket::set_no_peercred`]
275 /// (Cygwin only).
276 #[allow(rustdoc::broken_intra_doc_links)] // Socket::set_no_peercred
277 pub fn accept(&self) -> io::Result<(Socket, SockAddr)> {
278 // Use `accept4` on platforms that support it.
279 #[cfg(any(
280 target_os = "android",
281 target_os = "dragonfly",
282 target_os = "freebsd",
283 target_os = "fuchsia",
284 target_os = "illumos",
285 target_os = "linux",
286 target_os = "netbsd",
287 target_os = "openbsd",
288 target_os = "cygwin",
289 ))]
290 return self._accept4(libc::SOCK_CLOEXEC);
291
292 // Fall back to `accept` on platforms that do not support `accept4`.
293 #[cfg(not(any(
294 target_os = "android",
295 target_os = "dragonfly",
296 target_os = "freebsd",
297 target_os = "fuchsia",
298 target_os = "illumos",
299 target_os = "linux",
300 target_os = "netbsd",
301 target_os = "openbsd",
302 target_os = "cygwin",
303 )))]
304 {
305 let (socket, addr) = self.accept_raw()?;
306 let socket = set_common_flags(socket)?;
307 // `set_common_flags` does not disable inheritance on Windows because `Socket::new`
308 // unlike `accept` is able to create the socket with inheritance disabled.
309 #[cfg(windows)]
310 socket._set_no_inherit(true)?;
311 Ok((socket, addr))
312 }
313 }
314
315 /// Accept a new incoming connection from this listener.
316 ///
317 /// This function directly corresponds to the `accept(2)` function on
318 /// Windows and Unix.
319 pub fn accept_raw(&self) -> io::Result<(Socket, SockAddr)> {
320 sys::accept(self.as_raw()).map(|(inner, addr)| (Socket::from_raw(inner), addr))
321 }
322
323 /// Returns the socket address of the local half of this socket.
324 ///
325 /// This function directly corresponds to the `getsockname(2)` function on
326 /// Windows and Unix.
327 #[doc = man_links!(getsockname(2))]
328 ///
329 /// # Notes
330 ///
331 /// Depending on the OS this may return an error if the socket is not
332 /// [bound].
333 ///
334 /// [bound]: Socket::bind
335 pub fn local_addr(&self) -> io::Result<SockAddr> {
336 sys::getsockname(self.as_raw())
337 }
338
339 /// Returns the socket address of the remote peer of this socket.
340 ///
341 /// This function directly corresponds to the `getpeername(2)` function on
342 /// Windows and Unix.
343 #[doc = man_links!(getpeername(2))]
344 ///
345 /// # Notes
346 ///
347 /// This returns an error if the socket is not [`connect`ed].
348 ///
349 /// [`connect`ed]: Socket::connect
350 pub fn peer_addr(&self) -> io::Result<SockAddr> {
351 sys::getpeername(self.as_raw())
352 }
353
354 /// Returns the [`Type`] of this socket by checking the `SO_TYPE` option on
355 /// this socket.
356 pub fn r#type(&self) -> io::Result<Type> {
357 unsafe { getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_TYPE).map(Type) }
358 }
359
360 /// Creates a new independently owned handle to the underlying socket.
361 ///
362 /// # Notes
363 ///
364 /// On Unix this uses `F_DUPFD_CLOEXEC` and thus sets the `FD_CLOEXEC` on
365 /// the returned socket.
366 ///
367 /// On Windows this uses `WSA_FLAG_NO_HANDLE_INHERIT` setting inheriting to
368 /// false.
369 ///
370 /// On Windows this can **not** be used function cannot be used on a
371 /// QOS-enabled socket, see
372 /// <https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsaduplicatesocketw>.
373 pub fn try_clone(&self) -> io::Result<Socket> {
374 sys::try_clone(self.as_raw()).map(Socket::from_raw)
375 }
376
377 /// Returns true if this socket is set to nonblocking mode, false otherwise.
378 ///
379 /// # Notes
380 ///
381 /// On Unix this corresponds to calling `fcntl` returning the value of
382 /// `O_NONBLOCK`.
383 ///
384 /// On Windows it is not possible retrieve the nonblocking mode status.
385 #[cfg(all(feature = "all", unix))]
386 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix))))]
387 pub fn nonblocking(&self) -> io::Result<bool> {
388 sys::nonblocking(self.as_raw())
389 }
390
391 /// Moves this socket into or out of nonblocking mode.
392 ///
393 /// # Notes
394 ///
395 /// On Unix this corresponds to calling `fcntl` (un)setting `O_NONBLOCK`.
396 ///
397 /// On Windows this corresponds to calling `ioctlsocket` (un)setting
398 /// `FIONBIO`.
399 pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
400 sys::set_nonblocking(self.as_raw(), nonblocking)
401 }
402
403 /// Shuts down the read, write, or both halves of this connection.
404 ///
405 /// This function will cause all pending and future I/O on the specified
406 /// portions to return immediately with an appropriate value.
407 #[doc = man_links!(shutdown(2))]
408 pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
409 sys::shutdown(self.as_raw(), how)
410 }
411
412 /// Receives data on the socket from the remote address to which it is
413 /// connected.
414 ///
415 /// The [`connect`] method will connect this socket to a remote address.
416 /// This method might fail if the socket is not connected.
417 #[doc = man_links!(recv(2))]
418 ///
419 /// [`connect`]: Socket::connect
420 ///
421 /// # Safety
422 ///
423 /// Normally casting a `&mut [u8]` to `&mut [MaybeUninit<u8>]` would be
424 /// unsound, as that allows us to write uninitialised bytes to the buffer.
425 /// However this implementation promises to not write uninitialised bytes to
426 /// the `buf`fer and passes it directly to `recv(2)` system call. This
427 /// promise ensures that this function can be called using a `buf`fer of
428 /// type `&mut [u8]`.
429 ///
430 /// Note that the [`io::Read::read`] implementation calls this function with
431 /// a `buf`fer of type `&mut [u8]`, allowing initialised buffers to be used
432 /// without using `unsafe`.
433 pub fn recv(&self, buf: &mut [MaybeUninit<u8>]) -> io::Result<usize> {
434 self.recv_with_flags(buf, 0)
435 }
436
437 /// Receives out-of-band (OOB) data on the socket from the remote address to
438 /// which it is connected by setting the `MSG_OOB` flag for this call.
439 ///
440 /// For more information, see [`recv`], [`out_of_band_inline`].
441 ///
442 /// [`recv`]: Socket::recv
443 /// [`out_of_band_inline`]: Socket::out_of_band_inline
444 #[cfg_attr(target_os = "redox", allow(rustdoc::broken_intra_doc_links))]
445 pub fn recv_out_of_band(&self, buf: &mut [MaybeUninit<u8>]) -> io::Result<usize> {
446 self.recv_with_flags(buf, sys::MSG_OOB)
447 }
448
449 /// Identical to [`recv`] but allows for specification of arbitrary flags to
450 /// the underlying `recv` call.
451 ///
452 /// [`recv`]: Socket::recv
453 pub fn recv_with_flags(
454 &self,
455 buf: &mut [MaybeUninit<u8>],
456 flags: sys::c_int,
457 ) -> io::Result<usize> {
458 sys::recv(self.as_raw(), buf, flags)
459 }
460
461 /// Receives data on the socket from the remote address to which it is
462 /// connected. Unlike [`recv`] this allows passing multiple buffers.
463 ///
464 /// The [`connect`] method will connect this socket to a remote address.
465 /// This method might fail if the socket is not connected.
466 ///
467 /// In addition to the number of bytes read, this function returns the flags
468 /// for the received message. See [`RecvFlags`] for more information about
469 /// the returned flags.
470 #[doc = man_links!(recvmsg(2))]
471 ///
472 /// [`recv`]: Socket::recv
473 /// [`connect`]: Socket::connect
474 ///
475 /// # Safety
476 ///
477 /// Normally casting a `IoSliceMut` to `MaybeUninitSlice` would be unsound,
478 /// as that allows us to write uninitialised bytes to the buffer. However
479 /// this implementation promises to not write uninitialised bytes to the
480 /// `bufs` and passes it directly to `recvmsg(2)` system call. This promise
481 /// ensures that this function can be called using `bufs` of type `&mut
482 /// [IoSliceMut]`.
483 ///
484 /// Note that the [`io::Read::read_vectored`] implementation calls this
485 /// function with `buf`s of type `&mut [IoSliceMut]`, allowing initialised
486 /// buffers to be used without using `unsafe`.
487 #[cfg(not(target_os = "redox"))]
488 #[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))]
489 pub fn recv_vectored(
490 &self,
491 bufs: &mut [MaybeUninitSlice<'_>],
492 ) -> io::Result<(usize, RecvFlags)> {
493 self.recv_vectored_with_flags(bufs, 0)
494 }
495
496 /// Identical to [`recv_vectored`] but allows for specification of arbitrary
497 /// flags to the underlying `recvmsg`/`WSARecv` call.
498 ///
499 /// [`recv_vectored`]: Socket::recv_vectored
500 ///
501 /// # Safety
502 ///
503 /// `recv_from_vectored` makes the same safety guarantees regarding `bufs`
504 /// as [`recv_vectored`].
505 ///
506 /// [`recv_vectored`]: Socket::recv_vectored
507 #[cfg(not(target_os = "redox"))]
508 #[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))]
509 pub fn recv_vectored_with_flags(
510 &self,
511 bufs: &mut [MaybeUninitSlice<'_>],
512 flags: c_int,
513 ) -> io::Result<(usize, RecvFlags)> {
514 sys::recv_vectored(self.as_raw(), bufs, flags)
515 }
516
517 /// Receives data on the socket from the remote adress to which it is
518 /// connected, without removing that data from the queue. On success,
519 /// returns the number of bytes peeked.
520 ///
521 /// Successive calls return the same data. This is accomplished by passing
522 /// `MSG_PEEK` as a flag to the underlying `recv` system call.
523 ///
524 /// # Safety
525 ///
526 /// `peek` makes the same safety guarantees regarding the `buf`fer as
527 /// [`recv`].
528 ///
529 /// [`recv`]: Socket::recv
530 pub fn peek(&self, buf: &mut [MaybeUninit<u8>]) -> io::Result<usize> {
531 self.recv_with_flags(buf, sys::MSG_PEEK)
532 }
533
534 /// Receives data from the socket. On success, returns the number of bytes
535 /// read and the address from whence the data came.
536 #[doc = man_links!(recvfrom(2))]
537 ///
538 /// # Safety
539 ///
540 /// `recv_from` makes the same safety guarantees regarding the `buf`fer as
541 /// [`recv`].
542 ///
543 /// [`recv`]: Socket::recv
544 pub fn recv_from(&self, buf: &mut [MaybeUninit<u8>]) -> io::Result<(usize, SockAddr)> {
545 self.recv_from_with_flags(buf, 0)
546 }
547
548 /// Identical to [`recv_from`] but allows for specification of arbitrary
549 /// flags to the underlying `recvfrom` call.
550 ///
551 /// [`recv_from`]: Socket::recv_from
552 pub fn recv_from_with_flags(
553 &self,
554 buf: &mut [MaybeUninit<u8>],
555 flags: c_int,
556 ) -> io::Result<(usize, SockAddr)> {
557 sys::recv_from(self.as_raw(), buf, flags)
558 }
559
560 /// Receives data from the socket. Returns the amount of bytes read, the
561 /// [`RecvFlags`] and the remote address from the data is coming. Unlike
562 /// [`recv_from`] this allows passing multiple buffers.
563 #[doc = man_links!(recvmsg(2))]
564 ///
565 /// [`recv_from`]: Socket::recv_from
566 ///
567 /// # Safety
568 ///
569 /// `recv_from_vectored` makes the same safety guarantees regarding `bufs`
570 /// as [`recv_vectored`].
571 ///
572 /// [`recv_vectored`]: Socket::recv_vectored
573 #[cfg(not(target_os = "redox"))]
574 #[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))]
575 pub fn recv_from_vectored(
576 &self,
577 bufs: &mut [MaybeUninitSlice<'_>],
578 ) -> io::Result<(usize, RecvFlags, SockAddr)> {
579 self.recv_from_vectored_with_flags(bufs, 0)
580 }
581
582 /// Identical to [`recv_from_vectored`] but allows for specification of
583 /// arbitrary flags to the underlying `recvmsg`/`WSARecvFrom` call.
584 ///
585 /// [`recv_from_vectored`]: Socket::recv_from_vectored
586 ///
587 /// # Safety
588 ///
589 /// `recv_from_vectored` makes the same safety guarantees regarding `bufs`
590 /// as [`recv_vectored`].
591 ///
592 /// [`recv_vectored`]: Socket::recv_vectored
593 #[cfg(not(target_os = "redox"))]
594 #[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))]
595 pub fn recv_from_vectored_with_flags(
596 &self,
597 bufs: &mut [MaybeUninitSlice<'_>],
598 flags: c_int,
599 ) -> io::Result<(usize, RecvFlags, SockAddr)> {
600 sys::recv_from_vectored(self.as_raw(), bufs, flags)
601 }
602
603 /// Receives data from the socket, without removing it from the queue.
604 ///
605 /// Successive calls return the same data. This is accomplished by passing
606 /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call.
607 ///
608 /// On success, returns the number of bytes peeked and the address from
609 /// whence the data came.
610 ///
611 /// # Safety
612 ///
613 /// `peek_from` makes the same safety guarantees regarding the `buf`fer as
614 /// [`recv`].
615 ///
616 /// # Note: Datagram Sockets
617 /// For datagram sockets, the behavior of this method when `buf` is smaller than
618 /// the datagram at the head of the receive queue differs between Windows and
619 /// Unix-like platforms (Linux, macOS, BSDs, etc: colloquially termed "*nix").
620 ///
621 /// On *nix platforms, the datagram is truncated to the length of `buf`.
622 ///
623 /// On Windows, an error corresponding to `WSAEMSGSIZE` will be returned.
624 ///
625 /// For consistency between platforms, be sure to provide a sufficiently large buffer to avoid
626 /// truncation; the exact size required depends on the underlying protocol.
627 ///
628 /// If you just want to know the sender of the data, try [`peek_sender`].
629 ///
630 /// [`recv`]: Socket::recv
631 /// [`peek_sender`]: Socket::peek_sender
632 pub fn peek_from(&self, buf: &mut [MaybeUninit<u8>]) -> io::Result<(usize, SockAddr)> {
633 self.recv_from_with_flags(buf, sys::MSG_PEEK)
634 }
635
636 /// Retrieve the sender for the data at the head of the receive queue.
637 ///
638 /// This is equivalent to calling [`peek_from`] with a zero-sized buffer,
639 /// but suppresses the `WSAEMSGSIZE` error on Windows.
640 ///
641 /// [`peek_from`]: Socket::peek_from
642 pub fn peek_sender(&self) -> io::Result<SockAddr> {
643 sys::peek_sender(self.as_raw())
644 }
645
646 /// Receive a message from a socket using a message structure.
647 ///
648 /// This is not supported on Windows as calling `WSARecvMsg` (the `recvmsg`
649 /// equivalent) is not straight forward on Windows. See
650 /// <https://github.com/microsoft/Windows-classic-samples/blob/7cbd99ac1d2b4a0beffbaba29ea63d024ceff700/Samples/Win7Samples/netds/winsock/recvmsg/rmmc.cpp>
651 /// for an example (in C++).
652 #[doc = man_links!(recvmsg(2))]
653 #[cfg(all(unix, not(target_os = "redox")))]
654 #[cfg_attr(docsrs, doc(cfg(all(unix, not(target_os = "redox")))))]
655 pub fn recvmsg(&self, msg: &mut MsgHdrMut<'_, '_, '_>, flags: sys::c_int) -> io::Result<usize> {
656 sys::recvmsg(self.as_raw(), msg, flags)
657 }
658
659 /// Sends data on the socket to a connected peer.
660 ///
661 /// This is typically used on TCP sockets or datagram sockets which have
662 /// been connected.
663 ///
664 /// On success returns the number of bytes that were sent.
665 #[doc = man_links!(send(2))]
666 pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
667 self.send_with_flags(buf, 0)
668 }
669
670 /// Identical to [`send`] but allows for specification of arbitrary flags to the underlying
671 /// `send` call.
672 ///
673 /// [`send`]: Socket::send
674 pub fn send_with_flags(&self, buf: &[u8], flags: c_int) -> io::Result<usize> {
675 sys::send(self.as_raw(), buf, flags)
676 }
677
678 /// Send data to the connected peer. Returns the amount of bytes written.
679 #[cfg(not(target_os = "redox"))]
680 #[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))]
681 pub fn send_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
682 self.send_vectored_with_flags(bufs, 0)
683 }
684
685 /// Identical to [`send_vectored`] but allows for specification of arbitrary
686 /// flags to the underlying `sendmsg`/`WSASend` call.
687 #[doc = man_links!(sendmsg(2))]
688 ///
689 /// [`send_vectored`]: Socket::send_vectored
690 #[cfg(not(target_os = "redox"))]
691 #[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))]
692 pub fn send_vectored_with_flags(
693 &self,
694 bufs: &[IoSlice<'_>],
695 flags: c_int,
696 ) -> io::Result<usize> {
697 sys::send_vectored(self.as_raw(), bufs, flags)
698 }
699
700 /// Sends out-of-band (OOB) data on the socket to connected peer
701 /// by setting the `MSG_OOB` flag for this call.
702 ///
703 /// For more information, see [`send`], [`out_of_band_inline`].
704 ///
705 /// [`send`]: Socket::send
706 /// [`out_of_band_inline`]: Socket::out_of_band_inline
707 #[cfg_attr(target_os = "redox", allow(rustdoc::broken_intra_doc_links))]
708 pub fn send_out_of_band(&self, buf: &[u8]) -> io::Result<usize> {
709 self.send_with_flags(buf, sys::MSG_OOB)
710 }
711
712 /// Sends data on the socket to the given address. On success, returns the
713 /// number of bytes written.
714 ///
715 /// This is typically used on UDP or datagram-oriented sockets.
716 #[doc = man_links!(sendto(2))]
717 pub fn send_to(&self, buf: &[u8], addr: &SockAddr) -> io::Result<usize> {
718 self.send_to_with_flags(buf, addr, 0)
719 }
720
721 /// Identical to [`send_to`] but allows for specification of arbitrary flags
722 /// to the underlying `sendto` call.
723 ///
724 /// [`send_to`]: Socket::send_to
725 pub fn send_to_with_flags(
726 &self,
727 buf: &[u8],
728 addr: &SockAddr,
729 flags: c_int,
730 ) -> io::Result<usize> {
731 sys::send_to(self.as_raw(), buf, addr, flags)
732 }
733
734 /// Send data to a peer listening on `addr`. Returns the amount of bytes
735 /// written.
736 #[doc = man_links!(sendmsg(2))]
737 #[cfg(not(target_os = "redox"))]
738 #[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))]
739 pub fn send_to_vectored(&self, bufs: &[IoSlice<'_>], addr: &SockAddr) -> io::Result<usize> {
740 self.send_to_vectored_with_flags(bufs, addr, 0)
741 }
742
743 /// Identical to [`send_to_vectored`] but allows for specification of
744 /// arbitrary flags to the underlying `sendmsg`/`WSASendTo` call.
745 ///
746 /// [`send_to_vectored`]: Socket::send_to_vectored
747 #[cfg(not(target_os = "redox"))]
748 #[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))]
749 pub fn send_to_vectored_with_flags(
750 &self,
751 bufs: &[IoSlice<'_>],
752 addr: &SockAddr,
753 flags: c_int,
754 ) -> io::Result<usize> {
755 sys::send_to_vectored(self.as_raw(), bufs, addr, flags)
756 }
757
758 /// Send a message on a socket using a message structure.
759 #[doc = man_links!(sendmsg(2))]
760 #[cfg(not(target_os = "redox"))]
761 #[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))]
762 pub fn sendmsg(&self, msg: &MsgHdr<'_, '_, '_>, flags: sys::c_int) -> io::Result<usize> {
763 sys::sendmsg(self.as_raw(), msg, flags)
764 }
765}
766
767/// Set `SOCK_CLOEXEC` and `NO_HANDLE_INHERIT` on the `ty`pe on platforms that
768/// support it.
769#[inline(always)]
770const fn set_common_type(ty: Type) -> Type {
771 // On platforms that support it set `SOCK_CLOEXEC`.
772 #[cfg(any(
773 target_os = "android",
774 target_os = "dragonfly",
775 target_os = "freebsd",
776 target_os = "fuchsia",
777 target_os = "hurd",
778 target_os = "illumos",
779 target_os = "linux",
780 target_os = "netbsd",
781 target_os = "openbsd",
782 target_os = "cygwin",
783 ))]
784 let ty = ty._cloexec();
785
786 // On windows set `NO_HANDLE_INHERIT`.
787 #[cfg(windows)]
788 let ty = ty._no_inherit();
789
790 ty
791}
792
793/// Set `FD_CLOEXEC` and `NOSIGPIPE` on the `socket` for platforms that need it.
794#[inline(always)]
795#[allow(clippy::unnecessary_wraps)]
796fn set_common_flags(socket: Socket) -> io::Result<Socket> {
797 // On platforms that don't have `SOCK_CLOEXEC` use `FD_CLOEXEC`.
798 #[cfg(all(
799 unix,
800 not(any(
801 target_os = "android",
802 target_os = "dragonfly",
803 target_os = "freebsd",
804 target_os = "fuchsia",
805 target_os = "hurd",
806 target_os = "illumos",
807 target_os = "linux",
808 target_os = "netbsd",
809 target_os = "openbsd",
810 target_os = "espidf",
811 target_os = "vita",
812 target_os = "cygwin",
813 ))
814 ))]
815 socket._set_cloexec(true)?;
816
817 // On Apple platforms set `NOSIGPIPE`.
818 #[cfg(any(
819 target_os = "ios",
820 target_os = "visionos",
821 target_os = "macos",
822 target_os = "tvos",
823 target_os = "watchos",
824 ))]
825 socket._set_nosigpipe(true)?;
826
827 Ok(socket)
828}
829
830/// A local interface specified by its index or an address assigned to it.
831///
832/// `Index(0)` and `Address(Ipv4Addr::UNSPECIFIED)` are equivalent and indicate
833/// that an appropriate interface should be selected by the system.
834#[cfg(not(any(
835 target_os = "haiku",
836 target_os = "illumos",
837 target_os = "netbsd",
838 target_os = "redox",
839 target_os = "solaris",
840)))]
841#[derive(Debug)]
842pub enum InterfaceIndexOrAddress {
843 /// An interface index.
844 Index(u32),
845 /// An address assigned to an interface.
846 Address(Ipv4Addr),
847}
848
849/// Socket options get/set using `SOL_SOCKET`.
850///
851/// Additional documentation can be found in documentation of the OS.
852/// * Linux: <https://man7.org/linux/man-pages/man7/socket.7.html>
853/// * Windows: <https://docs.microsoft.com/en-us/windows/win32/winsock/sol-socket-socket-options>
854impl Socket {
855 /// Get the value of the `SO_BROADCAST` option for this socket.
856 ///
857 /// For more information about this option, see [`set_broadcast`].
858 ///
859 /// [`set_broadcast`]: Socket::set_broadcast
860 pub fn broadcast(&self) -> io::Result<bool> {
861 unsafe {
862 getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_BROADCAST)
863 .map(|broadcast| broadcast != 0)
864 }
865 }
866
867 /// Set the value of the `SO_BROADCAST` option for this socket.
868 ///
869 /// When enabled, this socket is allowed to send packets to a broadcast
870 /// address.
871 pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> {
872 unsafe {
873 setsockopt(
874 self.as_raw(),
875 sys::SOL_SOCKET,
876 sys::SO_BROADCAST,
877 broadcast as c_int,
878 )
879 }
880 }
881
882 /// Get the value of the `SO_ERROR` option on this socket.
883 ///
884 /// This will retrieve the stored error in the underlying socket, clearing
885 /// the field in the process. This can be useful for checking errors between
886 /// calls.
887 pub fn take_error(&self) -> io::Result<Option<io::Error>> {
888 match unsafe { getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_ERROR) } {
889 Ok(0) => Ok(None),
890 Ok(errno) => Ok(Some(io::Error::from_raw_os_error(errno))),
891 Err(err) => Err(err),
892 }
893 }
894
895 /// Get the value of the `SO_KEEPALIVE` option on this socket.
896 ///
897 /// For more information about this option, see [`set_keepalive`].
898 ///
899 /// [`set_keepalive`]: Socket::set_keepalive
900 pub fn keepalive(&self) -> io::Result<bool> {
901 unsafe {
902 getsockopt::<Bool>(self.as_raw(), sys::SOL_SOCKET, sys::SO_KEEPALIVE)
903 .map(|keepalive| keepalive != 0)
904 }
905 }
906
907 /// Set value for the `SO_KEEPALIVE` option on this socket.
908 ///
909 /// Enable sending of keep-alive messages on connection-oriented sockets.
910 pub fn set_keepalive(&self, keepalive: bool) -> io::Result<()> {
911 unsafe {
912 setsockopt(
913 self.as_raw(),
914 sys::SOL_SOCKET,
915 sys::SO_KEEPALIVE,
916 keepalive as c_int,
917 )
918 }
919 }
920
921 /// Get the value of the `SO_LINGER` option on this socket.
922 ///
923 /// For more information about this option, see [`set_linger`].
924 ///
925 /// [`set_linger`]: Socket::set_linger
926 pub fn linger(&self) -> io::Result<Option<Duration>> {
927 unsafe {
928 getsockopt::<sys::linger>(self.as_raw(), sys::SOL_SOCKET, sys::SO_LINGER)
929 .map(from_linger)
930 }
931 }
932
933 /// Set value for the `SO_LINGER` option on this socket.
934 ///
935 /// If `linger` is not `None`, a close(2) or shutdown(2) will not return
936 /// until all queued messages for the socket have been successfully sent or
937 /// the linger timeout has been reached. Otherwise, the call returns
938 /// immediately and the closing is done in the background. When the socket
939 /// is closed as part of exit(2), it always lingers in the background.
940 ///
941 /// # Notes
942 ///
943 /// On most OSs the duration only has a precision of seconds and will be
944 /// silently truncated.
945 ///
946 /// On Apple platforms (e.g. macOS, iOS, etc) this uses `SO_LINGER_SEC`.
947 pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
948 let linger = into_linger(linger);
949 unsafe { setsockopt(self.as_raw(), sys::SOL_SOCKET, sys::SO_LINGER, linger) }
950 }
951
952 /// Get value for the `SO_OOBINLINE` option on this socket.
953 ///
954 /// For more information about this option, see [`set_out_of_band_inline`].
955 ///
956 /// [`set_out_of_band_inline`]: Socket::set_out_of_band_inline
957 #[cfg(not(target_os = "redox"))]
958 #[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))]
959 pub fn out_of_band_inline(&self) -> io::Result<bool> {
960 unsafe {
961 getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_OOBINLINE)
962 .map(|oob_inline| oob_inline != 0)
963 }
964 }
965
966 /// Set value for the `SO_OOBINLINE` option on this socket.
967 ///
968 /// If this option is enabled, out-of-band data is directly placed into the
969 /// receive data stream. Otherwise, out-of-band data is passed only when the
970 /// `MSG_OOB` flag is set during receiving. As per RFC6093, TCP sockets
971 /// using the Urgent mechanism are encouraged to set this flag.
972 #[cfg(not(target_os = "redox"))]
973 #[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))]
974 pub fn set_out_of_band_inline(&self, oob_inline: bool) -> io::Result<()> {
975 unsafe {
976 setsockopt(
977 self.as_raw(),
978 sys::SOL_SOCKET,
979 sys::SO_OOBINLINE,
980 oob_inline as c_int,
981 )
982 }
983 }
984
985 /// Get value for the `SO_PASSCRED` option on this socket.
986 ///
987 /// For more information about this option, see [`set_passcred`].
988 ///
989 /// [`set_passcred`]: Socket::set_passcred
990 #[cfg(any(target_os = "linux", target_os = "cygwin"))]
991 #[cfg_attr(docsrs, doc(cfg(any(target_os = "linux", target_os = "cygwin"))))]
992 pub fn passcred(&self) -> io::Result<bool> {
993 unsafe {
994 getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_PASSCRED)
995 .map(|passcred| passcred != 0)
996 }
997 }
998
999 /// Set value for the `SO_PASSCRED` option on this socket.
1000 ///
1001 /// If this option is enabled, enables the receiving of the `SCM_CREDENTIALS`
1002 /// control messages.
1003 #[cfg(any(target_os = "linux", target_os = "cygwin"))]
1004 #[cfg_attr(docsrs, doc(cfg(any(target_os = "linux", target_os = "cygwin"))))]
1005 pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
1006 unsafe {
1007 setsockopt(
1008 self.as_raw(),
1009 sys::SOL_SOCKET,
1010 sys::SO_PASSCRED,
1011 passcred as c_int,
1012 )
1013 }
1014 }
1015
1016 /// Get value for the `SO_RCVBUF` option on this socket.
1017 ///
1018 /// For more information about this option, see [`set_recv_buffer_size`].
1019 ///
1020 /// [`set_recv_buffer_size`]: Socket::set_recv_buffer_size
1021 pub fn recv_buffer_size(&self) -> io::Result<usize> {
1022 unsafe {
1023 getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_RCVBUF)
1024 .map(|size| size as usize)
1025 }
1026 }
1027
1028 /// Set value for the `SO_RCVBUF` option on this socket.
1029 ///
1030 /// Changes the size of the operating system's receive buffer associated
1031 /// with the socket.
1032 pub fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> {
1033 unsafe {
1034 setsockopt(
1035 self.as_raw(),
1036 sys::SOL_SOCKET,
1037 sys::SO_RCVBUF,
1038 size as c_int,
1039 )
1040 }
1041 }
1042
1043 /// Get value for the `SO_RCVTIMEO` option on this socket.
1044 ///
1045 /// If the returned timeout is `None`, then `read` and `recv` calls will
1046 /// block indefinitely.
1047 pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
1048 sys::timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_RCVTIMEO)
1049 }
1050
1051 /// Set value for the `SO_RCVTIMEO` option on this socket.
1052 ///
1053 /// If `timeout` is `None`, then `read` and `recv` calls will block
1054 /// indefinitely.
1055 pub fn set_read_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
1056 sys::set_timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_RCVTIMEO, duration)
1057 }
1058
1059 /// Get the value of the `SO_REUSEADDR` option on this socket.
1060 ///
1061 /// For more information about this option, see [`set_reuse_address`].
1062 ///
1063 /// [`set_reuse_address`]: Socket::set_reuse_address
1064 pub fn reuse_address(&self) -> io::Result<bool> {
1065 unsafe {
1066 getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_REUSEADDR)
1067 .map(|reuse| reuse != 0)
1068 }
1069 }
1070
1071 /// Set value for the `SO_REUSEADDR` option on this socket.
1072 ///
1073 /// This indicates that further calls to `bind` may allow reuse of local
1074 /// addresses. For IPv4 sockets this means that a socket may bind even when
1075 /// there's a socket already listening on this port.
1076 pub fn set_reuse_address(&self, reuse: bool) -> io::Result<()> {
1077 unsafe {
1078 setsockopt(
1079 self.as_raw(),
1080 sys::SOL_SOCKET,
1081 sys::SO_REUSEADDR,
1082 reuse as c_int,
1083 )
1084 }
1085 }
1086
1087 /// Get the value of the `SO_SNDBUF` option on this socket.
1088 ///
1089 /// For more information about this option, see [`set_send_buffer_size`].
1090 ///
1091 /// [`set_send_buffer_size`]: Socket::set_send_buffer_size
1092 pub fn send_buffer_size(&self) -> io::Result<usize> {
1093 unsafe {
1094 getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_SNDBUF)
1095 .map(|size| size as usize)
1096 }
1097 }
1098
1099 /// Set value for the `SO_SNDBUF` option on this socket.
1100 ///
1101 /// Changes the size of the operating system's send buffer associated with
1102 /// the socket.
1103 pub fn set_send_buffer_size(&self, size: usize) -> io::Result<()> {
1104 unsafe {
1105 setsockopt(
1106 self.as_raw(),
1107 sys::SOL_SOCKET,
1108 sys::SO_SNDBUF,
1109 size as c_int,
1110 )
1111 }
1112 }
1113
1114 /// Get value for the `SO_SNDTIMEO` option on this socket.
1115 ///
1116 /// If the returned timeout is `None`, then `write` and `send` calls will
1117 /// block indefinitely.
1118 pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
1119 sys::timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_SNDTIMEO)
1120 }
1121
1122 /// Set value for the `SO_SNDTIMEO` option on this socket.
1123 ///
1124 /// If `timeout` is `None`, then `write` and `send` calls will block
1125 /// indefinitely.
1126 pub fn set_write_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
1127 sys::set_timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_SNDTIMEO, duration)
1128 }
1129}
1130
1131const fn from_linger(linger: sys::linger) -> Option<Duration> {
1132 if linger.l_onoff == 0 {
1133 None
1134 } else {
1135 Some(Duration::from_secs(linger.l_linger as u64))
1136 }
1137}
1138
1139const fn into_linger(duration: Option<Duration>) -> sys::linger {
1140 match duration {
1141 Some(duration) => sys::linger {
1142 l_onoff: 1,
1143 l_linger: duration.as_secs() as _,
1144 },
1145 None => sys::linger {
1146 l_onoff: 0,
1147 l_linger: 0,
1148 },
1149 }
1150}
1151
1152/// Socket options for IPv4 sockets, get/set using `IPPROTO_IP`.
1153///
1154/// Additional documentation can be found in documentation of the OS.
1155/// * Linux: <https://man7.org/linux/man-pages/man7/ip.7.html>
1156/// * Windows: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options>
1157impl Socket {
1158 /// This method is deprecated, use [`crate::Socket::header_included_v4`].
1159 #[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))]
1160 #[cfg_attr(
1161 docsrs,
1162 doc(cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf")))))
1163 )]
1164 #[deprecated = "Use `Socket::header_included_v4` instead"]
1165 pub fn header_included(&self) -> io::Result<bool> {
1166 self.header_included_v4()
1167 }
1168 /// Get the value of the `IP_HDRINCL` option on this socket.
1169 ///
1170 /// For more information about this option, see [`set_header_included`].
1171 ///
1172 /// [`set_header_included`]: Socket::set_header_included
1173 #[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))]
1174 #[cfg_attr(
1175 docsrs,
1176 doc(cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf")))))
1177 )]
1178 pub fn header_included_v4(&self) -> io::Result<bool> {
1179 unsafe {
1180 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_HDRINCL)
1181 .map(|included| included != 0)
1182 }
1183 }
1184
1185 /// This method is deprecated, use [`crate::Socket::set_header_included_v4`].
1186 #[cfg_attr(
1187 any(target_os = "fuchsia", target_os = "illumos", target_os = "solaris"),
1188 allow(rustdoc::broken_intra_doc_links)
1189 )]
1190 #[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))]
1191 #[cfg_attr(
1192 docsrs,
1193 doc(cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf")))))
1194 )]
1195 #[deprecated = "Use `Socket::set_header_included_v4` instead"]
1196 pub fn set_header_included(&self, included: bool) -> io::Result<()> {
1197 self.set_header_included_v4(included)
1198 }
1199
1200 /// Set the value of the `IP_HDRINCL` option on this socket.
1201 ///
1202 /// If enabled, the user supplies an IP header in front of the user data.
1203 /// Valid only for [`SOCK_RAW`] sockets; see [raw(7)] for more information.
1204 /// When this flag is enabled, the values set by `IP_OPTIONS`, [`IP_TTL`],
1205 /// and [`IP_TOS`] are ignored.
1206 ///
1207 /// [`SOCK_RAW`]: Type::RAW
1208 /// [raw(7)]: https://man7.org/linux/man-pages/man7/raw.7.html
1209 /// [`IP_TTL`]: Socket::set_ttl
1210 /// [`IP_TOS`]: Socket::set_tos
1211 #[cfg_attr(
1212 any(target_os = "fuchsia", target_os = "illumos", target_os = "solaris"),
1213 allow(rustdoc::broken_intra_doc_links)
1214 )]
1215 #[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))]
1216 #[cfg_attr(
1217 docsrs,
1218 doc(cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf")))))
1219 )]
1220 pub fn set_header_included_v4(&self, included: bool) -> io::Result<()> {
1221 unsafe {
1222 setsockopt(
1223 self.as_raw(),
1224 sys::IPPROTO_IP,
1225 sys::IP_HDRINCL,
1226 included as c_int,
1227 )
1228 }
1229 }
1230
1231 /// Get the value of the `IP_TRANSPARENT` option on this socket.
1232 ///
1233 /// For more information about this option, see [`set_ip_transparent`].
1234 ///
1235 /// [`set_ip_transparent`]: Socket::set_ip_transparent
1236 #[cfg(all(feature = "all", target_os = "linux"))]
1237 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
1238 pub fn ip_transparent(&self) -> io::Result<bool> {
1239 unsafe {
1240 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, libc::IP_TRANSPARENT)
1241 .map(|transparent| transparent != 0)
1242 }
1243 }
1244
1245 /// Set the value of the `IP_TRANSPARENT` option on this socket.
1246 ///
1247 /// Setting this boolean option enables transparent proxying
1248 /// on this socket. This socket option allows the calling
1249 /// application to bind to a nonlocal IP address and operate
1250 /// both as a client and a server with the foreign address as
1251 /// the local endpoint. NOTE: this requires that routing be
1252 /// set up in a way that packets going to the foreign address
1253 /// are routed through the TProxy box (i.e., the system
1254 /// hosting the application that employs the IP_TRANSPARENT
1255 /// socket option). Enabling this socket option requires
1256 /// superuser privileges (the `CAP_NET_ADMIN` capability).
1257 ///
1258 /// TProxy redirection with the iptables TPROXY target also
1259 /// requires that this option be set on the redirected socket.
1260 #[cfg(all(feature = "all", target_os = "linux"))]
1261 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
1262 pub fn set_ip_transparent(&self, transparent: bool) -> io::Result<()> {
1263 unsafe {
1264 setsockopt(
1265 self.as_raw(),
1266 sys::IPPROTO_IP,
1267 libc::IP_TRANSPARENT,
1268 transparent as c_int,
1269 )
1270 }
1271 }
1272
1273 /// Join a multicast group using `IP_ADD_MEMBERSHIP` option on this socket.
1274 ///
1275 /// This function specifies a new multicast group for this socket to join.
1276 /// The address must be a valid multicast address, and `interface` is the
1277 /// address of the local interface with which the system should join the
1278 /// multicast group. If it's [`Ipv4Addr::UNSPECIFIED`] (`INADDR_ANY`) then
1279 /// an appropriate interface is chosen by the system.
1280 pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
1281 let mreq = sys::IpMreq {
1282 imr_multiaddr: sys::to_in_addr(multiaddr),
1283 imr_interface: sys::to_in_addr(interface),
1284 };
1285 unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_ADD_MEMBERSHIP, mreq) }
1286 }
1287
1288 /// Leave a multicast group using `IP_DROP_MEMBERSHIP` option on this socket.
1289 ///
1290 /// For more information about this option, see [`join_multicast_v4`].
1291 ///
1292 /// [`join_multicast_v4`]: Socket::join_multicast_v4
1293 pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
1294 let mreq = sys::IpMreq {
1295 imr_multiaddr: sys::to_in_addr(multiaddr),
1296 imr_interface: sys::to_in_addr(interface),
1297 };
1298 unsafe {
1299 setsockopt(
1300 self.as_raw(),
1301 sys::IPPROTO_IP,
1302 sys::IP_DROP_MEMBERSHIP,
1303 mreq,
1304 )
1305 }
1306 }
1307
1308 /// Join a multicast group using `IP_ADD_MEMBERSHIP` option on this socket.
1309 ///
1310 /// This function specifies a new multicast group for this socket to join.
1311 /// The address must be a valid multicast address, and `interface` specifies
1312 /// the local interface with which the system should join the multicast
1313 /// group. See [`InterfaceIndexOrAddress`].
1314 #[cfg(not(any(
1315 target_os = "aix",
1316 target_os = "haiku",
1317 target_os = "illumos",
1318 target_os = "netbsd",
1319 target_os = "openbsd",
1320 target_os = "redox",
1321 target_os = "solaris",
1322 target_os = "nto",
1323 target_os = "espidf",
1324 target_os = "vita",
1325 target_os = "cygwin",
1326 )))]
1327 pub fn join_multicast_v4_n(
1328 &self,
1329 multiaddr: &Ipv4Addr,
1330 interface: &InterfaceIndexOrAddress,
1331 ) -> io::Result<()> {
1332 let mreqn = sys::to_mreqn(multiaddr, interface);
1333 unsafe {
1334 setsockopt(
1335 self.as_raw(),
1336 sys::IPPROTO_IP,
1337 sys::IP_ADD_MEMBERSHIP,
1338 mreqn,
1339 )
1340 }
1341 }
1342
1343 /// Leave a multicast group using `IP_DROP_MEMBERSHIP` option on this socket.
1344 ///
1345 /// For more information about this option, see [`join_multicast_v4_n`].
1346 ///
1347 /// [`join_multicast_v4_n`]: Socket::join_multicast_v4_n
1348 #[cfg(not(any(
1349 target_os = "aix",
1350 target_os = "haiku",
1351 target_os = "illumos",
1352 target_os = "netbsd",
1353 target_os = "openbsd",
1354 target_os = "redox",
1355 target_os = "solaris",
1356 target_os = "nto",
1357 target_os = "espidf",
1358 target_os = "vita",
1359 target_os = "cygwin",
1360 )))]
1361 pub fn leave_multicast_v4_n(
1362 &self,
1363 multiaddr: &Ipv4Addr,
1364 interface: &InterfaceIndexOrAddress,
1365 ) -> io::Result<()> {
1366 let mreqn = sys::to_mreqn(multiaddr, interface);
1367 unsafe {
1368 setsockopt(
1369 self.as_raw(),
1370 sys::IPPROTO_IP,
1371 sys::IP_DROP_MEMBERSHIP,
1372 mreqn,
1373 )
1374 }
1375 }
1376
1377 /// Join a multicast SSM channel using `IP_ADD_SOURCE_MEMBERSHIP` option on this socket.
1378 ///
1379 /// This function specifies a new multicast channel for this socket to join.
1380 /// The group must be a valid SSM group address, the source must be the address of the sender
1381 /// and `interface` is the address of the local interface with which the system should join the
1382 /// multicast group. If it's [`Ipv4Addr::UNSPECIFIED`] (`INADDR_ANY`) then
1383 /// an appropriate interface is chosen by the system.
1384 #[cfg(not(any(
1385 target_os = "dragonfly",
1386 target_os = "haiku",
1387 target_os = "hurd",
1388 target_os = "netbsd",
1389 target_os = "openbsd",
1390 target_os = "redox",
1391 target_os = "fuchsia",
1392 target_os = "nto",
1393 target_os = "espidf",
1394 target_os = "vita",
1395 )))]
1396 pub fn join_ssm_v4(
1397 &self,
1398 source: &Ipv4Addr,
1399 group: &Ipv4Addr,
1400 interface: &Ipv4Addr,
1401 ) -> io::Result<()> {
1402 let mreqs = sys::IpMreqSource {
1403 imr_multiaddr: sys::to_in_addr(group),
1404 imr_interface: sys::to_in_addr(interface),
1405 imr_sourceaddr: sys::to_in_addr(source),
1406 };
1407 unsafe {
1408 setsockopt(
1409 self.as_raw(),
1410 sys::IPPROTO_IP,
1411 sys::IP_ADD_SOURCE_MEMBERSHIP,
1412 mreqs,
1413 )
1414 }
1415 }
1416
1417 /// Leave a multicast group using `IP_DROP_SOURCE_MEMBERSHIP` option on this socket.
1418 ///
1419 /// For more information about this option, see [`join_ssm_v4`].
1420 ///
1421 /// [`join_ssm_v4`]: Socket::join_ssm_v4
1422 #[cfg(not(any(
1423 target_os = "dragonfly",
1424 target_os = "haiku",
1425 target_os = "hurd",
1426 target_os = "netbsd",
1427 target_os = "openbsd",
1428 target_os = "redox",
1429 target_os = "fuchsia",
1430 target_os = "nto",
1431 target_os = "espidf",
1432 target_os = "vita",
1433 )))]
1434 pub fn leave_ssm_v4(
1435 &self,
1436 source: &Ipv4Addr,
1437 group: &Ipv4Addr,
1438 interface: &Ipv4Addr,
1439 ) -> io::Result<()> {
1440 let mreqs = sys::IpMreqSource {
1441 imr_multiaddr: sys::to_in_addr(group),
1442 imr_interface: sys::to_in_addr(interface),
1443 imr_sourceaddr: sys::to_in_addr(source),
1444 };
1445 unsafe {
1446 setsockopt(
1447 self.as_raw(),
1448 sys::IPPROTO_IP,
1449 sys::IP_DROP_SOURCE_MEMBERSHIP,
1450 mreqs,
1451 )
1452 }
1453 }
1454
1455 /// Get the value of the `IP_MULTICAST_ALL` option for this socket.
1456 ///
1457 /// For more information about this option, see [`set_multicast_all_v4`].
1458 ///
1459 /// [`set_multicast_all_v4`]: Socket::set_multicast_all_v4
1460 #[cfg(all(feature = "all", target_os = "linux"))]
1461 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
1462 pub fn multicast_all_v4(&self) -> io::Result<bool> {
1463 unsafe {
1464 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, libc::IP_MULTICAST_ALL)
1465 .map(|all| all != 0)
1466 }
1467 }
1468
1469 /// Set the value of the `IP_MULTICAST_ALL` option for this socket.
1470 ///
1471 /// This option can be used to modify the delivery policy of
1472 /// multicast messages. The argument is a boolean
1473 /// (defaults to true). If set to true, the socket will receive
1474 /// messages from all the groups that have been joined
1475 /// globally on the whole system. Otherwise, it will deliver
1476 /// messages only from the groups that have been explicitly
1477 /// joined (for example via the `IP_ADD_MEMBERSHIP` option) on
1478 /// this particular socket.
1479 #[cfg(all(feature = "all", target_os = "linux"))]
1480 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
1481 pub fn set_multicast_all_v4(&self, all: bool) -> io::Result<()> {
1482 unsafe {
1483 setsockopt(
1484 self.as_raw(),
1485 sys::IPPROTO_IP,
1486 libc::IP_MULTICAST_ALL,
1487 all as c_int,
1488 )
1489 }
1490 }
1491
1492 /// Get the value of the `IP_MULTICAST_IF` option for this socket.
1493 ///
1494 /// For more information about this option, see [`set_multicast_if_v4`].
1495 ///
1496 /// [`set_multicast_if_v4`]: Socket::set_multicast_if_v4
1497 pub fn multicast_if_v4(&self) -> io::Result<Ipv4Addr> {
1498 unsafe {
1499 getsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_IF).map(sys::from_in_addr)
1500 }
1501 }
1502
1503 /// Set the value of the `IP_MULTICAST_IF` option for this socket.
1504 ///
1505 /// Specifies the interface to use for routing multicast packets.
1506 pub fn set_multicast_if_v4(&self, interface: &Ipv4Addr) -> io::Result<()> {
1507 let interface = sys::to_in_addr(interface);
1508 unsafe {
1509 setsockopt(
1510 self.as_raw(),
1511 sys::IPPROTO_IP,
1512 sys::IP_MULTICAST_IF,
1513 interface,
1514 )
1515 }
1516 }
1517
1518 /// Get the value of the `IP_MULTICAST_LOOP` option for this socket.
1519 ///
1520 /// For more information about this option, see [`set_multicast_loop_v4`].
1521 ///
1522 /// [`set_multicast_loop_v4`]: Socket::set_multicast_loop_v4
1523 pub fn multicast_loop_v4(&self) -> io::Result<bool> {
1524 unsafe {
1525 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_LOOP)
1526 .map(|loop_v4| loop_v4 != 0)
1527 }
1528 }
1529
1530 /// Set the value of the `IP_MULTICAST_LOOP` option for this socket.
1531 ///
1532 /// If enabled, multicast packets will be looped back to the local socket.
1533 /// Note that this may not have any affect on IPv6 sockets.
1534 pub fn set_multicast_loop_v4(&self, loop_v4: bool) -> io::Result<()> {
1535 unsafe {
1536 setsockopt(
1537 self.as_raw(),
1538 sys::IPPROTO_IP,
1539 sys::IP_MULTICAST_LOOP,
1540 loop_v4 as c_int,
1541 )
1542 }
1543 }
1544
1545 /// Get the value of the `IP_MULTICAST_TTL` option for this socket.
1546 ///
1547 /// For more information about this option, see [`set_multicast_ttl_v4`].
1548 ///
1549 /// [`set_multicast_ttl_v4`]: Socket::set_multicast_ttl_v4
1550 pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
1551 unsafe {
1552 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_TTL)
1553 .map(|ttl| ttl as u32)
1554 }
1555 }
1556
1557 /// Set the value of the `IP_MULTICAST_TTL` option for this socket.
1558 ///
1559 /// Indicates the time-to-live value of outgoing multicast packets for
1560 /// this socket. The default value is 1 which means that multicast packets
1561 /// don't leave the local network unless explicitly requested.
1562 ///
1563 /// Note that this may not have any affect on IPv6 sockets.
1564 pub fn set_multicast_ttl_v4(&self, ttl: u32) -> io::Result<()> {
1565 unsafe {
1566 setsockopt(
1567 self.as_raw(),
1568 sys::IPPROTO_IP,
1569 sys::IP_MULTICAST_TTL,
1570 ttl as c_int,
1571 )
1572 }
1573 }
1574
1575 /// Get the value of the `IP_TTL` option for this socket.
1576 ///
1577 /// For more information about this option, see [`set_ttl`].
1578 ///
1579 /// [`set_ttl`]: Socket::set_ttl
1580 pub fn ttl(&self) -> io::Result<u32> {
1581 unsafe {
1582 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_TTL).map(|ttl| ttl as u32)
1583 }
1584 }
1585
1586 /// Set the value of the `IP_TTL` option for this socket.
1587 ///
1588 /// This value sets the time-to-live field that is used in every packet sent
1589 /// from this socket.
1590 pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
1591 unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_TTL, ttl as c_int) }
1592 }
1593
1594 /// Set the value of the `IP_TOS` option for this socket.
1595 ///
1596 /// This value sets the type-of-service field that is used in every packet
1597 /// sent from this socket.
1598 ///
1599 /// NOTE: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options>
1600 /// documents that not all versions of windows support `IP_TOS`.
1601 #[cfg(not(any(
1602 target_os = "fuchsia",
1603 target_os = "redox",
1604 target_os = "solaris",
1605 target_os = "illumos",
1606 target_os = "haiku",
1607 )))]
1608 pub fn set_tos(&self, tos: u32) -> io::Result<()> {
1609 unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_TOS, tos as c_int) }
1610 }
1611
1612 /// Get the value of the `IP_TOS` option for this socket.
1613 ///
1614 /// For more information about this option, see [`set_tos`].
1615 ///
1616 /// NOTE: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options>
1617 /// documents that not all versions of windows support `IP_TOS`.
1618 ///
1619 /// [`set_tos`]: Socket::set_tos
1620 #[cfg(not(any(
1621 target_os = "fuchsia",
1622 target_os = "redox",
1623 target_os = "solaris",
1624 target_os = "illumos",
1625 target_os = "haiku",
1626 )))]
1627 pub fn tos(&self) -> io::Result<u32> {
1628 unsafe {
1629 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_TOS).map(|tos| tos as u32)
1630 }
1631 }
1632
1633 /// Set the value of the `IP_RECVTOS` option for this socket.
1634 ///
1635 /// If enabled, the `IP_TOS` ancillary message is passed with
1636 /// incoming packets. It contains a byte which specifies the
1637 /// Type of Service/Precedence field of the packet header.
1638 #[cfg(not(any(
1639 target_os = "aix",
1640 target_os = "dragonfly",
1641 target_os = "fuchsia",
1642 target_os = "hurd",
1643 target_os = "illumos",
1644 target_os = "netbsd",
1645 target_os = "openbsd",
1646 target_os = "redox",
1647 target_os = "solaris",
1648 target_os = "haiku",
1649 target_os = "nto",
1650 target_os = "espidf",
1651 target_os = "vita",
1652 target_os = "cygwin",
1653 )))]
1654 pub fn set_recv_tos(&self, recv_tos: bool) -> io::Result<()> {
1655 unsafe {
1656 setsockopt(
1657 self.as_raw(),
1658 sys::IPPROTO_IP,
1659 sys::IP_RECVTOS,
1660 recv_tos as c_int,
1661 )
1662 }
1663 }
1664
1665 /// Get the value of the `IP_RECVTOS` option for this socket.
1666 ///
1667 /// For more information about this option, see [`set_recv_tos`].
1668 ///
1669 /// [`set_recv_tos`]: Socket::set_recv_tos
1670 #[cfg(not(any(
1671 target_os = "aix",
1672 target_os = "dragonfly",
1673 target_os = "fuchsia",
1674 target_os = "hurd",
1675 target_os = "illumos",
1676 target_os = "netbsd",
1677 target_os = "openbsd",
1678 target_os = "redox",
1679 target_os = "solaris",
1680 target_os = "haiku",
1681 target_os = "nto",
1682 target_os = "espidf",
1683 target_os = "vita",
1684 target_os = "cygwin",
1685 )))]
1686 pub fn recv_tos(&self) -> io::Result<bool> {
1687 unsafe {
1688 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_RECVTOS)
1689 .map(|recv_tos| recv_tos > 0)
1690 }
1691 }
1692}
1693
1694/// Socket options for IPv6 sockets, get/set using `IPPROTO_IPV6`.
1695///
1696/// Additional documentation can be found in documentation of the OS.
1697/// * Linux: <https://man7.org/linux/man-pages/man7/ipv6.7.html>
1698/// * Windows: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ipv6-socket-options>
1699impl Socket {
1700 /// Get the value of the `IP_HDRINCL` option on this socket.
1701 ///
1702 /// For more information about this option, see [`set_header_included`].
1703 ///
1704 /// [`set_header_included`]: Socket::set_header_included
1705 #[cfg(all(
1706 feature = "all",
1707 not(any(
1708 target_os = "redox",
1709 target_os = "espidf",
1710 target_os = "openbsd",
1711 target_os = "freebsd",
1712 target_os = "dragonfly",
1713 target_os = "netbsd"
1714 ))
1715 ))]
1716 #[cfg_attr(
1717 docsrs,
1718 doc(cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf")))))
1719 )]
1720 pub fn header_included_v6(&self) -> io::Result<bool> {
1721 unsafe {
1722 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IP_HDRINCL)
1723 .map(|included| included != 0)
1724 }
1725 }
1726
1727 /// Set the value of the `IP_HDRINCL` option on this socket.
1728 ///
1729 /// If enabled, the user supplies an IP header in front of the user data.
1730 /// Valid only for [`SOCK_RAW`] sockets; see [raw(7)] for more information.
1731 /// When this flag is enabled, the values set by `IP_OPTIONS` are ignored.
1732 ///
1733 /// [`SOCK_RAW`]: Type::RAW
1734 /// [raw(7)]: https://man7.org/linux/man-pages/man7/raw.7.html
1735 #[cfg_attr(
1736 any(target_os = "fuchsia", target_os = "illumos", target_os = "solaris"),
1737 allow(rustdoc::broken_intra_doc_links)
1738 )]
1739 #[cfg(all(
1740 feature = "all",
1741 not(any(
1742 target_os = "redox",
1743 target_os = "espidf",
1744 target_os = "openbsd",
1745 target_os = "freebsd",
1746 target_os = "dragonfly",
1747 target_os = "netbsd"
1748 ))
1749 ))]
1750 #[cfg_attr(
1751 docsrs,
1752 doc(cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf")))))
1753 )]
1754 pub fn set_header_included_v6(&self, included: bool) -> io::Result<()> {
1755 unsafe {
1756 setsockopt(
1757 self.as_raw(),
1758 sys::IPPROTO_IPV6,
1759 sys::IP_HDRINCL,
1760 included as c_int,
1761 )
1762 }
1763 }
1764
1765 /// Join a multicast group using `IPV6_ADD_MEMBERSHIP` option on this socket.
1766 ///
1767 /// Some OSs use `IPV6_JOIN_GROUP` for this option.
1768 ///
1769 /// This function specifies a new multicast group for this socket to join.
1770 /// The address must be a valid multicast address, and `interface` is the
1771 /// index of the interface to join/leave (or 0 to indicate any interface).
1772 #[cfg(not(target_os = "nto"))]
1773 pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
1774 let mreq = sys::Ipv6Mreq {
1775 ipv6mr_multiaddr: sys::to_in6_addr(multiaddr),
1776 // NOTE: some OSs use `c_int`, others use `c_uint`.
1777 ipv6mr_interface: interface as _,
1778 };
1779 unsafe {
1780 setsockopt(
1781 self.as_raw(),
1782 sys::IPPROTO_IPV6,
1783 sys::IPV6_ADD_MEMBERSHIP,
1784 mreq,
1785 )
1786 }
1787 }
1788
1789 /// Leave a multicast group using `IPV6_DROP_MEMBERSHIP` option on this socket.
1790 ///
1791 /// Some OSs use `IPV6_LEAVE_GROUP` for this option.
1792 ///
1793 /// For more information about this option, see [`join_multicast_v6`].
1794 ///
1795 /// [`join_multicast_v6`]: Socket::join_multicast_v6
1796 #[cfg(not(target_os = "nto"))]
1797 pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
1798 let mreq = sys::Ipv6Mreq {
1799 ipv6mr_multiaddr: sys::to_in6_addr(multiaddr),
1800 // NOTE: some OSs use `c_int`, others use `c_uint`.
1801 ipv6mr_interface: interface as _,
1802 };
1803 unsafe {
1804 setsockopt(
1805 self.as_raw(),
1806 sys::IPPROTO_IPV6,
1807 sys::IPV6_DROP_MEMBERSHIP,
1808 mreq,
1809 )
1810 }
1811 }
1812
1813 /// Get the value of the `IPV6_MULTICAST_HOPS` option for this socket
1814 ///
1815 /// For more information about this option, see [`set_multicast_hops_v6`].
1816 ///
1817 /// [`set_multicast_hops_v6`]: Socket::set_multicast_hops_v6
1818 pub fn multicast_hops_v6(&self) -> io::Result<u32> {
1819 unsafe {
1820 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_HOPS)
1821 .map(|hops| hops as u32)
1822 }
1823 }
1824
1825 /// Set the value of the `IPV6_MULTICAST_HOPS` option for this socket
1826 ///
1827 /// Indicates the number of "routers" multicast packets will transit for
1828 /// this socket. The default value is 1 which means that multicast packets
1829 /// don't leave the local network unless explicitly requested.
1830 pub fn set_multicast_hops_v6(&self, hops: u32) -> io::Result<()> {
1831 unsafe {
1832 setsockopt(
1833 self.as_raw(),
1834 sys::IPPROTO_IPV6,
1835 sys::IPV6_MULTICAST_HOPS,
1836 hops as c_int,
1837 )
1838 }
1839 }
1840
1841 /// Get the value of the `IPV6_MULTICAST_ALL` option for this socket.
1842 ///
1843 /// For more information about this option, see [`set_multicast_all_v6`].
1844 ///
1845 /// [`set_multicast_all_v6`]: Socket::set_multicast_all_v6
1846 #[cfg(all(feature = "all", target_os = "linux"))]
1847 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
1848 pub fn multicast_all_v6(&self) -> io::Result<bool> {
1849 unsafe {
1850 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, libc::IPV6_MULTICAST_ALL)
1851 .map(|all| all != 0)
1852 }
1853 }
1854
1855 /// Set the value of the `IPV6_MULTICAST_ALL` option for this socket.
1856 ///
1857 /// This option can be used to modify the delivery policy of
1858 /// multicast messages. The argument is a boolean
1859 /// (defaults to true). If set to true, the socket will receive
1860 /// messages from all the groups that have been joined
1861 /// globally on the whole system. Otherwise, it will deliver
1862 /// messages only from the groups that have been explicitly
1863 /// joined (for example via the `IPV6_ADD_MEMBERSHIP` option) on
1864 /// this particular socket.
1865 #[cfg(all(feature = "all", target_os = "linux"))]
1866 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
1867 pub fn set_multicast_all_v6(&self, all: bool) -> io::Result<()> {
1868 unsafe {
1869 setsockopt(
1870 self.as_raw(),
1871 sys::IPPROTO_IPV6,
1872 libc::IPV6_MULTICAST_ALL,
1873 all as c_int,
1874 )
1875 }
1876 }
1877
1878 /// Get the value of the `IPV6_MULTICAST_IF` option for this socket.
1879 ///
1880 /// For more information about this option, see [`set_multicast_if_v6`].
1881 ///
1882 /// [`set_multicast_if_v6`]: Socket::set_multicast_if_v6
1883 pub fn multicast_if_v6(&self) -> io::Result<u32> {
1884 unsafe {
1885 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_IF)
1886 .map(|interface| interface as u32)
1887 }
1888 }
1889
1890 /// Set the value of the `IPV6_MULTICAST_IF` option for this socket.
1891 ///
1892 /// Specifies the interface to use for routing multicast packets. Unlike
1893 /// ipv4, this is generally required in ipv6 contexts where network routing
1894 /// prefixes may overlap.
1895 pub fn set_multicast_if_v6(&self, interface: u32) -> io::Result<()> {
1896 unsafe {
1897 setsockopt(
1898 self.as_raw(),
1899 sys::IPPROTO_IPV6,
1900 sys::IPV6_MULTICAST_IF,
1901 interface as c_int,
1902 )
1903 }
1904 }
1905
1906 /// Get the value of the `IPV6_MULTICAST_LOOP` option for this socket.
1907 ///
1908 /// For more information about this option, see [`set_multicast_loop_v6`].
1909 ///
1910 /// [`set_multicast_loop_v6`]: Socket::set_multicast_loop_v6
1911 pub fn multicast_loop_v6(&self) -> io::Result<bool> {
1912 unsafe {
1913 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_LOOP)
1914 .map(|loop_v6| loop_v6 != 0)
1915 }
1916 }
1917
1918 /// Set the value of the `IPV6_MULTICAST_LOOP` option for this socket.
1919 ///
1920 /// Controls whether this socket sees the multicast packets it sends itself.
1921 /// Note that this may not have any affect on IPv4 sockets.
1922 pub fn set_multicast_loop_v6(&self, loop_v6: bool) -> io::Result<()> {
1923 unsafe {
1924 setsockopt(
1925 self.as_raw(),
1926 sys::IPPROTO_IPV6,
1927 sys::IPV6_MULTICAST_LOOP,
1928 loop_v6 as c_int,
1929 )
1930 }
1931 }
1932
1933 /// Get the value of the `IPV6_UNICAST_HOPS` option for this socket.
1934 ///
1935 /// Specifies the hop limit for ipv6 unicast packets
1936 pub fn unicast_hops_v6(&self) -> io::Result<u32> {
1937 unsafe {
1938 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_UNICAST_HOPS)
1939 .map(|hops| hops as u32)
1940 }
1941 }
1942
1943 /// Set the value for the `IPV6_UNICAST_HOPS` option on this socket.
1944 ///
1945 /// Specifies the hop limit for ipv6 unicast packets
1946 pub fn set_unicast_hops_v6(&self, hops: u32) -> io::Result<()> {
1947 unsafe {
1948 setsockopt(
1949 self.as_raw(),
1950 sys::IPPROTO_IPV6,
1951 sys::IPV6_UNICAST_HOPS,
1952 hops as c_int,
1953 )
1954 }
1955 }
1956
1957 /// Get the value of the `IPV6_V6ONLY` option for this socket.
1958 ///
1959 /// For more information about this option, see [`set_only_v6`].
1960 ///
1961 /// [`set_only_v6`]: Socket::set_only_v6
1962 pub fn only_v6(&self) -> io::Result<bool> {
1963 unsafe {
1964 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_V6ONLY)
1965 .map(|only_v6| only_v6 != 0)
1966 }
1967 }
1968
1969 /// Set the value for the `IPV6_V6ONLY` option on this socket.
1970 ///
1971 /// If this is set to `true` then the socket is restricted to sending and
1972 /// receiving IPv6 packets only. In this case two IPv4 and IPv6 applications
1973 /// can bind the same port at the same time.
1974 ///
1975 /// If this is set to `false` then the socket can be used to send and
1976 /// receive packets from an IPv4-mapped IPv6 address.
1977 pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
1978 unsafe {
1979 setsockopt(
1980 self.as_raw(),
1981 sys::IPPROTO_IPV6,
1982 sys::IPV6_V6ONLY,
1983 only_v6 as c_int,
1984 )
1985 }
1986 }
1987
1988 /// Get the value of the `IPV6_RECVTCLASS` option for this socket.
1989 ///
1990 /// For more information about this option, see [`set_recv_tclass_v6`].
1991 ///
1992 /// [`set_recv_tclass_v6`]: Socket::set_recv_tclass_v6
1993 #[cfg(not(any(
1994 target_os = "dragonfly",
1995 target_os = "fuchsia",
1996 target_os = "illumos",
1997 target_os = "netbsd",
1998 target_os = "openbsd",
1999 target_os = "redox",
2000 target_os = "solaris",
2001 target_os = "haiku",
2002 target_os = "hurd",
2003 target_os = "espidf",
2004 target_os = "vita",
2005 )))]
2006 pub fn recv_tclass_v6(&self) -> io::Result<bool> {
2007 unsafe {
2008 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_RECVTCLASS)
2009 .map(|recv_tclass| recv_tclass > 0)
2010 }
2011 }
2012
2013 /// Set the value of the `IPV6_RECVTCLASS` option for this socket.
2014 ///
2015 /// If enabled, the `IPV6_TCLASS` ancillary message is passed with incoming
2016 /// packets. It contains a byte which specifies the traffic class field of
2017 /// the packet header.
2018 #[cfg(not(any(
2019 target_os = "dragonfly",
2020 target_os = "fuchsia",
2021 target_os = "illumos",
2022 target_os = "netbsd",
2023 target_os = "openbsd",
2024 target_os = "redox",
2025 target_os = "solaris",
2026 target_os = "haiku",
2027 target_os = "hurd",
2028 target_os = "espidf",
2029 target_os = "vita",
2030 )))]
2031 pub fn set_recv_tclass_v6(&self, recv_tclass: bool) -> io::Result<()> {
2032 unsafe {
2033 setsockopt(
2034 self.as_raw(),
2035 sys::IPPROTO_IPV6,
2036 sys::IPV6_RECVTCLASS,
2037 recv_tclass as c_int,
2038 )
2039 }
2040 }
2041
2042 /// Get the value of the `IPV6_RECVHOPLIMIT` option for this socket.
2043 ///
2044 /// For more information about this option, see [`set_recv_hoplimit_v6`].
2045 ///
2046 /// [`set_recv_hoplimit_v6`]: Socket::set_recv_hoplimit_v6
2047 #[cfg(all(
2048 feature = "all",
2049 not(any(
2050 windows,
2051 target_os = "dragonfly",
2052 target_os = "fuchsia",
2053 target_os = "illumos",
2054 target_os = "netbsd",
2055 target_os = "openbsd",
2056 target_os = "redox",
2057 target_os = "solaris",
2058 target_os = "haiku",
2059 target_os = "hurd",
2060 target_os = "espidf",
2061 target_os = "vita",
2062 target_os = "cygwin",
2063 ))
2064 ))]
2065 pub fn recv_hoplimit_v6(&self) -> io::Result<bool> {
2066 unsafe {
2067 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_RECVHOPLIMIT)
2068 .map(|recv_hoplimit| recv_hoplimit > 0)
2069 }
2070 }
2071 /// Set the value of the `IPV6_RECVHOPLIMIT` option for this socket.
2072 ///
2073 /// The received hop limit is returned as ancillary data by recvmsg()
2074 /// only if the application has enabled the IPV6_RECVHOPLIMIT socket
2075 /// option:
2076 #[cfg(all(
2077 feature = "all",
2078 not(any(
2079 windows,
2080 target_os = "dragonfly",
2081 target_os = "fuchsia",
2082 target_os = "illumos",
2083 target_os = "netbsd",
2084 target_os = "openbsd",
2085 target_os = "redox",
2086 target_os = "solaris",
2087 target_os = "haiku",
2088 target_os = "hurd",
2089 target_os = "espidf",
2090 target_os = "vita",
2091 target_os = "cygwin",
2092 ))
2093 ))]
2094 pub fn set_recv_hoplimit_v6(&self, recv_hoplimit: bool) -> io::Result<()> {
2095 unsafe {
2096 setsockopt(
2097 self.as_raw(),
2098 sys::IPPROTO_IPV6,
2099 sys::IPV6_RECVHOPLIMIT,
2100 recv_hoplimit as c_int,
2101 )
2102 }
2103 }
2104}
2105
2106/// Socket options for TCP sockets, get/set using `IPPROTO_TCP`.
2107///
2108/// Additional documentation can be found in documentation of the OS.
2109/// * Linux: <https://man7.org/linux/man-pages/man7/tcp.7.html>
2110/// * Windows: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-tcp-socket-options>
2111impl Socket {
2112 /// Get the value of the `TCP_KEEPIDLE` option on this socket.
2113 ///
2114 /// This returns the value of `TCP_KEEPALIVE` on macOS and iOS and `TCP_KEEPIDLE` on all other
2115 /// supported Unix operating systems.
2116 #[cfg(all(
2117 feature = "all",
2118 not(any(
2119 windows,
2120 target_os = "haiku",
2121 target_os = "openbsd",
2122 target_os = "vita"
2123 ))
2124 ))]
2125 #[cfg_attr(
2126 docsrs,
2127 doc(cfg(all(
2128 feature = "all",
2129 not(any(
2130 windows,
2131 target_os = "haiku",
2132 target_os = "openbsd",
2133 target_os = "vita"
2134 ))
2135 )))
2136 )]
2137 pub fn keepalive_time(&self) -> io::Result<Duration> {
2138 sys::keepalive_time(self.as_raw())
2139 }
2140
2141 /// Get the value of the `TCP_KEEPINTVL` option on this socket.
2142 ///
2143 /// For more information about this option, see [`set_tcp_keepalive`].
2144 ///
2145 /// [`set_tcp_keepalive`]: Socket::set_tcp_keepalive
2146 #[cfg(all(
2147 feature = "all",
2148 any(
2149 target_os = "android",
2150 target_os = "dragonfly",
2151 target_os = "freebsd",
2152 target_os = "fuchsia",
2153 target_os = "illumos",
2154 target_os = "ios",
2155 target_os = "visionos",
2156 target_os = "linux",
2157 target_os = "macos",
2158 target_os = "netbsd",
2159 target_os = "tvos",
2160 target_os = "watchos",
2161 target_os = "cygwin",
2162 )
2163 ))]
2164 #[cfg_attr(
2165 docsrs,
2166 doc(cfg(all(
2167 feature = "all",
2168 any(
2169 target_os = "android",
2170 target_os = "dragonfly",
2171 target_os = "freebsd",
2172 target_os = "fuchsia",
2173 target_os = "illumos",
2174 target_os = "ios",
2175 target_os = "visionos",
2176 target_os = "linux",
2177 target_os = "macos",
2178 target_os = "netbsd",
2179 target_os = "tvos",
2180 target_os = "watchos",
2181 )
2182 )))
2183 )]
2184 pub fn keepalive_interval(&self) -> io::Result<Duration> {
2185 unsafe {
2186 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_TCP, sys::TCP_KEEPINTVL)
2187 .map(|secs| Duration::from_secs(secs as u64))
2188 }
2189 }
2190
2191 /// Get the value of the `TCP_KEEPCNT` option on this socket.
2192 ///
2193 /// For more information about this option, see [`set_tcp_keepalive`].
2194 ///
2195 /// [`set_tcp_keepalive`]: Socket::set_tcp_keepalive
2196 #[cfg(all(
2197 feature = "all",
2198 any(
2199 target_os = "android",
2200 target_os = "dragonfly",
2201 target_os = "freebsd",
2202 target_os = "fuchsia",
2203 target_os = "illumos",
2204 target_os = "ios",
2205 target_os = "visionos",
2206 target_os = "linux",
2207 target_os = "macos",
2208 target_os = "netbsd",
2209 target_os = "tvos",
2210 target_os = "watchos",
2211 target_os = "cygwin",
2212 )
2213 ))]
2214 #[cfg_attr(
2215 docsrs,
2216 doc(cfg(all(
2217 feature = "all",
2218 any(
2219 target_os = "android",
2220 target_os = "dragonfly",
2221 target_os = "freebsd",
2222 target_os = "fuchsia",
2223 target_os = "illumos",
2224 target_os = "ios",
2225 target_os = "visionos",
2226 target_os = "linux",
2227 target_os = "macos",
2228 target_os = "netbsd",
2229 target_os = "tvos",
2230 target_os = "watchos",
2231 )
2232 )))
2233 )]
2234 pub fn keepalive_retries(&self) -> io::Result<u32> {
2235 unsafe {
2236 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_TCP, sys::TCP_KEEPCNT)
2237 .map(|retries| retries as u32)
2238 }
2239 }
2240
2241 /// Set parameters configuring TCP keepalive probes for this socket.
2242 ///
2243 /// The supported parameters depend on the operating system, and are
2244 /// configured using the [`TcpKeepalive`] struct. At a minimum, all systems
2245 /// support configuring the [keepalive time]: the time after which the OS
2246 /// will start sending keepalive messages on an idle connection.
2247 ///
2248 /// [keepalive time]: TcpKeepalive::with_time
2249 ///
2250 /// # Notes
2251 ///
2252 /// * This will enable `SO_KEEPALIVE` on this socket, if it is not already
2253 /// enabled.
2254 /// * On some platforms, such as Windows, any keepalive parameters *not*
2255 /// configured by the `TcpKeepalive` struct passed to this function may be
2256 /// overwritten with their default values. Therefore, this function should
2257 /// either only be called once per socket, or the same parameters should
2258 /// be passed every time it is called.
2259 ///
2260 /// # Examples
2261 ///
2262 /// ```
2263 /// use std::time::Duration;
2264 ///
2265 /// use socket2::{Socket, TcpKeepalive, Domain, Type};
2266 ///
2267 /// # fn main() -> std::io::Result<()> {
2268 /// let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?;
2269 /// let keepalive = TcpKeepalive::new()
2270 /// .with_time(Duration::from_secs(4));
2271 /// // Depending on the target operating system, we may also be able to
2272 /// // configure the keepalive probe interval and/or the number of
2273 /// // retries here as well.
2274 ///
2275 /// socket.set_tcp_keepalive(&keepalive)?;
2276 /// # Ok(()) }
2277 /// ```
2278 ///
2279 pub fn set_tcp_keepalive(&self, params: &TcpKeepalive) -> io::Result<()> {
2280 self.set_keepalive(true)?;
2281 sys::set_tcp_keepalive(self.as_raw(), params)
2282 }
2283
2284 /// Get the value of the `TCP_NODELAY` option on this socket.
2285 ///
2286 /// For more information about this option, see [`set_nodelay`].
2287 ///
2288 /// [`set_nodelay`]: Socket::set_nodelay
2289 pub fn nodelay(&self) -> io::Result<bool> {
2290 unsafe {
2291 getsockopt::<Bool>(self.as_raw(), sys::IPPROTO_TCP, sys::TCP_NODELAY)
2292 .map(|nodelay| nodelay != 0)
2293 }
2294 }
2295
2296 /// Set the value of the `TCP_NODELAY` option on this socket.
2297 ///
2298 /// If set, this option disables the Nagle algorithm. This means that
2299 /// segments are always sent as soon as possible, even if there is only a
2300 /// small amount of data. When not set, data is buffered until there is a
2301 /// sufficient amount to send out, thereby avoiding the frequent sending of
2302 /// small packets.
2303 pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
2304 unsafe {
2305 setsockopt(
2306 self.as_raw(),
2307 sys::IPPROTO_TCP,
2308 sys::TCP_NODELAY,
2309 nodelay as c_int,
2310 )
2311 }
2312 }
2313
2314 /// Get the value for the `SO_ORIGINAL_DST` option on this socket.
2315 #[cfg(all(
2316 feature = "all",
2317 any(
2318 target_os = "android",
2319 target_os = "fuchsia",
2320 target_os = "linux",
2321 target_os = "windows",
2322 )
2323 ))]
2324 #[cfg_attr(
2325 docsrs,
2326 doc(cfg(all(
2327 feature = "all",
2328 any(
2329 target_os = "android",
2330 target_os = "fuchsia",
2331 target_os = "linux",
2332 target_os = "windows",
2333 )
2334 )))
2335 )]
2336 pub fn original_dst(&self) -> io::Result<SockAddr> {
2337 sys::original_dst(self.as_raw())
2338 }
2339
2340 /// Get the value for the `IP6T_SO_ORIGINAL_DST` option on this socket.
2341 #[cfg(all(
2342 feature = "all",
2343 any(target_os = "android", target_os = "linux", target_os = "windows")
2344 ))]
2345 #[cfg_attr(
2346 docsrs,
2347 doc(cfg(all(
2348 feature = "all",
2349 any(target_os = "android", target_os = "linux", target_os = "windows")
2350 )))
2351 )]
2352 pub fn original_dst_ipv6(&self) -> io::Result<SockAddr> {
2353 sys::original_dst_ipv6(self.as_raw())
2354 }
2355}
2356
2357impl Read for Socket {
2358 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
2359 // Safety: the `recv` implementation promises not to write uninitialised
2360 // bytes to the `buf`fer, so this casting is safe.
2361 let buf = unsafe { &mut *(buf as *mut [u8] as *mut [MaybeUninit<u8>]) };
2362 self.recv(buf)
2363 }
2364
2365 #[cfg(not(target_os = "redox"))]
2366 fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
2367 // Safety: both `IoSliceMut` and `MaybeUninitSlice` promise to have the
2368 // same layout, that of `iovec`/`WSABUF`. Furthermore, `recv_vectored`
2369 // promises to not write unitialised bytes to the `bufs` and pass it
2370 // directly to the `recvmsg` system call, so this is safe.
2371 let bufs = unsafe { &mut *(bufs as *mut [IoSliceMut<'_>] as *mut [MaybeUninitSlice<'_>]) };
2372 self.recv_vectored(bufs).map(|(n, _)| n)
2373 }
2374}
2375
2376impl<'a> Read for &'a Socket {
2377 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
2378 // Safety: see other `Read::read` impl.
2379 let buf = unsafe { &mut *(buf as *mut [u8] as *mut [MaybeUninit<u8>]) };
2380 self.recv(buf)
2381 }
2382
2383 #[cfg(not(target_os = "redox"))]
2384 fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
2385 // Safety: see other `Read::read` impl.
2386 let bufs = unsafe { &mut *(bufs as *mut [IoSliceMut<'_>] as *mut [MaybeUninitSlice<'_>]) };
2387 self.recv_vectored(bufs).map(|(n, _)| n)
2388 }
2389}
2390
2391impl Write for Socket {
2392 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
2393 self.send(buf)
2394 }
2395
2396 #[cfg(not(target_os = "redox"))]
2397 fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
2398 self.send_vectored(bufs)
2399 }
2400
2401 fn flush(&mut self) -> io::Result<()> {
2402 Ok(())
2403 }
2404}
2405
2406impl<'a> Write for &'a Socket {
2407 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
2408 self.send(buf)
2409 }
2410
2411 #[cfg(not(target_os = "redox"))]
2412 fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
2413 self.send_vectored(bufs)
2414 }
2415
2416 fn flush(&mut self) -> io::Result<()> {
2417 Ok(())
2418 }
2419}
2420
2421impl fmt::Debug for Socket {
2422 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2423 f.debug_struct("Socket")
2424 .field("raw", &self.as_raw())
2425 .field("local_addr", &self.local_addr().ok())
2426 .field("peer_addr", &self.peer_addr().ok())
2427 .finish()
2428 }
2429}
2430
2431from!(net::TcpStream, Socket);
2432from!(net::TcpListener, Socket);
2433from!(net::UdpSocket, Socket);
2434from!(Socket, net::TcpStream);
2435from!(Socket, net::TcpListener);
2436from!(Socket, net::UdpSocket);