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