Stream: git-wasmtime

Topic: wasmtime / issue #12589 [wasmtime-wasi] reconnecting UDP ...


view this post on Zulip Wasmtime GitHub notifications bot (Feb 13 2026 at 20:44):

dicej opened issue #12589:

I've been adding WASIp2 support to mio and triaging failures in its test suite. This test is failing, which I tracked down to wasmtime-wasi spuriously changing the local address of a UDP socket when wasi:sockets/udp#udp-socket.stream is called a second time on the same socket (equivalent to calling connect(2) a second time in POSIX). The test fails because it uses the old local address, not realizing the socket suddenly has a new local address.

Here's a minimal test case:

// udp.rs
use std::{error::Error, net::UdpSocket};

fn main() -> Result<(), Box<dyn Error>> {
    let socket1 = UdpSocket::bind("127.0.0.1:0")?;
    let socket2 = UdpSocket::bind("127.0.0.1:0")?;

    let address1 = socket1.local_addr()?;
    let address2 = socket2.local_addr()?;

    println!(
        "before:\n  \
         socket1 local address: {address1:?}\n  \
         socket2 local address: {address2:?}"
    );

    socket1.connect(address1)?;
    socket1.connect(address2)?;
    socket2.connect(address1)?;

    println!(
        "before:\n  \
         socket1 local address: {address1:?} remote address: {remote1:?}\n  \
         socket2 local address: {address2:?} remote address: {remote2:?}",
        address1 = socket1.local_addr()?,
        address2 = socket2.local_addr()?,
        remote1 = socket1.peer_addr()?,
        remote2 = socket2.peer_addr()?
    );

    let data = b"foobar";
    socket1.send(data)?;

    let mut buffer = [0u8; 20];
    let count = socket2.recv(&mut buffer)?;

    assert_eq!(data, &buffer[..count]);

    println!("success!");

    Ok(())
}

If you build and run that natively on e.g. Linux using rustc udp.rs && ./udp, you'll see it succeed, with socket1's local address remaining unchanged before and after the UdpSocket::connect calls.

If you build and run for WASIp2 using rustc --target=wasm32-wasip2 udp.rs && wasmtime run -Sudp,inherit-network udp.wasm, you'll see it hang indefinitely due to socket1's local address changing due to the second UdpSocket::connect call.

While digging into this, I found that wasmtime-wasi proactively disconnects the socket by calling rustix::net::connect_unspec prior to reconnecting. When I comment out that code, the issue is fixed:

diff --git a/crates/wasi/src/p2/host/udp.rs b/crates/wasi/src/p2/host/udp.rs
index 1ef8350399..5dd426e736 100644
--- a/crates/wasi/src/p2/host/udp.rs
+++ b/crates/wasi/src/p2/host/udp.rs
@@ -71,9 +71,9 @@ impl udp::HostUdpSocket for WasiSocketsCtxView<'_> {
         //   if there isn't a disconnect in between.

         // Step #1: Disconnect
