1use crate::sockets::{SpinSockets, SpinSocketsView};
2use spin_factors::anyhow::Result;
3use std::mem;
4use wasmtime::component::{Linker, Resource, ResourceTable};
5use wasmtime_wasi::TrappableError;
6use wasmtime_wasi::cli::{WasiCli, WasiCliCtxView};
7use wasmtime_wasi::clocks::{WasiClocks, WasiClocksCtxView};
8use wasmtime_wasi::filesystem::{WasiFilesystem, WasiFilesystemCtxView};
9use wasmtime_wasi::p2::DynPollable;
10use wasmtime_wasi::p2::bindings::sockets::udp_create_socket as p2_udp_create;
11use wasmtime_wasi::random::{WasiRandom, WasiRandomCtx};
12
13mod latest {
14 pub use wasmtime_wasi::p2::bindings::*;
15}
16
17mod bindings {
18 pub use super::UdpSocket;
19 use super::latest;
20
21 wasmtime::component::bindgen!({
22 path: "../../wit",
23 world: "wasi:cli/reactor@0.2.0-rc-2023-10-18",
24 imports: {
25 "wasi:io/streams.[drop]output-stream": async | trappable,
26 "wasi:io/streams.[drop]input-stream": async | trappable,
27 "wasi:filesystem/types.[method]descriptor.access-at": async | trappable,
28 "wasi:filesystem/types.[method]descriptor.advise": async | trappable,
29 "wasi:filesystem/types.[method]descriptor.change-directory-permissions-at": async | trappable,
30 "wasi:filesystem/types.[method]descriptor.change-file-permissions-at": async | trappable,
31 "wasi:filesystem/types.[method]descriptor.create-directory-at": async | trappable,
32 "wasi:filesystem/types.[method]descriptor.get-flags": async | trappable,
33 "wasi:filesystem/types.[method]descriptor.get-type": async | trappable,
34 "wasi:filesystem/types.[method]descriptor.is-same-object": async | trappable,
35 "wasi:filesystem/types.[method]descriptor.link-at": async | trappable,
36 "wasi:filesystem/types.[method]descriptor.lock-exclusive": async | trappable,
37 "wasi:filesystem/types.[method]descriptor.lock-shared": async | trappable,
38 "wasi:filesystem/types.[method]descriptor.metadata-hash": async | trappable,
39 "wasi:filesystem/types.[method]descriptor.metadata-hash-at": async | trappable,
40 "wasi:filesystem/types.[method]descriptor.open-at": async | trappable,
41 "wasi:filesystem/types.[method]descriptor.read": async | trappable,
42 "wasi:filesystem/types.[method]descriptor.read-directory": async | trappable,
43 "wasi:filesystem/types.[method]descriptor.readlink-at": async | trappable,
44 "wasi:filesystem/types.[method]descriptor.remove-directory-at": async | trappable,
45 "wasi:filesystem/types.[method]descriptor.rename-at": async | trappable,
46 "wasi:filesystem/types.[method]descriptor.set-size": async | trappable,
47 "wasi:filesystem/types.[method]descriptor.set-times": async | trappable,
48 "wasi:filesystem/types.[method]descriptor.set-times-at": async | trappable,
49 "wasi:filesystem/types.[method]descriptor.stat": async | trappable,
50 "wasi:filesystem/types.[method]descriptor.stat-at": async | trappable,
51 "wasi:filesystem/types.[method]descriptor.symlink-at": async | trappable,
52 "wasi:filesystem/types.[method]descriptor.sync": async | trappable,
53 "wasi:filesystem/types.[method]descriptor.sync-data": async | trappable,
54 "wasi:filesystem/types.[method]descriptor.try-lock-exclusive": async | trappable,
55 "wasi:filesystem/types.[method]descriptor.try-lock-shared": async | trappable,
56 "wasi:filesystem/types.[method]descriptor.unlink-file-at": async | trappable,
57 "wasi:filesystem/types.[method]descriptor.unlock": async | trappable,
58 "wasi:filesystem/types.[method]descriptor.write": async | trappable,
59 "wasi:filesystem/types.[method]directory-entry-stream.read-directory-entry": async | trappable,
60 "wasi:io/streams.[method]input-stream.blocking-read": async | trappable,
61 "wasi:io/streams.[method]input-stream.blocking-skip": async | trappable,
62 "wasi:io/streams.[method]output-stream.forward": async | trappable,
63 "wasi:io/streams.[method]output-stream.blocking-splice": async | trappable,
64 "wasi:io/streams.[method]output-stream.blocking-flush": async | trappable,
65 "wasi:io/streams.[method]output-stream.blocking-write-and-flush": async | trappable,
66 "wasi:io/streams.[method]output-stream.blocking-write-zeroes-and-flush": async | trappable,
67 "wasi:io/poll.poll-list": async | trappable,
68 "wasi:io/poll.poll-one": async | trappable,
69 "wasi:sockets/ip-name-lookup.[drop]resolve-address-stream": async | trappable,
70 "wasi:sockets/tcp.[method]tcp-socket.start-bind": async | trappable,
71 "wasi:sockets/tcp.[method]tcp-socket.start-connect": async | trappable,
72 "wasi:sockets/tcp.[method]tcp-socket.start-listen": async | trappable,
73 "wasi:sockets/udp-create-socket.create-udp-socket": async | trappable,
74 "wasi:sockets/udp.[method]udp-socket.finish-connect": async | trappable,
75 "wasi:sockets/udp.[method]udp-socket.receive": async | trappable,
76 "wasi:sockets/udp.[method]udp-socket.send": async | trappable,
77 "wasi:sockets/udp.[method]udp-socket.start-bind": async | trappable,
78 "wasi:sockets/udp.[drop]udp-socket": async | trappable,
79 default: trappable,
80 },
81 with: {
82 "wasi:io/poll.pollable": latest::io::poll::Pollable,
83 "wasi:io/streams.input-stream": latest::io::streams::InputStream,
84 "wasi:io/streams.output-stream": latest::io::streams::OutputStream,
85 "wasi:io/streams.error": latest::io::streams::Error,
86 "wasi:filesystem/types.directory-entry-stream": latest::filesystem::types::DirectoryEntryStream,
87 "wasi:filesystem/types.descriptor": latest::filesystem::types::Descriptor,
88 "wasi:cli/terminal-input.terminal-input": latest::cli::terminal_input::TerminalInput,
89 "wasi:cli/terminal-output.terminal-output": latest::cli::terminal_output::TerminalOutput,
90 "wasi:sockets/tcp.tcp-socket": latest::sockets::tcp::TcpSocket,
91 "wasi:sockets/udp.udp-socket": UdpSocket,
92 "wasi:sockets/network.network": latest::sockets::network::Network,
93 "wasi:sockets/ip-name-lookup.resolve-address-stream": latest::sockets::ip_name_lookup::ResolveAddressStream,
94 },
95 });
96}
97
98mod wasi {
99 pub use super::bindings::wasi::{
100 cli0_2_0_rc_2023_10_18 as cli, clocks0_2_0_rc_2023_10_18 as clocks,
101 filesystem0_2_0_rc_2023_10_18 as filesystem, io0_2_0_rc_2023_10_18 as io,
102 random0_2_0_rc_2023_10_18 as random, sockets0_2_0_rc_2023_10_18 as sockets,
103 };
104}
105
106use wasi::cli::terminal_input::TerminalInput;
107use wasi::cli::terminal_output::TerminalOutput;
108use wasi::clocks::monotonic_clock::Instant;
109use wasi::clocks::wall_clock::Datetime;
110use wasi::filesystem::types::{
111 AccessType, Advice, Descriptor, DescriptorFlags, DescriptorStat, DescriptorType,
112 DirectoryEntry, DirectoryEntryStream, Error, ErrorCode as FsErrorCode, Filesize,
113 MetadataHashValue, Modes, NewTimestamp, OpenFlags, PathFlags,
114};
115use wasi::io::streams::{InputStream, OutputStream, StreamError};
116use wasi::sockets::ip_name_lookup::{IpAddress, ResolveAddressStream};
117use wasi::sockets::network::{Ipv4SocketAddress, Ipv6SocketAddress};
118use wasi::sockets::tcp::{
119 ErrorCode as SocketErrorCode, IpAddressFamily, IpSocketAddress, Network, ShutdownType,
120 TcpSocket,
121};
122use wasi::sockets::udp::Datagram;
123
124use crate::HasIo;
125
126pub fn add_to_linker<T>(
127 linker: &mut Linker<T>,
128 io_closure: fn(&mut T) -> &mut ResourceTable,
129 random_closure: fn(&mut T) -> &mut WasiRandomCtx,
130 clocks_closure: fn(&mut T) -> WasiClocksCtxView<'_>,
131 cli_closure: fn(&mut T) -> WasiCliCtxView<'_>,
132 filesystem_closure: fn(&mut T) -> WasiFilesystemCtxView<'_>,
133 sockets_closure: fn(&mut T) -> SpinSocketsView<'_, T>,
134) -> Result<()>
135where
136 T: Send + 'static,
137{
138 wasi::clocks::monotonic_clock::add_to_linker::<_, WasiClocks>(linker, clocks_closure)?;
139 wasi::clocks::wall_clock::add_to_linker::<_, WasiClocks>(linker, clocks_closure)?;
140 wasi::filesystem::types::add_to_linker::<_, WasiFilesystem>(linker, filesystem_closure)?;
141 wasi::filesystem::preopens::add_to_linker::<_, WasiFilesystem>(linker, filesystem_closure)?;
142 wasi::io::poll::add_to_linker::<_, HasIo>(linker, io_closure)?;
143 wasi::io::streams::add_to_linker::<_, HasIo>(linker, io_closure)?;
144 wasi::random::random::add_to_linker::<_, WasiRandom>(linker, random_closure)?;
145 wasi::random::insecure::add_to_linker::<_, WasiRandom>(linker, random_closure)?;
146 wasi::random::insecure_seed::add_to_linker::<_, WasiRandom>(linker, random_closure)?;
147 wasi::cli::exit::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
148 wasi::cli::environment::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
149 wasi::cli::stdin::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
150 wasi::cli::stdout::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
151 wasi::cli::stderr::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
152 wasi::cli::terminal_input::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
153 wasi::cli::terminal_output::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
154 wasi::cli::terminal_stdin::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
155 wasi::cli::terminal_stdout::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
156 wasi::cli::terminal_stderr::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
157 wasi::sockets::tcp::add_to_linker::<_, SpinSockets<T>>(linker, sockets_closure)?;
158 wasi::sockets::tcp_create_socket::add_to_linker::<_, SpinSockets<T>>(linker, sockets_closure)?;
159 wasi::sockets::udp::add_to_linker::<_, SpinSockets<T>>(linker, sockets_closure)?;
160 wasi::sockets::udp_create_socket::add_to_linker::<_, SpinSockets<T>>(linker, sockets_closure)?;
161 wasi::sockets::instance_network::add_to_linker::<_, SpinSockets<T>>(linker, sockets_closure)?;
162 wasi::sockets::network::add_to_linker::<_, SpinSockets<T>>(linker, sockets_closure)?;
163 wasi::sockets::ip_name_lookup::add_to_linker::<_, SpinSockets<T>>(linker, sockets_closure)?;
164 Ok(())
165}
166
167impl wasi::clocks::monotonic_clock::Host for WasiClocksCtxView<'_> {
168 fn now(&mut self) -> wasmtime::Result<Instant> {
169 latest::clocks::monotonic_clock::Host::now(self)
170 }
171
172 fn resolution(&mut self) -> wasmtime::Result<Instant> {
173 latest::clocks::monotonic_clock::Host::resolution(self)
174 }
175
176 fn subscribe(
177 &mut self,
178 when: Instant,
179 absolute: bool,
180 ) -> wasmtime::Result<Resource<DynPollable>> {
181 if absolute {
182 latest::clocks::monotonic_clock::Host::subscribe_instant(self, when)
183 } else {
184 latest::clocks::monotonic_clock::Host::subscribe_duration(self, when)
185 }
186 }
187}
188
189impl wasi::clocks::wall_clock::Host for WasiClocksCtxView<'_> {
190 fn now(&mut self) -> wasmtime::Result<Datetime> {
191 Ok(latest::clocks::wall_clock::Host::now(self)?.into())
192 }
193
194 fn resolution(&mut self) -> wasmtime::Result<Datetime> {
195 Ok(latest::clocks::wall_clock::Host::resolution(self)?.into())
196 }
197}
198
199impl wasi::filesystem::types::Host for WasiFilesystemCtxView<'_> {
200 fn filesystem_error_code(
201 &mut self,
202 err: Resource<wasi::filesystem::types::Error>,
203 ) -> wasmtime::Result<Option<FsErrorCode>> {
204 Ok(latest::filesystem::types::Host::filesystem_error_code(self, err)?.map(|e| e.into()))
205 }
206}
207
208impl wasi::filesystem::types::HostDescriptor for WasiFilesystemCtxView<'_> {
209 fn read_via_stream(
210 &mut self,
211 self_: Resource<Descriptor>,
212 offset: Filesize,
213 ) -> wasmtime::Result<Result<Resource<InputStream>, FsErrorCode>> {
214 convert_result(latest::filesystem::types::HostDescriptor::read_via_stream(
215 self, self_, offset,
216 ))
217 }
218
219 fn write_via_stream(
220 &mut self,
221 self_: Resource<Descriptor>,
222 offset: Filesize,
223 ) -> wasmtime::Result<Result<Resource<OutputStream>, FsErrorCode>> {
224 convert_result(latest::filesystem::types::HostDescriptor::write_via_stream(
225 self, self_, offset,
226 ))
227 }
228
229 fn append_via_stream(
230 &mut self,
231 self_: Resource<Descriptor>,
232 ) -> wasmtime::Result<Result<Resource<OutputStream>, FsErrorCode>> {
233 convert_result(latest::filesystem::types::HostDescriptor::append_via_stream(self, self_))
234 }
235
236 async fn advise(
237 &mut self,
238 self_: Resource<Descriptor>,
239 offset: Filesize,
240 length: Filesize,
241 advice: Advice,
242 ) -> wasmtime::Result<Result<(), FsErrorCode>> {
243 convert_result(
244 latest::filesystem::types::HostDescriptor::advise(
245 self,
246 self_,
247 offset,
248 length,
249 advice.into(),
250 )
251 .await,
252 )
253 }
254
255 async fn sync_data(
256 &mut self,
257 self_: Resource<Descriptor>,
258 ) -> wasmtime::Result<Result<(), FsErrorCode>> {
259 convert_result(latest::filesystem::types::HostDescriptor::sync_data(self, self_).await)
260 }
261
262 async fn get_flags(
263 &mut self,
264 self_: Resource<Descriptor>,
265 ) -> wasmtime::Result<Result<DescriptorFlags, FsErrorCode>> {
266 convert_result(latest::filesystem::types::HostDescriptor::get_flags(self, self_).await)
267 }
268
269 async fn get_type(
270 &mut self,
271 self_: Resource<Descriptor>,
272 ) -> wasmtime::Result<Result<DescriptorType, FsErrorCode>> {
273 convert_result(latest::filesystem::types::HostDescriptor::get_type(self, self_).await)
274 }
275
276 async fn set_size(
277 &mut self,
278 self_: Resource<Descriptor>,
279 size: Filesize,
280 ) -> wasmtime::Result<Result<(), FsErrorCode>> {
281 convert_result(latest::filesystem::types::HostDescriptor::set_size(self, self_, size).await)
282 }
283
284 async fn set_times(
285 &mut self,
286 self_: Resource<Descriptor>,
287 data_access_timestamp: NewTimestamp,
288 data_modification_timestamp: NewTimestamp,
289 ) -> wasmtime::Result<Result<(), FsErrorCode>> {
290 convert_result(
291 latest::filesystem::types::HostDescriptor::set_times(
292 self,
293 self_,
294 data_access_timestamp.into(),
295 data_modification_timestamp.into(),
296 )
297 .await,
298 )
299 }
300
301 async fn read(
302 &mut self,
303 self_: Resource<Descriptor>,
304 length: Filesize,
305 offset: Filesize,
306 ) -> wasmtime::Result<Result<(Vec<u8>, bool), FsErrorCode>> {
307 convert_result(
308 latest::filesystem::types::HostDescriptor::read(self, self_, length, offset).await,
309 )
310 }
311
312 async fn write(
313 &mut self,
314 self_: Resource<Descriptor>,
315 buffer: Vec<u8>,
316 offset: Filesize,
317 ) -> wasmtime::Result<Result<Filesize, FsErrorCode>> {
318 convert_result(
319 latest::filesystem::types::HostDescriptor::write(self, self_, buffer, offset).await,
320 )
321 }
322
323 async fn read_directory(
324 &mut self,
325 self_: Resource<Descriptor>,
326 ) -> wasmtime::Result<Result<Resource<DirectoryEntryStream>, FsErrorCode>> {
327 convert_result(latest::filesystem::types::HostDescriptor::read_directory(self, self_).await)
328 }
329
330 async fn sync(
331 &mut self,
332 self_: Resource<Descriptor>,
333 ) -> wasmtime::Result<Result<(), FsErrorCode>> {
334 convert_result(latest::filesystem::types::HostDescriptor::sync(self, self_).await)
335 }
336
337 async fn create_directory_at(
338 &mut self,
339 self_: Resource<Descriptor>,
340 path: String,
341 ) -> wasmtime::Result<Result<(), FsErrorCode>> {
342 convert_result(
343 latest::filesystem::types::HostDescriptor::create_directory_at(self, self_, path).await,
344 )
345 }
346
347 async fn stat(
348 &mut self,
349 self_: Resource<Descriptor>,
350 ) -> wasmtime::Result<Result<DescriptorStat, FsErrorCode>> {
351 convert_result(latest::filesystem::types::HostDescriptor::stat(self, self_).await)
352 }
353
354 async fn stat_at(
355 &mut self,
356 self_: Resource<Descriptor>,
357 path_flags: PathFlags,
358 path: String,
359 ) -> wasmtime::Result<Result<DescriptorStat, FsErrorCode>> {
360 convert_result(
361 latest::filesystem::types::HostDescriptor::stat_at(
362 self,
363 self_,
364 path_flags.into(),
365 path,
366 )
367 .await,
368 )
369 }
370
371 async fn set_times_at(
372 &mut self,
373 self_: Resource<Descriptor>,
374 path_flags: PathFlags,
375 path: String,
376 data_access_timestamp: NewTimestamp,
377 data_modification_timestamp: NewTimestamp,
378 ) -> wasmtime::Result<Result<(), FsErrorCode>> {
379 convert_result(
380 latest::filesystem::types::HostDescriptor::set_times_at(
381 self,
382 self_,
383 path_flags.into(),
384 path,
385 data_access_timestamp.into(),
386 data_modification_timestamp.into(),
387 )
388 .await,
389 )
390 }
391
392 async fn link_at(
393 &mut self,
394 self_: Resource<Descriptor>,
395 old_path_flags: PathFlags,
396 old_path: String,
397 new_descriptor: Resource<Descriptor>,
398 new_path: String,
399 ) -> wasmtime::Result<Result<(), FsErrorCode>> {
400 convert_result(
401 latest::filesystem::types::HostDescriptor::link_at(
402 self,
403 self_,
404 old_path_flags.into(),
405 old_path,
406 new_descriptor,
407 new_path,
408 )
409 .await,
410 )
411 }
412
413 async fn open_at(
414 &mut self,
415 self_: Resource<Descriptor>,
416 path_flags: PathFlags,
417 path: String,
418 open_flags: OpenFlags,
419 flags: DescriptorFlags,
420 _modes: Modes,
421 ) -> wasmtime::Result<Result<Resource<Descriptor>, FsErrorCode>> {
422 convert_result(
423 latest::filesystem::types::HostDescriptor::open_at(
424 self,
425 self_,
426 path_flags.into(),
427 path,
428 open_flags.into(),
429 flags.into(),
430 )
431 .await,
432 )
433 }
434
435 async fn readlink_at(
436 &mut self,
437 self_: Resource<Descriptor>,
438 path: String,
439 ) -> wasmtime::Result<Result<String, FsErrorCode>> {
440 convert_result(
441 latest::filesystem::types::HostDescriptor::readlink_at(self, self_, path).await,
442 )
443 }
444
445 async fn remove_directory_at(
446 &mut self,
447 self_: Resource<Descriptor>,
448 path: String,
449 ) -> wasmtime::Result<Result<(), FsErrorCode>> {
450 convert_result(
451 latest::filesystem::types::HostDescriptor::remove_directory_at(self, self_, path).await,
452 )
453 }
454
455 async fn rename_at(
456 &mut self,
457 self_: Resource<Descriptor>,
458 old_path: String,
459 new_descriptor: Resource<Descriptor>,
460 new_path: String,
461 ) -> wasmtime::Result<Result<(), FsErrorCode>> {
462 convert_result(
463 latest::filesystem::types::HostDescriptor::rename_at(
464 self,
465 self_,
466 old_path,
467 new_descriptor,
468 new_path,
469 )
470 .await,
471 )
472 }
473
474 async fn symlink_at(
475 &mut self,
476 self_: Resource<Descriptor>,
477 old_path: String,
478 new_path: String,
479 ) -> wasmtime::Result<Result<(), FsErrorCode>> {
480 convert_result(
481 latest::filesystem::types::HostDescriptor::symlink_at(self, self_, old_path, new_path)
482 .await,
483 )
484 }
485
486 async fn access_at(
487 &mut self,
488 _self_: Resource<Descriptor>,
489 _path_flags: PathFlags,
490 _path: String,
491 _type_: AccessType,
492 ) -> wasmtime::Result<Result<(), FsErrorCode>> {
493 wasmtime::bail!("access-at API is no longer supported in the latest snapshot")
494 }
495
496 async fn unlink_file_at(
497 &mut self,
498 self_: Resource<Descriptor>,
499 path: String,
500 ) -> wasmtime::Result<Result<(), FsErrorCode>> {
501 convert_result(
502 latest::filesystem::types::HostDescriptor::unlink_file_at(self, self_, path).await,
503 )
504 }
505
506 async fn change_file_permissions_at(
507 &mut self,
508 _self_: Resource<Descriptor>,
509 _path_flags: PathFlags,
510 _path: String,
511 _modes: Modes,
512 ) -> wasmtime::Result<Result<(), FsErrorCode>> {
513 wasmtime::bail!(
514 "change-file-permissions-at API is no longer supported in the latest snapshot"
515 )
516 }
517
518 async fn change_directory_permissions_at(
519 &mut self,
520 _self_: Resource<Descriptor>,
521 _path_flags: PathFlags,
522 _path: String,
523 _modes: Modes,
524 ) -> wasmtime::Result<Result<(), FsErrorCode>> {
525 wasmtime::bail!(
526 "change-directory-permissions-at API is no longer supported in the latest snapshot"
527 )
528 }
529
530 async fn lock_shared(
531 &mut self,
532 _self_: Resource<Descriptor>,
533 ) -> wasmtime::Result<Result<(), FsErrorCode>> {
534 wasmtime::bail!("lock-shared API is no longer supported in the latest snapshot")
535 }
536
537 async fn lock_exclusive(
538 &mut self,
539 _self_: Resource<Descriptor>,
540 ) -> wasmtime::Result<Result<(), FsErrorCode>> {
541 wasmtime::bail!("lock-exclusive API is no longer supported in the latest snapshot")
542 }
543
544 async fn try_lock_shared(
545 &mut self,
546 _self_: Resource<Descriptor>,
547 ) -> wasmtime::Result<Result<(), FsErrorCode>> {
548 wasmtime::bail!("try-lock-shared API is no longer supported in the latest snapshot")
549 }
550
551 async fn try_lock_exclusive(
552 &mut self,
553 _self_: Resource<Descriptor>,
554 ) -> wasmtime::Result<Result<(), FsErrorCode>> {
555 wasmtime::bail!("try-lock-exclusive API is no longer supported in the latest snapshot")
556 }
557
558 async fn unlock(
559 &mut self,
560 _self_: Resource<Descriptor>,
561 ) -> wasmtime::Result<Result<(), FsErrorCode>> {
562 wasmtime::bail!("unlock API is no longer supported in the latest snapshot")
563 }
564
565 async fn is_same_object(
566 &mut self,
567 self_: Resource<Descriptor>,
568 other: Resource<Descriptor>,
569 ) -> wasmtime::Result<bool> {
570 latest::filesystem::types::HostDescriptor::is_same_object(self, self_, other).await
571 }
572
573 async fn metadata_hash(
574 &mut self,
575 self_: Resource<Descriptor>,
576 ) -> wasmtime::Result<Result<MetadataHashValue, FsErrorCode>> {
577 convert_result(latest::filesystem::types::HostDescriptor::metadata_hash(self, self_).await)
578 }
579
580 async fn metadata_hash_at(
581 &mut self,
582 self_: Resource<Descriptor>,
583 path_flags: PathFlags,
584 path: String,
585 ) -> wasmtime::Result<Result<MetadataHashValue, FsErrorCode>> {
586 convert_result(
587 latest::filesystem::types::HostDescriptor::metadata_hash_at(
588 self,
589 self_,
590 path_flags.into(),
591 path,
592 )
593 .await,
594 )
595 }
596
597 fn drop(&mut self, rep: Resource<Descriptor>) -> wasmtime::Result<()> {
598 latest::filesystem::types::HostDescriptor::drop(self, rep)
599 }
600}
601
602impl wasi::filesystem::types::HostDirectoryEntryStream for WasiFilesystemCtxView<'_> {
603 async fn read_directory_entry(
604 &mut self,
605 self_: Resource<DirectoryEntryStream>,
606 ) -> wasmtime::Result<Result<Option<DirectoryEntry>, FsErrorCode>> {
607 convert_result(
608 latest::filesystem::types::HostDirectoryEntryStream::read_directory_entry(self, self_)
609 .await
610 .map(|e| e.map(DirectoryEntry::from)),
611 )
612 }
613
614 fn drop(&mut self, rep: Resource<DirectoryEntryStream>) -> wasmtime::Result<()> {
615 latest::filesystem::types::HostDirectoryEntryStream::drop(self, rep)
616 }
617}
618
619impl wasi::filesystem::preopens::Host for WasiFilesystemCtxView<'_> {
620 fn get_directories(&mut self) -> wasmtime::Result<Vec<(Resource<Descriptor>, String)>> {
621 latest::filesystem::preopens::Host::get_directories(self)
622 }
623}
624
625impl wasi::io::poll::Host for ResourceTable {
626 async fn poll_list(&mut self, list: Vec<Resource<DynPollable>>) -> wasmtime::Result<Vec<u32>> {
627 latest::io::poll::Host::poll(self, list).await
628 }
629
630 async fn poll_one(&mut self, rep: Resource<DynPollable>) -> wasmtime::Result<()> {
631 latest::io::poll::HostPollable::block(self, rep).await
632 }
633}
634
635impl wasi::io::poll::HostPollable for ResourceTable {
636 fn drop(&mut self, rep: Resource<DynPollable>) -> wasmtime::Result<()> {
637 latest::io::poll::HostPollable::drop(self, rep)
638 }
639}
640
641impl wasi::io::streams::Host for ResourceTable {}
642
643impl wasi::io::streams::HostError for ResourceTable {
644 fn to_debug_string(&mut self, self_: Resource<Error>) -> wasmtime::Result<String> {
645 latest::io::error::HostError::to_debug_string(self, self_)
646 }
647
648 fn drop(&mut self, rep: Resource<Error>) -> wasmtime::Result<()> {
649 latest::io::error::HostError::drop(self, rep)
650 }
651}
652
653impl wasi::io::streams::HostInputStream for ResourceTable {
654 fn read(
655 &mut self,
656 self_: Resource<InputStream>,
657 len: u64,
658 ) -> wasmtime::Result<Result<Vec<u8>, StreamError>> {
659 let result = latest::io::streams::HostInputStream::read(self, self_, len);
660 convert_stream_result(self, result)
661 }
662
663 async fn blocking_read(
664 &mut self,
665 self_: Resource<InputStream>,
666 len: u64,
667 ) -> wasmtime::Result<Result<Vec<u8>, StreamError>> {
668 let result = latest::io::streams::HostInputStream::blocking_read(self, self_, len).await;
669 convert_stream_result(self, result)
670 }
671
672 fn skip(
673 &mut self,
674 self_: Resource<InputStream>,
675 len: u64,
676 ) -> wasmtime::Result<Result<u64, StreamError>> {
677 let result = latest::io::streams::HostInputStream::skip(self, self_, len);
678 convert_stream_result(self, result)
679 }
680
681 async fn blocking_skip(
682 &mut self,
683 self_: Resource<InputStream>,
684 len: u64,
685 ) -> wasmtime::Result<Result<u64, StreamError>> {
686 let result = latest::io::streams::HostInputStream::blocking_skip(self, self_, len).await;
687 convert_stream_result(self, result)
688 }
689
690 fn subscribe(
691 &mut self,
692 self_: Resource<InputStream>,
693 ) -> wasmtime::Result<Resource<DynPollable>> {
694 latest::io::streams::HostInputStream::subscribe(self, self_)
695 }
696
697 async fn drop(&mut self, rep: Resource<InputStream>) -> wasmtime::Result<()> {
698 latest::io::streams::HostInputStream::drop(self, rep).await
699 }
700}
701
702impl wasi::io::streams::HostOutputStream for ResourceTable {
703 fn check_write(
704 &mut self,
705 self_: Resource<OutputStream>,
706 ) -> wasmtime::Result<Result<u64, StreamError>> {
707 let result = latest::io::streams::HostOutputStream::check_write(self, self_);
708 convert_stream_result(self, result)
709 }
710
711 fn write(
712 &mut self,
713 self_: Resource<OutputStream>,
714 contents: Vec<u8>,
715 ) -> wasmtime::Result<Result<(), StreamError>> {
716 let result = latest::io::streams::HostOutputStream::write(self, self_, contents);
717 convert_stream_result(self, result)
718 }
719
720 async fn blocking_write_and_flush(
721 &mut self,
722 self_: Resource<OutputStream>,
723 contents: Vec<u8>,
724 ) -> wasmtime::Result<Result<(), StreamError>> {
725 let result =
726 latest::io::streams::HostOutputStream::blocking_write_and_flush(self, self_, contents)
727 .await;
728 convert_stream_result(self, result)
729 }
730
731 fn flush(
732 &mut self,
733 self_: Resource<OutputStream>,
734 ) -> wasmtime::Result<Result<(), StreamError>> {
735 let result = latest::io::streams::HostOutputStream::flush(self, self_);
736 convert_stream_result(self, result)
737 }
738
739 async fn blocking_flush(
740 &mut self,
741 self_: Resource<OutputStream>,
742 ) -> wasmtime::Result<Result<(), StreamError>> {
743 let result = latest::io::streams::HostOutputStream::blocking_flush(self, self_).await;
744 convert_stream_result(self, result)
745 }
746
747 fn subscribe(
748 &mut self,
749 self_: Resource<OutputStream>,
750 ) -> wasmtime::Result<Resource<DynPollable>> {
751 latest::io::streams::HostOutputStream::subscribe(self, self_)
752 }
753
754 fn write_zeroes(
755 &mut self,
756 self_: Resource<OutputStream>,
757 len: u64,
758 ) -> wasmtime::Result<Result<(), StreamError>> {
759 let result = latest::io::streams::HostOutputStream::write_zeroes(self, self_, len);
760 convert_stream_result(self, result)
761 }
762
763 async fn blocking_write_zeroes_and_flush(
764 &mut self,
765 self_: Resource<OutputStream>,
766 len: u64,
767 ) -> wasmtime::Result<Result<(), StreamError>> {
768 let result = latest::io::streams::HostOutputStream::blocking_write_zeroes_and_flush(
769 self, self_, len,
770 )
771 .await;
772 convert_stream_result(self, result)
773 }
774
775 fn splice(
776 &mut self,
777 self_: Resource<OutputStream>,
778 src: Resource<InputStream>,
779 len: u64,
780 ) -> wasmtime::Result<Result<u64, StreamError>> {
781 let result = latest::io::streams::HostOutputStream::splice(self, self_, src, len);
782 convert_stream_result(self, result)
783 }
784
785 async fn blocking_splice(
786 &mut self,
787 self_: Resource<OutputStream>,
788 src: Resource<InputStream>,
789 len: u64,
790 ) -> wasmtime::Result<Result<u64, StreamError>> {
791 let result =
792 latest::io::streams::HostOutputStream::blocking_splice(self, self_, src, len).await;
793 convert_stream_result(self, result)
794 }
795
796 async fn forward(
797 &mut self,
798 _self_: Resource<OutputStream>,
799 _src: Resource<InputStream>,
800 ) -> wasmtime::Result<Result<u64, StreamError>> {
801 wasmtime::bail!("forward API no longer supported")
802 }
803
804 async fn drop(&mut self, rep: Resource<OutputStream>) -> wasmtime::Result<()> {
805 latest::io::streams::HostOutputStream::drop(self, rep).await
806 }
807}
808
809impl wasi::random::random::Host for WasiRandomCtx {
810 fn get_random_bytes(&mut self, len: u64) -> wasmtime::Result<Vec<u8>> {
811 latest::random::random::Host::get_random_bytes(self, len)
812 }
813
814 fn get_random_u64(&mut self) -> wasmtime::Result<u64> {
815 latest::random::random::Host::get_random_u64(self)
816 }
817}
818
819impl wasi::random::insecure::Host for WasiRandomCtx {
820 fn get_insecure_random_bytes(&mut self, len: u64) -> wasmtime::Result<Vec<u8>> {
821 latest::random::insecure::Host::get_insecure_random_bytes(self, len)
822 }
823
824 fn get_insecure_random_u64(&mut self) -> wasmtime::Result<u64> {
825 latest::random::insecure::Host::get_insecure_random_u64(self)
826 }
827}
828
829impl wasi::random::insecure_seed::Host for WasiRandomCtx {
830 fn insecure_seed(&mut self) -> wasmtime::Result<(u64, u64)> {
831 latest::random::insecure_seed::Host::insecure_seed(self)
832 }
833}
834
835impl wasi::cli::exit::Host for WasiCliCtxView<'_> {
836 fn exit(&mut self, status: Result<(), ()>) -> wasmtime::Result<()> {
837 latest::cli::exit::Host::exit(self, status)
838 }
839}
840
841impl wasi::cli::environment::Host for WasiCliCtxView<'_> {
842 fn get_environment(&mut self) -> wasmtime::Result<Vec<(String, String)>> {
843 latest::cli::environment::Host::get_environment(self)
844 }
845
846 fn get_arguments(&mut self) -> wasmtime::Result<Vec<String>> {
847 latest::cli::environment::Host::get_arguments(self)
848 }
849
850 fn initial_cwd(&mut self) -> wasmtime::Result<Option<String>> {
851 latest::cli::environment::Host::initial_cwd(self)
852 }
853}
854
855impl wasi::cli::stdin::Host for WasiCliCtxView<'_> {
856 fn get_stdin(&mut self) -> wasmtime::Result<Resource<InputStream>> {
857 latest::cli::stdin::Host::get_stdin(self)
858 }
859}
860
861impl wasi::cli::stdout::Host for WasiCliCtxView<'_> {
862 fn get_stdout(&mut self) -> wasmtime::Result<Resource<OutputStream>> {
863 latest::cli::stdout::Host::get_stdout(self)
864 }
865}
866
867impl wasi::cli::stderr::Host for WasiCliCtxView<'_> {
868 fn get_stderr(&mut self) -> wasmtime::Result<Resource<OutputStream>> {
869 latest::cli::stderr::Host::get_stderr(self)
870 }
871}
872
873impl wasi::cli::terminal_stdin::Host for WasiCliCtxView<'_> {
874 fn get_terminal_stdin(&mut self) -> wasmtime::Result<Option<Resource<TerminalInput>>> {
875 latest::cli::terminal_stdin::Host::get_terminal_stdin(self)
876 }
877}
878
879impl wasi::cli::terminal_stdout::Host for WasiCliCtxView<'_> {
880 fn get_terminal_stdout(&mut self) -> wasmtime::Result<Option<Resource<TerminalOutput>>> {
881 latest::cli::terminal_stdout::Host::get_terminal_stdout(self)
882 }
883}
884
885impl wasi::cli::terminal_stderr::Host for WasiCliCtxView<'_> {
886 fn get_terminal_stderr(&mut self) -> wasmtime::Result<Option<Resource<TerminalOutput>>> {
887 latest::cli::terminal_stderr::Host::get_terminal_stderr(self)
888 }
889}
890
891impl wasi::cli::terminal_input::Host for WasiCliCtxView<'_> {}
892
893impl wasi::cli::terminal_input::HostTerminalInput for WasiCliCtxView<'_> {
894 fn drop(&mut self, rep: Resource<TerminalInput>) -> wasmtime::Result<()> {
895 latest::cli::terminal_input::HostTerminalInput::drop(self, rep)
896 }
897}
898
899impl wasi::cli::terminal_output::Host for WasiCliCtxView<'_> {}
900
901impl wasi::cli::terminal_output::HostTerminalOutput for WasiCliCtxView<'_> {
902 fn drop(&mut self, rep: Resource<TerminalOutput>) -> wasmtime::Result<()> {
903 latest::cli::terminal_output::HostTerminalOutput::drop(self, rep)
904 }
905}
906
907impl<T> wasi::sockets::tcp::Host for SpinSocketsView<'_, T> {}
908
909impl<T> wasi::sockets::tcp::HostTcpSocket for SpinSocketsView<'_, T> {
910 async fn start_bind(
911 &mut self,
912 self_: Resource<TcpSocket>,
913 network: Resource<Network>,
914 local_address: IpSocketAddress,
915 ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
916 convert_result(
917 latest::sockets::tcp::HostTcpSocket::start_bind(
918 self,
919 self_,
920 network,
921 local_address.into(),
922 )
923 .await,
924 )
925 }
926
927 fn finish_bind(
928 &mut self,
929 self_: Resource<TcpSocket>,
930 ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
931 convert_result(latest::sockets::tcp::HostTcpSocket::finish_bind(
932 self, self_,
933 ))
934 }
935
936 async fn start_connect(
937 &mut self,
938 self_: Resource<TcpSocket>,
939 network: Resource<Network>,
940 remote_address: IpSocketAddress,
941 ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
942 convert_result(latest::sockets::tcp::HostTcpSocket::start_connect(
947 self,
948 self_,
949 network,
950 remote_address.into(),
951 ))
952 }
953
954 fn finish_connect(
955 &mut self,
956 self_: Resource<TcpSocket>,
957 ) -> wasmtime::Result<Result<(Resource<InputStream>, Resource<OutputStream>), SocketErrorCode>>
958 {
959 convert_result(latest::sockets::tcp::HostTcpSocket::finish_connect(
960 self, self_,
961 ))
962 }
963
964 async fn start_listen(
965 &mut self,
966 self_: Resource<TcpSocket>,
967 ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
968 convert_result(latest::sockets::tcp::HostTcpSocket::start_listen(self, self_).await)
969 }
970
971 fn finish_listen(
972 &mut self,
973 self_: Resource<TcpSocket>,
974 ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
975 convert_result(latest::sockets::tcp::HostTcpSocket::finish_listen(
976 self, self_,
977 ))
978 }
979
980 fn accept(
981 &mut self,
982 self_: Resource<TcpSocket>,
983 ) -> wasmtime::Result<
984 Result<
985 (
986 Resource<TcpSocket>,
987 Resource<InputStream>,
988 Resource<OutputStream>,
989 ),
990 SocketErrorCode,
991 >,
992 > {
993 convert_result(latest::sockets::tcp::HostTcpSocket::accept(self, self_))
994 }
995
996 fn local_address(
997 &mut self,
998 self_: Resource<TcpSocket>,
999 ) -> wasmtime::Result<Result<IpSocketAddress, SocketErrorCode>> {
1000 convert_result(latest::sockets::tcp::HostTcpSocket::local_address(
1001 self, self_,
1002 ))
1003 }
1004
1005 fn remote_address(
1006 &mut self,
1007 self_: Resource<TcpSocket>,
1008 ) -> wasmtime::Result<Result<IpSocketAddress, SocketErrorCode>> {
1009 convert_result(latest::sockets::tcp::HostTcpSocket::remote_address(
1010 self, self_,
1011 ))
1012 }
1013
1014 fn address_family(&mut self, self_: Resource<TcpSocket>) -> wasmtime::Result<IpAddressFamily> {
1015 latest::sockets::tcp::HostTcpSocket::address_family(self, self_).map(|e| e.into())
1016 }
1017
1018 fn ipv6_only(
1019 &mut self,
1020 _self_: Resource<TcpSocket>,
1021 ) -> wasmtime::Result<Result<bool, SocketErrorCode>> {
1022 wasmtime::bail!("ipv6-only API no longer supported")
1023 }
1024
1025 fn set_ipv6_only(
1026 &mut self,
1027 _self_: Resource<TcpSocket>,
1028 _value: bool,
1029 ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1030 wasmtime::bail!("ipv6-only API no longer supported")
1031 }
1032
1033 fn set_listen_backlog_size(
1034 &mut self,
1035 self_: Resource<TcpSocket>,
1036 value: u64,
1037 ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1038 convert_result(
1039 latest::sockets::tcp::HostTcpSocket::set_listen_backlog_size(self, self_, value),
1040 )
1041 }
1042
1043 fn keep_alive(
1044 &mut self,
1045 self_: Resource<TcpSocket>,
1046 ) -> wasmtime::Result<Result<bool, SocketErrorCode>> {
1047 convert_result(latest::sockets::tcp::HostTcpSocket::keep_alive_enabled(
1048 self, self_,
1049 ))
1050 }
1051
1052 fn set_keep_alive(
1053 &mut self,
1054 self_: Resource<TcpSocket>,
1055 value: bool,
1056 ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1057 convert_result(latest::sockets::tcp::HostTcpSocket::set_keep_alive_enabled(
1058 self, self_, value,
1059 ))
1060 }
1061
1062 fn no_delay(
1063 &mut self,
1064 _self_: Resource<TcpSocket>,
1065 ) -> wasmtime::Result<Result<bool, SocketErrorCode>> {
1066 wasmtime::bail!("no-delay API no longer supported")
1067 }
1068
1069 fn set_no_delay(
1070 &mut self,
1071 _self_: Resource<TcpSocket>,
1072 _value: bool,
1073 ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1074 wasmtime::bail!("set-no-delay API no longer supported")
1075 }
1076
1077 fn unicast_hop_limit(
1078 &mut self,
1079 self_: Resource<TcpSocket>,
1080 ) -> wasmtime::Result<Result<u8, SocketErrorCode>> {
1081 convert_result(latest::sockets::tcp::HostTcpSocket::hop_limit(self, self_))
1082 }
1083
1084 fn set_unicast_hop_limit(
1085 &mut self,
1086 self_: Resource<TcpSocket>,
1087 value: u8,
1088 ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1089 convert_result(latest::sockets::tcp::HostTcpSocket::set_hop_limit(
1090 self, self_, value,
1091 ))
1092 }
1093
1094 fn receive_buffer_size(
1095 &mut self,
1096 self_: Resource<TcpSocket>,
1097 ) -> wasmtime::Result<Result<u64, SocketErrorCode>> {
1098 convert_result(latest::sockets::tcp::HostTcpSocket::receive_buffer_size(
1099 self, self_,
1100 ))
1101 }
1102
1103 fn set_receive_buffer_size(
1104 &mut self,
1105 self_: Resource<TcpSocket>,
1106 value: u64,
1107 ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1108 convert_result(
1109 latest::sockets::tcp::HostTcpSocket::set_receive_buffer_size(self, self_, value),
1110 )
1111 }
1112
1113 fn send_buffer_size(
1114 &mut self,
1115 self_: Resource<TcpSocket>,
1116 ) -> wasmtime::Result<Result<u64, SocketErrorCode>> {
1117 convert_result(latest::sockets::tcp::HostTcpSocket::send_buffer_size(
1118 self, self_,
1119 ))
1120 }
1121
1122 fn set_send_buffer_size(
1123 &mut self,
1124 self_: Resource<TcpSocket>,
1125 value: u64,
1126 ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1127 convert_result(latest::sockets::tcp::HostTcpSocket::set_send_buffer_size(
1128 self, self_, value,
1129 ))
1130 }
1131
1132 fn subscribe(&mut self, self_: Resource<TcpSocket>) -> wasmtime::Result<Resource<DynPollable>> {
1133 latest::sockets::tcp::HostTcpSocket::subscribe(self, self_)
1134 }
1135
1136 fn shutdown(
1137 &mut self,
1138 self_: Resource<TcpSocket>,
1139 shutdown_type: ShutdownType,
1140 ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1141 convert_result(latest::sockets::tcp::HostTcpSocket::shutdown(
1142 self,
1143 self_,
1144 shutdown_type.into(),
1145 ))
1146 }
1147
1148 fn drop(&mut self, rep: Resource<TcpSocket>) -> wasmtime::Result<()> {
1149 latest::sockets::tcp::HostTcpSocket::drop(self, rep)
1150 }
1151}
1152
1153impl<T> wasi::sockets::tcp_create_socket::Host for SpinSocketsView<'_, T> {
1154 fn create_tcp_socket(
1155 &mut self,
1156 address_family: IpAddressFamily,
1157 ) -> wasmtime::Result<Result<Resource<TcpSocket>, SocketErrorCode>> {
1158 convert_result(latest::sockets::tcp_create_socket::Host::create_tcp_socket(
1159 self,
1160 address_family.into(),
1161 ))
1162 }
1163}
1164
1165impl<T> wasi::sockets::udp::Host for SpinSocketsView<'_, T> {}
1166
1167pub enum UdpSocket {
1174 Initial(Resource<latest::sockets::udp::UdpSocket>),
1175 Connecting(Resource<latest::sockets::udp::UdpSocket>, IpSocketAddress),
1176 Connected {
1177 socket: Resource<latest::sockets::udp::UdpSocket>,
1178 incoming: Resource<latest::sockets::udp::IncomingDatagramStream>,
1179 outgoing: Resource<latest::sockets::udp::OutgoingDatagramStream>,
1180 },
1181 Dummy,
1182}
1183
1184impl UdpSocket {
1185 async fn finish_connect<T>(
1186 table: &mut SpinSocketsView<'_, T>,
1187 socket: &Resource<UdpSocket>,
1188 explicit: bool,
1189 ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1190 let state = table.table.get_mut(socket)?;
1191 let (new_socket, addr) = match mem::replace(state, UdpSocket::Dummy) {
1192 UdpSocket::Initial(socket) if !explicit => (socket, None),
1195 UdpSocket::Connected { .. } if !explicit => return Ok(Ok(())),
1197 UdpSocket::Connecting(socket, addr) if explicit => (socket, Some(addr)),
1199 _ => return Ok(Err(SocketErrorCode::ConcurrencyConflict)),
1200 };
1201 let borrow = Resource::new_borrow(new_socket.rep());
1202 let result = convert_result(
1203 latest::sockets::udp::HostUdpSocket::stream(
1204 &mut table.inner,
1205 borrow,
1206 addr.map(|a| a.into()),
1207 )
1208 .await,
1209 )?;
1210 let (incoming, outgoing) = match result {
1211 Ok(pair) => pair,
1212 Err(e) => return Ok(Err(e)),
1213 };
1214 *table.table.get_mut(socket)? = UdpSocket::Connected {
1215 socket: new_socket,
1216 incoming,
1217 outgoing,
1218 };
1219 Ok(Ok(()))
1220 }
1221
1222 fn inner(&self) -> wasmtime::Result<Resource<latest::sockets::udp::UdpSocket>> {
1223 let r = match self {
1224 UdpSocket::Initial(r) => r,
1225 UdpSocket::Connecting(r, _) => r,
1226 UdpSocket::Connected { socket, .. } => socket,
1227 UdpSocket::Dummy => wasmtime::bail!("invalid udp socket state"),
1228 };
1229 Ok(Resource::new_borrow(r.rep()))
1230 }
1231}
1232
1233impl<T> wasi::sockets::udp::HostUdpSocket for SpinSocketsView<'_, T> {
1234 async fn start_bind(
1235 &mut self,
1236 self_: Resource<UdpSocket>,
1237 network: Resource<Network>,
1238 local_address: IpSocketAddress,
1239 ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1240 let socket = self.table.get(&self_)?.inner()?;
1241 convert_result(
1242 latest::sockets::udp::HostUdpSocket::start_bind(
1243 &mut self.inner,
1244 socket,
1245 network,
1246 local_address.into(),
1247 )
1248 .await,
1249 )
1250 }
1251
1252 fn finish_bind(
1253 &mut self,
1254 self_: Resource<UdpSocket>,
1255 ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1256 let socket = self.table.get(&self_)?.inner()?;
1257 convert_result(latest::sockets::udp::HostUdpSocket::finish_bind(
1258 &mut self.inner,
1259 socket,
1260 ))
1261 }
1262
1263 fn start_connect(
1264 &mut self,
1265 self_: Resource<UdpSocket>,
1266 _network: Resource<Network>,
1267 remote_address: IpSocketAddress,
1268 ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1269 let socket = self.table.get_mut(&self_)?;
1270 let (new_state, result) = match mem::replace(socket, UdpSocket::Dummy) {
1271 UdpSocket::Initial(socket) => (UdpSocket::Connecting(socket, remote_address), Ok(())),
1272 other => (other, Err(SocketErrorCode::ConcurrencyConflict)),
1273 };
1274 *socket = new_state;
1275 Ok(result)
1276 }
1277
1278 async fn finish_connect(
1279 &mut self,
1280 self_: Resource<UdpSocket>,
1281 ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1282 UdpSocket::finish_connect(self, &self_, true).await
1283 }
1284
1285 async fn receive(
1286 &mut self,
1287 self_: Resource<UdpSocket>,
1288 max_results: u64,
1289 ) -> wasmtime::Result<Result<Vec<Datagram>, SocketErrorCode>> {
1290 if let Err(e) = UdpSocket::finish_connect(self, &self_, true).await? {
1293 return Ok(Err(e));
1294 }
1295
1296 let incoming = match self.table.get(&self_)? {
1299 UdpSocket::Connected { incoming, .. } => Resource::new_borrow(incoming.rep()),
1300 _ => return Ok(Err(SocketErrorCode::ConcurrencyConflict)),
1301 };
1302 let result: Result<Vec<_>, _> = convert_result(
1303 latest::sockets::udp::HostIncomingDatagramStream::receive(self, incoming, max_results),
1304 )?;
1305 match result {
1306 Ok(datagrams) => Ok(Ok(datagrams
1307 .into_iter()
1308 .map(|datagram| datagram.into())
1309 .collect())),
1310 Err(e) => Ok(Err(e)),
1311 }
1312 }
1313
1314 async fn send(
1315 &mut self,
1316 self_: Resource<UdpSocket>,
1317 mut datagrams: Vec<Datagram>,
1318 ) -> wasmtime::Result<Result<u64, SocketErrorCode>> {
1319 if let Err(e) = UdpSocket::finish_connect(self, &self_, true).await? {
1322 return Ok(Err(e));
1323 }
1324
1325 let outgoing = match self.table.get(&self_)? {
1328 UdpSocket::Connected { outgoing, .. } => Resource::new_borrow(outgoing.rep()),
1329 _ => return Ok(Err(SocketErrorCode::ConcurrencyConflict)),
1330 };
1331
1332 let outgoing2 = Resource::new_borrow(outgoing.rep());
1335 match convert_result(
1336 latest::sockets::udp::HostOutgoingDatagramStream::check_send(self, outgoing2),
1337 )? {
1338 Ok(n) => {
1339 if datagrams.len() as u64 > n {
1340 datagrams.truncate(n as usize);
1341 }
1342 }
1343 Err(e) => return Ok(Err(e)),
1344 }
1345
1346 convert_result(latest::sockets::udp::HostOutgoingDatagramStream::send(
1348 self,
1349 outgoing,
1350 datagrams
1351 .into_iter()
1352 .map(|d| latest::sockets::udp::OutgoingDatagram {
1353 data: d.data,
1354 remote_address: Some(d.remote_address.into()),
1355 })
1356 .collect(),
1357 ))
1358 }
1359
1360 fn local_address(
1361 &mut self,
1362 self_: Resource<UdpSocket>,
1363 ) -> wasmtime::Result<Result<IpSocketAddress, SocketErrorCode>> {
1364 let socket = self.table.get(&self_)?.inner()?;
1365 convert_result(latest::sockets::udp::HostUdpSocket::local_address(
1366 &mut self.inner,
1367 socket,
1368 ))
1369 }
1370
1371 fn remote_address(
1372 &mut self,
1373 self_: Resource<UdpSocket>,
1374 ) -> wasmtime::Result<Result<IpSocketAddress, SocketErrorCode>> {
1375 let socket = self.table.get(&self_)?.inner()?;
1376 convert_result(latest::sockets::udp::HostUdpSocket::remote_address(
1377 &mut self.inner,
1378 socket,
1379 ))
1380 }
1381
1382 fn address_family(&mut self, self_: Resource<UdpSocket>) -> wasmtime::Result<IpAddressFamily> {
1383 let socket = self.table.get(&self_)?.inner()?;
1384 latest::sockets::udp::HostUdpSocket::address_family(&mut self.inner, socket)
1385 .map(|e| e.into())
1386 }
1387
1388 fn ipv6_only(
1389 &mut self,
1390 _self_: Resource<UdpSocket>,
1391 ) -> wasmtime::Result<Result<bool, SocketErrorCode>> {
1392 wasmtime::bail!("ipv6-only API no longer supported")
1393 }
1394
1395 fn set_ipv6_only(
1396 &mut self,
1397 _self_: Resource<UdpSocket>,
1398 _value: bool,
1399 ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1400 wasmtime::bail!("ipv6-only API no longer supported")
1401 }
1402
1403 fn unicast_hop_limit(
1404 &mut self,
1405 self_: Resource<UdpSocket>,
1406 ) -> wasmtime::Result<Result<u8, SocketErrorCode>> {
1407 let socket = self.table.get(&self_)?.inner()?;
1408 convert_result(latest::sockets::udp::HostUdpSocket::unicast_hop_limit(
1409 &mut self.inner,
1410 socket,
1411 ))
1412 }
1413
1414 fn set_unicast_hop_limit(
1415 &mut self,
1416 self_: Resource<UdpSocket>,
1417 value: u8,
1418 ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1419 let socket = self.table.get(&self_)?.inner()?;
1420 convert_result(latest::sockets::udp::HostUdpSocket::set_unicast_hop_limit(
1421 &mut self.inner,
1422 socket,
1423 value,
1424 ))
1425 }
1426
1427 fn receive_buffer_size(
1428 &mut self,
1429 self_: Resource<UdpSocket>,
1430 ) -> wasmtime::Result<Result<u64, SocketErrorCode>> {
1431 let socket = self.table.get(&self_)?.inner()?;
1432 convert_result(latest::sockets::udp::HostUdpSocket::receive_buffer_size(
1433 &mut self.inner,
1434 socket,
1435 ))
1436 }
1437
1438 fn set_receive_buffer_size(
1439 &mut self,
1440 self_: Resource<UdpSocket>,
1441 value: u64,
1442 ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1443 let socket = self.table.get(&self_)?.inner()?;
1444 convert_result(
1445 latest::sockets::udp::HostUdpSocket::set_receive_buffer_size(
1446 &mut self.inner,
1447 socket,
1448 value,
1449 ),
1450 )
1451 }
1452
1453 fn send_buffer_size(
1454 &mut self,
1455 self_: Resource<UdpSocket>,
1456 ) -> wasmtime::Result<Result<u64, SocketErrorCode>> {
1457 let socket = self.table.get(&self_)?.inner()?;
1458 convert_result(latest::sockets::udp::HostUdpSocket::send_buffer_size(
1459 &mut self.inner,
1460 socket,
1461 ))
1462 }
1463
1464 fn set_send_buffer_size(
1465 &mut self,
1466 self_: Resource<UdpSocket>,
1467 value: u64,
1468 ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1469 let socket = self.table.get(&self_)?.inner()?;
1470 convert_result(latest::sockets::udp::HostUdpSocket::set_send_buffer_size(
1471 &mut self.inner,
1472 socket,
1473 value,
1474 ))
1475 }
1476
1477 fn subscribe(&mut self, self_: Resource<UdpSocket>) -> wasmtime::Result<Resource<DynPollable>> {
1478 let socket = self.table.get(&self_)?.inner()?;
1479 latest::sockets::udp::HostUdpSocket::subscribe(&mut self.inner, socket)
1480 }
1481
1482 async fn drop(&mut self, rep: Resource<UdpSocket>) -> wasmtime::Result<()> {
1483 let socket_rep = rep.rep();
1484 let me = self.table.delete(rep)?;
1489 self.release_permit(socket_rep);
1490 let socket = match me {
1491 UdpSocket::Initial(s) => s,
1492 UdpSocket::Connecting(s, _) => s,
1493 UdpSocket::Connected {
1494 socket,
1495 incoming,
1496 outgoing,
1497 } => {
1498 latest::sockets::udp::HostIncomingDatagramStream::drop(&mut self.inner, incoming)
1499 .await?;
1500 latest::sockets::udp::HostOutgoingDatagramStream::drop(&mut self.inner, outgoing)
1501 .await?;
1502 socket
1503 }
1504 UdpSocket::Dummy => return Ok(()),
1505 };
1506 latest::sockets::udp::HostUdpSocket::drop(&mut self.inner, socket)
1508 }
1509}
1510
1511impl<T> wasi::sockets::udp_create_socket::Host for SpinSocketsView<'_, T> {
1512 async fn create_udp_socket(
1513 &mut self,
1514 address_family: IpAddressFamily,
1515 ) -> wasmtime::Result<Result<Resource<UdpSocket>, SocketErrorCode>> {
1516 let Ok(permit) = self.try_acquire() else {
1524 tracing::warn!("UDP socket creation refused: connection quota exhausted");
1525 return Ok(Err(SocketErrorCode::NewSocketLimit));
1526 };
1527 let result = convert_result(
1529 p2_udp_create::Host::create_udp_socket(&mut self.inner, address_family.into()).await,
1530 )?;
1531 let socket = match result {
1532 Ok(socket) => socket,
1533 Err(e) => return Ok(Err(e)),
1534 };
1535 let wrapped = self.table.push(UdpSocket::Initial(socket))?;
1536 self.register_permit(wrapped.rep(), permit);
1537 Ok(Ok(wrapped))
1538 }
1539}
1540
1541impl<T> wasi::sockets::instance_network::Host for SpinSocketsView<'_, T> {
1542 fn instance_network(&mut self) -> wasmtime::Result<Resource<Network>> {
1543 latest::sockets::instance_network::Host::instance_network(&mut self.inner)
1544 }
1545}
1546
1547impl<T> wasi::sockets::network::Host for SpinSocketsView<'_, T> {}
1548
1549impl<T> wasi::sockets::network::HostNetwork for SpinSocketsView<'_, T> {
1550 fn drop(&mut self, rep: Resource<Network>) -> wasmtime::Result<()> {
1551 latest::sockets::network::HostNetwork::drop(&mut self.inner, rep)
1552 }
1553}
1554
1555impl<T> wasi::sockets::ip_name_lookup::Host for SpinSocketsView<'_, T> {
1556 fn resolve_addresses(
1557 &mut self,
1558 network: Resource<Network>,
1559 name: String,
1560 _address_family: Option<IpAddressFamily>,
1561 _include_unavailable: bool,
1562 ) -> wasmtime::Result<Result<Resource<ResolveAddressStream>, SocketErrorCode>> {
1563 convert_result(latest::sockets::ip_name_lookup::Host::resolve_addresses(
1564 &mut self.inner,
1565 network,
1566 name,
1567 ))
1568 }
1569}
1570
1571impl<T> wasi::sockets::ip_name_lookup::HostResolveAddressStream for SpinSocketsView<'_, T> {
1572 fn resolve_next_address(
1573 &mut self,
1574 self_: Resource<ResolveAddressStream>,
1575 ) -> wasmtime::Result<Result<Option<IpAddress>, SocketErrorCode>> {
1576 convert_result(
1577 latest::sockets::ip_name_lookup::HostResolveAddressStream::resolve_next_address(
1578 &mut self.inner,
1579 self_,
1580 )
1581 .map(|e| e.map(|e| e.into())),
1582 )
1583 }
1584
1585 fn subscribe(
1586 &mut self,
1587 self_: Resource<ResolveAddressStream>,
1588 ) -> wasmtime::Result<Resource<DynPollable>> {
1589 latest::sockets::ip_name_lookup::HostResolveAddressStream::subscribe(&mut self.inner, self_)
1590 }
1591
1592 async fn drop(&mut self, rep: Resource<ResolveAddressStream>) -> wasmtime::Result<()> {
1593 latest::sockets::ip_name_lookup::HostResolveAddressStream::drop(&mut self.inner, rep).await
1594 }
1595}
1596
1597pub fn convert_result<T, T2, E, E2>(
1598 result: Result<T, TrappableError<E>>,
1599) -> wasmtime::Result<Result<T2, E2>>
1600where
1601 T2: From<T>,
1602 E: std::error::Error + Send + Sync + 'static,
1603 E2: From<E>,
1604{
1605 match result {
1606 Ok(e) => Ok(Ok(e.into())),
1607 Err(e) => Ok(Err(e.downcast()?.into())),
1608 }
1609}
1610
1611fn convert_stream_result<T, T2>(
1612 table: &mut ResourceTable,
1613 result: Result<T, wasmtime_wasi::p2::StreamError>,
1614) -> wasmtime::Result<Result<T2, StreamError>>
1615where
1616 T2: From<T>,
1617{
1618 match result {
1619 Ok(e) => Ok(Ok(e.into())),
1620 Err(wasmtime_wasi::p2::StreamError::Closed) => Ok(Err(StreamError::Closed)),
1621 Err(wasmtime_wasi::p2::StreamError::LastOperationFailed(e)) => {
1622 let e = table.push(e)?;
1623 Ok(Err(StreamError::LastOperationFailed(e)))
1624 }
1625 Err(wasmtime_wasi::p2::StreamError::Trap(e)) => Err(e),
1626 }
1627}
1628
1629#[macro_export]
1630macro_rules! convert {
1631 () => {};
1632 ($kind:ident $from:path [<=>] $to:path { $($body:tt)* } $($rest:tt)*) => {
1633 convert!($kind $from => $to { $($body)* });
1634 convert!($kind $to => $from { $($body)* });
1635
1636 convert!($($rest)*);
1637 };
1638 (struct $from:ty => $to:path { $($field:ident,)* } $($rest:tt)*) => {
1639 impl From<$from> for $to {
1640 fn from(e: $from) -> $to {
1641 $to {
1642 $( $field: e.$field.into(), )*
1643 }
1644 }
1645 }
1646
1647 convert!($($rest)*);
1648 };
1649 (enum $from:path => $to:path { $($variant:ident $(($e:ident))?,)* } $($rest:tt)*) => {
1650 impl From<$from> for $to {
1651 fn from(e: $from) -> $to {
1652 use $from as A;
1653 use $to as B;
1654 match e {
1655 $(
1656 A::$variant $(($e))? => B::$variant $(($e.into()))?,
1657 )*
1658 }
1659 }
1660 }
1661
1662 convert!($($rest)*);
1663 };
1664 (flags $from:path => $to:path { $($flag:ident,)* } $($rest:tt)*) => {
1665 impl From<$from> for $to {
1666 fn from(e: $from) -> $to {
1667 use $from as A;
1668 use $to as B;
1669 let mut out = B::empty();
1670 $(
1671 if e.contains(A::$flag) {
1672 out |= B::$flag;
1673 }
1674 )*
1675 out
1676 }
1677 }
1678
1679 convert!($($rest)*);
1680 };
1681}
1682
1683convert! {
1684 struct latest::clocks::wall_clock::Datetime [<=>] Datetime {
1685 seconds,
1686 nanoseconds,
1687 }
1688
1689 enum latest::filesystem::types::ErrorCode => FsErrorCode {
1690 Access,
1691 WouldBlock,
1692 Already,
1693 BadDescriptor,
1694 Busy,
1695 Deadlock,
1696 Quota,
1697 Exist,
1698 FileTooLarge,
1699 IllegalByteSequence,
1700 InProgress,
1701 Interrupted,
1702 Invalid,
1703 Io,
1704 IsDirectory,
1705 Loop,
1706 TooManyLinks,
1707 MessageSize,
1708 NameTooLong,
1709 NoDevice,
1710 NoEntry,
1711 NoLock,
1712 InsufficientMemory,
1713 InsufficientSpace,
1714 NotDirectory,
1715 NotEmpty,
1716 NotRecoverable,
1717 Unsupported,
1718 NoTty,
1719 NoSuchDevice,
1720 Overflow,
1721 NotPermitted,
1722 Pipe,
1723 ReadOnly,
1724 InvalidSeek,
1725 TextFileBusy,
1726 CrossDevice,
1727 }
1728
1729 enum Advice => latest::filesystem::types::Advice {
1730 Normal,
1731 Sequential,
1732 Random,
1733 WillNeed,
1734 DontNeed,
1735 NoReuse,
1736 }
1737
1738 flags DescriptorFlags [<=>] latest::filesystem::types::DescriptorFlags {
1739 READ,
1740 WRITE,
1741 FILE_INTEGRITY_SYNC,
1742 DATA_INTEGRITY_SYNC,
1743 REQUESTED_WRITE_SYNC,
1744 MUTATE_DIRECTORY,
1745 }
1746
1747 enum DescriptorType [<=>] latest::filesystem::types::DescriptorType {
1748 Unknown,
1749 BlockDevice,
1750 CharacterDevice,
1751 Directory,
1752 Fifo,
1753 SymbolicLink,
1754 RegularFile,
1755 Socket,
1756 }
1757
1758 enum NewTimestamp => latest::filesystem::types::NewTimestamp {
1759 NoChange,
1760 Now,
1761 Timestamp(e),
1762 }
1763
1764 flags PathFlags => latest::filesystem::types::PathFlags {
1765 SYMLINK_FOLLOW,
1766 }
1767
1768 flags OpenFlags => latest::filesystem::types::OpenFlags {
1769 CREATE,
1770 DIRECTORY,
1771 EXCLUSIVE,
1772 TRUNCATE,
1773 }
1774
1775 struct latest::filesystem::types::MetadataHashValue => MetadataHashValue {
1776 lower,
1777 upper,
1778 }
1779
1780 struct latest::filesystem::types::DirectoryEntry => DirectoryEntry {
1781 type_,
1782 name,
1783 }
1784
1785 enum latest::sockets::network::ErrorCode => SocketErrorCode {
1786 Unknown,
1787 AccessDenied,
1788 NotSupported,
1789 InvalidArgument,
1790 OutOfMemory,
1791 Timeout,
1792 ConcurrencyConflict,
1793 NotInProgress,
1794 WouldBlock,
1795 InvalidState,
1796 NewSocketLimit,
1797 AddressNotBindable,
1798 AddressInUse,
1799 RemoteUnreachable,
1800 ConnectionRefused,
1801 ConnectionReset,
1802 ConnectionAborted,
1803 DatagramTooLarge,
1804 NameUnresolvable,
1805 TemporaryResolverFailure,
1806 PermanentResolverFailure,
1807 }
1808
1809 enum latest::sockets::network::IpAddress [<=>] IpAddress {
1810 Ipv4(e),
1811 Ipv6(e),
1812 }
1813
1814 enum latest::sockets::network::IpSocketAddress [<=>] IpSocketAddress {
1815 Ipv4(e),
1816 Ipv6(e),
1817 }
1818
1819 struct latest::sockets::network::Ipv4SocketAddress [<=>] Ipv4SocketAddress {
1820 port,
1821 address,
1822 }
1823
1824 struct latest::sockets::network::Ipv6SocketAddress [<=>] Ipv6SocketAddress {
1825 port,
1826 flow_info,
1827 scope_id,
1828 address,
1829 }
1830
1831 enum latest::sockets::network::IpAddressFamily [<=>] IpAddressFamily {
1832 Ipv4,
1833 Ipv6,
1834 }
1835
1836 enum ShutdownType => latest::sockets::tcp::ShutdownType {
1837 Receive,
1838 Send,
1839 Both,
1840 }
1841
1842 struct latest::sockets::udp::IncomingDatagram => Datagram {
1843 data,
1844 remote_address,
1845 }
1846}
1847
1848impl From<latest::filesystem::types::DescriptorStat> for DescriptorStat {
1849 fn from(e: latest::filesystem::types::DescriptorStat) -> DescriptorStat {
1850 DescriptorStat {
1851 type_: e.type_.into(),
1852 link_count: e.link_count,
1853 size: e.size,
1854 data_access_timestamp: e.data_access_timestamp.map(|e| e.into()),
1855 data_modification_timestamp: e.data_modification_timestamp.map(|e| e.into()),
1856 status_change_timestamp: e.status_change_timestamp.map(|e| e.into()),
1857 }
1858 }
1859}