1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
use crate::{
    clocks::{
        host::{monotonic_clock, wall_clock},
        HostMonotonicClock, HostWallClock,
    },
    filesystem::{Dir, OpenMode},
    network::{SocketAddrCheck, SocketAddrUse},
    pipe, random, stdio,
    stdio::{StdinStream, StdoutStream},
    DirPerms, FilePerms,
};
use anyhow::Result;
use cap_rand::{Rng, RngCore, SeedableRng};
use cap_std::ambient_authority;
use std::path::Path;
use std::sync::Arc;
use std::{mem, net::SocketAddr};
use wasmtime::component::ResourceTable;

/// Builder-style structure used to create a [`WasiCtx`].
///
/// This type is used to create a [`WasiCtx`] that is considered per-[`Store`]
/// state. The [`build`][WasiCtxBuilder::build] method is used to finish the
/// building process and produce a finalized [`WasiCtx`].
///
/// # Examples
///
/// ```
/// use wasmtime_wasi::{WasiCtxBuilder, WasiCtx};
///
/// let mut wasi = WasiCtxBuilder::new();
/// wasi.arg("./foo.wasm");
/// wasi.arg("--help");
/// wasi.env("FOO", "bar");
///
/// let wasi: WasiCtx = wasi.build();
/// ```
///
/// [`Store`]: wasmtime::Store
pub struct WasiCtxBuilder {
    stdin: Box<dyn StdinStream>,
    stdout: Box<dyn StdoutStream>,
    stderr: Box<dyn StdoutStream>,
    env: Vec<(String, String)>,
    args: Vec<String>,
    preopens: Vec<(Dir, String)>,
    socket_addr_check: SocketAddrCheck,
    random: Box<dyn RngCore + Send>,
    insecure_random: Box<dyn RngCore + Send>,
    insecure_random_seed: u128,
    wall_clock: Box<dyn HostWallClock + Send>,
    monotonic_clock: Box<dyn HostMonotonicClock + Send>,
    allowed_network_uses: AllowedNetworkUses,
    allow_blocking_current_thread: bool,
    built: bool,
}

impl WasiCtxBuilder {
    /// Creates a builder for a new context with default parameters set.
    ///
    /// The current defaults are:
    ///
    /// * stdin is closed
    /// * stdout and stderr eat all input and it doesn't go anywhere
    /// * no env vars
    /// * no arguments
    /// * no preopens
    /// * clocks use the host implementation of wall/monotonic clocks
    /// * RNGs are all initialized with random state and suitable generator
    ///   quality to satisfy the requirements of WASI APIs.
    /// * TCP/UDP are allowed but all addresses are denied by default.
    /// * `wasi:network/ip-name-lookup` is denied by default.
    ///
    /// These defaults can all be updated via the various builder configuration
    /// methods below.
    pub fn new() -> Self {
        // For the insecure random API, use `SmallRng`, which is fast. It's
        // also insecure, but that's the deal here.
        let insecure_random = Box::new(
            cap_rand::rngs::SmallRng::from_rng(cap_rand::thread_rng(cap_rand::ambient_authority()))
                .unwrap(),
        );

        // For the insecure random seed, use a `u128` generated from
        // `thread_rng()`, so that it's not guessable from the insecure_random
        // API.
        let insecure_random_seed =
            cap_rand::thread_rng(cap_rand::ambient_authority()).gen::<u128>();
        Self {
            stdin: Box::new(pipe::ClosedInputStream),
            stdout: Box::new(pipe::SinkOutputStream),
            stderr: Box::new(pipe::SinkOutputStream),
            env: Vec::new(),
            args: Vec::new(),
            preopens: Vec::new(),
            socket_addr_check: SocketAddrCheck::default(),
            random: random::thread_rng(),
            insecure_random,
            insecure_random_seed,
            wall_clock: wall_clock(),
            monotonic_clock: monotonic_clock(),
            allowed_network_uses: AllowedNetworkUses::default(),
            allow_blocking_current_thread: false,
            built: false,
        }
    }

