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: Type = 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_RCVBUF` option on this socket.
969 ///
970 /// For more information about this option, see [`set_recv_buffer_size`].
971 ///
972 /// [`set_recv_buffer_size`]: Socket::set_recv_buffer_size
973 pub fn recv_buffer_size(&self) -> io::Result<usize> {
974 unsafe {
975 getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_RCVBUF)
976 .map(|size| size as usize)
977 }
978 }
979
980 /// Set value for the `SO_RCVBUF` option on this socket.
981 ///
982 /// Changes the size of the operating system's receive buffer associated
983 /// with the socket.
984 pub fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> {
985 unsafe {
986 setsockopt(
987 self.as_raw(),
988 sys::SOL_SOCKET,
989 sys::SO_RCVBUF,
990 size as c_int,
991 )
992 }
993 }
994
995 /// Get value for the `SO_RCVTIMEO` option on this socket.
996 ///
997 /// If the returned timeout is `None`, then `read` and `recv` calls will
998 /// block indefinitely.
999 pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
1000 sys::timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_RCVTIMEO)
1001 }
1002
1003 /// Set value for the `SO_RCVTIMEO` option on this socket.
1004 ///
1005 /// If `timeout` is `None`, then `read` and `recv` calls will block
1006 /// indefinitely.
1007 pub fn set_read_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
1008 sys::set_timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_RCVTIMEO, duration)
1009 }
1010
1011 /// Get the value of the `SO_REUSEADDR` option on this socket.
1012 ///
1013 /// For more information about this option, see [`set_reuse_address`].
1014 ///
1015 /// [`set_reuse_address`]: Socket::set_reuse_address
1016 pub fn reuse_address(&self) -> io::Result<bool> {
1017 unsafe {
1018 getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_REUSEADDR)
1019 .map(|reuse| reuse != 0)
1020 }
1021 }
1022
1023 /// Set value for the `SO_REUSEADDR` option on this socket.
1024 ///
1025 /// This indicates that futher calls to `bind` may allow reuse of local
1026 /// addresses. For IPv4 sockets this means that a socket may bind even when
1027 /// there's a socket already listening on this port.
1028 pub fn set_reuse_address(&self, reuse: bool) -> io::Result<()> {
1029 unsafe {
1030 setsockopt(
1031 self.as_raw(),
1032 sys::SOL_SOCKET,
1033 sys::SO_REUSEADDR,
1034 reuse as c_int,
1035 )
1036 }
1037 }
1038
1039 /// Get the value of the `SO_SNDBUF` option on this socket.
1040 ///
1041 /// For more information about this option, see [`set_send_buffer_size`].
1042 ///
1043 /// [`set_send_buffer_size`]: Socket::set_send_buffer_size
1044 pub fn send_buffer_size(&self) -> io::Result<usize> {
1045 unsafe {
1046 getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_SNDBUF)
1047 .map(|size| size as usize)
1048 }
1049 }
1050
1051 /// Set value for the `SO_SNDBUF` option on this socket.
1052 ///
1053 /// Changes the size of the operating system's send buffer associated with
1054 /// the socket.
1055 pub fn set_send_buffer_size(&self, size: usize) -> io::Result<()> {
1056 unsafe {
1057 setsockopt(
1058 self.as_raw(),
1059 sys::SOL_SOCKET,
1060 sys::SO_SNDBUF,
1061 size as c_int,
1062 )
1063 }
1064 }
1065
1066 /// Get value for the `SO_SNDTIMEO` option on this socket.
1067 ///
1068 /// If the returned timeout is `None`, then `write` and `send` calls will
1069 /// block indefinitely.
1070 pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
1071 sys::timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_SNDTIMEO)
1072 }
1073
1074 /// Set value for the `SO_SNDTIMEO` option on this socket.
1075 ///
1076 /// If `timeout` is `None`, then `write` and `send` calls will block
1077 /// indefinitely.
1078 pub fn set_write_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
1079 sys::set_timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_SNDTIMEO, duration)
1080 }
1081}
1082
1083const fn from_linger(linger: sys::linger) -> Option<Duration> {
1084 if linger.l_onoff == 0 {
1085 None
1086 } else {
1087 Some(Duration::from_secs(linger.l_linger as u64))
1088 }
1089}
1090
1091const fn into_linger(duration: Option<Duration>) -> sys::linger {
1092 match duration {
1093 Some(duration: Duration) => sys::linger {
1094 l_onoff: 1,
1095 l_linger: duration.as_secs() as _,
1096 },
1097 None => sys::linger {
1098 l_onoff: 0,
1099 l_linger: 0,
1100 },
1101 }
1102}
1103
1104/// Socket options for IPv4 sockets, get/set using `IPPROTO_IP`.
1105///
1106/// Additional documentation can be found in documentation of the OS.
1107/// * Linux: <https://man7.org/linux/man-pages/man7/ip.7.html>
1108/// * Windows: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options>
1109impl Socket {
1110 /// Get the value of the `IP_HDRINCL` option on this socket.
1111 ///
1112 /// For more information about this option, see [`set_header_included`].
1113 ///
1114 /// [`set_header_included`]: Socket::set_header_included
1115 #[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))]
1116 #[cfg_attr(
1117 docsrs,
1118 doc(cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf")))))
1119 )]
1120 pub fn header_included(&self) -> io::Result<bool> {
1121 unsafe {
1122 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_HDRINCL)
1123 .map(|included| included != 0)
1124 }
1125 }
1126
1127 /// Set the value of the `IP_HDRINCL` option on this socket.
1128 ///
1129 /// If enabled, the user supplies an IP header in front of the user data.
1130 /// Valid only for [`SOCK_RAW`] sockets; see [raw(7)] for more information.
1131 /// When this flag is enabled, the values set by `IP_OPTIONS`, [`IP_TTL`],
1132 /// and [`IP_TOS`] are ignored.
1133 ///
1134 /// [`SOCK_RAW`]: Type::RAW
1135 /// [raw(7)]: https://man7.org/linux/man-pages/man7/raw.7.html
1136 /// [`IP_TTL`]: Socket::set_ttl
1137 /// [`IP_TOS`]: Socket::set_tos
1138 #[cfg_attr(
1139 any(target_os = "fuchsia", target_os = "illumos", target_os = "solaris"),
1140 allow(rustdoc::broken_intra_doc_links)
1141 )]
1142 #[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))]
1143 #[cfg_attr(
1144 docsrs,
1145 doc(cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf")))))
1146 )]
1147 pub fn set_header_included(&self, included: bool) -> io::Result<()> {
1148 unsafe {
1149 setsockopt(
1150 self.as_raw(),
1151 sys::IPPROTO_IP,
1152 sys::IP_HDRINCL,
1153 included as c_int,
1154 )
1155 }
1156 }
1157
1158 /// Get the value of the `IP_TRANSPARENT` option on this socket.
1159 ///
1160 /// For more information about this option, see [`set_ip_transparent`].
1161 ///
1162 /// [`set_ip_transparent`]: Socket::set_ip_transparent
1163 #[cfg(all(feature = "all", target_os = "linux"))]
1164 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
1165 pub fn ip_transparent(&self) -> io::Result<bool> {
1166 unsafe {
1167 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, libc::IP_TRANSPARENT)
1168 .map(|transparent| transparent != 0)
1169 }
1170 }
1171
1172 /// Set the value of the `IP_TRANSPARENT` option on this socket.
1173 ///
1174 /// Setting this boolean option enables transparent proxying
1175 /// on this socket. This socket option allows the calling
1176 /// application to bind to a nonlocal IP address and operate
1177 /// both as a client and a server with the foreign address as
1178 /// the local endpoint. NOTE: this requires that routing be
1179 /// set up in a way that packets going to the foreign address
1180 /// are routed through the TProxy box (i.e., the system
1181 /// hosting the application that employs the IP_TRANSPARENT
1182 /// socket option). Enabling this socket option requires
1183 /// superuser privileges (the `CAP_NET_ADMIN` capability).
1184 ///
1185 /// TProxy redirection with the iptables TPROXY target also
1186 /// requires that this option be set on the redirected socket.
1187 #[cfg(all(feature = "all", target_os = "linux"))]
1188 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
1189 pub fn set_ip_transparent(&self, transparent: bool) -> io::Result<()> {
1190 unsafe {
1191 setsockopt(
1192 self.as_raw(),
1193 sys::IPPROTO_IP,
1194 libc::IP_TRANSPARENT,
1195 transparent as c_int,
1196 )
1197 }
1198 }
1199
1200 /// Join a multicast group using `IP_ADD_MEMBERSHIP` option on this socket.
1201 ///
1202 /// This function specifies a new multicast group for this socket to join.
1203 /// The address must be a valid multicast address, and `interface` is the
1204 /// address of the local interface with which the system should join the
1205 /// multicast group. If it's [`Ipv4Addr::UNSPECIFIED`] (`INADDR_ANY`) then
1206 /// an appropriate interface is chosen by the system.
1207 pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
1208 let mreq = sys::IpMreq {
1209 imr_multiaddr: sys::to_in_addr(multiaddr),
1210 imr_interface: sys::to_in_addr(interface),
1211 };
1212 unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_ADD_MEMBERSHIP, mreq) }
1213 }
1214
1215 /// Leave a multicast group using `IP_DROP_MEMBERSHIP` option on this socket.
1216 ///
1217 /// For more information about this option, see [`join_multicast_v4`].
1218 ///
1219 /// [`join_multicast_v4`]: Socket::join_multicast_v4
1220 pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
1221 let mreq = sys::IpMreq {
1222 imr_multiaddr: sys::to_in_addr(multiaddr),
1223 imr_interface: sys::to_in_addr(interface),
1224 };
1225 unsafe {
1226 setsockopt(
1227 self.as_raw(),
1228 sys::IPPROTO_IP,
1229 sys::IP_DROP_MEMBERSHIP,
1230 mreq,
1231 )
1232 }
1233 }
1234
1235 /// Join a multicast group using `IP_ADD_MEMBERSHIP` option on this socket.
1236 ///
1237 /// This function specifies a new multicast group for this socket to join.
1238 /// The address must be a valid multicast address, and `interface` specifies
1239 /// the local interface with which the system should join the multicast
1240 /// group. See [`InterfaceIndexOrAddress`].
1241 #[cfg(not(any(
1242 target_os = "aix",
1243 target_os = "haiku",
1244 target_os = "illumos",
1245 target_os = "netbsd",
1246 target_os = "openbsd",
1247 target_os = "redox",
1248 target_os = "solaris",
1249 target_os = "nto",
1250 target_os = "espidf",
1251 target_os = "vita",
1252 )))]
1253 pub fn join_multicast_v4_n(
1254 &self,
1255 multiaddr: &Ipv4Addr,
1256 interface: &InterfaceIndexOrAddress,
1257 ) -> io::Result<()> {
1258 let mreqn = sys::to_mreqn(multiaddr, interface);
1259 unsafe {
1260 setsockopt(
1261 self.as_raw(),
1262 sys::IPPROTO_IP,
1263 sys::IP_ADD_MEMBERSHIP,
1264 mreqn,
1265 )
1266 }
1267 }
1268
1269 /// Leave a multicast group using `IP_DROP_MEMBERSHIP` option on this socket.
1270 ///
1271 /// For more information about this option, see [`join_multicast_v4_n`].
1272 ///
1273 /// [`join_multicast_v4_n`]: Socket::join_multicast_v4_n
1274 #[cfg(not(any(
1275 target_os = "aix",
1276 target_os = "haiku",
1277 target_os = "illumos",
1278 target_os = "netbsd",
1279 target_os = "openbsd",
1280 target_os = "redox",
1281 target_os = "solaris",
1282 target_os = "nto",
1283 target_os = "espidf",
1284 target_os = "vita",
1285 )))]
1286 pub fn leave_multicast_v4_n(
1287 &self,
1288 multiaddr: &Ipv4Addr,
1289 interface: &InterfaceIndexOrAddress,
1290 ) -> io::Result<()> {
1291 let mreqn = sys::to_mreqn(multiaddr, interface);
1292 unsafe {
1293 setsockopt(
1294 self.as_raw(),
1295 sys::IPPROTO_IP,
1296 sys::IP_DROP_MEMBERSHIP,
1297 mreqn,
1298 )
1299 }
1300 }
1301
1302 /// Join a multicast SSM channel using `IP_ADD_SOURCE_MEMBERSHIP` option on this socket.
1303 ///
1304 /// This function specifies a new multicast channel for this socket to join.
1305 /// The group must be a valid SSM group address, the source must be the address of the sender
1306 /// and `interface` is the address of the local interface with which the system should join the
1307 /// multicast group. If it's [`Ipv4Addr::UNSPECIFIED`] (`INADDR_ANY`) then
1308 /// an appropriate interface is chosen by the system.
1309 #[cfg(not(any(
1310 target_os = "dragonfly",
1311 target_os = "haiku",
1312 target_os = "hurd",
1313 target_os = "netbsd",
1314 target_os = "openbsd",
1315 target_os = "redox",
1316 target_os = "fuchsia",
1317 target_os = "nto",
1318 target_os = "espidf",
1319 target_os = "vita",
1320 )))]
1321 pub fn join_ssm_v4(
1322 &self,
1323 source: &Ipv4Addr,
1324 group: &Ipv4Addr,
1325 interface: &Ipv4Addr,
1326 ) -> io::Result<()> {
1327 let mreqs = sys::IpMreqSource {
1328 imr_multiaddr: sys::to_in_addr(group),
1329 imr_interface: sys::to_in_addr(interface),
1330 imr_sourceaddr: sys::to_in_addr(source),
1331 };
1332 unsafe {
1333 setsockopt(
1334 self.as_raw(),
1335 sys::IPPROTO_IP,
1336 sys::IP_ADD_SOURCE_MEMBERSHIP,
1337 mreqs,
1338 )
1339 }
1340 }
1341
1342 /// Leave a multicast group using `IP_DROP_SOURCE_MEMBERSHIP` option on this socket.
1343 ///
1344 /// For more information about this option, see [`join_ssm_v4`].
1345 ///
1346 /// [`join_ssm_v4`]: Socket::join_ssm_v4
1347 #[cfg(not(any(
1348 target_os = "dragonfly",
1349 target_os = "haiku",
1350 target_os = "hurd",
1351 target_os = "netbsd",
1352 target_os = "openbsd",
1353 target_os = "redox",
1354 target_os = "fuchsia",
1355 target_os = "nto",
1356 target_os = "espidf",
1357 target_os = "vita",
1358 )))]
1359 pub fn leave_ssm_v4(
1360 &self,
1361 source: &Ipv4Addr,
1362 group: &Ipv4Addr,
1363 interface: &Ipv4Addr,
1364 ) -> io::Result<()> {
1365 let mreqs = sys::IpMreqSource {
1366 imr_multiaddr: sys::to_in_addr(group),
1367 imr_interface: sys::to_in_addr(interface),
1368 imr_sourceaddr: sys::to_in_addr(source),
1369 };
1370 unsafe {
1371 setsockopt(
1372 self.as_raw(),
1373 sys::IPPROTO_IP,
1374 sys::IP_DROP_SOURCE_MEMBERSHIP,
1375 mreqs,
1376 )
1377 }
1378 }
1379
1380 /// Get the value of the `IP_MULTICAST_ALL` option for this socket.
1381 ///
1382 /// For more information about this option, see [`set_multicast_all_v4`].
1383 ///
1384 /// [`set_multicast_all_v4`]: Socket::set_multicast_all_v4
1385 #[cfg(all(feature = "all", target_os = "linux"))]
1386 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
1387 pub fn multicast_all_v4(&self) -> io::Result<bool> {
1388 unsafe {
1389 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, libc::IP_MULTICAST_ALL)
1390 .map(|all| all != 0)
1391 }
1392 }
1393
1394 /// Set the value of the `IP_MULTICAST_ALL` option for this socket.
1395 ///
1396 /// This option can be used to modify the delivery policy of
1397 /// multicast messages. The argument is a boolean
1398 /// (defaults to true). If set to true, the socket will receive
1399 /// messages from all the groups that have been joined
1400 /// globally on the whole system. Otherwise, it will deliver
1401 /// messages only from the groups that have been explicitly
1402 /// joined (for example via the `IP_ADD_MEMBERSHIP` option) on
1403 /// this particular socket.
1404 #[cfg(all(feature = "all", target_os = "linux"))]
1405 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
1406 pub fn set_multicast_all_v4(&self, all: bool) -> io::Result<()> {
1407 unsafe {
1408 setsockopt(
1409 self.as_raw(),
1410 sys::IPPROTO_IP,
1411 libc::IP_MULTICAST_ALL,
1412 all as c_int,
1413 )
1414 }
1415 }
1416
1417 /// Get the value of the `IP_MULTICAST_IF` option for this socket.
1418 ///
1419 /// For more information about this option, see [`set_multicast_if_v4`].
1420 ///
1421 /// [`set_multicast_if_v4`]: Socket::set_multicast_if_v4
1422 pub fn multicast_if_v4(&self) -> io::Result<Ipv4Addr> {
1423 unsafe {
1424 getsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_IF).map(sys::from_in_addr)
1425 }
1426 }
1427
1428 /// Set the value of the `IP_MULTICAST_IF` option for this socket.
1429 ///
1430 /// Specifies the interface to use for routing multicast packets.
1431 pub fn set_multicast_if_v4(&self, interface: &Ipv4Addr) -> io::Result<()> {
1432 let interface = sys::to_in_addr(interface);
1433 unsafe {
1434 setsockopt(
1435 self.as_raw(),
1436 sys::IPPROTO_IP,
1437 sys::IP_MULTICAST_IF,
1438 interface,
1439 )
1440 }
1441 }
1442
1443 /// Get the value of the `IP_MULTICAST_LOOP` option for this socket.
1444 ///
1445 /// For more information about this option, see [`set_multicast_loop_v4`].
1446 ///
1447 /// [`set_multicast_loop_v4`]: Socket::set_multicast_loop_v4
1448 pub fn multicast_loop_v4(&self) -> io::Result<bool> {
1449 unsafe {
1450 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_LOOP)
1451 .map(|loop_v4| loop_v4 != 0)
1452 }
1453 }
1454
1455 /// Set the value of the `IP_MULTICAST_LOOP` option for this socket.
1456 ///
1457 /// If enabled, multicast packets will be looped back to the local socket.
1458 /// Note that this may not have any affect on IPv6 sockets.
1459 pub fn set_multicast_loop_v4(&self, loop_v4: bool) -> io::Result<()> {
1460 unsafe {
1461 setsockopt(
1462 self.as_raw(),
1463 sys::IPPROTO_IP,
1464 sys::IP_MULTICAST_LOOP,
1465 loop_v4 as c_int,
1466 )
1467 }
1468 }
1469
1470 /// Get the value of the `IP_MULTICAST_TTL` option for this socket.
1471 ///
1472 /// For more information about this option, see [`set_multicast_ttl_v4`].
1473 ///
1474 /// [`set_multicast_ttl_v4`]: Socket::set_multicast_ttl_v4
1475 pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
1476 unsafe {
1477 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_TTL)
1478 .map(|ttl| ttl as u32)
1479 }
1480 }
1481
1482 /// Set the value of the `IP_MULTICAST_TTL` option for this socket.
1483 ///
1484 /// Indicates the time-to-live value of outgoing multicast packets for
1485 /// this socket. The default value is 1 which means that multicast packets
1486 /// don't leave the local network unless explicitly requested.
1487 ///
1488 /// Note that this may not have any affect on IPv6 sockets.
1489 pub fn set_multicast_ttl_v4(&self, ttl: u32) -> io::Result<()> {
1490 unsafe {
1491 setsockopt(
1492 self.as_raw(),
1493 sys::IPPROTO_IP,
1494 sys::IP_MULTICAST_TTL,
1495 ttl as c_int,
1496 )
1497 }
1498 }
1499
1500 /// Get the value of the `IP_TTL` option for this socket.
1501 ///
1502 /// For more information about this option, see [`set_ttl`].
1503 ///
1504 /// [`set_ttl`]: Socket::set_ttl
1505 pub fn ttl(&self) -> io::Result<u32> {
1506 unsafe {
1507 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_TTL).map(|ttl| ttl as u32)
1508 }
1509 }
1510
1511 /// Set the value of the `IP_TTL` option for this socket.
1512 ///
1513 /// This value sets the time-to-live field that is used in every packet sent
1514 /// from this socket.
1515 pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
1516 unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_TTL, ttl as c_int) }
1517 }
1518
1519 /// Set the value of the `IP_TOS` option for this socket.
1520 ///
1521 /// This value sets the type-of-service field that is used in every packet
1522 /// sent from this socket.
1523 ///
1524 /// NOTE: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options>
1525 /// documents that not all versions of windows support `IP_TOS`.
1526 #[cfg(not(any(
1527 target_os = "fuchsia",
1528 target_os = "redox",
1529 target_os = "solaris",
1530 target_os = "illumos",
1531 target_os = "haiku",
1532 )))]
1533 pub fn set_tos(&self, tos: u32) -> io::Result<()> {
1534 unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_TOS, tos as c_int) }
1535 }
1536
1537 /// Get the value of the `IP_TOS` option for this socket.
1538 ///
1539 /// For more information about this option, see [`set_tos`].
1540 ///
1541 /// NOTE: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options>
1542 /// documents that not all versions of windows support `IP_TOS`.
1543 ///
1544 /// [`set_tos`]: Socket::set_tos
1545 #[cfg(not(any(
1546 target_os = "fuchsia",
1547 target_os = "redox",
1548 target_os = "solaris",
1549 target_os = "illumos",
1550 target_os = "haiku",
1551 )))]
1552 pub fn tos(&self) -> io::Result<u32> {
1553 unsafe {
1554 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_TOS).map(|tos| tos as u32)
1555 }
1556 }
1557
1558 /// Set the value of the `IP_RECVTOS` option for this socket.
1559 ///
1560 /// If enabled, the `IP_TOS` ancillary message is passed with
1561 /// incoming packets. It contains a byte which specifies the
1562 /// Type of Service/Precedence field of the packet header.
1563 #[cfg(not(any(
1564 target_os = "aix",
1565 target_os = "dragonfly",
1566 target_os = "fuchsia",
1567 target_os = "hurd",
1568 target_os = "illumos",
1569 target_os = "netbsd",
1570 target_os = "openbsd",
1571 target_os = "redox",
1572 target_os = "solaris",
1573 target_os = "haiku",
1574 target_os = "nto",
1575 target_os = "espidf",
1576 target_os = "vita",
1577 )))]
1578 pub fn set_recv_tos(&self, recv_tos: bool) -> io::Result<()> {
1579 unsafe {
1580 setsockopt(
1581 self.as_raw(),
1582 sys::IPPROTO_IP,
1583 sys::IP_RECVTOS,
1584 recv_tos as c_int,
1585 )
1586 }
1587 }
1588
1589 /// Get the value of the `IP_RECVTOS` option for this socket.
1590 ///
1591 /// For more information about this option, see [`set_recv_tos`].
1592 ///
1593 /// [`set_recv_tos`]: Socket::set_recv_tos
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 recv_tos(&self) -> io::Result<bool> {
1610 unsafe {
1611 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_RECVTOS)
1612 .map(|recv_tos| recv_tos > 0)
1613 }
1614 }
1615}
1616
1617/// Socket options for IPv6 sockets, get/set using `IPPROTO_IPV6`.
1618///
1619/// Additional documentation can be found in documentation of the OS.
1620/// * Linux: <https://man7.org/linux/man-pages/man7/ipv6.7.html>
1621/// * Windows: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ipv6-socket-options>
1622impl Socket {
1623 /// Join a multicast group using `IPV6_ADD_MEMBERSHIP` option on this socket.
1624 ///
1625 /// Some OSs use `IPV6_JOIN_GROUP` for this option.
1626 ///
1627 /// This function specifies a new multicast group for this socket to join.
1628 /// The address must be a valid multicast address, and `interface` is the
1629 /// index of the interface to join/leave (or 0 to indicate any interface).
1630 #[cfg(not(target_os = "nto"))]
1631 pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
1632 let mreq = sys::Ipv6Mreq {
1633 ipv6mr_multiaddr: sys::to_in6_addr(multiaddr),
1634 // NOTE: some OSs use `c_int`, others use `c_uint`.
1635 ipv6mr_interface: interface as _,
1636 };
1637 unsafe {
1638 setsockopt(
1639 self.as_raw(),
1640 sys::IPPROTO_IPV6,
1641 sys::IPV6_ADD_MEMBERSHIP,
1642 mreq,
1643 )
1644 }
1645 }
1646
1647 /// Leave a multicast group using `IPV6_DROP_MEMBERSHIP` option on this socket.
1648 ///
1649 /// Some OSs use `IPV6_LEAVE_GROUP` for this option.
1650 ///
1651 /// For more information about this option, see [`join_multicast_v6`].
1652 ///
1653 /// [`join_multicast_v6`]: Socket::join_multicast_v6
1654 #[cfg(not(target_os = "nto"))]
1655 pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
1656 let mreq = sys::Ipv6Mreq {
1657 ipv6mr_multiaddr: sys::to_in6_addr(multiaddr),
1658 // NOTE: some OSs use `c_int`, others use `c_uint`.
1659 ipv6mr_interface: interface as _,
1660 };
1661 unsafe {
1662 setsockopt(
1663 self.as_raw(),
1664 sys::IPPROTO_IPV6,
1665 sys::IPV6_DROP_MEMBERSHIP,
1666 mreq,
1667 )
1668 }
1669 }
1670
1671 /// Get the value of the `IPV6_MULTICAST_HOPS` option for this socket
1672 ///
1673 /// For more information about this option, see [`set_multicast_hops_v6`].
1674 ///
1675 /// [`set_multicast_hops_v6`]: Socket::set_multicast_hops_v6
1676 pub fn multicast_hops_v6(&self) -> io::Result<u32> {
1677 unsafe {
1678 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_HOPS)
1679 .map(|hops| hops as u32)
1680 }
1681 }
1682
1683 /// Set the value of the `IPV6_MULTICAST_HOPS` option for this socket
1684 ///
1685 /// Indicates the number of "routers" multicast packets will transit for
1686 /// this socket. The default value is 1 which means that multicast packets
1687 /// don't leave the local network unless explicitly requested.
1688 pub fn set_multicast_hops_v6(&self, hops: u32) -> io::Result<()> {
1689 unsafe {
1690 setsockopt(
1691 self.as_raw(),
1692 sys::IPPROTO_IPV6,
1693 sys::IPV6_MULTICAST_HOPS,
1694 hops as c_int,
1695 )
1696 }
1697 }
1698
1699 /// Get the value of the `IPV6_MULTICAST_ALL` option for this socket.
1700 ///
1701 /// For more information about this option, see [`set_multicast_all_v6`].
1702 ///
1703 /// [`set_multicast_all_v6`]: Socket::set_multicast_all_v6
1704 #[cfg(all(feature = "all", target_os = "linux"))]
1705 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
1706 pub fn multicast_all_v6(&self) -> io::Result<bool> {
1707 unsafe {
1708 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, libc::IPV6_MULTICAST_ALL)
1709 .map(|all| all != 0)
1710 }
1711 }
1712
1713 /// Set the value of the `IPV6_MULTICAST_ALL` option for this socket.
1714 ///
1715 /// This option can be used to modify the delivery policy of
1716 /// multicast messages. The argument is a boolean
1717 /// (defaults to true). If set to true, the socket will receive
1718 /// messages from all the groups that have been joined
1719 /// globally on the whole system. Otherwise, it will deliver
1720 /// messages only from the groups that have been explicitly
1721 /// joined (for example via the `IPV6_ADD_MEMBERSHIP` option) on
1722 /// this particular socket.
1723 #[cfg(all(feature = "all", target_os = "linux"))]
1724 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
1725 pub fn set_multicast_all_v6(&self, all: bool) -> io::Result<()> {
1726 unsafe {
1727 setsockopt(
1728 self.as_raw(),
1729 sys::IPPROTO_IPV6,
1730 libc::IPV6_MULTICAST_ALL,
1731 all as c_int,
1732 )
1733 }
1734 }
1735
1736 /// Get the value of the `IPV6_MULTICAST_IF` option for this socket.
1737 ///
1738 /// For more information about this option, see [`set_multicast_if_v6`].
1739 ///
1740 /// [`set_multicast_if_v6`]: Socket::set_multicast_if_v6
1741 pub fn multicast_if_v6(&self) -> io::Result<u32> {
1742 unsafe {
1743 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_IF)
1744 .map(|interface| interface as u32)
1745 }
1746 }
1747
1748 /// Set the value of the `IPV6_MULTICAST_IF` option for this socket.
1749 ///
1750 /// Specifies the interface to use for routing multicast packets. Unlike
1751 /// ipv4, this is generally required in ipv6 contexts where network routing
1752 /// prefixes may overlap.
1753 pub fn set_multicast_if_v6(&self, interface: u32) -> io::Result<()> {
1754 unsafe {
1755 setsockopt(
1756 self.as_raw(),
1757 sys::IPPROTO_IPV6,
1758 sys::IPV6_MULTICAST_IF,
1759 interface as c_int,
1760 )
1761 }
1762 }
1763
1764 /// Get the value of the `IPV6_MULTICAST_LOOP` option for this socket.
1765 ///
1766 /// For more information about this option, see [`set_multicast_loop_v6`].
1767 ///
1768 /// [`set_multicast_loop_v6`]: Socket::set_multicast_loop_v6
1769 pub fn multicast_loop_v6(&self) -> io::Result<bool> {
1770 unsafe {
1771 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_LOOP)
1772 .map(|loop_v6| loop_v6 != 0)
1773 }
1774 }
1775
1776 /// Set the value of the `IPV6_MULTICAST_LOOP` option for this socket.
1777 ///
1778 /// Controls whether this socket sees the multicast packets it sends itself.
1779 /// Note that this may not have any affect on IPv4 sockets.
1780 pub fn set_multicast_loop_v6(&self, loop_v6: bool) -> io::Result<()> {
1781 unsafe {
1782 setsockopt(
1783 self.as_raw(),
1784 sys::IPPROTO_IPV6,
1785 sys::IPV6_MULTICAST_LOOP,
1786 loop_v6 as c_int,
1787 )
1788 }
1789 }
1790
1791 /// Get the value of the `IPV6_UNICAST_HOPS` option for this socket.
1792 ///
1793 /// Specifies the hop limit for ipv6 unicast packets
1794 pub fn unicast_hops_v6(&self) -> io::Result<u32> {
1795 unsafe {
1796 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_UNICAST_HOPS)
1797 .map(|hops| hops as u32)
1798 }
1799 }
1800
1801 /// Set the value for the `IPV6_UNICAST_HOPS` option on this socket.
1802 ///
1803 /// Specifies the hop limit for ipv6 unicast packets
1804 pub fn set_unicast_hops_v6(&self, hops: u32) -> io::Result<()> {
1805 unsafe {
1806 setsockopt(
1807 self.as_raw(),
1808 sys::IPPROTO_IPV6,
1809 sys::IPV6_UNICAST_HOPS,
1810 hops as c_int,
1811 )
1812 }
1813 }
1814
1815 /// Get the value of the `IPV6_V6ONLY` option for this socket.
1816 ///
1817 /// For more information about this option, see [`set_only_v6`].
1818 ///
1819 /// [`set_only_v6`]: Socket::set_only_v6
1820 pub fn only_v6(&self) -> io::Result<bool> {
1821 unsafe {
1822 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_V6ONLY)
1823 .map(|only_v6| only_v6 != 0)
1824 }
1825 }
1826
1827 /// Set the value for the `IPV6_V6ONLY` option on this socket.
1828 ///
1829 /// If this is set to `true` then the socket is restricted to sending and
1830 /// receiving IPv6 packets only. In this case two IPv4 and IPv6 applications
1831 /// can bind the same port at the same time.
1832 ///
1833 /// If this is set to `false` then the socket can be used to send and
1834 /// receive packets from an IPv4-mapped IPv6 address.
1835 pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
1836 unsafe {
1837 setsockopt(
1838 self.as_raw(),
1839 sys::IPPROTO_IPV6,
1840 sys::IPV6_V6ONLY,
1841 only_v6 as c_int,
1842 )
1843 }
1844 }
1845
1846 /// Get the value of the `IPV6_RECVTCLASS` option for this socket.
1847 ///
1848 /// For more information about this option, see [`set_recv_tclass_v6`].
1849 ///
1850 /// [`set_recv_tclass_v6`]: Socket::set_recv_tclass_v6
1851 #[cfg(not(any(
1852 target_os = "dragonfly",
1853 target_os = "fuchsia",
1854 target_os = "illumos",
1855 target_os = "netbsd",
1856 target_os = "openbsd",
1857 target_os = "redox",
1858 target_os = "solaris",
1859 target_os = "haiku",
1860 target_os = "hurd",
1861 target_os = "espidf",
1862 target_os = "vita",
1863 )))]
1864 pub fn recv_tclass_v6(&self) -> io::Result<bool> {
1865 unsafe {
1866 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_RECVTCLASS)
1867 .map(|recv_tclass| recv_tclass > 0)
1868 }
1869 }
1870
1871 /// Set the value of the `IPV6_RECVTCLASS` option for this socket.
1872 ///
1873 /// If enabled, the `IPV6_TCLASS` ancillary message is passed with incoming
1874 /// packets. It contains a byte which specifies the traffic class field of
1875 /// the packet header.
1876 #[cfg(not(any(
1877 target_os = "dragonfly",
1878 target_os = "fuchsia",
1879 target_os = "illumos",
1880 target_os = "netbsd",
1881 target_os = "openbsd",
1882 target_os = "redox",
1883 target_os = "solaris",
1884 target_os = "haiku",
1885 target_os = "hurd",
1886 target_os = "espidf",
1887 target_os = "vita",
1888 )))]
1889 pub fn set_recv_tclass_v6(&self, recv_tclass: bool) -> io::Result<()> {
1890 unsafe {
1891 setsockopt(
1892 self.as_raw(),
1893 sys::IPPROTO_IPV6,
1894 sys::IPV6_RECVTCLASS,
1895 recv_tclass as c_int,
1896 )
1897 }
1898 }
1899}
1900
1901/// Socket options for TCP sockets, get/set using `IPPROTO_TCP`.
1902///
1903/// Additional documentation can be found in documentation of the OS.
1904/// * Linux: <https://man7.org/linux/man-pages/man7/tcp.7.html>
1905/// * Windows: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-tcp-socket-options>
1906impl Socket {
1907 /// Get the value of the `TCP_KEEPIDLE` option on this socket.
1908 ///
1909 /// This returns the value of `TCP_KEEPALIVE` on macOS and iOS and `TCP_KEEPIDLE` on all other
1910 /// supported Unix operating systems.
1911 #[cfg(all(
1912 feature = "all",
1913 not(any(
1914 windows,
1915 target_os = "haiku",
1916 target_os = "openbsd",
1917 target_os = "vita"
1918 ))
1919 ))]
1920 #[cfg_attr(
1921 docsrs,
1922 doc(cfg(all(
1923 feature = "all",
1924 not(any(
1925 windows,
1926 target_os = "haiku",
1927 target_os = "openbsd",
1928 target_os = "vita"
1929 ))
1930 )))
1931 )]
1932 pub fn keepalive_time(&self) -> io::Result<Duration> {
1933 sys::keepalive_time(self.as_raw())
1934 }
1935
1936 /// Get the value of the `TCP_KEEPINTVL` option on this socket.
1937 ///
1938 /// For more information about this option, see [`set_tcp_keepalive`].
1939 ///
1940 /// [`set_tcp_keepalive`]: Socket::set_tcp_keepalive
1941 #[cfg(all(
1942 feature = "all",
1943 any(
1944 target_os = "android",
1945 target_os = "dragonfly",
1946 target_os = "freebsd",
1947 target_os = "fuchsia",
1948 target_os = "illumos",
1949 target_os = "ios",
1950 target_os = "linux",
1951 target_os = "macos",
1952 target_os = "netbsd",
1953 target_os = "tvos",
1954 target_os = "watchos",
1955 )
1956 ))]
1957 #[cfg_attr(
1958 docsrs,
1959 doc(cfg(all(
1960 feature = "all",
1961 any(
1962 target_os = "android",
1963 target_os = "dragonfly",
1964 target_os = "freebsd",
1965 target_os = "fuchsia",
1966 target_os = "illumos",
1967 target_os = "ios",
1968 target_os = "linux",
1969 target_os = "macos",
1970 target_os = "netbsd",
1971 target_os = "tvos",
1972 target_os = "watchos",
1973 )
1974 )))
1975 )]
1976 pub fn keepalive_interval(&self) -> io::Result<Duration> {
1977 unsafe {
1978 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_TCP, sys::TCP_KEEPINTVL)
1979 .map(|secs| Duration::from_secs(secs as u64))
1980 }
1981 }
1982
1983 /// Get the value of the `TCP_KEEPCNT` option on this socket.
1984 ///
1985 /// For more information about this option, see [`set_tcp_keepalive`].
1986 ///
1987 /// [`set_tcp_keepalive`]: Socket::set_tcp_keepalive
1988 #[cfg(all(
1989 feature = "all",
1990 any(
1991 target_os = "android",
1992 target_os = "dragonfly",
1993 target_os = "freebsd",
1994 target_os = "fuchsia",
1995 target_os = "illumos",
1996 target_os = "ios",
1997 target_os = "linux",
1998 target_os = "macos",
1999 target_os = "netbsd",
2000 target_os = "tvos",
2001 target_os = "watchos",
2002 )
2003 ))]
2004 #[cfg_attr(
2005 docsrs,
2006 doc(cfg(all(
2007 feature = "all",
2008 any(
2009 target_os = "android",
2010 target_os = "dragonfly",
2011 target_os = "freebsd",
2012 target_os = "fuchsia",
2013 target_os = "illumos",
2014 target_os = "ios",
2015 target_os = "linux",
2016 target_os = "macos",
2017 target_os = "netbsd",
2018 target_os = "tvos",
2019 target_os = "watchos",
2020 )
2021 )))
2022 )]
2023 pub fn keepalive_retries(&self) -> io::Result<u32> {
2024 unsafe {
2025 getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_TCP, sys::TCP_KEEPCNT)
2026 .map(|retries| retries as u32)
2027 }
2028 }
2029
2030 /// Set parameters configuring TCP keepalive probes for this socket.
2031 ///
2032 /// The supported parameters depend on the operating system, and are
2033 /// configured using the [`TcpKeepalive`] struct. At a minimum, all systems
2034 /// support configuring the [keepalive time]: the time after which the OS
2035 /// will start sending keepalive messages on an idle connection.
2036 ///
2037 /// [keepalive time]: TcpKeepalive::with_time
2038 ///
2039 /// # Notes
2040 ///
2041 /// * This will enable `SO_KEEPALIVE` on this socket, if it is not already
2042 /// enabled.
2043 /// * On some platforms, such as Windows, any keepalive parameters *not*
2044 /// configured by the `TcpKeepalive` struct passed to this function may be
2045 /// overwritten with their default values. Therefore, this function should
2046 /// either only be called once per socket, or the same parameters should
2047 /// be passed every time it is called.
2048 ///
2049 /// # Examples
2050 ///
2051 /// ```
2052 /// use std::time::Duration;
2053 ///
2054 /// use socket2::{Socket, TcpKeepalive, Domain, Type};
2055 ///
2056 /// # fn main() -> std::io::Result<()> {
2057 /// let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?;
2058 /// let keepalive = TcpKeepalive::new()
2059 /// .with_time(Duration::from_secs(4));
2060 /// // Depending on the target operating system, we may also be able to
2061 /// // configure the keepalive probe interval and/or the number of
2062 /// // retries here as well.
2063 ///
2064 /// socket.set_tcp_keepalive(&keepalive)?;
2065 /// # Ok(()) }
2066 /// ```
2067 ///
2068 pub fn set_tcp_keepalive(&self, params: &TcpKeepalive) -> io::Result<()> {
2069 self.set_keepalive(true)?;
2070 sys::set_tcp_keepalive(self.as_raw(), params)
2071 }
2072
2073 /// Get the value of the `TCP_NODELAY` option on this socket.
2074 ///
2075 /// For more information about this option, see [`set_nodelay`].
2076 ///
2077 /// [`set_nodelay`]: Socket::set_nodelay
2078 pub fn nodelay(&self) -> io::Result<bool> {
2079 unsafe {
2080 getsockopt::<Bool>(self.as_raw(), sys::IPPROTO_TCP, sys::TCP_NODELAY)
2081 .map(|nodelay| nodelay != 0)
2082 }
2083 }
2084
2085 /// Set the value of the `TCP_NODELAY` option on this socket.
2086 ///
2087 /// If set, this option disables the Nagle algorithm. This means that
2088 /// segments are always sent as soon as possible, even if there is only a
2089 /// small amount of data. When not set, data is buffered until there is a
2090 /// sufficient amount to send out, thereby avoiding the frequent sending of
2091 /// small packets.
2092 pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
2093 unsafe {
2094 setsockopt(
2095 self.as_raw(),
2096 sys::IPPROTO_TCP,
2097 sys::TCP_NODELAY,
2098 nodelay as c_int,
2099 )
2100 }
2101 }
2102}
2103
2104impl Read for Socket {
2105 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
2106 // Safety: the `recv` implementation promises not to write uninitialised
2107 // bytes to the `buf`fer, so this casting is safe.
2108 let buf: &mut [MaybeUninit] = unsafe { &mut *(buf as *mut [u8] as *mut [MaybeUninit<u8>]) };
2109 self.recv(buf)
2110 }
2111
2112 #[cfg(not(target_os = "redox"))]
2113 fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
2114 // Safety: both `IoSliceMut` and `MaybeUninitSlice` promise to have the
2115 // same layout, that of `iovec`/`WSABUF`. Furthermore `recv_vectored`
2116 // promises to not write unitialised bytes to the `bufs` and pass it
2117 // directly to the `recvmsg` system call, so this is safe.
2118 let bufs: &mut [MaybeUninitSlice<'_>] = unsafe { &mut *(bufs as *mut [IoSliceMut<'_>] as *mut [MaybeUninitSlice<'_>]) };
2119 self.recv_vectored(bufs).map(|(n: usize, _)| n)
2120 }
2121}
2122
2123impl<'a> Read for &'a Socket {
2124 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
2125 // Safety: see other `Read::read` impl.
2126 let buf: &mut [MaybeUninit] = unsafe { &mut *(buf as *mut [u8] as *mut [MaybeUninit<u8>]) };
2127 self.recv(buf)
2128 }
2129
2130 #[cfg(not(target_os = "redox"))]
2131 fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
2132 // Safety: see other `Read::read` impl.
2133 let bufs: &mut [MaybeUninitSlice<'_>] = unsafe { &mut *(bufs as *mut [IoSliceMut<'_>] as *mut [MaybeUninitSlice<'_>]) };
2134 self.recv_vectored(bufs).map(|(n: usize, _)| n)
2135 }
2136}
2137
2138impl Write for Socket {
2139 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
2140 self.send(buf)
2141 }
2142
2143 #[cfg(not(target_os = "redox"))]
2144 fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
2145 self.send_vectored(bufs)
2146 }
2147
2148 fn flush(&mut self) -> io::Result<()> {
2149 Ok(())
2150 }
2151}
2152
2153impl<'a> Write for &'a Socket {
2154 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
2155 self.send(buf)
2156 }
2157
2158 #[cfg(not(target_os = "redox"))]
2159 fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
2160 self.send_vectored(bufs)
2161 }
2162
2163 fn flush(&mut self) -> io::Result<()> {
2164 Ok(())
2165 }
2166}
2167
2168impl fmt::Debug for Socket {
2169 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2170 f&mut DebugStruct<'_, '_>.debug_struct("Socket")
2171 .field("raw", &self.as_raw())
2172 .field("local_addr", &self.local_addr().ok())
2173 .field(name:"peer_addr", &self.peer_addr().ok())
2174 .finish()
2175 }
2176}
2177
2178from!(net::TcpStream, Socket);
2179from!(net::TcpListener, Socket);
2180from!(net::UdpSocket, Socket);
2181from!(Socket, net::TcpStream);
2182from!(Socket, net::TcpListener);
2183from!(Socket, net::UdpSocket);
2184