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