    /// Provides a custom implementation of stdin to use.
    ///
    /// By default stdin is closed but an example of using the host's native
    /// stdin loos like:
    ///
    /// ```
    /// use wasmtime_wasi::{stdin, WasiCtxBuilder};
    ///
    /// let mut wasi = WasiCtxBuilder::new();
    /// wasi.stdin(stdin());
    /// ```
    ///
    /// Note that inheriting the process's stdin can also be done through
    /// [`inherit_stdin`](WasiCtxBuilder::inherit_stdin).
    pub fn stdin(&mut self, stdin: impl StdinStream + 'static) -> &mut Self {
        self.stdin = Box::new(stdin);
        self
    }

    /// Same as [`stdin`](WasiCtxBuilder::stdin), but for stdout.
    pub fn stdout(&mut self, stdout: impl StdoutStream + 'static) -> &mut Self {
        self.stdout = Box::new(stdout);
        self
    }

    /// Same as [`stdin`](WasiCtxBuilder::stdin), but for stderr.
    pub fn stderr(&mut self, stderr: impl StdoutStream + 'static) -> &mut Self {
        self.stderr = Box::new(stderr);
        self
    }

    /// Configures this context's stdin stream to read the host process's
    /// stdin.
    ///
    /// Note that concurrent reads of stdin can produce surprising results so
    /// when using this it's typically best to have a single wasm instance in
    /// the process using this.
    pub fn inherit_stdin(&mut self) -> &mut Self {
        self.stdin(stdio::stdin())
    }

    /// Configures this context's stdout stream to write to the host process's
    /// stdout.
    ///
    /// Note that unlike [`inherit_stdin`](WasiCtxBuilder::inherit_stdin)
    /// multiple instances printing to stdout works well.
    pub fn inherit_stdout(&mut self) -> &mut Self {
        self.stdout(stdio::stdout())
    }

    /// Configures this context's stderr stream to write to the host process's
    /// stderr.
    ///
    /// Note that unlike [`inherit_stdin`](WasiCtxBuilder::inherit_stdin)
    /// multiple instances printing to stderr works well.
    pub fn inherit_stderr(&mut self) -> &mut Self {
        self.stderr(stdio::stderr())
    }

    /// Configures all of stdin, stdout, and stderr to be inherited from the
    /// host process.
    ///
    /// See [`inherit_stdin`](WasiCtxBuilder::inherit_stdin) for some rationale
    /// on why this should only be done in situations of
    /// one-instance-per-process.
    pub fn inherit_stdio(&mut self) -> &mut Self {
        self.inherit_stdin().inherit_stdout().inherit_stderr()
    }

    /// Configures whether or not blocking operations made through this
    /// `WasiCtx` are allowed to block the current thread.
    ///
    /// WASI is currently implemented on top of the Rust
    /// [Tokio](https://tokio.rs/) library. While most WASI APIs are
    /// non-blocking some are instead blocking from the perspective of
    /// WebAssembly. For example opening a file is a blocking operation with
    /// respect to WebAssembly but it's implemented as an asynchronous operation
    /// on the host. This is currently done with Tokio's
    /// [`spawn_blocking`](https://docs.rs/tokio/latest/tokio/task/fn.spawn_blocking.html).
    ///
    /// When WebAssembly is used in a synchronous context, for example when
    /// [`Config::async_support`] is disabled, then this asynchronous operation
    /// is quickly turned back into a synchronous operation with a `block_on` in
    /// Rust. This switching back-and-forth between a blocking a non-blocking
    /// context can have overhead, and this option exists to help alleviate this
    /// overhead.
    ///
    /// This option indicates that for WASI functions that are blocking from the
    /// perspective of WebAssembly it's ok to block the native thread as well.
    /// This means that this back-and-forth between async and sync won't happen
    /// and instead blocking operations are performed on-thread (such as opening
    /// a file). This can improve the performance of WASI operations when async
    /// support is disabled.
    ///
    /// [`Config::async_support`]: https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.async_support
    pub fn allow_blocking_current_thread(&mut self, enable: bool) -> &mut Self {
        self.allow_blocking_current_thread = enable;
        self
    }

