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