Showing preview only (403K chars total). Download the full file or copy to clipboard to get everything.
Repository: alexcrichton/socket2-rs
Branch: master
Commit: c93d95a0140f
Files: 18
Total size: 390.5 KB
Directory structure:
gitextract_pvnieb04/
├── .github/
│ └── workflows/
│ └── main.yml
├── .gitignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── Makefile
├── README.md
├── src/
│ ├── lib.rs
│ ├── sockaddr.rs
│ ├── socket.rs
│ ├── sockref.rs
│ └── sys/
│ ├── unix.rs
│ └── windows.rs
└── tests/
├── data/
│ ├── hello_world.txt
│ └── lorem_ipsum.txt
└── socket.rs
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/workflows/main.yml
================================================
name: CI
on:
push:
branches: [ master, "v0.4.x" ]
pull_request:
branches: [ master, "v0.4.x" ]
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: full
jobs:
Test:
name: Test
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
build: [stable, msrv-linux, msrv-windows, beta, nightly, macos, windows]
include:
- build: stable
os: ubuntu-latest
rust: stable
- build: msrv-linux
os: ubuntu-latest
rust: 1.70.0
- build: msrv-windows
os: windows-latest
rust: 1.70.0
- build: beta
os: ubuntu-latest
rust: beta
- build: nightly
os: ubuntu-latest
rust: nightly
- build: macos
os: macos-latest
rust: stable
- build: windows
os: windows-latest
rust: stable
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
- uses: taiki-e/install-action@cargo-hack
- name: Pin windows-sys for MSRV compatibility
if: matrix.os == 'windows-latest' && matrix.rust == '1.70.0'
run: cargo update -p windows-sys --precise 0.60.2
- name: Run tests
run: cargo hack test --feature-powerset && cargo hack test --feature-powerset --release
Rustfmt:
name: Rustfmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- name: Check formatting
run: cargo fmt --all -- --check
Check:
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
target:
- aarch64-apple-darwin
- aarch64-apple-ios
- aarch64-apple-tvos
- aarch64-apple-visionos
- aarch64-apple-watchos
- aarch64-linux-android
- aarch64-unknown-freebsd
- aarch64-unknown-linux-gnu
- aarch64-unknown-linux-musl
- aarch64-unknown-linux-ohos
- aarch64-unknown-netbsd
- aarch64-unknown-openbsd
- aarch64-unknown-redox
- arm-linux-androideabi
- arm64_32-apple-watchos
- armv6k-nintendo-3ds
- armv7-linux-androideabi
- armv7-sony-vita-newlibeabihf
- armv7-unknown-linux-ohos
- i686-linux-android
# Broken, see https://github.com/rust-lang/socket2/issues/539.
#- i686-unknown-hurd-gnu
- i686-unknown-linux-gnu
- sparcv9-sun-solaris
- x86_64-apple-darwin
- x86_64-apple-ios
- x86_64-pc-cygwin
- x86_64-pc-solaris
# Fails with:
# `rror calling dlltool 'x86_64-w64-mingw32-dlltool': No such file or
# directory (os error 2)`, build log:
# <https://github.com/rust-lang/socket2/actions/runs/9577808331/job/26406752150>.
#- x86_64-pc-windows-gnu
- x86_64-pc-windows-msvc
- x86_64-unknown-dragonfly
- x86_64-unknown-freebsd
- x86_64-unknown-fuchsia
- x86_64-unknown-illumos
- x86_64-unknown-linux-gnu
- x86_64-unknown-linux-musl
- x86_64-unknown-linux-ohos
- x86_64-unknown-netbsd
- x86_64-unknown-openbsd
- x86_64-unknown-redox
- wasm32-wasip2
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
with:
components: rust-src
- uses: taiki-e/install-action@cargo-hack
- name: Check build
run: cargo hack check -Z build-std=std,panic_abort --feature-powerset --target ${{ matrix.target }}
- name: Check docs
run: RUSTDOCFLAGS="-D warnings --cfg docsrs" cargo doc -Z build-std=std,panic_abort --no-deps --all-features --target ${{ matrix.target }}
Clippy:
name: Clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- name: Run Clippy
run: cargo clippy --all-targets --all-features -- -D warnings
CheckExternalTypes:
name: check-external-types (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- windows-latest
- ubuntu-latest
- macos-latest
rust:
# `check-external-types` requires a specific Rust nightly version. See
# the README for details: https://github.com/awslabs/cargo-check-external-types
- nightly-2024-06-30
steps:
- uses: actions/checkout@v4
- name: Install Rust ${{ matrix.rust }}
uses: dtolnay/rust-toolchain@stable
with:
toolchain: ${{ matrix.rust }}
- name: Install cargo-check-external-types
uses: taiki-e/cache-cargo-install-action@v1
with:
tool: cargo-check-external-types@0.1.13
locked: true
- name: check-external-types
run: cargo check-external-types --all-features
vmactions:
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-freebsd
arch: x86_64
- target: i686-unknown-freebsd
arch: i686
name: FreeBSD/${{ matrix.arch }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Test on FreeBSD
uses: vmactions/freebsd-vm@v1
with:
release: "14.4"
usesh: true
prepare: |
pkg install -y curl cargo-hack
kldload cc_newreno # For the tcp_congestion test
fetch https://sh.rustup.rs -o rustup.sh
sh rustup.sh -y --profile=minimal
. $HOME/.cargo/env
rustup target add ${{ matrix.target }}
run: |
. $HOME/.cargo/env
cargo hack test --target ${{ matrix.target }} --feature-powerset
================================================
FILE: .gitignore
================================================
/target
**/*.rs.bk
Cargo.lock
.vscode/
================================================
FILE: CHANGELOG.md
================================================
# 0.6.3
* Added support for wasm32-wasip2.
* Added `Socket::(set_)ip_transparent_v6`.
* Added `Socket::set_tcp_ack_frequency`.
* Support windows-sys v0.61 in addition to v0.60.
**POTENTIALLY BREAKING** The MSRV of windows-sys v0.61 is 1.71. To use socket2
with its MSRV of 1.70, please downgrade windows-sys to v0.60.x. This can be done
using: `cargo update windows-sys --precise 0.60.2`
# 0.6.2
* `MsgHdr` and `MsgHdrMut` are marked as transparent meaning both have the same
layout as `msghdr` on Unix and `WSAMSG` on Windows
(https://github.com/rust-lang/socket2/pull/635).
* Don't set `SO_NOSIGPIPE` when accepting sockets, this is inherited from the
parent socket (https://github.com/rust-lang/socket2/pull/632).
* Fixes `Socket::tcp_notsent_lowat` by using the correct argument type
(https://github.com/rust-lang/socket2/pull/622).
# 0.6.1
## Added
* Added support for Windows Registered I/O (RIO)
(https://github.com/rust-lang/socket2/pull/604).
* Added support for `TCP_NOTSENT_LOWAT` on Linux via `Socket::(set_)tcp_notsent_lowat`
(https://github.com/rust-lang/socket2/pull/611).
* Added support for `SO_BUSY_POLL` on Linux via `Socket::set_busy_poll`
(https://github.com/rust-lang/socket2/pull/607).
* `SockFilter::new` is now a const function
(https://github.com/rust-lang/socket2/pull/609).
## Changed
* Updated the windows-sys dependency to version 0.60
(https://github.com/rust-lang/socket2/pull/605).
# 0.6.0
## Breaking changes
All IPv4 methods now have a `_v4` suffix, IPv6 uses `_v6`. TCP methods have a
`tcp_` prefix (looked better than a suffix).
Furthermore we removed all types from external libraries (i.e. libc or
windows-sys) from the public API, allowing us to update those without breaking
the API.
* Renamed `Socket::freebind_ipv6` to `freebind_v6`
(https://github.com/rust-lang/socket2/pull/592).
* Renamed `Socket::freebind` to `freebind_v4`
(https://github.com/rust-lang/socket2/pull/592).
* Renamed `Socket::original_dst` to `original_dst_v4`
(https://github.com/rust-lang/socket2/pull/592).
* Renamed `Socket::original_dst_ipv6` to `original_dst_v6`
(https://github.com/rust-lang/socket2/pull/592).
* Bump MSRV to 1.70
(https://github.com/rust-lang/socket2/pull/597).
* Use `c_int` from `std::ffi` instead of from libc
(https://github.com/rust-lang/socket2/pull/599,
https://github.com/rust-lang/socket2/pull/595).
* `SockAddr`'s methods now accept/return `SockAddrStorage` instead of
`sockaddr_storage`/`SOCKADDR_STORAGE`
(https://github.com/rust-lang/socket2/pull/576):
* `new`
* `try_init`
* `as_ptr`
* `as_storage`
* Add `SockFilter`, wrapper around `libc::sock_filter`, argument to
`Socket::attach_filter`
(https://github.com/rust-lang/socket2/pull/581).
* Various renames of TCP methods on `Socket`
(https://github.com/rust-lang/socket2/pull/592):
* `keepalive_time` -> `tcp_keepalive_time`
* `keepalive_interval` -> `tcp_keepalive_interval`
* `keepalive_retries` -> `tcp_keepalive_retries`
* `nodelay` -> `tcp_nodelay`
* `set_nodelay` -> `set_tcp_nodelay`
* `tcp_mss` -> `mss`
* `tcp_set_mss` -> `set_mss`
* `tcp_cork` -> `cork`
* `tcp_set_cork` -> `set_cork`
* `tcp_quickack` -> `quickack`
* `tcp_set_quickack` -> `set_quickack`
* `thin_linear_timeouts` -> `tcp_thin_linear_timeouts`.
## Non-breaking changes
* Added `Socket::(set_)priority`
(https://github.com/rust-lang/socket2/pull/588).
* Added TCP retries on Windows
(https://github.com/rust-lang/socket2/pull/557).
* Added `SockAddrStorage`, wrapper around `sockaddr_storage`/`SOCKADDR_STORAGE`
for usage with `SockAddr` (instead of the types from libc/windows-sys)
(https://github.com/rust-lang/socket2/pull/576).
* Implemented `Socket::bind_device_by_index_{v4,v6}` on Android and Linux
(https://github.com/rust-lang/socket2/pull/572).
* Implemented `Copy` and `Clone` for `InterfaceIndexOrAddress`
(https://github.com/rust-lang/socket2/pull/571).
* Updated to Windows-sys v0.59
(https://github.com/rust-lang/socket2/pull/579).
* We now use `OwnedFd`/`OwnedSocket` internally for `Socket`
(https://github.com/rust-lang/socket2/pull/600).
# 0.5.10
* Add cygwin support
(https://github.com/rust-lang/socket2/pull/568,
https://github.com/rust-lang/socket2/pull/578).
# 0.5.9
* Enable `IP_BOUND_IF` on illumos and Solaris
(https://github.com/rust-lang/socket2/pull/561,
https://github.com/rust-lang/socket2/pull/566).
# 0.5.8
* Added `Socket::(set_)header_included_v4` and
`Socket::(set_)header_included_v6`
(https://github.com/rust-lang/socket2/pull/518).
* Added support for `Socket::original_dst` and
`Socket::original_dst_ipv6` on Windows
(https://github.com/rust-lang/socket2/pull/529).
# 0.5.7
* Added `Socket::(set_)passcred`
(https://github.com/rust-lang/socket2/pull/506).
* Added `RecvFlags::is_confirm` and `RecvFlags::is_dontroute`
(https://github.com/rust-lang/socket2/pull/499).
* Added `MsgHdrMut::control_len`
(https://github.com/rust-lang/socket2/pull/505).
# 0.5.6
* Added `Socket::(set_)multicast_all_v{4,6}`
(https://github.com/rust-lang/socket2/pull/485 and
https://github.com/rust-lang/socket2/pull/486).
* Added support for GNU/Hurd
(https://github.com/rust-lang/socket2/pull/474).
* Fixes compilation on Haiku
(https://github.com/rust-lang/socket2/pull/479 and
https://github.com/rust-lang/socket2/pull/482).
* Fixes compilation on OpenHarmony
(https://github.com/rust-lang/socket2/pull/491).
* Update to window-sys v0.52
(https://github.com/rust-lang/socket2/pull/480).
# 0.5.5
* Added support for Vita
(https://github.com/rust-lang/socket2/pull/465).
# 0.5.4
* Deprecated `Socket::(bind_)device_by_index`, replaced by
`Socket::(bind_)device_by_index_v4` for IPv4 sockets
(https://github.com/rust-lang/socket2/pull/432).
* Added `Socket::(bind_)device_by_index_v6`
(https://github.com/rust-lang/socket2/pull/432).
* Added experimental support for the ESP-IDF framework
(https://github.com/rust-lang/socket2/pull/452)
* Added `Socket::{send,recv}msg` and `MsgHdr(Mut)` types, wrapping `sendmsg(2)`
and `recvmsg(2)`
(https://github.com/rust-lang/socket2/pull/447).
* Added `Socket::(set_)reuse_port_lb` to retrieve or set `SO_REUSEPORT_LB` on
FreeBSD
(https://github.com/rust-lang/socket2/pull/442).
* Added `Protocol::DIVERT` on FreeBSD and OpenBSD
(https://github.com/rust-lang/socket2/pull/448).
* Added `Socket::protocol` for Windows (using `WSAPROTOCOL_INFOW`)
(https://github.com/rust-lang/socket2/pull/470).
* `From<SocketAddrV{4,6}>` for `SockAddr ` nows sets `ss_len` on platforms that
have the fields (most BSDs)
(https://github.com/rust-lang/socket2/pull/469).
* Change Windows to use `ADDRESS_FAMILY` for `sa_family_t`, this shouldn't
affect anything in practice
(https://github.com/rust-lang/socket2/pull/463).
# 0.5.3
* Added support for two new Android targets `armv7-linux-androideabi` and
`i686-linux-android` (https://github.com/rust-lang/socket2/pull/434).
* Added `Socket::cookie` to retrieve `SO_COOKIE` on Linux
(https://github.com/rust-lang/socket2/pull/437).
# 0.5.2
* Added Unix socket methods to `SockAddr`
(https://github.com/rust-lang/socket2/pull/403 and
https://github.com/rust-lang/socket2/pull/429).
* Added `SockAddr::as_storage`
(https://github.com/rust-lang/socket2/pull/417).
* Added `SockAddr::set_length`
(https://github.com/rust-lang/socket2/pull/428).
* Added `Protocol::UDPLITE`
(https://github.com/rust-lang/socket2/pull/427).
* Update windows-sys to 0.48
(https://github.com/rust-lang/socket2/pull/422).
* Fixes Fuchsia target after it changes in 1.68, see
<https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-1680-2023-03-09>
(https://github.com/rust-lang/socket2/pull/423).
* Fixes musl target and adds it to the CI
(https://github.com/rust-lang/socket2/pull/426).
# 0.5.1
## Added
* `Type::cloexec` for Redox and Solaris
(https://github.com/rust-lang/socket2/pull/398).
* Generate documentation for more targets on docs.rs
(https://github.com/rust-lang/socket2/pull/398).
## Fixed
* Generatation of documentation on docs.rs
(https://github.com/rust-lang/socket2/pull/398).
# 0.5.0
## Changed
* **BREAKING** `SockAddr::init` is renamed to `try_init` to indicate it can fail
(https://github.com/rust-lang/socket2/pull/328).
* **BREAKING** Remove the returned `Result` from `SockAddr::vsock`, it can't
fail (https://github.com/rust-lang/socket2/pull/328).
* **BREAKING** `From<S>` is now implemented using the I/O traits `AsFd` and
`AsRawSocket`
(https://github.com/rust-lang/socket2/pull/325):
* **BREAKING** renamed `SockAddr::vsock_addr` `SockAddr::as_vsock_addr` to match
the IPv4 and IPv6 methods
(https://github.com/rust-lang/socket2/pull/334).
* Redox now works on a stable compiler
(https://github.com/rust-lang/socket2/pull/326).
* Remove copy from `From<SocketAddrV{4,6}>` implementation for `SockAddr`
(https://github.com/rust-lang/socket2/pull/335).
* Marked function as constant where possible.
* Updated to Rust edition 2021
(https://github.com/rust-lang/socket2/pull/393).
## Added
* Links to OS documentation to a lot of methods
(https://github.com/rust-lang/socket2/pull/319).
* I/O-safety traits (https://github.com/rust-lang/socket2/pull/325):
* `AsFd` for `Socket` (Unix only).
* `From<OwnedFd>` for `Socket` (Unix only).
* `From<Socket>` for `OwnedFd` (Unix only).
* `AsSocket` for `Socket` (Windows only).
* `From<OwnedSocket>` for `Socket` (Windows only).
* `From<Socket>` for `OwnedSocket` (Windows only).
* Unix socket support on Windows
(https://github.com/rust-lang/socket2/pull/249).
* `SockAddr::is_ipv{4,6}` and `SockAddr::domain`
(https://github.com/rust-lang/socket2/pull/334).
* `Socket::nonblocking`
(https://github.com/rust-lang/socket2/pull/348).
* `Socket::original_dst(_ipv6)`
(https://github.com/rust-lang/socket2/pull/360).
* `Socket::(set_)recv_tclass_v6` and `Socket::(set_)tclass_v6`
(https://github.com/rust-lang/socket2/pull/364).
* `Socket::(set_)tcp_congestion`
(https://github.com/rust-lang/socket2/pull/371).
* Support for various DCCP socket options in the form of
(https://github.com/rust-lang/socket2/pull/359):
* `Socket::(set_)dccp_service`
* `Socket::dccp_available_ccids`
* `Socket::dccp_qpolicy_txqlen`
* `Socket::dccp_recv_cscov`
* `Socket::dccp_send_cscov`
* `Socket::dccp_server_timewait`
* `Socket::dccp_server_timewait`
* `Socket::dccp_tx_ccid`
* `Socket::dccp_xx_ccid`
* `Socket::set_dccp_ccid`
* `Socket::set_dccp_qpolicy_txqlen`
* `Socket::set_dccp_recv_cscov`
* `Socket::set_dccp_send_cscov`
* `Socket::set_dccp_server_timewait`
* `Socket::dccp_cur_mps`
* `Socket::peek_send`
(https://github.com/rust-lang/socket2/pull/389).
* `Protocol::MPTCP`
(https://github.com/rust-lang/socket2/pull/349).
* `Protocol::SCTP`
(https://github.com/rust-lang/socket2/pull/356).
* `Protocol::DCCP`
(https://github.com/rust-lang/socket2/pull/359).
* `Type::DCCP`
(https://github.com/rust-lang/socket2/pull/359).
* Implement `Eq` and `Hash` for `SockAddr`
(https://github.com/rust-lang/socket2/pull/374).
* Support for QNX Neutrino
(https://github.com/rust-lang/socket2/pull/380).
* Support for AIX
(https://github.com/rust-lang/socket2/pull/351).
# 0.4.10
* Fixed compilation with the `all` on QNX Neutrino
(https://github.com/rust-lang/socket2/pull/419).
* Added support for ESP-IDF
(https://github.com/rust-lang/socket2/pull/455).
* Added support for Vita
(https://github.com/rust-lang/socket2/pull/475).
# 0.4.9
* Fixed compilation on Windows
(https://github.com/rust-lang/socket2/pull/409).
# 0.4.8 (yanked)
This release was broken for Windows.
* Added `Socket::peek_sender` (backport)
(https://github.com/rust-lang/socket2/pull/404).
# 0.4.7
* Fixes compilation on OpenBSD
(https://github.com/rust-lang/socket2/pull/344).
* Fixes compilation on DragonFlyBSD
(https://github.com/rust-lang/socket2/pull/342).
# 0.4.6
* Reverted back to the `winapi` dependency as switch to `windows-sys` was a
breaking change (https://github.com/rust-lang/socket2/pull/340).
Note that we'll will switch to `windows-sys` in v0.5 .
* Disable RECVTOS on OpenBSD
(https://github.com/rust-lang/socket2/pull/307).
* Derive Clone for SockAddr
(https://github.com/rust-lang/socket2/pull/311).
* Fixes cfg attributes for Fuchsia
(https://github.com/rust-lang/socket2/pull/314).
# 0.4.5 (yanked)
## Changed
* Replace `winapi` dependency with `windows-sys`
(https://github.com/rust-lang/socket2/pull/303).
## Added
* `Socket::join_ssm_v4` and `Socket::leave_ssm_v4`
(https://github.com/rust-lang/socket2/pull/298).
* `Socket::set_recv_tos` and `Socket::recv_tos`
(https://github.com/rust-lang/socket2/pull/299).
## Fixed
* OpenBSD build
(https://github.com/rust-lang/socket2/pull/291).
# 0.4.4
## Fixed
* Libc v0.2.114 fixed an issue where `ip_mreqn` where was not defined for Linux
s390x.
# 0.4.3 (yanked)
## Added
* `Socket::set_fib`: sets `SO_SETFIB` (https://github.com/rust-lang/socket2/pull/271).
* `Socket::attach_filter`, `SO_ATTACH_FILTER` (https://github.com/rust-lang/socket2/commit/6601ed132b37d6e9d178b34918bfb0b236800232).
* `Socket::detach_filter`, `SO_DETACH_FILTER` (https://github.com/rust-lang/socket2/commit/6601ed132b37d6e9d178b34918bfb0b236800232).
* `Socket::{header_included, set_header_included}`: sets or gets `IP_HDRINCL`
(https://github.com/rust-lang/socket2/commit/f9e882ee53c0b4e89c5043b6d709af95c9db5599).
* `Socket::{cork, set_cork}`: sets or gets `TCP_CORK`
(https://github.com/rust-lang/socket2/commit/50f31f18aac8fd6ef277df2906adeeed9fa391de).
* `Socket::{quickack, set_quickack}`: sets or gets `TCP_QUICKACK`
(https://github.com/rust-lang/socket2/commit/849eee2abc5d5170d2d3bc635386a2ba13b04530).
* `Socket::{thin_linear_timeouts, set_thin_linear_timeouts}`: sets or gets
`TCP_THIN_LINEAR_TIMEOUTS`
(https://github.com/rust-lang/socket2/commit/24c231ca463a17f51e53e7a554c7915a95bdbcc7).
* `Socket::{join_multicast_v4_n, leave_multicast_v4_n}`: extends the existing
multicast API by allowing an index to be used (in addition to an address)
(https://github.com/rust-lang/socket2/commit/750f83618b967c620bbfdf6ca04de7362bdb42b5).
# 0.4.2
## Added
* `Socket::(set_)freebind_ipv6`, getter and setter for `IPV6_FREEBIND`.
## Fixed
* Compilation on OpenBSD.
* Usage of incorrect flag in `Socket::(set_)freebind`.
# 0.4.1
## Added
* Added `SockAddr::new`
* Support for `TCP_USER_TIMEOUT`.
* Support for `IP_BOUND_IF`.
* Support for `IP_TRANSPARENT`.
* Enable `Socket::type` on all platforms.
* Support for uclibc (for Haiku support).
* Added DragonFly support for TCP keepalive (`KEEPINTVL`/`KEEPCNT`).
* Documentation for proper use of `SockRef::from`, and the improper use.
* Assertion in `SockRef::from` to ensure the raw socket valid.
## Fixed
* Compilation on Haiku.
* Setting TCP keepalive on Haiku and OpenBSD (by not setting it as it's not
supported).
* Size check for abstract namespaces in `SockAddr::unix`.
* Set noinherit on accepted sockets on Windows when opening sockets.
# 0.4.0
## Added
* New `all` feature: enables API that is not available on all tier 1 platforms.
* `SockRef` type: used to create a reference to an existing socket, e.g.
`std::net::TcpStream`, making all methods of `Socket` available on it.
* Support for vectored I/O:
* `Socket::recv_vectored`, `Socket::recv_with_flags`.
* `Socket::recv_from_vectored`, `Socket::recv_from_vectored_with_flags`.
* `Socket::send_vectored`, `Socket::send_vectored_with_flags`.
* `Socket::send_to_vectored`, `Socket::send_to_vectored_with_flags`.
* In the `Read` and `Write` implementations.
* `Socket::new_raw`, `Socket::pair_raw` and `Socket::accept_raw` methods
that don't set common flags, such as the close-on-exec flag.
* `Socket::accept4`: `accept4(2)` system call.
* `Socket::sendfile`: the `sendfile(2)` system call.
* `Socket::set_cloexec`: set the close-on-exec flag on Unix.
* `Socket::set_no_inherit`: set inherit handle flag on Windows.
* `Socket::set_nosigpipe`: set `SO_NOSIGPIPE` on Apple targets.
* `Socket::set_mark` and `Socket::mark`, setting/getting the `SO_MARK` socket
option.
* `Socket::set_cpu_affinity` and `Socket::cpu_affinity`, setting/getting the
`SO_INCOMING_CPU` socket option.
* `Socket::set_mss` and `Socket::mss`, setting/getting the `TCP_MAXSEG` socket
option.
* `Socket::set_freebind` and `Socket::freebind`, setting/getting the
`IP_FREEBIND` socket option.
* `Socket::bind_device` and `Socket::device`, setting/getting the
`SO_BINDTODEVICE` socket option.
* Adopted Mio's TCP keepalive API:
* `Socket::keepalive_time`,
* `Socket::keepalive_interval`,
* `Socket::keepalive_retries`,
* `Socket::set_tcp_keepalive`.
* `Socket::is_listener` getting the `SO_ACCEPTCONN` socket option.
* `Socket::domain` getting the `SO_DOMAIN` socket option.
* `Socket::protocol` getting the `SO_PROTOCOL` socket option.
* `Socket::type` getting the `SO_TYPE` socket option.
* `Domain::for_address`: the correct `Domain` for a `std::net::SocketAddr`.
* `Type::nonblocking`: set `SOCK_NONBLOCK`.
* `Type::cloexec`: set `SOCK_CLOEXEC`.
* `Type::no_inherit`: set `HANDLE_FLAG_INHERIT`.
* `SockAddr::init`: initialises a `SockAddr`.
* `MaybeUninitSlice` type: a version of `IoSliceMut` that allows the buffer to
be uninitialised, used in `Socket::recv_vectored` and related functions.
* `RecvFlags` type: provides additional information about incoming messages,
returned by `Socket::recv_vectored` and related functions.
* `TcpKeepalive` type: configuration type for a socket's TCP keepalive
parameters.
## Changed
* Repository moved to <https://github.com/rust-lang/socket2>.
* **BREAKING:** Changed constructor functions into constants:
* `Domain::ipv4` => `Domain::IPV4`.
* `Domain::ipv6` => `Domain::IPV4`.
* `Domain::unix` => `Domain::UNIX`.
* `Domain::packet` => `Domain::PACKET`.
* `Type::stream` => `Type::STREAM`.
* `Type::dgram` => `Type::DGRAM`.
* `Type::seqpacket` => `Type::SEQPACKET`.
* `Type::raw` => `Type::RAW`.
* `Protocol::icmpv4` => `Protocol::ICMPV4`.
* `Protocol::icmpv6` => `Protocol::ICMPV6`.
* `Protocol::tcp` => `Protocol::TCP`.
* `Protocol::udp` => `Protocol::UDP`.
* **BREAKING:** Changed the signature of `Socket::recv`, `Socket::recv_vectored`
and related methods to accept uninitialised buffers. The `Read` implementation
can be used to read into initialised buffers.
* **BREAKING:** Renamed `SockAddr::as_std` to `as_socket`.
* **BREAKING:** Renamed `SockAddr::as_inet` to `as_socket_ipv4`.
* **BREAKING:** Renamed `SockAddr::as_inet6` to `as_socket_ipv6`.
* **BREAKING:** Replace all previously existing features (reuseport, pair, unix)
with a new all features (see above for description of the all feature).
* Use `accept4(2)` with `SOCK_CLOEXEC` in `Socket::accept`, reducing the amount
of system calls required.
* Marked many functions as constant.
* The `Read` implementation now calls `recv(2)` rather than `read(2)`.
* Split the `impl` block for the `Socket` type to create groupings for setting
and getting different level socket options using
`setsockopt(2)`/`getsockopt(2)`.
* Updated `winapi` depdency to version 0.3.9 and dropped unused features.
## Removed
* Removed the `-rs` suffix from the repository name.
* **BREAKING:** Removed `SockAddr::from_raw_parts`, use `SockAddr::init` instead.
* **BREAKING:** Removed `Socket::into_*` functions and replaced them with a `From`
implementation:
* `Socket::into_tcp_stream` => `TcpStream::from(socket)`.
* `Socket::into_tcp_listener` => `TcpListener::from(socket)`.
* `Socket::into_udp_socket` => `UdpSocket::from(socket)`.
* `Socket::into_unix_stream` => `UnixStream::from(socket)`.
* `Socket::into_unix_listener` => `UnixListener::from(socket)`.
* `Socket::into_unix_datagram` => `UnixDatagram::from(socket)`.
* Removed `cfg-if` dependency.
* Remove `redox_syscall` depdency.
## Fixes
* Fixes the Andoid, Fuchsia, Haiku, iOS, illumos, NetBSD and Redox (nightly
only) targets.
* Correctly call `recv_from` in `Socket::recv_from_with_flags` (called `recv`
previously).
* Correctly call `send_to` in `Socket::send_to_with_flags` (called `recv`
previously).
* Use correct inmutable references in `Socket::send_with_flags` and
`Socket::send_out_of_band`.
* Use `IPPROTO_IPV6` in `Socket::join_multicast_v6` on Windows.
* Use `c_int` instead of `i32` where appropriate.
## From v0.4.0-alpha.1 to v0.4.0-alpha.2
* Fixes the Fuchsia target.
* `Socket::device` now returns a `Vec<u8>` rather than `CString`.
* `Socket::bind_device` now accepts a `&[u8]` rather than `&CStr`.
## From v0.4.0-alpha.2 to v0.4.0-alpha.3
* `Socket::connect_timeout` was added back.
## From v0.4.0-alpha.4 to v0.4.0-alpha.5
* Changed `Socket::set_cpu_affinity` and `Socket::cpu_affinity` to use an
immutable reference.
## From v0.4.0-alpha.5 to v0.4.0
* Use `SO_LINGER_SEC` on macOS for `Socket::get/set_linger`.
# 0.3.16
* Don't assume the memory layout of `std::net::SocketAddr`.
* Other changes omited
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to Socket2
There are many ways to contribute to Socket2, including (but not limited to)
answering questions, adding new features, fixing bugs or expanding the
documentation. This document will focus on adding new features and fixing bugs.
If you're adding a new feature please first [open an issue] laying out what
would be added and a design you're proposing. Doing this before actually writing
the code will save you time if others suggest improvements to the design. Once
there is some consensus on 1) the feature is a good addition to Socket2 and 2)
the proposed design is the right one, open a [pull request] with the changes.
If you're working on fixing a bug please say so on the specific issue so that
two people don't work on fixing the same bug. For more complex bugs or fixes
please also share your proposed design on the issue tracker, same as for new
features.
Once you're working on the code it's useful to understand where the code is (or
should) be located, the [code structure section] describes how the code of
Socket2 is organised.
To make sure we don't create the same bug again, or to ensure that new features
keep working, please add (regression) test for the changes you've made to the
code. The [testing section] below describes how to run the tests and where to
add new tests.
[open an issue]: https://github.com/rust-lang/socket2/issues/new
[pull request]: https://github.com/rust-lang/socket2/compare
[code structure section]: #code-structure
[testing section]: #testing
# Code structure
All types and methods that are available on all tier 1 platforms are defined in
the first level of the source, i.e. `src/*.rs` files. Additional API that is
platform specific, e.g. `Domain::VSOCK`, is defined in `src/sys/*.rs` and only
for the platforms that support it. For API that is not available on all tier 1
platforms the `all` feature is used, to indicate to the user that they're using
API that might is not available on all platforms.
The main `Socket` type is defined in `src/socket.rs` with additional methods
defined in the `src/sys/*.rs` files, as per above. The methods on
`Socket` are split into multiple `impl` blocks. The first `impl` block contains
a collection of system calls for creating and using the socket, e.g.
`socket(2)`, `bind(2)`, `listen(2)`, etc. The other implementation blocks are
for getting and setting socket options on various levels, e.g. `SOL_SOCKET`,
where each block contains a single level. The methods in these block are sorted
based on the option name, e.g. `IP_ADD_MEMBERSHIP` rather than
`join_multicast_v4`. Finally the last block contains platforms specific methods
such as `Socket::freebind` which is (at the time of writing) only available on
Android, Linux and Fuchsia, which is defined in the `src/sys/*.rs` files.
Other types are mostly defined in `src/lib.rs`, except for `SockAddr` and
`SockRef` which have their own file. These types follow the same structure as
`Socket`, where OS specific methods are defined in `src/sys/*.rs`, e.g.
`Type::cloexec`.
# Testing
Testing Socket2 is as simple as running `cargo test --all-features`.
However Socket2 supports a good number of OSs and features. If you want to
test/check all those combinations it's easier to use the [Makefile]. Using `make
test_all` it will check all supported OS targets and all combinations of
supported features. Note that this requires [cargo-hack] and various rustup
targets to be installed. Cargo-hack must be installed manually, the various
targets can be installed automatically using `make install_targets` (which uses
[rustup]).
[Makefile]: ./Makefile
[cargo-hack]: https://crates.io/crates/cargo-hack
[rustup]: https://rustup.rs
## Adding a test
Tests should be added to `tests/socket.rs`, following (roughly) the same order
in which the methods are defined on a type. At the bottom of this file it has a
macro to create a simple get/set socket option test, more complex API however
needs a manually written test.
Tests that need to use internal API can be defined directly at the bottom of the
source file. No need for a test module since we intend on keeping the number of
internal tests low.
================================================
FILE: Cargo.toml
================================================
[package]
name = "socket2"
version = "0.6.3"
authors = [
"Alex Crichton <alex@alexcrichton.com>",
"Thomas de Zeeuw <thomasdezeeuw@gmail.com>"
]
license = "MIT OR Apache-2.0"
readme = "README.md"
repository = "https://github.com/rust-lang/socket2"
homepage = "https://github.com/rust-lang/socket2"
documentation = "https://docs.rs/socket2"
description = """
Utilities for handling networking sockets with a maximal amount of configuration
possible intended.
"""
keywords = ["io", "socket", "network"]
categories = ["api-bindings", "network-programming"]
edition = "2021"
rust-version = "1.70"
include = [
"Cargo.toml",
"LICENSE-APACHE",
"LICENSE-MIT",
"README.md",
"src/**/*.rs",
]
[package.metadata.docs.rs]
all-features = true
default-target = "x86_64-unknown-linux-gnu"
targets = [
"aarch64-apple-ios",
"aarch64-linux-android",
"armv7-linux-androideabi",
"i686-linux-android",
"x86_64-apple-darwin",
"x86_64-pc-solaris",
"x86_64-pc-windows-msvc",
"x86_64-unknown-freebsd",
"x86_64-unknown-fuchsia",
"x86_64-unknown-illumos",
"x86_64-unknown-linux-gnu",
"x86_64-unknown-linux-musl",
"x86_64-unknown-netbsd",
"x86_64-unknown-redox",
]
[package.metadata.playground]
features = ["all"]
[target.'cfg(any(unix, target_os = "wasi"))'.dependencies]
libc = "0.2.172"
[target.'cfg(windows)'.dependencies.windows-sys]
version = ">=0.60, <0.62"
features = [
"Win32_Foundation",
"Win32_Networking_WinSock",
"Win32_System_IO",
"Win32_System_Threading",
"Win32_System_WindowsProgramming",
]
[features]
# Enable all API, even ones not available on all OSs.
all = []
[package.metadata.cargo_check_external_types]
allowed_external_types = [
# Referenced via a type alias.
"libc::socklen_t",
"libc::*::socklen_t", # libc::socklen_t isn't always detected.
"libc::sa_family_t",
"libc::*::sa_family_t", # libc::sa_family_t is always detected.
"windows_sys::Win32::Networking::WinSock::socklen_t",
"windows_sys::Win32::Networking::WinSock::ADDRESS_FAMILY",
]
================================================
FILE: LICENSE-APACHE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: LICENSE-MIT
================================================
Copyright (c) 2014 Alex Crichton
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
================================================
FILE: Makefile
================================================
# Targets available via Rustup that are supported.
# NOTE: keep in sync with the CI and docs.rs targets.
TARGETS ?= "aarch64-apple-ios" "aarch64-linux-android" "x86_64-apple-darwin" "x86_64-unknown-fuchsia" "x86_64-pc-windows-msvc" "x86_64-pc-solaris" "x86_64-unknown-freebsd" "x86_64-unknown-illumos" "x86_64-unknown-linux-gnu" "x86_64-unknown-linux-musl" "x86_64-unknown-netbsd" "x86_64-unknown-redox" "armv7-linux-androideabi" "i686-linux-android"
test:
cargo test --all-features
# Test everything for the current OS/architecture and check all targets in
# $TARGETS.
test_all: check_all_targets
cargo hack test --feature-powerset
cargo hack test --feature-powerset --release
# Check all targets using all features.
check_all_targets: $(TARGETS)
$(TARGETS):
cargo hack check --feature-powerset --all-targets --examples --bins --tests --target $@
# Installs all required targets for `check_all_targets`.
install_targets:
rustup target add $(TARGETS)
# NOTE: when using this command you might want to change the `test` target to
# only run a subset of the tests you're actively working on.
dev:
find src/ tests/ Makefile Cargo.toml | entr -d -c $(MAKE) test
clean:
cargo clean
.PHONY: test test_all check_all_targets $(TARGETS) install_targets dev clean
================================================
FILE: README.md
================================================
# Socket2
Socket2 is a crate that provides utilities for creating and using sockets.
The goal of this crate is to create and use a socket using advanced
configuration options (those that are not available in the types in the standard
library) without using any unsafe code.
This crate provides as direct as possible access to the system's functionality
for sockets, this means little effort to provide cross-platform utilities. It is
up to the user to know how to use sockets when using this crate. *If you don't
know how to create a socket using libc/system calls then this crate is not for
you*. Most, if not all, functions directly relate to the equivalent system call
with no error handling applied, so no handling errors such as `EINTR`. As a
result using this crate can be a little wordy, but it should give you maximal
flexibility over configuration of sockets.
See the [API documentation] for more.
[API documentation]: https://docs.rs/socket2
# Branches
Currently Socket2 supports the following versions:
* v0.6 developed in the master branch
* v0.5 developed in the [v0.5.x branch]
* v0.4 developed in the [v0.4.x branch]
[v0.5.x branch]: https://github.com/rust-lang/socket2/tree/v0.5.x
[v0.4.x branch]: https://github.com/rust-lang/socket2/tree/v0.4.x
# OS support
Socket2 attempts to support the same OS/architectures as Rust does, see
https://doc.rust-lang.org/nightly/rustc/platform-support.html. However this is
not always possible, below is current list of support OSs.
*If your favorite OS is not on the list consider contributing it!*
### Tier 1
These OSs are tested with each commit in the CI and must always pass the tests.
All functions/types/etc., excluding ones behind the `all` feature, must work on
these OSs.
* Linux
* macOS
* Windows
### Tier 2
These OSs are currently build in the CI, but not tested. Not all
functions/types/etc. may work on these OSs, even ones **not** behind the `all`
feature flag.
* Android
* FreeBSD
* Fuchsia
* iOS
* illumos
* NetBSD
* Redox
* Solaris
* OpenHarmony
# Minimum Supported Rust Version (MSRV)
Socket2 uses 1.70.0 as MSRV.
# License
This project is licensed under either of
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
https://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or
https://opensource.org/licenses/MIT)
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in this project by you, as defined in the Apache-2.0 license,
shall be dual licensed as above, without any additional terms or conditions.
================================================
FILE: src/lib.rs
================================================
// Copyright 2015 The Rust Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(clippy::needless_lifetimes)]
//! Utilities for creating and using sockets.
//!
//! The goal of this crate is to create and use a socket using advanced
//! configuration options (those that are not available in the types in the
//! standard library) without using any unsafe code.
//!
//! This crate provides as direct as possible access to the system's
//! functionality for sockets, this means little effort to provide
//! cross-platform utilities. It is up to the user to know how to use sockets
//! when using this crate. *If you don't know how to create a socket using
//! libc/system calls then this crate is not for you*. Most, if not all,
//! functions directly relate to the equivalent system call with no error
//! handling applied, so no handling errors such as [`EINTR`]. As a result using
//! this crate can be a little wordy, but it should give you maximal flexibility
//! over configuration of sockets.
//!
//! [`EINTR`]: std::io::ErrorKind::Interrupted
//!
//! # Examples
//!
//! ```no_run
//! # fn main() -> std::io::Result<()> {
//! use std::net::{SocketAddr, TcpListener};
//! use socket2::{Socket, Domain, Type};
//!
//! // Create a TCP listener bound to two addresses.
//! let socket = Socket::new(Domain::IPV6, Type::STREAM, None)?;
//!
//! socket.set_only_v6(false)?;
//! let address: SocketAddr = "[::1]:12345".parse().unwrap();
//! socket.bind(&address.into())?;
//! socket.listen(128)?;
//!
//! let listener: TcpListener = socket.into();
//! // ...
//! # drop(listener);
//! # Ok(()) }
//! ```
//!
//! ## Features
//!
//! This crate has a single feature `all`, which enables all functions even ones
//! that are not available on all OSs.
#![deny(missing_docs, missing_debug_implementations, rust_2018_idioms)]
// Automatically generate required OS/features for docs.rs.
#![cfg_attr(docsrs, feature(doc_cfg))]
// Disallow warnings when running tests.
#![cfg_attr(test, deny(warnings))]
// Disallow warnings in examples.
#![doc(test(attr(deny(warnings))))]
use std::fmt;
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
use std::io::IoSlice;
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
use std::marker::PhantomData;
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
use std::mem;
use std::mem::MaybeUninit;
use std::net::SocketAddr;
use std::ops::{Deref, DerefMut};
use std::time::Duration;
/// 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 `windows_sys`.
$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)
}
}
};
}
/// Macro to convert from one network type to another.
macro_rules! from {
($from: ty, $for: ty) => {
impl From<$from> for $for {
fn from(socket: $from) -> $for {
#[cfg(any(unix, all(target_os = "wasi", not(target_env = "p1"))))]
unsafe {
<$for>::from_raw_fd(socket.into_raw_fd())
}
#[cfg(windows)]
unsafe {
<$for>::from_raw_socket(socket.into_raw_socket())
}
}
}
};
}
/// Link to online documentation for (almost) all supported OSs.
#[rustfmt::skip]
macro_rules! man_links {
// Links to all OSs.
($syscall: tt ( $section: tt ) ) => {
concat!(
man_links!(__ intro),
man_links!(__ unix $syscall($section)),
man_links!(__ windows $syscall($section)),
)
};
// Links to Unix-like OSs.
(unix: $syscall: tt ( $section: tt ) ) => {
concat!(
man_links!(__ intro),
man_links!(__ unix $syscall($section)),
)
};
// Links to Windows only.
(windows: $syscall: tt ( $section: tt ) ) => {
concat!(
man_links!(__ intro),
man_links!(__ windows $syscall($section)),
)
};
// Internals.
(__ intro) => {
"\n\nAdditional documentation can be found in manual of the OS:\n\n"
};
// List for Unix-like OSs.
(__ unix $syscall: tt ( $section: tt ) ) => {
concat!(
" * DragonFly BSD: <https://man.dragonflybsd.org/?command=", stringify!($syscall), "§ion=", stringify!($section), ">\n",
" * FreeBSD: <https://www.freebsd.org/cgi/man.cgi?query=", stringify!($syscall), "&sektion=", stringify!($section), ">\n",
" * Linux: <https://man7.org/linux/man-pages/man", stringify!($section), "/", stringify!($syscall), ".", stringify!($section), ".html>\n",
" * macOS: <https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/", stringify!($syscall), ".", stringify!($section), ".html> (archived, actually for iOS)\n",
" * NetBSD: <https://man.netbsd.org/", stringify!($syscall), ".", stringify!($section), ">\n",
" * OpenBSD: <https://man.openbsd.org/", stringify!($syscall), ".", stringify!($section), ">\n",
" * iOS: <https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/", stringify!($syscall), ".", stringify!($section), ".html> (archived)\n",
" * illumos: <https://illumos.org/man/3SOCKET/", stringify!($syscall), ">\n",
)
};
// List for Window (so just Windows).
(__ windows $syscall: tt ( $section: tt ) ) => {
concat!(
" * Windows: <https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-", stringify!($syscall), ">\n",
)
};
}
mod sockaddr;
mod socket;
mod sockref;
#[cfg_attr(
any(unix, all(target_os = "wasi", not(target_env = "p1"))),
path = "sys/unix.rs"
)]
#[cfg_attr(windows, path = "sys/windows.rs")]
mod sys;
#[cfg(not(any(windows, unix, all(target_os = "wasi", not(target_env = "p1")))))]
compile_error!("Socket2 doesn't support the compile target");
use sys::c_int;
pub use sockaddr::{sa_family_t, socklen_t, SockAddr, SockAddrStorage};
#[cfg(not(any(
target_os = "haiku",
target_os = "illumos",
target_os = "netbsd",
target_os = "redox",
target_os = "solaris",
target_os = "wasi",
)))]
pub use socket::InterfaceIndexOrAddress;
pub use socket::Socket;
pub use sockref::SockRef;
#[cfg(all(feature = "all", target_os = "linux"))]
pub use sys::CcidEndpoints;
#[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
pub use sys::SockFilter;
/// Specification of the communication domain for a socket.
///
/// This is a newtype wrapper around an integer which provides a nicer API in
/// addition to an injection point for documentation. Convenience constants such
/// as [`Domain::IPV4`], [`Domain::IPV6`], etc, are provided to avoid reaching
/// into libc for various constants.
///
/// This type is freely interconvertible with C's `int` type, however, if a raw
/// value needs to be provided.
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct Domain(c_int);
impl Domain {
/// Domain for IPv4 communication, corresponding to `AF_INET`.
pub const IPV4: Domain = Domain(sys::AF_INET);
/// Domain for IPv6 communication, corresponding to `AF_INET6`.
pub const IPV6: Domain = Domain(sys::AF_INET6);
/// Domain for Unix socket communication, corresponding to `AF_UNIX`.
#[cfg(not(target_os = "wasi"))]
pub const UNIX: Domain = Domain(sys::AF_UNIX);
/// Returns the correct domain for `address`.
pub const fn for_address(address: SocketAddr) -> Domain {
match address {
SocketAddr::V4(_) => Domain::IPV4,
SocketAddr::V6(_) => Domain::IPV6,
}
}
}
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.
///
/// This is a newtype wrapper around an integer which provides a nicer API in
/// addition to an injection point for documentation. Convenience constants such
/// as [`Type::STREAM`], [`Type::DGRAM`], etc, are provided to avoid reaching
/// into libc for various constants.
///
/// This type is freely interconvertible with C's `int` type, however, if a raw
/// value needs to be provided.
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct Type(c_int);
impl Type {
/// Type corresponding to `SOCK_STREAM`.
///
/// Used for protocols such as TCP.
pub const STREAM: Type = Type(sys::SOCK_STREAM);
/// Type corresponding to `SOCK_DGRAM`.
///
/// Used for protocols such as UDP.
pub const DGRAM: Type = Type(sys::SOCK_DGRAM);
/// Type corresponding to `SOCK_DCCP`.
///
/// Used for the DCCP protocol.
#[cfg(all(feature = "all", target_os = "linux"))]
pub const DCCP: Type = Type(sys::SOCK_DCCP);
/// Type corresponding to `SOCK_SEQPACKET`.
#[cfg(all(
feature = "all",
not(any(target_os = "espidf", target_os = "wasi", target_os = "horizon"))
))]
pub const SEQPACKET: Type = Type(sys::SOCK_SEQPACKET);
/// Type corresponding to `SOCK_RAW`.
#[cfg(all(
feature = "all",
not(any(
target_os = "redox",
target_os = "espidf",
target_os = "wasi",
target_os = "horizon"
))
))]
pub const 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 C's `int` type, however, if a raw
/// value needs to be provided.
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct Protocol(c_int);
impl Protocol {
/// Protocol corresponding to `ICMPv4`.
#[cfg(not(target_os = "wasi"))]
pub const ICMPV4: Protocol = Protocol(sys::IPPROTO_ICMP);
/// Protocol corresponding to `ICMPv6`.
#[cfg(not(target_os = "wasi"))]
pub const ICMPV6: Protocol = Protocol(sys::IPPROTO_ICMPV6);
/// Protocol corresponding to `TCP`.
pub const TCP: Protocol = Protocol(sys::IPPROTO_TCP);
/// Protocol corresponding to `UDP`.
pub const UDP: Protocol = Protocol(sys::IPPROTO_UDP);
#[cfg(target_os = "linux")]
/// Protocol corresponding to `MPTCP`.
pub const MPTCP: Protocol = Protocol(sys::IPPROTO_MPTCP);
/// Protocol corresponding to `DCCP`.
#[cfg(all(feature = "all", target_os = "linux"))]
pub const DCCP: Protocol = Protocol(sys::IPPROTO_DCCP);
/// Protocol corresponding to `SCTP`.
#[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
pub const SCTP: Protocol = Protocol(sys::IPPROTO_SCTP);
/// Protocol corresponding to `UDPLITE`.
#[cfg(all(
feature = "all",
any(
target_os = "android",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "linux",
)
))]
pub const UDPLITE: Protocol = Protocol(sys::IPPROTO_UDPLITE);
/// Protocol corresponding to `DIVERT`.
#[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "openbsd")))]
pub const DIVERT: Protocol = Protocol(sys::IPPROTO_DIVERT);
}
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
}
}
/// Flags for incoming messages.
///
/// Flags provide additional information about incoming messages.
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct RecvFlags(c_int);
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
impl RecvFlags {
/// Check if the message contains a truncated datagram.
///
/// This flag is only used for datagram-based sockets,
/// not for stream sockets.
///
/// On Unix this corresponds to the `MSG_TRUNC` flag.
/// On Windows this corresponds to the `WSAEMSGSIZE` error code.
#[cfg(not(target_os = "espidf"))]
pub const fn is_truncated(self) -> bool {
self.0 & sys::MSG_TRUNC != 0
}
}
/// A version of [`IoSliceMut`] that allows the buffer to be uninitialised.
///
/// [`IoSliceMut`]: std::io::IoSliceMut
#[repr(transparent)]
pub struct MaybeUninitSlice<'a>(sys::MaybeUninitSlice<'a>);
impl<'a> fmt::Debug for MaybeUninitSlice<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.0.as_slice(), fmt)
}
}
impl<'a> MaybeUninitSlice<'a> {
/// Creates a new `MaybeUninitSlice` wrapping a byte slice.
///
/// # Panics
///
/// Panics on Windows if the slice is larger than 4GB.
pub fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> {
MaybeUninitSlice(sys::MaybeUninitSlice::new(buf))
}
}
impl<'a> Deref for MaybeUninitSlice<'a> {
type Target = [MaybeUninit<u8>];
fn deref(&self) -> &[MaybeUninit<u8>] {
self.0.as_slice()
}
}
impl<'a> DerefMut for MaybeUninitSlice<'a> {
fn deref_mut(&mut self) -> &mut [MaybeUninit<u8>] {
self.0.as_mut_slice()
}
}
/// Configures a socket's TCP keepalive parameters.
///
/// See [`Socket::set_tcp_keepalive`].
#[derive(Debug, Clone)]
pub struct TcpKeepalive {
#[cfg_attr(
any(target_os = "openbsd", target_os = "haiku", target_os = "vita"),
allow(dead_code)
)]
time: Option<Duration>,
#[cfg(not(any(
target_os = "openbsd",
target_os = "redox",
target_os = "solaris",
target_os = "nto",
target_os = "espidf",
target_os = "vita",
target_os = "haiku",
target_os = "horizon"
)))]
interval: Option<Duration>,
#[cfg(not(any(
target_os = "openbsd",
target_os = "redox",
target_os = "solaris",
target_os = "nto",
target_os = "espidf",
target_os = "vita",
target_os = "haiku",
target_os = "horizon"
)))]
retries: Option<u32>,
}
impl TcpKeepalive {
/// Returns a new, empty set of TCP keepalive parameters.
#[allow(clippy::new_without_default)]
pub const fn new() -> TcpKeepalive {
TcpKeepalive {
time: None,
#[cfg(not(any(
target_os = "openbsd",
target_os = "redox",
target_os = "solaris",
target_os = "nto",
target_os = "espidf",
target_os = "vita",
target_os = "haiku",
target_os = "horizon"
)))]
interval: None,
#[cfg(not(any(
target_os = "openbsd",
target_os = "redox",
target_os = "solaris",
target_os = "nto",
target_os = "espidf",
target_os = "vita",
target_os = "haiku",
target_os = "horizon"
)))]
retries: None,
}
}
/// Set the amount of time after which TCP keepalive probes will be sent on
/// idle connections.
///
/// This will set `TCP_KEEPALIVE` on macOS and iOS, and
/// `TCP_KEEPIDLE` on all other Unix operating systems, except
/// OpenBSD and Haiku which don't support any way to set this
/// option. On Windows, this sets the value of the `tcp_keepalive`
/// struct's `keepalivetime` field.
///
/// Some platforms specify this value in seconds, so sub-second
/// specifications may be omitted.
pub const fn with_time(self, time: Duration) -> Self {
Self {
time: Some(time),
..self
}
}
/// Set the value of the `TCP_KEEPINTVL` option. On Windows, this sets the
/// value of the `tcp_keepalive` struct's `keepaliveinterval` field.
///
/// Sets the time interval between TCP keepalive probes.
///
/// Some platforms specify this value in seconds, so sub-second
/// specifications may be omitted.
#[cfg(any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "illumos",
target_os = "ios",
target_os = "visionos",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
target_os = "tvos",
target_os = "watchos",
target_os = "windows",
target_os = "cygwin",
all(target_os = "wasi", not(target_env = "p1")),
))]
pub const fn with_interval(self, interval: Duration) -> Self {
Self {
interval: Some(interval),
..self
}
}
/// Set the value of the `TCP_KEEPCNT` option.
///
/// Set the maximum number of TCP keepalive probes that will be sent before
/// dropping a connection, if TCP keepalive is enabled on this socket.
#[cfg(all(
feature = "all",
any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "illumos",
target_os = "ios",
target_os = "visionos",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
target_os = "tvos",
target_os = "watchos",
target_os = "cygwin",
target_os = "windows",
all(target_os = "wasi", not(target_env = "p1")),
)
))]
pub const fn with_retries(self, retries: u32) -> Self {
Self {
retries: Some(retries),
..self
}
}
}
/// Configuration of a `sendmsg(2)` system call.
///
/// This wraps `msghdr` on Unix and `WSAMSG` on Windows. Also see [`MsgHdrMut`]
/// for the variant used by `recvmsg(2)`.
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
#[repr(transparent)]
pub struct MsgHdr<'addr, 'bufs, 'control> {
inner: sys::msghdr,
#[allow(clippy::type_complexity)]
_lifetimes: PhantomData<(&'addr SockAddr, &'bufs IoSlice<'bufs>, &'control [u8])>,
}
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
impl<'addr, 'bufs, 'control> MsgHdr<'addr, 'bufs, 'control> {
/// Create a new `MsgHdr` with all empty/zero fields.
#[allow(clippy::new_without_default)]
pub fn new() -> MsgHdr<'addr, 'bufs, 'control> {
// SAFETY: all zero is valid for `msghdr` and `WSAMSG`.
MsgHdr {
inner: unsafe { mem::zeroed() },
_lifetimes: PhantomData,
}
}
/// Set the address (name) of the message.
///
/// Corresponds to setting `msg_name` and `msg_namelen` on Unix and `name`
/// and `namelen` on Windows.
pub fn with_addr(mut self, addr: &'addr SockAddr) -> Self {
sys::set_msghdr_name(&mut self.inner, addr);
self
}
/// Set the buffer(s) of the message.
///
/// Corresponds to setting `msg_iov` and `msg_iovlen` on Unix and `lpBuffers`
/// and `dwBufferCount` on Windows.
pub fn with_buffers(mut self, bufs: &'bufs [IoSlice<'_>]) -> Self {
let ptr = bufs.as_ptr() as *mut _;
sys::set_msghdr_iov(&mut self.inner, ptr, bufs.len());
self
}
/// Set the control buffer of the message.
///
/// Corresponds to setting `msg_control` and `msg_controllen` on Unix and
/// `Control` on Windows.
pub fn with_control(mut self, buf: &'control [u8]) -> Self {
let ptr = buf.as_ptr() as *mut _;
sys::set_msghdr_control(&mut self.inner, ptr, buf.len());
self
}
/// Set the flags of the message.
///
/// Corresponds to setting `msg_flags` on Unix and `dwFlags` on Windows.
pub fn with_flags(mut self, flags: sys::c_int) -> Self {
sys::set_msghdr_flags(&mut self.inner, flags);
self
}
}
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
impl<'name, 'bufs, 'control> fmt::Debug for MsgHdr<'name, 'bufs, 'control> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
"MsgHdr".fmt(fmt)
}
}
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
unsafe impl Send for MsgHdr<'_, '_, '_> {}
/// Configuration of a `recvmsg(2)` system call.
///
/// This wraps `msghdr` on Unix and `WSAMSG` on Windows. Also see [`MsgHdr`] for
/// the variant used by `sendmsg(2)`.
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
#[repr(transparent)]
pub struct MsgHdrMut<'addr, 'bufs, 'control> {
inner: sys::msghdr,
#[allow(clippy::type_complexity)]
_lifetimes: PhantomData<(
&'addr mut SockAddr,
&'bufs mut MaybeUninitSlice<'bufs>,
&'control mut [u8],
)>,
}
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
impl<'addr, 'bufs, 'control> MsgHdrMut<'addr, 'bufs, 'control> {
/// Create a new `MsgHdrMut` with all empty/zero fields.
#[allow(clippy::new_without_default)]
pub fn new() -> MsgHdrMut<'addr, 'bufs, 'control> {
// SAFETY: all zero is valid for `msghdr` and `WSAMSG`.
MsgHdrMut {
inner: unsafe { mem::zeroed() },
_lifetimes: PhantomData,
}
}
/// Set the mutable address (name) of the message.
///
/// Corresponds to setting `msg_name` and `msg_namelen` on Unix and `name`
/// and `namelen` on Windows.
#[allow(clippy::needless_pass_by_ref_mut)]
pub fn with_addr(mut self, addr: &'addr mut SockAddr) -> Self {
sys::set_msghdr_name(&mut self.inner, addr);
self
}
/// Set the mutable buffer(s) of the message.
///
/// Corresponds to setting `msg_iov` and `msg_iovlen` on Unix and `lpBuffers`
/// and `dwBufferCount` on Windows.
pub fn with_buffers(mut self, bufs: &'bufs mut [MaybeUninitSlice<'_>]) -> Self {
sys::set_msghdr_iov(&mut self.inner, bufs.as_mut_ptr().cast(), bufs.len());
self
}
/// Set the mutable control buffer of the message.
///
/// Corresponds to setting `msg_control` and `msg_controllen` on Unix and
/// `Control` on Windows.
pub fn with_control(mut self, buf: &'control mut [MaybeUninit<u8>]) -> Self {
sys::set_msghdr_control(&mut self.inner, buf.as_mut_ptr().cast(), buf.len());
self
}
/// Returns the flags of the message.
pub fn flags(&self) -> RecvFlags {
sys::msghdr_flags(&self.inner)
}
/// Gets the length of the control buffer.
///
/// Can be used to determine how much, if any, of the control buffer was filled by `recvmsg`.
///
/// Corresponds to `msg_controllen` on Unix and `Control.len` on Windows.
pub fn control_len(&self) -> usize {
sys::msghdr_control_len(&self.inner)
}
}
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
impl<'name, 'bufs, 'control> fmt::Debug for MsgHdrMut<'name, 'bufs, 'control> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
"MsgHdrMut".fmt(fmt)
}
}
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
unsafe impl Send for MsgHdrMut<'_, '_, '_> {}
================================================
FILE: src/sockaddr.rs
================================================
use std::hash::Hash;
use std::mem::{self, size_of};
use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
#[cfg(not(target_os = "wasi"))]
use std::path::Path;
use std::{fmt, io, ptr};
#[cfg(windows)]
use windows_sys::Win32::Networking::WinSock::SOCKADDR_IN6_0;
#[cfg(not(target_os = "wasi"))]
use crate::sys::AF_UNIX;
use crate::sys::{c_int, sockaddr_in, sockaddr_in6, sockaddr_storage, AF_INET, AF_INET6};
use crate::Domain;
/// The integer type used with `getsockname` on this platform.
#[allow(non_camel_case_types)]
pub type socklen_t = crate::sys::socklen_t;
/// The integer type for the `ss_family` field on this platform.
#[allow(non_camel_case_types)]
pub type sa_family_t = crate::sys::sa_family_t;
/// Rust version of the [`sockaddr_storage`] type.
///
/// This type is intended to be used with with direct calls to the `getsockname` syscall. See the
/// documentation of [`SockAddr::new`] for examples.
///
/// This crate defines its own `sockaddr_storage` type to avoid semver concerns with upgrading
/// `windows-sys`.
#[repr(transparent)]
pub struct SockAddrStorage {
storage: sockaddr_storage,
}
impl SockAddrStorage {
/// Construct a new storage containing all zeros.
#[inline]
pub fn zeroed() -> Self {
// SAFETY: All zeros is valid for this type.
unsafe { mem::zeroed() }
}
/// Returns the size of this storage.
#[inline]
pub fn size_of(&self) -> socklen_t {
size_of::<Self>() as socklen_t
}
/// View this type as another type.
///
/// # Safety
///
/// The type `T` must be one of the `sockaddr_*` types defined by this platform.
///
/// # Examples
/// ```
/// # #[allow(dead_code)]
/// # #[cfg(unix)] mod unix_example {
/// # use core::mem::size_of;
/// use libc::sockaddr_storage;
/// use socket2::{SockAddr, SockAddrStorage, socklen_t};
///
/// fn from_sockaddr_storage(recv_address: &sockaddr_storage) -> SockAddr {
/// let mut storage = SockAddrStorage::zeroed();
/// let libc_address = unsafe { storage.view_as::<sockaddr_storage>() };
/// *libc_address = *recv_address;
/// unsafe { SockAddr::new(storage, size_of::<sockaddr_storage>() as socklen_t) }
/// }
/// # }
/// ```
#[inline]
pub unsafe fn view_as<T>(&mut self) -> &mut T {
assert!(size_of::<T>() <= size_of::<Self>());
// SAFETY: This type is repr(transparent) over `sockaddr_storage` and `T` is one of the
// `sockaddr_*` types defined by this platform.
&mut *(self as *mut Self as *mut T)
}
}
impl std::fmt::Debug for SockAddrStorage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("sockaddr_storage")
.field("ss_family", &self.storage.ss_family)
.finish_non_exhaustive()
}
}
/// The address of a socket.
///
/// `SockAddr`s may be constructed directly to and from the standard library
/// [`SocketAddr`], [`SocketAddrV4`], and [`SocketAddrV6`] types.
#[derive(Clone)]
pub struct SockAddr {
storage: sockaddr_storage,
len: socklen_t,
}
#[allow(clippy::len_without_is_empty)]
impl SockAddr {
/// Create a `SockAddr` from the underlying storage and its length.
///
/// # Safety
///
/// Caller must ensure that the address family and length match the type of
/// storage address. For example if `storage.ss_family` is set to `AF_INET`
/// the `storage` must be initialised as `sockaddr_in`, setting the content
/// and length appropriately.
///
/// # Examples
///
/// ```
/// # fn main() -> std::io::Result<()> {
/// # #[cfg(unix)] {
/// use std::io;
/// use std::os::fd::AsRawFd;
///
/// use socket2::{SockAddr, SockAddrStorage, Socket, Domain, Type};
///
/// let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?;
///
/// // Initialise a `SocketAddr` by calling `getsockname(2)`.
/// let mut addr_storage = SockAddrStorage::zeroed();
/// let mut len = addr_storage.size_of();
///
/// // The `getsockname(2)` system call will initialize `storage` for
/// // us, setting `len` to the correct length.
/// let res = unsafe {
/// libc::getsockname(
/// socket.as_raw_fd(),
/// addr_storage.view_as(),
/// &mut len,
/// )
/// };
/// if res == -1 {
/// return Err(io::Error::last_os_error());
/// }
///
/// let address = unsafe { SockAddr::new(addr_storage, len) };
/// # drop(address);
/// # }
/// # Ok(())
/// # }
/// ```
pub const unsafe fn new(storage: SockAddrStorage, len: socklen_t) -> SockAddr {
SockAddr {
storage: storage.storage,
len: len as socklen_t,
}
}
/// Initialise a `SockAddr` by calling the function `init`.
///
/// The type of the address storage and length passed to the function `init`
/// is OS/architecture specific.
///
/// The address is zeroed before `init` is called and is thus valid to
/// dereference and read from. The length initialised to the maximum length
/// of the storage.
///
/// # Safety
///
/// Caller must ensure that the address family and length match the type of
/// storage address. For example if `storage.ss_family` is set to `AF_INET`
/// the `storage` must be initialised as `sockaddr_in`, setting the content
/// and length appropriately.
///
/// # Examples
///
/// ```
/// # fn main() -> std::io::Result<()> {
/// # #[cfg(unix)] {
/// use std::io;
/// use std::os::fd::AsRawFd;
///
/// use socket2::{SockAddr, Socket, Domain, Type};
///
/// let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?;
///
/// // Initialise a `SocketAddr` by calling `getsockname(2)`.
/// let (_, address) = unsafe {
/// SockAddr::try_init(|addr_storage, len| {
/// // The `getsockname(2)` system call will initialize `storage` for
/// // us, setting `len` to the correct length.
/// if libc::getsockname(socket.as_raw_fd(), addr_storage.cast(), len) == -1 {
/// Err(io::Error::last_os_error())
/// } else {
/// Ok(())
/// }
/// })
/// }?;
/// # drop(address);
/// # }
/// # Ok(())
/// # }
/// ```
pub unsafe fn try_init<F, T>(init: F) -> io::Result<(T, SockAddr)>
where
F: FnOnce(*mut SockAddrStorage, *mut socklen_t) -> io::Result<T>,
{
const STORAGE_SIZE: socklen_t = size_of::<sockaddr_storage>() as socklen_t;
// NOTE: `SockAddr::unix` depends on the storage being zeroed before
// calling `init`.
// NOTE: calling `recvfrom` with an empty buffer also depends on the
// storage being zeroed before calling `init` as the OS might not
// initialise it.
let mut storage = SockAddrStorage::zeroed();
let mut len = STORAGE_SIZE;
init(&mut storage, &mut len).map(|res| {
debug_assert!(len <= STORAGE_SIZE, "overflown address storage");
(res, SockAddr::new(storage, len))
})
}
/// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path.
///
/// Returns an error if the path is longer than `SUN_LEN`.
#[cfg(not(target_os = "wasi"))]
pub fn unix<P>(path: P) -> io::Result<SockAddr>
where
P: AsRef<Path>,
{
crate::sys::unix_sockaddr(path.as_ref())
}
/// Set the length of the address.
///
/// # Safety
///
/// Caller must ensure that the address up to `length` bytes are properly
/// initialised.
pub unsafe fn set_length(&mut self, length: socklen_t) {
self.len = length;
}
/// Returns this address's family.
pub const fn family(&self) -> sa_family_t {
self.storage.ss_family
}
/// Returns this address's `Domain`.
pub const fn domain(&self) -> Domain {
Domain(self.storage.ss_family as c_int)
}
/// Returns the size of this address in bytes.
pub const fn len(&self) -> socklen_t {
self.len
}
/// Returns a raw pointer to the address.
pub const fn as_ptr(&self) -> *const SockAddrStorage {
&self.storage as *const sockaddr_storage as *const SockAddrStorage
}
/// Returns the address as the storage.
pub const fn as_storage(self) -> SockAddrStorage {
SockAddrStorage {
storage: self.storage,
}
}
/// Returns true if this address is in the `AF_INET` (IPv4) family, false otherwise.
pub const fn is_ipv4(&self) -> bool {
self.storage.ss_family == AF_INET as sa_family_t
}
/// Returns true if this address is in the `AF_INET6` (IPv6) family, false
/// otherwise.
pub const fn is_ipv6(&self) -> bool {
self.storage.ss_family == AF_INET6 as sa_family_t
}
/// Returns true if this address is of a unix socket (for local interprocess communication),
/// i.e. it is from the `AF_UNIX` family, false otherwise.
#[cfg(not(target_os = "wasi"))]
pub fn is_unix(&self) -> bool {
self.storage.ss_family == AF_UNIX as sa_family_t
}
/// Returns this address as a `SocketAddr` if it is in the `AF_INET` (IPv4)
/// or `AF_INET6` (IPv6) family, otherwise returns `None`.
pub fn as_socket(&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 { &*(ptr::addr_of!(self.storage).cast::<sockaddr_in>()) };
let ip = crate::sys::from_in_addr(addr.sin_addr);
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 { &*(ptr::addr_of!(self.storage).cast::<sockaddr_in6>()) };
let ip = crate::sys::from_in6_addr(addr.sin6_addr);
let port = u16::from_be(addr.sin6_port);
Some(SocketAddr::V6(SocketAddrV6::new(
ip,
port,
addr.sin6_flowinfo,
#[cfg(any(unix, all(target_os = "wasi", not(target_env = "p1"))))]
addr.sin6_scope_id,
#[cfg(windows)]
unsafe {
addr.Anonymous.sin6_scope_id
},
)))
} else {
None
}
}
/// Returns this address as a [`SocketAddrV4`] if it is in the `AF_INET`
/// family.
pub fn as_socket_ipv4(&self) -> Option<SocketAddrV4> {
match self.as_socket() {
Some(SocketAddr::V4(addr)) => Some(addr),
_ => None,
}
}
/// Returns this address as a [`SocketAddrV6`] if it is in the `AF_INET6`
/// family.
pub fn as_socket_ipv6(&self) -> Option<SocketAddrV6> {
match self.as_socket() {
Some(SocketAddr::V6(addr)) => Some(addr),
_ => None,
}
}
/// Returns the initialised storage bytes.
fn as_bytes(&self) -> &[u8] {
// SAFETY: `self.storage` is a C struct which can always be treated a
// slice of bytes. Furthermore, we ensure we don't read any uninitialised
// bytes by using `self.len`.
unsafe { std::slice::from_raw_parts(self.as_ptr().cast(), self.len as usize) }
}
}
impl From<SocketAddr> for SockAddr {
fn from(addr: SocketAddr) -> SockAddr {
match addr {
SocketAddr::V4(addr) => addr.into(),
SocketAddr::V6(addr) => addr.into(),
}
}
}
impl From<SocketAddrV4> for SockAddr {
fn from(addr: SocketAddrV4) -> SockAddr {
// SAFETY: a `sockaddr_storage` of all zeros is valid.
let mut storage = unsafe { mem::zeroed::<sockaddr_storage>() };
let len = {
let storage = unsafe { &mut *ptr::addr_of_mut!(storage).cast::<sockaddr_in>() };
storage.sin_family = AF_INET as sa_family_t;
storage.sin_port = addr.port().to_be();
storage.sin_addr = crate::sys::to_in_addr(addr.ip());
#[cfg(not(target_os = "wasi"))]
{
storage.sin_zero = Default::default();
}
mem::size_of::<sockaddr_in>() as socklen_t
};
#[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "haiku",
target_os = "hermit",
target_os = "ios",
target_os = "visionos",
target_os = "macos",
target_os = "netbsd",
target_os = "nto",
target_os = "openbsd",
target_os = "tvos",
target_os = "vxworks",
target_os = "watchos",
))]
{
storage.ss_len = len as u8;
}
SockAddr { storage, len }
}
}
impl From<SocketAddrV6> for SockAddr {
fn from(addr: SocketAddrV6) -> SockAddr {
// SAFETY: a `sockaddr_storage` of all zeros is valid.
let mut storage = unsafe { mem::zeroed::<sockaddr_storage>() };
let len = {
let storage = unsafe { &mut *ptr::addr_of_mut!(storage).cast::<sockaddr_in6>() };
storage.sin6_family = AF_INET6 as sa_family_t;
storage.sin6_port = addr.port().to_be();
storage.sin6_addr = crate::sys::to_in6_addr(addr.ip());
storage.sin6_flowinfo = addr.flowinfo();
#[cfg(any(unix, all(target_os = "wasi", not(target_env = "p1"))))]
{
storage.sin6_scope_id = addr.scope_id();
}
#[cfg(windows)]
{
storage.Anonymous = SOCKADDR_IN6_0 {
sin6_scope_id: addr.scope_id(),
};
}
mem::size_of::<sockaddr_in6>() as socklen_t
};
#[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "haiku",
target_os = "hermit",
target_os = "ios",
target_os = "visionos",
target_os = "macos",
target_os = "netbsd",
target_os = "nto",
target_os = "openbsd",
target_os = "tvos",
target_os = "vxworks",
target_os = "watchos",
))]
{
storage.ss_len = len as u8;
}
SockAddr { storage, len }
}
}
impl fmt::Debug for SockAddr {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut f = fmt.debug_struct("SockAddr");
#[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "haiku",
target_os = "hermit",
target_os = "ios",
target_os = "visionos",
target_os = "macos",
target_os = "netbsd",
target_os = "nto",
target_os = "openbsd",
target_os = "tvos",
target_os = "vxworks",
target_os = "watchos",
))]
f.field("ss_len", &self.storage.ss_len);
f.field("ss_family", &self.storage.ss_family)
.field("len", &self.len)
.finish()
}
}
impl PartialEq for SockAddr {
fn eq(&self, other: &Self) -> bool {
self.as_bytes() == other.as_bytes()
}
}
impl Eq for SockAddr {}
impl Hash for SockAddr {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.as_bytes().hash(state);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ipv4() {
use std::net::Ipv4Addr;
let std = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
let addr = SockAddr::from(std);
assert!(addr.is_ipv4());
assert!(!addr.is_ipv6());
#[cfg(not(target_os = "wasi"))]
assert!(!addr.is_unix());
assert_eq!(addr.family(), AF_INET as sa_family_t);
assert_eq!(addr.domain(), Domain::IPV4);
assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t);
assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std)));
assert_eq!(addr.as_socket_ipv4(), Some(std));
assert!(addr.as_socket_ipv6().is_none());
let addr = SockAddr::from(SocketAddr::from(std));
assert_eq!(addr.family(), AF_INET as sa_family_t);
assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t);
assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std)));
assert_eq!(addr.as_socket_ipv4(), Some(std));
assert!(addr.as_socket_ipv6().is_none());
#[cfg(all(unix, not(target_os = "wasi")))]
{
assert!(addr.as_pathname().is_none());
assert!(addr.as_abstract_namespace().is_none());
}
}
#[test]
fn ipv6() {
use std::net::Ipv6Addr;
let std = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
let addr = SockAddr::from(std);
assert!(addr.is_ipv6());
assert!(!addr.is_ipv4());
#[cfg(not(target_os = "wasi"))]
assert!(!addr.is_unix());
assert_eq!(addr.family(), AF_INET6 as sa_family_t);
assert_eq!(addr.domain(), Domain::IPV6);
assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t);
assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std)));
assert!(addr.as_socket_ipv4().is_none());
assert_eq!(addr.as_socket_ipv6(), Some(std));
let addr = SockAddr::from(SocketAddr::from(std));
assert_eq!(addr.family(), AF_INET6 as sa_family_t);
assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t);
assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std)));
assert!(addr.as_socket_ipv4().is_none());
assert_eq!(addr.as_socket_ipv6(), Some(std));
#[cfg(all(unix, not(target_os = "wasi")))]
{
assert!(addr.as_pathname().is_none());
assert!(addr.as_abstract_namespace().is_none());
}
}
#[test]
fn ipv4_eq() {
use std::net::Ipv4Addr;
let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
let std2 = SocketAddrV4::new(Ipv4Addr::new(5, 6, 7, 8), 8765);
test_eq(
SockAddr::from(std1),
SockAddr::from(std1),
SockAddr::from(std2),
);
}
#[test]
fn ipv4_hash() {
use std::net::Ipv4Addr;
let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
let std2 = SocketAddrV4::new(Ipv4Addr::new(5, 6, 7, 8), 8765);
test_hash(
SockAddr::from(std1),
SockAddr::from(std1),
SockAddr::from(std2),
);
}
#[test]
fn ipv6_eq() {
use std::net::Ipv6Addr;
let std1 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
let std2 = SocketAddrV6::new(Ipv6Addr::new(3, 4, 5, 6, 7, 8, 9, 0), 7654, 13, 14);
test_eq(
SockAddr::from(std1),
SockAddr::from(std1),
SockAddr::from(std2),
);
}
#[test]
fn ipv6_hash() {
use std::net::Ipv6Addr;
let std1 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
let std2 = SocketAddrV6::new(Ipv6Addr::new(3, 4, 5, 6, 7, 8, 9, 0), 7654, 13, 14);
test_hash(
SockAddr::from(std1),
SockAddr::from(std1),
SockAddr::from(std2),
);
}
#[test]
fn ipv4_ipv6_eq() {
use std::net::Ipv4Addr;
use std::net::Ipv6Addr;
let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
let std2 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
test_eq(
SockAddr::from(std1),
SockAddr::from(std1),
SockAddr::from(std2),
);
test_eq(
SockAddr::from(std2),
SockAddr::from(std2),
SockAddr::from(std1),
);
}
#[test]
fn ipv4_ipv6_hash() {
use std::net::Ipv4Addr;
use std::net::Ipv6Addr;
let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
let std2 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
test_hash(
SockAddr::from(std1),
SockAddr::from(std1),
SockAddr::from(std2),
);
test_hash(
SockAddr::from(std2),
SockAddr::from(std2),
SockAddr::from(std1),
);
}
#[allow(clippy::eq_op)] // allow a0 == a0 check
fn test_eq(a0: SockAddr, a1: SockAddr, b: SockAddr) {
assert!(a0 == a0);
assert!(a0 == a1);
assert!(a1 == a0);
assert!(a0 != b);
assert!(b != a0);
}
fn test_hash(a0: SockAddr, a1: SockAddr, b: SockAddr) {
assert!(calculate_hash(&a0) == calculate_hash(&a0));
assert!(calculate_hash(&a0) == calculate_hash(&a1));
// technically unequal values can have the same hash, in this case x != z and both have different hashes
assert!(calculate_hash(&a0) != calculate_hash(&b));
}
fn calculate_hash(x: &SockAddr) -> u64 {
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
let mut hasher = DefaultHasher::new();
x.hash(&mut hasher);
hasher.finish()
}
}
================================================
FILE: src/socket.rs
================================================
// Copyright 2015 The Rust Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::fmt;
use std::io::{self, Read, Write};
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
use std::io::{IoSlice, IoSliceMut};
use std::mem::MaybeUninit;
#[cfg(not(target_os = "nto"))]
use std::net::Ipv6Addr;
use std::net::{self, Ipv4Addr, Shutdown};
#[cfg(any(unix, all(target_os = "wasi", not(target_env = "p1"))))]
use std::os::fd::{FromRawFd, IntoRawFd};
#[cfg(windows)]
use std::os::windows::io::{FromRawSocket, IntoRawSocket};
use std::time::Duration;
use crate::sys::{self, c_int, getsockopt, setsockopt, Bool};
#[cfg(all(unix, not(any(target_os = "redox", target_os = "horizon"))))]
use crate::MsgHdrMut;
use crate::{Domain, Protocol, SockAddr, TcpKeepalive, Type};
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
use crate::{MaybeUninitSlice, MsgHdr, RecvFlags};
/// 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.
///
/// ## Converting to and from other types
///
/// This type can be freely converted into the network primitives provided by
/// the standard library, such as [`TcpStream`] or [`UdpSocket`], using the
/// [`From`] trait, see the example below.
///
/// [`TcpStream`]: std::net::TcpStream
/// [`UdpSocket`]: std::net::UdpSocket
///
/// # Notes
///
/// Some methods that set options on `Socket` require two system calls to set
/// their options without overwriting previously set options. We do this by
/// first getting the current settings, applying the desired changes, and then
/// updating the settings. This means that the operation is **not** atomic. This
/// can lead to a data race when two threads are changing options in parallel.
///
/// # Examples
/// ```no_run
/// # fn main() -> std::io::Result<()> {
/// use std::net::{SocketAddr, TcpListener};
/// use socket2::{Socket, Domain, Type};
///
/// // create a TCP listener
/// let socket = Socket::new(Domain::IPV6, Type::STREAM, None)?;
///
/// let address: SocketAddr = "[::1]:12345".parse().unwrap();
/// let address = address.into();
/// socket.bind(&address)?;
/// socket.listen(128)?;
///
/// let listener: TcpListener = socket.into();
/// // ...
/// # drop(listener);
/// # Ok(()) }
/// ```
pub struct Socket {
inner: sys::Socket,
}
impl Socket {
/// # Safety
///
/// The caller must ensure `raw` is a valid file descriptor/socket. NOTE:
/// this should really be marked `unsafe`, but this being an internal
/// function, often passed as mapping function, it's makes it very
/// inconvenient to mark it as `unsafe`.
pub(crate) fn from_raw(raw: sys::RawSocket) -> Socket {
Socket {
// SAFETY: the caller must ensure that `raw` is a valid file
// descriptor, but when it isn't it could return I/O errors, or
// potentially close a fd it doesn't own. All of that isn't memory
// unsafe, so it's not desired but never memory unsafe or causes UB.
inner: unsafe { sys::socket_from_raw(raw) },
}
}
pub(crate) fn as_raw(&self) -> sys::RawSocket {
sys::socket_as_raw(&self.inner)
}
pub(crate) fn into_raw(self) -> sys::RawSocket {
sys::socket_into_raw(self.inner)
}
/// Creates a new socket and sets common flags.
///
/// This function corresponds to `socket(2)` on Unix and `WSASocketW` on
/// Windows.
///
/// On Unix-like systems, the close-on-exec flag is set on the new socket.
/// Additionally, on Apple platforms `SOCK_NOSIGPIPE` is set. On Windows,
/// the socket is made non-inheritable.
///
/// [`Socket::new_raw`] can be used if you don't want these flags to be set.
#[doc = man_links!(socket(2))]
pub fn new(domain: Domain, ty: Type, protocol: Option<Protocol>) -> io::Result<Socket> {
let ty = set_common_type(ty);
Socket::new_raw(domain, ty, protocol).and_then(set_common_flags)
}
/// Creates a new socket ready to be configured.
///
/// This function corresponds to `socket(2)` on Unix and `WSASocketW` on
/// Windows and simply creates a new socket, no other configuration is done.
pub fn new_raw(domain: Domain, ty: Type, protocol: Option<Protocol>) -> io::Result<Socket> {
let protocol = protocol.map_or(0, |p| p.0);
sys::socket(domain.0, ty.0, protocol).map(Socket::from_raw)
}
/// Creates a pair of sockets which are connected to each other.
///
/// This function corresponds to `socketpair(2)`.
///
/// This function sets the same flags as in done for [`Socket::new`],
/// [`Socket::pair_raw`] can be used if you don't want to set those flags.
#[doc = man_links!(unix: socketpair(2))]
#[cfg(all(feature = "all", unix))]
pub fn pair(
domain: Domain,
ty: Type,
protocol: Option<Protocol>,
) -> io::Result<(Socket, Socket)> {
let ty = set_common_type(ty);
let (a, b) = Socket::pair_raw(domain, ty, protocol)?;
let a = set_common_flags(a)?;
let b = set_common_flags(b)?;
Ok((a, b))
}
/// Creates a pair of sockets which are connected to each other.
///
/// This function corresponds to `socketpair(2)`.
#[cfg(all(feature = "all", unix))]
pub fn pair_raw(
domain: Domain,
ty: Type,
protocol: Option<Protocol>,
) -> io::Result<(Socket, Socket)> {
let protocol = protocol.map_or(0, |p| p.0);
sys::socketpair(domain.0, ty.0, protocol)
.map(|[a, b]| (Socket::from_raw(a), Socket::from_raw(b)))
}
/// Binds this socket to the specified address.
///
/// This function directly corresponds to the `bind(2)` function on Windows
/// and Unix.
#[doc = man_links!(bind(2))]
pub fn bind(&self, address: &SockAddr) -> io::Result<()> {
sys::bind(self.as_raw(), address)
}
/// Initiate a connection on this socket to the specified address.
///
/// This function directly corresponds to the `connect(2)` function on
/// Windows and Unix.
///
/// An error will be returned if `listen` or `connect` has already been
/// called on this builder.
#[doc = man_links!(connect(2))]
///
/// # Notes
///
/// When using a non-blocking connect (by setting the socket into
/// non-blocking mode before calling this function), socket option can't be
/// set *while connecting*. This will cause errors on Windows. Socket
/// options can be safely set before and after connecting the socket.
///
/// On Cygwin, a Unix domain socket connect blocks until the server accepts
/// it. If the behavior is not expected, try [`Socket::set_no_peercred`]
/// (Cygwin only).
#[allow(rustdoc::broken_intra_doc_links)] // Socket::set_no_peercred
pub fn connect(&self, address: &SockAddr) -> io::Result<()> {
sys::connect(self.as_raw(), address)
}
/// Initiate a connection on this socket to the specified address, only
/// only waiting for a certain period of time for the connection to be
/// established.
///
/// Unlike many other methods on `Socket`, this does *not* correspond to a
/// single C function. It sets the socket to nonblocking mode, connects via
/// connect(2), and then waits for the connection to complete with poll(2)
/// on Unix and select on Windows. When the connection is complete, the
/// socket is set back to blocking mode. On Unix, this will loop over
/// `EINTR` errors.
///
/// # Warnings
///
/// The non-blocking state of the socket is overridden by this function -
/// it will be returned in blocking mode on success, and in an indeterminate
/// state on failure.
///
/// If the connection request times out, it may still be processing in the
/// background - a second call to `connect` or `connect_timeout` may fail.
pub fn connect_timeout(&self, addr: &SockAddr, timeout: Duration) -> io::Result<()> {
self.set_nonblocking(true)?;
let res = self.connect(addr);
self.set_nonblocking(false)?;
match res {
Ok(()) => return Ok(()),
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {}
#[cfg(any(unix, all(target_os = "wasi", not(target_env = "p1"))))]
Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {}
Err(e) => return Err(e),
}
sys::poll_connect(self, timeout)
}
/// Mark a socket as ready to accept incoming connection requests using
/// [`Socket::accept()`].
///
/// This function directly corresponds to the `listen(2)` function on
/// Windows and Unix.
///
/// An error will be returned if `listen` or `connect` has already been
/// called on this builder.
#[doc = man_links!(listen(2))]
pub fn listen(&self, backlog: c_int) -> io::Result<()> {
sys::listen(self.as_raw(), backlog)
}
/// Accept a new incoming connection from this listener.
///
/// This function uses `accept4(2)` on platforms that support it and
/// `accept(2)` platforms that do not.
///
/// This function sets the same flags as in done for [`Socket::new`],
/// [`Socket::accept_raw`] can be used if you don't want to set those flags.
#[doc = man_links!(accept(2))]
///
/// # Notes
///
/// On Cygwin, a Unix domain socket connect blocks until the server accepts
/// it. If the behavior is not expected, try [`Socket::set_no_peercred`]
/// (Cygwin only).
#[allow(rustdoc::broken_intra_doc_links)] // Socket::set_no_peercred
pub fn accept(&self) -> io::Result<(Socket, SockAddr)> {
// Use `accept4` on platforms that support it.
#[cfg(any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "illumos",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
target_os = "cygwin",
))]
return self._accept4(libc::SOCK_CLOEXEC);
// Fall back to `accept` on platforms that do not support `accept4`.
#[cfg(not(any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "illumos",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
target_os = "cygwin",
)))]
{
let (socket, addr) = self.accept_raw()?;
let socket = set_common_accept_flags(socket)?;
// `set_common_flags` does not disable inheritance on Windows because `Socket::new`
// unlike `accept` is able to create the socket with inheritance disabled.
#[cfg(windows)]
socket._set_no_inherit(true)?;
Ok((socket, addr))
}
}
/// Accept a new incoming connection from this listener.
///
/// This function directly corresponds to the `accept(2)` function on
/// Windows and Unix.
pub fn accept_raw(&self) -> io::Result<(Socket, SockAddr)> {
sys::accept(self.as_raw()).map(|(inner, addr)| (Socket::from_raw(inner), addr))
}
/// Returns the socket address of the local half of this socket.
///
/// This function directly corresponds to the `getsockname(2)` function on
/// Windows and Unix.
#[doc = man_links!(getsockname(2))]
///
/// # Notes
///
/// Depending on the OS this may return an error if the socket is not
/// [bound].
///
/// [bound]: Socket::bind
pub fn local_addr(&self) -> io::Result<SockAddr> {
sys::getsockname(self.as_raw())
}
/// Returns the socket address of the remote peer of this socket.
///
/// This function directly corresponds to the `getpeername(2)` function on
/// Windows and Unix.
#[doc = man_links!(getpeername(2))]
///
/// # Notes
///
/// This returns an error if the socket is not [`connect`ed].
///
/// [`connect`ed]: Socket::connect
pub fn peer_addr(&self) -> io::Result<SockAddr> {
sys::getpeername(self.as_raw())
}
/// Returns the [`Type`] of this socket by checking the `SO_TYPE` option on
/// this socket.
pub fn r#type(&self) -> io::Result<Type> {
unsafe { getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_TYPE).map(Type) }
}
/// Creates a new independently owned handle to the underlying socket.
///
/// # Notes
///
/// On Unix this uses `F_DUPFD_CLOEXEC` and thus sets the `FD_CLOEXEC` on
/// the returned socket.
///
/// On Windows this uses `WSA_FLAG_NO_HANDLE_INHERIT` setting inheriting to
/// false.
///
/// On Windows this can **not** be used function cannot be used on a
/// QOS-enabled socket, see
/// <https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsaduplicatesocketw>.
#[cfg(not(target_os = "wasi"))]
pub fn try_clone(&self) -> io::Result<Socket> {
sys::try_clone(self.as_raw()).map(Socket::from_raw)
}
/// Returns true if this socket is set to nonblocking mode, false otherwise.
///
/// # Notes
///
/// On Unix this corresponds to calling `fcntl` returning the value of
/// `O_NONBLOCK`.
///
/// On Windows it is not possible retrieve the nonblocking mode status.
#[cfg(all(
feature = "all",
any(unix, all(target_os = "wasi", not(target_env = "p1")))
))]
pub fn nonblocking(&self) -> io::Result<bool> {
sys::nonblocking(self.as_raw())
}
/// Moves this socket into or out of nonblocking mode.
///
/// # Notes
///
/// On Unix this corresponds to calling `fcntl` (un)setting `O_NONBLOCK`.
///
/// On Windows this corresponds to calling `ioctlsocket` (un)setting
/// `FIONBIO`.
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
sys::set_nonblocking(self.as_raw(), nonblocking)
}
/// Shuts down the read, write, or both halves of this connection.
///
/// This function will cause all pending and future I/O on the specified
/// portions to return immediately with an appropriate value.
#[doc = man_links!(shutdown(2))]
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
sys::shutdown(self.as_raw(), how)
}
/// Receives data on the socket from the remote address to which it is
/// connected.
///
/// The [`connect`] method will connect this socket to a remote address.
/// This method might fail if the socket is not connected.
#[doc = man_links!(recv(2))]
///
/// [`connect`]: Socket::connect
///
/// # Safety
///
/// Normally casting a `&mut [u8]` to `&mut [MaybeUninit<u8>]` would be
/// unsound, as that allows us to write uninitialised bytes to the buffer.
/// However this implementation promises to not write uninitialised bytes to
/// the `buf`fer and passes it directly to `recv(2)` system call. This
/// promise ensures that this function can be called using a `buf`fer of
/// type `&mut [u8]`.
///
/// Note that the [`io::Read::read`] implementation calls this function with
/// a `buf`fer of type `&mut [u8]`, allowing initialised buffers to be used
/// without using `unsafe`.
pub fn recv(&self, buf: &mut [MaybeUninit<u8>]) -> io::Result<usize> {
self.recv_with_flags(buf, 0)
}
/// 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`]: Socket::recv
/// [`out_of_band_inline`]: Socket::out_of_band_inline
#[cfg_attr(target_os = "redox", allow(rustdoc::broken_intra_doc_links))]
#[cfg(not(target_os = "wasi"))]
pub fn recv_out_of_band(&self, buf: &mut [MaybeUninit<u8>]) -> io::Result<usize> {
self.recv_with_flags(buf, sys::MSG_OOB)
}
/// Identical to [`recv`] but allows for specification of arbitrary flags to
/// the underlying `recv` call.
///
/// [`recv`]: Socket::recv
pub fn recv_with_flags(
&self,
buf: &mut [MaybeUninit<u8>],
flags: sys::c_int,
) -> io::Result<usize> {
sys::recv(self.as_raw(), buf, flags)
}
/// Receives data on the socket from the remote address to which it is
/// connected. Unlike [`recv`] this allows passing multiple buffers.
///
/// The [`connect`] method will connect this socket to a remote address.
/// This method might fail if the socket is not connected.
///
/// In addition to the number of bytes read, this function returns the flags
/// for the received message. See [`RecvFlags`] for more information about
/// the returned flags.
#[doc = man_links!(recvmsg(2))]
///
/// [`recv`]: Socket::recv
/// [`connect`]: Socket::connect
///
/// # Safety
///
/// Normally casting a `IoSliceMut` to `MaybeUninitSlice` would be unsound,
/// as that allows us to write uninitialised bytes to the buffer. However
/// this implementation promises to not write uninitialised bytes to the
/// `bufs` and passes it directly to `recvmsg(2)` system call. This promise
/// ensures that this function can be called using `bufs` of type `&mut
/// [IoSliceMut]`.
///
/// Note that the [`io::Read::read_vectored`] implementation calls this
/// function with `buf`s of type `&mut [IoSliceMut]`, allowing initialised
/// buffers to be used without using `unsafe`.
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
pub fn recv_vectored(
&self,
bufs: &mut [MaybeUninitSlice<'_>],
) -> io::Result<(usize, RecvFlags)> {
self.recv_vectored_with_flags(bufs, 0)
}
/// Identical to [`recv_vectored`] but allows for specification of arbitrary
/// flags to the underlying `recvmsg`/`WSARecv` call.
///
/// [`recv_vectored`]: Socket::recv_vectored
///
/// # Safety
///
/// `recv_from_vectored` makes the same safety guarantees regarding `bufs`
/// as [`recv_vectored`].
///
/// [`recv_vectored`]: Socket::recv_vectored
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
pub fn recv_vectored_with_flags(
&self,
bufs: &mut [MaybeUninitSlice<'_>],
flags: c_int,
) -> io::Result<(usize, RecvFlags)> {
sys::recv_vectored(self.as_raw(), bufs, flags)
}
/// Receives data on the socket from the remote address to which it is
/// connected, without removing that data from the queue. On success,
/// returns the number of bytes peeked.
///
/// Successive calls return the same data. This is accomplished by passing
/// `MSG_PEEK` as a flag to the underlying `recv` system call.
///
/// # Safety
///
/// `peek` makes the same safety guarantees regarding the `buf`fer as
/// [`recv`].
///
/// [`recv`]: Socket::recv
pub fn peek(&self, buf: &mut [MaybeUninit<u8>]) -> io::Result<usize> {
self.recv_with_flags(buf, sys::MSG_PEEK)
}
/// Receives data from the socket. On success, returns the number of bytes
/// read and the address from whence the data came.
#[doc = man_links!(recvfrom(2))]
///
/// # Safety
///
/// `recv_from` makes the same safety guarantees regarding the `buf`fer as
/// [`recv`].
///
/// [`recv`]: Socket::recv
pub fn recv_from(&self, buf: &mut [MaybeUninit<u8>]) -> io::Result<(usize, SockAddr)> {
self.recv_from_with_flags(buf, 0)
}
/// Identical to [`recv_from`] but allows for specification of arbitrary
/// flags to the underlying `recvfrom` call.
///
/// [`recv_from`]: Socket::recv_from
pub fn recv_from_with_flags(
&self,
buf: &mut [MaybeUninit<u8>],
flags: c_int,
) -> io::Result<(usize, SockAddr)> {
sys::recv_from(self.as_raw(), buf, flags)
}
/// Receives data from the socket. Returns the amount of bytes read, the
/// [`RecvFlags`] and the remote address from the data is coming. Unlike
/// [`recv_from`] this allows passing multiple buffers.
#[doc = man_links!(recvmsg(2))]
///
/// [`recv_from`]: Socket::recv_from
///
/// # Safety
///
/// `recv_from_vectored` makes the same safety guarantees regarding `bufs`
/// as [`recv_vectored`].
///
/// [`recv_vectored`]: Socket::recv_vectored
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
pub fn recv_from_vectored(
&self,
bufs: &mut [MaybeUninitSlice<'_>],
) -> io::Result<(usize, RecvFlags, SockAddr)> {
self.recv_from_vectored_with_flags(bufs, 0)
}
/// Identical to [`recv_from_vectored`] but allows for specification of
/// arbitrary flags to the underlying `recvmsg`/`WSARecvFrom` call.
///
/// [`recv_from_vectored`]: Socket::recv_from_vectored
///
/// # Safety
///
/// `recv_from_vectored` makes the same safety guarantees regarding `bufs`
/// as [`recv_vectored`].
///
/// [`recv_vectored`]: Socket::recv_vectored
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
pub fn recv_from_vectored_with_flags(
&self,
bufs: &mut [MaybeUninitSlice<'_>],
flags: c_int,
) -> io::Result<(usize, RecvFlags, SockAddr)> {
sys::recv_from_vectored(self.as_raw(), bufs, flags)
}
/// Receives data from the socket, without removing it from the queue.
///
/// Successive calls return the same data. This is accomplished by passing
/// `MSG_PEEK` as a flag to the underlying `recvfrom` system call.
///
/// On success, returns the number of bytes peeked and the address from
/// whence the data came.
///
/// # Safety
///
/// `peek_from` makes the same safety guarantees regarding the `buf`fer as
/// [`recv`].
///
/// # Note: Datagram Sockets
/// For datagram sockets, the behavior of this method when `buf` is smaller than
/// the datagram at the head of the receive queue differs between Windows and
/// Unix-like platforms (Linux, macOS, BSDs, etc: colloquially termed "*nix").
///
/// On *nix platforms, the datagram is truncated to the length of `buf`.
///
/// On Windows, an error corresponding to `WSAEMSGSIZE` will be returned.
///
/// For consistency between platforms, be sure to provide a sufficiently large buffer to avoid
/// truncation; the exact size required depends on the underlying protocol.
///
/// If you just want to know the sender of the data, try [`peek_sender`].
///
/// [`recv`]: Socket::recv
/// [`peek_sender`]: Socket::peek_sender
pub fn peek_from(&self, buf: &mut [MaybeUninit<u8>]) -> io::Result<(usize, SockAddr)> {
self.recv_from_with_flags(buf, sys::MSG_PEEK)
}
/// Retrieve the sender for the data at the head of the receive queue.
///
/// This is equivalent to calling [`peek_from`] with a zero-sized buffer,
/// but suppresses the `WSAEMSGSIZE` error on Windows.
///
/// [`peek_from`]: Socket::peek_from
pub fn peek_sender(&self) -> io::Result<SockAddr> {
sys::peek_sender(self.as_raw())
}
/// Receive a message from a socket using a message structure.
///
/// This is not supported on Windows as calling `WSARecvMsg` (the `recvmsg`
/// equivalent) is not straight forward on Windows. See
/// <https://github.com/microsoft/Windows-classic-samples/blob/7cbd99ac1d2b4a0beffbaba29ea63d024ceff700/Samples/Win7Samples/netds/winsock/recvmsg/rmmc.cpp>
/// for an example (in C++).
#[doc = man_links!(recvmsg(2))]
#[cfg(all(unix, not(any(target_os = "redox", target_os = "horizon"))))]
pub fn recvmsg(&self, msg: &mut MsgHdrMut<'_, '_, '_>, flags: sys::c_int) -> io::Result<usize> {
sys::recvmsg(self.as_raw(), msg, flags)
}
/// Sends data on the socket to a connected peer.
///
/// This is typically used on TCP sockets or datagram sockets which have
/// been connected.
///
/// On success returns the number of bytes that were sent.
#[doc = man_links!(send(2))]
pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
self.send_with_flags(buf, 0)
}
/// Identical to [`send`] but allows for specification of arbitrary flags to the underlying
/// `send` call.
///
/// [`send`]: Socket::send
pub fn send_with_flags(&self, buf: &[u8], flags: c_int) -> io::Result<usize> {
sys::send(self.as_raw(), buf, flags)
}
/// Send data to the connected peer. Returns the amount of bytes written.
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
pub fn send_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
self.send_vectored_with_flags(bufs, 0)
}
/// Identical to [`send_vectored`] but allows for specification of arbitrary
/// flags to the underlying `sendmsg`/`WSASend` call.
#[doc = man_links!(sendmsg(2))]
///
/// [`send_vectored`]: Socket::send_vectored
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
pub fn send_vectored_with_flags(
&self,
bufs: &[IoSlice<'_>],
flags: c_int,
) -> io::Result<usize> {
sys::send_vectored(self.as_raw(), bufs, 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`]: Socket::send
/// [`out_of_band_inline`]: Socket::out_of_band_inline
#[cfg_attr(target_os = "redox", allow(rustdoc::broken_intra_doc_links))]
#[cfg(not(target_os = "wasi"))]
pub fn send_out_of_band(&self, buf: &[u8]) -> io::Result<usize> {
self.send_with_flags(buf, sys::MSG_OOB)
}
/// Sends data on the socket to the given address. On success, returns the
/// number of bytes written.
///
/// This is typically used on UDP or datagram-oriented sockets.
#[doc = man_links!(sendto(2))]
pub fn send_to(&self, buf: &[u8], addr: &SockAddr) -> io::Result<usize> {
self.send_to_with_flags(buf, addr, 0)
}
/// Identical to [`send_to`] but allows for specification of arbitrary flags
/// to the underlying `sendto` call.
///
/// [`send_to`]: Socket::send_to
pub fn send_to_with_flags(
&self,
buf: &[u8],
addr: &SockAddr,
flags: c_int,
) -> io::Result<usize> {
sys::send_to(self.as_raw(), buf, addr, flags)
}
/// Send data to a peer listening on `addr`. Returns the amount of bytes
/// written.
#[doc = man_links!(sendmsg(2))]
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
pub fn send_to_vectored(&self, bufs: &[IoSlice<'_>], addr: &SockAddr) -> io::Result<usize> {
self.send_to_vectored_with_flags(bufs, addr, 0)
}
/// Identical to [`send_to_vectored`] but allows for specification of
/// arbitrary flags to the underlying `sendmsg`/`WSASendTo` call.
///
/// [`send_to_vectored`]: Socket::send_to_vectored
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
pub fn send_to_vectored_with_flags(
&self,
bufs: &[IoSlice<'_>],
addr: &SockAddr,
flags: c_int,
) -> io::Result<usize> {
sys::send_to_vectored(self.as_raw(), bufs, addr, flags)
}
/// Send a message on a socket using a message structure.
#[doc = man_links!(sendmsg(2))]
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
pub fn sendmsg(&self, msg: &MsgHdr<'_, '_, '_>, flags: sys::c_int) -> io::Result<usize> {
sys::sendmsg(self.as_raw(), msg, flags)
}
}
/// Set `SOCK_CLOEXEC` and `NO_HANDLE_INHERIT` on the `ty`pe on platforms that
/// support it.
#[inline(always)]
const fn set_common_type(ty: Type) -> Type {
// On platforms that support it set `SOCK_CLOEXEC`.
#[cfg(any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "hurd",
target_os = "illumos",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
target_os = "cygwin",
))]
let ty = ty._cloexec();
// On windows set `NO_HANDLE_INHERIT`.
#[cfg(windows)]
let ty = ty._no_inherit();
ty
}
/// Set `FD_CLOEXEC` and `NOSIGPIPE` on the `socket` for platforms that need it.
///
/// Sockets created via `accept` should use `set_common_accept_flags` instead.
fn set_common_flags(socket: Socket) -> io::Result<Socket> {
// On platforms that don't have `SOCK_CLOEXEC` use `FD_CLOEXEC`.
#[cfg(all(
unix,
not(any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "hurd",
target_os = "illumos",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
target_os = "espidf",
target_os = "vita",
target_os = "cygwin",
))
))]
socket._set_cloexec(true)?;
// On Apple platforms set `NOSIGPIPE`.
#[cfg(any(
target_os = "ios",
target_os = "visionos",
target_os = "macos",
target_os = "tvos",
target_os = "watchos",
))]
socket._set_nosigpipe(true)?;
Ok(socket)
}
/// Set `FD_CLOEXEC` on the `socket` for platforms that need it.
///
/// Unlike `set_common_flags` we don't set `NOSIGPIPE` as that is inherited from
/// the listener. Furthermore, attempts to set it on a unix socket domain
/// results in an error.
#[cfg(not(any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "illumos",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
target_os = "cygwin",
)))]
fn set_common_accept_flags(socket: Socket) -> io::Result<Socket> {
// On platforms that don't have `SOCK_CLOEXEC` use `FD_CLOEXEC`.
#[cfg(all(
unix,
not(any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "hurd",
target_os = "illumos",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
target_os = "espidf",
target_os = "vita",
target_os = "cygwin",
))
))]
socket._set_cloexec(true)?;
Ok(socket)
}
/// A local interface specified by its index or an address assigned to it.
///
/// `Index(0)` and `Address(Ipv4Addr::UNSPECIFIED)` are equivalent and indicate
/// that an appropriate interface should be selected by the system.
#[cfg(not(any(
target_os = "haiku",
target_os = "illumos",
target_os = "netbsd",
target_os = "redox",
target_os = "solaris",
target_os = "wasi",
)))]
#[derive(Debug, Copy, Clone)]
pub enum InterfaceIndexOrAddress {
/// An interface index.
Index(u32),
/// An address assigned to an interface.
Address(Ipv4Addr),
}
/// 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 {
/// Get the value of the `SO_BROADCAST` option for this socket.
///
/// For more information about this option, see [`set_broadcast`].
///
/// [`set_broadcast`]: Socket::set_broadcast
pub fn broadcast(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_BROADCAST)
.map(|broadcast| broadcast != 0)
}
}
/// Set the value of the `SO_BROADCAST` option for this socket.
///
/// When enabled, this socket is allowed to send packets to a broadcast
/// address.
pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::SOL_SOCKET,
sys::SO_BROADCAST,
broadcast as c_int,
)
}
}
/// Get the value of the `SO_ERROR` option on this socket.
///
/// This will retrieve the stored error in the underlying socket, clearing
/// the field in the process. This can be useful for checking errors between
/// calls.
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
match unsafe { getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_ERROR) } {
Ok(0) => Ok(None),
Ok(errno) => Ok(Some(io::Error::from_raw_os_error(errno))),
Err(err) => Err(err),
}
}
/// Get the value of the `SO_KEEPALIVE` option on this socket.
///
/// For more information about this option, see [`set_keepalive`].
///
/// [`set_keepalive`]: Socket::set_keepalive
pub fn keepalive(&self) -> io::Result<bool> {
unsafe {
getsockopt::<Bool>(self.as_raw(), sys::SOL_SOCKET, sys::SO_KEEPALIVE)
.map(|keepalive| keepalive != false as Bool)
}
}
/// Set value for the `SO_KEEPALIVE` option on this socket.
///
/// Enable sending of keep-alive messages on connection-oriented sockets.
pub fn set_keepalive(&self, keepalive: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::SOL_SOCKET,
sys::SO_KEEPALIVE,
keepalive as c_int,
)
}
}
/// Get the value of the `SO_LINGER` option on this socket.
///
/// For more information about this option, see [`set_linger`].
///
/// [`set_linger`]: Socket::set_linger
pub fn linger(&self) -> io::Result<Option<Duration>> {
unsafe {
getsockopt::<sys::linger>(self.as_raw(), sys::SOL_SOCKET, sys::SO_LINGER)
.map(from_linger)
}
}
/// Set value for the `SO_LINGER` option on this socket.
///
/// If `linger` is not `None`, a close(2) or shutdown(2) will not return
/// until all queued messages for the socket have been successfully sent or
/// the linger timeout has been reached. Otherwise, the call returns
/// immediately and the closing is done in the background. When the socket
/// is closed as part of exit(2), it always lingers in the background.
///
/// # Notes
///
/// On most OSs the duration only has a precision of seconds and will be
/// silently truncated.
///
/// On Apple platforms (e.g. macOS, iOS, etc) this uses `SO_LINGER_SEC`.
pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
let linger = into_linger(linger);
unsafe { setsockopt(self.as_raw(), sys::SOL_SOCKET, sys::SO_LINGER, linger) }
}
/// Get value for the `SO_OOBINLINE` option on this socket.
///
/// For more information about this option, see [`set_out_of_band_inline`].
///
/// [`set_out_of_band_inline`]: Socket::set_out_of_band_inline
#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
pub fn out_of_band_inline(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_OOBINLINE)
.map(|oob_inline| oob_inline != 0)
}
}
/// Set value for the `SO_OOBINLINE` option on this socket.
///
/// If this option is enabled, out-of-band data is directly placed into the
/// receive data stream. Otherwise, out-of-band data is passed only when the
/// `MSG_OOB` flag is set during receiving. As per RFC6093, TCP sockets
/// using the Urgent mechanism are encouraged to set this flag.
#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
pub fn set_out_of_band_inline(&self, oob_inline: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::SOL_SOCKET,
sys::SO_OOBINLINE,
oob_inline as c_int,
)
}
}
/// Get value for the `SO_PASSCRED` option on this socket.
///
/// For more information about this option, see [`set_passcred`].
///
/// [`set_passcred`]: Socket::set_passcred
#[cfg(any(target_os = "linux", target_os = "cygwin"))]
pub fn passcred(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_PASSCRED)
.map(|passcred| passcred != 0)
}
}
/// Set value for the `SO_PASSCRED` option on this socket.
///
/// If this option is enabled, enables the receiving of the `SCM_CREDENTIALS`
/// control messages.
#[cfg(any(target_os = "linux", target_os = "cygwin"))]
pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::SOL_SOCKET,
sys::SO_PASSCRED,
passcred as c_int,
)
}
}
/// Get value for the `SO_PRIORITY` option on this socket.
///
/// For more information about this option, see [`set_priority`].
///
/// [`set_priority`]: Socket::set_priority
#[cfg(all(
feature = "all",
any(target_os = "linux", target_os = "android", target_os = "fuchsia")
))]
pub fn priority(&self) -> io::Result<u32> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_PRIORITY)
.map(|prio| prio as u32)
}
}
/// Set value for the `SO_PRIORITY` option on this socket.
///
/// Packets with a higher priority may be processed earlier depending on the selected device
/// queueing discipline.
#[cfg(all(
feature = "all",
any(target_os = "linux", target_os = "android", target_os = "fuchsia")
))]
pub fn set_priority(&self, priority: u32) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::SOL_SOCKET,
sys::SO_PRIORITY,
priority as c_int,
)
}
}
/// Get value for the `SO_RCVBUF` option on this socket.
///
/// For more information about this option, see [`set_recv_buffer_size`].
///
/// [`set_recv_buffer_size`]: Socket::set_recv_buffer_size
pub fn recv_buffer_size(&self) -> io::Result<usize> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_RCVBUF)
.map(|size| size as usize)
}
}
/// Set value for the `SO_RCVBUF` option on this socket.
///
/// Changes the size of the operating system's receive buffer associated
/// with the socket.
pub fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::SOL_SOCKET,
sys::SO_RCVBUF,
size as c_int,
)
}
}
/// Get value for the `SO_RCVTIMEO` option on this socket.
///
/// If the returned timeout is `None`, then `read` and `recv` calls will
/// block indefinitely.
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
sys::timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_RCVTIMEO)
}
/// Set value for the `SO_RCVTIMEO` option on this socket.
///
/// If `timeout` is `None`, then `read` and `recv` calls will block
/// indefinitely.
pub fn set_read_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
sys::set_timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_RCVTIMEO, duration)
}
/// Get the value of the `SO_REUSEADDR` option on this socket.
///
/// For more information about this option, see [`set_reuse_address`].
///
/// [`set_reuse_address`]: Socket::set_reuse_address
pub fn reuse_address(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_REUSEADDR)
.map(|reuse| reuse != 0)
}
}
/// Set value for the `SO_REUSEADDR` option on this socket.
///
/// 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.
pub fn set_reuse_address(&self, reuse: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::SOL_SOCKET,
sys::SO_REUSEADDR,
reuse as c_int,
)
}
}
/// Get the value of the `SO_SNDBUF` option on this socket.
///
/// For more information about this option, see [`set_send_buffer_size`].
///
/// [`set_send_buffer_size`]: Socket::set_send_buffer_size
pub fn send_buffer_size(&self) -> io::Result<usize> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_SNDBUF)
.map(|size| size as usize)
}
}
/// Set value for the `SO_SNDBUF` option on this socket.
///
/// Changes the size of the operating system's send buffer associated with
/// the socket.
pub fn set_send_buffer_size(&self, size: usize) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::SOL_SOCKET,
sys::SO_SNDBUF,
size as c_int,
)
}
}
/// Get value for the `SO_SNDTIMEO` option on this socket.
///
/// If the returned timeout is `None`, then `write` and `send` calls will
/// block indefinitely.
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
sys::timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_SNDTIMEO)
}
/// Set value for the `SO_SNDTIMEO` option on this socket.
///
/// If `timeout` is `None`, then `write` and `send` calls will block
/// indefinitely.
pub fn set_write_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
sys::set_timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_SNDTIMEO, duration)
}
}
const fn from_linger(linger: sys::linger) -> Option<Duration> {
if linger.l_onoff == 0 {
None
} else {
Some(Duration::from_secs(linger.l_linger as u64))
}
}
const fn into_linger(duration: Option<Duration>) -> sys::linger {
match duration {
Some(duration) => sys::linger {
l_onoff: 1,
l_linger: duration.as_secs() as _,
},
None => sys::linger {
l_onoff: 0,
l_linger: 0,
},
}
}
/// Socket options for IPv4 sockets, get/set using `IPPROTO_IP` or `SOL_IP`.
///
/// Additional documentation can be found in documentation of the OS.
/// * Linux: <https://man7.org/linux/man-pages/man7/ip.7.html>
/// * Windows: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options>
impl Socket {
/// Get the value of the `IP_HDRINCL` option on this socket.
///
/// For more information about this option, see [`set_header_included_v4`].
///
/// [`set_header_included_v4`]: Socket::set_header_included_v4
#[cfg(all(
feature = "all",
not(any(
target_os = "redox",
target_os = "espidf",
target_os = "wasi",
target_os = "horizon"
))
))]
pub fn header_included_v4(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_HDRINCL)
.map(|included| included != 0)
}
}
/// Set the value of the `IP_HDRINCL` option on this socket.
///
/// If enabled, the user supplies an IP header in front of the user data.
/// Valid only for [`SOCK_RAW`] sockets; see [raw(7)] for more information.
/// When this flag is enabled, the values set by `IP_OPTIONS`, [`IP_TTL`],
/// and [`IP_TOS`] are ignored.
///
/// [`SOCK_RAW`]: Type::RAW
/// [raw(7)]: https://man7.org/linux/man-pages/man7/raw.7.html
/// [`IP_TTL`]: Socket::set_ttl_v4
/// [`IP_TOS`]: Socket::set_tos_v4
#[cfg_attr(
any(target_os = "fuchsia", target_os = "illumos", target_os = "solaris"),
allow(rustdoc::broken_intra_doc_links)
)]
#[cfg(all(
feature = "all",
not(any(
target_os = "redox",
target_os = "espidf",
target_os = "wasi",
target_os = "horizon"
))
))]
pub fn set_header_included_v4(&self, included: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IP,
sys::IP_HDRINCL,
included as c_int,
)
}
}
/// Get the value of the `IP_TRANSPARENT` option on this socket.
///
/// For more information about this option, see [`set_ip_transparent_v4`].
///
/// [`set_ip_transparent_v4`]: Socket::set_ip_transparent_v4
#[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
pub fn ip_transparent_v4(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, libc::IP_TRANSPARENT)
.map(|transparent| transparent != 0)
}
}
/// Set the value of the `IP_TRANSPARENT` option on this socket.
///
/// Setting this boolean option enables transparent proxying
/// on this socket. This socket option allows the calling
/// application to bind to a nonlocal IP address and operate
/// both as a client and a server with the foreign address as
/// the local endpoint. NOTE: this requires that routing be
/// set up in a way that packets going to the foreign address
/// are routed through the TProxy box (i.e., the system
/// hosting the application that employs the IP_TRANSPARENT
/// socket option). Enabling this socket option requires
/// superuser privileges (the `CAP_NET_ADMIN` capability).
///
/// TProxy redirection with the iptables TPROXY target also
/// requires that this option be set on the redirected socket.
#[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
pub fn set_ip_transparent_v4(&self, transparent: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IP,
libc::IP_TRANSPARENT,
transparent as c_int,
)
}
}
/// Join a multicast group using `IP_ADD_MEMBERSHIP` option on this socket.
///
/// This function specifies a new multicast group for this socket to join.
/// The address must be a valid multicast address, and `interface` is the
/// address of the local interface with which the system should join the
/// multicast group. If it's [`Ipv4Addr::UNSPECIFIED`] (`INADDR_ANY`) then
/// an appropriate interface is chosen by the system.
pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
let mreq = sys::IpMreq {
imr_multiaddr: sys::to_in_addr(multiaddr),
imr_interface: sys::to_in_addr(interface),
};
unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_ADD_MEMBERSHIP, mreq) }
}
/// Leave a multicast group using `IP_DROP_MEMBERSHIP` option on this socket.
///
/// For more information about this option, see [`join_multicast_v4`].
///
/// [`join_multicast_v4`]: Socket::join_multicast_v4
pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
let mreq = sys::IpMreq {
imr_multiaddr: sys::to_in_addr(multiaddr),
imr_interface: sys::to_in_addr(interface),
};
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IP,
sys::IP_DROP_MEMBERSHIP,
mreq,
)
}
}
/// Join a multicast group using `IP_ADD_MEMBERSHIP` option on this socket.
///
/// This function specifies a new multicast group for this socket to join.
/// The address must be a valid multicast address, and `interface` specifies
/// the local interface with which the system should join the multicast
/// group. See [`InterfaceIndexOrAddress`].
#[cfg(not(any(
target_os = "aix",
target_os = "haiku",
target_os = "illumos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox",
target_os = "solaris",
target_os = "nto",
target_os = "espidf",
target_os = "vita",
target_os = "cygwin",
target_os = "wasi",
target_os = "horizon"
)))]
pub fn join_multicast_v4_n(
&self,
multiaddr: &Ipv4Addr,
interface: &InterfaceIndexOrAddress,
) -> io::Result<()> {
let mreqn = sys::to_mreqn(multiaddr, interface);
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IP,
sys::IP_ADD_MEMBERSHIP,
mreqn,
)
}
}
/// Leave a multicast group using `IP_DROP_MEMBERSHIP` option on this socket.
///
/// For more information about this option, see [`join_multicast_v4_n`].
///
/// [`join_multicast_v4_n`]: Socket::join_multicast_v4_n
#[cfg(not(any(
target_os = "aix",
target_os = "haiku",
target_os = "illumos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox",
target_os = "solaris",
target_os = "nto",
target_os = "espidf",
target_os = "vita",
target_os = "cygwin",
target_os = "wasi",
target_os = "horizon"
)))]
pub fn leave_multicast_v4_n(
&self,
multiaddr: &Ipv4Addr,
interface: &InterfaceIndexOrAddress,
) -> io::Result<()> {
let mreqn = sys::to_mreqn(multiaddr, interface);
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IP,
sys::IP_DROP_MEMBERSHIP,
mreqn,
)
}
}
/// Join a multicast SSM channel using `IP_ADD_SOURCE_MEMBERSHIP` option on this socket.
///
/// This function specifies a new multicast channel for this socket to join.
/// The group must be a valid SSM group address, the source must be the address of the sender
/// and `interface` is the address of the local interface with which the system should join the
/// multicast group. If it's [`Ipv4Addr::UNSPECIFIED`] (`INADDR_ANY`) then
/// an appropriate interface is chosen by the system.
#[cfg(not(any(
target_os = "dragonfly",
target_os = "haiku",
target_os = "hurd",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox",
target_os = "fuchsia",
target_os = "nto",
target_os = "espidf",
target_os = "vita",
target_os = "wasi",
target_os = "horizon"
)))]
pub fn join_ssm_v4(
&self,
source: &Ipv4Addr,
group: &Ipv4Addr,
interface: &Ipv4Addr,
) -> io::Result<()> {
let mreqs = sys::IpMreqSource {
imr_multiaddr: sys::to_in_addr(group),
imr_interface: sys::to_in_addr(interface),
imr_sourceaddr: sys::to_in_addr(source),
};
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IP,
sys::IP_ADD_SOURCE_MEMBERSHIP,
mreqs,
)
}
}
/// Leave a multicast group using `IP_DROP_SOURCE_MEMBERSHIP` option on this socket.
///
/// For more information about this option, see [`join_ssm_v4`].
///
/// [`join_ssm_v4`]: Socket::join_ssm_v4
#[cfg(not(any(
target_os = "dragonfly",
target_os = "haiku",
target_os = "hurd",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox",
target_os = "fuchsia",
target_os = "nto",
target_os = "espidf",
target_os = "vita",
target_os = "wasi",
target_os = "horizon"
)))]
pub fn leave_ssm_v4(
&self,
source: &Ipv4Addr,
group: &Ipv4Addr,
interface: &Ipv4Addr,
) -> io::Result<()> {
let mreqs = sys::IpMreqSource {
imr_multiaddr: sys::to_in_addr(group),
imr_interface: sys::to_in_addr(interface),
imr_sourceaddr: sys::to_in_addr(source),
};
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IP,
sys::IP_DROP_SOURCE_MEMBERSHIP,
mreqs,
)
}
}
/// Get the value of the `IP_MULTICAST_ALL` option for this socket.
///
/// For more information about this option, see [`set_multicast_all_v4`].
///
/// [`set_multicast_all_v4`]: Socket::set_multicast_all_v4
#[cfg(all(feature = "all", target_os = "linux"))]
pub fn multicast_all_v4(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, libc::IP_MULTICAST_ALL)
.map(|all| all != 0)
}
}
/// Set the value of the `IP_MULTICAST_ALL` option for this socket.
///
/// This option can be used to modify the delivery policy of
/// multicast messages. The argument is a boolean
/// (defaults to true). If set to true, the socket will receive
/// messages from all the groups that have been joined
/// globally on the whole system. Otherwise, it will deliver
/// messages only from the groups that have been explicitly
/// joined (for example via the `IP_ADD_MEMBERSHIP` option) on
/// this particular socket.
#[cfg(all(feature = "all", target_os = "linux"))]
pub fn set_multicast_all_v4(&self, all: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IP,
libc::IP_MULTICAST_ALL,
all as c_int,
)
}
}
/// Get the value of the `IP_MULTICAST_IF` option for this socket.
///
/// For more information about this option, see [`set_multicast_if_v4`].
///
/// [`set_multicast_if_v4`]: Socket::set_multicast_if_v4
#[cfg(not(target_os = "wasi"))]
pub fn multicast_if_v4(&self) -> io::Result<Ipv4Addr> {
unsafe {
getsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_IF).map(sys::from_in_addr)
}
}
/// Set the value of the `IP_MULTICAST_IF` option for this socket.
///
/// Specifies the interface to use for routing multicast packets.
#[cfg(not(target_os = "wasi"))]
pub fn set_multicast_if_v4(&self, interface: &Ipv4Addr) -> io::Result<()> {
let interface = sys::to_in_addr(interface);
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IP,
sys::IP_MULTICAST_IF,
interface,
)
}
}
/// Get the value of the `IP_MULTICAST_LOOP` option for this socket.
///
/// For more information about this option, see [`set_multicast_loop_v4`].
///
/// [`set_multicast_loop_v4`]: Socket::set_multicast_loop_v4
pub fn multicast_loop_v4(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_LOOP)
.map(|loop_v4| loop_v4 != 0)
}
}
/// Set the value of the `IP_MULTICAST_LOOP` option for this socket.
///
/// If enabled, multicast packets will be looped back to the local socket.
/// Note that this may not have any affect on IPv6 sockets.
pub fn set_multicast_loop_v4(&self, loop_v4: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IP,
sys::IP_MULTICAST_LOOP,
loop_v4 as c_int,
)
}
}
/// Get the value of the `IP_MULTICAST_TTL` option for this socket.
///
/// For more information about this option, see [`set_multicast_ttl_v4`].
///
/// [`set_multicast_ttl_v4`]: Socket::set_multicast_ttl_v4
pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_TTL)
.map(|ttl| ttl as u32)
}
}
/// Set the value of the `IP_MULTICAST_TTL` option for this socket.
///
/// Indicates the time-to-live value of outgoing multicast packets for
/// this socket. The default value is 1 which means that multicast packets
/// don't leave the local network unless explicitly requested.
///
/// Note that this may not have any affect on IPv6 sockets.
pub fn set_multicast_ttl_v4(&self, ttl: u32) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IP,
sys::IP_MULTICAST_TTL,
ttl as c_int,
)
}
}
/// Get the value of the `IP_TTL` option for this socket.
///
/// For more information about this option, see [`set_ttl_v4`].
///
/// [`set_ttl_v4`]: Socket::set_ttl_v4
pub fn ttl_v4(&self) -> io::Result<u32> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_TTL).map(|ttl| ttl as u32)
}
}
/// Set the value of the `IP_TTL` option for this socket.
///
/// This value sets the time-to-live field that is used in every packet sent
/// from this socket.
pub fn set_ttl_v4(&self, ttl: u32) -> io::Result<()> {
unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_TTL, ttl as c_int) }
}
/// Set the value of the `IP_TOS` option for this socket.
///
/// This value sets the type-of-service field that is used in every packet
/// sent from this socket.
///
/// NOTE: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options>
/// documents that not all versions of windows support `IP_TOS`.
#[cfg(not(any(
target_os = "fuchsia",
target_os = "redox",
target_os = "solaris",
target_os = "illumos",
target_os = "haiku",
target_os = "wasi",
)))]
pub fn set_tos_v4(&self, tos: u32) -> io::Result<()> {
unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_TOS, tos as c_int) }
}
/// Get the value of the `IP_TOS` option for this socket.
///
/// For more information about this option, see [`set_tos_v4`].
///
/// NOTE: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options>
/// documents that not all versions of windows support `IP_TOS`.
///
/// [`set_tos_v4`]: Socket::set_tos_v4
#[cfg(not(any(
target_os = "fuchsia",
target_os = "redox",
target_os = "solaris",
target_os = "illumos",
target_os = "haiku",
target_os = "wasi",
)))]
pub fn tos_v4(&self) -> io::Result<u32> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_TOS).map(|tos| tos as u32)
}
}
/// Set the value of the `IP_RECVTOS` option for this socket.
///
/// If enabled, the `IP_TOS` ancillary message is passed with
/// incoming packets. It contains a byte which specifies the
/// Type of Service/Precedence field of the packet header.
#[cfg(not(any(
target_os = "aix",
target_os = "dragonfly",
target_os = "fuchsia",
target_os = "hurd",
target_os = "illumos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox",
target_os = "solaris",
target_os = "haiku",
target_os = "nto",
target_os = "espidf",
target_os = "vita",
target_os = "cygwin",
target_os = "wasi",
target_os = "horizon"
)))]
pub fn set_recv_tos_v4(&self, recv_tos: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IP,
sys::IP_RECVTOS,
recv_tos as c_int,
)
}
}
/// Get the value of the `IP_RECVTOS` option for this socket.
///
/// For more information about this option, see [`set_recv_tos_v4`].
///
/// [`set_recv_tos_v4`]: Socket::set_recv_tos_v4
#[cfg(not(any(
target_os = "aix",
target_os = "dragonfly",
target_os = "fuchsia",
target_os = "hurd",
target_os = "illumos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox",
target_os = "solaris",
target_os = "haiku",
target_os = "nto",
target_os = "espidf",
target_os = "vita",
target_os = "cygwin",
target_os = "wasi",
target_os = "horizon"
)))]
pub fn recv_tos_v4(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_RECVTOS)
.map(|recv_tos| recv_tos > 0)
}
}
/// Get the value for the `SO_ORIGINAL_DST` option on this socket.
#[cfg(all(
feature = "all",
any(
target_os = "android",
target_os = "fuchsia",
target_os = "linux",
target_os = "windows",
)
))]
pub fn original_dst_v4(&self) -> io::Result<SockAddr> {
sys::original_dst_v4(self.as_raw())
}
}
/// Socket options for IPv6 sockets, get/set using `IPPROTO_IPV6` or `SOL_IPV6`.
///
/// Additional documentation can be found in documentation of the OS.
/// * Linux: <https://man7.org/linux/man-pages/man7/ipv6.7.html>
/// * Windows: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ipv6-socket-options>
impl Socket {
/// Get the value of the `IP_HDRINCL` option on this socket.
///
/// For more information about this option, see [`set_header_included_v6`].
///
/// [`set_header_included_v6`]: Socket::set_header_included_v6
#[cfg(all(
feature = "all",
not(any(
target_os = "redox",
target_os = "espidf",
target_os = "openbsd",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "netbsd",
target_os = "wasi",
target_os = "horizon"
))
))]
pub fn header_included_v6(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IP_HDRINCL)
.map(|included| included != 0)
}
}
/// Set the value of the `IP_HDRINCL` option on this socket.
///
/// If enabled, the user supplies an IP header in front of the user data.
/// Valid only for [`SOCK_RAW`] sockets; see [raw(7)] for more information.
/// When this flag is enabled, the values set by `IP_OPTIONS` are ignored.
///
/// [`SOCK_RAW`]: Type::RAW
/// [raw(7)]: https://man7.org/linux/man-pages/man7/raw.7.html
#[cfg_attr(
any(target_os = "fuchsia", target_os = "illumos", target_os = "solaris"),
allow(rustdoc::broken_intra_doc_links)
)]
#[cfg(all(
feature = "all",
not(any(
target_os = "redox",
target_os = "espidf",
target_os = "openbsd",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "netbsd",
target_os = "wasi",
target_os = "horizon"
))
))]
pub fn set_header_included_v6(&self, included: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IPV6,
#[cfg(target_os = "linux")]
sys::IPV6_HDRINCL,
#[cfg(not(target_os = "linux"))]
sys::IP_HDRINCL,
included as c_int,
)
}
}
/// Get the value of the `IPV6_TRANSPARENT` option on this socket.
///
/// For more information about this option, see [`set_ip_transparent_v6`].
///
/// [`set_ip_transparent_v6`]: Socket::set_ip_transparent_v6
#[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
pub fn ip_transparent_v6(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, libc::IPV6_TRANSPARENT)
.map(|transparent| transparent != 0)
}
}
/// Set the value of the `IPV6_TRANSPARENT` option on this socket.
///
/// Setting this boolean option enables transparent proxying
/// on this socket. This socket option allows the calling
/// application to bind to a nonlocal IP address and operate
/// both as a client and a server with the foreign address as
/// the local endpoint. NOTE: this requires that routing be
/// set up in a way that packets going to the foreign address
/// are routed through the TProxy box (i.e., the system
/// hosting the application that employs the IPV6_TRANSPARENT
/// socket option). Enabling this socket option requires
/// superuser privileges (the `CAP_NET_ADMIN` capability).
///
/// TProxy redirection with the iptables TPROXY target also
/// requires that this option be set on the redirected socket.
#[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
pub fn set_ip_transparent_v6(&self, transparent: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IPV6,
libc::IPV6_TRANSPARENT,
transparent as c_int,
)
}
}
/// Join a multicast group using `IPV6_ADD_MEMBERSHIP` option on this socket.
///
/// Some OSs use `IPV6_JOIN_GROUP` for this option.
///
/// This function specifies a new multicast group for this socket to join.
/// The address must be a valid multicast address, and `interface` is the
/// index of the interface to join/leave (or 0 to indicate any interface).
#[cfg(not(target_os = "nto"))]
pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
let mreq = sys::Ipv6Mreq {
ipv6mr_multiaddr: sys::to_in6_addr(multiaddr),
// NOTE: some OSs use `c_int`, others use `c_uint`.
ipv6mr_interface: interface as _,
};
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IPV6,
sys::IPV6_ADD_MEMBERSHIP,
mreq,
)
}
}
/// Leave a multicast group using `IPV6_DROP_MEMBERSHIP` option on this socket.
///
/// Some OSs use `IPV6_LEAVE_GROUP` for this option.
///
/// For more information about this option, see [`join_multicast_v6`].
///
/// [`join_multicast_v6`]: Socket::join_multicast_v6
#[cfg(not(target_os = "nto"))]
pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
let mreq = sys::Ipv6Mreq {
ipv6mr_multiaddr: sys::to_in6_addr(multiaddr),
// NOTE: some OSs use `c_int`, others use `c_uint`.
ipv6mr_interface: interface as _,
};
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IPV6,
sys::IPV6_DROP_MEMBERSHIP,
mreq,
)
}
}
/// Get the value of the `IPV6_MULTICAST_HOPS` option for this socket
///
/// For more information about this option, see [`set_multicast_hops_v6`].
///
/// [`set_multicast_hops_v6`]: Socket::set_multicast_hops_v6
#[cfg(not(target_os = "wasi"))]
pub fn multicast_hops_v6(&self) -> io::Result<u32> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_HOPS)
.map(|hops| hops as u32)
}
}
/// Set the value of the `IPV6_MULTICAST_HOPS` option for this socket
///
/// Indicates the number of "routers" multicast packets will transit for
/// this socket. The default value is 1 which means that multicast packets
/// don't leave the local network unless explicitly requested.
#[cfg(not(target_os = "wasi"))]
pub fn set_multicast_hops_v6(&self, hops: u32) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IPV6,
sys::IPV6_MULTICAST_HOPS,
hops as c_int,
)
}
}
/// Get the value of the `IPV6_MULTICAST_ALL` option for this socket.
///
/// For more information about this option, see [`set_multicast_all_v6`].
///
/// [`set_multicast_all_v6`]: Socket::set_multicast_all_v6
#[cfg(all(feature = "all", target_os = "linux"))]
pub fn multicast_all_v6(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, libc::IPV6_MULTICAST_ALL)
.map(|all| all != 0)
}
}
/// Set the value of the `IPV6_MULTICAST_ALL` option for this socket.
///
/// This option can be used to modify the delivery policy of
/// multicast messages. The argument is a boolean
/// (defaults to true). If set to true, the socket will receive
/// messages from all the groups that have been joined
/// globally on the whole system. Otherwise, it will deliver
/// messages only from the groups that have been explicitly
/// joined (for example via the `IPV6_ADD_MEMBERSHIP` option) on
/// this particular socket.
#[cfg(all(feature = "all", target_os = "linux"))]
pub fn set_multicast_all_v6(&self, all: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IPV6,
libc::IPV6_MULTICAST_ALL,
all as c_int,
)
}
}
/// Get the value of the `IPV6_MULTICAST_IF` option for this socket.
///
/// For more information about this option, see [`set_multicast_if_v6`].
///
/// [`set_multicast_if_v6`]: Socket::set_multicast_if_v6
#[cfg(not(target_os = "wasi"))]
pub fn multicast_if_v6(&self) -> io::Result<u32> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_IF)
.map(|interface| interface as u32)
}
}
/// Set the value of the `IPV6_MULTICAST_IF` option for this socket.
///
/// Specifies the interface to use for routing multicast packets. Unlike
/// ipv4, this is generally required in ipv6 contexts where network routing
/// prefixes may overlap.
#[cfg(not(target_os = "wasi"))]
pub fn set_multicast_if_v6(&self, interface: u32) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IPV6,
sys::IPV6_MULTICAST_IF,
interface as c_int,
)
}
}
/// Get the value of the `IPV6_MULTICAST_LOOP` option for this socket.
///
/// For more information about this option, see [`set_multicast_loop_v6`].
///
/// [`set_multicast_loop_v6`]: Socket::set_multicast_loop_v6
pub fn multicast_loop_v6(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_LOOP)
.map(|loop_v6| loop_v6 != 0)
}
}
/// Set the value of the `IPV6_MULTICAST_LOOP` option for this socket.
///
/// Controls whether this socket sees the multicast packets it sends itself.
/// Note that this may not have any affect on IPv4 sockets.
pub fn set_multicast_loop_v6(&self, loop_v6: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IPV6,
sys::IPV6_MULTICAST_LOOP,
loop_v6 as c_int,
)
}
}
/// Get the value of the `IPV6_UNICAST_HOPS` option for this socket.
///
/// Specifies the hop limit for ipv6 unicast packets
pub fn unicast_hops_v6(&self) -> io::Result<u32> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_UNICAST_HOPS)
.map(|hops| hops as u32)
}
}
/// Set the value for the `IPV6_UNICAST_HOPS` option on this socket.
///
/// Specifies the hop limit for ipv6 unicast packets
pub fn set_unicast_hops_v6(&self, hops: u32) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IPV6,
sys::IPV6_UNICAST_HOPS,
hops as c_int,
)
}
}
/// Get the value of the `IPV6_V6ONLY` option for this socket.
///
/// For more information about this option, see [`set_only_v6`].
///
/// [`set_only_v6`]: Socket::set_only_v6
pub fn only_v6(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_V6ONLY)
.map(|only_v6| only_v6 != 0)
}
}
/// Set the value for the `IPV6_V6ONLY` option on this socket.
///
/// If this is set to `true` then the socket is restricted to sending and
/// receiving IPv6 packets only. In this case two IPv4 and IPv6 applications
/// can bind the same port at the same time.
///
/// If this is set to `false` then the socket can be used to send and
/// receive packets from an IPv4-mapped IPv6 address.
pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IPV6,
sys::IPV6_V6ONLY,
only_v6 as c_int,
)
}
}
/// Get the value of the `IPV6_RECVTCLASS` option for this socket.
///
/// For more information about this option, see [`set_recv_tclass_v6`].
///
/// [`set_recv_tclass_v6`]: Socket::set_recv_tclass_v6
#[cfg(not(any(
target_os = "dragonfly",
target_os = "fuchsia",
target_os = "illumos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox",
target_os = "solaris",
target_os = "haiku",
target_os = "hurd",
target_os = "espidf",
target_os = "vita",
target_os = "wasi",
target_os = "horizon"
)))]
pub fn recv_tclass_v6(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_RECVTCLASS)
.map(|recv_tclass| recv_tclass > 0)
}
}
/// Set the value of the `IPV6_RECVTCLASS` option for this socket.
///
/// If enabled, the `IPV6_TCLASS` ancillary message is passed with incoming
/// packets. It contains a byte which specifies the traffic class field of
/// the packet header.
#[cfg(not(any(
target_os = "dragonfly",
target_os = "fuchsia",
target_os = "illumos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox",
target_os = "solaris",
target_os = "haiku",
target_os = "hurd",
target_os = "espidf",
target_os = "vita",
target_os = "wasi",
target_os = "horizon"
)))]
pub fn set_recv_tclass_v6(&self, recv_tclass: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IPV6,
sys::IPV6_RECVTCLASS,
recv_tclass as c_int,
)
}
}
/// Get the value of the `IPV6_RECVHOPLIMIT` option for this socket.
///
/// For more information about this option, see [`set_recv_hoplimit_v6`].
///
/// [`set_recv_hoplimit_v6`]: Socket::set_recv_hoplimit_v6
#[cfg(all(
feature = "all",
not(any(
windows,
target_os = "dragonfly",
target_os = "fuchsia",
target_os = "illumos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox",
target_os = "solaris",
target_os = "haiku",
target_os = "hurd",
target_os = "espidf",
target_os = "vita",
target_os = "cygwin",
target_os = "wasi",
target_os = "horizon"
))
))]
pub fn recv_hoplimit_v6(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_RECVHOPLIMIT)
.map(|recv_hoplimit| recv_hoplimit > 0)
}
}
/// Set the value of the `IPV6_RECVHOPLIMIT` option for this socket.
///
/// The received hop limit is returned as ancillary data by recvmsg()
/// only if the application has enabled the IPV6_RECVHOPLIMIT socket
/// option:
#[cfg(all(
feature = "all",
not(any(
windows,
target_os = "dragonfly",
target_os = "fuchsia",
target_os = "illumos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox",
target_os = "solaris",
target_os = "haiku",
target_os = "hurd",
target_os = "espidf",
target_os = "vita",
target_os = "cygwin",
target_os = "wasi",
target_os = "horizon"
))
))]
pub fn set_recv_hoplimit_v6(&self, recv_hoplimit: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IPV6,
sys::IPV6_RECVHOPLIMIT,
recv_hoplimit as c_int,
)
}
}
/// Get the value for the `IP6T_SO_ORIGINAL_DST` option on this socket.
#[cfg(all(
feature = "all",
any(target_os = "android", target_os = "linux", target_os = "windows")
))]
pub fn original_dst_v6(&self) -> io::Result<SockAddr> {
sys::original_dst_v6(self.as_raw())
}
}
/// Socket options for TCP sockets, get/set using `IPPROTO_TCP`.
///
/// Additional documentation can be found in documentation of the OS.
/// * Linux: <https://man7.org/linux/man-pages/man7/tcp.7.html>
/// * Windows: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-tcp-socket-options>
impl Socket {
/// Get the value of the `TCP_KEEPIDLE` option on this socket.
///
/// This returns the value of `TCP_KEEPALIVE` on macOS and iOS and `TCP_KEEPIDLE` on all other
/// supported Unix operating systems.
#[cfg(all(
feature = "all",
not(any(
windows,
target_os = "haiku",
target_os = "openbsd",
target_os = "vita"
))
))]
pub fn tcp_keepalive_time(&self) -> io::Result<Duration> {
sys::tcp_keepalive_time(self.as_raw())
}
/// Get the value of the `TCP_KEEPINTVL` option on this socket.
///
/// For more information about this option, see [`set_tcp_keepalive`].
///
/// [`set_tcp_keepalive`]: Socket::set_tcp_keepalive
#[cfg(all(
feature = "all",
any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "illumos",
target_os = "ios",
target_os = "visionos",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
target_os = "tvos",
target_os = "watchos",
target_os = "cygwin",
all(target_os = "wasi", not(target_env = "p1")),
)
))]
pub fn tcp_keepalive_interval(&self) -> io::Result<Duration> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_TCP, sys::TCP_KEEPINTVL)
.map(|secs| Duration::from_secs(secs as u64))
}
}
/// Get the value of the `TCP_KEEPCNT` option on this socket.
///
/// For more information about this option, see [`set_tcp_keepalive`].
///
/// [`set_tcp_keepalive`]: Socket::set_tcp_keepalive
#[cfg(all(
feature = "all",
any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "illumos",
target_os = "ios",
target_os = "visionos",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
target_os = "tvos",
target_os = "watchos",
target_os = "cygwin",
target_os = "windows",
all(target_os = "wasi", not(target_env = "p1")),
)
))]
pub fn tcp_keepalive_retries(&self) -> io::Result<u32> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_TCP, sys::TCP_KEEPCNT)
.map(|retries| retries as u32)
}
}
/// Set parameters configuring TCP keepalive probes for this socket.
///
/// The supported parameters depend on the operating system, and are
/// configured using the [`TcpKeepalive`] struct. At a minimum, all systems
/// support configuring the [keepalive time]: the time after which the OS
/// will start sending keepalive messages on an idle connection.
///
/// [keepalive time]: TcpKeepalive::with_time
///
/// # Notes
///
/// * This will enable `SO_KEEPALIVE` on this socket, if it is not already
/// enabled.
/// * On some platforms, such as Windows, any keepalive parameters *not*
/// configured by the `TcpKeepalive` struct passed to this function may be
/// overwritten with their default values. Therefore, this function should
/// either only be called once per socket, or the same parameters should
/// be passed every time it is called.
///
/// # Examples
///
/// ```
/// use std::time::Duration;
///
/// use socket2::{Socket, TcpKeepalive, Domain, Type};
///
/// # fn main() -> std::io::Result<()> {
/// let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?;
/// let keepalive = TcpKeepalive::new()
/// .with_time(Duration::from_secs(4));
/// // Depending on the target operating system, we may also be able to
/// // configure the keepalive probe interval and/or the number of
/// // retries here as well.
///
/// socket.set_tcp_keepalive(&keepalive)?;
/// # Ok(()) }
/// ```
///
pub fn set_tcp_keepalive(&self, params: &TcpKeepalive) -> io::Result<()> {
self.set_keepalive(true)?;
sys::set_tcp_keepalive(self.as_raw(), params)
}
/// Get the value of the `TCP_NODELAY` option on this socket.
///
/// For more information about this option, see [`set_tcp_nodelay`].
///
/// [`set_tcp_nodelay`]: Socket::set_tcp_nodelay
pub fn tcp_nodelay(&self) -> io::Result<bool> {
unsafe {
getsockopt::<Bool>(self.as_raw(), sys::IPPROTO_TCP, sys::TCP_NODELAY)
.map(|nodelay| nodelay != false as Bool)
}
}
/// Set the value of the `TCP_NODELAY` option on this socket.
///
/// If set, this option disables the Nagle algorithm. This means that
/// segments are always sent as soon as possible, even if there is only a
/// small amount of data. When not set, data is buffered until there is a
/// sufficient amount to send out, thereby avoiding the frequent sending of
/// small packets.
pub fn set_tcp_nodelay(&self, nodelay: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_TCP,
sys::TCP_NODELAY,
nodelay as c_int,
)
}
}
/// On Windows this invokes the `SIO_TCP_SET_ACK_FREQUENCY` IOCTL which
/// configures the number of TCP segments that must be received before
/// the delayed ACK timer is ignored.
#[cfg(all(feature = "all", windows))]
pub fn set_tcp_ack_frequency(&self, frequency: u8) -> io::Result<()> {
sys::set_tcp_ack_frequency(self.as_raw(), frequency)
}
}
impl Read for Socket {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
// Safety: the `recv` implementation promises not to write uninitialised
// bytes to the `buf`fer, so this casting is safe.
let buf = unsafe { &mut *(buf as *mut [u8] as *mut [MaybeUninit<u8>]) };
self.recv(buf)
}
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
// Safety: both `IoSliceMut` and `MaybeUninitSlice` promise to have the
// same layout, that of `iovec`/`WSABUF`. Furthermore, `recv_vectored`
// promises to not write uninitialised bytes to the `bufs` and pass it
// directly to the `recvmsg` system call, so this is safe.
let bufs = unsafe { &mut *(bufs as *mut [IoSliceMut<'_>] as *mut [MaybeUninitSlice<'_>]) };
self.recv_vectored(bufs).map(|(n, _)| n)
}
}
impl<'a> Read for &'a Socket {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
// Safety: see other `Read::read` impl.
let buf = unsafe { &mut *(buf as *mut [u8] as *mut [MaybeUninit<u8>]) };
self.recv(buf)
}
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
// Safety: see other `Read::read` impl.
let bufs = unsafe { &mut *(bufs as *mut [IoSliceMut<'_>] as *mut [MaybeUninitSlice<'_>]) };
self.recv_vectored(bufs).map(|(n, _)| n)
}
}
impl Write for Socket {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.send(buf)
}
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
self.send_vectored(bufs)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl<'a> Write for &'a Socket {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.send(buf)
}
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
self.send_vectored(bufs)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl fmt::Debug for Socket {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Socket")
.field("raw", &self.as_raw())
.field("local_addr", &self.local_addr().ok())
.field("peer_addr", &self.peer_addr().ok())
.finish()
}
}
from!(net::TcpStream, Socket);
from!(net::TcpListener, Socket);
from!(net::UdpSocket, Socket);
from!(Socket, net::TcpStream);
from!(Socket, net::TcpListener);
from!(Socket, net::UdpSocket);
================================================
FILE: src/sockref.rs
================================================
use std::fmt;
use std::marker::PhantomData;
use std::mem::ManuallyDrop;
use std::ops::Deref;
#[cfg(any(unix, all(target_os = "wasi", not(target_env = "p1"))))]
use std::os::fd::{AsFd, AsRawFd, FromRawFd};
#[cfg(windows)]
use std::os::windows::io::{AsRawSocket, AsSocket, FromRawSocket};
use crate::Socket;
/// A reference to a [`Socket`] that can be used to configure socket types other
/// than the `Socket` type itself.
///
/// This allows for example a [`TcpStream`], found in the standard library, to
/// be configured using all the additional methods found in the [`Socket`] API.
///
/// `SockRef` can be created from any socket type that implements [`AsFd`]
/// (Unix) or [`AsSocket`] (Windows) using the [`From`] implementation.
///
/// [`TcpStream`]: std::net::TcpStream
// Don't use intra-doc links because they won't build on every platform.
/// [`AsFd`]: https://doc.rust-lang.org/stable/std/os/fd/trait.AsFd.html
/// [`AsSocket`]: https://doc.rust-lang.org/stable/std/os/windows/io/trait.AsSocket.html
///
/// # Examples
///
/// Below is an example of converting a [`TcpStream`] into a [`SockRef`].
///
/// ```
/// use std::net::{TcpStream, SocketAddr};
///
/// use socket2::SockRef;
///
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// // Create `TcpStream` from the standard library.
/// let address: SocketAddr = "127.0.0.1:1234".parse()?;
/// # let b1 = std::sync::Arc::new(std::sync::Barrier::new(2));
/// # let b2 = b1.clone();
/// # let handle = std::thread::spawn(move || {
/// # let listener = std::net::TcpListener::bind(address).unwrap();
/// # b2.wait();
/// # let (stream, _) = listener.accept().unwrap();
/// # std::thread::sleep(std::time::Duration::from_millis(10));
/// # drop(stream);
/// # });
/// # b1.wait();
/// let stream = TcpStream::connect(address)?;
///
/// // Create a `SockRef`erence to the stream.
/// let socket_ref = SockRef::from(&stream);
/// // Use `Socket::set_tcp_nodelay` on the stream.
/// socket_ref.set_tcp_nodelay(true)?;
/// drop(socket_ref);
///
/// assert_eq!(stream.nodelay()?, true);
/// # handle.join().unwrap();
/// # Ok(())
/// # }
/// ```
pub struct SockRef<'s> {
/// Because this is a reference we don't own the `Socket`, however `Socket`
/// closes itself when dropped, so we use `ManuallyDrop` to prevent it from
/// closing itself.
socket: ManuallyDrop<Socket>,
/// Because we don't own the socket we need to ensure the socket remains
/// open while we have a "reference" to it, the lifetime `'s` ensures this.
_lifetime: PhantomData<&'s Socket>,
}
impl<'s> Deref for SockRef<'s> {
type Target = Socket;
fn deref(&self) -> &Self::Target {
&self.socket
}
}
/// On Windows, a corresponding `From<&impl AsSocket>` implementation exists.
#[cfg(any(unix, all(target_os = "wasi", not(target_env = "p1"))))]
impl<'s, S> From<&'s S> for SockRef<'s>
where
S: AsFd,
{
/// The caller must ensure `S` is actually a socket.
fn from(socket: &'s S) -> Self {
let fd = socket.as_fd().as_raw_fd();
assert!(fd >= 0);
SockRef {
socket: ManuallyDrop::new(unsafe { Socket::from_raw_fd(fd) }),
_lifetime: PhantomData,
}
}
}
/// On Unix, a corresponding `From<&impl AsFd>` implementation exists.
#[cfg(windows)]
impl<'s, S> From<&'s S> for SockRef<'s>
where
S: AsSocket,
{
/// See the `From<&impl AsFd>` implementation.
fn from(socket: &'s S) -> Self {
let socket = socket.as_socket().as_raw_socket();
assert!(socket != windows_sys::Win32::Networking::WinSock::INVALID_SOCKET as _);
SockRef {
socket: ManuallyDrop::new(unsafe { Socket::from_raw_socket(socket) }),
_lifetime: PhantomData,
}
}
}
impl fmt::Debug for SockRef<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SockRef")
.field("raw", &self.socket.as_raw())
.field("local_addr", &self.socket.local_addr().ok())
.field("peer_addr", &self.socket.peer_addr().ok())
.finish()
}
}
================================================
FILE: src/sys/unix.rs
================================================
// Copyright 2015 The Rust Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::cmp::min;
#[cfg(not(target_os = "wasi"))]
use std::ffi::OsStr;
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
use std::io::IoSlice;
use std::marker::PhantomData;
use std::mem::{self, size_of, MaybeUninit};
use std::net::Shutdown;
use std::net::{Ipv4Addr, Ipv6Addr};
#[cfg(all(
feature = "all",
any(
target_os = "ios",
target_os = "visionos",
target_os = "macos",
target_os = "tvos",
target_os = "watchos",
target_os = "illumos",
target_os = "solaris",
target_os = "linux",
target_os = "android",
)
))]
use std::num::NonZeroU32;
#[cfg(all(
feature = "all",
any(
target_os = "aix",
target_os = "android",
target_os = "freebsd",
target_os = "ios",
target_os = "visionos",
target_os = "linux",
target_os = "macos",
target_os = "tvos",
target_os = "watchos",
)
))]
use std::num::NonZeroUsize;
use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
#[cfg(not(target_os = "wasi"))]
use std::os::unix::ffi::OsStrExt;
#[cfg(all(feature = "all", unix))]
use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream};
#[cfg(not(target_os = "wasi"))]
use std::path::Path;
use std::ptr;
use std::time::{Duration, Instant};
use std::{io, slice};
#[cfg(not(any(
target_os = "ios",
target_os = "visionos",
target_os = "macos",
target_os = "tvos",
target_os = "watchos",
target_os = "cygwin",
)))]
use libc::ssize_t;
use libc::{in6_addr, in_addr};
#[cfg(not(target_os = "wasi"))]
use crate::SockAddrStorage;
use crate::{Domain, Protocol, SockAddr, TcpKeepalive, Type};
#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
use crate::{MsgHdr, MsgHdrMut, RecvFlags};
pub(crate) use std::ffi::c_int;
// Used in `Domain`.
#[cfg(not(target_os = "wasi"))]
pub(crate) use libc::AF_UNIX;
pub(crate) use libc::{AF_INET, AF_INET6};
// Used in `Type`.
#[cfg(all(feature = "all", target_os = "linux"))]
pub(crate) use libc::SOCK_DCCP;
#[cfg(all(
feature = "all",
not(any(
target_os = "redox",
target_os = "espidf",
target_os = "wasi",
target_os = "horizon"
))
))]
pub(crate) use libc::SOCK_RAW;
#[cfg(all(
feature = "all",
not(any(target_os = "espidf", target_os = "wasi", target_os = "horizon"))
))]
pub(crate) use libc::SOCK_SEQPACKET;
pub(crate) use libc::{SOCK_DGRAM, SOCK_STREAM};
// Used in `Protocol`.
#[cfg(all(feature = "all", target_os = "linux"))]
pub(crate) use libc::IPPROTO_DCCP;
#[cfg(target_os = "linux")]
pub(crate) use libc::IPPROTO_MPTCP;
#[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
pub(crate) use libc::IPPROTO_SCTP;
#[cfg(all(
feature = "all",
any(
target_os = "android",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "linux",
)
))]
pub(crate) use libc::IPPROTO_UDPLITE;
#[cfg(not(target_os = "wasi"))]
pub(crate) use libc::{IPPROTO_ICMP, IPPROTO_ICMPV6};
pub(crate) use libc::{IPPROTO_TCP, IPPROTO_UDP};
// Used in `SockAddr`.
#[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "openbsd")))]
pub(crate) use libc::IPPROTO_DIVERT;
pub(crate) use libc::{
sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t,
};
// Used in `RecvFlags`.
#[cfg(not(any(
target_os = "redox",
target_os = "espidf",
target_os = "wasi",
target_os = "horizon"
)))]
pub(crate) use libc::MSG_TRUNC;
#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
pub(crate) use libc::SO_OOBINLINE;
// Used in `Socket`.
#[cfg(not(target_os = "nto"))]
pub(crate) use libc::ipv6_mreq as Ipv6Mreq;
#[cfg(all(feature = "all", target_os = "linux"))]
pub(crate) use libc::IPV6_HDRINCL;
#[cfg(all(
feature = "all",
not(any(
target_os = "dragonfly",
target_os = "fuchsia",
target_os = "hurd",
target_os = "illumos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox",
target_os = "solaris",
target_os = "haiku",
target_os = "espidf",
target_os = "vita",
target_os = "wasi",
target_os = "cygwin",
target_os = "horizon"
))
))]
pub(crate) use libc::IPV6_RECVHOPLIMIT;
#[cfg(not(any(
target_os = "dragonfly",
target_os = "fuchsia",
target_os = "hurd",
target_os = "illumos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox",
target_os = "solaris",
target_os = "haiku",
target_os = "espidf",
target_os = "vita",
target_os = "wasi",
target_os = "horizon"
)))]
pub(crate) use libc::IPV6_RECVTCLASS;
#[cfg(all(
feature = "all",
not(any(
target_os = "redox",
target_os = "espidf",
target_os = "wasi",
target_os = "horizon"
))
))]
pub(crate) use libc::IP_HDRINCL;
#[cfg(not(any(
target_os = "aix",
target_os = "dragonfly",
target_os = "fuchsia",
target_os = "illumos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox",
target_os = "solaris",
target_os = "haiku",
target_os = "hurd",
target_os = "nto",
target_os = "espidf",
target_os = "vita",
target_os = "wasi",
target_os = "cygwin",
target_os = "horizon"
)))]
pub(crate) use libc::IP_RECVTOS;
#[cfg(not(any(
target_os = "fuchsia",
target_os = "redox",
target_os = "solaris",
target_os = "haiku",
target_os = "illumos",
target_os = "wasi",
)))]
pub(crate) use libc::IP_TOS;
#[cfg(not(any(
target_os = "ios",
target_os = "visionos",
target_os = "macos",
target_os = "tvos",
target_os = "watchos",
)))]
pub(crate) use libc::SO_LINGER;
#[cfg(any(
target_os = "ios",
target_os = "visionos",
target_os = "macos",
target_os = "tvos",
target_os = "watchos",
))]
pub(crate) use libc::SO_LINGER_SEC as SO_LINGER;
#[cfg(any(target_os = "linux", target_os = "cygwin"))]
pub(crate) use libc::SO_PASSCRED;
#[cfg(all(
feature = "all",
any(target_os = "linux", target_os = "android", target_os = "fuchsia")
))]
pub(crate) use libc::SO_PRIORITY;
pub(crate) use libc::{
ip_mreq as IpMreq, linger, IPPROTO_IP, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, IPV6_UNICAST_HOPS,
IPV6_V6ONLY, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_MULTICAST_LOOP, IP_MULTICAST_TTL,
IP_TTL, MSG_PEEK, SOL_SOCKET, SO_BROADCAST, SO_ERROR, SO_KEEPALIVE, SO_RCVBUF, SO_RCVTIMEO,
SO_REUSEADDR, SO_SNDBUF, SO_SNDTIMEO, SO_TYPE, TCP_NODELAY,
};
#[cfg(not(any(
target_os = "dragonfly",
target_os = "haiku",
target_os = "hurd",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox",
target_os = "fuchsia",
target_os = "nto",
target_os = "espidf",
target_os = "vita",
target_os = "wasi",
target_os = "horizon"
)))]
pub(crate) use libc::{
ip_mreq_source as IpMreqSource, IP_ADD_SOURCE_MEMBERSHIP, IP_DROP_SOURCE_MEMBERSHIP,
};
#[cfg(not(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "haiku",
target_os = "illumos",
target_os = "ios",
target_os = "visionos",
target_os = "macos",
target_os = "netbsd",
target_os = "nto",
target_os = "openbsd",
target_os = "solaris",
target_os = "tvos",
target_os = "watchos",
target_os = "wasi",
)))]
pub(crate) use libc::{IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP};
#[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "haiku",
target_os = "illumos",
target_os = "ios",
target_os = "visionos",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "solaris",
target_os = "tvos",
target_os = "watchos",
all(target_os = "wasi", not(target_env = "p1")),
))]
pub(crate) use libc::{
IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP, IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP,
};
#[cfg(not(target_os = "wasi"))]
pub(crate) use libc::{IPV6_MULTICAST_HOPS, IPV6_MULTICAST_IF, IP_MULTICAST_IF, MSG_OOB};
#[cfg(all(
feature = "all",
any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "illumos",
target_os = "ios",
target_os = "visionos",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
target_os = "tvos",
target_os = "watchos",
target_os = "cygwin",
all(target_os = "wasi", not(target_env = "p1")),
)
))]
pub(crate) use libc::{TCP_KEEPCNT, TCP_KEEPINTVL};
// See this type in the Windows file.
pub(crate) type Bool = c_int;
#[cfg(any(
target_os = "ios",
target_os = "visionos",
target_os = "macos",
all(target_os = "nto", any(target_env = "nto70", target_env = "nto71"),),
target_os = "tvos",
target_os = "watchos",
))]
use libc::TCP_KEEPALIVE as KEEPALIVE_TIME;
#[cfg(not(any(
target_os = "ha
gitextract_pvnieb04/
├── .github/
│ └── workflows/
│ └── main.yml
├── .gitignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── Makefile
├── README.md
├── src/
│ ├── lib.rs
│ ├── sockaddr.rs
│ ├── socket.rs
│ ├── sockref.rs
│ └── sys/
│ ├── unix.rs
│ └── windows.rs
└── tests/
├── data/
│ ├── hello_world.txt
│ └── lorem_ipsum.txt
└── socket.rs
SYMBOL INDEX (574 symbols across 7 files)
FILE: src/lib.rs
type Domain (line 218) | pub struct Domain(c_int);
constant IPV4 (line 222) | pub const IPV4: Domain = Domain(sys::AF_INET);
constant IPV6 (line 225) | pub const IPV6: Domain = Domain(sys::AF_INET6);
constant UNIX (line 229) | pub const UNIX: Domain = Domain(sys::AF_UNIX);
method for_address (line 232) | pub const fn for_address(address: SocketAddr) -> Domain {
method from (line 241) | fn from(d: c_int) -> Domain {
method from (line 247) | fn from(d: Domain) -> c_int {
type Type (line 262) | pub struct Type(c_int);
constant STREAM (line 268) | pub const STREAM: Type = Type(sys::SOCK_STREAM);
constant DGRAM (line 273) | pub const DGRAM: Type = Type(sys::SOCK_DGRAM);
constant DCCP (line 279) | pub const DCCP: Type = Type(sys::SOCK_DCCP);
constant SEQPACKET (line 286) | pub const SEQPACKET: Type = Type(sys::SOCK_SEQPACKET);
constant RAW (line 298) | pub const RAW: Type = Type(sys::SOCK_RAW);
method from (line 302) | fn from(t: c_int) -> Type {
method from (line 308) | fn from(t: Type) -> c_int {
type Protocol (line 321) | pub struct Protocol(c_int);
constant ICMPV4 (line 326) | pub const ICMPV4: Protocol = Protocol(sys::IPPROTO_ICMP);
constant ICMPV6 (line 330) | pub const ICMPV6: Protocol = Protocol(sys::IPPROTO_ICMPV6);
constant TCP (line 333) | pub const TCP: Protocol = Protocol(sys::IPPROTO_TCP);
constant UDP (line 336) | pub const UDP: Protocol = Protocol(sys::IPPROTO_UDP);
constant MPTCP (line 340) | pub const MPTCP: Protocol = Protocol(sys::IPPROTO_MPTCP);
constant DCCP (line 344) | pub const DCCP: Protocol = Protocol(sys::IPPROTO_DCCP);
constant SCTP (line 348) | pub const SCTP: Protocol = Protocol(sys::IPPROTO_SCTP);
constant UDPLITE (line 360) | pub const UDPLITE: Protocol = Protocol(sys::IPPROTO_UDPLITE);
constant DIVERT (line 364) | pub const DIVERT: Protocol = Protocol(sys::IPPROTO_DIVERT);
method from (line 368) | fn from(p: c_int) -> Protocol {
method from (line 374) | fn from(p: Protocol) -> c_int {
type RecvFlags (line 384) | pub struct RecvFlags(c_int);
method is_truncated (line 396) | pub const fn is_truncated(self) -> bool {
type MaybeUninitSlice (line 405) | pub struct MaybeUninitSlice<'a>(sys::MaybeUninitSlice<'a>);
function fmt (line 408) | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
function new (line 419) | pub fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> {
type Target (line 425) | type Target = [MaybeUninit<u8>];
method deref (line 427) | fn deref(&self) -> &[MaybeUninit<u8>] {
method deref_mut (line 433) | fn deref_mut(&mut self) -> &mut [MaybeUninit<u8>] {
type TcpKeepalive (line 442) | pub struct TcpKeepalive {
method new (line 475) | pub const fn new() -> TcpKeepalive {
method with_time (line 514) | pub const fn with_time(self, time: Duration) -> Self {
method with_interval (line 545) | pub const fn with_interval(self, interval: Duration) -> Self {
method with_retries (line 576) | pub const fn with_retries(self, retries: u32) -> Self {
type MsgHdr (line 590) | pub struct MsgHdr<'addr, 'bufs, 'control> {
function new (line 600) | pub fn new() -> MsgHdr<'addr, 'bufs, 'control> {
function with_addr (line 612) | pub fn with_addr(mut self, addr: &'addr SockAddr) -> Self {
function with_buffers (line 621) | pub fn with_buffers(mut self, bufs: &'bufs [IoSlice<'_>]) -> Self {
function with_control (line 631) | pub fn with_control(mut self, buf: &'control [u8]) -> Self {
function with_flags (line 640) | pub fn with_flags(mut self, flags: sys::c_int) -> Self {
function fmt (line 648) | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
type MsgHdrMut (line 662) | pub struct MsgHdrMut<'addr, 'bufs, 'control> {
function new (line 676) | pub fn new() -> MsgHdrMut<'addr, 'bufs, 'control> {
function with_addr (line 689) | pub fn with_addr(mut self, addr: &'addr mut SockAddr) -> Self {
function with_buffers (line 698) | pub fn with_buffers(mut self, bufs: &'bufs mut [MaybeUninitSlice<'_>]) -...
function with_control (line 707) | pub fn with_control(mut self, buf: &'control mut [MaybeUninit<u8>]) -> S...
function flags (line 713) | pub fn flags(&self) -> RecvFlags {
function control_len (line 722) | pub fn control_len(&self) -> usize {
function fmt (line 729) | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
FILE: src/sockaddr.rs
type socklen_t (line 18) | pub type socklen_t = crate::sys::socklen_t;
type sa_family_t (line 22) | pub type sa_family_t = crate::sys::sa_family_t;
type SockAddrStorage (line 32) | pub struct SockAddrStorage {
method zeroed (line 39) | pub fn zeroed() -> Self {
method size_of (line 46) | pub fn size_of(&self) -> socklen_t {
method view_as (line 73) | pub unsafe fn view_as<T>(&mut self) -> &mut T {
method fmt (line 82) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
type SockAddr (line 94) | pub struct SockAddr {
method new (line 145) | pub const unsafe fn new(storage: SockAddrStorage, len: socklen_t) -> S...
method try_init (line 197) | pub unsafe fn try_init<F, T>(init: F) -> io::Result<(T, SockAddr)>
method unix (line 219) | pub fn unix<P>(path: P) -> io::Result<SockAddr>
method set_length (line 232) | pub unsafe fn set_length(&mut self, length: socklen_t) {
method family (line 237) | pub const fn family(&self) -> sa_family_t {
method domain (line 242) | pub const fn domain(&self) -> Domain {
method len (line 247) | pub const fn len(&self) -> socklen_t {
method as_ptr (line 252) | pub const fn as_ptr(&self) -> *const SockAddrStorage {
method as_storage (line 257) | pub const fn as_storage(self) -> SockAddrStorage {
method is_ipv4 (line 264) | pub const fn is_ipv4(&self) -> bool {
method is_ipv6 (line 270) | pub const fn is_ipv6(&self) -> bool {
method is_unix (line 277) | pub fn is_unix(&self) -> bool {
method as_socket (line 283) | pub fn as_socket(&self) -> Option<SocketAddr> {
method as_socket_ipv4 (line 315) | pub fn as_socket_ipv4(&self) -> Option<SocketAddrV4> {
method as_socket_ipv6 (line 324) | pub fn as_socket_ipv6(&self) -> Option<SocketAddrV6> {
method as_bytes (line 332) | fn as_bytes(&self) -> &[u8] {
method from (line 341) | fn from(addr: SocketAddr) -> SockAddr {
method from (line 350) | fn from(addr: SocketAddrV4) -> SockAddr {
method from (line 387) | fn from(addr: SocketAddrV6) -> SockAddr {
method fmt (line 431) | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
method eq (line 456) | fn eq(&self, other: &Self) -> bool {
method hash (line 464) | fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
function ipv4 (line 474) | fn ipv4() {
function ipv6 (line 503) | fn ipv6() {
function ipv4_eq (line 532) | fn ipv4_eq() {
function ipv4_hash (line 546) | fn ipv4_hash() {
function ipv6_eq (line 560) | fn ipv6_eq() {
function ipv6_hash (line 574) | fn ipv6_hash() {
function ipv4_ipv6_eq (line 588) | fn ipv4_ipv6_eq() {
function ipv4_ipv6_hash (line 609) | fn ipv4_ipv6_hash() {
function test_eq (line 630) | fn test_eq(a0: SockAddr, a1: SockAddr, b: SockAddr) {
function test_hash (line 638) | fn test_hash(a0: SockAddr, a1: SockAddr, b: SockAddr) {
function calculate_hash (line 645) | fn calculate_hash(x: &SockAddr) -> u64 {
FILE: src/socket.rs
type Socket (line 75) | pub struct Socket {
method from_raw (line 86) | pub(crate) fn from_raw(raw: sys::RawSocket) -> Socket {
method as_raw (line 96) | pub(crate) fn as_raw(&self) -> sys::RawSocket {
method into_raw (line 100) | pub(crate) fn into_raw(self) -> sys::RawSocket {
method new (line 115) | pub fn new(domain: Domain, ty: Type, protocol: Option<Protocol>) -> io...
method new_raw (line 124) | pub fn new_raw(domain: Domain, ty: Type, protocol: Option<Protocol>) -...
method pair (line 137) | pub fn pair(
method pair_raw (line 153) | pub fn pair_raw(
method bind (line 168) | pub fn bind(&self, address: &SockAddr) -> io::Result<()> {
method connect (line 192) | pub fn connect(&self, address: &SockAddr) -> io::Result<()> {
method connect_timeout (line 215) | pub fn connect_timeout(&self, addr: &SockAddr, timeout: Duration) -> i...
method listen (line 240) | pub fn listen(&self, backlog: c_int) -> io::Result<()> {
method accept (line 259) | pub fn accept(&self) -> io::Result<(Socket, SockAddr)> {
method accept_raw (line 301) | pub fn accept_raw(&self) -> io::Result<(Socket, SockAddr)> {
method local_addr (line 317) | pub fn local_addr(&self) -> io::Result<SockAddr> {
method peer_addr (line 332) | pub fn peer_addr(&self) -> io::Result<SockAddr> {
method r#type (line 338) | pub fn r#type(&self) -> io::Result<Type> {
method try_clone (line 356) | pub fn try_clone(&self) -> io::Result<Socket> {
method nonblocking (line 372) | pub fn nonblocking(&self) -> io::Result<bool> {
method set_nonblocking (line 384) | pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
method shutdown (line 393) | pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
method recv (line 418) | pub fn recv(&self, buf: &mut [MaybeUninit<u8>]) -> io::Result<usize> {
method recv_out_of_band (line 431) | pub fn recv_out_of_band(&self, buf: &mut [MaybeUninit<u8>]) -> io::Res...
method recv_with_flags (line 439) | pub fn recv_with_flags(
method recv_vectored (line 474) | pub fn recv_vectored(
method recv_vectored_with_flags (line 493) | pub fn recv_vectored_with_flags(
method peek (line 514) | pub fn peek(&self, buf: &mut [MaybeUninit<u8>]) -> io::Result<usize> {
method recv_from (line 528) | pub fn recv_from(&self, buf: &mut [MaybeUninit<u8>]) -> io::Result<(us...
method recv_from_with_flags (line 536) | pub fn recv_from_with_flags(
method recv_from_vectored (line 558) | pub fn recv_from_vectored(
method recv_from_vectored_with_flags (line 577) | pub fn recv_from_vectored_with_flags(
method peek_from (line 614) | pub fn peek_from(&self, buf: &mut [MaybeUninit<u8>]) -> io::Result<(us...
method peek_sender (line 624) | pub fn peek_sender(&self) -> io::Result<SockAddr> {
method recvmsg (line 636) | pub fn recvmsg(&self, msg: &mut MsgHdrMut<'_, '_, '_>, flags: sys::c_i...
method send (line 647) | pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
method send_with_flags (line 655) | pub fn send_with_flags(&self, buf: &[u8], flags: c_int) -> io::Result<...
method send_vectored (line 661) | pub fn send_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
method send_vectored_with_flags (line 671) | pub fn send_vectored_with_flags(
method send_out_of_band (line 688) | pub fn send_out_of_band(&self, buf: &[u8]) -> io::Result<usize> {
method send_to (line 697) | pub fn send_to(&self, buf: &[u8], addr: &SockAddr) -> io::Result<usize> {
method send_to_with_flags (line 705) | pub fn send_to_with_flags(
method send_to_vectored (line 718) | pub fn send_to_vectored(&self, bufs: &[IoSlice<'_>], addr: &SockAddr) ...
method send_to_vectored_with_flags (line 727) | pub fn send_to_vectored_with_flags(
method sendmsg (line 739) | pub fn sendmsg(&self, msg: &MsgHdr<'_, '_, '_>, flags: sys::c_int) -> ...
method broadcast (line 878) | pub fn broadcast(&self) -> io::Result<bool> {
method set_broadcast (line 889) | pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> {
method take_error (line 905) | pub fn take_error(&self) -> io::Result<Option<io::Error>> {
method keepalive (line 918) | pub fn keepalive(&self) -> io::Result<bool> {
method set_keepalive (line 928) | pub fn set_keepalive(&self, keepalive: bool) -> io::Result<()> {
method linger (line 944) | pub fn linger(&self) -> io::Result<Option<Duration>> {
method set_linger (line 965) | pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
method out_of_band_inline (line 976) | pub fn out_of_band_inline(&self) -> io::Result<bool> {
method set_out_of_band_inline (line 990) | pub fn set_out_of_band_inline(&self, oob_inline: bool) -> io::Result<(...
method passcred (line 1007) | pub fn passcred(&self) -> io::Result<bool> {
method set_passcred (line 1019) | pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
method priority (line 1039) | pub fn priority(&self) -> io::Result<u32> {
method set_priority (line 1054) | pub fn set_priority(&self, priority: u32) -> io::Result<()> {
method recv_buffer_size (line 1070) | pub fn recv_buffer_size(&self) -> io::Result<usize> {
method set_recv_buffer_size (line 1081) | pub fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> {
method read_timeout (line 1096) | pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
method set_read_timeout (line 1104) | pub fn set_read_timeout(&self, duration: Option<Duration>) -> io::Resu...
method reuse_address (line 1113) | pub fn reuse_address(&self) -> io::Result<bool> {
method set_reuse_address (line 1125) | pub fn set_reuse_address(&self, reuse: bool) -> io::Result<()> {
method send_buffer_size (line 1141) | pub fn send_buffer_size(&self) -> io::Result<usize> {
method set_send_buffer_size (line 1152) | pub fn set_send_buffer_size(&self, size: usize) -> io::Result<()> {
method write_timeout (line 1167) | pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
method set_write_timeout (line 1175) | pub fn set_write_timeout(&self, duration: Option<Duration>) -> io::Res...
method header_included_v4 (line 1221) | pub fn header_included_v4(&self) -> io::Result<bool> {
method set_header_included_v4 (line 1252) | pub fn set_header_included_v4(&self, included: bool) -> io::Result<()> {
method ip_transparent_v4 (line 1269) | pub fn ip_transparent_v4(&self) -> io::Result<bool> {
method set_ip_transparent_v4 (line 1292) | pub fn set_ip_transparent_v4(&self, transparent: bool) -> io::Result<(...
method join_multicast_v4 (line 1310) | pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4...
method leave_multicast_v4 (line 1323) | pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv...
method join_multicast_v4_n (line 1359) | pub fn join_multicast_v4_n(
method leave_multicast_v4_n (line 1395) | pub fn leave_multicast_v4_n(
method join_ssm_v4 (line 1432) | pub fn join_ssm_v4(
method leave_ssm_v4 (line 1472) | pub fn leave_ssm_v4(
method multicast_all_v4 (line 1499) | pub fn multicast_all_v4(&self) -> io::Result<bool> {
method set_multicast_all_v4 (line 1517) | pub fn set_multicast_all_v4(&self, all: bool) -> io::Result<()> {
method multicast_if_v4 (line 1534) | pub fn multicast_if_v4(&self) -> io::Result<Ipv4Addr> {
method set_multicast_if_v4 (line 1544) | pub fn set_multicast_if_v4(&self, interface: &Ipv4Addr) -> io::Result<...
method multicast_loop_v4 (line 1561) | pub fn multicast_loop_v4(&self) -> io::Result<bool> {
method set_multicast_loop_v4 (line 1572) | pub fn set_multicast_loop_v4(&self, loop_v4: bool) -> io::Result<()> {
method multicast_ttl_v4 (line 1588) | pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
method set_multicast_ttl_v4 (line 1602) | pub fn set_multicast_ttl_v4(&self, ttl: u32) -> io::Result<()> {
method ttl_v4 (line 1618) | pub fn ttl_v4(&self) -> io::Result<u32> {
method set_ttl_v4 (line 1628) | pub fn set_ttl_v4(&self, ttl: u32) -> io::Result<()> {
method set_tos_v4 (line 1647) | pub fn set_tos_v4(&self, tos: u32) -> io::Result<()> {
method tos_v4 (line 1667) | pub fn tos_v4(&self) -> io::Result<u32> {
method set_recv_tos_v4 (line 1696) | pub fn set_recv_tos_v4(&self, recv_tos: bool) -> io::Result<()> {
method recv_tos_v4 (line 1730) | pub fn recv_tos_v4(&self) -> io::Result<bool> {
method original_dst_v4 (line 1747) | pub fn original_dst_v4(&self) -> io::Result<SockAddr> {
method header_included_v6 (line 1776) | pub fn header_included_v6(&self) -> io::Result<bool> {
method set_header_included_v6 (line 1808) | pub fn set_header_included_v6(&self, included: bool) -> io::Result<()> {
method ip_transparent_v6 (line 1828) | pub fn ip_transparent_v6(&self) -> io::Result<bool> {
method set_ip_transparent_v6 (line 1851) | pub fn set_ip_transparent_v6(&self, transparent: bool) -> io::Result<(...
method join_multicast_v6 (line 1870) | pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) ...
method leave_multicast_v6 (line 1894) | pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32)...
method multicast_hops_v6 (line 1916) | pub fn multicast_hops_v6(&self) -> io::Result<u32> {
method set_multicast_hops_v6 (line 1929) | pub fn set_multicast_hops_v6(&self, hops: u32) -> io::Result<()> {
method multicast_all_v6 (line 1946) | pub fn multicast_all_v6(&self) -> io::Result<bool> {
method set_multicast_all_v6 (line 1964) | pub fn set_multicast_all_v6(&self, all: bool) -> io::Result<()> {
method multicast_if_v6 (line 1981) | pub fn multicast_if_v6(&self) -> io::Result<u32> {
method set_multicast_if_v6 (line 1994) | pub fn set_multicast_if_v6(&self, interface: u32) -> io::Result<()> {
method multicast_loop_v6 (line 2010) | pub fn multicast_loop_v6(&self) -> io::Result<bool> {
method set_multicast_loop_v6 (line 2021) | pub fn set_multicast_loop_v6(&self, loop_v6: bool) -> io::Result<()> {
method unicast_hops_v6 (line 2035) | pub fn unicast_hops_v6(&self) -> io::Result<u32> {
method set_unicast_hops_v6 (line 2045) | pub fn set_unicast_hops_v6(&self, hops: u32) -> io::Result<()> {
method only_v6 (line 2061) | pub fn only_v6(&self) -> io::Result<bool> {
method set_only_v6 (line 2076) | pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
method recv_tclass_v6 (line 2107) | pub fn recv_tclass_v6(&self) -> io::Result<bool> {
method set_recv_tclass_v6 (line 2134) | pub fn set_recv_tclass_v6(&self, recv_tclass: bool) -> io::Result<()> {
method recv_hoplimit_v6 (line 2170) | pub fn recv_hoplimit_v6(&self) -> io::Result<bool> {
method set_recv_hoplimit_v6 (line 2201) | pub fn set_recv_hoplimit_v6(&self, recv_hoplimit: bool) -> io::Result<...
method original_dst_v6 (line 2217) | pub fn original_dst_v6(&self) -> io::Result<SockAddr> {
method tcp_keepalive_time (line 2241) | pub fn tcp_keepalive_time(&self) -> io::Result<Duration> {
method tcp_keepalive_interval (line 2269) | pub fn tcp_keepalive_interval(&self) -> io::Result<Duration> {
method tcp_keepalive_retries (line 2301) | pub fn tcp_keepalive_retries(&self) -> io::Result<u32> {
method set_tcp_keepalive (line 2346) | pub fn set_tcp_keepalive(&self, params: &TcpKeepalive) -> io::Result<(...
method tcp_nodelay (line 2356) | pub fn tcp_nodelay(&self) -> io::Result<bool> {
method set_tcp_nodelay (line 2370) | pub fn set_tcp_nodelay(&self, nodelay: bool) -> io::Result<()> {
method set_tcp_ack_frequency (line 2385) | pub fn set_tcp_ack_frequency(&self, frequency: u8) -> io::Result<()> {
method fmt (line 2455) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
function set_common_type (line 747) | const fn set_common_type(ty: Type) -> Type {
function set_common_flags (line 773) | fn set_common_flags(socket: Socket) -> io::Result<Socket> {
function set_common_accept_flags (line 823) | fn set_common_accept_flags(socket: Socket) -> io::Result<Socket> {
type InterfaceIndexOrAddress (line 860) | pub enum InterfaceIndexOrAddress {
function from_linger (line 1180) | const fn from_linger(linger: sys::linger) -> Option<Duration> {
function into_linger (line 1188) | const fn into_linger(duration: Option<Duration>) -> sys::linger {
method read (line 2391) | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
method read_vectored (line 2399) | fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<u...
method read (line 2410) | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
method read_vectored (line 2417) | fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<u...
method write (line 2425) | fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
method write_vectored (line 2430) | fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
method flush (line 2434) | fn flush(&mut self) -> io::Result<()> {
method write (line 2440) | fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
method write_vectored (line 2445) | fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
method flush (line 2449) | fn flush(&mut self) -> io::Result<()> {
FILE: src/sockref.rs
type SockRef (line 61) | pub struct SockRef<'s> {
type Target (line 72) | type Target = Socket;
method deref (line 74) | fn deref(&self) -> &Self::Target {
function from (line 86) | fn from(socket: &'s S) -> Self {
function from (line 103) | fn from(socket: &'s S) -> Self {
function fmt (line 114) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
FILE: src/sys/unix.rs
type Bool (line 321) | pub(crate) type Bool = c_int;
constant MAX_BUF_LEN (line 367) | const MAX_BUF_LEN: usize = ssize_t::MAX as usize;
constant MAX_BUF_LEN (line 385) | const MAX_BUF_LEN: usize = c_int::MAX as usize - 1;
constant TCP_CA_NAME_MAX (line 389) | const TCP_CA_NAME_MAX: usize = 16;
type IovLen (line 401) | type IovLen = usize;
type IovLen (line 432) | type IovLen = c_int;
constant PACKET (line 441) | pub const PACKET: Domain = Domain(libc::AF_PACKET);
constant VSOCK (line 445) | pub const VSOCK: Domain = Domain(libc::AF_VSOCK);
method nonblocking (line 479) | pub const fn nonblocking(self) -> Type {
method cloexec (line 501) | pub const fn cloexec(self) -> Type {
method _cloexec (line 519) | pub(crate) const fn _cloexec(self) -> Type {
method is_end_of_record (line 612) | pub const fn is_end_of_record(self) -> bool {
method is_out_of_band (line 622) | pub const fn is_out_of_band(self) -> bool {
method is_confirm (line 634) | pub const fn is_confirm(self) -> bool {
method is_dontroute (line 648) | pub const fn is_dontroute(self) -> bool {
method fmt (line 655) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
type MaybeUninitSlice (line 674) | pub struct MaybeUninitSlice<'a> {
function new (line 684) | pub(crate) fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> {
function as_slice (line 694) | pub(crate) fn as_slice(&self) -> &[MaybeUninit<u8>] {
function as_mut_slice (line 698) | pub(crate) fn as_mut_slice(&mut self) -> &mut [MaybeUninit<u8>] {
function offset_of_path (line 705) | pub(crate) fn offset_of_path(storage: &libc::sockaddr_un) -> usize {
function unix_sockaddr (line 713) | pub(crate) fn unix_sockaddr(path: &Path) -> io::Result<SockAddr> {
function set_msghdr_name (line 762) | pub(crate) fn set_msghdr_name(msg: &mut msghdr, name: &SockAddr) {
function set_msghdr_iov (line 769) | pub(crate) fn set_msghdr_iov(msg: &mut msghdr, ptr: *mut libc::iovec, le...
function set_msghdr_control (line 775) | pub(crate) fn set_msghdr_control(msg: &mut msghdr, ptr: *mut libc::c_voi...
function set_msghdr_flags (line 781) | pub(crate) fn set_msghdr_flags(msg: &mut msghdr, flags: c_int) {
function msghdr_flags (line 786) | pub(crate) fn msghdr_flags(msg: &msghdr) -> RecvFlags {
function msghdr_control_len (line 791) | pub(crate) fn msghdr_control_len(msg: &msghdr) -> usize {
method vsock (line 805) | pub fn vsock(cid: u32, port: u32) -> SockAddr {
method as_vsock_address (line 820) | pub fn as_vsock_address(&self) -> Option<(u32, u32)> {
method is_unnamed (line 836) | pub fn is_unnamed(&self) -> bool {
method as_sockaddr_un (line 852) | pub(crate) fn as_sockaddr_un(&self) -> Option<&libc::sockaddr_un> {
method path_len (line 864) | fn path_len(&self, storage: &libc::sockaddr_un) -> usize {
method path_bytes (line 872) | fn path_bytes(&self, storage: &libc::sockaddr_un, abstract_name: bool) -...
method as_unix (line 891) | pub fn as_unix(&self) -> Option<std::os::unix::net::SocketAddr> {
method as_pathname (line 900) | pub fn as_pathname(&self) -> Option<&Path> {
method as_abstract_namespace (line 914) | pub fn as_abstract_namespace(&self) -> Option<&[u8]> {
type Socket (line 929) | pub(crate) type Socket = std::os::fd::OwnedFd;
type RawSocket (line 930) | pub(crate) type RawSocket = c_int;
function socket_from_raw (line 932) | pub(crate) unsafe fn socket_from_raw(socket: RawSocket) -> Socket {
function socket_as_raw (line 936) | pub(crate) fn socket_as_raw(socket: &Socket) -> RawSocket {
function socket_into_raw (line 940) | pub(crate) fn socket_into_raw(socket: Socket) -> RawSocket {
function socket (line 944) | pub(crate) fn socket(family: c_int, ty: c_int, protocol: c_int) -> io::R...
function socketpair (line 949) | pub(crate) fn socketpair(family: c_int, ty: c_int, protocol: c_int) -> i...
function bind (line 954) | pub(crate) fn bind(fd: RawSocket, addr: &SockAddr) -> io::Result<()> {
function connect (line 958) | pub(crate) fn connect(fd: RawSocket, addr: &SockAddr) -> io::Result<()> {
function poll_connect (line 962) | pub(crate) fn poll_connect(socket: &crate::Socket, timeout: Duration) ->...
function listen (line 1004) | pub(crate) fn listen(fd: RawSocket, backlog: c_int) -> io::Result<()> {
function accept (line 1008) | pub(crate) fn accept(fd: RawSocket) -> io::Result<(RawSocket, SockAddr)> {
function getsockname (line 1013) | pub(crate) fn getsockname(fd: RawSocket) -> io::Result<SockAddr> {
function getpeername (line 1019) | pub(crate) fn getpeername(fd: RawSocket) -> io::Result<SockAddr> {
function try_clone (line 1026) | pub(crate) fn try_clone(fd: RawSocket) -> io::Result<RawSocket> {
function nonblocking (line 1035) | pub(crate) fn nonblocking(fd: RawSocket) -> io::Result<bool> {
function nonblocking (line 1041) | pub(crate) fn nonblocking(fd: RawSocket) -> io::Result<bool> {
function set_nonblocking (line 1048) | pub(crate) fn set_nonblocking(fd: RawSocket, nonblocking: bool) -> io::R...
function set_nonblocking (line 1057) | pub(crate) fn set_nonblocking(fd: RawSocket, nonblocking: bool) -> io::R...
function shutdown (line 1068) | pub(crate) fn shutdown(fd: RawSocket, how: Shutdown) -> io::Result<()> {
function recv (line 1077) | pub(crate) fn recv(fd: RawSocket, buf: &mut [MaybeUninit<u8>], flags: c_...
function recv_from (line 1087) | pub(crate) fn recv_from(
function peek_sender (line 1108) | pub(crate) fn peek_sender(fd: RawSocket) -> io::Result<SockAddr> {
function recv_vectored (line 1118) | pub(crate) fn recv_vectored(
function recv_from_vectored (line 1129) | pub(crate) fn recv_from_vectored(
function recvmsg (line 1151) | pub(crate) fn recvmsg(
function send (line 1159) | pub(crate) fn send(fd: RawSocket, buf: &[u8], flags: c_int) -> io::Resul...
function send_vectored (line 1170) | pub(crate) fn send_vectored(
function send_to (line 1179) | pub(crate) fn send_to(
function send_to_vectored (line 1197) | pub(crate) fn send_to_vectored(
function sendmsg (line 1208) | pub(crate) fn sendmsg(fd: RawSocket, msg: &MsgHdr<'_, '_, '_>, flags: c_...
function timeout_opt (line 1213) | pub(crate) fn timeout_opt(fd: RawSocket, opt: c_int, val: c_int) -> io::...
function from_timeval (line 1217) | const fn from_timeval(duration: libc::timeval) -> Option<Duration> {
function set_timeout_opt (line 1228) | pub(crate) fn set_timeout_opt(
function into_timeval (line 1238) | fn into_timeval(duration: Option<Duration>) -> libc::timeval {
function tcp_keepalive_time (line 1257) | pub(crate) fn tcp_keepalive_time(fd: RawSocket) -> io::Result<Duration> {
function set_tcp_keepalive (line 1265) | pub(crate) fn set_tcp_keepalive(fd: RawSocket, keepalive: &TcpKeepalive)...
function into_secs (line 1321) | fn into_secs(duration: Duration) -> c_int {
function fcntl_get (line 1327) | fn fcntl_get(fd: RawSocket, cmd: c_int) -> io::Result<c_int> {
function fcntl_add (line 1333) | fn fcntl_add(fd: RawSocket, get_cmd: c_int, set_cmd: c_int, flag: c_int)...
function fcntl_remove (line 1346) | fn fcntl_remove(fd: RawSocket, get_cmd: c_int, set_cmd: c_int, flag: c_i...
function getsockopt (line 1358) | pub(crate) unsafe fn getsockopt<T>(fd: RawSocket, opt: c_int, val: c_int...
function setsockopt (line 1376) | pub(crate) unsafe fn setsockopt<T>(
function to_in_addr (line 1393) | pub(crate) const fn to_in_addr(addr: &Ipv4Addr) -> in_addr {
function from_in_addr (line 1402) | pub(crate) fn from_in_addr(in_addr: in_addr) -> Ipv4Addr {
function to_in6_addr (line 1406) | pub(crate) const fn to_in6_addr(addr: &Ipv6Addr) -> in6_addr {
function from_in6_addr (line 1412) | pub(crate) fn from_in6_addr(addr: in6_addr) -> Ipv6Addr {
function to_mreqn (line 1431) | pub(crate) const fn to_mreqn(
function original_dst_v4 (line 1453) | pub(crate) fn original_dst_v4(fd: RawSocket) -> io::Result<SockAddr> {
function original_dst_v6 (line 1474) | pub(crate) fn original_dst_v6(fd: RawSocket) -> io::Result<SockAddr> {
function accept4 (line 1514) | pub fn accept4(&self, flags: c_int) -> io::Result<(crate::Socket, SockAd...
function _accept4 (line 1529) | pub(crate) fn _accept4(&self, flags: c_int) -> io::Result<(crate::Socket...
function set_cloexec (line 1557) | pub fn set_cloexec(&self, close_on_exec: bool) -> io::Result<()> {
function _set_cloexec (line 1562) | pub(crate) fn _set_cloexec(&self, close_on_exec: bool) -> io::Result<()> {
function set_no_peercred (line 1594) | pub fn set_no_peercred(&self) -> io::Result<()> {
function set_nosigpipe (line 1616) | pub fn set_nosigpipe(&self, nosigpipe: bool) -> io::Result<()> {
function _set_nosigpipe (line 1627) | pub(crate) fn _set_nosigpipe(&self, nosigpipe: bool) -> io::Result<()> {
function tcp_mss (line 1644) | pub fn tcp_mss(&self) -> io::Result<u32> {
function set_tcp_mss (line 1656) | pub fn set_tcp_mss(&self, mss: u32) -> io::Result<()> {
function is_listener (line 1680) | pub fn is_listener(&self) -> io::Result<bool> {
function domain (line 1699) | pub fn domain(&self) -> io::Result<Domain> {
function protocol (line 1714) | pub fn protocol(&self) -> io::Result<Option<Protocol>> {
function mark (line 1734) | pub fn mark(&self) -> io::Result<u32> {
function set_mark (line 1752) | pub fn set_mark(&self, mark: u32) -> io::Result<()> {
function tcp_cork (line 1772) | pub fn tcp_cork(&self) -> io::Result<bool> {
function set_tcp_cork (line 1789) | pub fn set_tcp_cork(&self, cork: bool) -> io::Result<()> {
function tcp_quickack (line 1814) | pub fn tcp_quickack(&self) -> io::Result<bool> {
function set_tcp_quickack (line 1836) | pub fn set_tcp_quickack(&self, quickack: bool) -> io::Result<()> {
function tcp_thin_linear_timeouts (line 1856) | pub fn tcp_thin_linear_timeouts(&self) -> io::Result<bool> {
function set_tcp_thin_linear_timeouts (line 1876) | pub fn set_tcp_thin_linear_timeouts(&self, timeouts: bool) -> io::Result...
function tcp_notsent_lowat (line 1893) | pub fn tcp_notsent_lowat(&self) -> io::Result<u32> {
function set_tcp_notsent_lowat (line 1905) | pub fn set_tcp_notsent_lowat(&self, lowat: u32) -> io::Result<()> {
function device (line 1923) | pub fn device(&self) -> io::Result<Option<Vec<u8>>> {
function bind_device (line 1955) | pub fn bind_device(&self, interface: Option<&[u8]>) -> io::Result<()> {
function set_fib (line 1975) | pub fn set_fib(&self, fib: u32) -> io::Result<()> {
function bind_device_by_index_v4 (line 2010) | pub fn bind_device_by_index_v4(&self, interface: Option<NonZeroU32>) -> ...
function bind_device_by_index_v6 (line 2061) | pub fn bind_device_by_index_v6(&self, interface: Option<NonZeroU32>) -> ...
function device_index_v4 (line 2107) | pub fn device_index_v4(&self) -> io::Result<Option<NonZeroU32>> {
function device_index_v6 (line 2147) | pub fn device_index_v6(&self) -> io::Result<Option<NonZeroU32>> {
function cpu_affinity (line 2175) | pub fn cpu_affinity(&self) -> io::Result<usize> {
function set_cpu_affinity (line 2186) | pub fn set_cpu_affinity(&self, cpu: usize) -> io::Result<()> {
function reuse_port (line 2211) | pub fn reuse_port(&self) -> io::Result<bool> {
function set_reuse_port (line 2232) | pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> {
function reuse_port_lb (line 2249) | pub fn reuse_port_lb(&self) -> io::Result<bool> {
function set_reuse_port_lb (line 2261) | pub fn set_reuse_port_lb(&self, reuse: bool) -> io::Result<()> {
function freebind_v4 (line 2281) | pub fn freebind_v4(&self) -> io::Result<bool> {
function set_freebind_v4 (line 2299) | pub fn set_freebind_v4(&self, freebind: bool) -> io::Result<()> {
function freebind_v6 (line 2318) | pub fn freebind_v6(&self) -> io::Result<bool> {
function set_freebind_v6 (line 2356) | pub fn set_freebind_v6(&self, freebind: bool) -> io::Result<()> {
function sendfile (line 2400) | pub fn sendfile<F>(
function _sendfile (line 2422) | fn _sendfile(
function _sendfile (line 2447) | fn _sendfile(
function _sendfile (line 2463) | fn _sendfile(
function _sendfile (line 2488) | fn _sendfile(
function set_tcp_user_timeout (line 2537) | pub fn set_tcp_user_timeout(&self, timeout: Option<Duration>) -> io::Res...
function tcp_user_timeout (line 2565) | pub fn tcp_user_timeout(&self) -> io::Result<Option<Duration>> {
function attach_filter (line 2585) | pub fn attach_filter(&self, filters: &[SockFilter]) -> io::Result<()> {
function detach_filter (line 2608) | pub fn detach_filter(&self) -> io::Result<()> {
function cookie (line 2619) | pub fn cookie(&self) -> io::Result<u64> {
function tclass_v6 (line 2642) | pub fn tclass_v6(&self) -> io::Result<u32> {
function set_tclass_v6 (line 2667) | pub fn set_tclass_v6(&self, tclass: u32) -> io::Result<()> {
function tcp_congestion (line 2684) | pub fn tcp_congestion(&self) -> io::Result<Vec<u8>> {
function set_tcp_congestion (line 2704) | pub fn set_tcp_congestion(&self, tcp_ca_name: &[u8]) -> io::Result<()> {
function set_dccp_service (line 2726) | pub fn set_dccp_service(&self, code: u32) -> io::Result<()> {
function dccp_service (line 2743) | pub fn dccp_service(&self) -> io::Result<u32> {
function set_dccp_ccid (line 2751) | pub fn set_dccp_ccid(&self, ccid: u8) -> io::Result<()> {
function dccp_tx_ccid (line 2761) | pub fn dccp_tx_ccid(&self) -> io::Result<u32> {
function dccp_xx_ccid (line 2771) | pub fn dccp_xx_ccid(&self) -> io::Result<u32> {
function set_dccp_server_timewait (line 2780) | pub fn set_dccp_server_timewait(&self, hold_timewait: bool) -> io::Resul...
function dccp_server_timewait (line 2797) | pub fn dccp_server_timewait(&self) -> io::Result<bool> {
function set_dccp_send_cscov (line 2815) | pub fn set_dccp_send_cscov(&self, level: u32) -> io::Result<()> {
function dccp_send_cscov (line 2832) | pub fn dccp_send_cscov(&self) -> io::Result<u32> {
function set_dccp_recv_cscov (line 2842) | pub fn set_dccp_recv_cscov(&self, level: u32) -> io::Result<()> {
function dccp_recv_cscov (line 2859) | pub fn dccp_recv_cscov(&self) -> io::Result<u32> {
function set_dccp_qpolicy_txqlen (line 2868) | pub fn set_dccp_qpolicy_txqlen(&self, length: u32) -> io::Result<()> {
function dccp_qpolicy_txqlen (line 2885) | pub fn dccp_qpolicy_txqlen(&self) -> io::Result<u32> {
function dccp_available_ccids (line 2905) | pub fn dccp_available_ccids<const N: usize>(&self) -> io::Result<CcidEnd...
function dccp_cur_mps (line 2923) | pub fn dccp_cur_mps(&self) -> io::Result<u32> {
function busy_poll (line 2937) | pub fn busy_poll(&self) -> io::Result<u32> {
function set_busy_poll (line 2945) | pub fn set_busy_poll(&self, busy_poll: u32) -> io::Result<()> {
type SockFilter (line 2964) | pub struct SockFilter {
method new (line 2974) | pub const fn new(code: u16, jt: u8, jf: u8, k: u32) -> SockFilter {
method fmt (line 2983) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
type CcidEndpoints (line 2993) | pub struct CcidEndpoints<const N: usize> {
type Target (line 3000) | type Target = [u8];
function deref (line 3002) | fn deref(&self) -> &[u8] {
method as_fd (line 3008) | fn as_fd(&self) -> BorrowedFd<'_> {
method as_raw_fd (line 3015) | fn as_raw_fd(&self) -> RawFd {
method from (line 3021) | fn from(sock: crate::Socket) -> OwnedFd {
method into_raw_fd (line 3028) | fn into_raw_fd(self) -> c_int {
function from (line 3034) | fn from(fd: OwnedFd) -> crate::Socket {
method from_raw_fd (line 3041) | unsafe fn from_raw_fd(fd: c_int) -> crate::Socket {
function in_addr_convertion (line 3060) | fn in_addr_convertion() {
function in6_addr_convertion (line 3076) | fn in6_addr_convertion() {
FILE: src/sys/windows.rs
type c_int (line 45) | pub(crate) type c_int = std::ffi::c_int;
constant MSG_TRUNC (line 51) | pub(crate) const MSG_TRUNC: c_int = 0x01;
constant AF_INET (line 54) | pub(crate) const AF_INET: c_int = windows_sys::Win32::Networking::WinSoc...
constant AF_INET6 (line 55) | pub(crate) const AF_INET6: c_int = windows_sys::Win32::Networking::WinSo...
constant AF_UNIX (line 56) | pub(crate) const AF_UNIX: c_int = windows_sys::Win32::Networking::WinSoc...
constant AF_UNSPEC (line 57) | pub(crate) const AF_UNSPEC: c_int = windows_sys::Win32::Networking::WinS...
constant SOCK_STREAM (line 59) | pub(crate) const SOCK_STREAM: c_int = windows_sys::Win32::Networking::Wi...
constant SOCK_DGRAM (line 60) | pub(crate) const SOCK_DGRAM: c_int = windows_sys::Win32::Networking::Win...
constant SOCK_RAW (line 61) | pub(crate) const SOCK_RAW: c_int = windows_sys::Win32::Networking::WinSo...
constant SOCK_RDM (line 62) | const SOCK_RDM: c_int = windows_sys::Win32::Networking::WinSock::SOCK_RD...
constant SOCK_SEQPACKET (line 63) | pub(crate) const SOCK_SEQPACKET: c_int =
type sa_family_t (line 78) | pub(crate) type sa_family_t = windows_sys::Win32::Networking::WinSock::A...
type socklen_t (line 80) | pub(crate) type socklen_t = windows_sys::Win32::Networking::WinSock::soc...
constant IPPROTO_IP (line 94) | pub(crate) const IPPROTO_IP: c_int = windows_sys::Win32::Networking::Win...
constant SOL_SOCKET (line 95) | pub(crate) const SOL_SOCKET: c_int = windows_sys::Win32::Networking::Win...
type Bool (line 103) | pub(crate) type Bool = bool;
constant MAX_BUF_LEN (line 106) | const MAX_BUF_LEN: usize = c_int::MAX as usize;
constant NO_INHERIT (line 133) | const NO_INHERIT: c_int = 1 << ((size_of::<c_int>() * 8) - 1);
constant REGISTERED_IO (line 135) | const REGISTERED_IO: c_int = 1 << ((size_of::<c_int>() * 8) - 2);
method no_inherit (line 139) | pub const fn no_inherit(self) -> Type {
method registered_io (line 145) | pub const fn registered_io(self) -> Type {
method _no_inherit (line 149) | pub(crate) const fn _no_inherit(self) -> Type {
method fmt (line 172) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
type MaybeUninitSlice (line 180) | pub struct MaybeUninitSlice<'a> {
function new (line 190) | pub fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> {
function as_slice (line 201) | pub fn as_slice(&self) -> &[MaybeUninit<u8>] {
function as_mut_slice (line 205) | pub fn as_mut_slice(&mut self) -> &mut [MaybeUninit<u8>] {
function set_msghdr_name (line 213) | pub(crate) fn set_msghdr_name(msg: &mut msghdr, name: &SockAddr) {
function set_msghdr_iov (line 218) | pub(crate) fn set_msghdr_iov(msg: &mut msghdr, ptr: *mut WSABUF, len: us...
function set_msghdr_control (line 223) | pub(crate) fn set_msghdr_control(msg: &mut msghdr, ptr: *mut u8, len: us...
function set_msghdr_flags (line 228) | pub(crate) fn set_msghdr_flags(msg: &mut msghdr, flags: c_int) {
function msghdr_flags (line 232) | pub(crate) fn msghdr_flags(msg: &msghdr) -> RecvFlags {
function msghdr_control_len (line 236) | pub(crate) fn msghdr_control_len(msg: &msghdr) -> usize {
function init (line 240) | fn init() {
type Socket (line 251) | pub(crate) type Socket = std::os::windows::io::OwnedSocket;
type RawSocket (line 252) | pub(crate) type RawSocket = windows_sys::Win32::Networking::WinSock::SOC...
function socket_from_raw (line 254) | pub(crate) unsafe fn socket_from_raw(socket: RawSocket) -> Socket {
function socket_as_raw (line 258) | pub(crate) fn socket_as_raw(socket: &Socket) -> RawSocket {
function socket_into_raw (line 262) | pub(crate) fn socket_into_raw(socket: Socket) -> RawSocket {
function socket (line 266) | pub(crate) fn socket(family: c_int, mut ty: c_int, protocol: c_int) -> i...
function bind (line 297) | pub(crate) fn bind(socket: RawSocket, addr: &SockAddr) -> io::Result<()> {
function connect (line 306) | pub(crate) fn connect(socket: RawSocket, addr: &SockAddr) -> io::Result<...
function poll_connect (line 315) | pub(crate) fn poll_connect(socket: &crate::Socket, timeout: Duration) ->...
function clamp (line 365) | fn clamp<T>(value: T, min: T, max: T) -> T
function listen (line 378) | pub(crate) fn listen(socket: RawSocket, backlog: c_int) -> io::Result<()> {
function accept (line 382) | pub(crate) fn accept(socket: RawSocket) -> io::Result<(RawSocket, SockAd...
function getsockname (line 395) | pub(crate) fn getsockname(socket: RawSocket) -> io::Result<SockAddr> {
function getpeername (line 409) | pub(crate) fn getpeername(socket: RawSocket) -> io::Result<SockAddr> {
function try_clone (line 423) | pub(crate) fn try_clone(socket: RawSocket) -> io::Result<RawSocket> {
function set_nonblocking (line 448) | pub(crate) fn set_nonblocking(socket: RawSocket, nonblocking: bool) -> i...
function shutdown (line 453) | pub(crate) fn shutdown(socket: RawSocket, how: Shutdown) -> io::Result<(...
function recv (line 462) | pub(crate) fn recv(
function recv_vectored (line 484) | pub(crate) fn recv_vectored(
function recv_from (line 514) | pub(crate) fn recv_from(
function peek_sender (line 543) | pub(crate) fn peek_sender(socket: RawSocket) -> io::Result<SockAddr> {
function recv_from_vectored (line 575) | pub(crate) fn recv_from_vectored(
function send (line 615) | pub(crate) fn send(socket: RawSocket, buf: &[u8], flags: c_int) -> io::R...
function send_vectored (line 629) | pub(crate) fn send_vectored(
function send_to (line 664) | pub(crate) fn send_to(
function send_to_vectored (line 685) | pub(crate) fn send_to_vectored(
function sendmsg (line 711) | pub(crate) fn sendmsg(
function timeout_opt (line 733) | pub(crate) fn timeout_opt(fd: RawSocket, lvl: c_int, name: i32) -> io::R...
function from_ms (line 737) | fn from_ms(duration: u32) -> Option<Duration> {
function set_timeout_opt (line 748) | pub(crate) fn set_timeout_opt(
function into_ms (line 758) | fn into_ms(duration: Option<Duration>) -> u32 {
function set_tcp_keepalive (line 771) | pub(crate) fn set_tcp_keepalive(socket: RawSocket, keepalive: &TcpKeepal...
function set_tcp_ack_frequency (line 808) | pub(crate) fn set_tcp_ack_frequency(socket: RawSocket, frequency: u8) ->...
function getsockopt (line 834) | pub(crate) unsafe fn getsockopt<T>(socket: RawSocket, level: c_int, optn...
function setsockopt (line 857) | pub(crate) unsafe fn setsockopt<T>(
function ioctlsocket (line 877) | fn ioctlsocket(socket: RawSocket, cmd: i32, payload: &mut u32) -> io::Re...
function to_in_addr (line 886) | pub(crate) fn to_in_addr(addr: &Ipv4Addr) -> IN_ADDR {
function from_in_addr (line 897) | pub(crate) fn from_in_addr(in_addr: IN_ADDR) -> Ipv4Addr {
function to_in6_addr (line 901) | pub(crate) fn to_in6_addr(addr: &Ipv6Addr) -> IN6_ADDR {
function from_in6_addr (line 909) | pub(crate) fn from_in6_addr(addr: IN6_ADDR) -> Ipv6Addr {
function to_mreqn (line 913) | pub(crate) fn to_mreqn(
function original_dst_v4 (line 940) | pub(crate) fn original_dst_v4(socket: RawSocket) -> io::Result<SockAddr> {
function original_dst_v6 (line 960) | pub(crate) fn original_dst_v6(socket: RawSocket) -> io::Result<SockAddr> {
function unix_sockaddr (line 980) | pub(crate) fn unix_sockaddr(path: &Path) -> io::Result<SockAddr> {
function set_no_inherit (line 1027) | pub fn set_no_inherit(&self, no_inherit: bool) -> io::Result<()> {
function _set_no_inherit (line 1031) | pub(crate) fn _set_no_inherit(&self, no_inherit: bool) -> io::Result<()> {
function protocol (line 1054) | pub fn protocol(&self) -> io::Result<Option<crate::Protocol>> {
method as_socket (line 1066) | fn as_socket(&self) -> BorrowedSocket<'_> {
method as_raw_socket (line 1073) | fn as_raw_socket(&self) -> StdRawSocket {
method from (line 1079) | fn from(sock: crate::Socket) -> OwnedSocket {
method into_raw_socket (line 1086) | fn into_raw_socket(self) -> StdRawSocket {
function from (line 1092) | fn from(fd: OwnedSocket) -> crate::Socket {
method from_raw_socket (line 1099) | unsafe fn from_raw_socket(socket: StdRawSocket) -> crate::Socket {
function in_addr_convertion (line 1105) | fn in_addr_convertion() {
function in6_addr_convertion (line 1121) | fn in6_addr_convertion() {
FILE: tests/socket.rs
function domain_for_address (line 65) | fn domain_for_address() {
function domain_fmt_debug (line 76) | fn domain_fmt_debug() {
function type_fmt_debug (line 100) | fn type_fmt_debug() {
function protocol_fmt_debug (line 121) | fn protocol_fmt_debug() {
function from_invalid_raw_fd_should_panic (line 150) | fn from_invalid_raw_fd_should_panic() {
function socket_address_unix (line 157) | fn socket_address_unix() {
function socket_address_unix_unnamed (line 178) | fn socket_address_unix_unnamed() {
function socket_address_unix_abstract_namespace (line 200) | fn socket_address_unix_abstract_namespace() {
function socket_address_vsock (line 216) | fn socket_address_vsock() {
function set_nonblocking (line 225) | fn set_nonblocking() {
function assert_common_flags (line 236) | fn assert_common_flags(socket: &Socket, expected: bool) {
function common_flags (line 259) | fn common_flags() {
function no_common_flags (line 274) | fn no_common_flags() {
function type_nonblocking (line 301) | fn type_nonblocking() {
function assert_nonblocking (line 310) | pub fn assert_nonblocking(socket: &Socket, want: bool) {
function assert_nonblocking (line 344) | pub fn assert_nonblocking(_: &Socket, _: bool) {
function set_cloexec (line 350) | fn set_cloexec() {
function type_cloexec (line 375) | fn type_cloexec() {
function assert_close_on_exec (line 384) | pub fn assert_close_on_exec<S>(socket: &S, want: bool)
function set_no_inherit (line 394) | fn set_no_inherit() {
function type_no_inherit (line 407) | fn type_no_inherit() {
function assert_flag_no_inherit (line 416) | pub fn assert_flag_no_inherit<S>(socket: &S, want: bool)
function type_registered_io (line 434) | fn type_registered_io() {
function assert_registered_io (line 443) | pub fn assert_registered_io<S>(socket: &S)
function set_nosigpipe (line 485) | fn set_nosigpipe() {
function assert_flag_no_sigpipe (line 505) | pub fn assert_flag_no_sigpipe<S>(socket: &S, want: bool)
constant DATA (line 528) | const DATA: &[u8] = b"hello world";
function connect_timeout_unrouteable (line 532) | fn connect_timeout_unrouteable() {
function connect_timeout_unbound (line 548) | fn connect_timeout_unbound() {
function connect_timeout_valid (line 568) | fn connect_timeout_valid() {
function pair (line 585) | fn pair() {
function unix_sockets_supported (line 595) | fn unix_sockets_supported() -> bool {
function unix (line 620) | fn unix() {
function unix_accept (line 653) | fn unix_accept() {
function vsock (line 679) | fn vsock() {
function out_of_band (line 701) | fn out_of_band() {
function udp_peek_sender (line 732) | fn udp_peek_sender() {
function send_recv_vectored (line 747) | fn send_recv_vectored() {
function send_from_recv_to_vectored (line 794) | fn send_from_recv_to_vectored() {
function sendmsg (line 847) | fn sendmsg() {
function recv_vectored_truncated (line 865) | fn recv_vectored_truncated() {
function recv_from_vectored_truncated (line 885) | fn recv_from_vectored_truncated() {
function udp_pair_unconnected (line 911) | fn udp_pair_unconnected() -> (Socket, Socket) {
function udp_pair_connected (line 939) | fn udp_pair_connected() -> (Socket, Socket) {
function tcp_keepalive (line 952) | fn tcp_keepalive() {
function device (line 1050) | fn device() {
function device (line 1094) | fn device() {
function device_v6 (line 1142) | fn device_v6() {
function sendfile (line 1191) | fn sendfile() {
function is_listener (line 1265) | fn is_listener() {
function domain (line 1284) | fn domain() {
function protocol (line 1306) | fn protocol() {
function r#type (line 1326) | fn r#type() {
function cpu_affinity (line 1358) | fn cpu_affinity() {
function niche (line 1370) | fn niche() {
function any_ipv4 (line 1376) | fn any_ipv4() -> SockAddr {
function assume_init (line 1383) | unsafe fn assume_init(buf: &[MaybeUninit<u8>]) -> &[u8] {
constant SET_BUF_SIZE (line 1434) | const SET_BUF_SIZE: usize = 4096;
constant GET_BUF_SIZE (line 1438) | const GET_BUF_SIZE: usize = SET_BUF_SIZE;
constant GET_BUF_SIZE (line 1440) | const GET_BUF_SIZE: usize = 2 * SET_BUF_SIZE;
function join_leave_multicast_v4_n (line 1655) | fn join_leave_multicast_v4_n() {
function join_leave_ssm_v4 (line 1687) | fn join_leave_ssm_v4() {
function header_included (line 1698) | fn header_included() {
function header_included_ipv6 (line 1733) | fn header_included_ipv6() {
function original_dst_v4 (line 1765) | fn original_dst_v4() {
function original_dst_v6 (line 1789) | fn original_dst_v6() {
function tcp_congestion (line 1814) | fn tcp_congestion() {
function tcp_set_ack_frequency (line 1866) | fn tcp_set_ack_frequency() {
function dccp (line 1886) | fn dccp() {
function cookie (line 1916) | fn cookie() {
function set_passcred (line 1934) | fn set_passcred() {
function set_priority (line 1950) | fn set_priority() {
function set_busy_poll (line 1963) | fn set_busy_poll() {
Condensed preview — 18 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (417K chars).
[
{
"path": ".github/workflows/main.yml",
"chars": 6033,
"preview": "name: CI\non:\n push:\n branches: [ master, \"v0.4.x\" ]\n pull_request:\n branches: [ master, \"v0.4.x\" ]\nenv:\n CARGO_"
},
{
"path": ".gitignore",
"chars": 40,
"preview": "/target\n**/*.rs.bk\nCargo.lock\n\n.vscode/\n"
},
{
"path": "CHANGELOG.md",
"chars": 21121,
"preview": "# 0.6.3\n\n* Added support for wasm32-wasip2.\n* Added `Socket::(set_)ip_transparent_v6`.\n* Added `Socket::set_tcp_ack_freq"
},
{
"path": "CONTRIBUTING.md",
"chars": 4174,
"preview": "# Contributing to Socket2\n\nThere are many ways to contribute to Socket2, including (but not limited to)\nanswering questi"
},
{
"path": "Cargo.toml",
"chars": 2073,
"preview": "[package]\nname = \"socket2\"\nversion = \"0.6.3\"\nauthors = [\n \"Alex Crichton <alex@alexcrichton.com>\","
},
{
"path": "LICENSE-APACHE",
"chars": 10847,
"preview": " Apache License\n Version 2.0, January 2004\n http"
},
{
"path": "LICENSE-MIT",
"chars": 1057,
"preview": "Copyright (c) 2014 Alex Crichton\n\nPermission is hereby granted, free of charge, to any\nperson obtaining a copy of this s"
},
{
"path": "Makefile",
"chars": 1268,
"preview": "# Targets available via Rustup that are supported.\n# NOTE: keep in sync with the CI and docs.rs targets.\nTARGETS ?= \"aar"
},
{
"path": "README.md",
"chars": 2635,
"preview": "# Socket2\n\nSocket2 is a crate that provides utilities for creating and using sockets.\n\nThe goal of this crate is to crea"
},
{
"path": "src/lib.rs",
"chars": 24644,
"preview": "// Copyright 2015 The Rust Project Developers.\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n/"
},
{
"path": "src/sockaddr.rs",
"chars": 21675,
"preview": "use std::hash::Hash;\nuse std::mem::{self, size_of};\nuse std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};\n#[cfg(not(ta"
},
{
"path": "src/socket.rs",
"chars": 89273,
"preview": "// Copyright 2015 The Rust Project Developers.\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n/"
},
{
"path": "src/sockref.rs",
"chars": 4105,
"preview": "use std::fmt;\nuse std::marker::PhantomData;\nuse std::mem::ManuallyDrop;\nuse std::ops::Deref;\n#[cfg(any(unix, all(target_"
},
{
"path": "src/sys/unix.rs",
"chars": 101636,
"preview": "// Copyright 2015 The Rust Project Developers.\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n/"
},
{
"path": "src/sys/windows.rs",
"chars": 35131,
"preview": "// Copyright 2015 The Rust Project Developers.\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n/"
},
{
"path": "tests/data/hello_world.txt",
"chars": 13,
"preview": "Hello world!\n"
},
{
"path": "tests/data/lorem_ipsum.txt",
"chars": 11935,
"preview": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec blandit ex vel turpis mollis, sed pretium purus ultricies"
},
{
"path": "tests/socket.rs",
"chars": 62213,
"preview": "#![allow(clippy::bool_assert_comparison)]\n#[cfg(all(\n feature = \"all\",\n any(\n target_os = \"android\",\n "
}
]
About this extraction
This page contains the full source code of the alexcrichton/socket2-rs GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 18 files (390.5 KB), approximately 106.8k tokens, and a symbol index with 574 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.