    /// Appends multiple environment variables at once for this builder.
    ///
    /// All environment variables are appended to the list of environment
    /// variables that this builder will configure.
    ///
    /// At this time environment variables are not deduplicated and if the same
    /// key is set twice then the guest will see two entries for the same key.
    ///
    /// # Examples
    ///
    /// ```
    /// use wasmtime_wasi::{stdin, WasiCtxBuilder};
    ///
    /// let mut wasi = WasiCtxBuilder::new();
    /// wasi.envs(&[
    ///     ("FOO", "bar"),
    ///     ("HOME", "/somewhere"),
    /// ]);
    /// ```
    pub fn envs(&mut self, env: &[(impl AsRef<str>, impl AsRef<str>)]) -> &mut Self {
        self.env.extend(
            env.iter()
                .map(|(k, v)| (k.as_ref().to_owned(), v.as_ref().to_owned())),
        );
        self
    }

    /// Appends a single environment variable for this builder.
    ///
    /// At this time environment variables are not deduplicated and if the same
    /// key is set twice then the guest will see two entries for the same key.
    ///
    /// # Examples
    ///
    /// ```
    /// use wasmtime_wasi::{stdin, WasiCtxBuilder};
    ///
    /// let mut wasi = WasiCtxBuilder::new();
    /// wasi.env("FOO", "bar");
    /// ```
    pub fn env(&mut self, k: impl AsRef<str>, v: impl AsRef<str>) -> &mut Self {
        self.env
            .push((k.as_ref().to_owned(), v.as_ref().to_owned()));
        self
    }

    /// Configures all environment variables to be inherited from the calling
    /// process into this configuration.
    ///
    /// This will use [`envs`](WasiCtxBuilder::envs) to append all host-defined
    /// environment variables.
    pub fn inherit_env(&mut self) -> &mut Self {
        self.envs(&std::env::vars().collect::<Vec<(String, String)>>())
    }

    /// Appends a list of arguments to the argument array to pass to wasm.
    pub fn args(&mut self, args: &[impl AsRef<str>]) -> &mut Self {
        self.args.extend(args.iter().map(|a| a.as_ref().to_owned()));
        self
    }

    /// Appends a single argument to get passed to wasm.
    pub fn arg(&mut self, arg: impl AsRef<str>) -> &mut Self {
        self.args.push(arg.as_ref().to_owned());
        self
    }

    /// Appends all host process arguments to the list of arguments to get
    /// passed to wasm.
    pub fn inherit_args(&mut self) -> &mut Self {
        self.args(&std::env::args().collect::<Vec<String>>())
    }

