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