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