1use crate::p2::bindings::sockets::network::{ErrorCode, IpAddressFamily, IpSocketAddress, Network};
2use crate::p2::bindings::sockets::udp;
3use crate::p2::udp::{AsyncOperation, IncomingDatagramStream, OutgoingDatagramStream};
4use crate::p2::{Pollable, SocketError, SocketResult, UdpSocket};
5use crate::sockets::{SocketAddressFamily, WasiSocketsCtxView};
6use async_trait::async_trait;
7use std::future::poll_fn;
8use std::net::SocketAddr;
9use std::task::{Context, Poll, Waker};
10use wasmtime::component::Resource;
11use wasmtime::format_err;
12use wasmtime_wasi_io::poll::DynPollable;
13
14const MAX_DATAGRAMS: usize = 16;
15
16impl udp::Host for WasiSocketsCtxView<'_> {}
17
18impl udp::HostUdpSocket for WasiSocketsCtxView<'_> {
19 async fn start_bind(
20 &mut self,
21 this: Resource<UdpSocket>,
22 network: Resource<Network>,
23 local_address: IpSocketAddress,
24 ) -> SocketResult<()> {
25 _ = self.table.get(&network)?;
29
30 let local_address = SocketAddr::from(local_address);
31 let socket = self.table.get_mut(&this)?;
32 if socket.in_progress_operation.is_some() {
33 return Err(ErrorCode::ConcurrencyConflict.into());
34 }
35
36 socket
37 .get_mut()
38 .ok_or(ErrorCode::InvalidState)?
39 .bind(local_address)
40 .await?;
41
42 socket.in_progress_operation = Some(AsyncOperation::Bind);
43 Ok(())
44 }
45
46 fn finish_bind(&mut self, this: Resource<UdpSocket>) -> SocketResult<()> {
47 let socket = self.table.get_mut(&this)?;
48 if socket.in_progress_operation != Some(AsyncOperation::Bind) {
49 return Err(ErrorCode::NotInProgress.into());
50 };
51 socket.in_progress_operation = None;
52 Ok(())
53 }
54
55 async fn stream(
56 &mut self,
57 this: Resource<UdpSocket>,
58 remote_address: Option<IpSocketAddress>,
59 ) -> SocketResult<(
60 Resource<udp::IncomingDatagramStream>,
61 Resource<udp::OutgoingDatagramStream>,
62 )> {
63 let has_active_streams = self
64 .table
65 .iter_children(&this)?
66 .any(|c| c.is::<IncomingDatagramStream>() || c.is::<OutgoingDatagramStream>());
67
68 if has_active_streams {
69 return Err(SocketError::trap(format_err!(
70 "UDP streams not dropped yet"
71 )));
72 }
73
74 let socket = self.table.get_mut(&this)?;
75 let inner = socket
76 .get_mut()
77 .ok_or(SocketError::trap(wasmtime::error::format_err!(
78 "`connect` needs exclusive access"
79 )))?;
80
81 if !inner.is_bound() {
82 return Err(ErrorCode::InvalidState.into());
84 }
85
86 if let Some(connect_addr) = remote_address {
87 inner.connect(connect_addr.into()).await?;
88 } else if inner.is_connected() {
89 inner.disconnect()?;
90 }
91 let incoming_stream = IncomingDatagramStream::new(socket.inner.clone());
92 let outgoing_stream = OutgoingDatagramStream::new(socket.inner.clone());
93 Ok((
94 self.table.push_child(incoming_stream, &this)?,
95 self.table.push_child(outgoing_stream, &this)?,
96 ))
97 }
98
99 fn local_address(&mut self, this: Resource<UdpSocket>) -> SocketResult<IpSocketAddress> {
100 let mut socket = self.table.get(&this)?.lock();
101 Ok(socket.local_address()?.into())
102 }
103
104 fn remote_address(&mut self, this: Resource<UdpSocket>) -> SocketResult<IpSocketAddress> {
105 let mut socket = self.table.get(&this)?.lock();
106 Ok(socket.remote_address()?.into())
107 }
108
109 fn address_family(
110 &mut self,
111 this: Resource<UdpSocket>,
112 ) -> Result<IpAddressFamily, wasmtime::Error> {
113 let socket = self.table.get(&this)?.lock();
114 Ok(socket.address_family().into())
115 }
116
117 fn unicast_hop_limit(&mut self, this: Resource<UdpSocket>) -> SocketResult<u8> {
118 let socket = self.table.get(&this)?.lock();
119 Ok(socket.unicast_hop_limit()?)
120 }
121
122 fn set_unicast_hop_limit(&mut self, this: Resource<UdpSocket>, value: u8) -> SocketResult<()> {
123 let socket = self.table.get(&this)?.lock();
124 socket.set_unicast_hop_limit(value)?;
125 Ok(())
126 }
127
128 fn receive_buffer_size(&mut self, this: Resource<UdpSocket>) -> SocketResult<u64> {
129 let socket = self.table.get(&this)?.lock();
130 Ok(socket.receive_buffer_size()?)
131 }
132
133 fn set_receive_buffer_size(
134 &mut self,
135 this: Resource<UdpSocket>,
136 value: u64,
137 ) -> SocketResult<()> {
138 let socket = self.table.get(&this)?.lock();
139 socket.set_receive_buffer_size(value)?;
140 Ok(())
141 }
142
143 fn send_buffer_size(&mut self, this: Resource<UdpSocket>) -> SocketResult<u64> {
144 let socket = self.table.get(&this)?.lock();
145 Ok(socket.send_buffer_size()?)
146 }
147
148 fn set_send_buffer_size(&mut self, this: Resource<UdpSocket>, value: u64) -> SocketResult<()> {
149 let socket = self.table.get(&this)?.lock();
150 socket.set_send_buffer_size(value)?;
151 Ok(())
152 }
153
154 fn subscribe(&mut self, this: Resource<UdpSocket>) -> wasmtime::Result<Resource<DynPollable>> {
155 wasmtime_wasi_io::poll::subscribe(self.table, this)
156 }
157
158 fn drop(&mut self, this: Resource<UdpSocket>) -> Result<(), wasmtime::Error> {
159 let dropped = self.table.delete(this)?;
162 drop(dropped);
163
164 Ok(())
165 }
166}
167
168#[async_trait]
169impl Pollable for UdpSocket {
170 async fn ready(&mut self) {
171 }
173}
174
175impl udp::HostIncomingDatagramStream for WasiSocketsCtxView<'_> {
176 fn receive(
177 &mut self,
178 this: Resource<udp::IncomingDatagramStream>,
179 max_results: u64,
180 ) -> SocketResult<Vec<udp::IncomingDatagram>> {
181 let stream = self.table.get_mut(&this)?;
182 let max_results: usize = max_results
183 .try_into()
184 .unwrap_or(usize::MAX)
185 .min(MAX_DATAGRAMS);
186 if max_results == 0 {
187 return Ok(vec![]);
188 }
189
190 let mut datagrams = vec![];
191 let mut sum = 0;
192
193 while datagrams.len() < max_results && sum < crate::MAX_READ_SIZE_ALLOC {
194 match stream.try_recv() {
195 Err(ErrorCode::WouldBlock) => break,
196 Ok((data, remote_addr)) => {
197 sum += 1 + data.len();
198 datagrams.push(udp::IncomingDatagram {
199 data,
200 remote_address: remote_addr.into(),
201 });
202 }
203 Err(_) if datagrams.len() > 0 => break,
204 Err(e) => {
205 return Err(e.into());
206 }
207 }
208 }
209
210 Ok(datagrams)
211 }
212
213 fn subscribe(
214 &mut self,
215 this: Resource<udp::IncomingDatagramStream>,
216 ) -> wasmtime::Result<Resource<DynPollable>> {
217 wasmtime_wasi_io::poll::subscribe(self.table, this)
218 }
219
220 fn drop(&mut self, this: Resource<udp::IncomingDatagramStream>) -> Result<(), wasmtime::Error> {
221 let dropped = self.table.delete(this)?;
224 drop(dropped);
225
226 Ok(())
227 }
228}
229
230#[async_trait]
231impl Pollable for IncomingDatagramStream {
232 async fn ready(&mut self) {
233 poll_fn(|cx| self.poll_recv_ready(cx)).await
234 }
235}
236
237impl udp::HostOutgoingDatagramStream for WasiSocketsCtxView<'_> {
238 fn check_send(&mut self, this: Resource<udp::OutgoingDatagramStream>) -> SocketResult<u64> {
239 let stream = self.table.get_mut(&this)?;
240
241 let count = if let Poll::Ready(()) =
242 stream.poll_send_ready(&mut Context::from_waker(Waker::noop()))
243 {
244 MAX_DATAGRAMS
249 } else {
250 0
251 };
252
253 stream.check_send_permit_count = count;
254
255 Ok(count.try_into().unwrap())
256 }
257
258 fn send(
259 &mut self,
260 this: Resource<udp::OutgoingDatagramStream>,
261 datagrams: Vec<udp::OutgoingDatagram>,
262 ) -> SocketResult<u64> {
263 let stream = self.table.get_mut(&this)?;
264
265 if datagrams.is_empty() {
266 return Ok(0);
267 }
268
269 if datagrams.len() > stream.check_send_permit_count {
270 return Err(SocketError::trap(wasmtime::format_err!(
271 "unpermitted: argument exceeds permitted size"
272 )));
273 }
274
275 stream.check_send_permit_count = 0;
278
279 let mut count = 0;
280
281 for datagram in datagrams {
282 match stream.try_send(datagram.data, datagram.remote_address.map(SocketAddr::from)) {
283 Err(ErrorCode::WouldBlock) => break,
284 Ok(()) => count += 1,
285 Err(_) if count > 0 => {
286 break;
288 }
289 Err(e) => {
290 return Err(e.into());
291 }
292 }
293 }
294
295 Ok(count)
296 }
297
298 fn subscribe(
299 &mut self,
300 this: Resource<udp::OutgoingDatagramStream>,
301 ) -> wasmtime::Result<Resource<DynPollable>> {
302 wasmtime_wasi_io::poll::subscribe(self.table, this)
303 }
304
305 async fn drop(
306 &mut self,
307 this: Resource<udp::OutgoingDatagramStream>,
308 ) -> Result<(), wasmtime::Error> {
309 let mut stream = self.table.delete(this)?;
310 std::future::poll_fn(|cx| stream.poll_send_ready(cx)).await;
315 drop(stream);
316 Ok(())
317 }
318}
319
320#[async_trait]
321impl Pollable for OutgoingDatagramStream {
322 async fn ready(&mut self) {
323 poll_fn(|cx| self.poll_send_ready(cx)).await
324 }
325}
326
327impl From<SocketAddressFamily> for IpAddressFamily {
328 fn from(family: SocketAddressFamily) -> IpAddressFamily {
329 match family {
330 SocketAddressFamily::Ipv4 => IpAddressFamily::Ipv4,
331 SocketAddressFamily::Ipv6 => IpAddressFamily::Ipv6,
332 }
333 }
334}
335
336pub mod sync {
337 use wasmtime::component::Resource;
338
339 use crate::p2::{
340 SocketError, UdpSocket,
341 bindings::{
342 sockets::{
343 network::Network,
344 udp::{
345 self as async_udp,
346 HostIncomingDatagramStream as AsyncHostIncomingDatagramStream,
347 HostOutgoingDatagramStream as AsyncHostOutgoingDatagramStream,
348 HostUdpSocket as AsyncHostUdpSocket, IncomingDatagramStream,
349 OutgoingDatagramStream,
350 },
351 },
352 sync::sockets::udp::{
353 self, HostIncomingDatagramStream, HostOutgoingDatagramStream, HostUdpSocket,
354 IncomingDatagram, IpAddressFamily, IpSocketAddress, OutgoingDatagram, Pollable,
355 },
356 },
357 };
358 use crate::runtime::in_tokio;
359 use crate::sockets::WasiSocketsCtxView;
360
361 impl udp::Host for WasiSocketsCtxView<'_> {}
362
363 impl HostUdpSocket for WasiSocketsCtxView<'_> {
364 fn start_bind(
365 &mut self,
366 self_: Resource<UdpSocket>,
367 network: Resource<Network>,
368 local_address: IpSocketAddress,
369 ) -> Result<(), SocketError> {
370 in_tokio(async {
371 AsyncHostUdpSocket::start_bind(self, self_, network, local_address).await
372 })
373 }
374
375 fn finish_bind(&mut self, self_: Resource<UdpSocket>) -> Result<(), SocketError> {
376 AsyncHostUdpSocket::finish_bind(self, self_)
377 }
378
379 fn stream(
380 &mut self,
381 self_: Resource<UdpSocket>,
382 remote_address: Option<IpSocketAddress>,
383 ) -> Result<
384 (
385 Resource<IncomingDatagramStream>,
386 Resource<OutgoingDatagramStream>,
387 ),
388 SocketError,
389 > {
390 in_tokio(async { AsyncHostUdpSocket::stream(self, self_, remote_address).await })
391 }
392
393 fn local_address(
394 &mut self,
395 self_: Resource<UdpSocket>,
396 ) -> Result<IpSocketAddress, SocketError> {
397 AsyncHostUdpSocket::local_address(self, self_)
398 }
399
400 fn remote_address(
401 &mut self,
402 self_: Resource<UdpSocket>,
403 ) -> Result<IpSocketAddress, SocketError> {
404 AsyncHostUdpSocket::remote_address(self, self_)
405 }
406
407 fn address_family(
408 &mut self,
409 self_: Resource<UdpSocket>,
410 ) -> wasmtime::Result<IpAddressFamily> {
411 AsyncHostUdpSocket::address_family(self, self_)
412 }
413
414 fn unicast_hop_limit(&mut self, self_: Resource<UdpSocket>) -> Result<u8, SocketError> {
415 AsyncHostUdpSocket::unicast_hop_limit(self, self_)
416 }
417
418 fn set_unicast_hop_limit(
419 &mut self,
420 self_: Resource<UdpSocket>,
421 value: u8,
422 ) -> Result<(), SocketError> {
423 AsyncHostUdpSocket::set_unicast_hop_limit(self, self_, value)
424 }
425
426 fn receive_buffer_size(&mut self, self_: Resource<UdpSocket>) -> Result<u64, SocketError> {
427 AsyncHostUdpSocket::receive_buffer_size(self, self_)
428 }
429
430 fn set_receive_buffer_size(
431 &mut self,
432 self_: Resource<UdpSocket>,
433 value: u64,
434 ) -> Result<(), SocketError> {
435 AsyncHostUdpSocket::set_receive_buffer_size(self, self_, value)
436 }
437
438 fn send_buffer_size(&mut self, self_: Resource<UdpSocket>) -> Result<u64, SocketError> {
439 AsyncHostUdpSocket::send_buffer_size(self, self_)
440 }
441
442 fn set_send_buffer_size(
443 &mut self,
444 self_: Resource<UdpSocket>,
445 value: u64,
446 ) -> Result<(), SocketError> {
447 AsyncHostUdpSocket::set_send_buffer_size(self, self_, value)
448 }
449
450 fn subscribe(
451 &mut self,
452 self_: Resource<UdpSocket>,
453 ) -> wasmtime::Result<Resource<Pollable>> {
454 AsyncHostUdpSocket::subscribe(self, self_)
455 }
456
457 fn drop(&mut self, rep: Resource<UdpSocket>) -> wasmtime::Result<()> {
458 AsyncHostUdpSocket::drop(self, rep)
459 }
460 }
461
462 impl HostIncomingDatagramStream for WasiSocketsCtxView<'_> {
463 fn receive(
464 &mut self,
465 self_: Resource<IncomingDatagramStream>,
466 max_results: u64,
467 ) -> Result<Vec<IncomingDatagram>, SocketError> {
468 Ok(
469 AsyncHostIncomingDatagramStream::receive(self, self_, max_results)?
470 .into_iter()
471 .map(Into::into)
472 .collect(),
473 )
474 }
475
476 fn subscribe(
477 &mut self,
478 self_: Resource<IncomingDatagramStream>,
479 ) -> wasmtime::Result<Resource<Pollable>> {
480 AsyncHostIncomingDatagramStream::subscribe(self, self_)
481 }
482
483 fn drop(&mut self, rep: Resource<IncomingDatagramStream>) -> wasmtime::Result<()> {
484 AsyncHostIncomingDatagramStream::drop(self, rep)
485 }
486 }
487
488 impl From<async_udp::IncomingDatagram> for IncomingDatagram {
489 fn from(other: async_udp::IncomingDatagram) -> Self {
490 let async_udp::IncomingDatagram {
491 data,
492 remote_address,
493 } = other;
494 Self {
495 data,
496 remote_address,
497 }
498 }
499 }
500
501 impl HostOutgoingDatagramStream for WasiSocketsCtxView<'_> {
502 fn check_send(
503 &mut self,
504 self_: Resource<OutgoingDatagramStream>,
505 ) -> Result<u64, SocketError> {
506 AsyncHostOutgoingDatagramStream::check_send(self, self_)
507 }
508
509 fn send(
510 &mut self,
511 self_: Resource<OutgoingDatagramStream>,
512 datagrams: Vec<OutgoingDatagram>,
513 ) -> Result<u64, SocketError> {
514 let datagrams = datagrams.into_iter().map(Into::into).collect();
515 AsyncHostOutgoingDatagramStream::send(self, self_, datagrams)
516 }
517
518 fn subscribe(
519 &mut self,
520 self_: Resource<OutgoingDatagramStream>,
521 ) -> wasmtime::Result<Resource<Pollable>> {
522 AsyncHostOutgoingDatagramStream::subscribe(self, self_)
523 }
524
525 fn drop(&mut self, rep: Resource<OutgoingDatagramStream>) -> wasmtime::Result<()> {
526 in_tokio(async { AsyncHostOutgoingDatagramStream::drop(self, rep).await })
527 }
528 }
529
530 impl From<OutgoingDatagram> for async_udp::OutgoingDatagram {
531 fn from(other: OutgoingDatagram) -> Self {
532 let OutgoingDatagram {
533 data,
534 remote_address,
535 } = other;
536 Self {
537 data,
538 remote_address,
539 }
540 }
541 }
542}