-        if socket.is_connected() {
-            socket.disconnect()?;
-        }
+        // if socket.is_connected() {
+        //     socket.disconnect()?;
+        // }

         // Step #2: (Re)connect
         if let Some(connect_addr) = remote_address {
diff --git a/crates/wasi/src/sockets/udp.rs b/crates/wasi/src/sockets/udp.rs
index 482c6aa090..ba1e93f18d 100644
--- a/crates/wasi/src/sockets/udp.rs
+++ b/crates/wasi/src/sockets/udp.rs
@@ -162,10 +162,10 @@ impl UdpSocket {
         //   if there isn't a disconnect in between.

         // Step #1: Disconnect
-        if let UdpState::Connected(..) = self.udp_state {
-            udp_disconnect(&self.socket)?;
-            self.udp_state = UdpState::Bound;
-        }
+        // if let UdpState::Connected(..) = self.udp_state {
+        //     udp_disconnect(&self.socket)?;
+        //     self.udp_state = UdpState::Bound;
+        // }
         // Step #2: (Re)connect
         connect(&self.socket, &addr).map_err(|error| match error {
             Errno::AFNOSUPPORT => ErrorCode::InvalidArgument, // See `udp_bind` implementation.

However, per the surrounding comments, that code is there for a reason, so I assume that removing it isn't the right solution. @badeend this seems to be related to https://github.com/bytecodealliance/wasmtime/pull/7411, so perhaps you have thoughts?

view this post on Zulip Wasmtime GitHub notifications bot (Feb 13 2026 at 20:50):

dicej edited issue #12589:

I've been adding WASIp2 support to mio and triaging failures in its test suite. This test is failing, which I tracked down to wasmtime-wasi spuriously changing the local address of a UDP socket when wasi:sockets/udp#udp-socket.stream is called a second time on the same socket (equivalent to calling connect(2) a second time in POSIX). The test fails because it uses the old local address, not realizing the socket suddenly has a new local address.

Here's a minimal test case:

// udp.rs
use std::{error::Error, net::UdpSocket};

fn main() -> Result<(), Box<dyn Error>> {
    let socket1 = UdpSocket::bind("127.0.0.1:0")?;
    let socket2 = UdpSocket::bind("127.0.0.1:0")?;

    let address1 = socket1.local_addr()?;
    let address2 = socket2.local_addr()?;

    println!(
        "before:\n  \
         socket1 local address: {address1:?}\n  \
         socket2 local address: {address2:?}"
    );

    socket1.connect(address1)?;
    socket1.connect(address2)?;
    socket2.connect(address1)?;

    println!(
        "after:\n  \
         socket1 local address: {address1:?} remote address: {remote1:?}\n  \
         socket2 local address: {address2:?} remote address: {remote2:?}",
        address1 = socket1.local_addr()?,
        address2 = socket2.local_addr()?,
        remote1 = socket1.peer_addr()?,
        remote2 = socket2.peer_addr()?
    );

    let data = b"foobar";
    socket1.send(data)?;

    let mut buffer = [0u8; 20];
    let count = socket2.recv(&mut buffer)?;

    assert_eq!(data, &buffer[..count]);

    println!("success!");

    Ok(())
}

If you build and run that natively on e.g. Linux using rustc udp.rs && ./udp, you'll see it succeed, with socket1's local address remaining unchanged before and after the UdpSocket::connect calls.

If you build and run for WASIp2 using rustc --target=wasm32-wasip2 udp.rs && wasmtime run -Sudp,inherit-network udp.wasm, you'll see it hang indefinitely due to socket1's local address changing due to the second UdpSocket::connect call.

While digging into this, I found that wasmtime-wasi proactively disconnects the socket by calling rustix::net::connect_unspec prior to reconnecting. When I comment out that code, the issue is fixed:

diff --git a/crates/wasi/src/p2/host/udp.rs b/crates/wasi/src/p2/host/udp.rs
index 1ef8350399..5dd426e736 100644
--- a/crates/wasi/src/p2/host/udp.rs
+++ b/crates/wasi/src/p2/host/udp.rs
@@ -71,9 +71,9 @@ impl udp::HostUdpSocket for WasiSocketsCtxView<'_> {
         //   if there isn't a disconnect in between.

         // Step #1: Disconnect
-        if socket.is_connected() {
-            socket.disconnect()?;
-        }
+        // if socket.is_connected() {
+        //     socket.disconnect()?;
+        // }

         // Step #2: (Re)connect
         if let Some(connect_addr) = remote_address {
diff --git a/crates/wasi/src/sockets/udp.rs b/crates/wasi/src/sockets/udp.rs
index 482c6aa090..ba1e93f18d 100644
--- a/crates/wasi/src/sockets/udp.rs
+++ b/crates/wasi/src/sockets/udp.rs
@@ -162,10 +162,10 @@ impl UdpSocket {
         //   if there isn't a disconnect in between.

         // Step #1: Disconnect
-        if let UdpState::Connected(..) = self.udp_state {
-            udp_disconnect(&self.socket)?;
-            self.udp_state = UdpState::Bound;
-        }
+        // if let UdpState::Connected(..) = self.udp_state {
+        //     udp_disconnect(&self.socket)?;
+        //     self.udp_state = UdpState::Bound;
+        // }
         // Step #2: (Re)connect
         connect(&self.socket, &addr).map_err(|error| match error {
             Errno::AFNOSUPPORT => ErrorCode::InvalidArgument, // See `udp_bind` implementation.

However, per the surrounding comments, that code is there for a reason, so I assume that removing it isn't the right solution. @badeend this seems to be related to https://github.com/bytecodealliance/wasmtime/pull/7411, so perhaps you have thoughts?

view this post on Zulip Wasmtime GitHub notifications bot (Feb 13 2026 at 20:54):

dicej added the wasi label to Issue #12589.


Last updated: Feb 24 2026 at 04:36 UTC