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