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_accept_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 address 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///
766/// Sockets created via `accept` should use `set_common_accept_flags` instead.
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/// Set `FD_CLOEXEC` on the `socket` for platforms that need it.
802///
803/// Unlike `set_common_flags` we don't set `NOSIGPIPE` as that is inherited from
804/// the listener. Furthermore, attempts to set it on a unix socket domain
805/// results in an error.
806#[cfg(not(any(
807 target_os = "android",
808 target_os = "dragonfly",
809 target_os = "freebsd",
810 target_os = "fuchsia",
811 target_os = "illumos",
812 target_os = "linux",
813 target_os = "netbsd",
814 target_os = "openbsd",
815 target_os = "cygwin",
816)))]
817fn set_common_accept_flags(socket: Socket) -> io::Result<Socket> {
818 // On platforms that don't have `SOCK_CLOEXEC` use `FD_CLOEXEC`.
819 #[cfg(all(
820 unix,
821 not(any(
822 target_os = "android",
823 target_os = "dragonfly",
824 target_os = "freebsd",
825 target_os = "fuchsia",
826 target_os = "hurd",
827 target_os = "illumos",
828 target_os = "linux",
829 target_os = "netbsd",
830 target_os = "openbsd",
831 target_os = "espidf",
832 target_os = "vita",
833 target_os = "cygwin",
834 ))
835 ))]
836 socket._set_cloexec(true)?;
837
838 Ok(socket)
839}
840
841/// A local interface specified by its index or an address assigned to it.
842///
843/// `Index(0)` and `Address(Ipv4Addr::UNSPECIFIED)` are equivalent and indicate
844/// that an appropriate interface should be selected by the system.
845#[cfg(not(any(
846 target_os = "haiku",
847 target_os = "illumos",
848 target_os = "netbsd",
849 target_os = "redox",
850 target_os = "solaris",
851)))]
852#[derive(Debug, Copy, Clone)]
853pub enum InterfaceIndexOrAddress {
854 /// An interface index.
855 Index(u32),
856 /// An address assigned to an interface.
857 Address(Ipv4Addr),
858}
859
860/// Socket options get/set using `SOL_SOCKET`.
861///
862/// Additional documentation can be found in documentation of the OS.
863/// * Linux: <https://man7.org/linux/man-pages/man7/socket.7.html>
864/// * Windows: <https://docs.microsoft.com/en-us/windows/win32/winsock/sol-socket-socket-options>
865impl Socket {
866 /// Get the value of the `SO_BROADCAST` option for this socket.
867 ///
868 /// For more information about this option, see [`set_broadcast`].
869 ///
870 /// [`set_broadcast`]: Socket::set_broadcast
871 pub fn broadcast(&self) -> io::Result<bool> {
872 unsafe {
873 getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_BROADCAST)
874 .map(|broadcast| broadcast != 0)
875 }
876 }
877
878 /// Set the value of the `SO_BROADCAST` option for this socket.
879 ///
880 /// When enabled, this socket is allowed to send packets to a broadcast
881 /// address.
882 pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> {
883 unsafe {
884 setsockopt(
885 self.as_raw(),
886 sys::SOL_SOCKET,
887 sys::SO_BROADCAST,
888 broadcast as c_int,
889 )
890 }
891 }
892
893 /// Get the value of the `SO_ERROR` option on this socket.
894 ///
895 /// This will retrieve the stored error in the underlying socket, clearing
896 /// the field in the process. This can be useful for checking errors between
897 /// calls.
898 pub fn take_error(&self) -> io::Result<Option<io::Error>> {
899 match unsafe { getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_ERROR) } {
900 Ok(0) => Ok(None),
901 Ok(errno) => Ok(Some(io::Error::from_raw_os_error(errno))),
902 Err(err) => Err(err),
903 }
904 }
905
906 /// Get the value of the `SO_KEEPALIVE` option on this socket.
907 ///
908 /// For more information about this option, see [`set_keepalive`].
909 ///
910 /// [`set_keepalive`]: Socket::set_keepalive
911 pub fn keepalive(&self) -> io::Result<bool> {
912 unsafe {
913 getsockopt::<Bool>(self.as_raw(), sys::SOL_SOCKET, sys::SO_KEEPALIVE)
914 .map(|keepalive| keepalive != false as Bool)
915 }
916 }
917
918 /// Set value for the `SO_KEEPALIVE` option on this socket.
919 ///
920 /// Enable sending of keep-alive messages on connection-oriented sockets.
921 pub fn set_keepalive(&self, keepalive: bool) -> io::Result<()> {
922 unsafe {
923 setsockopt(
924 self.as_raw(),
925 sys::SOL_SOCKET,
926 sys::SO_KEEPALIVE,
927 keepalive as c_int,
928 )
929 }
930 }
931
932 /// Get the value of the `SO_LINGER` option on this socket.
933 ///
934 /// For more information about this option, see [`set_linger`].
935 ///
936 /// [`set_linger`]: Socket::set_linger
937 pub fn linger(&self) -> io::Result<Option<Duration>> {
938 unsafe {
939 getsockopt::<sys::linger>(self.as_raw(), sys::SOL_SOCKET, sys::SO_LINGER)
940 .map(from_linger)
941 }
942 }
943
944 /// Set value for the `SO_LINGER` option on this socket.
945 ///
946 /// If `linger` is not `None`, a close(2) or shutdown(2) will not return
947 /// until all queued messages for the socket have been successfully sent or
948 /// the linger timeout has been reached. Otherwise, the call returns
949 /// immediately and the closing is done in the background. When the socket
950 /// is closed as part of exit(2), it always lingers in the background.
951 ///
952 /// # Notes
953 ///
954 /// On most OSs the duration only has a precision of seconds and will be
955 /// silently truncated.
956 ///
957 /// On Apple platforms (e.g. macOS, iOS, etc) this uses `SO_LINGER_SEC`.
958 pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
959 let linger = into_linger(linger);
960 unsafe { setsockopt(self.as_raw(), sys::SOL_SOCKET, sys::SO_LINGER, linger) }
961 }
962
963 /// Get value for the `SO_OOBINLINE` option on this socket.
964 ///
965 /// For more information about this option, see [`set_out_of_band_inline`].
966 ///
967 /// [`set_out_of_band_inline`]: Socket::set_out_of_band_inline
968 #[cfg(not(target_os = "redox"))]
969 pub fn out_of_band_inline(&self) -> io::Result<bool> {
970 unsafe {
971 getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_OOBINLINE)
972 .map(|oob_inline| oob_inline != 0)
973 }
974 }
975
976 /// Set value for the `SO_OOBINLINE` option on this socket.
977 ///
978 /// If this option is enabled, out-of-band data is directly placed into the
979 /// receive data stream. Otherwise, out-of-band data is passed only when the
980 /// `MSG_OOB` flag is set during receiving. As per RFC6093, TCP sockets
981 /// using the Urgent mechanism are encouraged to set this flag.
982 #[cfg(not(target_os = "redox"))]
983 pub fn set_out_of_band_inline(&self, oob_inline: bool) -> io::Result<()> {
984 unsafe {
985 setsockopt(
986 self.as_raw(),
987 sys::SOL_SOCKET,
988 sys::SO_OOBINLINE,
989 oob_inline as c_int,
990 )
991 }
992 }
993
994 /// Get value for the `SO_PASSCRED` option on this socket.
995 ///
996 /// For more information about this option, see [`set_passcred`].
997 ///
998 /// [`set_passcred`]: Socket::set_passcred
999 #[cfg(any(target_os = "linux", target_os = "cygwin"))]
1000 pub fn passcred(&self) -> io::Result<bool> {
1001 unsafe {
1002 getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_PASSCRED)
1003 .map(|passcred| passcred != 0)
1004 }
1005 }
1006
1007 /// Set value for the `SO_PASSCRED` option on this socket.
1008 ///
1009 /// If this option is enabled, enables the receiving of the `SCM_CREDENTIALS`
1010 /// control messages.
1011 #[cfg(any(target_os = "linux", target_os = "cygwin"))]
1012 pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
1013 unsafe {
1014 setsockopt(
1015 self.as_raw(),
1016 sys::SOL_SOCKET,
1017 sys::SO_PASSCRED,
1018 passcred as c_int,
1019 )
1020 }
1021 }
1022
1023 /// Get value for the `SO_PRIORITY` option on this socket.
1024 ///
1025 /// For more information about this option, see [`set_priority`].
1026 ///
1027 /// [`set_priority`]: Socket::set_priority
1028 #[cfg(all(
1029 feature = "all",
1030 any(target_os = "linux", target_os = "android", target_os = "fuchsia")
1031 ))]
1032 pub fn priority(&self) -> io::Result<u32> {
1033 unsafe {
1034 getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_PRIORITY)
1035 .map(|prio| prio as u32)
1036 }
1037 }
1038
1039 /// Set value for the `SO_PRIORITY` option on this socket.
1040 ///
1041 /// Packets with a higher priority may be processed earlier depending on the selected device
1042 /// queueing discipline.
1043 #[cfg(all(
1044 feature = "all",
1045 any(target_os = "linux", target_os = "android", target_os = "fuchsia")
1046 ))]
1047 pub fn set_priority(&self, priority: u32) -> io::Result<()> {
1048 unsafe {
1049 setsockopt(
1050 self.as_raw(),
1051 sys::SOL_SOCKET,
1052 sys::SO_PRIORITY,
1053 priority as c_int,
1054 )
1055 }
1056 }
1057
1058 /// Get value for the `SO_RCVBUF` option on this socket.
1059 ///
1060 /// For more information about this option, see [`set_recv_buffer_size`].
1061 ///
1062 /// [`set_recv_buffer_size`]: Socket::set_recv_buffer_size
1063 pub fn recv_buffer_size(&self) -> io::Result<usize> {
1064 unsafe {
1065 getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_RCVBUF)
1066 .map(|size| size as usize)
1067 }
1068 }
1069
1070 /// Set value for the `SO_RCVBUF` option on this socket.
1071 ///
1072 /// Changes the size of the operating system's receive buffer associated
1073 /// with the socket.
1074 pub fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> {
1075 unsafe {
1076 setsockopt(
1077 self.as_raw(),
1078 sys::SOL_SOCKET,
1079 sys::SO_RCVBUF,
1080 size as c_int,
1081 )
1082 }
1083 }
1084
1085 /// Get value for the `SO_RCVTIMEO` option on this socket.
1086 ///
1087 /// If the returned timeout is `None`, then `read` and `recv` calls will
1088 /// block indefinitely.
1089 pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
1090 sys::timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_RCVTIMEO)
1091 }
1092
1093 /// Set value for the `SO_RCVTIMEO` option on this socket.
1094 ///
1095 /// If `timeout` is `None`, then `read` and `recv` calls will block
1096 /// indefinitely.
1097 pub fn set_read_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
1098 sys::set_timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_RCVTIMEO, duration)
1099 }
1100
1101 /// Get the value of the `SO_REUSEADDR` option on this socket.
1102 ///
1103 /// For more information about this option, see [`set_reuse_address`].
1104 ///
1105 /// [`set_reuse_address`]: Socket::set_reuse_address
1106 pub fn reuse_address(&self) -> io::Result<bool> {
1107 unsafe {
1108 getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_REUSEADDR)
1109 .map(|reuse| reuse != 0)
1110 }
1111 }
1112
1113 /// Set value for the `SO_REUSEADDR` option on this socket.
1114 ///
1115 /// This indicates that further calls to `bind` may allow reuse of local
1116 /// addresses. For IPv4 sockets this means that a socket may bind even when
1117 /// there's a socket already listening on this port.
1118 pub fn set_reuse_address(&self, reuse: bool) -> io::Result<()> {
1119 unsafe {
1120 setsockopt(
1121 self.as_raw(),
1122 sys::SOL_SOCKET,
1123 sys::SO_REUSEADDR,
1124 reuse as c_int,
1125 )
1126 }
1127 }
1128
1129 /// Get the value of the `SO_SNDBUF` option on this socket.
1130 ///
1131 /// For more information about this option, see [`set_send_buffer_size`].
1132 ///
1133 /// [`set_send_buffer_size`]: Socket::set_send_buffer_size
1134 pub fn send_buffer_size(&self) -> io::Result<usize> {
1135 unsafe {
1136 getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_SNDBUF)
1137 .map(|size| size as usize)
1138 }
1139 }
1140
1141 /// Set value for the `SO_SNDBUF` option on this socket.
1142 ///
1143 /// Changes the size of the operating system's send buffer associated with
1144 /// the socket.
1145 pub fn set_send_buffer_size(&self, size: usize) -> io::Result<()> {
1146 unsafe {
1147 setsockopt(
1148 self.as_raw(),
1149 sys::SOL_SOCKET,
1150 sys::SO_SNDBUF,
1151 size as c_int,
1152 )
1153 }
1154 }
1155
1156 /// Get value for the `SO_SNDTIMEO` option on this socket.
1157 ///
1158 /// If the returned timeout is `None`, then `write` and `send` calls will
1159 /// block indefinitely.
1160 pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
1161 sys::timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_SNDTIMEO)
1162 }
1163
1164 /// Set value for the `SO_SNDTIMEO` option on this socket.
1165 ///
1166 /// If `timeout` is `None`, then `write` and `send` calls will block
1167 /// indefinitely.
1168 pub fn set_write_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
1169 sys::set_timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_SNDTIMEO, duration)
1170 }
1171}
1172
1173const fn from_linger(linger: sys::linger) -> Option<Duration> {
1174 if linger.l_onoff == 0 {
1175 None
1176 } else {
1177 Some(Duration::from_secs(linger.l_linger as u64))
1178 }
1179}
1180
1181const fn into_linger(duration: Option<Duration>) -> sys::linger {
1182 match duration {
1183 Some(duration) => sys::linger {
1184 l_onoff: 1,
1185 l_linger: duration.as_secs() as _,
1186 },
1187 None => sys::linger {
1188 l_onoff: 0,
1189 l_linger: 0,
1190 },
1191 }
1192}
1193
1194/// Socket options for IPv4 sockets, get/set using `IPPROTO_IP` or `SOL_IP`.
1195///
1196/// Additional documentation can be found in documentation of the OS.
1197/// * Linux: <https://man7.org/linux/man-pages/man7/ip.7.html>
1198/// * Windows: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options>
1199impl Socket {
1200 /// Get the value of the `IP_HDRINCL` option on this socket.
1201 ///
1202 /// For more information about this option, see [`set_header_included_v4`].
1203 ///
1204 /// [`set_header_included_v4`]: Socket::set_header_included_v4
1205 #[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))]
1206 pub fn header_included_v4(&self) -> io::Result<bool> {
1207 unsafe {
1208 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_HDRINCL)
1209 .map(|included| included != 0)
1210 }
1211 }
1212
1213 /// Set the value of the `IP_HDRINCL` option on this socket.
1214 ///
1215 /// If enabled, the user supplies an IP header in front of the user data.
1216 /// Valid only for [`SOCK_RAW`] sockets; see [raw(7)] for more information.
1217 /// When this flag is enabled, the values set by `IP_OPTIONS`, [`IP_TTL`],
1218 /// and [`IP_TOS`] are ignored.
1219 ///
1220 /// [`SOCK_RAW`]: Type::RAW
1221 /// [raw(7)]: https://man7.org/linux/man-pages/man7/raw.7.html
1222 /// [`IP_TTL`]: Socket::set_ttl_v4
1223 /// [`IP_TOS`]: Socket::set_tos_v4
1224 #[cfg_attr(
1225 any(target_os = "fuchsia", target_os = "illumos", target_os = "solaris"),
1226 allow(rustdoc::broken_intra_doc_links)
1227 )]
1228 #[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))]
1229 pub fn set_header_included_v4(&self, included: bool) -> io::Result<()> {
1230 unsafe {
1231 setsockopt(
1232 self.as_raw(),
1233 sys::IPPROTO_IP,
1234 sys::IP_HDRINCL,
1235 included as c_int,
1236 )
1237 }
1238 }
1239
1240 /// Get the value of the `IP_TRANSPARENT` option on this socket.
1241 ///
1242 /// For more information about this option, see [`set_ip_transparent_v4`].
1243 ///
1244 /// [`set_ip_transparent_v4`]: Socket::set_ip_transparent_v4
1245 #[cfg(all(feature = "all", target_os = "linux"))]
1246 pub fn ip_transparent_v4(&self) -> io::Result<bool> {
1247 unsafe {
1248 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, libc::IP_TRANSPARENT)
1249 .map(|transparent| transparent != 0)
1250 }
1251 }
1252
1253 /// Set the value of the `IP_TRANSPARENT` option on this socket.
1254 ///
1255 /// Setting this boolean option enables transparent proxying
1256 /// on this socket. This socket option allows the calling
1257 /// application to bind to a nonlocal IP address and operate
1258 /// both as a client and a server with the foreign address as
1259 /// the local endpoint. NOTE: this requires that routing be
1260 /// set up in a way that packets going to the foreign address
1261 /// are routed through the TProxy box (i.e., the system
1262 /// hosting the application that employs the IP_TRANSPARENT
1263 /// socket option). Enabling this socket option requires
1264 /// superuser privileges (the `CAP_NET_ADMIN` capability).
1265 ///
1266 /// TProxy redirection with the iptables TPROXY target also
1267 /// requires that this option be set on the redirected socket.
1268 #[cfg(all(feature = "all", target_os = "linux"))]
1269 pub fn set_ip_transparent_v4(&self, transparent: bool) -> io::Result<()> {
1270 unsafe {
1271 setsockopt(
1272 self.as_raw(),
1273 sys::IPPROTO_IP,
1274 libc::IP_TRANSPARENT,
1275 transparent as c_int,
1276 )
1277 }
1278 }
1279
1280 /// Join a multicast group using `IP_ADD_MEMBERSHIP` option on this socket.
1281 ///
1282 /// This function specifies a new multicast group for this socket to join.
1283 /// The address must be a valid multicast address, and `interface` is the
1284 /// address of the local interface with which the system should join the
1285 /// multicast group. If it's [`Ipv4Addr::UNSPECIFIED`] (`INADDR_ANY`) then
1286 /// an appropriate interface is chosen by the system.
1287 pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
1288 let mreq = sys::IpMreq {
1289 imr_multiaddr: sys::to_in_addr(multiaddr),
1290 imr_interface: sys::to_in_addr(interface),
1291 };
1292 unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_ADD_MEMBERSHIP, mreq) }
1293 }
1294
1295 /// Leave a multicast group using `IP_DROP_MEMBERSHIP` option on this socket.
1296 ///
1297 /// For more information about this option, see [`join_multicast_v4`].
1298 ///
1299 /// [`join_multicast_v4`]: Socket::join_multicast_v4
1300 pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
1301 let mreq = sys::IpMreq {
1302 imr_multiaddr: sys::to_in_addr(multiaddr),
1303 imr_interface: sys::to_in_addr(interface),
1304 };
1305 unsafe {
1306 setsockopt(
1307 self.as_raw(),
1308 sys::IPPROTO_IP,
1309 sys::IP_DROP_MEMBERSHIP,
1310 mreq,
1311 )
1312 }
1313 }
1314
1315 /// Join a multicast group using `IP_ADD_MEMBERSHIP` option on this socket.
1316 ///
1317 /// This function specifies a new multicast group for this socket to join.
1318 /// The address must be a valid multicast address, and `interface` specifies
1319 /// the local interface with which the system should join the multicast
1320 /// group. See [`InterfaceIndexOrAddress`].
1321 #[cfg(not(any(
1322 target_os = "aix",
1323 target_os = "haiku",
1324 target_os = "illumos",
1325 target_os = "netbsd",
1326 target_os = "openbsd",
1327 target_os = "redox",
1328 target_os = "solaris",
1329 target_os = "nto",
1330 target_os = "espidf",
1331 target_os = "vita",
1332 target_os = "cygwin",
1333 )))]
1334 pub fn join_multicast_v4_n(
1335 &self,
1336 multiaddr: &Ipv4Addr,
1337 interface: &InterfaceIndexOrAddress,
1338 ) -> io::Result<()> {
1339 let mreqn = sys::to_mreqn(multiaddr, interface);
1340 unsafe {
1341 setsockopt(
1342 self.as_raw(),
1343 sys::IPPROTO_IP,
1344 sys::IP_ADD_MEMBERSHIP,
1345 mreqn,
1346 )
1347 }
1348 }
1349
1350 /// Leave a multicast group using `IP_DROP_MEMBERSHIP` option on this socket.
1351 ///
1352 /// For more information about this option, see [`join_multicast_v4_n`].
1353 ///
1354 /// [`join_multicast_v4_n`]: Socket::join_multicast_v4_n
1355 #[cfg(not(any(
1356 target_os = "aix",
1357 target_os = "haiku",
1358 target_os = "illumos",
1359 target_os = "netbsd",
1360 target_os = "openbsd",
1361 target_os = "redox",
1362 target_os = "solaris",
1363 target_os = "nto",
1364 target_os = "espidf",
1365 target_os = "vita",
1366 target_os = "cygwin",
1367 )))]
1368 pub fn leave_multicast_v4_n(
1369 &self,
1370 multiaddr: &Ipv4Addr,
1371 interface: &InterfaceIndexOrAddress,
1372 ) -> io::Result<()> {
1373 let mreqn = sys::to_mreqn(multiaddr, interface);
1374 unsafe {
1375 setsockopt(
1376 self.as_raw(),
1377 sys::IPPROTO_IP,
1378 sys::IP_DROP_MEMBERSHIP,
1379 mreqn,
1380 )
1381 }
1382 }
1383
1384 /// Join a multicast SSM channel using `IP_ADD_SOURCE_MEMBERSHIP` option on this socket.
1385 ///
1386 /// This function specifies a new multicast channel for this socket to join.
1387 /// The group must be a valid SSM group address, the source must be the address of the sender
1388 /// and `interface` is the address of the local interface with which the system should join the
1389 /// multicast group. If it's [`Ipv4Addr::UNSPECIFIED`] (`INADDR_ANY`) then
1390 /// an appropriate interface is chosen by the system.
1391 #[cfg(not(any(
1392 target_os = "dragonfly",
1393 target_os = "haiku",
1394 target_os = "hurd",
1395 target_os = "netbsd",
1396 target_os = "openbsd",
1397 target_os = "redox",
1398 target_os = "fuchsia",
1399 target_os = "nto",
1400 target_os = "espidf",
1401 target_os = "vita",
1402 )))]
1403 pub fn join_ssm_v4(
1404 &self,
1405 source: &Ipv4Addr,
1406 group: &Ipv4Addr,
1407 interface: &Ipv4Addr,
1408 ) -> io::Result<()> {
1409 let mreqs = sys::IpMreqSource {
1410 imr_multiaddr: sys::to_in_addr(group),
1411 imr_interface: sys::to_in_addr(interface),
1412 imr_sourceaddr: sys::to_in_addr(source),
1413 };
1414 unsafe {
1415 setsockopt(
1416 self.as_raw(),
1417 sys::IPPROTO_IP,
1418 sys::IP_ADD_SOURCE_MEMBERSHIP,
1419 mreqs,
1420 )
1421 }
1422 }
1423
1424 /// Leave a multicast group using `IP_DROP_SOURCE_MEMBERSHIP` option on this socket.
1425 ///
1426 /// For more information about this option, see [`join_ssm_v4`].
1427 ///
1428 /// [`join_ssm_v4`]: Socket::join_ssm_v4
1429 #[cfg(not(any(
1430 target_os = "dragonfly",
1431 target_os = "haiku",
1432 target_os = "hurd",
1433 target_os = "netbsd",
1434 target_os = "openbsd",
1435 target_os = "redox",
1436 target_os = "fuchsia",
1437 target_os = "nto",
1438 target_os = "espidf",
1439 target_os = "vita",
1440 )))]
1441 pub fn leave_ssm_v4(
1442 &self,
1443 source: &Ipv4Addr,
1444 group: &Ipv4Addr,
1445 interface: &Ipv4Addr,
1446 ) -> io::Result<()> {
1447 let mreqs = sys::IpMreqSource {
1448 imr_multiaddr: sys::to_in_addr(group),
1449 imr_interface: sys::to_in_addr(interface),
1450 imr_sourceaddr: sys::to_in_addr(source),
1451 };
1452 unsafe {
1453 setsockopt(
1454 self.as_raw(),
1455 sys::IPPROTO_IP,
1456 sys::IP_DROP_SOURCE_MEMBERSHIP,
1457 mreqs,
1458 )
1459 }
1460 }
1461
1462 /// Get the value of the `IP_MULTICAST_ALL` option for this socket.
1463 ///
1464 /// For more information about this option, see [`set_multicast_all_v4`].
1465 ///
1466 /// [`set_multicast_all_v4`]: Socket::set_multicast_all_v4
1467 #[cfg(all(feature = "all", target_os = "linux"))]
1468 pub fn multicast_all_v4(&self) -> io::Result<bool> {
1469 unsafe {
1470 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, libc::IP_MULTICAST_ALL)
1471 .map(|all| all != 0)
1472 }
1473 }
1474
1475 /// Set the value of the `IP_MULTICAST_ALL` option for this socket.
1476 ///
1477 /// This option can be used to modify the delivery policy of
1478 /// multicast messages. The argument is a boolean
1479 /// (defaults to true). If set to true, the socket will receive
1480 /// messages from all the groups that have been joined
1481 /// globally on the whole system. Otherwise, it will deliver
1482 /// messages only from the groups that have been explicitly
1483 /// joined (for example via the `IP_ADD_MEMBERSHIP` option) on
1484 /// this particular socket.
1485 #[cfg(all(feature = "all", target_os = "linux"))]
1486 pub fn set_multicast_all_v4(&self, all: bool) -> io::Result<()> {
1487 unsafe {
1488 setsockopt(
1489 self.as_raw(),
1490 sys::IPPROTO_IP,
1491 libc::IP_MULTICAST_ALL,
1492 all as c_int,
1493 )
1494 }
1495 }
1496
1497 /// Get the value of the `IP_MULTICAST_IF` option for this socket.
1498 ///
1499 /// For more information about this option, see [`set_multicast_if_v4`].
1500 ///
1501 /// [`set_multicast_if_v4`]: Socket::set_multicast_if_v4
1502 pub fn multicast_if_v4(&self) -> io::Result<Ipv4Addr> {
1503 unsafe {
1504 getsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_IF).map(sys::from_in_addr)
1505 }
1506 }
1507
1508 /// Set the value of the `IP_MULTICAST_IF` option for this socket.
1509 ///
1510 /// Specifies the interface to use for routing multicast packets.
1511 pub fn set_multicast_if_v4(&self, interface: &Ipv4Addr) -> io::Result<()> {
1512 let interface = sys::to_in_addr(interface);
1513 unsafe {
1514 setsockopt(
1515 self.as_raw(),
1516 sys::IPPROTO_IP,
1517 sys::IP_MULTICAST_IF,
1518 interface,
1519 )
1520 }
1521 }
1522
1523 /// Get the value of the `IP_MULTICAST_LOOP` option for this socket.
1524 ///
1525 /// For more information about this option, see [`set_multicast_loop_v4`].
1526 ///
1527 /// [`set_multicast_loop_v4`]: Socket::set_multicast_loop_v4
1528 pub fn multicast_loop_v4(&self) -> io::Result<bool> {
1529 unsafe {
1530 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_LOOP)
1531 .map(|loop_v4| loop_v4 != 0)
1532 }
1533 }
1534
1535 /// Set the value of the `IP_MULTICAST_LOOP` option for this socket.
1536 ///
1537 /// If enabled, multicast packets will be looped back to the local socket.
1538 /// Note that this may not have any affect on IPv6 sockets.
1539 pub fn set_multicast_loop_v4(&self, loop_v4: bool) -> io::Result<()> {
1540 unsafe {
1541 setsockopt(
1542 self.as_raw(),
1543 sys::IPPROTO_IP,
1544 sys::IP_MULTICAST_LOOP,
1545 loop_v4 as c_int,
1546 )
1547 }
1548 }
1549
1550 /// Get the value of the `IP_MULTICAST_TTL` option for this socket.
1551 ///
1552 /// For more information about this option, see [`set_multicast_ttl_v4`].
1553 ///
1554 /// [`set_multicast_ttl_v4`]: Socket::set_multicast_ttl_v4
1555 pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
1556 unsafe {
1557 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_TTL)
1558 .map(|ttl| ttl as u32)
1559 }
1560 }
1561
1562 /// Set the value of the `IP_MULTICAST_TTL` option for this socket.
1563 ///
1564 /// Indicates the time-to-live value of outgoing multicast packets for
1565 /// this socket. The default value is 1 which means that multicast packets
1566 /// don't leave the local network unless explicitly requested.
1567 ///
1568 /// Note that this may not have any affect on IPv6 sockets.
1569 pub fn set_multicast_ttl_v4(&self, ttl: u32) -> io::Result<()> {
1570 unsafe {
1571 setsockopt(
1572 self.as_raw(),
1573 sys::IPPROTO_IP,
1574 sys::IP_MULTICAST_TTL,
1575 ttl as c_int,
1576 )
1577 }
1578 }
1579
1580 /// Get the value of the `IP_TTL` option for this socket.
1581 ///
1582 /// For more information about this option, see [`set_ttl_v4`].
1583 ///
1584 /// [`set_ttl_v4`]: Socket::set_ttl_v4
1585 pub fn ttl_v4(&self) -> io::Result<u32> {
1586 unsafe {
1587 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_TTL).map(|ttl| ttl as u32)
1588 }
1589 }
1590
1591 /// Set the value of the `IP_TTL` option for this socket.
1592 ///
1593 /// This value sets the time-to-live field that is used in every packet sent
1594 /// from this socket.
1595 pub fn set_ttl_v4(&self, ttl: u32) -> io::Result<()> {
1596 unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_TTL, ttl as c_int) }
1597 }
1598
1599 /// Set the value of the `IP_TOS` option for this socket.
1600 ///
1601 /// This value sets the type-of-service field that is used in every packet
1602 /// sent from this socket.
1603 ///
1604 /// NOTE: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options>
1605 /// documents that not all versions of windows support `IP_TOS`.
1606 #[cfg(not(any(
1607 target_os = "fuchsia",
1608 target_os = "redox",
1609 target_os = "solaris",
1610 target_os = "illumos",
1611 target_os = "haiku",
1612 )))]
1613 pub fn set_tos_v4(&self, tos: u32) -> io::Result<()> {
1614 unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_TOS, tos as c_int) }
1615 }
1616
1617 /// Get the value of the `IP_TOS` option for this socket.
1618 ///
1619 /// For more information about this option, see [`set_tos_v4`].
1620 ///
1621 /// NOTE: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options>
1622 /// documents that not all versions of windows support `IP_TOS`.
1623 ///
1624 /// [`set_tos_v4`]: Socket::set_tos_v4
1625 #[cfg(not(any(
1626 target_os = "fuchsia",
1627 target_os = "redox",
1628 target_os = "solaris",
1629 target_os = "illumos",
1630 target_os = "haiku",
1631 )))]
1632 pub fn tos_v4(&self) -> io::Result<u32> {
1633 unsafe {
1634 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_TOS).map(|tos| tos as u32)
1635 }
1636 }
1637
1638 /// Set the value of the `IP_RECVTOS` option for this socket.
1639 ///
1640 /// If enabled, the `IP_TOS` ancillary message is passed with
1641 /// incoming packets. It contains a byte which specifies the
1642 /// Type of Service/Precedence field of the packet header.
1643 #[cfg(not(any(
1644 target_os = "aix",
1645 target_os = "dragonfly",
1646 target_os = "fuchsia",
1647 target_os = "hurd",
1648 target_os = "illumos",
1649 target_os = "netbsd",
1650 target_os = "openbsd",
1651 target_os = "redox",
1652 target_os = "solaris",
1653 target_os = "haiku",
1654 target_os = "nto",
1655 target_os = "espidf",
1656 target_os = "vita",
1657 target_os = "cygwin",
1658 )))]
1659 pub fn set_recv_tos_v4(&self, recv_tos: bool) -> io::Result<()> {
1660 unsafe {
1661 setsockopt(
1662 self.as_raw(),
1663 sys::IPPROTO_IP,
1664 sys::IP_RECVTOS,
1665 recv_tos as c_int,
1666 )
1667 }
1668 }
1669
1670 /// Get the value of the `IP_RECVTOS` option for this socket.
1671 ///
1672 /// For more information about this option, see [`set_recv_tos_v4`].
1673 ///
1674 /// [`set_recv_tos_v4`]: Socket::set_recv_tos_v4
1675 #[cfg(not(any(
1676 target_os = "aix",
1677 target_os = "dragonfly",
1678 target_os = "fuchsia",
1679 target_os = "hurd",
1680 target_os = "illumos",
1681 target_os = "netbsd",
1682 target_os = "openbsd",
1683 target_os = "redox",
1684 target_os = "solaris",
1685 target_os = "haiku",
1686 target_os = "nto",
1687 target_os = "espidf",
1688 target_os = "vita",
1689 target_os = "cygwin",
1690 )))]
1691 pub fn recv_tos_v4(&self) -> io::Result<bool> {
1692 unsafe {
1693 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_RECVTOS)
1694 .map(|recv_tos| recv_tos > 0)
1695 }
1696 }
1697
1698 /// Get the value for the `SO_ORIGINAL_DST` option on this socket.
1699 #[cfg(all(
1700 feature = "all",
1701 any(
1702 target_os = "android",
1703 target_os = "fuchsia",
1704 target_os = "linux",
1705 target_os = "windows",
1706 )
1707 ))]
1708 pub fn original_dst_v4(&self) -> io::Result<SockAddr> {
1709 sys::original_dst_v4(self.as_raw())
1710 }
1711}
1712
1713/// Socket options for IPv6 sockets, get/set using `IPPROTO_IPV6` or `SOL_IPV6`.
1714///
1715/// Additional documentation can be found in documentation of the OS.
1716/// * Linux: <https://man7.org/linux/man-pages/man7/ipv6.7.html>
1717/// * Windows: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ipv6-socket-options>
1718impl Socket {
1719 /// Get the value of the `IP_HDRINCL` option on this socket.
1720 ///
1721 /// For more information about this option, see [`set_header_included_v6`].
1722 ///
1723 /// [`set_header_included_v6`]: Socket::set_header_included_v6
1724 #[cfg(all(
1725 feature = "all",
1726 not(any(
1727 target_os = "redox",
1728 target_os = "espidf",
1729 target_os = "openbsd",
1730 target_os = "freebsd",
1731 target_os = "dragonfly",
1732 target_os = "netbsd"
1733 ))
1734 ))]
1735 pub fn header_included_v6(&self) -> io::Result<bool> {
1736 unsafe {
1737 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IP_HDRINCL)
1738 .map(|included| included != 0)
1739 }
1740 }
1741
1742 /// Set the value of the `IP_HDRINCL` option on this socket.
1743 ///
1744 /// If enabled, the user supplies an IP header in front of the user data.
1745 /// Valid only for [`SOCK_RAW`] sockets; see [raw(7)] for more information.
1746 /// When this flag is enabled, the values set by `IP_OPTIONS` are ignored.
1747 ///
1748 /// [`SOCK_RAW`]: Type::RAW
1749 /// [raw(7)]: https://man7.org/linux/man-pages/man7/raw.7.html
1750 #[cfg_attr(
1751 any(target_os = "fuchsia", target_os = "illumos", target_os = "solaris"),
1752 allow(rustdoc::broken_intra_doc_links)
1753 )]
1754 #[cfg(all(
1755 feature = "all",
1756 not(any(
1757 target_os = "redox",
1758 target_os = "espidf",
1759 target_os = "openbsd",
1760 target_os = "freebsd",
1761 target_os = "dragonfly",
1762 target_os = "netbsd"
1763 ))
1764 ))]
1765 pub fn set_header_included_v6(&self, included: bool) -> io::Result<()> {
1766 unsafe {
1767 setsockopt(
1768 self.as_raw(),
1769 sys::IPPROTO_IPV6,
1770 #[cfg(target_os = "linux")]
1771 sys::IPV6_HDRINCL,
1772 #[cfg(not(target_os = "linux"))]
1773 sys::IP_HDRINCL,
1774 included as c_int,
1775 )
1776 }
1777 }
1778
1779 /// Join a multicast group using `IPV6_ADD_MEMBERSHIP` option on this socket.
1780 ///
1781 /// Some OSs use `IPV6_JOIN_GROUP` for this option.
1782 ///
1783 /// This function specifies a new multicast group for this socket to join.
1784 /// The address must be a valid multicast address, and `interface` is the
1785 /// index of the interface to join/leave (or 0 to indicate any interface).
1786 #[cfg(not(target_os = "nto"))]
1787 pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
1788 let mreq = sys::Ipv6Mreq {
1789 ipv6mr_multiaddr: sys::to_in6_addr(multiaddr),
1790 // NOTE: some OSs use `c_int`, others use `c_uint`.
1791 ipv6mr_interface: interface as _,
1792 };
1793 unsafe {
1794 setsockopt(
1795 self.as_raw(),
1796 sys::IPPROTO_IPV6,
1797 sys::IPV6_ADD_MEMBERSHIP,
1798 mreq,
1799 )
1800 }
1801 }
1802
1803 /// Leave a multicast group using `IPV6_DROP_MEMBERSHIP` option on this socket.
1804 ///
1805 /// Some OSs use `IPV6_LEAVE_GROUP` for this option.
1806 ///
1807 /// For more information about this option, see [`join_multicast_v6`].
1808 ///
1809 /// [`join_multicast_v6`]: Socket::join_multicast_v6
1810 #[cfg(not(target_os = "nto"))]
1811 pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
1812 let mreq = sys::Ipv6Mreq {
1813 ipv6mr_multiaddr: sys::to_in6_addr(multiaddr),
1814 // NOTE: some OSs use `c_int`, others use `c_uint`.
1815 ipv6mr_interface: interface as _,
1816 };
1817 unsafe {
1818 setsockopt(
1819 self.as_raw(),
1820 sys::IPPROTO_IPV6,
1821 sys::IPV6_DROP_MEMBERSHIP,
1822 mreq,
1823 )
1824 }
1825 }
1826
1827 /// Get the value of the `IPV6_MULTICAST_HOPS` option for this socket
1828 ///
1829 /// For more information about this option, see [`set_multicast_hops_v6`].
1830 ///
1831 /// [`set_multicast_hops_v6`]: Socket::set_multicast_hops_v6
1832 pub fn multicast_hops_v6(&self) -> io::Result<u32> {
1833 unsafe {
1834 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_HOPS)
1835 .map(|hops| hops as u32)
1836 }
1837 }
1838
1839 /// Set the value of the `IPV6_MULTICAST_HOPS` option for this socket
1840 ///
1841 /// Indicates the number of "routers" multicast packets will transit for
1842 /// this socket. The default value is 1 which means that multicast packets
1843 /// don't leave the local network unless explicitly requested.
1844 pub fn set_multicast_hops_v6(&self, hops: u32) -> io::Result<()> {
1845 unsafe {
1846 setsockopt(
1847 self.as_raw(),
1848 sys::IPPROTO_IPV6,
1849 sys::IPV6_MULTICAST_HOPS,
1850 hops as c_int,
1851 )
1852 }
1853 }
1854
1855 /// Get the value of the `IPV6_MULTICAST_ALL` option for this socket.
1856 ///
1857 /// For more information about this option, see [`set_multicast_all_v6`].
1858 ///
1859 /// [`set_multicast_all_v6`]: Socket::set_multicast_all_v6
1860 #[cfg(all(feature = "all", target_os = "linux"))]
1861 pub fn multicast_all_v6(&self) -> io::Result<bool> {
1862 unsafe {
1863 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, libc::IPV6_MULTICAST_ALL)
1864 .map(|all| all != 0)
1865 }
1866 }
1867
1868 /// Set the value of the `IPV6_MULTICAST_ALL` option for this socket.
1869 ///
1870 /// This option can be used to modify the delivery policy of
1871 /// multicast messages. The argument is a boolean
1872 /// (defaults to true). If set to true, the socket will receive
1873 /// messages from all the groups that have been joined
1874 /// globally on the whole system. Otherwise, it will deliver
1875 /// messages only from the groups that have been explicitly
1876 /// joined (for example via the `IPV6_ADD_MEMBERSHIP` option) on
1877 /// this particular socket.
1878 #[cfg(all(feature = "all", target_os = "linux"))]
1879 pub fn set_multicast_all_v6(&self, all: bool) -> io::Result<()> {
1880 unsafe {
1881 setsockopt(
1882 self.as_raw(),
1883 sys::IPPROTO_IPV6,
1884 libc::IPV6_MULTICAST_ALL,
1885 all as c_int,
1886 )
1887 }
1888 }
1889
1890 /// Get the value of the `IPV6_MULTICAST_IF` option for this socket.
1891 ///
1892 /// For more information about this option, see [`set_multicast_if_v6`].
1893 ///
1894 /// [`set_multicast_if_v6`]: Socket::set_multicast_if_v6
1895 pub fn multicast_if_v6(&self) -> io::Result<u32> {
1896 unsafe {
1897 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_IF)
1898 .map(|interface| interface as u32)
1899 }
1900 }
1901
1902 /// Set the value of the `IPV6_MULTICAST_IF` option for this socket.
1903 ///
1904 /// Specifies the interface to use for routing multicast packets. Unlike
1905 /// ipv4, this is generally required in ipv6 contexts where network routing
1906 /// prefixes may overlap.
1907 pub fn set_multicast_if_v6(&self, interface: u32) -> io::Result<()> {
1908 unsafe {
1909 setsockopt(
1910 self.as_raw(),
1911 sys::IPPROTO_IPV6,
1912 sys::IPV6_MULTICAST_IF,
1913 interface as c_int,
1914 )
1915 }
1916 }
1917
1918 /// Get the value of the `IPV6_MULTICAST_LOOP` option for this socket.
1919 ///
1920 /// For more information about this option, see [`set_multicast_loop_v6`].
1921 ///
1922 /// [`set_multicast_loop_v6`]: Socket::set_multicast_loop_v6
1923 pub fn multicast_loop_v6(&self) -> io::Result<bool> {
1924 unsafe {
1925 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_LOOP)
1926 .map(|loop_v6| loop_v6 != 0)
1927 }
1928 }
1929
1930 /// Set the value of the `IPV6_MULTICAST_LOOP` option for this socket.
1931 ///
1932 /// Controls whether this socket sees the multicast packets it sends itself.
1933 /// Note that this may not have any affect on IPv4 sockets.
1934 pub fn set_multicast_loop_v6(&self, loop_v6: bool) -> io::Result<()> {
1935 unsafe {
1936 setsockopt(
1937 self.as_raw(),
1938 sys::IPPROTO_IPV6,
1939 sys::IPV6_MULTICAST_LOOP,
1940 loop_v6 as c_int,
1941 )
1942 }
1943 }
1944
1945 /// Get the value of the `IPV6_UNICAST_HOPS` option for this socket.
1946 ///
1947 /// Specifies the hop limit for ipv6 unicast packets
1948 pub fn unicast_hops_v6(&self) -> io::Result<u32> {
1949 unsafe {
1950 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_UNICAST_HOPS)
1951 .map(|hops| hops as u32)
1952 }
1953 }
1954
1955 /// Set the value for the `IPV6_UNICAST_HOPS` option on this socket.
1956 ///
1957 /// Specifies the hop limit for ipv6 unicast packets
1958 pub fn set_unicast_hops_v6(&self, hops: u32) -> io::Result<()> {
1959 unsafe {
1960 setsockopt(
1961 self.as_raw(),
1962 sys::IPPROTO_IPV6,
1963 sys::IPV6_UNICAST_HOPS,
1964 hops as c_int,
1965 )
1966 }
1967 }
1968
1969 /// Get the value of the `IPV6_V6ONLY` option for this socket.
1970 ///
1971 /// For more information about this option, see [`set_only_v6`].
1972 ///
1973 /// [`set_only_v6`]: Socket::set_only_v6
1974 pub fn only_v6(&self) -> io::Result<bool> {
1975 unsafe {
1976 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_V6ONLY)
1977 .map(|only_v6| only_v6 != 0)
1978 }
1979 }
1980
1981 /// Set the value for the `IPV6_V6ONLY` option on this socket.
1982 ///
1983 /// If this is set to `true` then the socket is restricted to sending and
1984 /// receiving IPv6 packets only. In this case two IPv4 and IPv6 applications
1985 /// can bind the same port at the same time.
1986 ///
1987 /// If this is set to `false` then the socket can be used to send and
1988 /// receive packets from an IPv4-mapped IPv6 address.
1989 pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
1990 unsafe {
1991 setsockopt(
1992 self.as_raw(),
1993 sys::IPPROTO_IPV6,
1994 sys::IPV6_V6ONLY,
1995 only_v6 as c_int,
1996 )
1997 }
1998 }
1999
2000 /// Get the value of the `IPV6_RECVTCLASS` option for this socket.
2001 ///
2002 /// For more information about this option, see [`set_recv_tclass_v6`].
2003 ///
2004 /// [`set_recv_tclass_v6`]: Socket::set_recv_tclass_v6
2005 #[cfg(not(any(
2006 target_os = "dragonfly",
2007 target_os = "fuchsia",
2008 target_os = "illumos",
2009 target_os = "netbsd",
2010 target_os = "openbsd",
2011 target_os = "redox",
2012 target_os = "solaris",
2013 target_os = "haiku",
2014 target_os = "hurd",
2015 target_os = "espidf",
2016 target_os = "vita",
2017 )))]
2018 pub fn recv_tclass_v6(&self) -> io::Result<bool> {
2019 unsafe {
2020 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_RECVTCLASS)
2021 .map(|recv_tclass| recv_tclass > 0)
2022 }
2023 }
2024
2025 /// Set the value of the `IPV6_RECVTCLASS` option for this socket.
2026 ///
2027 /// If enabled, the `IPV6_TCLASS` ancillary message is passed with incoming
2028 /// packets. It contains a byte which specifies the traffic class field of
2029 /// the packet header.
2030 #[cfg(not(any(
2031 target_os = "dragonfly",
2032 target_os = "fuchsia",
2033 target_os = "illumos",
2034 target_os = "netbsd",
2035 target_os = "openbsd",
2036 target_os = "redox",
2037 target_os = "solaris",
2038 target_os = "haiku",
2039 target_os = "hurd",
2040 target_os = "espidf",
2041 target_os = "vita",
2042 )))]
2043 pub fn set_recv_tclass_v6(&self, recv_tclass: bool) -> io::Result<()> {
2044 unsafe {
2045 setsockopt(
2046 self.as_raw(),
2047 sys::IPPROTO_IPV6,
2048 sys::IPV6_RECVTCLASS,
2049 recv_tclass as c_int,
2050 )
2051 }
2052 }
2053
2054 /// Get the value of the `IPV6_RECVHOPLIMIT` option for this socket.
2055 ///
2056 /// For more information about this option, see [`set_recv_hoplimit_v6`].
2057 ///
2058 /// [`set_recv_hoplimit_v6`]: Socket::set_recv_hoplimit_v6
2059 #[cfg(all(
2060 feature = "all",
2061 not(any(
2062 windows,
2063 target_os = "dragonfly",
2064 target_os = "fuchsia",
2065 target_os = "illumos",
2066 target_os = "netbsd",
2067 target_os = "openbsd",
2068 target_os = "redox",
2069 target_os = "solaris",
2070 target_os = "haiku",
2071 target_os = "hurd",
2072 target_os = "espidf",
2073 target_os = "vita",
2074 target_os = "cygwin",
2075 ))
2076 ))]
2077 pub fn recv_hoplimit_v6(&self) -> io::Result<bool> {
2078 unsafe {
2079 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_RECVHOPLIMIT)
2080 .map(|recv_hoplimit| recv_hoplimit > 0)
2081 }
2082 }
2083 /// Set the value of the `IPV6_RECVHOPLIMIT` option for this socket.
2084 ///
2085 /// The received hop limit is returned as ancillary data by recvmsg()
2086 /// only if the application has enabled the IPV6_RECVHOPLIMIT socket
2087 /// option:
2088 #[cfg(all(
2089 feature = "all",
2090 not(any(
2091 windows,
2092 target_os = "dragonfly",
2093 target_os = "fuchsia",
2094 target_os = "illumos",
2095 target_os = "netbsd",
2096 target_os = "openbsd",
2097 target_os = "redox",
2098 target_os = "solaris",
2099 target_os = "haiku",
2100 target_os = "hurd",
2101 target_os = "espidf",
2102 target_os = "vita",
2103 target_os = "cygwin",
2104 ))
2105 ))]
2106 pub fn set_recv_hoplimit_v6(&self, recv_hoplimit: bool) -> io::Result<()> {
2107 unsafe {
2108 setsockopt(
2109 self.as_raw(),
2110 sys::IPPROTO_IPV6,
2111 sys::IPV6_RECVHOPLIMIT,
2112 recv_hoplimit as c_int,
2113 )
2114 }
2115 }
2116
2117 /// Get the value for the `IP6T_SO_ORIGINAL_DST` option on this socket.
2118 #[cfg(all(
2119 feature = "all",
2120 any(target_os = "android", target_os = "linux", target_os = "windows")
2121 ))]
2122 pub fn original_dst_v6(&self) -> io::Result<SockAddr> {
2123 sys::original_dst_v6(self.as_raw())
2124 }
2125}
2126
2127/// Socket options for TCP sockets, get/set using `IPPROTO_TCP`.
2128///
2129/// Additional documentation can be found in documentation of the OS.
2130/// * Linux: <https://man7.org/linux/man-pages/man7/tcp.7.html>
2131/// * Windows: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-tcp-socket-options>
2132impl Socket {
2133 /// Get the value of the `TCP_KEEPIDLE` option on this socket.
2134 ///
2135 /// This returns the value of `TCP_KEEPALIVE` on macOS and iOS and `TCP_KEEPIDLE` on all other
2136 /// supported Unix operating systems.
2137 #[cfg(all(
2138 feature = "all",
2139 not(any(
2140 windows,
2141 target_os = "haiku",
2142 target_os = "openbsd",
2143 target_os = "vita"
2144 ))
2145 ))]
2146 pub fn tcp_keepalive_time(&self) -> io::Result<Duration> {
2147 sys::tcp_keepalive_time(self.as_raw())
2148 }
2149
2150 /// Get the value of the `TCP_KEEPINTVL` option on this socket.
2151 ///
2152 /// For more information about this option, see [`set_tcp_keepalive`].
2153 ///
2154 /// [`set_tcp_keepalive`]: Socket::set_tcp_keepalive
2155 #[cfg(all(
2156 feature = "all",
2157 any(
2158 target_os = "android",
2159 target_os = "dragonfly",
2160 target_os = "freebsd",
2161 target_os = "fuchsia",
2162 target_os = "illumos",
2163 target_os = "ios",
2164 target_os = "visionos",
2165 target_os = "linux",
2166 target_os = "macos",
2167 target_os = "netbsd",
2168 target_os = "tvos",
2169 target_os = "watchos",
2170 target_os = "cygwin",
2171 )
2172 ))]
2173 pub fn tcp_keepalive_interval(&self) -> io::Result<Duration> {
2174 unsafe {
2175 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_TCP, sys::TCP_KEEPINTVL)
2176 .map(|secs| Duration::from_secs(secs as u64))
2177 }
2178 }
2179
2180 /// Get the value of the `TCP_KEEPCNT` option on this socket.
2181 ///
2182 /// For more information about this option, see [`set_tcp_keepalive`].
2183 ///
2184 /// [`set_tcp_keepalive`]: Socket::set_tcp_keepalive
2185 #[cfg(all(
2186 feature = "all",
2187 any(
2188 target_os = "android",
2189 target_os = "dragonfly",
2190 target_os = "freebsd",
2191 target_os = "fuchsia",
2192 target_os = "illumos",
2193 target_os = "ios",
2194 target_os = "visionos",
2195 target_os = "linux",
2196 target_os = "macos",
2197 target_os = "netbsd",
2198 target_os = "tvos",
2199 target_os = "watchos",
2200 target_os = "cygwin",
2201 target_os = "windows",
2202 )
2203 ))]
2204 pub fn tcp_keepalive_retries(&self) -> io::Result<u32> {
2205 unsafe {
2206 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_TCP, sys::TCP_KEEPCNT)
2207 .map(|retries| retries as u32)
2208 }
2209 }
2210
2211 /// Set parameters configuring TCP keepalive probes for this socket.
2212 ///
2213 /// The supported parameters depend on the operating system, and are
2214 /// configured using the [`TcpKeepalive`] struct. At a minimum, all systems
2215 /// support configuring the [keepalive time]: the time after which the OS
2216 /// will start sending keepalive messages on an idle connection.
2217 ///
2218 /// [keepalive time]: TcpKeepalive::with_time
2219 ///
2220 /// # Notes
2221 ///
2222 /// * This will enable `SO_KEEPALIVE` on this socket, if it is not already
2223 /// enabled.
2224 /// * On some platforms, such as Windows, any keepalive parameters *not*
2225 /// configured by the `TcpKeepalive` struct passed to this function may be
2226 /// overwritten with their default values. Therefore, this function should
2227 /// either only be called once per socket, or the same parameters should
2228 /// be passed every time it is called.
2229 ///
2230 /// # Examples
2231 ///
2232 /// ```
2233 /// use std::time::Duration;
2234 ///
2235 /// use socket2::{Socket, TcpKeepalive, Domain, Type};
2236 ///
2237 /// # fn main() -> std::io::Result<()> {
2238 /// let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?;
2239 /// let keepalive = TcpKeepalive::new()
2240 /// .with_time(Duration::from_secs(4));
2241 /// // Depending on the target operating system, we may also be able to
2242 /// // configure the keepalive probe interval and/or the number of
2243 /// // retries here as well.
2244 ///
2245 /// socket.set_tcp_keepalive(&keepalive)?;
2246 /// # Ok(()) }
2247 /// ```
2248 ///
2249 pub fn set_tcp_keepalive(&self, params: &TcpKeepalive) -> io::Result<()> {
2250 self.set_keepalive(true)?;
2251 sys::set_tcp_keepalive(self.as_raw(), params)
2252 }
2253
2254 /// Get the value of the `TCP_NODELAY` option on this socket.
2255 ///
2256 /// For more information about this option, see [`set_tcp_nodelay`].
2257 ///
2258 /// [`set_tcp_nodelay`]: Socket::set_tcp_nodelay
2259 pub fn tcp_nodelay(&self) -> io::Result<bool> {
2260 unsafe {
2261 getsockopt::<Bool>(self.as_raw(), sys::IPPROTO_TCP, sys::TCP_NODELAY)
2262 .map(|nodelay| nodelay != false as Bool)
2263 }
2264 }
2265
2266 /// Set the value of the `TCP_NODELAY` option on this socket.
2267 ///
2268 /// If set, this option disables the Nagle algorithm. This means that
2269 /// segments are always sent as soon as possible, even if there is only a
2270 /// small amount of data. When not set, data is buffered until there is a
2271 /// sufficient amount to send out, thereby avoiding the frequent sending of
2272 /// small packets.
2273 pub fn set_tcp_nodelay(&self, nodelay: bool) -> io::Result<()> {
2274 unsafe {
2275 setsockopt(
2276 self.as_raw(),
2277 sys::IPPROTO_TCP,
2278 sys::TCP_NODELAY,
2279 nodelay as c_int,
2280 )
2281 }
2282 }
2283}
2284
2285impl Read for Socket {
2286 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
2287 // Safety: the `recv` implementation promises not to write uninitialised
2288 // bytes to the `buf`fer, so this casting is safe.
2289 let buf = unsafe { &mut *(buf as *mut [u8] as *mut [MaybeUninit<u8>]) };
2290 self.recv(buf)
2291 }
2292
2293 #[cfg(not(target_os = "redox"))]
2294 fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
2295 // Safety: both `IoSliceMut` and `MaybeUninitSlice` promise to have the
2296 // same layout, that of `iovec`/`WSABUF`. Furthermore, `recv_vectored`
2297 // promises to not write uninitialised bytes to the `bufs` and pass it
2298 // directly to the `recvmsg` system call, so this is safe.
2299 let bufs = unsafe { &mut *(bufs as *mut [IoSliceMut<'_>] as *mut [MaybeUninitSlice<'_>]) };
2300 self.recv_vectored(bufs).map(|(n, _)| n)
2301 }
2302}
2303
2304impl<'a> Read for &'a Socket {
2305 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
2306 // Safety: see other `Read::read` impl.
2307 let buf = unsafe { &mut *(buf as *mut [u8] as *mut [MaybeUninit<u8>]) };
2308 self.recv(buf)
2309 }
2310
2311 #[cfg(not(target_os = "redox"))]
2312 fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
2313 // Safety: see other `Read::read` impl.
2314 let bufs = unsafe { &mut *(bufs as *mut [IoSliceMut<'_>] as *mut [MaybeUninitSlice<'_>]) };
2315 self.recv_vectored(bufs).map(|(n, _)| n)
2316 }
2317}
2318
2319impl Write for Socket {
2320 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
2321 self.send(buf)
2322 }
2323
2324 #[cfg(not(target_os = "redox"))]
2325 fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
2326 self.send_vectored(bufs)
2327 }
2328
2329 fn flush(&mut self) -> io::Result<()> {
2330 Ok(())
2331 }
2332}
2333
2334impl<'a> Write for &'a Socket {
2335 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
2336 self.send(buf)
2337 }
2338
2339 #[cfg(not(target_os = "redox"))]
2340 fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
2341 self.send_vectored(bufs)
2342 }
2343
2344 fn flush(&mut self) -> io::Result<()> {
2345 Ok(())
2346 }
2347}
2348
2349impl fmt::Debug for Socket {
2350 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2351 f.debug_struct("Socket")
2352 .field("raw", &self.as_raw())
2353 .field("local_addr", &self.local_addr().ok())
2354 .field("peer_addr", &self.peer_addr().ok())
2355 .finish()
2356 }
2357}
2358
2359from!(net::TcpStream, Socket);
2360from!(net::TcpListener, Socket);
2361from!(net::UdpSocket, Socket);
2362from!(Socket, net::TcpStream);
2363from!(Socket, net::TcpListener);
2364from!(Socket, net::UdpSocket);