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