    /// Configures a "preopened directory" to be available to WebAssembly.
    ///
    /// By default WebAssembly does not have access to the filesystem because
    /// the are no preopened directories. All filesystem operations, such as
    /// opening a file, are done through a preexisting handle. This means that
    /// to provide WebAssembly access to a directory it must be configured
    /// through this API.
    ///
    /// WASI will also prevent access outside of files provided here. For
    /// example `..` can't be used to traverse up from the `dir` provided here
    /// to the containing directory.
    ///
    /// * `host_path` - a path to a directory on the host to open and make
    ///   accessible to WebAssembly. Note that the name of this directory in the
    ///   guest is configured with `guest_path` below.
    /// * `guest_path` - the name of the preopened directory from WebAssembly's
    ///   perspective. Note that this does not need to match the host's name for
    ///   the directory.
    /// * `dir_perms` - this is the permissions that wasm will have to operate on
    ///   `dir`. This can be used, for example, to provide readonly access to a
    ///   directory.
    /// * `file_perms` - similar to `perms` but corresponds to the maximum set
    ///   of permissions that can be used for any file in this directory.
    ///
    /// # Errors
    ///
    /// This method will return an error if `host_path` cannot be opened.
    ///
    /// # Examples
    ///
    /// ```
    /// use wasmtime_wasi::{WasiCtxBuilder, DirPerms, FilePerms};
    ///
    /// # fn main() {}
    /// # fn foo() -> wasmtime::Result<()> {
    /// let mut wasi = WasiCtxBuilder::new();
    ///
    /// // Make `./host-directory` available in the guest as `.`
    /// wasi.preopened_dir("./host-directory", ".", DirPerms::all(), FilePerms::all());
    ///
    /// // Make `./readonly` available in the guest as `./ro`
    /// wasi.preopened_dir("./readonly", "./ro", DirPerms::READ, FilePerms::READ);
    /// # Ok(())
    /// # }
    /// ```
    pub fn preopened_dir(
        &mut self,
        host_path: impl AsRef<Path>,
        guest_path: impl AsRef<str>,
        dir_perms: DirPerms,
        file_perms: FilePerms,
    ) -> Result<&mut Self> {
        let dir = cap_std::fs::Dir::open_ambient_dir(host_path.as_ref(), ambient_authority())?;
        let mut open_mode = OpenMode::empty();
        if dir_perms.contains(DirPerms::READ) {
            open_mode |= OpenMode::READ;
        }
        if dir_perms.contains(DirPerms::MUTATE) {
            open_mode |= OpenMode::WRITE;
        }
        self.preopens.push((
            Dir::new(
                dir,
                dir_perms,
                file_perms,
                open_mode,
                self.allow_blocking_current_thread,
            ),
            guest_path.as_ref().to_owned(),
        ));
        Ok(self)
    }

    /// Set the generator for the `wasi:random/random` number generator to the
    /// custom generator specified.
    ///
    /// Note that contexts have a default RNG configured which is a suitable
    /// generator for WASI and is configured with a random seed per-context.
    ///
    /// Guest code may rely on this random number generator to produce fresh
    /// unpredictable random data in order to maintain its security invariants,
    /// and ideally should use the insecure random API otherwise, so using any
    /// prerecorded or otherwise predictable data may compromise security.
    pub fn secure_random(&mut self, random: impl RngCore + Send + 'static) -> &mut Self {
        self.random = Box::new(random);
        self
    }

    /// Configures the generator for `wasi:random/insecure`.
    ///
    /// The `insecure_random` generator provided will be used for all randomness
    /// requested by the `wasi:random/insecure` interface.
    pub fn insecure_random(&mut self, insecure_random: impl RngCore + Send + 'static) -> &mut Self {
        self.insecure_random = Box::new(insecure_random);
        self
    }

    /// Configures the seed to be returned from `wasi:random/insecure-seed` to
    /// the specified custom value.
    ///
    /// By default this number is randomly generated when a builder is created.
    pub fn insecure_random_seed(&mut self, insecure_random_seed: u128) -> &mut Self {
        self.insecure_random_seed = insecure_random_seed;
        self
    }

    /// Configures `wasi:clocks/wall-clock` to use the `clock` specified.
    ///
    /// By default the host's wall clock is used.
    pub fn wall_clock(&mut self, clock: impl HostWallClock + 'static) -> &mut Self {
        self.wall_clock = Box::new(clock);
        self
    }

    /// Configures `wasi:clocks/monotonic-clock` to use the `clock` specified.
    ///
    /// By default the host's monotonic clock is used.
    pub fn monotonic_clock(&mut self, clock: impl HostMonotonicClock + 'static) -> &mut Self {
        self.monotonic_clock = Box::new(clock);
        self
    }

    /// Allow all network addresses accessible to the host.
    ///
    /// This method will inherit all network addresses meaning that any address
    /// can be bound by the guest or connected to by the guest using any
    /// protocol.
    ///
    /// See also [`WasiCtxBuilder::socket_addr_check`].
    pub fn inherit_network(&mut self) -> &mut Self {
        self.socket_addr_check(|_, _| true)
    }

