|
1 | | -use crate::preview2::udp::UdpSocket; |
| 1 | +use crate::preview2::udp::{IncomingDatagramStream, OutgoingDatagramStream, UdpSocket}; |
2 | 2 | use crate::preview2::{ |
3 | 3 | bindings::{ |
4 | 4 | sockets::network::{ErrorCode, IpAddressFamily, IpSocketAddress, Network}, |
5 | 5 | sockets::udp, |
6 | 6 | sockets::udp_create_socket, |
7 | 7 | }, |
8 | | - udp::{IncomingDatagramStream, OutgoingDatagramStream, SendState, UdpState}, |
| 8 | + udp::UdpState, |
9 | 9 | Subscribe, |
10 | 10 | }; |
11 | 11 | use crate::preview2::{Pollable, SocketError, SocketResult, WasiView}; |
@@ -106,7 +106,7 @@ impl<T: WasiView> udp::HostUdpSocket for T { |
106 | 106 |
|
107 | 107 | let has_active_streams = table |
108 | 108 | .iter_children(&this)? |
109 | | - .any(|c| c.is::<IncomingDatagramStream>() || c.is::<OutgoingDatagramStream>()); |
| 109 | + .any(|c| c.is::<IncomingStreamResource>() || c.is::<OutgoingStreamResource>()); |
110 | 110 |
|
111 | 111 | if has_active_streams { |
112 | 112 | return Err(SocketError::trap(anyhow!("UDP streams not dropped yet"))); |
@@ -138,15 +138,9 @@ impl<T: WasiView> udp::HostUdpSocket for T { |
138 | 138 | socket.udp_state = UdpState::Connected; |
139 | 139 | } |
140 | 140 |
|
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); |
150 | 144 |
|
151 | 145 | Ok(( |
152 | 146 | self.table_mut().push_child(incoming_stream, &this)?, |
@@ -288,13 +282,14 @@ impl<T: WasiView> udp::HostIncomingDatagramStream for T { |
288 | 282 | ) -> SocketResult<Vec<udp::IncomingDatagram>> { |
289 | 283 | // Returns Ok(None) when the message was dropped. |
290 | 284 | fn recv_one( |
291 | | - stream: &IncomingDatagramStream, |
| 285 | + stream: &IncomingStreamResource, |
292 | 286 | ) -> SocketResult<Option<udp::IncomingDatagram>> { |
293 | 287 | 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)?; |
295 | 289 | debug_assert!(size <= buf.len()); |
296 | 290 |
|
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 | + { |
298 | 293 | // Normally, this should have already been checked for us by the OS. |
299 | 294 | return Ok(None); |
300 | 295 | } |
@@ -357,13 +352,41 @@ impl<T: WasiView> udp::HostIncomingDatagramStream for T { |
357 | 352 | } |
358 | 353 | } |
359 | 354 |
|
| 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 | + |
360 | 383 | #[async_trait] |
361 | | -impl Subscribe for IncomingDatagramStream { |
| 384 | +impl Subscribe for OutgoingStreamResource { |
362 | 385 | 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 | + } |
367 | 390 | } |
368 | 391 | } |
369 | 392 |
|
@@ -391,26 +414,26 @@ impl<T: WasiView> udp::HostOutgoingDatagramStream for T { |
391 | 414 | datagrams: Vec<udp::OutgoingDatagram>, |
392 | 415 | ) -> SocketResult<u64> { |
393 | 416 | fn send_one( |
394 | | - stream: &OutgoingDatagramStream, |
| 417 | + stream: &OutgoingStreamResource, |
395 | 418 | datagram: &udp::OutgoingDatagram, |
396 | 419 | ) -> SocketResult<()> { |
397 | 420 | if datagram.data.len() > MAX_UDP_DATAGRAM_SIZE { |
398 | 421 | return Err(ErrorCode::DatagramTooLarge.into()); |
399 | 422 | } |
400 | 423 |
|
401 | 424 | 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)?; |
405 | 428 | } |
406 | | - (true, None) => { |
407 | | - stream.inner.send_data(&datagram.data)?; |
| 429 | + (Some(target), None) => { |
| 430 | + stream.inner.send(&datagram.data, target)?; |
408 | 431 | } |
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)?; |
411 | 434 | } |
412 | 435 | _ => return Err(ErrorCode::InvalidArgument.into()), |
413 | | - }; |
| 436 | + } |
414 | 437 |
|
415 | 438 | Ok(()) |
416 | 439 | } |
@@ -479,18 +502,24 @@ impl<T: WasiView> udp::HostOutgoingDatagramStream for T { |
479 | 502 | } |
480 | 503 | } |
481 | 504 |
|
| 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 | + |
482 | 520 | #[async_trait] |
483 | | -impl Subscribe for OutgoingDatagramStream { |
| 521 | +impl Subscribe for IncomingStreamResource { |
484 | 522 | 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; |
495 | 524 | } |
496 | 525 | } |
0 commit comments