Skip to main content

wasmtime_wasi/p3/sockets/
mod.rs

1use crate::TrappableError;
2use crate::p3::Interface;
3use crate::p3::bindings::sockets::{ip_name_lookup, types};
4use crate::sockets::{WasiSockets, WasiSocketsNamed, WasiSocketsNamedView, WasiSocketsView};
5use crate::{NamedId, WasiCtxNamedView};
6use wasmtime::component::{Component, Linker};
7
8mod conv;
9mod host;
10
11pub type SocketResult<T> = Result<T, SocketError>;
12pub type SocketError = TrappableError<types::ErrorCode>;
13
14/// Add all WASI interfaces from this module into the `linker` provided.
15///
16/// This function will add all interfaces implemented by this module to the
17/// [`Linker`], which corresponds to the `wasi:sockets/imports` world supported by
18/// this module.
19///
20/// This is low-level API for advanced use cases,
21/// [`wasmtime_wasi::p3::add_to_linker`](crate::p3::add_to_linker) can be used instead
22/// to add *all* wasip3 interfaces (including the ones from this module) to the `linker`.
23///
24/// # Example
25///
26/// ```
27/// use wasmtime::{Engine, Result, Store, Config};
28/// use wasmtime::component::{Linker, ResourceTable};
29/// use wasmtime_wasi::sockets::{WasiSocketsCtx, WasiSocketsCtxView, WasiSocketsView};
30///
31/// fn main() -> Result<()> {
32///     let mut config = Config::new();
33///     config.wasm_component_model_async(true);
34///     let engine = Engine::new(&config)?;
35///
36///     let mut linker = Linker::<MyState>::new(&engine);
37///     wasmtime_wasi::p3::sockets::add_to_linker(&mut linker)?;
38///     // ... add any further functionality to `linker` if desired ...
39///
40///     let mut store = Store::new(
41///         &engine,
42///         MyState::default(),
43///     );
44///
45///     // ... use `linker` to instantiate within `store` ...
46///
47///     Ok(())
48/// }
49///
50/// #[derive(Default)]
51/// struct MyState {
52///     sockets: WasiSocketsCtx,
53///     table: ResourceTable,
54/// }
55///
56/// impl WasiSocketsView for MyState {
57///     fn sockets(&mut self) -> WasiSocketsCtxView<'_> {
58///         WasiSocketsCtxView {
59///             ctx: &mut self.sockets,
60///             table: &mut self.table,
61///         }
62///     }
63/// }
64/// ```
65pub fn add_to_linker<T>(linker: &mut Linker<T>) -> wasmtime::Result<()>
66where
67    T: WasiSocketsView + 'static,
68{
69    ip_name_lookup::add_to_linker::<_, WasiSockets>(linker, T::sockets)?;
70    types::add_to_linker::<_, WasiSockets>(linker, T::sockets)?;
71    Ok(())
72}
73
74/// Convenience function to add `wasi:sockets` interfaces into `linker` for any
75/// named imports of `wasi:sockets` interfaces.
76///
77/// This function is similar to [`add_to_linker`] except that it's specifically
78/// designed to work with named imports of `wasi:sockets` interfaces that
79/// components may have. This requires a [`Component`] parameter to be passed in
80/// when populating the [`Linker`] provided to see what the [`Component`]
81/// actually imports.
82///
83/// Like [`add_to_linker`] this is a bit low level and you may want to possibly
84/// invoke [`wasmtime_wasi::p3::add_named_to_linker`] instead. Alternatively if
85/// this isn't low level enough you can additionally invoke bindgen-generated
86/// `add_to_linker` functions directly from within the
87/// [`named_imports::wasi::sockets`] module.
88///
89/// [`wasmtime_wasi::p3::add_named_to_linker`]: crate::p3::add_named_to_linker
90/// [`named_imports::wasi::sockets`]: crate::p3::bindings::named_imports::wasi::sockets
91///
92/// The `lookup` function provided here is invoked for every named import found
93/// for a particular interface. The [`Interface`] given is what's being bound,
94/// and the `&str` argument is the name that the component imports it as. The
95/// embedder can then decide how it would like to allocate a [`NamedId`] for
96/// this import. If `Ok` is returned then the linker is populated with this
97/// name, and imported functions will pass the [`NamedId`] later to the
98/// implementation of [`WasiSocketsNamedView`] on `T` when invoked. If `Err` is
99/// returned then the error will cause this entire function to fail and this
100/// function call will return the same error.
101///
102/// # Example
103///
104/// ```
105/// use std::collections::HashMap;
106/// use wasmtime::component::{Component, Linker, ResourceTable};
107/// use wasmtime::{Engine, Result, Store, Config};
108/// use wasmtime_wasi::NamedId;
109/// use wasmtime_wasi::sockets::{WasiSocketsCtx, WasiSocketsCtxView, WasiSocketsNamedView};
110///
111/// fn main() -> Result<()> {
112///     let engine = Engine::default();
113///     let component = Component::new(&engine, "(component)")?;
114///
115///     let mut linker = Linker::<MyState>::new(&engine);
116///
117///     // ... add default functionality to `linker` as needed ...
118///
119///     // and then additionally fill in any specific named imports `component`
120///     // might have for `wasi:sockets` interfaces.
121///     let mut name_map = HashMap::new();
122///     wasmtime_wasi::p3::sockets::add_named_to_linker(&mut linker, &component, |_i, name| {
123///         let len = name_map.len();
124///         Ok(NamedId(*name_map.entry(name.to_string()).or_insert(len)))
125///     })?;
126///
127///     // Here a `WasiSocketsCtx` is allocated per-named-import and will then be
128///     // referred to internally by the [`NamedId`] allocated above. You could
129///     // also use `name_map` to configure each context differently.
130///     let mut my_state = MyState::default();
131///     for _ in 0..name_map.len() {
132///         my_state.contexts.push(WasiSocketsCtx::default());
133///     }
134///     let mut store = Store::new(&engine, my_state);
135///     let instance = linker.instantiate(&mut store, &component)?;
136///
137///     // ... work with `instance` ...
138///
139///     Ok(())
140/// }
141///
142/// #[derive(Default)]
143/// struct MyState {
144///     table: ResourceTable,
145///     contexts: Vec<WasiSocketsCtx>,
146/// }
147///
148/// impl WasiSocketsNamedView for MyState {
149///     fn sockets(&mut self, id: NamedId) -> WasiSocketsCtxView<'_> {
150///         WasiSocketsCtxView {
151///             ctx: &mut self.contexts[id.0],
152///             table: &mut self.table,
153///         }
154///     }
155/// }
156/// ```
157pub fn add_named_to_linker<T>(
158    linker: &mut Linker<T>,
159    component: &Component,
160    mut lookup: impl FnMut(Interface, &str) -> wasmtime::Result<NamedId>,
161) -> wasmtime::Result<()>
162where
163    T: WasiSocketsNamedView + 'static,
164{
165    use crate::p3::bindings::named_imports::wasi::sockets::{ip_name_lookup, types};
166    ip_name_lookup::add_to_linker::<_, WasiSocketsNamed<T>>(
167        linker,
168        component,
169        |name| lookup(Interface::SocketsIpNameLookup, name),
170        |x| WasiCtxNamedView(x),
171    )?;
172    types::add_to_linker::<_, WasiSocketsNamed<T>>(
173        linker,
174        component,
175        |name| lookup(Interface::SocketsTypes, name),
176        |x| WasiCtxNamedView(x),
177    )?;
178    Ok(())
179}