mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
Bug 1716518 - Upgrade socket2 to v0.3.19.
Differential Revision: https://phabricator.services.mozilla.com/D117862 Depends on D117861
This commit is contained in:
parent
4c2c284417
commit
79ae0b3aff
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -4706,13 +4706,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.3.10"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df028e0e632c2a1823d920ad74895e7f9128e6438cbc4bc6fd1f180e644767b9"
|
||||
checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
|
@ -1 +1 @@
|
||||
{"files":{"Cargo.toml":"183f6012d61dc2388de7c5d5453c03a3f9971c00203ec95b17d11a463fc7a44f","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"76b59d53338de3386da807f4d5028cb2a73d027e5d7747e2ad04e2ef113c41dc","src/lib.rs":"4c2966cd283751a96f1769fbe529fd1105bc2a8ac15dc2148b6cfc4cca24cd38","src/sockaddr.rs":"66a14de3a133fb81cefb30737a4470de38c12cd04b115fdd98b1ef7870c22e19","src/socket.rs":"674a1ecb5a7caa256533e85d075afe43c6e97eaf9b68fcaacaaaeb29eb338040","src/sys/redox/mod.rs":"a6ba2a38a7af83a3c85cee892f2a2dc7c66aba267e50f02f682eee938f067e95","src/sys/unix.rs":"8fadee55eb4ed7d6c18700b3e673667b1a4f29ec3a3280194a60c0fe6a7fbad1","src/sys/windows.rs":"2e914bf3aa08452ebf3358f941f93469b7eb2982909d620139f263c3bb82f28a","src/utils.rs":"53968de8c8e078a650fa316438622be9bb78bca95ed07c4f8da2c940ae27e0ae"},"package":"df028e0e632c2a1823d920ad74895e7f9128e6438cbc4bc6fd1f180e644767b9"}
|
||||
{"files":{"Cargo.toml":"54fecae223099432de172b711c6f23f4bb46d99e8fcb3f63f52ae1960c23b8c6","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"9c3d94f57a3464986df30edf46250fa70200b40b9c70d8cac6b2fc3a76d24631","SO_ACCEPTCONN.patch":"e942fd2208a41d2b895354a6d80bc0c4aed875d48e6f5a66fa94cf193233c5c2","TODO":"4d0c6a6a858204015a6eac72f2e6d6fc8638ee78595c5600a07a8015975fdaf2","check_targets.bash":"dd9de020e3991988c8183327ab1d1b7c0cfbb21364676a6c4b8a4a0f8fafd6ef","diff.patch":"acb27c495149dab10f9436efcca5f5637d2f4a1527028eeeb58858a3e1ad13e0","src/lib.rs":"1f2159502b551883652e32a02a6f4d60b284ad916cd970994c8beb40b4cc9118","src/sockaddr.rs":"109824754ba77687a47e51a3ed5f8b0abecbe397a633a99fc94cc637bc698d76","src/socket.rs":"6aeb83003381e4a4424c2c7b08bd01bbd837fd4edcec156983df07316e1dca57","src/sys/unix.rs":"10e3d4d2e4e460f45acc670c7fb9ad24f3f60cdf0971bf4ed6f94e158e0551a8","src/sys/windows.rs":"5180e6fbe029fcfc710e1d3498646f4a13b39a7eb62a2b3b0b01c29a7e9dc411","src/tests.rs":"d17e44cc61c646f41b4a18a7f7cb4e632ea34dc1c7d347928e0ed6295840a0ae","src/utils.rs":"53968de8c8e078a650fa316438622be9bb78bca95ed07c4f8da2c940ae27e0ae"},"package":"122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e"}
|
13
third_party/rust/socket2/Cargo.toml
vendored
13
third_party/rust/socket2/Cargo.toml
vendored
@ -13,7 +13,7 @@
|
||||
[package]
|
||||
edition = "2018"
|
||||
name = "socket2"
|
||||
version = "0.3.10"
|
||||
version = "0.3.19"
|
||||
authors = ["Alex Crichton <alex@alexcrichton.com>"]
|
||||
description = "Utilities for handling networking sockets with a maximal amount of configuration\npossible intended.\n"
|
||||
homepage = "https://github.com/alexcrichton/socket2-rs"
|
||||
@ -29,13 +29,12 @@ version = "0.3"
|
||||
pair = []
|
||||
reuseport = []
|
||||
unix = []
|
||||
[target."cfg(any(unix, target_os = \"redox\"))".dependencies.cfg-if]
|
||||
version = "0.1"
|
||||
[target."cfg(unix)".dependencies.cfg-if]
|
||||
version = "1.0"
|
||||
|
||||
[target."cfg(any(unix, target_os = \"redox\"))".dependencies.libc]
|
||||
version = "0.2.42"
|
||||
[target."cfg(target_os = \"redox\")".dependencies.redox_syscall]
|
||||
version = "0.1.38"
|
||||
[target."cfg(unix)".dependencies.libc]
|
||||
version = "0.2.66"
|
||||
features = ["align"]
|
||||
[target."cfg(windows)".dependencies.winapi]
|
||||
version = "0.3.3"
|
||||
features = ["handleapi", "ws2def", "ws2ipdef", "ws2tcpip", "minwindef"]
|
||||
|
3
third_party/rust/socket2/README.md
vendored
3
third_party/rust/socket2/README.md
vendored
@ -1,8 +1,5 @@
|
||||
# socket2-rs
|
||||
|
||||
[![Build Status](https://travis-ci.com/alexcrichton/socket2-rs.svg?branch=master)](https://travis-ci.com/alexcrichton/socket2-rs)
|
||||
[![Build status](https://ci.appveyor.com/api/projects/status/hovebj1gr4bgm3d9?svg=true)](https://ci.appveyor.com/project/alexcrichton/socket2-rs)
|
||||
|
||||
[Documentation](https://docs.rs/socket2)
|
||||
|
||||
# License
|
||||
|
96
third_party/rust/socket2/SO_ACCEPTCONN.patch
vendored
Normal file
96
third_party/rust/socket2/SO_ACCEPTCONN.patch
vendored
Normal file
@ -0,0 +1,96 @@
|
||||
diff --git a/src/socket.rs b/src/socket.rs
|
||||
index 725ad2a..3f7b499 100644
|
||||
--- a/src/socket.rs
|
||||
+++ b/src/socket.rs
|
||||
@@ -963,6 +963,26 @@ fn inner(&self) -> &sys::Socket {
|
||||
}
|
||||
}
|
||||
|
||||
+/// Socket options get/set using `SOL_SOCKET`.
|
||||
+///
|
||||
+/// Additional documentation can be found in documentation of the OS.
|
||||
+/// * Linux: <https://man7.org/linux/man-pages/man7/socket.7.html>
|
||||
+/// * Windows: <https://docs.microsoft.com/en-us/windows/win32/winsock/sol-socket-socket-options>
|
||||
+impl Socket {
|
||||
+ /// Gets the value of the `SO_ACCEPTCONN` option on this socket.
|
||||
+ ///
|
||||
+ /// Returns `true` if this socket has been marked to accept connections with
|
||||
+ /// [`listen`].
|
||||
+ ///
|
||||
+ /// [`listen`]: Socket::listen
|
||||
+ pub fn is_listener(&self) -> io::Result<bool> {
|
||||
+ unsafe {
|
||||
+ getsockopt::<c_int>(self.inner, sys::SOL_SOCKET, sys::SO_ACCEPTCONN)
|
||||
+ .map(|is_listener| is_listener != 0)
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/// Socket options for TCP socket, get/set using `IPPROTO_TCP`.
|
||||
///
|
||||
/// Additional documentation can be found in documentation of the OS.
|
||||
diff --git a/src/sys/unix.rs b/src/sys/unix.rs
|
||||
index 60593a1..51b916a 100644
|
||||
--- a/src/sys/unix.rs
|
||||
+++ b/src/sys/unix.rs
|
||||
@@ -54,8 +54,8 @@
|
||||
pub(crate) use libc::MSG_OOB;
|
||||
pub(crate) use libc::{
|
||||
IPPROTO_IP, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, IPV6_MULTICAST_LOOP, IPV6_UNICAST_HOPS,
|
||||
- IPV6_V6ONLY, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_TTL, MSG_PEEK, SOL_SOCKET, SO_BROADCAST,
|
||||
- SO_ERROR, TCP_NODELAY,
|
||||
+ IPV6_V6ONLY, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_TTL, MSG_PEEK, SOL_SOCKET, SO_ACCEPTCONN,
|
||||
+ SO_BROADCAST, SO_ERROR, TCP_NODELAY,
|
||||
};
|
||||
|
||||
// See this type in the Windows file.
|
||||
diff --git a/src/sys/windows.rs b/src/sys/windows.rs
|
||||
index 663b63f..a212525 100644
|
||||
--- a/src/sys/windows.rs
|
||||
+++ b/src/sys/windows.rs
|
||||
@@ -60,7 +60,7 @@
|
||||
pub(crate) use winapi::um::ws2tcpip::socklen_t;
|
||||
// Used in `Socket`.
|
||||
pub(crate) use winapi::shared::ws2def::{
|
||||
- IPPROTO_IP, SOL_SOCKET, SO_BROADCAST, SO_ERROR, TCP_NODELAY,
|
||||
+ IPPROTO_IP, SOL_SOCKET, SO_ACCEPTCONN, SO_BROADCAST, SO_ERROR, TCP_NODELAY,
|
||||
};
|
||||
pub(crate) use winapi::shared::ws2ipdef::{
|
||||
IPV6_MULTICAST_HOPS, IPV6_MULTICAST_LOOP, IPV6_UNICAST_HOPS, IPV6_V6ONLY, IP_MULTICAST_LOOP,
|
||||
diff --git a/tests/options.rs b/tests/options.rs
|
||||
index 9c3d1c2..2d256a7 100644
|
||||
--- a/tests/options.rs
|
||||
+++ b/tests/options.rs
|
||||
@@ -1,6 +1,8 @@
|
||||
//! Tests for getting and setting socket options.
|
||||
|
||||
-use socket2::{Domain, Socket, Type};
|
||||
+use std::net::SocketAddr;
|
||||
+
|
||||
+use socket2::{Domain, Protocol, Socket, Type};
|
||||
|
||||
/// Macro to create a simple test to set and get a socket option.
|
||||
macro_rules! test {
|
||||
@@ -86,6 +88,22 @@ fn $get_fn() {
|
||||
set_mark(123)
|
||||
);
|
||||
|
||||
+#[test]
|
||||
+fn is_listener() {
|
||||
+ // TODO: IPv6.
|
||||
+
|
||||
+ let socket = Socket::new(Domain::IPV4, Type::STREAM, Some(Protocol::TCP))
|
||||
+ .expect("failed to create `Socket`");
|
||||
+ //assert_eq!(socket.is_listener().unwrap(), false);
|
||||
+
|
||||
+ let addr: SocketAddr = "127.0.0.1:0".parse().unwrap();
|
||||
+ let addr = addr.into();
|
||||
+ socket.bind(&addr).unwrap();
|
||||
+ socket.listen(1).unwrap();
|
||||
+ dbg!(socket.is_listener());
|
||||
+ assert_eq!(socket.is_listener().unwrap(), true);
|
||||
+}
|
||||
+
|
||||
test!(IPv4 ttl, set_ttl(40));
|
||||
#[cfg(not(windows))] // TODO: returns `WSAENOPROTOOPT` (10042) on Windows.
|
||||
test!(IPv4 broadcast, set_broadcast(true));
|
20
third_party/rust/socket2/TODO
vendored
Normal file
20
third_party/rust/socket2/TODO
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
# Refactor
|
||||
|
||||
* [ ] CONTRIBUTING.md
|
||||
* [ ] Move tests from src/*.rs to tests dir.
|
||||
* [ ] Tracking issue for tests. Check all functions/coverage (with `rustcov`).
|
||||
* [ ] Look at `SockAddr`.
|
||||
* [ ] Add docs about its size.
|
||||
|
||||
## Maybe add socket options
|
||||
|
||||
# SOL_SOCKET
|
||||
SO_ACCEPTCONN
|
||||
SO_DOMAIN
|
||||
SO_TYPE
|
||||
SO_INCOMING_CPU // Linux only?
|
||||
SO_INCOMING_NAPI_ID // Linux only?
|
||||
|
||||
# No-op/error returned on Windows:
|
||||
SO_RCVLOWAT
|
||||
SO_SNDLOWAT
|
15
third_party/rust/socket2/check_targets.bash
vendored
Executable file
15
third_party/rust/socket2/check_targets.bash
vendored
Executable file
@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eu
|
||||
|
||||
declare -a targets=(
|
||||
"x86_64-apple-darwin"
|
||||
"x86_64-unknown-freebsd"
|
||||
"x86_64-unknown-linux-gnu"
|
||||
"x86_64-pc-windows-gnu"
|
||||
)
|
||||
|
||||
for target in "${targets[@]}"; do
|
||||
cargo check --target "$target" --all-targets --examples --bins --tests --no-default-features
|
||||
cargo check --target "$target" --all-targets --examples --bins --tests --all-features
|
||||
done
|
134
third_party/rust/socket2/diff.patch
vendored
Normal file
134
third_party/rust/socket2/diff.patch
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
commit 3851430dec41c204d6219a84c47ca6885622a98e
|
||||
Author: kolapapa <kola@kolapapas-MacBook-Pro.local>
|
||||
Date: Sun Dec 20 14:02:52 2020 +0100
|
||||
|
||||
Add Socket::(bind_)device
|
||||
|
||||
Co-authored-by: Thomas de Zeeuw <thomasdezeeuw@gmail.com>
|
||||
|
||||
diff --git a/src/sys/unix.rs b/src/sys/unix.rs
|
||||
index 72097ae..1a0f24e 100644
|
||||
--- a/src/sys/unix.rs
|
||||
+++ b/src/sys/unix.rs
|
||||
@@ -7,6 +7,8 @@
|
||||
// except according to those terms.
|
||||
|
||||
use std::cmp::min;
|
||||
+#[cfg(all(feature = "all", target_os = "linux"))]
|
||||
+use std::ffi::{CStr, CString};
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
use std::io::{IoSlice, IoSliceMut};
|
||||
use std::mem::{self, size_of, MaybeUninit};
|
||||
@@ -19,6 +21,8 @@
|
||||
use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream};
|
||||
#[cfg(feature = "all")]
|
||||
use std::path::Path;
|
||||
+#[cfg(all(feature = "all", target_os = "linux"))]
|
||||
+use std::slice;
|
||||
use std::time::Duration;
|
||||
use std::{io, ptr};
|
||||
|
||||
@@ -867,6 +871,73 @@ pub fn set_mark(&self, mark: u32) -> io::Result<()> {
|
||||
unsafe { setsockopt::<c_int>(self.inner, libc::SOL_SOCKET, libc::SO_MARK, mark as c_int) }
|
||||
}
|
||||
|
||||
+ /// Gets the value for the `SO_BINDTODEVICE` option on this socket.
|
||||
+ ///
|
||||
+ /// This value gets the socket binded device's interface name.
|
||||
+ ///
|
||||
+ /// This function is only available on Linux.
|
||||
+ #[cfg(all(feature = "all", target_os = "linux"))]
|
||||
+ pub fn device(&self) -> io::Result<Option<CString>> {
|
||||
+ // TODO: replace with `MaybeUninit::uninit_array` once stable.
|
||||
+ let mut buf: [MaybeUninit<u8>; libc::IFNAMSIZ] =
|
||||
+ unsafe { MaybeUninit::<[MaybeUninit<u8>; libc::IFNAMSIZ]>::uninit().assume_init() };
|
||||
+ let mut len = buf.len() as libc::socklen_t;
|
||||
+ unsafe {
|
||||
+ syscall!(getsockopt(
|
||||
+ self.inner,
|
||||
+ libc::SOL_SOCKET,
|
||||
+ libc::SO_BINDTODEVICE,
|
||||
+ buf.as_mut_ptr().cast(),
|
||||
+ &mut len,
|
||||
+ ))?;
|
||||
+ }
|
||||
+ if len == 0 {
|
||||
+ Ok(None)
|
||||
+ } else {
|
||||
+ // Allocate a buffer for `CString` with the length including the
|
||||
+ // null terminator.
|
||||
+ let len = len as usize;
|
||||
+ let mut name = Vec::with_capacity(len);
|
||||
+
|
||||
+ // TODO: use `MaybeUninit::slice_assume_init_ref` once stable.
|
||||
+ // Safety: `len` bytes are writen by the OS, this includes a null
|
||||
+ // terminator. However we don't copy the null terminator because
|
||||
+ // `CString::from_vec_unchecked` adds its own null terminator.
|
||||
+ let buf = unsafe { slice::from_raw_parts(buf.as_ptr().cast(), len - 1) };
|
||||
+ name.extend_from_slice(buf);
|
||||
+
|
||||
+ // Safety: the OS initialised the string for us, which shouldn't
|
||||
+ // include any null bytes.
|
||||
+ Ok(Some(unsafe { CString::from_vec_unchecked(name) }))
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /// Sets the value for the `SO_BINDTODEVICE` option on this socket.
|
||||
+ ///
|
||||
+ /// If a socket is bound to an interface, only packets received from that
|
||||
+ /// particular interface are processed by the socket. Note that this only
|
||||
+ /// works for some socket types, particularly `AF_INET` sockets.
|
||||
+ ///
|
||||
+ /// If `interface` is `None` or an empty string it removes the binding.
|
||||
+ ///
|
||||
+ /// This function is only available on Linux.
|
||||
+ #[cfg(all(feature = "all", target_os = "linux"))]
|
||||
+ pub fn bind_device(&self, interface: Option<&CStr>) -> io::Result<()> {
|
||||
+ let (value, len) = if let Some(interface) = interface {
|
||||
+ (interface.as_ptr(), interface.to_bytes_with_nul().len())
|
||||
+ } else {
|
||||
+ (ptr::null(), 0)
|
||||
+ };
|
||||
+ syscall!(setsockopt(
|
||||
+ self.inner,
|
||||
+ libc::SOL_SOCKET,
|
||||
+ libc::SO_BINDTODEVICE,
|
||||
+ value.cast(),
|
||||
+ len as libc::socklen_t,
|
||||
+ ))
|
||||
+ .map(|_| ())
|
||||
+ }
|
||||
+
|
||||
/// Get the value of the `SO_REUSEPORT` option on this socket.
|
||||
///
|
||||
/// For more information about this option, see [`set_reuse_port`].
|
||||
diff --git a/tests/socket.rs b/tests/socket.rs
|
||||
index 11a3d9c..75890af 100644
|
||||
--- a/tests/socket.rs
|
||||
+++ b/tests/socket.rs
|
||||
@@ -1,3 +1,5 @@
|
||||
+#[cfg(all(feature = "all", target_os = "linux"))]
|
||||
+use std::ffi::CStr;
|
||||
#[cfg(any(windows, target_vendor = "apple"))]
|
||||
use std::io;
|
||||
#[cfg(unix)]
|
||||
@@ -271,3 +273,19 @@ fn keepalive() {
|
||||
))]
|
||||
assert_eq!(socket.keepalive_retries().unwrap(), 10);
|
||||
}
|
||||
+
|
||||
+#[cfg(all(feature = "all", target_os = "linux"))]
|
||||
+#[test]
|
||||
+fn device() {
|
||||
+ const INTERFACE: &str = "lo0\0";
|
||||
+ let interface = CStr::from_bytes_with_nul(INTERFACE.as_bytes()).unwrap();
|
||||
+ let socket = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap();
|
||||
+
|
||||
+ assert_eq!(socket.device().unwrap(), None);
|
||||
+
|
||||
+ socket.bind_device(Some(interface)).unwrap();
|
||||
+ assert_eq!(socket.device().unwrap().as_deref(), Some(interface));
|
||||
+
|
||||
+ socket.bind_device(None).unwrap();
|
||||
+ assert_eq!(socket.device().unwrap(), None);
|
||||
+}
|
192
third_party/rust/socket2/src/lib.rs
vendored
192
third_party/rust/socket2/src/lib.rs
vendored
@ -39,64 +39,56 @@
|
||||
|
||||
use crate::utils::NetInt;
|
||||
|
||||
#[cfg(any(unix, target_os = "redox"))]
|
||||
use libc::{sockaddr_storage, socklen_t};
|
||||
#[cfg(windows)]
|
||||
use winapi::shared::ws2def::SOCKADDR_STORAGE as sockaddr_storage;
|
||||
#[cfg(windows)]
|
||||
use winapi::um::ws2tcpip::socklen_t;
|
||||
/// Macro to implement `fmt::Debug` for a type, printing the constant names
|
||||
/// rather than a number.
|
||||
///
|
||||
/// Note this is used in the `sys` module and thus must be defined before
|
||||
/// defining the modules.
|
||||
macro_rules! impl_debug {
|
||||
(
|
||||
// Type name for which to implement `fmt::Debug`.
|
||||
$type: path,
|
||||
$(
|
||||
$(#[$target: meta])*
|
||||
// The flag(s) to check.
|
||||
// Need to specific the libc crate because Windows doesn't use
|
||||
// `libc` but `winapi`.
|
||||
$libc: ident :: $flag: ident
|
||||
),+ $(,)*
|
||||
) => {
|
||||
impl std::fmt::Debug for $type {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let string = match self.0 {
|
||||
$(
|
||||
$(#[$target])*
|
||||
$libc :: $flag => stringify!($flag),
|
||||
)+
|
||||
n => return write!(f, "{}", n),
|
||||
};
|
||||
f.write_str(string)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
mod sockaddr;
|
||||
mod socket;
|
||||
mod utils;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
#[cfg(unix)]
|
||||
#[path = "sys/unix.rs"]
|
||||
mod sys;
|
||||
#[cfg(windows)]
|
||||
#[path = "sys/windows.rs"]
|
||||
mod sys;
|
||||
#[cfg(target_os = "redox")]
|
||||
#[path = "sys/redox/mod.rs"]
|
||||
mod sys;
|
||||
|
||||
/// Newtype, owned, wrapper around a system socket.
|
||||
///
|
||||
/// This type simply wraps an instance of a file descriptor (`c_int`) on Unix
|
||||
/// and an instance of `SOCKET` on Windows. This is the main type exported by
|
||||
/// this crate and is intended to mirror the raw semantics of sockets on
|
||||
/// platforms as closely as possible. Almost all methods correspond to
|
||||
/// precisely one libc or OS API call which is essentially just a "Rustic
|
||||
/// translation" of what's below.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::net::SocketAddr;
|
||||
/// use socket2::{Socket, Domain, Type, SockAddr};
|
||||
///
|
||||
/// // create a TCP listener bound to two addresses
|
||||
/// let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap();
|
||||
///
|
||||
/// socket.bind(&"127.0.0.1:12345".parse::<SocketAddr>().unwrap().into()).unwrap();
|
||||
/// socket.bind(&"127.0.0.1:12346".parse::<SocketAddr>().unwrap().into()).unwrap();
|
||||
/// socket.listen(128).unwrap();
|
||||
///
|
||||
/// let listener = socket.into_tcp_listener();
|
||||
/// // ...
|
||||
/// ```
|
||||
pub struct Socket {
|
||||
inner: sys::Socket,
|
||||
}
|
||||
use sys::c_int;
|
||||
|
||||
/// The address of a socket.
|
||||
///
|
||||
/// `SockAddr`s may be constructed directly to and from the standard library
|
||||
/// `SocketAddr`, `SocketAddrV4`, and `SocketAddrV6` types.
|
||||
pub struct SockAddr {
|
||||
storage: sockaddr_storage,
|
||||
len: socklen_t,
|
||||
}
|
||||
pub use sockaddr::SockAddr;
|
||||
pub use socket::Socket;
|
||||
|
||||
/// Specification of the communication domain for a socket.
|
||||
///
|
||||
@ -105,10 +97,34 @@ pub struct SockAddr {
|
||||
/// such as `Domain::ipv4`, `Domain::ipv6`, etc, are provided to avoid reaching
|
||||
/// into libc for various constants.
|
||||
///
|
||||
/// This type is freely interconvertible with the `i32` type, however, if a raw
|
||||
/// This type is freely interconvertible with C's `int` type, however, if a raw
|
||||
/// value needs to be provided.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Domain(i32);
|
||||
pub struct Domain(c_int);
|
||||
|
||||
impl Domain {
|
||||
/// Domain for IPv4 communication, corresponding to `AF_INET`.
|
||||
pub fn ipv4() -> Domain {
|
||||
Domain(sys::AF_INET)
|
||||
}
|
||||
|
||||
/// Domain for IPv6 communication, corresponding to `AF_INET6`.
|
||||
pub fn ipv6() -> Domain {
|
||||
Domain(sys::AF_INET6)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<c_int> for Domain {
|
||||
fn from(d: c_int) -> Domain {
|
||||
Domain(d)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Domain> for c_int {
|
||||
fn from(d: Domain) -> c_int {
|
||||
d.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Specification of communication semantics on a socket.
|
||||
///
|
||||
@ -117,26 +133,98 @@ pub struct Domain(i32);
|
||||
/// such as `Type::stream`, `Type::dgram`, etc, are provided to avoid reaching
|
||||
/// into libc for various constants.
|
||||
///
|
||||
/// This type is freely interconvertible with the `i32` type, however, if a raw
|
||||
/// This type is freely interconvertible with C's `int` type, however, if a raw
|
||||
/// value needs to be provided.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Type(i32);
|
||||
pub struct Type(c_int);
|
||||
|
||||
impl Type {
|
||||
/// Type corresponding to `SOCK_STREAM`.
|
||||
///
|
||||
/// Used for protocols such as TCP.
|
||||
pub fn stream() -> Type {
|
||||
Type(sys::SOCK_STREAM)
|
||||
}
|
||||
|
||||
/// Type corresponding to `SOCK_DGRAM`.
|
||||
///
|
||||
/// Used for protocols such as UDP.
|
||||
pub fn dgram() -> Type {
|
||||
Type(sys::SOCK_DGRAM)
|
||||
}
|
||||
|
||||
/// Type corresponding to `SOCK_SEQPACKET`.
|
||||
pub fn seqpacket() -> Type {
|
||||
Type(sys::SOCK_SEQPACKET)
|
||||
}
|
||||
|
||||
/// Type corresponding to `SOCK_RAW`.
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
pub fn raw() -> Type {
|
||||
Type(sys::SOCK_RAW)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<c_int> for Type {
|
||||
fn from(t: c_int) -> Type {
|
||||
Type(t)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Type> for c_int {
|
||||
fn from(t: Type) -> c_int {
|
||||
t.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Protocol specification used for creating sockets via `Socket::new`.
|
||||
///
|
||||
/// This is a newtype wrapper around an integer which provides a nicer API in
|
||||
/// addition to an injection point for documentation.
|
||||
///
|
||||
/// This type is freely interconvertible with the `i32` type, however, if a raw
|
||||
/// This type is freely interconvertible with C's `int` type, however, if a raw
|
||||
/// value needs to be provided.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Protocol(i32);
|
||||
pub struct Protocol(c_int);
|
||||
|
||||
impl Protocol {
|
||||
/// Protocol corresponding to `ICMPv4`.
|
||||
pub fn icmpv4() -> Self {
|
||||
Protocol(sys::IPPROTO_ICMP)
|
||||
}
|
||||
|
||||
/// Protocol corresponding to `ICMPv6`.
|
||||
pub fn icmpv6() -> Self {
|
||||
Protocol(sys::IPPROTO_ICMPV6)
|
||||
}
|
||||
|
||||
/// Protocol corresponding to `TCP`.
|
||||
pub fn tcp() -> Self {
|
||||
Protocol(sys::IPPROTO_TCP)
|
||||
}
|
||||
|
||||
/// Protocol corresponding to `UDP`.
|
||||
pub fn udp() -> Self {
|
||||
Protocol(sys::IPPROTO_UDP)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<c_int> for Protocol {
|
||||
fn from(p: c_int) -> Protocol {
|
||||
Protocol(p)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Protocol> for c_int {
|
||||
fn from(p: Protocol) -> c_int {
|
||||
p.0
|
||||
}
|
||||
}
|
||||
|
||||
fn hton<I: NetInt>(i: I) -> I {
|
||||
i.to_be()
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
fn ntoh<I: NetInt>(i: I) -> I {
|
||||
I::from_be(i)
|
||||
}
|
||||
|
189
third_party/rust/socket2/src/sockaddr.rs
vendored
189
third_party/rust/socket2/src/sockaddr.rs
vendored
@ -1,24 +1,35 @@
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
|
||||
use std::mem::{self, MaybeUninit};
|
||||
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
|
||||
use std::ptr;
|
||||
|
||||
#[cfg(any(unix, target_os = "redox"))]
|
||||
use libc::{
|
||||
sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t, AF_INET,
|
||||
AF_INET6,
|
||||
in6_addr, in_addr, sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage,
|
||||
socklen_t, AF_INET, AF_INET6,
|
||||
};
|
||||
#[cfg(windows)]
|
||||
use winapi::shared::in6addr::{in6_addr_u, IN6_ADDR as in6_addr};
|
||||
#[cfg(windows)]
|
||||
use winapi::shared::inaddr::{in_addr_S_un, IN_ADDR as in_addr};
|
||||
#[cfg(windows)]
|
||||
use winapi::shared::ws2def::{
|
||||
ADDRESS_FAMILY as sa_family_t, AF_INET, AF_INET6, SOCKADDR as sockaddr,
|
||||
SOCKADDR_IN as sockaddr_in, SOCKADDR_STORAGE as sockaddr_storage,
|
||||
};
|
||||
#[cfg(windows)]
|
||||
use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH as sockaddr_in6;
|
||||
use winapi::shared::ws2ipdef::{SOCKADDR_IN6_LH_u, SOCKADDR_IN6_LH as sockaddr_in6};
|
||||
#[cfg(windows)]
|
||||
use winapi::um::ws2tcpip::socklen_t;
|
||||
|
||||
use crate::SockAddr;
|
||||
/// The address of a socket.
|
||||
///
|
||||
/// `SockAddr`s may be constructed directly to and from the standard library
|
||||
/// `SocketAddr`, `SocketAddrV4`, and `SocketAddrV6` types.
|
||||
pub struct SockAddr {
|
||||
storage: sockaddr_storage,
|
||||
len: socklen_t,
|
||||
}
|
||||
|
||||
impl fmt::Debug for SockAddr {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
@ -36,16 +47,17 @@ impl fmt::Debug for SockAddr {
|
||||
impl SockAddr {
|
||||
/// Constructs a `SockAddr` from its raw components.
|
||||
pub unsafe fn from_raw_parts(addr: *const sockaddr, len: socklen_t) -> SockAddr {
|
||||
let mut storage = mem::uninitialized::<sockaddr_storage>();
|
||||
let mut storage = MaybeUninit::<sockaddr_storage>::zeroed();
|
||||
ptr::copy_nonoverlapping(
|
||||
addr as *const _ as *const u8,
|
||||
&mut storage as *mut _ as *mut u8,
|
||||
storage.as_mut_ptr() as *mut u8,
|
||||
len as usize,
|
||||
);
|
||||
|
||||
SockAddr {
|
||||
storage: storage,
|
||||
len: len,
|
||||
// This is safe as we written the address to `storage` above.
|
||||
storage: storage.assume_init(),
|
||||
len,
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,24 +124,63 @@ impl SockAddr {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn as_<T>(&self, family: sa_family_t) -> Option<T> {
|
||||
if self.storage.ss_family != family {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(mem::transmute_copy(&self.storage))
|
||||
}
|
||||
|
||||
/// Returns this address as a `SocketAddrV4` if it is in the `AF_INET`
|
||||
/// family.
|
||||
pub fn as_inet(&self) -> Option<SocketAddrV4> {
|
||||
unsafe { self.as_(AF_INET as sa_family_t) }
|
||||
match self.as_std() {
|
||||
Some(SocketAddr::V4(addr)) => Some(addr),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns this address as a `SocketAddrV6` if it is in the `AF_INET6`
|
||||
/// family.
|
||||
pub fn as_inet6(&self) -> Option<SocketAddrV6> {
|
||||
unsafe { self.as_(AF_INET6 as sa_family_t) }
|
||||
match self.as_std() {
|
||||
Some(SocketAddr::V6(addr)) => Some(addr),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns this address as a `SocketAddr` if it is in the `AF_INET`
|
||||
/// or `AF_INET6` family, otherwise returns `None`.
|
||||
pub fn as_std(&self) -> Option<SocketAddr> {
|
||||
if self.storage.ss_family == AF_INET as sa_family_t {
|
||||
// Safety: if the ss_family field is AF_INET then storage must be a sockaddr_in.
|
||||
let addr = unsafe { &*(&self.storage as *const _ as *const sockaddr_in) };
|
||||
|
||||
#[cfg(unix)]
|
||||
let ip = Ipv4Addr::from(addr.sin_addr.s_addr.to_ne_bytes());
|
||||
#[cfg(windows)]
|
||||
let ip = {
|
||||
let ip_bytes = unsafe { addr.sin_addr.S_un.S_un_b() };
|
||||
Ipv4Addr::from([ip_bytes.s_b1, ip_bytes.s_b2, ip_bytes.s_b3, ip_bytes.s_b4])
|
||||
};
|
||||
let port = u16::from_be(addr.sin_port);
|
||||
Some(SocketAddr::V4(SocketAddrV4::new(ip, port)))
|
||||
} else if self.storage.ss_family == AF_INET6 as sa_family_t {
|
||||
// Safety: if the ss_family field is AF_INET6 then storage must be a sockaddr_in6.
|
||||
let addr = unsafe { &*(&self.storage as *const _ as *const sockaddr_in6) };
|
||||
|
||||
#[cfg(unix)]
|
||||
let ip = Ipv6Addr::from(addr.sin6_addr.s6_addr);
|
||||
#[cfg(windows)]
|
||||
let ip = Ipv6Addr::from(*unsafe { addr.sin6_addr.u.Byte() });
|
||||
let port = u16::from_be(addr.sin6_port);
|
||||
Some(SocketAddr::V6(SocketAddrV6::new(
|
||||
ip,
|
||||
port,
|
||||
addr.sin6_flowinfo,
|
||||
#[cfg(unix)]
|
||||
addr.sin6_scope_id,
|
||||
#[cfg(windows)]
|
||||
unsafe {
|
||||
*addr.u.sin6_scope_id()
|
||||
},
|
||||
)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns this address's family.
|
||||
@ -148,34 +199,92 @@ impl SockAddr {
|
||||
}
|
||||
}
|
||||
|
||||
// SocketAddrV4 and SocketAddrV6 are just wrappers around sockaddr_in and sockaddr_in6
|
||||
|
||||
// check to make sure that the sizes at least match up
|
||||
fn _size_checks(v4: SocketAddrV4, v6: SocketAddrV6) {
|
||||
unsafe {
|
||||
mem::transmute::<SocketAddrV4, sockaddr_in>(v4);
|
||||
mem::transmute::<SocketAddrV6, sockaddr_in6>(v6);
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SocketAddrV4> for SockAddr {
|
||||
fn from(addr: SocketAddrV4) -> SockAddr {
|
||||
unsafe {
|
||||
SockAddr::from_raw_parts(
|
||||
&addr as *const _ as *const _,
|
||||
mem::size_of::<SocketAddrV4>() as socklen_t,
|
||||
)
|
||||
#[cfg(unix)]
|
||||
let sin_addr = in_addr {
|
||||
s_addr: u32::from_ne_bytes(addr.ip().octets()),
|
||||
};
|
||||
#[cfg(windows)]
|
||||
let sin_addr = unsafe {
|
||||
let mut s_un = mem::zeroed::<in_addr_S_un>();
|
||||
*s_un.S_addr_mut() = u32::from_ne_bytes(addr.ip().octets());
|
||||
in_addr { S_un: s_un }
|
||||
};
|
||||
|
||||
let sockaddr_in = sockaddr_in {
|
||||
sin_family: AF_INET as sa_family_t,
|
||||
sin_port: addr.port().to_be(),
|
||||
sin_addr,
|
||||
sin_zero: Default::default(),
|
||||
#[cfg(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
sin_len: 0,
|
||||
};
|
||||
let mut storage = MaybeUninit::<sockaddr_storage>::zeroed();
|
||||
// Safety: A `sockaddr_in` is memory compatible with a `sockaddr_storage`
|
||||
unsafe { (storage.as_mut_ptr() as *mut sockaddr_in).write(sockaddr_in) };
|
||||
SockAddr {
|
||||
storage: unsafe { storage.assume_init() },
|
||||
len: mem::size_of::<sockaddr_in>() as socklen_t,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SocketAddrV6> for SockAddr {
|
||||
fn from(addr: SocketAddrV6) -> SockAddr {
|
||||
unsafe {
|
||||
SockAddr::from_raw_parts(
|
||||
&addr as *const _ as *const _,
|
||||
mem::size_of::<SocketAddrV6>() as socklen_t,
|
||||
)
|
||||
#[cfg(unix)]
|
||||
let sin6_addr = in6_addr {
|
||||
s6_addr: addr.ip().octets(),
|
||||
};
|
||||
#[cfg(windows)]
|
||||
let sin6_addr = unsafe {
|
||||
let mut u = mem::zeroed::<in6_addr_u>();
|
||||
*u.Byte_mut() = addr.ip().octets();
|
||||
in6_addr { u }
|
||||
};
|
||||
#[cfg(windows)]
|
||||
let u = unsafe {
|
||||
let mut u = mem::zeroed::<SOCKADDR_IN6_LH_u>();
|
||||
*u.sin6_scope_id_mut() = addr.scope_id();
|
||||
u
|
||||
};
|
||||
|
||||
let sockaddr_in6 = sockaddr_in6 {
|
||||
sin6_family: AF_INET6 as sa_family_t,
|
||||
sin6_port: addr.port().to_be(),
|
||||
sin6_addr,
|
||||
sin6_flowinfo: addr.flowinfo(),
|
||||
#[cfg(unix)]
|
||||
sin6_scope_id: addr.scope_id(),
|
||||
#[cfg(windows)]
|
||||
u,
|
||||
#[cfg(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
sin6_len: 0,
|
||||
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
|
||||
__sin6_src_id: 0,
|
||||
};
|
||||
let mut storage = MaybeUninit::<sockaddr_storage>::zeroed();
|
||||
// Safety: A `sockaddr_in6` is memory compatible with a `sockaddr_storage`
|
||||
unsafe { (storage.as_mut_ptr() as *mut sockaddr_in6).write(sockaddr_in6) };
|
||||
SockAddr {
|
||||
storage: unsafe { storage.assume_init() },
|
||||
len: mem::size_of::<sockaddr_in6>() as socklen_t,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
361
third_party/rust/socket2/src/socket.rs
vendored
361
third_party/rust/socket2/src/socket.rs
vendored
@ -8,6 +8,8 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::fmt;
|
||||
use std::io::{self, Read, Write};
|
||||
use std::net::{self, Ipv4Addr, Ipv6Addr, Shutdown};
|
||||
@ -16,12 +18,42 @@ use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream};
|
||||
use std::time::Duration;
|
||||
|
||||
#[cfg(any(unix, target_os = "redox"))]
|
||||
use libc as c;
|
||||
use libc::MSG_OOB;
|
||||
#[cfg(windows)]
|
||||
use winapi::shared::ws2def as c;
|
||||
use winapi::um::winsock2::MSG_OOB;
|
||||
|
||||
use crate::sys;
|
||||
use crate::{Domain, Protocol, SockAddr, Socket, Type};
|
||||
use crate::{Domain, Protocol, SockAddr, Type};
|
||||
|
||||
/// Newtype, owned, wrapper around a system socket.
|
||||
///
|
||||
/// This type simply wraps an instance of a file descriptor (`c_int`) on Unix
|
||||
/// and an instance of `SOCKET` on Windows. This is the main type exported by
|
||||
/// this crate and is intended to mirror the raw semantics of sockets on
|
||||
/// platforms as closely as possible. Almost all methods correspond to
|
||||
/// precisely one libc or OS API call which is essentially just a "Rustic
|
||||
/// translation" of what's below.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::net::SocketAddr;
|
||||
/// use socket2::{Socket, Domain, Type, SockAddr};
|
||||
///
|
||||
/// // create a TCP listener bound to two addresses
|
||||
/// let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap();
|
||||
///
|
||||
/// socket.bind(&"127.0.0.1:12345".parse::<SocketAddr>().unwrap().into()).unwrap();
|
||||
/// socket.bind(&"127.0.0.1:12346".parse::<SocketAddr>().unwrap().into()).unwrap();
|
||||
/// socket.listen(128).unwrap();
|
||||
///
|
||||
/// let listener = socket.into_tcp_listener();
|
||||
/// // ...
|
||||
/// ```
|
||||
pub struct Socket {
|
||||
// The `sys` module most have access to the socket.
|
||||
pub(crate) inner: sys::Socket,
|
||||
}
|
||||
|
||||
impl Socket {
|
||||
/// Creates a new socket ready to be configured.
|
||||
@ -213,7 +245,26 @@ impl Socket {
|
||||
///
|
||||
/// [`connect`]: #method.connect
|
||||
pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.inner.recv(buf)
|
||||
self.inner.recv(buf, 0)
|
||||
}
|
||||
|
||||
/// Identical to [`recv`] but allows for specification of arbitrary flags to the underlying
|
||||
/// `recv` call.
|
||||
///
|
||||
/// [`recv`]: #method.recv
|
||||
pub fn recv_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result<usize> {
|
||||
self.inner.recv(buf, flags)
|
||||
}
|
||||
|
||||
/// Receives out-of-band (OOB) data on the socket from the remote address to
|
||||
/// which it is connected by setting the `MSG_OOB` flag for this call.
|
||||
///
|
||||
/// For more information, see [`recv`], [`out_of_band_inline`].
|
||||
///
|
||||
/// [`recv`]: #method.recv
|
||||
/// [`out_of_band_inline`]: #method.out_of_band_inline
|
||||
pub fn recv_out_of_band(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.inner.recv(buf, MSG_OOB)
|
||||
}
|
||||
|
||||
/// Receives data on the socket from the remote adress to which it is
|
||||
@ -229,7 +280,19 @@ impl Socket {
|
||||
/// Receives data from the socket. On success, returns the number of bytes
|
||||
/// read and the address from whence the data came.
|
||||
pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> {
|
||||
self.inner.recv_from(buf)
|
||||
self.inner.recv_from(buf, 0)
|
||||
}
|
||||
|
||||
/// Identical to [`recv_from`] but allows for specification of arbitrary flags to the underlying
|
||||
/// `recvfrom` call.
|
||||
///
|
||||
/// [`recv_from`]: #method.recv_from
|
||||
pub fn recv_from_with_flags(
|
||||
&self,
|
||||
buf: &mut [u8],
|
||||
flags: i32,
|
||||
) -> io::Result<(usize, SockAddr)> {
|
||||
self.inner.recv_from(buf, flags)
|
||||
}
|
||||
|
||||
/// Receives data from the socket, without removing it from the queue.
|
||||
@ -250,7 +313,26 @@ impl Socket {
|
||||
///
|
||||
/// On success returns the number of bytes that were sent.
|
||||
pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.inner.send(buf)
|
||||
self.inner.send(buf, 0)
|
||||
}
|
||||
|
||||
/// Identical to [`send`] but allows for specification of arbitrary flags to the underlying
|
||||
/// `send` call.
|
||||
///
|
||||
/// [`send`]: #method.send
|
||||
pub fn send_with_flags(&self, buf: &[u8], flags: i32) -> io::Result<usize> {
|
||||
self.inner.send(buf, flags)
|
||||
}
|
||||
|
||||
/// Sends out-of-band (OOB) data on the socket to connected peer
|
||||
/// by setting the `MSG_OOB` flag for this call.
|
||||
///
|
||||
/// For more information, see [`send`], [`out_of_band_inline`].
|
||||
///
|
||||
/// [`send`]: #method.send
|
||||
/// [`out_of_band_inline`]: #method.out_of_band_inline
|
||||
pub fn send_out_of_band(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.inner.send(buf, MSG_OOB)
|
||||
}
|
||||
|
||||
/// Sends data on the socket to the given address. On success, returns the
|
||||
@ -259,7 +341,15 @@ impl Socket {
|
||||
/// This is typically used on UDP or datagram-oriented sockets. On success
|
||||
/// returns the number of bytes that were sent.
|
||||
pub fn send_to(&self, buf: &[u8], addr: &SockAddr) -> io::Result<usize> {
|
||||
self.inner.send_to(buf, addr)
|
||||
self.inner.send_to(buf, 0, addr)
|
||||
}
|
||||
|
||||
/// Identical to [`send_to`] but allows for specification of arbitrary flags to the underlying
|
||||
/// `sendto` call.
|
||||
///
|
||||
/// [`send_to`]: #method.send_to
|
||||
pub fn send_to_with_flags(&self, buf: &[u8], addr: &SockAddr, flags: i32) -> io::Result<usize> {
|
||||
self.inner.send_to(buf, flags, addr)
|
||||
}
|
||||
|
||||
// ================================================
|
||||
@ -281,6 +371,73 @@ impl Socket {
|
||||
self.inner.set_ttl(ttl)
|
||||
}
|
||||
|
||||
/// Gets the value of the `TCP_MAXSEG` option on this socket.
|
||||
///
|
||||
/// The `TCP_MAXSEG` option denotes the TCP Maximum Segment
|
||||
/// Size and is only available on TCP sockets.
|
||||
#[cfg(all(unix, not(target_os = "redox")))]
|
||||
pub fn mss(&self) -> io::Result<u32> {
|
||||
self.inner.mss()
|
||||
}
|
||||
|
||||
/// Sets the value of the `TCP_MAXSEG` option on this socket.
|
||||
///
|
||||
/// The `TCP_MAXSEG` option denotes the TCP Maximum Segment
|
||||
/// Size and is only available on TCP sockets.
|
||||
#[cfg(all(unix, not(target_os = "redox")))]
|
||||
pub fn set_mss(&self, mss: u32) -> io::Result<()> {
|
||||
self.inner.set_mss(mss)
|
||||
}
|
||||
|
||||
/// Gets the value for the `SO_MARK` option on this socket.
|
||||
///
|
||||
/// This value gets the socket mark field for each packet sent through
|
||||
/// this socket.
|
||||
///
|
||||
/// This function is only available on Linux and requires the
|
||||
/// `CAP_NET_ADMIN` capability.
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn mark(&self) -> io::Result<u32> {
|
||||
self.inner.mark()
|
||||
}
|
||||
|
||||
/// Sets the value for the `SO_MARK` option on this socket.
|
||||
///
|
||||
/// This value sets the socket mark field for each packet sent through
|
||||
/// this socket. Changing the mark can be used for mark-based routing
|
||||
/// without netfilter or for packet filtering.
|
||||
///
|
||||
/// This function is only available on Linux and requires the
|
||||
/// `CAP_NET_ADMIN` capability.
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn set_mark(&self, mark: u32) -> io::Result<()> {
|
||||
self.inner.set_mark(mark)
|
||||
}
|
||||
|
||||
/// Gets the value for the `SO_BINDTODEVICE` option on this socket.
|
||||
///
|
||||
/// This value gets the socket binded device's interface name.
|
||||
///
|
||||
/// This function is only available on Linux.
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn device(&self) -> io::Result<Option<CString>> {
|
||||
self.inner.device()
|
||||
}
|
||||
|
||||
/// Sets the value for the `SO_BINDTODEVICE` option on this socket.
|
||||
///
|
||||
/// If a socket is bound to an interface, only packets received from that
|
||||
/// particular interface are processed by the socket. Note that this only
|
||||
/// works for some socket types, particularly `AF_INET` sockets.
|
||||
///
|
||||
/// If `interface` is `None` or an empty string it removes the binding.
|
||||
///
|
||||
/// This function is only available on Linux.
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn bind_device(&self, interface: Option<&CStr>) -> io::Result<()> {
|
||||
self.inner.bind_device(interface)
|
||||
}
|
||||
|
||||
/// Gets the value of the `IPV6_UNICAST_HOPS` option for this socket.
|
||||
///
|
||||
/// Specifies the hop limit for ipv6 unicast packets
|
||||
@ -628,24 +785,50 @@ impl Socket {
|
||||
self.inner.set_keepalive(keepalive)
|
||||
}
|
||||
|
||||
/// Returns the value of the `SO_OOBINLINE` flag of the underlying socket.
|
||||
/// For more information about this option, see [`set_out_of_band_inline`][link].
|
||||
///
|
||||
/// [link]: #method.set_out_of_band_inline
|
||||
pub fn out_of_band_inline(&self) -> io::Result<bool> {
|
||||
self.inner.out_of_band_inline()
|
||||
}
|
||||
|
||||
/// Sets the `SO_OOBINLINE` flag of the underlying socket.
|
||||
/// as per RFC6093, TCP sockets using the Urgent mechanism
|
||||
/// are encouraged to set this flag.
|
||||
///
|
||||
/// If this flag is not set, the `MSG_OOB` flag is needed
|
||||
/// while `recv`ing to aquire the out-of-band data.
|
||||
pub fn set_out_of_band_inline(&self, oob_inline: bool) -> io::Result<()> {
|
||||
self.inner.set_out_of_band_inline(oob_inline)
|
||||
}
|
||||
|
||||
/// Check the value of the `SO_REUSEPORT` option on this socket.
|
||||
///
|
||||
/// This function is only available on Unix when the `reuseport` feature is
|
||||
/// enabled.
|
||||
#[cfg(all(unix, feature = "reuseport"))]
|
||||
#[cfg(all(
|
||||
unix,
|
||||
not(any(target_os = "solaris", target_os = "illumos")),
|
||||
feature = "reuseport"
|
||||
))]
|
||||
pub fn reuse_port(&self) -> io::Result<bool> {
|
||||
self.inner.reuse_port()
|
||||
}
|
||||
|
||||
/// Set value for the `SO_REUSEPORT` option on this socket.
|
||||
///
|
||||
/// This indicates that futher calls to `bind` may allow reuse of local
|
||||
/// This indicates that further calls to `bind` may allow reuse of local
|
||||
/// addresses. For IPv4 sockets this means that a socket may bind even when
|
||||
/// there's a socket already listening on this port.
|
||||
///
|
||||
/// This function is only available on Unix when the `reuseport` feature is
|
||||
/// enabled.
|
||||
#[cfg(all(unix, feature = "reuseport"))]
|
||||
#[cfg(all(
|
||||
unix,
|
||||
not(any(target_os = "solaris", target_os = "illumos")),
|
||||
feature = "reuseport"
|
||||
))]
|
||||
pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> {
|
||||
self.inner.set_reuse_port(reuse)
|
||||
}
|
||||
@ -779,111 +962,6 @@ impl From<Socket> for UnixDatagram {
|
||||
}
|
||||
}
|
||||
|
||||
impl Domain {
|
||||
/// Domain for IPv4 communication, corresponding to `AF_INET`.
|
||||
pub fn ipv4() -> Domain {
|
||||
Domain(c::AF_INET)
|
||||
}
|
||||
|
||||
/// Domain for IPv6 communication, corresponding to `AF_INET6`.
|
||||
pub fn ipv6() -> Domain {
|
||||
Domain(c::AF_INET6)
|
||||
}
|
||||
|
||||
/// Domain for Unix socket communication, corresponding to `AF_UNIX`.
|
||||
///
|
||||
/// This function is only available on Unix when the `unix` feature is
|
||||
/// activated.
|
||||
#[cfg(all(unix, feature = "unix"))]
|
||||
pub fn unix() -> Domain {
|
||||
Domain(c::AF_UNIX)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i32> for Domain {
|
||||
fn from(a: i32) -> Domain {
|
||||
Domain(a)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Domain> for i32 {
|
||||
fn from(a: Domain) -> i32 {
|
||||
a.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Type {
|
||||
/// Type corresponding to `SOCK_STREAM`
|
||||
///
|
||||
/// Used for protocols such as TCP.
|
||||
pub fn stream() -> Type {
|
||||
Type(c::SOCK_STREAM)
|
||||
}
|
||||
|
||||
/// Type corresponding to `SOCK_DGRAM`
|
||||
///
|
||||
/// Used for protocols such as UDP.
|
||||
pub fn dgram() -> Type {
|
||||
Type(c::SOCK_DGRAM)
|
||||
}
|
||||
|
||||
/// Type corresponding to `SOCK_SEQPACKET`
|
||||
pub fn seqpacket() -> Type {
|
||||
Type(sys::SOCK_SEQPACKET)
|
||||
}
|
||||
|
||||
/// Type corresponding to `SOCK_RAW`
|
||||
pub fn raw() -> Type {
|
||||
Type(sys::SOCK_RAW)
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::Protocol {
|
||||
/// Protocol corresponding to `ICMPv4`
|
||||
pub fn icmpv4() -> Self {
|
||||
crate::Protocol(sys::IPPROTO_ICMP)
|
||||
}
|
||||
|
||||
/// Protocol corresponding to `ICMPv6`
|
||||
pub fn icmpv6() -> Self {
|
||||
crate::Protocol(sys::IPPROTO_ICMPV6)
|
||||
}
|
||||
|
||||
/// Protocol corresponding to `TCP`
|
||||
pub fn tcp() -> Self {
|
||||
crate::Protocol(sys::IPPROTO_TCP)
|
||||
}
|
||||
|
||||
/// Protocol corresponding to `UDP`
|
||||
pub fn udp() -> Self {
|
||||
crate::Protocol(sys::IPPROTO_UDP)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i32> for Type {
|
||||
fn from(a: i32) -> Type {
|
||||
Type(a)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Type> for i32 {
|
||||
fn from(a: Type) -> i32 {
|
||||
a.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i32> for Protocol {
|
||||
fn from(a: i32) -> Protocol {
|
||||
Protocol(a)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Protocol> for i32 {
|
||||
fn from(a: Protocol) -> i32 {
|
||||
a.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::net::SocketAddr;
|
||||
@ -994,4 +1072,57 @@ mod test {
|
||||
assert!(result.is_ok());
|
||||
assert!(result.unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn out_of_band_inline() {
|
||||
let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap();
|
||||
|
||||
assert_eq!(socket.out_of_band_inline().unwrap(), false);
|
||||
|
||||
socket.set_out_of_band_inline(true).unwrap();
|
||||
assert_eq!(socket.out_of_band_inline().unwrap(), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux"))]
|
||||
fn out_of_band_send_recv() {
|
||||
let s1 = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap();
|
||||
s1.bind(&"127.0.0.1:0".parse::<SocketAddr>().unwrap().into())
|
||||
.unwrap();
|
||||
let s1_addr = s1.local_addr().unwrap();
|
||||
s1.listen(1).unwrap();
|
||||
|
||||
let s2 = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap();
|
||||
s2.connect(&s1_addr).unwrap();
|
||||
|
||||
let (s3, _) = s1.accept().unwrap();
|
||||
|
||||
let mut buf = [0; 10];
|
||||
// send some plain inband data
|
||||
s2.send(&mut buf).unwrap();
|
||||
// send a single out of band byte
|
||||
assert_eq!(s2.send_out_of_band(&mut [b"!"[0]]).unwrap(), 1);
|
||||
// recv the OOB data first
|
||||
assert_eq!(s3.recv_out_of_band(&mut buf).unwrap(), 1);
|
||||
assert_eq!(buf[0], b"!"[0]);
|
||||
assert_eq!(s3.recv(&mut buf).unwrap(), 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tcp() {
|
||||
let s1 = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap();
|
||||
s1.bind(&"127.0.0.1:0".parse::<SocketAddr>().unwrap().into())
|
||||
.unwrap();
|
||||
let s1_addr = s1.local_addr().unwrap();
|
||||
s1.listen(1).unwrap();
|
||||
|
||||
let s2 = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap();
|
||||
s2.connect(&s1_addr).unwrap();
|
||||
|
||||
let (s3, _) = s1.accept().unwrap();
|
||||
|
||||
let mut buf = [0; 11];
|
||||
assert_eq!(s2.send(&mut buf).unwrap(), 11);
|
||||
assert_eq!(s3.recv(&mut buf).unwrap(), 11);
|
||||
}
|
||||
}
|
||||
|
828
third_party/rust/socket2/src/sys/redox/mod.rs
vendored
828
third_party/rust/socket2/src/sys/redox/mod.rs
vendored
@ -1,828 +0,0 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::cmp;
|
||||
use std::fmt;
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::{ErrorKind, Read, Write};
|
||||
use std::mem;
|
||||
use std::net::Shutdown;
|
||||
use std::net::{self, Ipv4Addr, Ipv6Addr};
|
||||
use std::ops::Neg;
|
||||
use std::os::unix::prelude::*;
|
||||
use std::time::Duration;
|
||||
use syscall;
|
||||
|
||||
use libc::{self, c_int, c_uint, c_void, socklen_t, ssize_t};
|
||||
|
||||
use libc::IPV6_ADD_MEMBERSHIP;
|
||||
use libc::IPV6_DROP_MEMBERSHIP;
|
||||
|
||||
const MSG_NOSIGNAL: c_int = 0x0;
|
||||
|
||||
use libc::TCP_KEEPIDLE as KEEPALIVE_OPTION;
|
||||
|
||||
use crate::utils::One;
|
||||
use crate::SockAddr;
|
||||
|
||||
pub const IPPROTO_TCP: i32 = libc::IPPROTO_TCP;
|
||||
|
||||
pub const IPPROTO_ICMP: i32 = -1;
|
||||
pub const IPPROTO_ICMPV6: i32 = -1;
|
||||
pub const IPPROTO_UDP: i32 = -1;
|
||||
pub const SOCK_RAW: i32 = -1;
|
||||
pub const SOCK_SEQPACKET: i32 = -1;
|
||||
|
||||
pub struct Socket {
|
||||
fd: c_int,
|
||||
}
|
||||
|
||||
impl Socket {
|
||||
pub fn new(family: c_int, ty: c_int, protocol: c_int) -> io::Result<Socket> {
|
||||
if ty == -1 {
|
||||
return Err(io::Error::new(ErrorKind::Other, "Type not implemented yet"));
|
||||
}
|
||||
if protocol == -1 {
|
||||
return Err(io::Error::new(
|
||||
ErrorKind::Other,
|
||||
"Protocol not implemented yet",
|
||||
));
|
||||
}
|
||||
unsafe {
|
||||
let fd = cvt(libc::socket(family, ty, protocol))?;
|
||||
let fd = Socket::from_raw_fd(fd as RawFd);
|
||||
set_cloexec(fd.as_raw_fd() as c_int)?;
|
||||
Ok(fd)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pair(_family: c_int, _ty: c_int, _protocol: c_int) -> io::Result<(Socket, Socket)> {
|
||||
return Err(io::Error::new(ErrorKind::Other, "Not implemented yet"));
|
||||
}
|
||||
|
||||
pub fn bind(&self, addr: &SockAddr) -> io::Result<()> {
|
||||
unsafe { cvt(libc::bind(self.fd, addr.as_ptr(), addr.len() as _)).map(|_| ()) }
|
||||
}
|
||||
|
||||
pub fn listen(&self, backlog: i32) -> io::Result<()> {
|
||||
unsafe { cvt(libc::listen(self.fd, backlog)).map(|_| ()) }
|
||||
}
|
||||
|
||||
pub fn connect(&self, addr: &SockAddr) -> io::Result<()> {
|
||||
unsafe { cvt(libc::connect(self.fd, addr.as_ptr(), addr.len())).map(|_| ()) }
|
||||
}
|
||||
|
||||
pub fn connect_timeout(&self, addr: &SockAddr, timeout: Duration) -> io::Result<()> {
|
||||
if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
|
||||
return Err(io::Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
"cannot set a 0 duration timeout",
|
||||
));
|
||||
}
|
||||
if timeout.as_secs() > ::std::i64::MAX as u64 {
|
||||
return Err(io::Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
"too large duration",
|
||||
));
|
||||
}
|
||||
|
||||
self.connect(addr)?;
|
||||
|
||||
let mut event = File::open("event:")?;
|
||||
let mut time = File::open("time:")?;
|
||||
|
||||
event.write(&syscall::Event {
|
||||
id: self.fd as usize,
|
||||
flags: syscall::EVENT_WRITE,
|
||||
data: 0,
|
||||
})?;
|
||||
|
||||
event.write(&syscall::Event {
|
||||
id: time.as_raw_fd(),
|
||||
flags: syscall::EVENT_WRITE,
|
||||
data: 1,
|
||||
})?;
|
||||
|
||||
let mut current = syscall::TimeSpec::default();
|
||||
time.read(&mut current)?;
|
||||
current.tv_sec += timeout.as_secs() as i64;
|
||||
current.tv_nsec += timeout.subsec_nanos() as i32;
|
||||
time.write(¤t)?;
|
||||
|
||||
let mut out = syscall::Event::default();
|
||||
event.read(&mut out)?;
|
||||
|
||||
if out.data == 1 {
|
||||
// the timeout we registered
|
||||
return Err(io::Error::new(ErrorKind::TimedOut, "connection timed out"));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn local_addr(&self) -> io::Result<SockAddr> {
|
||||
unsafe {
|
||||
let mut storage: libc::sockaddr_storage = mem::zeroed();
|
||||
let mut len = mem::size_of_val(&storage) as libc::socklen_t;
|
||||
cvt(libc::getsockname(
|
||||
self.fd,
|
||||
&mut storage as *mut _ as *mut _,
|
||||
&mut len,
|
||||
))?;
|
||||
Ok(SockAddr::from_raw_parts(
|
||||
&storage as *const _ as *const _,
|
||||
len,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn peer_addr(&self) -> io::Result<SockAddr> {
|
||||
unsafe {
|
||||
let mut storage: libc::sockaddr_storage = mem::zeroed();
|
||||
let mut len = mem::size_of_val(&storage) as libc::socklen_t;
|
||||
cvt(libc::getpeername(
|
||||
self.fd,
|
||||
&mut storage as *mut _ as *mut _,
|
||||
&mut len,
|
||||
))?;
|
||||
Ok(SockAddr::from_raw_parts(
|
||||
&storage as *const _ as *const _,
|
||||
len as c_uint,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_clone(&self) -> io::Result<Socket> {
|
||||
return Err(io::Error::new(ErrorKind::Other, "Not implemented yet"));
|
||||
}
|
||||
|
||||
#[allow(unused_mut)]
|
||||
pub fn accept(&self) -> io::Result<(Socket, SockAddr)> {
|
||||
return Err(io::Error::new(ErrorKind::Other, "Not implemented yet"));
|
||||
}
|
||||
|
||||
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
||||
unsafe {
|
||||
let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_ERROR)?;
|
||||
if raw == 0 {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(io::Error::from_raw_os_error(raw as i32)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
||||
unsafe {
|
||||
let previous = cvt(libc::fcntl(self.fd, libc::F_GETFL))?;
|
||||
let new = if nonblocking {
|
||||
previous | libc::O_NONBLOCK
|
||||
} else {
|
||||
previous & !libc::O_NONBLOCK
|
||||
};
|
||||
if new != previous {
|
||||
cvt(libc::fcntl(self.fd, libc::F_SETFL, new))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn shutdown(&self, _how: Shutdown) -> io::Result<()> {
|
||||
return Err(io::Error::new(ErrorKind::Other, "Not implemented yet"));
|
||||
}
|
||||
|
||||
pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let n = cvt({
|
||||
libc::recv(
|
||||
self.fd,
|
||||
buf.as_mut_ptr() as *mut c_void,
|
||||
cmp::min(buf.len(), max_len()),
|
||||
0,
|
||||
)
|
||||
})?;
|
||||
Ok(n as usize)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn peek(&self, _buf: &mut [u8]) -> io::Result<usize> {
|
||||
return Err(io::Error::new(ErrorKind::Other, "Not implemented yet"));
|
||||
}
|
||||
|
||||
pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> {
|
||||
self.recvfrom(buf, 0)
|
||||
}
|
||||
|
||||
pub fn peek_from(&self, _buf: &mut [u8]) -> io::Result<(usize, SockAddr)> {
|
||||
return Err(io::Error::new(ErrorKind::Other, "Not implemented yet"));
|
||||
}
|
||||
|
||||
fn recvfrom(&self, buf: &mut [u8], flags: c_int) -> io::Result<(usize, SockAddr)> {
|
||||
unsafe {
|
||||
let mut storage: libc::sockaddr_storage = mem::zeroed();
|
||||
let mut addrlen = mem::size_of_val(&storage) as socklen_t;
|
||||
|
||||
let n = cvt({
|
||||
libc::recvfrom(
|
||||
self.fd,
|
||||
buf.as_mut_ptr() as *mut c_void,
|
||||
cmp::min(buf.len(), max_len()),
|
||||
flags,
|
||||
&mut storage as *mut _ as *mut _,
|
||||
&mut addrlen,
|
||||
)
|
||||
})?;
|
||||
let addr = SockAddr::from_raw_parts(&storage as *const _ as *const _, addrlen);
|
||||
Ok((n as usize, addr))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let n = cvt({
|
||||
libc::send(
|
||||
self.fd,
|
||||
buf.as_ptr() as *const c_void,
|
||||
cmp::min(buf.len(), max_len()),
|
||||
MSG_NOSIGNAL,
|
||||
)
|
||||
})?;
|
||||
Ok(n as usize)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_to(&self, buf: &[u8], addr: &SockAddr) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let n = cvt({
|
||||
libc::sendto(
|
||||
self.fd,
|
||||
buf.as_ptr() as *const c_void,
|
||||
cmp::min(buf.len(), max_len()),
|
||||
MSG_NOSIGNAL,
|
||||
addr.as_ptr(),
|
||||
addr.len(),
|
||||
)
|
||||
})?;
|
||||
Ok(n as usize)
|
||||
}
|
||||
}
|
||||
|
||||
// ================================================
|
||||
|
||||
pub fn ttl(&self) -> io::Result<u32> {
|
||||
unsafe {
|
||||
let raw: c_int = self.getsockopt(libc::IPPROTO_IP, libc::IP_TTL)?;
|
||||
Ok(raw as u32)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
|
||||
unsafe { self.setsockopt(libc::IPPROTO_IP, libc::IP_TTL, ttl as c_int) }
|
||||
}
|
||||
|
||||
pub fn unicast_hops_v6(&self) -> io::Result<u32> {
|
||||
return Err(io::Error::new(ErrorKind::Other, "Not implemented yet"));
|
||||
}
|
||||
|
||||
pub fn set_unicast_hops_v6(&self, _hops: u32) -> io::Result<()> {
|
||||
return Err(io::Error::new(ErrorKind::Other, "Not implemented yet"));
|
||||
}
|
||||
|
||||
pub fn only_v6(&self) -> io::Result<bool> {
|
||||
unsafe {
|
||||
let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_V6ONLY)?;
|
||||
Ok(raw != 0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
|
||||
unsafe { self.setsockopt(libc::IPPROTO_IPV6, libc::IPV6_V6ONLY, only_v6 as c_int) }
|
||||
}
|
||||
|
||||
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
|
||||
unsafe {
|
||||
Ok(timeval2dur(
|
||||
self.getsockopt(libc::SOL_SOCKET, libc::SO_RCVTIMEO)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
|
||||
unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_RCVTIMEO, dur2timeval(dur)?) }
|
||||
}
|
||||
|
||||
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
|
||||
unsafe {
|
||||
Ok(timeval2dur(
|
||||
self.getsockopt(libc::SOL_SOCKET, libc::SO_SNDTIMEO)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
|
||||
unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_SNDTIMEO, dur2timeval(dur)?) }
|
||||
}
|
||||
|
||||
pub fn nodelay(&self) -> io::Result<bool> {
|
||||
unsafe {
|
||||
let raw: c_int = self.getsockopt(libc::IPPROTO_TCP, libc::TCP_NODELAY)?;
|
||||
Ok(raw != 0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
|
||||
unsafe { self.setsockopt(libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int) }
|
||||
}
|
||||
|
||||
pub fn broadcast(&self) -> io::Result<bool> {
|
||||
unsafe {
|
||||
let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_BROADCAST)?;
|
||||
Ok(raw != 0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> {
|
||||
unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_BROADCAST, broadcast as c_int) }
|
||||
}
|
||||
|
||||
pub fn multicast_loop_v4(&self) -> io::Result<bool> {
|
||||
unsafe {
|
||||
let raw: c_int = self.getsockopt(libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP)?;
|
||||
Ok(raw != 0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> {
|
||||
unsafe {
|
||||
self.setsockopt(
|
||||
libc::IPPROTO_IP,
|
||||
libc::IP_MULTICAST_LOOP,
|
||||
multicast_loop_v4 as c_int,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
|
||||
unsafe {
|
||||
let raw: c_int = self.getsockopt(libc::IPPROTO_IP, libc::IP_MULTICAST_TTL)?;
|
||||
Ok(raw as u32)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> {
|
||||
unsafe {
|
||||
self.setsockopt(
|
||||
libc::IPPROTO_IP,
|
||||
libc::IP_MULTICAST_TTL,
|
||||
multicast_ttl_v4 as c_int,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn multicast_hops_v6(&self) -> io::Result<u32> {
|
||||
return Err(io::Error::new(ErrorKind::Other, "Not implemented yet"));
|
||||
}
|
||||
|
||||
pub fn set_multicast_hops_v6(&self, _hops: u32) -> io::Result<()> {
|
||||
return Err(io::Error::new(ErrorKind::Other, "Not implemented yet"));
|
||||
}
|
||||
|
||||
pub fn multicast_if_v4(&self) -> io::Result<Ipv4Addr> {
|
||||
return Err(io::Error::new(ErrorKind::Other, "Not implemented yet"));
|
||||
}
|
||||
|
||||
pub fn set_multicast_if_v4(&self, _interface: &Ipv4Addr) -> io::Result<()> {
|
||||
return Err(io::Error::new(ErrorKind::Other, "Not implemented yet"));
|
||||
}
|
||||
|
||||
pub fn multicast_if_v6(&self) -> io::Result<u32> {
|
||||
return Err(io::Error::new(ErrorKind::Other, "Not implemented yet"));
|
||||
}
|
||||
|
||||
pub fn set_multicast_if_v6(&self, _interface: u32) -> io::Result<()> {
|
||||
return Err(io::Error::new(ErrorKind::Other, "Not implemented yet"));
|
||||
}
|
||||
|
||||
pub fn multicast_loop_v6(&self) -> io::Result<bool> {
|
||||
unsafe {
|
||||
let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_MULTICAST_LOOP)?;
|
||||
Ok(raw != 0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> {
|
||||
unsafe {
|
||||
self.setsockopt(
|
||||
libc::IPPROTO_IPV6,
|
||||
libc::IPV6_MULTICAST_LOOP,
|
||||
multicast_loop_v6 as c_int,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
|
||||
let multiaddr = to_s_addr(multiaddr);
|
||||
let interface = to_s_addr(interface);
|
||||
let mreq = libc::ip_mreq {
|
||||
imr_multiaddr: libc::in_addr { s_addr: multiaddr },
|
||||
imr_interface: libc::in_addr { s_addr: interface },
|
||||
};
|
||||
unsafe { self.setsockopt(libc::IPPROTO_IP, libc::IP_ADD_MEMBERSHIP, mreq) }
|
||||
}
|
||||
|
||||
pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
|
||||
let multiaddr = to_in6_addr(multiaddr);
|
||||
let mreq = libc::ipv6_mreq {
|
||||
ipv6mr_multiaddr: multiaddr,
|
||||
ipv6mr_interface: to_ipv6mr_interface(interface),
|
||||
};
|
||||
unsafe { self.setsockopt(libc::IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq) }
|
||||
}
|
||||
|
||||
pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
|
||||
let multiaddr = to_s_addr(multiaddr);
|
||||
let interface = to_s_addr(interface);
|
||||
let mreq = libc::ip_mreq {
|
||||
imr_multiaddr: libc::in_addr { s_addr: multiaddr },
|
||||
imr_interface: libc::in_addr { s_addr: interface },
|
||||
};
|
||||
unsafe { self.setsockopt(libc::IPPROTO_IP, libc::IP_DROP_MEMBERSHIP, mreq) }
|
||||
}
|
||||
|
||||
pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
|
||||
let multiaddr = to_in6_addr(multiaddr);
|
||||
let mreq = libc::ipv6_mreq {
|
||||
ipv6mr_multiaddr: multiaddr,
|
||||
ipv6mr_interface: to_ipv6mr_interface(interface),
|
||||
};
|
||||
unsafe { self.setsockopt(libc::IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, mreq) }
|
||||
}
|
||||
|
||||
pub fn linger(&self) -> io::Result<Option<Duration>> {
|
||||
unsafe {
|
||||
Ok(linger2dur(
|
||||
self.getsockopt(libc::SOL_SOCKET, libc::SO_LINGER)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_linger(&self, dur: Option<Duration>) -> io::Result<()> {
|
||||
unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_LINGER, dur2linger(dur)) }
|
||||
}
|
||||
|
||||
pub fn set_reuse_address(&self, reuse: bool) -> io::Result<()> {
|
||||
unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_REUSEADDR, reuse as c_int) }
|
||||
}
|
||||
|
||||
pub fn reuse_address(&self) -> io::Result<bool> {
|
||||
unsafe {
|
||||
let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_REUSEADDR)?;
|
||||
Ok(raw != 0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn recv_buffer_size(&self) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_RCVBUF)?;
|
||||
Ok(raw as usize)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> {
|
||||
unsafe {
|
||||
// TODO: casting usize to a c_int should be a checked cast
|
||||
self.setsockopt(libc::SOL_SOCKET, libc::SO_RCVBUF, size as c_int)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_buffer_size(&self) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_SNDBUF)?;
|
||||
Ok(raw as usize)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_send_buffer_size(&self, size: usize) -> io::Result<()> {
|
||||
unsafe {
|
||||
// TODO: casting usize to a c_int should be a checked cast
|
||||
self.setsockopt(libc::SOL_SOCKET, libc::SO_SNDBUF, size as c_int)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn keepalive(&self) -> io::Result<Option<Duration>> {
|
||||
unsafe {
|
||||
let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_KEEPALIVE)?;
|
||||
if raw == 0 {
|
||||
return Ok(None);
|
||||
}
|
||||
let secs: c_int = self.getsockopt(libc::IPPROTO_TCP, KEEPALIVE_OPTION)?;
|
||||
Ok(Some(Duration::new(secs as u64, 0)))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_keepalive(&self, keepalive: Option<Duration>) -> io::Result<()> {
|
||||
unsafe {
|
||||
self.setsockopt(
|
||||
libc::SOL_SOCKET,
|
||||
libc::SO_KEEPALIVE,
|
||||
keepalive.is_some() as c_int,
|
||||
)?;
|
||||
if let Some(dur) = keepalive {
|
||||
// TODO: checked cast here
|
||||
self.setsockopt(libc::IPPROTO_TCP, KEEPALIVE_OPTION, dur.as_secs() as c_int)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn setsockopt<T>(&self, opt: c_int, val: c_int, payload: T) -> io::Result<()>
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
let payload = &payload as *const T as *const c_void;
|
||||
cvt(libc::setsockopt(
|
||||
self.fd,
|
||||
opt,
|
||||
val,
|
||||
payload,
|
||||
mem::size_of::<T>() as libc::socklen_t,
|
||||
))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn getsockopt<T: Copy>(&self, opt: c_int, val: c_int) -> io::Result<T> {
|
||||
let mut slot: T = mem::zeroed();
|
||||
let mut len = mem::size_of::<T>() as libc::socklen_t;
|
||||
cvt(libc::getsockopt(
|
||||
self.fd,
|
||||
opt,
|
||||
val,
|
||||
&mut slot as *mut _ as *mut _,
|
||||
&mut len,
|
||||
))?;
|
||||
assert_eq!(len as usize, mem::size_of::<T>());
|
||||
Ok(slot)
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for Socket {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
<&Socket>::read(&mut &*self, buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Read for &'a Socket {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let n = cvt({
|
||||
libc::read(
|
||||
self.fd,
|
||||
buf.as_mut_ptr() as *mut c_void,
|
||||
cmp::min(buf.len(), max_len()),
|
||||
)
|
||||
})?;
|
||||
Ok(n as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for Socket {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
<&Socket>::write(&mut &*self, buf)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
<&Socket>::flush(&mut &*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Write for &'a Socket {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.send(buf)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Socket {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut f = f.debug_struct("Socket");
|
||||
f.field("fd", &self.fd);
|
||||
if let Ok(addr) = self.local_addr() {
|
||||
f.field("local_addr", &addr);
|
||||
}
|
||||
if let Ok(addr) = self.peer_addr() {
|
||||
f.field("peer_addr", &addr);
|
||||
}
|
||||
f.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Socket {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.fd as RawFd
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for Socket {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
let fd = self.fd as RawFd;
|
||||
mem::forget(self);
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for Socket {
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> Socket {
|
||||
Socket { fd: fd as c_int }
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for crate::Socket {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.inner.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for crate::Socket {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.inner.into_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for crate::Socket {
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> crate::Socket {
|
||||
crate::Socket {
|
||||
inner: Socket::from_raw_fd(fd),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Socket {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let _ = libc::close(self.fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Socket> for net::TcpStream {
|
||||
fn from(socket: Socket) -> net::TcpStream {
|
||||
unsafe { net::TcpStream::from_raw_fd(socket.into_raw_fd()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Socket> for net::TcpListener {
|
||||
fn from(socket: Socket) -> net::TcpListener {
|
||||
unsafe { net::TcpListener::from_raw_fd(socket.into_raw_fd()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Socket> for net::UdpSocket {
|
||||
fn from(socket: Socket) -> net::UdpSocket {
|
||||
unsafe { net::UdpSocket::from_raw_fd(socket.into_raw_fd()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<net::TcpStream> for Socket {
|
||||
fn from(socket: net::TcpStream) -> Socket {
|
||||
unsafe { Socket::from_raw_fd(socket.into_raw_fd()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<net::TcpListener> for Socket {
|
||||
fn from(socket: net::TcpListener) -> Socket {
|
||||
unsafe { Socket::from_raw_fd(socket.into_raw_fd()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<net::UdpSocket> for Socket {
|
||||
fn from(socket: net::UdpSocket) -> Socket {
|
||||
unsafe { Socket::from_raw_fd(socket.into_raw_fd()) }
|
||||
}
|
||||
}
|
||||
|
||||
fn max_len() -> usize {
|
||||
// The maximum read limit on most posix-like systems is `SSIZE_MAX`,
|
||||
// with the man page quoting that if the count of bytes to read is
|
||||
// greater than `SSIZE_MAX` the result is "unspecified".
|
||||
<ssize_t>::max_value() as usize
|
||||
}
|
||||
|
||||
fn cvt<T: One + PartialEq + Neg<Output = T>>(t: T) -> io::Result<T> {
|
||||
let one: T = T::one();
|
||||
if t == -one {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(t)
|
||||
}
|
||||
}
|
||||
|
||||
fn set_cloexec(fd: c_int) -> io::Result<()> {
|
||||
unsafe {
|
||||
let previous = cvt(libc::fcntl(fd, libc::F_GETFD))?;
|
||||
let new = previous | syscall::O_CLOEXEC as i32;
|
||||
if new != previous {
|
||||
cvt(libc::fcntl(fd, libc::F_SETFD, new))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn dur2timeval(dur: Option<Duration>) -> io::Result<libc::timeval> {
|
||||
match dur {
|
||||
Some(dur) => {
|
||||
if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
|
||||
return Err(io::Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
"cannot set a 0 duration timeout",
|
||||
));
|
||||
}
|
||||
|
||||
let secs = if dur.as_secs() > libc::time_t::max_value() as u64 {
|
||||
libc::time_t::max_value()
|
||||
} else {
|
||||
dur.as_secs() as libc::time_t
|
||||
};
|
||||
let mut timeout = libc::timeval {
|
||||
tv_sec: secs,
|
||||
tv_usec: (dur.subsec_nanos() / 1000) as libc::suseconds_t,
|
||||
};
|
||||
if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
|
||||
timeout.tv_usec = 1;
|
||||
}
|
||||
Ok(timeout)
|
||||
}
|
||||
None => Ok(libc::timeval {
|
||||
tv_sec: 0,
|
||||
tv_usec: 0,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn timeval2dur(raw: libc::timeval) -> Option<Duration> {
|
||||
if raw.tv_sec == 0 && raw.tv_usec == 0 {
|
||||
None
|
||||
} else {
|
||||
let sec = raw.tv_sec as u64;
|
||||
let nsec = (raw.tv_usec as u32) * 1000;
|
||||
Some(Duration::new(sec, nsec))
|
||||
}
|
||||
}
|
||||
|
||||
fn to_s_addr(addr: &Ipv4Addr) -> libc::in_addr_t {
|
||||
let octets = addr.octets();
|
||||
crate::hton(
|
||||
((octets[0] as libc::in_addr_t) << 24)
|
||||
| ((octets[1] as libc::in_addr_t) << 16)
|
||||
| ((octets[2] as libc::in_addr_t) << 8)
|
||||
| ((octets[3] as libc::in_addr_t) << 0),
|
||||
)
|
||||
}
|
||||
|
||||
fn to_in6_addr(addr: &Ipv6Addr) -> libc::in6_addr {
|
||||
let mut ret: libc::in6_addr = unsafe { mem::zeroed() };
|
||||
ret.s6_addr = addr.octets();
|
||||
return ret;
|
||||
}
|
||||
|
||||
fn to_ipv6mr_interface(value: u32) -> libc::c_uint {
|
||||
value as libc::c_uint
|
||||
}
|
||||
|
||||
fn linger2dur(linger_opt: libc::linger) -> Option<Duration> {
|
||||
if linger_opt.l_onoff == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(Duration::from_secs(linger_opt.l_linger as u64))
|
||||
}
|
||||
}
|
||||
|
||||
fn dur2linger(dur: Option<Duration>) -> libc::linger {
|
||||
match dur {
|
||||
Some(d) => libc::linger {
|
||||
l_onoff: 1,
|
||||
l_linger: d.as_secs() as c_int,
|
||||
},
|
||||
None => libc::linger {
|
||||
l_onoff: 0,
|
||||
l_linger: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ip() {
|
||||
let ip = Ipv4Addr::new(127, 0, 0, 1);
|
||||
assert_eq!(ip, from_s_addr(to_s_addr(&ip)));
|
||||
}
|
288
third_party/rust/socket2/src/sys/unix.rs
vendored
288
third_party/rust/socket2/src/sys/unix.rs
vendored
@ -9,26 +9,48 @@
|
||||
// except according to those terms.
|
||||
|
||||
use std::cmp;
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::io::{ErrorKind, Read, Write};
|
||||
use std::mem;
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::mem::MaybeUninit;
|
||||
use std::net::Shutdown;
|
||||
use std::net::{self, Ipv4Addr, Ipv6Addr};
|
||||
use std::ops::Neg;
|
||||
#[cfg(feature = "unix")]
|
||||
use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream};
|
||||
use std::os::unix::prelude::*;
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::ptr;
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::slice;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use libc::{self, c_int, c_void, socklen_t, ssize_t};
|
||||
use libc::{self, c_void, socklen_t, ssize_t};
|
||||
|
||||
use crate::{Domain, Type};
|
||||
|
||||
pub use libc::c_int;
|
||||
|
||||
// Used in `Domain`.
|
||||
pub(crate) use libc::{AF_INET, AF_INET6};
|
||||
// Used in `Type`.
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
pub(crate) use libc::SOCK_RAW;
|
||||
pub(crate) use libc::{SOCK_DGRAM, SOCK_SEQPACKET, SOCK_STREAM};
|
||||
// Used in `Protocol`.
|
||||
pub(crate) use libc::{IPPROTO_ICMP, IPPROTO_ICMPV6, IPPROTO_TCP, IPPROTO_UDP};
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
|
||||
target_os = "ios", target_os = "macos",
|
||||
target_os = "openbsd", target_os = "netbsd",
|
||||
target_os = "solaris", target_os = "haiku"))] {
|
||||
target_os = "solaris", target_os = "illumos",
|
||||
target_os = "haiku"))] {
|
||||
use libc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP;
|
||||
use libc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP;
|
||||
} else {
|
||||
@ -37,17 +59,6 @@ cfg_if::cfg_if! {
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(target_os = "linux", target_os = "android",
|
||||
target_os = "dragonfly", target_os = "freebsd",
|
||||
target_os = "openbsd", target_os = "netbsd",
|
||||
target_os = "haiku", target_os = "bitrig"))] {
|
||||
use libc::MSG_NOSIGNAL;
|
||||
} else {
|
||||
const MSG_NOSIGNAL: c_int = 0x0;
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(target_os = "macos", target_os = "ios"))] {
|
||||
use libc::TCP_KEEPALIVE as KEEPALIVE_OPTION;
|
||||
@ -61,12 +72,109 @@ cfg_if::cfg_if! {
|
||||
use crate::utils::One;
|
||||
use crate::SockAddr;
|
||||
|
||||
pub const IPPROTO_ICMP: i32 = libc::IPPROTO_ICMP;
|
||||
pub const IPPROTO_ICMPV6: i32 = libc::IPPROTO_ICMPV6;
|
||||
pub const IPPROTO_TCP: i32 = libc::IPPROTO_TCP;
|
||||
pub const IPPROTO_UDP: i32 = libc::IPPROTO_UDP;
|
||||
pub const SOCK_SEQPACKET: i32 = libc::SOCK_SEQPACKET;
|
||||
pub const SOCK_RAW: i32 = libc::SOCK_RAW;
|
||||
/// Unix only API.
|
||||
impl Domain {
|
||||
/// Domain for Unix socket communication, corresponding to `AF_UNIX`.
|
||||
pub fn unix() -> Domain {
|
||||
Domain(libc::AF_UNIX)
|
||||
}
|
||||
|
||||
/// Domain for low-level packet interface, corresponding to `AF_PACKET`.
|
||||
///
|
||||
/// # Notes
|
||||
///
|
||||
/// This function is only available on Linux.
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn packet() -> Domain {
|
||||
Domain(libc::AF_PACKET)
|
||||
}
|
||||
}
|
||||
|
||||
impl_debug!(
|
||||
Domain,
|
||||
libc::AF_INET,
|
||||
libc::AF_INET6,
|
||||
libc::AF_UNIX,
|
||||
libc::AF_UNSPEC, // = 0.
|
||||
);
|
||||
|
||||
/// Unix only API.
|
||||
impl Type {
|
||||
/// Set `SOCK_NONBLOCK` on the `Type`.
|
||||
///
|
||||
/// # Notes
|
||||
///
|
||||
/// This function is only available on Android, DragonFlyBSD, FreeBSD,
|
||||
/// Linux, NetBSD and OpenBSD.
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
pub fn non_blocking(self) -> Type {
|
||||
Type(self.0 | libc::SOCK_NONBLOCK)
|
||||
}
|
||||
|
||||
/// Set `SOCK_CLOEXEC` on the `Type`.
|
||||
///
|
||||
/// # Notes
|
||||
///
|
||||
/// This function is only available on Android, DragonFlyBSD, FreeBSD,
|
||||
/// Linux, NetBSD and OpenBSD.
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
pub fn cloexec(self) -> Type {
|
||||
Type(self.0 | libc::SOCK_CLOEXEC)
|
||||
}
|
||||
}
|
||||
|
||||
impl_debug!(
|
||||
crate::Type,
|
||||
libc::SOCK_STREAM,
|
||||
libc::SOCK_DGRAM,
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
libc::SOCK_RAW,
|
||||
#[cfg(not(any(target_os = "haiku", target_os = "redox")))]
|
||||
libc::SOCK_RDM,
|
||||
libc::SOCK_SEQPACKET,
|
||||
/* TODO: add these optional bit OR-ed flags:
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
libc::SOCK_NONBLOCK,
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
libc::SOCK_CLOEXEC,
|
||||
*/
|
||||
);
|
||||
|
||||
impl_debug!(
|
||||
crate::Protocol,
|
||||
libc::IPPROTO_ICMP,
|
||||
libc::IPPROTO_ICMPV6,
|
||||
libc::IPPROTO_TCP,
|
||||
libc::IPPROTO_UDP,
|
||||
);
|
||||
|
||||
pub struct Socket {
|
||||
fd: c_int,
|
||||
@ -92,7 +200,7 @@ impl Socket {
|
||||
let fd = cvt(libc::socket(family, ty, protocol))?;
|
||||
let fd = Socket::from_raw_fd(fd);
|
||||
set_cloexec(fd.as_raw_fd())?;
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
{
|
||||
fd.setsockopt(libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1i32)?;
|
||||
}
|
||||
@ -107,7 +215,7 @@ impl Socket {
|
||||
let fds = (Socket::from_raw_fd(fds[0]), Socket::from_raw_fd(fds[1]));
|
||||
set_cloexec(fds.0.as_raw_fd())?;
|
||||
set_cloexec(fds.1.as_raw_fd())?;
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
{
|
||||
fds.0
|
||||
.setsockopt(libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1i32)?;
|
||||
@ -281,7 +389,7 @@ impl Socket {
|
||||
libc::SYS_accept4,
|
||||
self.fd as libc::c_long,
|
||||
&mut storage as *mut _ as libc::c_long,
|
||||
len as libc::c_long,
|
||||
&mut len,
|
||||
libc::SOCK_CLOEXEC as libc::c_long,
|
||||
) as libc::c_int
|
||||
});
|
||||
@ -342,14 +450,14 @@ impl Socket {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
pub fn recv(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let n = cvt({
|
||||
libc::recv(
|
||||
self.fd,
|
||||
buf.as_mut_ptr() as *mut c_void,
|
||||
cmp::min(buf.len(), max_len()),
|
||||
0,
|
||||
flags,
|
||||
)
|
||||
})?;
|
||||
Ok(n as usize)
|
||||
@ -370,15 +478,11 @@ impl Socket {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> {
|
||||
self.recvfrom(buf, 0)
|
||||
}
|
||||
|
||||
pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> {
|
||||
self.recvfrom(buf, libc::MSG_PEEK)
|
||||
self.recv_from(buf, libc::MSG_PEEK)
|
||||
}
|
||||
|
||||
fn recvfrom(&self, buf: &mut [u8], flags: c_int) -> io::Result<(usize, SockAddr)> {
|
||||
pub fn recv_from(&self, buf: &mut [u8], flags: c_int) -> io::Result<(usize, SockAddr)> {
|
||||
unsafe {
|
||||
let mut storage: libc::sockaddr_storage = mem::zeroed();
|
||||
let mut addrlen = mem::size_of_val(&storage) as socklen_t;
|
||||
@ -398,28 +502,28 @@ impl Socket {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
pub fn send(&self, buf: &[u8], flags: c_int) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let n = cvt({
|
||||
libc::send(
|
||||
self.fd,
|
||||
buf.as_ptr() as *const c_void,
|
||||
cmp::min(buf.len(), max_len()),
|
||||
MSG_NOSIGNAL,
|
||||
flags,
|
||||
)
|
||||
})?;
|
||||
Ok(n as usize)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_to(&self, buf: &[u8], addr: &SockAddr) -> io::Result<usize> {
|
||||
pub fn send_to(&self, buf: &[u8], flags: c_int, addr: &SockAddr) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let n = cvt({
|
||||
libc::sendto(
|
||||
self.fd,
|
||||
buf.as_ptr() as *const c_void,
|
||||
cmp::min(buf.len(), max_len()),
|
||||
MSG_NOSIGNAL,
|
||||
flags,
|
||||
addr.as_ptr(),
|
||||
addr.len(),
|
||||
)
|
||||
@ -441,6 +545,88 @@ impl Socket {
|
||||
unsafe { self.setsockopt(libc::IPPROTO_IP, libc::IP_TTL, ttl as c_int) }
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
pub fn mss(&self) -> io::Result<u32> {
|
||||
unsafe {
|
||||
let raw: c_int = self.getsockopt(libc::IPPROTO_TCP, libc::TCP_MAXSEG)?;
|
||||
Ok(raw as u32)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
pub fn set_mss(&self, mss: u32) -> io::Result<()> {
|
||||
unsafe { self.setsockopt(libc::IPPROTO_TCP, libc::TCP_MAXSEG, mss as c_int) }
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn mark(&self) -> io::Result<u32> {
|
||||
unsafe {
|
||||
let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_MARK)?;
|
||||
Ok(raw as u32)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn set_mark(&self, mark: u32) -> io::Result<()> {
|
||||
unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_MARK, mark as c_int) }
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn device(&self) -> io::Result<Option<CString>> {
|
||||
// TODO: replace with `MaybeUninit::uninit_array` once stable.
|
||||
let mut buf: [MaybeUninit<u8>; libc::IFNAMSIZ] =
|
||||
unsafe { MaybeUninit::<[MaybeUninit<u8>; libc::IFNAMSIZ]>::uninit().assume_init() };
|
||||
let mut len = buf.len() as libc::socklen_t;
|
||||
let len = unsafe {
|
||||
cvt(libc::getsockopt(
|
||||
self.fd,
|
||||
libc::SOL_SOCKET,
|
||||
libc::SO_BINDTODEVICE,
|
||||
buf.as_mut_ptr().cast(),
|
||||
&mut len,
|
||||
))?
|
||||
};
|
||||
if len == 0 {
|
||||
Ok(None)
|
||||
} else {
|
||||
// Allocate a buffer for `CString` with the length including the
|
||||
// null terminator.
|
||||
let len = len as usize;
|
||||
let mut name = Vec::with_capacity(len);
|
||||
|
||||
// TODO: use `MaybeUninit::slice_assume_init_ref` once stable.
|
||||
// Safety: `len` bytes are writen by the OS, this includes a null
|
||||
// terminator. However we don't copy the null terminator because
|
||||
// `CString::from_vec_unchecked` adds its own null terminator.
|
||||
let buf = unsafe { slice::from_raw_parts(buf.as_ptr().cast(), len - 1) };
|
||||
name.extend_from_slice(buf);
|
||||
|
||||
// Safety: the OS initialised the string for us, which shouldn't
|
||||
// include any null bytes.
|
||||
Ok(Some(unsafe { CString::from_vec_unchecked(name) }))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn bind_device(&self, interface: Option<&CStr>) -> io::Result<()> {
|
||||
let (value, len) = if let Some(interface) = interface {
|
||||
(interface.as_ptr(), interface.to_bytes_with_nul().len())
|
||||
} else {
|
||||
(ptr::null(), 0)
|
||||
};
|
||||
|
||||
unsafe {
|
||||
cvt(libc::setsockopt(
|
||||
self.fd,
|
||||
libc::SOL_SOCKET,
|
||||
libc::SO_BINDTODEVICE,
|
||||
value.cast(),
|
||||
len as libc::socklen_t,
|
||||
))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unicast_hops_v6(&self) -> io::Result<u32> {
|
||||
unsafe {
|
||||
let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_UNICAST_HOPS)?;
|
||||
@ -724,7 +910,11 @@ impl Socket {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(unix, feature = "reuseport"))]
|
||||
#[cfg(all(
|
||||
unix,
|
||||
not(any(target_os = "solaris", target_os = "illumos")),
|
||||
feature = "reuseport"
|
||||
))]
|
||||
pub fn reuse_port(&self) -> io::Result<bool> {
|
||||
unsafe {
|
||||
let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_REUSEPORT)?;
|
||||
@ -732,11 +922,26 @@ impl Socket {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(unix, feature = "reuseport"))]
|
||||
#[cfg(all(
|
||||
unix,
|
||||
not(any(target_os = "solaris", target_os = "illumos")),
|
||||
feature = "reuseport"
|
||||
))]
|
||||
pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> {
|
||||
unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_REUSEPORT, reuse as c_int) }
|
||||
}
|
||||
|
||||
pub fn out_of_band_inline(&self) -> io::Result<bool> {
|
||||
unsafe {
|
||||
let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_OOBINLINE)?;
|
||||
Ok(raw != 0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_out_of_band_inline(&self, oob_inline: bool) -> io::Result<()> {
|
||||
unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_OOBINLINE, oob_inline as c_int) }
|
||||
}
|
||||
|
||||
unsafe fn setsockopt<T>(&self, opt: c_int, val: c_int, payload: T) -> io::Result<()>
|
||||
where
|
||||
T: Copy,
|
||||
@ -800,7 +1005,7 @@ impl Write for Socket {
|
||||
|
||||
impl<'a> Write for &'a Socket {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.send(buf)
|
||||
self.send(buf, 0)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
@ -1101,3 +1306,12 @@ fn test_ip() {
|
||||
let ip = Ipv4Addr::new(127, 0, 0, 1);
|
||||
assert_eq!(ip, from_s_addr(to_s_addr(&ip)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_out_of_band_inline() {
|
||||
let tcp = Socket::new(libc::AF_INET, libc::SOCK_STREAM, 0).unwrap();
|
||||
assert_eq!(tcp.out_of_band_inline().unwrap(), false);
|
||||
|
||||
tcp.set_out_of_band_inline(true).unwrap();
|
||||
assert_eq!(tcp.out_of_band_inline().unwrap(), true);
|
||||
}
|
||||
|
95
third_party/rust/socket2/src/sys/windows.rs
vendored
95
third_party/rust/socket2/src/sys/windows.rs
vendored
@ -17,16 +17,15 @@ use std::net::Shutdown;
|
||||
use std::net::{self, Ipv4Addr, Ipv6Addr};
|
||||
use std::os::windows::prelude::*;
|
||||
use std::ptr;
|
||||
use std::sync::{Once, ONCE_INIT};
|
||||
use std::sync::Once;
|
||||
use std::time::Duration;
|
||||
|
||||
use winapi::ctypes::{c_char, c_int, c_long, c_ulong};
|
||||
use winapi::ctypes::{c_char, c_long, c_ulong};
|
||||
use winapi::shared::in6addr::*;
|
||||
use winapi::shared::inaddr::*;
|
||||
use winapi::shared::minwindef::DWORD;
|
||||
use winapi::shared::ntdef::{HANDLE, ULONG};
|
||||
use winapi::shared::ws2def;
|
||||
use winapi::shared::ws2def::*;
|
||||
use winapi::shared::ws2def::{self, *};
|
||||
use winapi::shared::ws2ipdef::*;
|
||||
use winapi::um::handleapi::SetHandleInformation;
|
||||
use winapi::um::processthreadsapi::GetCurrentProcessId;
|
||||
@ -43,12 +42,42 @@ const SD_SEND: c_int = 1;
|
||||
const SIO_KEEPALIVE_VALS: DWORD = 0x98000004;
|
||||
const WSA_FLAG_OVERLAPPED: DWORD = 0x01;
|
||||
|
||||
pub const IPPROTO_ICMP: i32 = ws2def::IPPROTO_ICMP as i32;
|
||||
pub const IPPROTO_ICMPV6: i32 = ws2def::IPPROTO_ICMPV6 as i32;
|
||||
pub const IPPROTO_TCP: i32 = ws2def::IPPROTO_TCP as i32;
|
||||
pub const IPPROTO_UDP: i32 = ws2def::IPPROTO_UDP as i32;
|
||||
pub const SOCK_SEQPACKET: i32 = ws2def::SOCK_SEQPACKET as i32;
|
||||
pub const SOCK_RAW: i32 = ws2def::SOCK_RAW as i32;
|
||||
pub use winapi::ctypes::c_int;
|
||||
|
||||
// Used in `Domain`.
|
||||
pub(crate) use winapi::shared::ws2def::{AF_INET, AF_INET6};
|
||||
// Used in `Type`.
|
||||
pub(crate) use winapi::shared::ws2def::{SOCK_DGRAM, SOCK_RAW, SOCK_SEQPACKET, SOCK_STREAM};
|
||||
// Used in `Protocol`.
|
||||
pub(crate) const IPPROTO_ICMP: c_int = winapi::shared::ws2def::IPPROTO_ICMP as c_int;
|
||||
pub(crate) const IPPROTO_ICMPV6: c_int = winapi::shared::ws2def::IPPROTO_ICMPV6 as c_int;
|
||||
pub(crate) const IPPROTO_TCP: c_int = winapi::shared::ws2def::IPPROTO_TCP as c_int;
|
||||
pub(crate) const IPPROTO_UDP: c_int = winapi::shared::ws2def::IPPROTO_UDP as c_int;
|
||||
|
||||
impl_debug!(
|
||||
crate::Domain,
|
||||
ws2def::AF_INET,
|
||||
ws2def::AF_INET6,
|
||||
ws2def::AF_UNIX,
|
||||
ws2def::AF_UNSPEC, // = 0.
|
||||
);
|
||||
|
||||
impl_debug!(
|
||||
crate::Type,
|
||||
ws2def::SOCK_STREAM,
|
||||
ws2def::SOCK_DGRAM,
|
||||
ws2def::SOCK_RAW,
|
||||
ws2def::SOCK_RDM,
|
||||
ws2def::SOCK_SEQPACKET,
|
||||
);
|
||||
|
||||
impl_debug!(
|
||||
crate::Protocol,
|
||||
self::IPPROTO_ICMP,
|
||||
self::IPPROTO_ICMPV6,
|
||||
self::IPPROTO_TCP,
|
||||
self::IPPROTO_UDP,
|
||||
);
|
||||
|
||||
#[repr(C)]
|
||||
struct tcp_keepalive {
|
||||
@ -58,7 +87,7 @@ struct tcp_keepalive {
|
||||
}
|
||||
|
||||
fn init() {
|
||||
static INIT: Once = ONCE_INIT;
|
||||
static INIT: Once = Once::new();
|
||||
|
||||
INIT.call_once(|| {
|
||||
// Initialize winsock through the standard library by just creating a
|
||||
@ -285,14 +314,14 @@ impl Socket {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
pub fn recv(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let n = {
|
||||
sock::recv(
|
||||
self.socket,
|
||||
buf.as_mut_ptr() as *mut c_char,
|
||||
clamp(buf.len()),
|
||||
0,
|
||||
flags,
|
||||
)
|
||||
};
|
||||
match n {
|
||||
@ -321,15 +350,11 @@ impl Socket {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> {
|
||||
self.recvfrom(buf, 0)
|
||||
}
|
||||
|
||||
pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> {
|
||||
self.recvfrom(buf, MSG_PEEK)
|
||||
self.recv_from(buf, MSG_PEEK)
|
||||
}
|
||||
|
||||
fn recvfrom(&self, buf: &mut [u8], flags: c_int) -> io::Result<(usize, SockAddr)> {
|
||||
pub fn recv_from(&self, buf: &mut [u8], flags: c_int) -> io::Result<(usize, SockAddr)> {
|
||||
unsafe {
|
||||
let mut storage: SOCKADDR_STORAGE = mem::zeroed();
|
||||
let mut addrlen = mem::size_of_val(&storage) as c_int;
|
||||
@ -354,14 +379,14 @@ impl Socket {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
pub fn send(&self, buf: &[u8], flags: c_int) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let n = {
|
||||
sock::send(
|
||||
self.socket,
|
||||
buf.as_ptr() as *const c_char,
|
||||
clamp(buf.len()),
|
||||
0,
|
||||
flags,
|
||||
)
|
||||
};
|
||||
if n == sock::SOCKET_ERROR {
|
||||
@ -372,14 +397,14 @@ impl Socket {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_to(&self, buf: &[u8], addr: &SockAddr) -> io::Result<usize> {
|
||||
pub fn send_to(&self, buf: &[u8], flags: c_int, addr: &SockAddr) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let n = {
|
||||
sock::sendto(
|
||||
self.socket,
|
||||
buf.as_ptr() as *const c_char,
|
||||
clamp(buf.len()),
|
||||
0,
|
||||
flags,
|
||||
addr.as_ptr(),
|
||||
addr.len(),
|
||||
)
|
||||
@ -688,6 +713,17 @@ impl Socket {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn out_of_band_inline(&self) -> io::Result<bool> {
|
||||
unsafe {
|
||||
let raw: c_int = self.getsockopt(SOL_SOCKET, SO_OOBINLINE)?;
|
||||
Ok(raw != 0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_out_of_band_inline(&self, oob_inline: bool) -> io::Result<()> {
|
||||
unsafe { self.setsockopt(SOL_SOCKET, SO_OOBINLINE, oob_inline as c_int) }
|
||||
}
|
||||
|
||||
unsafe fn setsockopt<T>(&self, opt: c_int, val: c_int, payload: T) -> io::Result<()>
|
||||
where
|
||||
T: Copy,
|
||||
@ -738,7 +774,7 @@ impl Read for Socket {
|
||||
|
||||
impl<'a> Read for &'a Socket {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.recv(buf)
|
||||
self.recv(buf, 0)
|
||||
}
|
||||
}
|
||||
|
||||
@ -754,7 +790,7 @@ impl Write for Socket {
|
||||
|
||||
impl<'a> Write for &'a Socket {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.send(buf)
|
||||
self.send(buf, 0)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
@ -975,3 +1011,12 @@ fn test_ip() {
|
||||
let ip = Ipv4Addr::new(127, 0, 0, 1);
|
||||
assert_eq!(ip, from_s_addr(to_s_addr(&ip)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_out_of_band_inline() {
|
||||
let tcp = Socket::new(AF_INET, SOCK_STREAM, 0).unwrap();
|
||||
assert_eq!(tcp.out_of_band_inline().unwrap(), false);
|
||||
|
||||
tcp.set_out_of_band_inline(true).unwrap();
|
||||
assert_eq!(tcp.out_of_band_inline().unwrap(), true);
|
||||
}
|
||||
|
62
third_party/rust/socket2/src/tests.rs
vendored
Normal file
62
third_party/rust/socket2/src/tests.rs
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
use std::io::Write;
|
||||
use std::str;
|
||||
|
||||
use crate::{Domain, Protocol, Type};
|
||||
|
||||
#[test]
|
||||
fn domain_fmt_debug() {
|
||||
let tests = &[
|
||||
(Domain::ipv4(), "AF_INET"),
|
||||
(Domain::ipv6(), "AF_INET6"),
|
||||
#[cfg(unix)]
|
||||
(Domain::unix(), "AF_UNIX"),
|
||||
(0.into(), "AF_UNSPEC"),
|
||||
(500.into(), "500"),
|
||||
];
|
||||
|
||||
let mut buf = Vec::new();
|
||||
for (input, want) in tests {
|
||||
buf.clear();
|
||||
write!(buf, "{:?}", input).unwrap();
|
||||
let got = str::from_utf8(&buf).unwrap();
|
||||
assert_eq!(got, *want);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn type_fmt_debug() {
|
||||
let tests = &[
|
||||
(Type::stream(), "SOCK_STREAM"),
|
||||
(Type::dgram(), "SOCK_DGRAM"),
|
||||
(Type::seqpacket(), "SOCK_SEQPACKET"),
|
||||
(Type::raw(), "SOCK_RAW"),
|
||||
(500.into(), "500"),
|
||||
];
|
||||
|
||||
let mut buf = Vec::new();
|
||||
for (input, want) in tests {
|
||||
buf.clear();
|
||||
write!(buf, "{:?}", input).unwrap();
|
||||
let got = str::from_utf8(&buf).unwrap();
|
||||
assert_eq!(got, *want);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn protocol_fmt_debug() {
|
||||
let tests = &[
|
||||
(Protocol::icmpv4(), "IPPROTO_ICMP"),
|
||||
(Protocol::icmpv6(), "IPPROTO_ICMPV6"),
|
||||
(Protocol::tcp(), "IPPROTO_TCP"),
|
||||
(Protocol::udp(), "IPPROTO_UDP"),
|
||||
(500.into(), "500"),
|
||||
];
|
||||
|
||||
let mut buf = Vec::new();
|
||||
for (input, want) in tests {
|
||||
buf.clear();
|
||||
write!(buf, "{:?}", input).unwrap();
|
||||
let got = str::from_utf8(&buf).unwrap();
|
||||
assert_eq!(got, *want);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user