Skip to content

Commit cc1e62f

Browse files
committed
Allow overriding streams
Signed-off-by: Ryan Levick <ryan.levick@fermyon.com>
1 parent 2ac3638 commit cc1e62f

4 files changed

Lines changed: 171 additions & 152 deletions

File tree

crates/wasi/src/preview2/host/udp.rs

Lines changed: 69 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
use crate::preview2::udp::UdpSocket;
1+
use crate::preview2::udp::{IncomingDatagramStream, OutgoingDatagramStream, UdpSocket};
22
use crate::preview2::{
33
bindings::{
44
sockets::network::{ErrorCode, IpAddressFamily, IpSocketAddress, Network},
55
sockets::udp,
66
sockets::udp_create_socket,
77
},
8-
udp::{IncomingDatagramStream, OutgoingDatagramStream, SendState, UdpState},
8+
udp::UdpState,
99
Subscribe,
1010
};
1111
use crate::preview2::{Pollable, SocketError, SocketResult, WasiView};
@@ -106,7 +106,7 @@ impl<T: WasiView> udp::HostUdpSocket for T {
106106

107107
let has_active_streams = table
108108
.iter_children(&this)?
109-
.any(|c| c.is::<IncomingDatagramStream>() || c.is::<OutgoingDatagramStream>());
109+
.any(|c| c.is::<IncomingStreamResource>() || c.is::<OutgoingStreamResource>());
110110

111111
if has_active_streams {
112112
return Err(SocketError::trap(anyhow!("UDP streams not dropped yet")));
@@ -138,15 +138,9 @@ impl<T: WasiView> udp::HostUdpSocket for T {
138138
socket.udp_state = UdpState::Connected;
139139
}
140140

141-
let incoming_stream = IncomingDatagramStream {
142-
inner: socket.inner.clone(),
143-
is_connected: remote_address.is_some(),
144-
};
145-
let outgoing_stream = OutgoingDatagramStream {
146-
inner: socket.inner.clone(),
147-
is_connected: remote_address.is_some(),
148-
send_state: SendState::Idle,
149-
};
141+
let (incoming_stream, outgoing_stream) = socket.inner.streams();
142+
let incoming_stream = IncomingStreamResource::new(incoming_stream, remote_address);
143+
let outgoing_stream = OutgoingStreamResource::new(outgoing_stream, remote_address);
150144

151145
Ok((
152146
self.table_mut().push_child(incoming_stream, &this)?,
@@ -288,13 +282,14 @@ impl<T: WasiView> udp::HostIncomingDatagramStream for T {
288282
) -> SocketResult<Vec<udp::IncomingDatagram>> {
289283
// Returns Ok(None) when the message was dropped.
290284
fn recv_one(
291-
stream: &IncomingDatagramStream,
285+
stream: &IncomingStreamResource,
292286
) -> SocketResult<Option<udp::IncomingDatagram>> {
293287
let mut buf = [0; MAX_UDP_DATAGRAM_SIZE];
294-
let (size, received_addr) = stream.inner.receive_data(&mut buf)?;
288+
let (size, received_addr) = stream.inner.recv(&mut buf)?;
295289
debug_assert!(size <= buf.len());
296290

297-
if stream.is_connected && stream.inner.remote_address()? != received_addr {
291+
if matches!(stream.remote_address, Some(remote_address) if remote_address != received_addr)
292+
{
298293
// Normally, this should have already been checked for us by the OS.
299294
return Ok(None);
300295
}
@@ -357,13 +352,41 @@ impl<T: WasiView> udp::HostIncomingDatagramStream for T {
357352
}
358353
}
359354

355+
pub struct OutgoingStreamResource {
356+
pub(crate) inner: OutgoingDatagramStream,
357+
358+
/// If this has a value, the stream is "connected".
359+
pub(crate) remote_address: Option<SocketAddr>,
360+
361+
pub(crate) send_state: SendState,
362+
}
363+
364+
pub(crate) enum SendState {
365+
/// Waiting for the API consumer to call `check-send`.
366+
Idle,
367+
/// Ready to send up to x datagrams.
368+
Permitted(usize),
369+
/// Waiting for the OS.
370+
Waiting,
371+
}
372+
373+
impl OutgoingStreamResource {
374+
fn new(inner: OutgoingDatagramStream, remote_address: Option<SocketAddr>) -> Self {
375+
Self {
376+
inner,
377+
remote_address,
378+
send_state: SendState::Idle,
379+
}
380+
}
381+
}
382+
360383
#[async_trait]
361-
impl Subscribe for IncomingDatagramStream {
384+
impl Subscribe for OutgoingStreamResource {
362385
async fn ready(&mut self) {
363-
self.inner
364-
.await_readable()
365-
.await
366-
.expect("failed to await UDP socket readiness");
386+
if let SendState::Waiting = self.send_state {
387+
self.inner.ready().await;
388+
self.send_state = SendState::Idle;
389+
}
367390
}
368391
}
369392

@@ -391,26 +414,26 @@ impl<T: WasiView> udp::HostOutgoingDatagramStream for T {
391414
datagrams: Vec<udp::OutgoingDatagram>,
392415
) -> SocketResult<u64> {
393416
fn send_one(
394-
stream: &OutgoingDatagramStream,
417+
stream: &OutgoingStreamResource,
395418
datagram: &udp::OutgoingDatagram,
396419
) -> SocketResult<()> {
397420
if datagram.data.len() > MAX_UDP_DATAGRAM_SIZE {
398421
return Err(ErrorCode::DatagramTooLarge.into());
399422
}
400423

401424
let provided_addr = datagram.remote_address.map(SocketAddr::from);
402-
match (stream.is_connected, provided_addr) {
403-
(false, Some(addr)) => {
404-
stream.inner.send_data_to(addr, &datagram.data)?;
425+
match (stream.remote_address, provided_addr) {
426+
(None, Some(target)) => {
427+
stream.inner.send(&datagram.data, target)?;
405428
}
406-
(true, None) => {
407-
stream.inner.send_data(&datagram.data)?;
429+
(Some(target), None) => {
430+
stream.inner.send(&datagram.data, target)?;
408431
}
409-
(true, Some(provided_addr)) if stream.inner.remote_address()? == provided_addr => {
410-
stream.inner.send_data(&datagram.data)?;
432+
(Some(connected_addr), Some(provided_addr)) if connected_addr == provided_addr => {
433+
stream.inner.send(&datagram.data, provided_addr)?;
411434
}
412435
_ => return Err(ErrorCode::InvalidArgument.into()),
413-
};
436+
}
414437

415438
Ok(())
416439
}
@@ -479,18 +502,24 @@ impl<T: WasiView> udp::HostOutgoingDatagramStream for T {
479502
}
480503
}
481504

505+
pub struct IncomingStreamResource {
506+
inner: IncomingDatagramStream,
507+
/// If this has a value, the stream is "connected".
508+
pub(crate) remote_address: Option<SocketAddr>,
509+
}
510+
511+
impl IncomingStreamResource {
512+
fn new(inner: IncomingDatagramStream, remote_address: Option<SocketAddr>) -> Self {
513+
Self {
514+
inner,
515+
remote_address,
516+
}
517+
}
518+
}
519+
482520
#[async_trait]
483-
impl Subscribe for OutgoingDatagramStream {
521+
impl Subscribe for IncomingStreamResource {
484522
async fn ready(&mut self) {
485-
match self.send_state {
486-
SendState::Idle | SendState::Permitted(_) => {}
487-
SendState::Waiting => {
488-
self.inner
489-
.await_writable()
490-
.await
491-
.expect("failed to await UDP socket readiness");
492-
self.send_state = SendState::Idle;
493-
}
494-
}
523+
self.inner.ready().await;
495524
}
496525
}

crates/wasi/src/preview2/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,8 @@ pub mod bindings {
164164
"wasi:sockets/network/network": super::network::NetworkResource,
165165
"wasi:sockets/tcp/tcp-socket": super::host::tcp::TcpSocketResource,
166166
"wasi:sockets/udp/udp-socket": super::host::udp::UdpSocketResource,
167-
"wasi:sockets/udp/incoming-datagram-stream": super::udp::IncomingDatagramStream,
168-
"wasi:sockets/udp/outgoing-datagram-stream": super::udp::OutgoingDatagramStream,
167+
"wasi:sockets/udp/incoming-datagram-stream": super::host::udp::IncomingStreamResource,
168+
"wasi:sockets/udp/outgoing-datagram-stream": super::host::udp::OutgoingStreamResource,
169169
"wasi:sockets/ip-name-lookup/resolve-address-stream": super::host::ip_name_lookup::ResolveAddressStreamResource,
170170
"wasi:filesystem/types/directory-entry-stream": super::filesystem::ReaddirIterator,
171171
"wasi:filesystem/types/descriptor": super::filesystem::Descriptor,

crates/wasi/src/preview2/network.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -173,10 +173,6 @@ impl SocketAddrCheck {
173173
Self(Arc::new(|_, _| false))
174174
}
175175

176-
pub fn allow() -> Self {
177-
Self(Arc::new(|_, _| true))
178-
}
179-
180176
pub fn check(&self, addr: &SocketAddr, reason: SocketAddrUse) -> std::io::Result<()> {
181177
if (self.0)(addr, reason) {
182178
Ok(())

0 commit comments

Comments
 (0)