1993e26e0STrevor Elliott //! Common functionality shared between command implementations.
2993e26e0STrevor Elliott
3993e26e0STrevor Elliott use clap::Parser;
482670953SAlex Crichton use std::net::TcpListener;
515b464b6SAdam Bratschi-Kaye use std::{fs::File, path::Path, time::Duration};
694740588SNick Fitzgerald use wasmtime::{
794740588SNick Fitzgerald Engine, Module, Precompiled, Result, StoreLimits, StoreLimitsBuilder, bail,
894740588SNick Fitzgerald error::Context as _, format_err,
994740588SNick Fitzgerald };
1090ac295eSAlex Crichton use wasmtime_cli_flags::{CommonOptions, opt::WasmtimeOptionValue};
11f7a5aa34SAlex Crichton use wasmtime_wasi::WasiCtxBuilder;
12993e26e0STrevor Elliott
13993e26e0STrevor Elliott #[cfg(feature = "component-model")]
14993e26e0STrevor Elliott use wasmtime::component::Component;
15993e26e0STrevor Elliott
16eced7c7eSAlex Crichton /// Whether or not WASIp3 is enabled by default.
17eced7c7eSAlex Crichton ///
18eced7c7eSAlex Crichton /// Currently this is disabled (the `&& false`), but that'll get removed in the
19eced7c7eSAlex Crichton /// future.
20eced7c7eSAlex Crichton pub const P3_DEFAULT: bool = cfg!(feature = "component-model-async") && false;
21eced7c7eSAlex Crichton
22133a0ef4SChris Fallin #[derive(Clone)]
23993e26e0STrevor Elliott pub enum RunTarget {
24993e26e0STrevor Elliott Core(Module),
25993e26e0STrevor Elliott
26993e26e0STrevor Elliott #[cfg(feature = "component-model")]
27993e26e0STrevor Elliott Component(Component),
28993e26e0STrevor Elliott }
29993e26e0STrevor Elliott
30993e26e0STrevor Elliott impl RunTarget {
unwrap_core(&self) -> &Module31993e26e0STrevor Elliott pub fn unwrap_core(&self) -> &Module {
32993e26e0STrevor Elliott match self {
33993e26e0STrevor Elliott RunTarget::Core(module) => module,
34993e26e0STrevor Elliott #[cfg(feature = "component-model")]
35993e26e0STrevor Elliott RunTarget::Component(_) => panic!("expected a core wasm module, not a component"),
36993e26e0STrevor Elliott }
37993e26e0STrevor Elliott }
38993e26e0STrevor Elliott
39993e26e0STrevor Elliott #[cfg(feature = "component-model")]
unwrap_component(&self) -> &Component40993e26e0STrevor Elliott pub fn unwrap_component(&self) -> &Component {
41993e26e0STrevor Elliott match self {
42993e26e0STrevor Elliott RunTarget::Component(c) => c,
43993e26e0STrevor Elliott RunTarget::Core(_) => panic!("expected a component, not a core wasm module"),
44993e26e0STrevor Elliott }
45993e26e0STrevor Elliott }
46993e26e0STrevor Elliott }
47993e26e0STrevor Elliott
48993e26e0STrevor Elliott /// Common command line arguments for run commands.
49be12a665SAlex Crichton #[derive(Parser)]
50993e26e0STrevor Elliott pub struct RunCommon {
51f9f8a4dfSXinzhao Xu #[command(flatten)]
52993e26e0STrevor Elliott pub common: CommonOptions,
53993e26e0STrevor Elliott
54993e26e0STrevor Elliott /// Allow executing precompiled WebAssembly modules as `*.cwasm` files.
55993e26e0STrevor Elliott ///
56993e26e0STrevor Elliott /// Note that this option is not safe to pass if the module being passed in
57993e26e0STrevor Elliott /// is arbitrary user input. Only `wasmtime`-precompiled modules generated
58993e26e0STrevor Elliott /// via the `wasmtime compile` command or equivalent should be passed as an
59993e26e0STrevor Elliott /// argument with this option specified.
60f9f8a4dfSXinzhao Xu #[arg(long = "allow-precompiled")]
61993e26e0STrevor Elliott pub allow_precompiled: bool,
62993e26e0STrevor Elliott
63993e26e0STrevor Elliott /// Profiling strategy (valid options are: perfmap, jitdump, vtune, guest)
64993e26e0STrevor Elliott ///
65993e26e0STrevor Elliott /// The perfmap, jitdump, and vtune profiling strategies integrate Wasmtime
66993e26e0STrevor Elliott /// with external profilers such as `perf`. The guest profiling strategy
67993e26e0STrevor Elliott /// enables in-process sampling and will write the captured profile to
68993e26e0STrevor Elliott /// `wasmtime-guest-profile.json` by default which can be viewed at
69993e26e0STrevor Elliott /// https://profiler.firefox.com/.
70993e26e0STrevor Elliott ///
71993e26e0STrevor Elliott /// The `guest` option can be additionally configured as:
72993e26e0STrevor Elliott ///
73993e26e0STrevor Elliott /// --profile=guest[,path[,interval]]
74993e26e0STrevor Elliott ///
75993e26e0STrevor Elliott /// where `path` is where to write the profile and `interval` is the
76993e26e0STrevor Elliott /// duration between samples. When used with `--wasm-timeout` the timeout
77993e26e0STrevor Elliott /// will be rounded up to the nearest multiple of this interval.
78f9f8a4dfSXinzhao Xu #[arg(
79993e26e0STrevor Elliott long,
80993e26e0STrevor Elliott value_name = "STRATEGY",
81993e26e0STrevor Elliott value_parser = Profile::parse,
82993e26e0STrevor Elliott )]
83993e26e0STrevor Elliott pub profile: Option<Profile>,
8482670953SAlex Crichton
8582670953SAlex Crichton /// Grant access of a host directory to a guest.
8682670953SAlex Crichton ///
8782670953SAlex Crichton /// If specified as just `HOST_DIR` then the same directory name on the
8882670953SAlex Crichton /// host is made available within the guest. If specified as `HOST::GUEST`
8982670953SAlex Crichton /// then the `HOST` directory is opened and made available as the name
9082670953SAlex Crichton /// `GUEST` in the guest.
9182670953SAlex Crichton #[arg(long = "dir", value_name = "HOST_DIR[::GUEST_DIR]", value_parser = parse_dirs)]
9282670953SAlex Crichton pub dirs: Vec<(String, String)>,
9382670953SAlex Crichton
9482670953SAlex Crichton /// Pass an environment variable to the program.
9582670953SAlex Crichton ///
9682670953SAlex Crichton /// The `--env FOO=BAR` form will set the environment variable named `FOO`
9782670953SAlex Crichton /// to the value `BAR` for the guest program using WASI. The `--env FOO`
9882670953SAlex Crichton /// form will set the environment variable named `FOO` to the same value it
9982670953SAlex Crichton /// has in the calling process for the guest, or in other words it will
10082670953SAlex Crichton /// cause the environment variable `FOO` to be inherited.
10182670953SAlex Crichton #[arg(long = "env", number_of_values = 1, value_name = "NAME[=VAL]", value_parser = parse_env_var)]
10282670953SAlex Crichton pub vars: Vec<(String, Option<String>)>,
103*dbaaa92fSChris Fallin
104*dbaaa92fSChris Fallin /// Attach the built-in gdbstub debugger component, listening on
105*dbaaa92fSChris Fallin /// the given TCP address. Accepts a port number (e.g. `1234`) or
106*dbaaa92fSChris Fallin /// a full `address:port`. A bare port number will bind on
107*dbaaa92fSChris Fallin /// localhost only (`127.0.0.1`). A debugger (e.g. LLDB) can then
108*dbaaa92fSChris Fallin /// connect via `process connect --plugin=wasm
109*dbaaa92fSChris Fallin /// connect://<ADDR>:<PORT>`.
110*dbaaa92fSChris Fallin #[cfg(feature = "gdbstub")]
111*dbaaa92fSChris Fallin #[arg(short = 'g', long = "gdbstub", value_name = "[ADDR:]PORT")]
112*dbaaa92fSChris Fallin pub gdbstub: Option<String>,
11382670953SAlex Crichton }
11482670953SAlex Crichton
parse_env_var(s: &str) -> Result<(String, Option<String>)>11582670953SAlex Crichton fn parse_env_var(s: &str) -> Result<(String, Option<String>)> {
11682670953SAlex Crichton let mut parts = s.splitn(2, '=');
11782670953SAlex Crichton Ok((
11882670953SAlex Crichton parts.next().unwrap().to_string(),
11982670953SAlex Crichton parts.next().map(|s| s.to_string()),
12082670953SAlex Crichton ))
12182670953SAlex Crichton }
12282670953SAlex Crichton
parse_dirs(s: &str) -> Result<(String, String)>12382670953SAlex Crichton fn parse_dirs(s: &str) -> Result<(String, String)> {
12482670953SAlex Crichton let mut parts = s.split("::");
12582670953SAlex Crichton let host = parts.next().unwrap();
12682670953SAlex Crichton let guest = match parts.next() {
12782670953SAlex Crichton Some(guest) => guest,
12882670953SAlex Crichton None => host,
12982670953SAlex Crichton };
13082670953SAlex Crichton Ok((host.into(), guest.into()))
131993e26e0STrevor Elliott }
132993e26e0STrevor Elliott
133993e26e0STrevor Elliott impl RunCommon {
store_limits(&self) -> StoreLimits134993e26e0STrevor Elliott pub fn store_limits(&self) -> StoreLimits {
135993e26e0STrevor Elliott let mut limits = StoreLimitsBuilder::new();
136993e26e0STrevor Elliott if let Some(max) = self.common.wasm.max_memory_size {
137993e26e0STrevor Elliott limits = limits.memory_size(max);
138993e26e0STrevor Elliott }
139993e26e0STrevor Elliott if let Some(max) = self.common.wasm.max_table_elements {
140993e26e0STrevor Elliott limits = limits.table_elements(max);
141993e26e0STrevor Elliott }
142993e26e0STrevor Elliott if let Some(max) = self.common.wasm.max_instances {
143993e26e0STrevor Elliott limits = limits.instances(max);
144993e26e0STrevor Elliott }
145993e26e0STrevor Elliott if let Some(max) = self.common.wasm.max_tables {
146993e26e0STrevor Elliott limits = limits.tables(max);
147993e26e0STrevor Elliott }
148993e26e0STrevor Elliott if let Some(max) = self.common.wasm.max_memories {
149993e26e0STrevor Elliott limits = limits.memories(max);
150993e26e0STrevor Elliott }
151993e26e0STrevor Elliott if let Some(enable) = self.common.wasm.trap_on_grow_failure {
152993e26e0STrevor Elliott limits = limits.trap_on_grow_failure(enable);
153993e26e0STrevor Elliott }
154993e26e0STrevor Elliott
155993e26e0STrevor Elliott limits.build()
156993e26e0STrevor Elliott }
157993e26e0STrevor Elliott
ensure_allow_precompiled(&self) -> Result<()>158993e26e0STrevor Elliott pub fn ensure_allow_precompiled(&self) -> Result<()> {
159993e26e0STrevor Elliott if self.allow_precompiled {
160993e26e0STrevor Elliott Ok(())
161993e26e0STrevor Elliott } else {
162993e26e0STrevor Elliott bail!("running a precompiled module requires the `--allow-precompiled` flag")
163993e26e0STrevor Elliott }
164993e26e0STrevor Elliott }
165993e26e0STrevor Elliott
166993e26e0STrevor Elliott #[cfg(feature = "component-model")]
ensure_allow_components(&self) -> Result<()>167993e26e0STrevor Elliott fn ensure_allow_components(&self) -> Result<()> {
16894b3e84eSAlex Crichton if self.common.wasm.component_model == Some(false) {
169993e26e0STrevor Elliott bail!("cannot execute a component without `--wasm component-model`");
170993e26e0STrevor Elliott }
171993e26e0STrevor Elliott
172993e26e0STrevor Elliott Ok(())
173993e26e0STrevor Elliott }
174993e26e0STrevor Elliott
load_module( &self, engine: &Engine, path: &Path, preloaded_bytes: Option<&[u8]>, ) -> Result<RunTarget>175*dbaaa92fSChris Fallin pub fn load_module(
176*dbaaa92fSChris Fallin &self,
177*dbaaa92fSChris Fallin engine: &Engine,
178*dbaaa92fSChris Fallin path: &Path,
179*dbaaa92fSChris Fallin preloaded_bytes: Option<&[u8]>,
180*dbaaa92fSChris Fallin ) -> Result<RunTarget> {
181993e26e0STrevor Elliott let path = match path.to_str() {
182993e26e0STrevor Elliott #[cfg(unix)]
183993e26e0STrevor Elliott Some("-") => "/dev/stdin".as_ref(),
184993e26e0STrevor Elliott _ => path,
185993e26e0STrevor Elliott };
186*dbaaa92fSChris Fallin if let Some(bytes) = preloaded_bytes {
187*dbaaa92fSChris Fallin self.load_module_contents(
188*dbaaa92fSChris Fallin engine,
189*dbaaa92fSChris Fallin path,
190*dbaaa92fSChris Fallin &bytes,
191*dbaaa92fSChris Fallin || unsafe { Module::deserialize(engine, &bytes) },
192*dbaaa92fSChris Fallin #[cfg(feature = "component-model")]
193*dbaaa92fSChris Fallin || unsafe { Component::deserialize(engine, &bytes) },
194*dbaaa92fSChris Fallin )
195*dbaaa92fSChris Fallin } else {
1962ad3bea6SAlex Crichton let file =
1972ad3bea6SAlex Crichton File::open(path).with_context(|| format!("failed to open wasm module {path:?}"))?;
198993e26e0STrevor Elliott
199993e26e0STrevor Elliott // First attempt to load the module as an mmap. If this succeeds then
200993e26e0STrevor Elliott // detection can be done with the contents of the mmap and if a
201993e26e0STrevor Elliott // precompiled module is detected then `deserialize_file` can be used
202993e26e0STrevor Elliott // which is a slightly more optimal version than `deserialize` since we
203993e26e0STrevor Elliott // can leave most of the bytes on disk until they're referenced.
204993e26e0STrevor Elliott //
205993e26e0STrevor Elliott // If the mmap fails, for example if stdin is a pipe, then fall back to
206993e26e0STrevor Elliott // `std::fs::read` to load the contents. At that point precompiled
207993e26e0STrevor Elliott // modules must go through the `deserialize` functions.
208993e26e0STrevor Elliott //
209993e26e0STrevor Elliott // Note that this has the unfortunate side effect for precompiled
210993e26e0STrevor Elliott // modules on disk that they're opened once to detect what they are and
211993e26e0STrevor Elliott // then again internally in Wasmtime as part of the `deserialize_file`
212993e26e0STrevor Elliott // API. Currently there's no way to pass the `MmapVec` here through to
21372004aadSNick Fitzgerald // Wasmtime itself (that'd require making `MmapVec` a public type, both
21472004aadSNick Fitzgerald // which isn't ready to happen at this time). It's hoped though that
21572004aadSNick Fitzgerald // opening a file twice isn't too bad in the grand scheme of things with
21672004aadSNick Fitzgerald // respect to the CLI.
21715b464b6SAdam Bratschi-Kaye match wasmtime::_internal::MmapVec::from_file(file) {
218993e26e0STrevor Elliott Ok(map) => self.load_module_contents(
219993e26e0STrevor Elliott engine,
220993e26e0STrevor Elliott path,
221993e26e0STrevor Elliott &map,
222993e26e0STrevor Elliott || unsafe { Module::deserialize_file(engine, path) },
223993e26e0STrevor Elliott #[cfg(feature = "component-model")]
224993e26e0STrevor Elliott || unsafe { Component::deserialize_file(engine, path) },
225993e26e0STrevor Elliott ),
226993e26e0STrevor Elliott Err(_) => {
227993e26e0STrevor Elliott let bytes = std::fs::read(path)
228993e26e0STrevor Elliott .with_context(|| format!("failed to read file: {}", path.display()))?;
229993e26e0STrevor Elliott self.load_module_contents(
230993e26e0STrevor Elliott engine,
231993e26e0STrevor Elliott path,
232993e26e0STrevor Elliott &bytes,
233993e26e0STrevor Elliott || unsafe { Module::deserialize(engine, &bytes) },
234993e26e0STrevor Elliott #[cfg(feature = "component-model")]
235993e26e0STrevor Elliott || unsafe { Component::deserialize(engine, &bytes) },
236993e26e0STrevor Elliott )
237993e26e0STrevor Elliott }
238993e26e0STrevor Elliott }
239993e26e0STrevor Elliott }
240*dbaaa92fSChris Fallin }
241993e26e0STrevor Elliott
load_module_contents( &self, engine: &Engine, path: &Path, bytes: &[u8], deserialize_module: impl FnOnce() -> Result<Module>, #[cfg(feature = "component-model")] deserialize_component: impl FnOnce() -> Result<Component>, ) -> Result<RunTarget>242993e26e0STrevor Elliott pub fn load_module_contents(
243993e26e0STrevor Elliott &self,
244993e26e0STrevor Elliott engine: &Engine,
245993e26e0STrevor Elliott path: &Path,
246993e26e0STrevor Elliott bytes: &[u8],
247993e26e0STrevor Elliott deserialize_module: impl FnOnce() -> Result<Module>,
248993e26e0STrevor Elliott #[cfg(feature = "component-model")] deserialize_component: impl FnOnce() -> Result<Component>,
249993e26e0STrevor Elliott ) -> Result<RunTarget> {
2503e406d2eSAlex Crichton Ok(match Engine::detect_precompiled(bytes) {
251993e26e0STrevor Elliott Some(Precompiled::Module) => {
252993e26e0STrevor Elliott self.ensure_allow_precompiled()?;
253993e26e0STrevor Elliott RunTarget::Core(deserialize_module()?)
254993e26e0STrevor Elliott }
255993e26e0STrevor Elliott #[cfg(feature = "component-model")]
256993e26e0STrevor Elliott Some(Precompiled::Component) => {
257993e26e0STrevor Elliott self.ensure_allow_precompiled()?;
258993e26e0STrevor Elliott self.ensure_allow_components()?;
259993e26e0STrevor Elliott RunTarget::Component(deserialize_component()?)
260993e26e0STrevor Elliott }
261993e26e0STrevor Elliott #[cfg(not(feature = "component-model"))]
262993e26e0STrevor Elliott Some(Precompiled::Component) => {
263993e26e0STrevor Elliott bail!("support for components was not enabled at compile time");
264993e26e0STrevor Elliott }
26571951c9cSAlex Crichton #[cfg(any(feature = "cranelift", feature = "winch"))]
266993e26e0STrevor Elliott None => {
267f673cde3SAlex Crichton let mut code = wasmtime::CodeBuilder::new(engine);
268f673cde3SAlex Crichton code.wasm_binary_or_text(bytes, Some(path))?;
269f673cde3SAlex Crichton match code.hint() {
270f673cde3SAlex Crichton Some(wasmtime::CodeHint::Component) => {
271993e26e0STrevor Elliott #[cfg(feature = "component-model")]
272993e26e0STrevor Elliott {
273993e26e0STrevor Elliott self.ensure_allow_components()?;
274f673cde3SAlex Crichton RunTarget::Component(code.compile_component()?)
275993e26e0STrevor Elliott }
276993e26e0STrevor Elliott #[cfg(not(feature = "component-model"))]
277993e26e0STrevor Elliott {
278993e26e0STrevor Elliott bail!("support for components was not enabled at compile time");
279993e26e0STrevor Elliott }
280f673cde3SAlex Crichton }
281f673cde3SAlex Crichton Some(wasmtime::CodeHint::Module) | None => {
282f673cde3SAlex Crichton RunTarget::Core(code.compile_module()?)
283993e26e0STrevor Elliott }
284993e26e0STrevor Elliott }
285f673cde3SAlex Crichton }
286f673cde3SAlex Crichton
28771951c9cSAlex Crichton #[cfg(not(any(feature = "cranelift", feature = "winch")))]
28871951c9cSAlex Crichton None => {
2893e406d2eSAlex Crichton let _ = (path, engine);
29071951c9cSAlex Crichton bail!("support for compiling modules was disabled at compile time");
29171951c9cSAlex Crichton }
292993e26e0STrevor Elliott })
293993e26e0STrevor Elliott }
29482670953SAlex Crichton
configure_wasip2(&self, builder: &mut WasiCtxBuilder) -> Result<()>29582670953SAlex Crichton pub fn configure_wasip2(&self, builder: &mut WasiCtxBuilder) -> Result<()> {
29682670953SAlex Crichton // It's ok to block the current thread since we're the only thread in
29782670953SAlex Crichton // the program as the CLI. This helps improve the performance of some
29882670953SAlex Crichton // blocking operations in WASI, for example, by skipping the
29982670953SAlex Crichton // back-and-forth between sync and async.
3004005a813SNick Fitzgerald //
3014005a813SNick Fitzgerald // However, do not set this if a timeout is configured, as that would
3024005a813SNick Fitzgerald // cause the timeout to be ignored if the guest does, for example,
3034005a813SNick Fitzgerald // something like `sleep(FOREVER)`.
3044005a813SNick Fitzgerald builder.allow_blocking_current_thread(self.common.wasm.timeout.is_none());
30582670953SAlex Crichton
30682670953SAlex Crichton if self.common.wasi.inherit_env == Some(true) {
30782670953SAlex Crichton for (k, v) in std::env::vars() {
30882670953SAlex Crichton builder.env(&k, &v);
30982670953SAlex Crichton }
31082670953SAlex Crichton }
31182670953SAlex Crichton for (key, value) in self.vars.iter() {
31282670953SAlex Crichton let value = match value {
31382670953SAlex Crichton Some(value) => value.clone(),
31482670953SAlex Crichton None => match std::env::var_os(key) {
31582670953SAlex Crichton Some(val) => val
31682670953SAlex Crichton .into_string()
31794740588SNick Fitzgerald .map_err(|_| format_err!("environment variable `{key}` not valid utf-8"))?,
31882670953SAlex Crichton None => {
31982670953SAlex Crichton // leave the env var un-set in the guest
32082670953SAlex Crichton continue;
32182670953SAlex Crichton }
32282670953SAlex Crichton },
32382670953SAlex Crichton };
32482670953SAlex Crichton builder.env(key, &value);
32582670953SAlex Crichton }
32682670953SAlex Crichton
32782670953SAlex Crichton for (host, guest) in self.dirs.iter() {
32882670953SAlex Crichton builder.preopened_dir(
32982670953SAlex Crichton host,
33082670953SAlex Crichton guest,
33182670953SAlex Crichton wasmtime_wasi::DirPerms::all(),
33282670953SAlex Crichton wasmtime_wasi::FilePerms::all(),
33382670953SAlex Crichton )?;
33482670953SAlex Crichton }
33582670953SAlex Crichton
33682670953SAlex Crichton if self.common.wasi.listenfd == Some(true) {
33782670953SAlex Crichton bail!("components do not support --listenfd");
33882670953SAlex Crichton }
33982670953SAlex Crichton for _ in self.compute_preopen_sockets()? {
34082670953SAlex Crichton bail!("components do not support --tcplisten");
34182670953SAlex Crichton }
34282670953SAlex Crichton
34382670953SAlex Crichton if self.common.wasi.inherit_network == Some(true) {
34482670953SAlex Crichton builder.inherit_network();
34582670953SAlex Crichton }
34682670953SAlex Crichton if let Some(enable) = self.common.wasi.allow_ip_name_lookup {
34782670953SAlex Crichton builder.allow_ip_name_lookup(enable);
34882670953SAlex Crichton }
34982670953SAlex Crichton if let Some(enable) = self.common.wasi.tcp {
35082670953SAlex Crichton builder.allow_tcp(enable);
35182670953SAlex Crichton }
35282670953SAlex Crichton if let Some(enable) = self.common.wasi.udp {
35382670953SAlex Crichton builder.allow_udp(enable);
35482670953SAlex Crichton }
355301dc716SAlex Crichton if let Some(max_size) = self.common.wasi.max_random_size {
356301dc716SAlex Crichton builder.max_random_size(max_size);
357301dc716SAlex Crichton }
35882670953SAlex Crichton
35982670953SAlex Crichton Ok(())
36082670953SAlex Crichton }
36182670953SAlex Crichton
362301dc716SAlex Crichton #[cfg(feature = "wasi-http")]
wasi_http_ctx(&self) -> Result<wasmtime_wasi_http::WasiHttpCtx>363301dc716SAlex Crichton pub fn wasi_http_ctx(&self) -> Result<wasmtime_wasi_http::WasiHttpCtx> {
364301dc716SAlex Crichton let mut http = wasmtime_wasi_http::WasiHttpCtx::new();
365301dc716SAlex Crichton if let Some(limit) = self.common.wasi.max_http_fields_size {
366301dc716SAlex Crichton http.set_field_size_limit(limit);
367301dc716SAlex Crichton }
368301dc716SAlex Crichton Ok(http)
369301dc716SAlex Crichton }
370301dc716SAlex Crichton
371365e2d89SAlex Crichton #[cfg(feature = "wasi-http")]
wasi_http_hooks(&self) -> HttpHooks372365e2d89SAlex Crichton pub fn wasi_http_hooks(&self) -> HttpHooks {
373365e2d89SAlex Crichton HttpHooks {
374365e2d89SAlex Crichton p2_outgoing_body_buffer_chunks: self
375365e2d89SAlex Crichton .common
376365e2d89SAlex Crichton .wasi
377365e2d89SAlex Crichton .http_outgoing_body_buffer_chunks
378365e2d89SAlex Crichton .unwrap_or_else(|| wasmtime_wasi_http::p2::DEFAULT_OUTGOING_BODY_BUFFER_CHUNKS),
379365e2d89SAlex Crichton p2_outgoing_body_chunk_size: self
380365e2d89SAlex Crichton .common
381365e2d89SAlex Crichton .wasi
382365e2d89SAlex Crichton .http_outgoing_body_chunk_size
383365e2d89SAlex Crichton .unwrap_or_else(|| wasmtime_wasi_http::p2::DEFAULT_OUTGOING_BODY_CHUNK_SIZE),
384365e2d89SAlex Crichton }
385365e2d89SAlex Crichton }
386365e2d89SAlex Crichton
compute_preopen_sockets(&self) -> Result<Vec<TcpListener>>38782670953SAlex Crichton pub fn compute_preopen_sockets(&self) -> Result<Vec<TcpListener>> {
38882670953SAlex Crichton let mut listeners = vec![];
38982670953SAlex Crichton
39082670953SAlex Crichton for address in &self.common.wasi.tcplisten {
39182670953SAlex Crichton let stdlistener = std::net::TcpListener::bind(address)
39246098121SHamir Mahal .with_context(|| format!("failed to bind to address '{address}'"))?;
39382670953SAlex Crichton
39482670953SAlex Crichton let _ = stdlistener.set_nonblocking(true)?;
39582670953SAlex Crichton
39682670953SAlex Crichton listeners.push(stdlistener)
39782670953SAlex Crichton }
39882670953SAlex Crichton Ok(listeners)
39982670953SAlex Crichton }
400c230353dSDave Bakker
validate_p3_option(&self) -> Result<()>401eced7c7eSAlex Crichton pub fn validate_p3_option(&self) -> Result<()> {
402eced7c7eSAlex Crichton let p3 = self.common.wasi.p3.unwrap_or(P3_DEFAULT);
403eced7c7eSAlex Crichton if p3 && !cfg!(feature = "component-model-async") {
404eced7c7eSAlex Crichton bail!("support for WASIp3 disabled at compile time");
405eced7c7eSAlex Crichton }
406eced7c7eSAlex Crichton Ok(())
407eced7c7eSAlex Crichton }
408eced7c7eSAlex Crichton
validate_cli_enabled(&self) -> Result<Option<bool>>409eced7c7eSAlex Crichton pub fn validate_cli_enabled(&self) -> Result<Option<bool>> {
410eced7c7eSAlex Crichton let mut cli = self.common.wasi.cli;
411eced7c7eSAlex Crichton
412eced7c7eSAlex Crichton // Accept -Scommon as a deprecated alias for -Scli.
413eced7c7eSAlex Crichton if let Some(common) = self.common.wasi.common {
414eced7c7eSAlex Crichton if cli.is_some() {
415eced7c7eSAlex Crichton bail!(
416eced7c7eSAlex Crichton "The -Scommon option should not be use with -Scli as it is a deprecated alias"
417eced7c7eSAlex Crichton );
418eced7c7eSAlex Crichton } else {
419eced7c7eSAlex Crichton // In the future, we may add a warning here to tell users to use
420eced7c7eSAlex Crichton // `-S cli` instead of `-S common`.
421eced7c7eSAlex Crichton cli = Some(common);
422eced7c7eSAlex Crichton }
423eced7c7eSAlex Crichton }
424eced7c7eSAlex Crichton
425eced7c7eSAlex Crichton Ok(cli)
426eced7c7eSAlex Crichton }
427eced7c7eSAlex Crichton
428eced7c7eSAlex Crichton /// Adds `wasmtime-wasi` interfaces (dubbed "-Scli" in the flags to the
429eced7c7eSAlex Crichton /// `wasmtime` command) to the `linker` provided.
430eced7c7eSAlex Crichton ///
431eced7c7eSAlex Crichton /// This will handle adding various WASI standard versions to the linker
432eced7c7eSAlex Crichton /// internally.
433eced7c7eSAlex Crichton #[cfg(feature = "component-model")]
add_wasmtime_wasi_to_linker<T>( &self, linker: &mut wasmtime::component::Linker<T>, ) -> Result<()> where T: wasmtime_wasi::WasiView,434eced7c7eSAlex Crichton pub fn add_wasmtime_wasi_to_linker<T>(
435eced7c7eSAlex Crichton &self,
436eced7c7eSAlex Crichton linker: &mut wasmtime::component::Linker<T>,
437eced7c7eSAlex Crichton ) -> Result<()>
438eced7c7eSAlex Crichton where
439eced7c7eSAlex Crichton T: wasmtime_wasi::WasiView,
440eced7c7eSAlex Crichton {
441eced7c7eSAlex Crichton let mut p2_options = wasmtime_wasi::p2::bindings::LinkOptions::default();
442eced7c7eSAlex Crichton p2_options.cli_exit_with_code(self.common.wasi.cli_exit_with_code.unwrap_or(false));
443eced7c7eSAlex Crichton p2_options.network_error_code(self.common.wasi.network_error_code.unwrap_or(false));
444eced7c7eSAlex Crichton wasmtime_wasi::p2::add_to_linker_with_options_async(linker, &p2_options)?;
445eced7c7eSAlex Crichton
446eced7c7eSAlex Crichton #[cfg(feature = "component-model-async")]
447eced7c7eSAlex Crichton if self.common.wasi.p3.unwrap_or(P3_DEFAULT) {
448eced7c7eSAlex Crichton let mut p3_options = wasmtime_wasi::p3::bindings::LinkOptions::default();
449eced7c7eSAlex Crichton p3_options.cli_exit_with_code(self.common.wasi.cli_exit_with_code.unwrap_or(false));
450eced7c7eSAlex Crichton wasmtime_wasi::p3::add_to_linker_with_options(linker, &p3_options)
451eced7c7eSAlex Crichton .context("failed to link `wasi:[email protected]`")?;
452eced7c7eSAlex Crichton }
453eced7c7eSAlex Crichton
454eced7c7eSAlex Crichton Ok(())
455c230353dSDave Bakker }
456993e26e0STrevor Elliott }
457993e26e0STrevor Elliott
458519808fcSAlex Crichton #[derive(Clone, PartialEq)]
459993e26e0STrevor Elliott pub enum Profile {
460993e26e0STrevor Elliott Native(wasmtime::ProfilingStrategy),
461993e26e0STrevor Elliott Guest { path: String, interval: Duration },
462993e26e0STrevor Elliott }
463993e26e0STrevor Elliott
464993e26e0STrevor Elliott impl Profile {
465993e26e0STrevor Elliott /// Parse the `profile` argument to either the `run` or `serve` commands.
parse(s: &str) -> Result<Profile>466993e26e0STrevor Elliott pub fn parse(s: &str) -> Result<Profile> {
467993e26e0STrevor Elliott let parts = s.split(',').collect::<Vec<_>>();
468993e26e0STrevor Elliott match &parts[..] {
469993e26e0STrevor Elliott ["perfmap"] => Ok(Profile::Native(wasmtime::ProfilingStrategy::PerfMap)),
470993e26e0STrevor Elliott ["jitdump"] => Ok(Profile::Native(wasmtime::ProfilingStrategy::JitDump)),
471993e26e0STrevor Elliott ["vtune"] => Ok(Profile::Native(wasmtime::ProfilingStrategy::VTune)),
4721d1c06f3SAlex Crichton ["pulley"] => Ok(Profile::Native(wasmtime::ProfilingStrategy::Pulley)),
473993e26e0STrevor Elliott ["guest"] => Ok(Profile::Guest {
474993e26e0STrevor Elliott path: "wasmtime-guest-profile.json".to_string(),
475993e26e0STrevor Elliott interval: Duration::from_millis(10),
476993e26e0STrevor Elliott }),
477993e26e0STrevor Elliott ["guest", path] => Ok(Profile::Guest {
478993e26e0STrevor Elliott path: path.to_string(),
479993e26e0STrevor Elliott interval: Duration::from_millis(10),
480993e26e0STrevor Elliott }),
481993e26e0STrevor Elliott ["guest", path, dur] => Ok(Profile::Guest {
482993e26e0STrevor Elliott path: path.to_string(),
483993e26e0STrevor Elliott interval: WasmtimeOptionValue::parse(Some(dur))?,
484993e26e0STrevor Elliott }),
485993e26e0STrevor Elliott _ => bail!("unknown profiling strategy: {s}"),
486993e26e0STrevor Elliott }
487993e26e0STrevor Elliott }
488993e26e0STrevor Elliott }
489c90925f6SAlex Crichton
490365e2d89SAlex Crichton #[derive(Copy, Clone, Debug)]
491365e2d89SAlex Crichton #[cfg(feature = "wasi-http")]
492365e2d89SAlex Crichton pub struct HttpHooks {
493365e2d89SAlex Crichton p2_outgoing_body_buffer_chunks: usize,
494365e2d89SAlex Crichton p2_outgoing_body_chunk_size: usize,
495365e2d89SAlex Crichton }
496365e2d89SAlex Crichton
497365e2d89SAlex Crichton #[cfg(feature = "wasi-http")]
498365e2d89SAlex Crichton impl Default for HttpHooks {
default() -> Self499365e2d89SAlex Crichton fn default() -> Self {
500365e2d89SAlex Crichton Self {
501365e2d89SAlex Crichton p2_outgoing_body_buffer_chunks:
502365e2d89SAlex Crichton wasmtime_wasi_http::p2::DEFAULT_OUTGOING_BODY_BUFFER_CHUNKS,
503365e2d89SAlex Crichton p2_outgoing_body_chunk_size: wasmtime_wasi_http::p2::DEFAULT_OUTGOING_BODY_CHUNK_SIZE,
504365e2d89SAlex Crichton }
505365e2d89SAlex Crichton }
506365e2d89SAlex Crichton }
507365e2d89SAlex Crichton
508365e2d89SAlex Crichton #[cfg(feature = "wasi-http")]
509365e2d89SAlex Crichton impl wasmtime_wasi_http::p2::WasiHttpHooks for HttpHooks {
outgoing_body_buffer_chunks(&mut self) -> usize510365e2d89SAlex Crichton fn outgoing_body_buffer_chunks(&mut self) -> usize {
511365e2d89SAlex Crichton self.p2_outgoing_body_buffer_chunks
512365e2d89SAlex Crichton }
513365e2d89SAlex Crichton
outgoing_body_chunk_size(&mut self) -> usize514365e2d89SAlex Crichton fn outgoing_body_chunk_size(&mut self) -> usize {
515365e2d89SAlex Crichton self.p2_outgoing_body_chunk_size
516365e2d89SAlex Crichton }
517365e2d89SAlex Crichton }
518365e2d89SAlex Crichton
519365e2d89SAlex Crichton #[cfg(feature = "wasi-http")]
520365e2d89SAlex Crichton impl wasmtime_wasi_http::p3::WasiHttpHooks for HttpHooks {}
521