Coverage Report

Created: 2025-07-11 07:00

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