wasm: add wasm32-wasip2 networking support (#7933)

Motivation

This adds networking support for the `wasm32-wasip2` target platform, which
includes more extensive support for sockets than `wasm32-wasip1`.

Solution

The bulk of the changes are in https://github.com/tokio-rs/mio/pull/1931.  This
patch mainly tweaks a few `cfg` directives to indicate `wasm32-wasip2`'s
additional capabilities.

Note that this is a draft PR until until
https://github.com/tokio-rs/mio/pull/1931 and
https://github.com/rust-lang/socket2/pull/639 have been include in stable
releases of their respective projects.

Also note that I've added a `wasm32-wasip2` target to CI and triaged each test
which was previously disabled for WASI into one of three categories:

- Disabled on both WASIp1 and p2 due to not-yet-supported features such as multithreading
- Disabled on p1 but enabled on p2
- Disabled on p1 and _temporarily_ disabled on p2 due to `wasi-libc` bugfixes which have been merged but not yet included in a Rust release.  I'll open an issue to re-enable them when the fixes land in Rust.

Future Work

In the future, we could consider adding support for `tokio::net::lookup_host`.
WASIp2 natively supports asynchronous DNS lookups and is single threaded,
whereas Tokio currently assumes DNS lookups are blocking and require
multithreading to emulate async lookups.  A WASIp2-specific implementation could
do the lookup directly without multithreading.

WASIp2 also supports single-threaded, asynchronous file I/O, timers, etc.  We
could either support those directly or wait for WASIp3's multithreading support,
in which case most of `tokio::fs` (as well as `tokio::net::lookup_host`, etc.)
_should_ work unchanged via `wasi-libc` and worker threads.

Currently, building for WASIp2 requires RUSTFLAGS="--cfg tokio_unstable"`.  Once
we have a solid maintenance plan, we can remove that requirement.
This commit is contained in:
Joel Dice
2026-04-02 11:53:17 +02:00
committed by GitHub
parent b4c3246d33
commit 43134f1e57
24 changed files with 322 additions and 86 deletions
+26
View File
@@ -1117,6 +1117,32 @@ jobs:
CARGO_TARGET_WASM32_WASIP1_THREADS_RUNNER: "wasmtime run -W bulk-memory=y -W threads=y -W shared-memory=y -S threads=y --"
RUSTFLAGS: --cfg tokio_unstable -Dwarnings -C target-feature=+atomics,+bulk-memory -C link-args=--max-memory=67108864
wasm32-wasip2:
name: test tokio for wasm32-wasip2
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- name: Install Rust ${{ env.rust_stable }}
uses: dtolnay/rust-toolchain@stable
with:
toolchain: ${{ env.rust_stable }}
targets: wasm32-wasip2
- name: Install cargo-nextest, wasmtime
uses: taiki-e/install-action@v2
with:
tool: cargo-nextest,wasmtime-cli
- uses: Swatinem/rust-cache@v2
- name: test tokio --target wasm32-wasip2
run: cargo nextest run --target wasm32-wasip2 --features net,macros,rt,io-util
working-directory: tokio
env:
RUSTFLAGS: --cfg tokio_unstable
CARGO_TARGET_WASM32_WASIP2_RUNNER: wasmtime run -Sinherit-network
check-external-types:
name: check-external-types (${{ matrix.os }})
needs: basics
+2 -1
View File
@@ -1,4 +1,4 @@
313
314
&
+
<
@@ -310,5 +310,6 @@ wakers
Wakers
wakeup
wakeups
WASI
workstealing
ZST
+7 -4
View File
@@ -96,11 +96,11 @@ pin-project-lite = "0.2.11"
# Everything else is optional...
bytes = { version = "1.2.1", optional = true }
mio = { version = "1.0.1", optional = true, default-features = false }
mio = { version = "1.2.0", optional = true, default-features = false }
parking_lot = { version = "0.12.0", optional = true }
[target.'cfg(not(target_family = "wasm"))'.dependencies]
socket2 = { version = "0.6.0", optional = true, features = ["all"] }
[target.'cfg(any(not(target_family = "wasm"), all(target_os = "wasi", not(target_env = "p1"))))'.dependencies]
socket2 = { version = "0.6.3", optional = true, features = ["all"] }
# Currently unstable. The API exposed by these features may be broken at any time.
# Requires `--cfg tokio_unstable` to enable.
@@ -112,7 +112,7 @@ tracing = { version = "0.1.29", default-features = false, features = ["std"], op
[target.'cfg(all(tokio_unstable, target_os = "linux"))'.dependencies]
io-uring = { version = "0.7.11", default-features = false, optional = true }
libc = { version = "0.2.168", optional = true }
mio = { version = "1.0.1", default-features = false, features = ["os-poll", "os-ext"], optional = true }
mio = { version = "1.2.0", default-features = false, features = ["os-poll", "os-ext"], optional = true }
slab = { version = "0.4.9", optional = true }
backtrace = { version = "0.3.58", optional = true }
@@ -120,6 +120,9 @@ backtrace = { version = "0.3.58", optional = true }
libc = { version = "0.2.168", optional = true }
signal-hook-registry = { version = "1.1.1", optional = true }
[target.'cfg(target_os = "wasi")'.dependencies]
libc = { version = "0.2.168", optional = true }
[target.'cfg(unix)'.dev-dependencies]
libc = { version = "0.2.168" }
nix = { version = "0.29.0", default-features = false, features = ["aio", "fs", "socket"] }
+21
View File
@@ -58,6 +58,18 @@ macro_rules! cfg_unix {
}
}
/// Enables Unix-specific code, including WASI.
/// Use this macro instead of `cfg(any(unix, target_os = "wasi"))` to generate docs properly.
macro_rules! cfg_unix_or_wasi {
($($item:item)*) => {
$(
#[cfg(any(all(doc, docsrs), unix, target_os = "wasi"))]
#[cfg_attr(docsrs, doc(cfg(any(unix, target_os = "wasi"))))]
$item
)*
}
}
/// Enables unstable Windows-specific code.
/// Use this macro instead of `cfg(windows)` to generate docs properly.
macro_rules! cfg_unstable_windows {
@@ -674,6 +686,15 @@ macro_rules! cfg_not_wasi {
}
}
macro_rules! cfg_not_wasip1 {
($($item:item)*) => {
$(
#[cfg(not(all(target_os = "wasi", target_env = "p1")))]
$item
)*
}
}
macro_rules! cfg_is_wasm_not_wasi {
($($item:item)*) => {
$(
+2 -2
View File
@@ -29,7 +29,7 @@
//! [`AsyncFd`]: crate::io::unix::AsyncFd
mod addr;
cfg_not_wasi! {
cfg_not_wasip1! {
#[cfg(feature = "net")]
pub(crate) use addr::to_socket_addrs;
}
@@ -42,7 +42,7 @@ cfg_net! {
pub mod tcp;
pub use tcp::listener::TcpListener;
pub use tcp::stream::TcpStream;
cfg_not_wasi! {
cfg_not_wasip1! {
pub use tcp::socket::TcpSocket;
mod udp;
+5 -5
View File
@@ -2,7 +2,7 @@ use crate::io::{Interest, PollEvented};
use crate::net::tcp::TcpStream;
use crate::util::check_socket_for_blocking;
cfg_not_wasi! {
cfg_not_wasip1! {
use crate::net::{to_socket_addrs, ToSocketAddrs};
}
@@ -60,7 +60,7 @@ cfg_net! {
}
impl TcpListener {
cfg_not_wasi! {
cfg_not_wasip1! {
/// Creates a new `TcpListener`, which will be bound to the specified address.
///
/// The returned listener is ready for accepting connections.
@@ -292,7 +292,7 @@ impl TcpListener {
#[cfg(target_os = "wasi")]
{
use std::os::wasi::io::{FromRawFd, IntoRawFd};
use std::os::fd::{FromRawFd, IntoRawFd};
self.io
.into_inner()
.map(|io| io.into_raw_fd())
@@ -300,7 +300,7 @@ impl TcpListener {
}
}
cfg_not_wasi! {
cfg_not_wasip1! {
pub(crate) fn new(listener: mio::net::TcpListener) -> io::Result<TcpListener> {
let io = PollEvented::new(listener)?;
Ok(TcpListener { io })
@@ -427,7 +427,7 @@ cfg_unstable! {
#[cfg(target_os = "wasi")]
mod sys {
use super::TcpListener;
use std::os::wasi::prelude::*;
use std::os::fd::{RawFd, BorrowedFd, AsRawFd, AsFd};
impl AsRawFd for TcpListener {
fn as_raw_fd(&self) -> RawFd {
+1 -1
View File
@@ -2,7 +2,7 @@
pub(crate) mod listener;
cfg_not_wasi! {
cfg_not_wasip1! {
pub(crate) mod socket;
}
+31 -21
View File
@@ -4,8 +4,8 @@ use std::fmt;
use std::io;
use std::net::SocketAddr;
#[cfg(unix)]
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
#[cfg(not(windows))]
use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
use std::time::Duration;
cfg_windows! {
@@ -170,7 +170,8 @@ impl TcpSocket {
target_os = "illumos",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd"
target_os = "openbsd",
target_os = "wasi",
))]
let ty = ty.nonblocking();
let inner = socket2::Socket::new(domain, ty, Some(socket2::Protocol::TCP))?;
@@ -182,7 +183,8 @@ impl TcpSocket {
target_os = "illumos",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd"
target_os = "openbsd",
target_os = "wasi",
)))]
inner.set_nonblocking(true)?;
Ok(TcpSocket { inner })
@@ -597,7 +599,8 @@ impl TcpSocket {
target_os = "redox",
target_os = "solaris",
target_os = "illumos",
target_os = "haiku"
target_os = "haiku",
target_os = "wasi",
)))]
#[cfg_attr(
docsrs,
@@ -606,7 +609,8 @@ impl TcpSocket {
target_os = "redox",
target_os = "solaris",
target_os = "illumos",
target_os = "haiku"
target_os = "haiku",
target_os = "wasi",
))))
)]
pub fn tos_v4(&self) -> io::Result<u32> {
@@ -625,7 +629,8 @@ impl TcpSocket {
target_os = "redox",
target_os = "solaris",
target_os = "illumos",
target_os = "haiku"
target_os = "haiku",
target_os = "wasi",
)))]
#[cfg_attr(
docsrs,
@@ -634,7 +639,8 @@ impl TcpSocket {
target_os = "redox",
target_os = "solaris",
target_os = "illumos",
target_os = "haiku"
target_os = "haiku",
target_os = "wasi",
))))
)]
pub fn tos(&self) -> io::Result<u32> {
@@ -657,7 +663,8 @@ impl TcpSocket {
target_os = "redox",
target_os = "solaris",
target_os = "illumos",
target_os = "haiku"
target_os = "haiku",
target_os = "wasi",
)))]
#[cfg_attr(
docsrs,
@@ -666,7 +673,8 @@ impl TcpSocket {
target_os = "redox",
target_os = "solaris",
target_os = "illumos",
target_os = "haiku"
target_os = "haiku",
target_os = "wasi",
))))
)]
pub fn set_tos_v4(&self, tos: u32) -> io::Result<()> {
@@ -685,7 +693,8 @@ impl TcpSocket {
target_os = "redox",
target_os = "solaris",
target_os = "illumos",
target_os = "haiku"
target_os = "haiku",
target_os = "wasi",
)))]
#[cfg_attr(
docsrs,
@@ -694,7 +703,8 @@ impl TcpSocket {
target_os = "redox",
target_os = "solaris",
target_os = "illumos",
target_os = "haiku"
target_os = "haiku",
target_os = "wasi",
))))
)]
pub fn set_tos(&self, tos: u32) -> io::Result<()> {
@@ -826,7 +836,7 @@ impl TcpSocket {
/// ```
pub async fn connect(self, addr: SocketAddr) -> io::Result<TcpStream> {
if let Err(err) = self.inner.connect(&addr.into()) {
#[cfg(unix)]
#[cfg(not(windows))]
if err.raw_os_error() != Some(libc::EINPROGRESS) {
return Err(err);
}
@@ -835,9 +845,9 @@ impl TcpSocket {
return Err(err);
}
}
#[cfg(unix)]
#[cfg(not(windows))]
let mio = {
use std::os::unix::io::{FromRawFd, IntoRawFd};
use std::os::fd::{FromRawFd, IntoRawFd};
let raw_fd = self.inner.into_raw_fd();
unsafe { mio::net::TcpStream::from_raw_fd(raw_fd) }
@@ -891,9 +901,9 @@ impl TcpSocket {
/// ```
pub fn listen(self, backlog: u32) -> io::Result<TcpListener> {
self.inner.listen(backlog as i32)?;
#[cfg(unix)]
#[cfg(not(windows))]
let mio = {
use std::os::unix::io::{FromRawFd, IntoRawFd};
use std::os::fd::{FromRawFd, IntoRawFd};
let raw_fd = self.inner.into_raw_fd();
unsafe { mio::net::TcpListener::from_raw_fd(raw_fd) }
@@ -945,9 +955,9 @@ impl TcpSocket {
/// }
/// ```
pub fn from_std_stream(std_stream: std::net::TcpStream) -> TcpSocket {
#[cfg(unix)]
#[cfg(not(windows))]
{
use std::os::unix::io::{FromRawFd, IntoRawFd};
use std::os::fd::{FromRawFd, IntoRawFd};
let raw_fd = std_stream.into_raw_fd();
unsafe { TcpSocket::from_raw_fd(raw_fd) }
@@ -981,8 +991,8 @@ impl fmt::Debug for TcpSocket {
// These trait implementations can't be build on Windows, so we completely
// ignore them, even when building documentation.
#[cfg(unix)]
cfg_unix! {
#[cfg(any(unix, target_os = "wasi"))]
cfg_unix_or_wasi! {
impl AsRawFd for TcpSocket {
fn as_raw_fd(&self) -> RawFd {
self.inner.as_raw_fd()
+7 -4
View File
@@ -1,7 +1,10 @@
cfg_not_wasi! {
use std::time::Duration;
}
cfg_not_wasip1! {
use crate::net::{to_socket_addrs, ToSocketAddrs};
use std::future::poll_fn;
use std::time::Duration;
}
use crate::io::{AsyncRead, AsyncWrite, Interest, PollEvented, ReadBuf, Ready};
@@ -73,7 +76,7 @@ cfg_net! {
}
impl TcpStream {
cfg_not_wasi! {
cfg_not_wasip1! {
/// Opens a TCP connection to a remote host.
///
/// `addr` is an address of the remote host. Anything which implements the
@@ -272,7 +275,7 @@ impl TcpStream {
#[cfg(target_os = "wasi")]
{
use std::os::wasi::io::{FromRawFd, IntoRawFd};
use std::os::fd::{FromRawFd, IntoRawFd};
self.io
.into_inner()
.map(|io| io.into_raw_fd())
@@ -1564,7 +1567,7 @@ cfg_windows! {
#[cfg(all(tokio_unstable, target_os = "wasi"))]
mod sys {
use super::TcpStream;
use std::os::wasi::prelude::*;
use std::os::fd::{AsFd, AsRawFd, BorrowedFd, RawFd};
impl AsRawFd for TcpStream {
fn as_raw_fd(&self) -> RawFd {
+20 -12
View File
@@ -254,9 +254,9 @@ impl UdpSocket {
/// [`std::net::UdpSocket`]: std::net::UdpSocket
/// [`set_nonblocking`]: fn@std::net::UdpSocket::set_nonblocking
pub fn into_std(self) -> io::Result<std::net::UdpSocket> {
#[cfg(unix)]
#[cfg(not(windows))]
{
use std::os::unix::io::{FromRawFd, IntoRawFd};
use std::os::fd::{FromRawFd, IntoRawFd};
self.io
.into_inner()
.map(IntoRawFd::into_raw_fd)
@@ -2084,7 +2084,8 @@ impl UdpSocket {
target_os = "redox",
target_os = "solaris",
target_os = "illumos",
target_os = "haiku"
target_os = "haiku",
target_os = "wasi",
)))]
#[cfg_attr(
docsrs,
@@ -2093,7 +2094,8 @@ impl UdpSocket {
target_os = "redox",
target_os = "solaris",
target_os = "illumos",
target_os = "haiku"
target_os = "haiku",
target_os = "wasi",
))))
)]
pub fn tos_v4(&self) -> io::Result<u32> {
@@ -2112,7 +2114,8 @@ impl UdpSocket {
target_os = "redox",
target_os = "solaris",
target_os = "illumos",
target_os = "haiku"
target_os = "haiku",
target_os = "wasi",
)))]
#[cfg_attr(
docsrs,
@@ -2121,7 +2124,8 @@ impl UdpSocket {
target_os = "redox",
target_os = "solaris",
target_os = "illumos",
target_os = "haiku"
target_os = "haiku",
target_os = "wasi",
))))
)]
pub fn tos(&self) -> io::Result<u32> {
@@ -2144,7 +2148,8 @@ impl UdpSocket {
target_os = "redox",
target_os = "solaris",
target_os = "illumos",
target_os = "haiku"
target_os = "haiku",
target_os = "wasi",
)))]
#[cfg_attr(
docsrs,
@@ -2153,7 +2158,8 @@ impl UdpSocket {
target_os = "redox",
target_os = "solaris",
target_os = "illumos",
target_os = "haiku"
target_os = "haiku",
target_os = "wasi",
))))
)]
pub fn set_tos_v4(&self, tos: u32) -> io::Result<()> {
@@ -2172,7 +2178,8 @@ impl UdpSocket {
target_os = "redox",
target_os = "solaris",
target_os = "illumos",
target_os = "haiku"
target_os = "haiku",
target_os = "wasi",
)))]
#[cfg_attr(
docsrs,
@@ -2181,7 +2188,8 @@ impl UdpSocket {
target_os = "redox",
target_os = "solaris",
target_os = "illumos",
target_os = "haiku"
target_os = "haiku",
target_os = "wasi",
))))
)]
pub fn set_tos(&self, tos: u32) -> io::Result<()> {
@@ -2297,10 +2305,10 @@ impl fmt::Debug for UdpSocket {
}
}
#[cfg(unix)]
#[cfg(not(windows))]
mod sys {
use super::UdpSocket;
use std::os::unix::prelude::*;
use std::os::fd::{AsFd, AsRawFd, BorrowedFd, RawFd};
impl AsRawFd for UdpSocket {
fn as_raw_fd(&self) -> RawFd {
+1 -1
View File
@@ -118,7 +118,7 @@ impl Registration {
// Uses the poll path, requiring the caller to ensure mutual exclusion for
// correctness. Only the last task to call this function is notified.
#[cfg(not(target_os = "wasi"))]
#[cfg(not(all(target_os = "wasi", target_env = "p1")))]
pub(crate) fn poll_read_io<R>(
&self,
cx: &mut Context<'_>,
+10 -1
View File
@@ -1,5 +1,14 @@
#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(target_os = "wasi")))] // Wasi doesn't support panic recovery or bind
// WASIp1 doesn't support bind
// No `socket` on miri.
#![cfg(all(
feature = "net",
feature = "macros",
feature = "rt",
feature = "io-util",
not(all(target_os = "wasi", target_env = "p1")),
not(miri)
))]
use tokio::net::TcpListener;
+15 -1
View File
@@ -1,4 +1,11 @@
#![cfg(all(feature = "full", not(target_os = "wasi")))] // Wasi does not support direct socket operations
// WASIp1 doesn't support direct socket operations
#![cfg(all(
feature = "net",
feature = "macros",
feature = "rt",
feature = "io-util",
not(all(target_os = "wasi", target_env = "p1")),
))]
use tokio::net;
use tokio_test::assert_ok;
@@ -22,6 +29,13 @@ async fn lookup_str_socket_addr() {
assert_eq!(vec![addr], actual);
}
// Note that WASIp2 _does_ support asynchronous name lookups without requiring a
// worker thread, so this test could be ungated for WASI if/when that's
// implemented.
#[cfg_attr(
target_os = "wasi",
ignore = "net::lookup_host requires multithreading, which WASI does not yet support"
)]
#[tokio::test]
#[cfg_attr(miri, ignore)] // No `getaddrinfo` in miri.
async fn resolve_dns() -> io::Result<()> {
+16 -3
View File
@@ -1,6 +1,14 @@
#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(target_os = "wasi"), not(miri)))] // Wasi doesn't support bind
// No `socket` on miri.
// WASIp1 doesn't support bind
// No `socket` on miri.
#![cfg(all(
feature = "net",
feature = "macros",
feature = "rt",
feature = "io-util",
not(all(target_os = "wasi", target_env = "p1")),
not(miri)
))]
use tokio::net::{TcpListener, TcpStream};
use tokio::sync::{mpsc, oneshot};
@@ -10,8 +18,9 @@ use std::io;
use std::net::{IpAddr, SocketAddr};
macro_rules! test_accept {
($(($ident:ident, $target:expr),)*) => {
($($(#[$attribute:meta])*($ident:ident, $target:expr),)*) => {
$(
$(#[$attribute])*
#[tokio::test]
async fn $ident() {
let listener = assert_ok!(TcpListener::bind($target).await);
@@ -35,6 +44,10 @@ macro_rules! test_accept {
test_accept! {
(ip_str, "127.0.0.1:0"),
// Note that WASIp2 _does_ support asynchronous name lookups without
// requiring a worker thread, so this test could be ungated if/when that's
// implemented.
#[cfg_attr(target_os = "wasi", ignore = "net::lookup_host requires multithreading, which WASI does not yet support")]
(host_str, "localhost:0"),
(socket_addr, "127.0.0.1:0".parse::<SocketAddr>().unwrap()),
(str_port_tuple, ("127.0.0.1", 0)),
+24 -2
View File
@@ -1,6 +1,14 @@
#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(target_os = "wasi"), not(miri)))] // Wasi doesn't support bind
// No `socket` on miri.
// WASIp1 doesn't support bind
// No `socket` on miri.
#![cfg(all(
feature = "net",
feature = "macros",
feature = "rt",
feature = "io-util",
not(all(target_os = "wasi", target_env = "p1")),
not(miri)
))]
use tokio::net::{TcpListener, TcpStream};
use tokio::sync::oneshot;
@@ -96,6 +104,13 @@ async fn connect_addr_ip_str_slice() {
join!(server, client);
}
// Note that WASIp2 _does_ support asynchronous name lookups without
// requiring a worker thread, so this test could be ungated if/when that's
// implemented.
#[cfg_attr(
target_os = "wasi",
ignore = "net::lookup_host requires multithreading, which WASI does not yet support"
)]
#[tokio::test]
async fn connect_addr_host_string() {
let srv = assert_ok!(TcpListener::bind("127.0.0.1:0").await);
@@ -147,6 +162,13 @@ async fn connect_addr_ip_str_port_tuple() {
join!(server, client);
}
// Note that WASIp2 _does_ support asynchronous name lookups without
// requiring a worker thread, so this test could be ungated if/when that's
// implemented.
#[cfg_attr(
target_os = "wasi",
ignore = "net::lookup_host requires multithreading, which WASI does not yet support"
)]
#[tokio::test]
async fn connect_addr_host_str_port_tuple() {
let srv = assert_ok!(TcpListener::bind("127.0.0.1:0").await);
+10 -2
View File
@@ -1,6 +1,14 @@
#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(target_os = "wasi"), not(miri)))] // Wasi doesn't support bind
// No socket on miri.
// WASIp1 doesn't support bind
// No `socket` on miri.
#![cfg(all(
feature = "net",
feature = "macros",
feature = "rt",
feature = "io-util",
not(all(target_os = "wasi", target_env = "p1")),
not(miri)
))]
use tokio::io::{self, AsyncReadExt, AsyncWriteExt};
use tokio::net::{TcpListener, TcpStream};
+1 -1
View File
@@ -1,5 +1,5 @@
#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(target_os = "wasi"), not(miri)))] // Wasi doesn't support bind
#![cfg(all(feature = "full", not(target_os = "wasi"), not(miri)))] // Wasi doesn't support multithreading or peeking
// No `socket` on miri.
use std::io::{Error, ErrorKind, Result};
+10 -2
View File
@@ -1,6 +1,14 @@
#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(target_os = "wasi"), not(miri)))] // Wasi doesn't support bind
// No socket on `miri`.
// WASIp1 doesn't support bind
// No `socket` on miri.
#![cfg(all(
feature = "net",
feature = "macros",
feature = "rt",
feature = "io-util",
not(all(target_os = "wasi", target_env = "p1")),
not(miri)
))]
use std::io::Read;
use std::io::Result;
+1 -1
View File
@@ -1,5 +1,5 @@
#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(target_os = "wasi"), not(miri)))] // Wasi doesn't support bind
#![cfg(all(feature = "full", not(target_os = "wasi"), not(miri)))] // Wasi doesn't support peeking
// No `socket` on miri.
use tokio::io::AsyncReadExt;
+1 -1
View File
@@ -1,5 +1,5 @@
#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(target_os = "wasi"), not(miri)))] // Wasi doesn't support bind
#![cfg(all(feature = "full", not(target_os = "wasi"), not(miri)))] // Wasi doesn't support mulithreading
// No `socket` on miri.
use tokio::io::{self, AsyncReadExt, AsyncWriteExt};
+14 -3
View File
@@ -1,6 +1,14 @@
#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(target_os = "wasi"), not(miri)))] // Wasi doesn't support bind
// No `socket` on miri.
// WASIp1 doesn't support bind
// No `socket` on miri.
#![cfg(all(
feature = "net",
feature = "macros",
feature = "rt",
feature = "io-util",
not(all(target_os = "wasi", target_env = "p1")),
not(miri)
))]
use std::time::Duration;
use tokio::net::TcpSocket;
@@ -61,6 +69,7 @@ async fn bind_before_connect() {
let _ = assert_ok!(srv.accept().await);
}
#[cfg_attr(target_os = "wasi", ignore = "WASI does not yet support `SO_LINGER`")]
#[tokio::test]
async fn basic_linger() {
// Create server
@@ -154,6 +163,7 @@ test!(
);
test!(
#[cfg_attr(target_os = "wasi", ignore = "WASI does not yet support `SO_LINGER`")]
#[expect(deprecated, reason = "set_linger is deprecated")]
linger,
set_linger(Some(Duration::from_secs(10)))
@@ -179,6 +189,7 @@ test!(IPv6 tclass_v6, set_tclass_v6(96));
target_os = "redox",
target_os = "solaris",
target_os = "illumos",
target_os = "haiku"
target_os = "haiku",
target_os = "wasi"
)))]
test!(IPv4 tos_v4, set_tos_v4(96));
+1 -1
View File
@@ -1,5 +1,5 @@
#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(target_os = "wasi"), not(miri)))] // Wasi doesn't support bind
#![cfg(all(feature = "full", not(target_os = "wasi"), not(miri)))] // Wasi doesn't support peeking
// No `socket` on miri.
use std::io::Result;
+47 -14
View File
@@ -1,5 +1,14 @@
#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(target_os = "wasi")))] // Wasi doesn't support bind
// WASIp1 doesn't support bind
// No `socket` on miri.
#![cfg(all(
feature = "net",
feature = "macros",
feature = "rt",
feature = "io-util",
not(all(target_os = "wasi", target_env = "p1")),
not(miri)
))]
use tokio::io::{AsyncReadExt, AsyncWriteExt, Interest};
use tokio::net::{TcpListener, TcpStream};
@@ -10,9 +19,11 @@ use tokio_test::{assert_ok, assert_pending, assert_ready_ok};
use std::future::poll_fn;
use std::io;
use std::task::Poll;
#[cfg(not(target_os = "wasi"))]
use std::time::Duration;
#[tokio::test]
#[cfg(not(target_os = "wasi"))] // WASI does not yet support `SO_LINGER`
#[cfg_attr(miri, ignore)] // No `socket` on miri.
#[expect(deprecated)] // set_linger is deprecated
async fn set_linger() {
@@ -33,6 +44,10 @@ async fn set_linger() {
}
#[tokio::test]
#[cfg_attr(
target_os = "wasi",
ignore = "temporarily disabled for WASI pending https://github.com/WebAssembly/wasi-libc/pull/734"
)]
#[cfg_attr(miri, ignore)] // No `socket` on miri.
async fn try_read_write() {
const DATA: &[u8] = b"this is some data to write to the socket";
@@ -98,6 +113,7 @@ async fn try_read_write() {
}
written.clear();
written.reserve(10 * 1024 * 1024);
client.writable().await.unwrap();
// Fill the write buffer using vectored I/O
@@ -108,7 +124,9 @@ async fn try_read_write() {
assert_ready_ok!(writable.poll());
match client.try_write_vectored(&data_bufs) {
Ok(n) => written.extend(&DATA[..n]),
Ok(n) => {
written.extend(&DATA[..n]);
}
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
break;
}
@@ -145,13 +163,16 @@ async fn try_read_write() {
// Now, we listen for shutdown
drop(client);
loop {
let ready = server.ready(Interest::READABLE).await.unwrap();
#[cfg(not(target_os = "wasi"))] // WASI does not yet support `POLLHUP` or `POLLRDHUP`
{
loop {
let ready = server.ready(Interest::READABLE).await.unwrap();
if ready.is_read_closed() {
return;
} else {
tokio::task::yield_now().await;
if ready.is_read_closed() {
return;
} else {
tokio::task::yield_now().await;
}
}
}
}
@@ -359,19 +380,31 @@ async fn try_read_buf() {
// Now, we listen for shutdown
drop(client);
loop {
let ready = server.ready(Interest::READABLE).await.unwrap();
#[cfg(not(target_os = "wasi"))] // WASI does not yet support `POLLHUP` or `POLLRDHUP`
{
let mut count = 0;
loop {
count += 1;
if count > 100 {
panic!("loop 4")
}
let ready = server.ready(Interest::READABLE).await.unwrap();
if ready.is_read_closed() {
return;
} else {
tokio::task::yield_now().await;
if ready.is_read_closed() {
return;
} else {
tokio::task::yield_now().await;
}
}
}
}
// read_closed is a best effort event, so test only for no false positives.
#[tokio::test]
#[cfg_attr(
target_os = "wasi",
ignore = "temporarily disabled for WASI pending https://github.com/WebAssembly/wasi-libc/pull/732"
)]
#[cfg_attr(miri, ignore)] // No `socket` on miri.
async fn read_closed() {
let (client, mut server) = create_pair().await;
+49 -3
View File
@@ -1,6 +1,14 @@
#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(target_os = "wasi"), not(miri)))] // Wasi does not support bind or UDP
// No `socket` on miri.
// WASIp1 doesn't support bind
// No `socket` on miri.
#![cfg(all(
feature = "net",
feature = "macros",
feature = "rt",
feature = "io-util",
not(all(target_os = "wasi", target_env = "p1")),
not(miri)
))]
use std::future::poll_fn;
use std::io;
@@ -47,6 +55,10 @@ async fn send_recv_poll() -> std::io::Result<()> {
}
#[tokio::test]
#[cfg_attr(
target_os = "wasi",
ignore = "temporarily disabled for WASI pending https://github.com/WebAssembly/wasi-libc/pull/734"
)]
async fn send_to_recv_from() -> std::io::Result<()> {
let sender = UdpSocket::bind("127.0.0.1:0").await?;
let receiver = UdpSocket::bind("127.0.0.1:0").await?;
@@ -63,6 +75,10 @@ async fn send_to_recv_from() -> std::io::Result<()> {
}
#[tokio::test]
#[cfg_attr(
target_os = "wasi",
ignore = "temporarily disabled for WASI pending https://github.com/WebAssembly/wasi-libc/pull/734"
)]
async fn send_to_recv_from_poll() -> std::io::Result<()> {
let sender = UdpSocket::bind("127.0.0.1:0").await?;
let receiver = UdpSocket::bind("127.0.0.1:0").await?;
@@ -79,6 +95,7 @@ async fn send_to_recv_from_poll() -> std::io::Result<()> {
Ok(())
}
#[cfg_attr(target_os = "wasi", ignore = "WASI does not yet support peeking")]
#[tokio::test]
async fn send_to_peek_from() -> std::io::Result<()> {
let sender = UdpSocket::bind("127.0.0.1:0").await?;
@@ -107,6 +124,7 @@ async fn send_to_peek_from() -> std::io::Result<()> {
Ok(())
}
#[cfg_attr(target_os = "wasi", ignore = "WASI does not yet support peeking")]
#[tokio::test]
async fn send_to_try_peek_from() -> std::io::Result<()> {
let sender = UdpSocket::bind("127.0.0.1:0").await?;
@@ -146,6 +164,7 @@ async fn send_to_try_peek_from() -> std::io::Result<()> {
Ok(())
}
#[cfg_attr(target_os = "wasi", ignore = "WASI does not yet support peeking")]
#[tokio::test]
async fn send_to_peek_from_poll() -> std::io::Result<()> {
let sender = UdpSocket::bind("127.0.0.1:0").await?;
@@ -174,6 +193,7 @@ async fn send_to_peek_from_poll() -> std::io::Result<()> {
Ok(())
}
#[cfg_attr(target_os = "wasi", ignore = "WASI does not yet support peeking")]
#[tokio::test]
async fn peek_sender() -> std::io::Result<()> {
let sender = UdpSocket::bind("127.0.0.1:0").await?;
@@ -199,6 +219,7 @@ async fn peek_sender() -> std::io::Result<()> {
Ok(())
}
#[cfg_attr(target_os = "wasi", ignore = "WASI does not yet support peeking")]
#[tokio::test]
async fn poll_peek_sender() -> std::io::Result<()> {
let sender = UdpSocket::bind("127.0.0.1:0").await?;
@@ -225,6 +246,7 @@ async fn poll_peek_sender() -> std::io::Result<()> {
Ok(())
}
#[cfg_attr(target_os = "wasi", ignore = "WASI does not yet support peeking")]
#[tokio::test]
async fn try_peek_sender() -> std::io::Result<()> {
let sender = UdpSocket::bind("127.0.0.1:0").await?;
@@ -353,6 +375,10 @@ async fn split_chan_poll() -> std::io::Result<()> {
// **not** be okay because it's resources are completion based (via IOCP).
// If data is sent and not yet received, attempting to send more data will
// result in `ErrorKind::WouldBlock` until the first operation completes.
#[cfg_attr(
target_os = "wasi",
ignore = "WASI does not yet support multithreading"
)]
#[tokio::test]
async fn try_send_spawn() {
const MSG2: &[u8] = b"world!";
@@ -439,6 +465,10 @@ async fn try_send_recv() {
}
#[tokio::test]
#[cfg_attr(
target_os = "wasi",
ignore = "temporarily disabled for WASI pending https://github.com/WebAssembly/wasi-libc/pull/734"
)]
async fn try_send_to_recv_from() {
// Create listener
let server = UdpSocket::bind("127.0.0.1:0").await.unwrap();
@@ -543,6 +573,10 @@ async fn recv_buf() -> std::io::Result<()> {
}
#[tokio::test]
#[cfg_attr(
target_os = "wasi",
ignore = "temporarily disabled for WASI pending https://github.com/WebAssembly/wasi-libc/pull/734"
)]
async fn try_recv_buf_from() {
// Create listener
let server = UdpSocket::bind("127.0.0.1:0").await.unwrap();
@@ -586,6 +620,10 @@ async fn try_recv_buf_from() {
}
#[tokio::test]
#[cfg_attr(
target_os = "wasi",
ignore = "temporarily disabled for WASI pending https://github.com/WebAssembly/wasi-libc/pull/734"
)]
async fn recv_buf_from() -> std::io::Result<()> {
let sender = UdpSocket::bind("127.0.0.1:0").await?;
let receiver = UdpSocket::bind("127.0.0.1:0").await?;
@@ -603,6 +641,10 @@ async fn recv_buf_from() -> std::io::Result<()> {
}
#[tokio::test]
#[cfg_attr(
target_os = "wasi",
ignore = "temporarily disabled for WASI pending https://github.com/WebAssembly/wasi-libc/pull/734"
)]
async fn poll_ready() {
// Create listener
let server = UdpSocket::bind("127.0.0.1:0").await.unwrap();
@@ -690,13 +732,16 @@ macro_rules! test {
};
}
#[cfg(not(target_os = "wasi"))] // WASI does not yet support broadcast
test!(broadcast, set_broadcast(true));
#[cfg(not(target_os = "wasi"))] // WASI does not yet support multicast
test!(IPv4 multicast_loop_v4, set_multicast_loop_v4(false));
#[cfg(target_os = "linux")] // broken on non-Linux platforms https://github.com/rust-lang/socket2/pull/630
test!(multicast_ttl_v4, set_multicast_ttl_v4(40));
#[cfg(not(target_os = "wasi"))] // WASI does not yet support multicast
test!(IPv6 multicast_loop_v6, set_multicast_loop_v6(false));
#[cfg(any(
@@ -719,6 +764,7 @@ test!(IPv4 ttl, set_ttl(40));
target_os = "redox",
target_os = "solaris",
target_os = "illumos",
target_os = "haiku"
target_os = "haiku",
target_os = "wasi"
)))]
test!(IPv4 tos_v4, set_tos_v4(96));