    /// A check that will be called for each socket address that is used.
    ///
    /// Returning `true` will permit socket connections to the `SocketAddr`,
    /// while returning `false` will reject the connection.
    pub fn socket_addr_check<F>(&mut self, check: F) -> &mut Self
    where
        F: Fn(&SocketAddr, SocketAddrUse) -> bool + Send + Sync + 'static,
    {
        self.socket_addr_check = SocketAddrCheck(Arc::new(check));
        self
    }

    /// Allow usage of `wasi:sockets/ip-name-lookup`
    ///
    /// By default this is disabled.
    pub fn allow_ip_name_lookup(&mut self, enable: bool) -> &mut Self {
        self.allowed_network_uses.ip_name_lookup = enable;
        self
    }

    /// Allow usage of UDP.
    ///
    /// This is enabled by default, but can be disabled if UDP should be blanket
    /// disabled.
    pub fn allow_udp(&mut self, enable: bool) -> &mut Self {
        self.allowed_network_uses.udp = enable;
        self
    }

    /// Allow usage of TCP
    ///
    /// This is enabled by default, but can be disabled if TCP should be blanket
    /// disabled.
    pub fn allow_tcp(&mut self, enable: bool) -> &mut Self {
        self.allowed_network_uses.tcp = enable;
        self
    }

    /// Uses the configured context so far to construct the final [`WasiCtx`].
    ///
    /// Note that each `WasiCtxBuilder` can only be used to "build" once, and
    /// calling this method twice will panic.
    ///
    /// # Panics
    ///
    /// Panics if this method is called twice. Each [`WasiCtxBuilder`] can be
    /// used to create only a single [`WasiCtx`]. Repeated usage of this method
    /// is not allowed and should use a second builder instead.
    pub fn build(&mut self) -> WasiCtx {
        assert!(!self.built);

        let Self {
            stdin,
            stdout,
            stderr,
            env,
            args,
            preopens,
            socket_addr_check,
            random,
            insecure_random,
            insecure_random_seed,
            wall_clock,
            monotonic_clock,
            allowed_network_uses,
            allow_blocking_current_thread,
            built: _,
        } = mem::replace(self, Self::new());
        self.built = true;

        WasiCtx {
            stdin,
            stdout,
            stderr,
            env,
            args,
            preopens,
            socket_addr_check,
            random,
            insecure_random,
            insecure_random_seed,
            wall_clock,
            monotonic_clock,
            allowed_network_uses,
            allow_blocking_current_thread,
        }
    }

    /// Builds a WASIp1 context instead of a [`WasiCtx`].
    ///
    /// This method is the same as [`build`](WasiCtxBuilder::build) but it
    /// creates a [`WasiP1Ctx`] instead. This is intended for use with the
    /// [`preview1`] module of this crate
    ///
    /// [`WasiP1Ctx`]: crate::preview1::WasiP1Ctx
    /// [`preview1`]: crate::preview1
    ///
    /// # Panics
    ///
    /// Panics if this method is called twice. Each [`WasiCtxBuilder`] can be
    /// used to create only a single [`WasiCtx`] or [`WasiP1Ctx`]. Repeated
    /// usage of this method is not allowed and should use a second builder
    /// instead.
    #[cfg(feature = "preview1")]
    pub fn build_p1(&mut self) -> crate::preview1::WasiP1Ctx {
        let wasi = self.build();
        crate::preview1::WasiP1Ctx::new(wasi)
    }
}

