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