/// A trait which provides access to internal WASI state.
///
/// This trait is the basis of implementation of all traits in this crate. All
/// traits are implemented like:
///
/// ```
/// # trait WasiView {}
/// # mod bindings { pub mod wasi { pub trait Host {} } }
/// impl<T: WasiView> bindings::wasi::Host for T {
///     // ...
/// }
/// ```
///
/// For a [`Store<T>`](wasmtime::Store) this trait will be implemented
/// for the `T`. This also corresponds to the `T` in
/// [`Linker<T>`](wasmtime::component::Linker).
///
/// # Example
///
/// ```
/// use wasmtime_wasi::{WasiCtx, ResourceTable, WasiView, WasiCtxBuilder};
///
/// struct MyState {
///     ctx: WasiCtx,
///     table: ResourceTable,
/// }
///
/// impl WasiView for MyState {
///     fn ctx(&mut self) -> &mut WasiCtx { &mut self.ctx }
///     fn table(&mut self) -> &mut ResourceTable { &mut self.table }
/// }
///
/// impl MyState {
///     fn new() -> MyState {
///         let mut wasi = WasiCtxBuilder::new();
///         wasi.arg("./foo.wasm");
///         wasi.arg("--help");
///         wasi.env("FOO", "bar");
///
///         MyState {
///             ctx: wasi.build(),
///             table: ResourceTable::new(),
///         }
///     }
/// }
/// ```
pub trait WasiView: Send {
    /// Yields mutable access to the internal resource management that this
    /// context contains.
    ///
    /// Embedders can add custom resources to this table as well to give
    /// resources to wasm as well.
    fn table(&mut self) -> &mut ResourceTable;

    /// Yields mutable access to the configuration used for this context.
    ///
    /// The returned type is created through [`WasiCtxBuilder`].
    fn ctx(&mut self) -> &mut WasiCtx;
}

/// Per-[`Store`] state which holds state necessary to implement WASI from this
/// crate.
///
/// This structure is created through [`WasiCtxBuilder`] and is stored within
/// the `T` of [`Store<T>`][`Store`]. Access to the structure is provided
/// through the [`WasiView`] trait as an implementation on `T`.
///
/// Note that this structure itself does not have any accessors, it's here for
/// internal use within the `wasmtime-wasi` crate's implementation of
/// bindgen-generated traits.
///
/// [`Store`]: wasmtime::Store
pub struct WasiCtx {
    pub(crate) random: Box<dyn RngCore + Send>,
    pub(crate) insecure_random: Box<dyn RngCore + Send>,
    pub(crate) insecure_random_seed: u128,
    pub(crate) wall_clock: Box<dyn HostWallClock + Send>,
    pub(crate) monotonic_clock: Box<dyn HostMonotonicClock + Send>,
    pub(crate) env: Vec<(String, String)>,
    pub(crate) args: Vec<String>,
    pub(crate) preopens: Vec<(Dir, String)>,
    pub(crate) stdin: Box<dyn StdinStream>,
    pub(crate) stdout: Box<dyn StdoutStream>,
    pub(crate) stderr: Box<dyn StdoutStream>,
    pub(crate) socket_addr_check: SocketAddrCheck,
    pub(crate) allowed_network_uses: AllowedNetworkUses,
    pub(crate) allow_blocking_current_thread: bool,
}

impl WasiCtx {
    /// Convenience function for calling [`WasiCtxBuilder::new`].
    pub fn builder() -> WasiCtxBuilder {
        WasiCtxBuilder::new()
    }
}

pub struct AllowedNetworkUses {
    pub ip_name_lookup: bool,
    pub udp: bool,
    pub tcp: bool,
}

impl Default for AllowedNetworkUses {
    fn default() -> Self {
        Self {
            ip_name_lookup: false,
            udp: true,
            tcp: true,
        }
    }
}

impl AllowedNetworkUses {
    pub(crate) fn check_allowed_udp(&self) -> std::io::Result<()> {
        if !self.udp {
            return Err(std::io::Error::new(
                std::io::ErrorKind::PermissionDenied,
                "UDP is not allowed",
            ));
        }

        Ok(())
    }

    pub(crate) fn check_allowed_tcp(&self) -> std::io::Result<()> {
        if !self.tcp {
            return Err(std::io::Error::new(
                std::io::ErrorKind::PermissionDenied,
                "TCP is not allowed",
            ));
        }

        Ok(())
    }
}