Skip to content

Commit e6121ae

Browse files
committed
Import sd listen
Signed-off-by: Harald Hoyer <[email protected]>
1 parent 72f6c4f commit e6121ae

File tree

5 files changed

+141
-6
lines changed

5 files changed

+141
-6
lines changed

Cargo.lock

Lines changed: 16 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ rayon = "1.5.0"
3939
humantime = "2.0.0"
4040
wasmparser = "0.81.0"
4141
lazy_static = "1.4.0"
42+
listenfd = "0.3.5"
4243

4344
[target.'cfg(unix)'.dependencies]
4445
rustix = "0.31.0"

crates/wasi-common/cap-std-sync/src/lib.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,13 @@ pub mod tcpstream;
4343

4444
pub use cap_std::ambient_authority;
4545
pub use cap_std::fs::Dir;
46+
pub use cap_std::net::TcpListener;
4647
pub use clocks::clocks_ctx;
4748
pub use sched::sched_ctx;
4849

4950
use cap_rand::RngCore;
5051
use std::path::Path;
51-
use wasi_common::{table::Table, Error, WasiCtx, WasiFile};
52+
use wasi_common::{file::FileCaps, table::Table, Error, WasiCtx, WasiFile};
5253

5354
pub struct WasiCtxBuilder(WasiCtx);
5455

@@ -122,6 +123,18 @@ impl WasiCtxBuilder {
122123
self.0.push_preopened_dir(dir, guest_path)?;
123124
Ok(self)
124125
}
126+
pub fn preopened_listener(mut self, fd: u32, listener: TcpListener) -> Result<Self, Error> {
127+
let file: Box<dyn WasiFile> =
128+
Box::new(crate::tcplisten::TcpListener::from_cap_std(listener));
129+
130+
let caps = FileCaps::FDSTAT_SET_FLAGS
131+
| FileCaps::FILESTAT_GET
132+
| FileCaps::READ
133+
| FileCaps::POLL_READWRITE;
134+
135+
self.0.insert_file(fd, file, caps);
136+
Ok(self)
137+
}
125138
pub fn build(self) -> WasiCtx {
126139
self.0
127140
}

crates/wasi-common/tokio/src/lib.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ use wasi_common::{Error, Table, WasiCtx, WasiFile};
1414

1515
pub use dir::Dir;
1616
pub use file::File;
17+
pub use tcplisten::TcpListener;
18+
pub use tcpstream::TcpStream;
19+
use wasi_common::file::FileCaps;
1720

1821
use crate::sched::sched_ctx;
1922

@@ -93,6 +96,22 @@ impl WasiCtxBuilder {
9396
self.0.push_preopened_dir(dir, guest_path)?;
9497
Ok(self)
9598
}
99+
pub fn preopened_listener(
100+
mut self,
101+
fd: u32,
102+
listener: cap_std::net::TcpListener,
103+
) -> Result<Self, Error> {
104+
let file: Box<dyn WasiFile> = Box::new(TcpListener::from_cap_std(listener));
105+
106+
let caps = FileCaps::FDSTAT_SET_FLAGS
107+
| FileCaps::FILESTAT_GET
108+
| FileCaps::READ
109+
| FileCaps::POLL_READWRITE;
110+
111+
self.0.insert_file(fd, file, caps);
112+
Ok(self)
113+
}
114+
96115
pub fn build(self) -> WasiCtx {
97116
self.0
98117
}

src/commands/run.rs

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use std::{
1313
};
1414
use structopt::{clap::AppSettings, StructOpt};
1515
use wasmtime::{Engine, Func, Linker, Module, Store, Trap, Val, ValType};
16-
use wasmtime_wasi::sync::{ambient_authority, Dir, WasiCtxBuilder};
16+
use wasmtime_wasi::sync::{ambient_authority, Dir, TcpListener, WasiCtxBuilder};
1717

1818
#[cfg(feature = "wasi-nn")]
1919
use wasmtime_wasi_nn::WasiNnCtx;
@@ -91,6 +91,19 @@ pub struct RunCommand {
9191
#[structopt(long = "allow-precompiled")]
9292
allow_precompiled: bool,
9393

94+
/// Inherit environment variables and file descriptors following the
95+
/// systemd listen fd specification (UNIX only)
96+
#[structopt(long = "listenfd")]
97+
listenfd: bool,
98+
99+
/// Grant access to the given TCP listen socket
100+
#[structopt(
101+
long = "tcplisten",
102+
number_of_values = 1,
103+
value_name = "SOCKET ADDRESS"
104+
)]
105+
tcplisten: Vec<String>,
106+
94107
/// Grant access to the given host directory
95108
#[structopt(long = "dir", number_of_values = 1, value_name = "DIRECTORY")]
96109
dirs: Vec<String>,
@@ -165,6 +178,8 @@ impl RunCommand {
165178
&argv,
166179
&self.vars,
167180
&self.common.wasi_modules.unwrap_or(WasiModules::default()),
181+
self.listenfd,
182+
&self.tcplisten,
168183
)?;
169184

170185
// Load the preload wasm modules.
@@ -415,16 +430,39 @@ fn populate_with_wasi(
415430
argv: &[String],
416431
vars: &[(String, String)],
417432
wasi_modules: &WasiModules,
433+
listenfd: bool,
434+
tcplisten: &Vec<String>,
418435
) -> Result<()> {
419436
if wasi_modules.wasi_common {
420437
wasmtime_wasi::add_to_linker(linker, |host| host.wasi.as_mut().unwrap())?;
421438

422439
let mut builder = WasiCtxBuilder::new();
423440
builder = builder.inherit_stdio().args(argv)?.envs(vars)?;
424441

442+
let mut num_fd: usize = 3;
443+
444+
if listenfd {
445+
let (n, b) = ctx_set_listenfd(num_fd, builder)?;
446+
num_fd = n;
447+
builder = b;
448+
}
449+
450+
for address in tcplisten.iter() {
451+
let stdlistener = std::net::TcpListener::bind(address)
452+
.with_context(|| format!("failed to bind to address '{}'", address))?;
453+
454+
let _ = stdlistener.set_nonblocking(true)?;
455+
456+
let listener = TcpListener::from_std(stdlistener);
457+
458+
builder = builder.preopened_listener(num_fd as _, listener)?;
459+
num_fd += 1;
460+
}
461+
425462
for (name, dir) in preopen_dirs.into_iter() {
426463
builder = builder.preopened_dir(dir, name)?;
427464
}
465+
428466
store.data_mut().wasi = Some(builder.build());
429467
}
430468

@@ -454,3 +492,55 @@ fn populate_with_wasi(
454492

455493
Ok(())
456494
}
495+
496+
#[cfg(not(unix))]
497+
fn ctx_set_listenfd(num_fd: usize, builder: WasiCtxBuilder) -> Result<(usize, WasiCtxBuilder)> {
498+
use listenfd::ListenFd;
499+
500+
let mut builder = builder;
501+
let mut num_fd = num_fd;
502+
503+
let mut listenfd = ListenFd::from_env();
504+
505+
for i in 0..listenfd.len() {
506+
if let Some(stdlistener) = listenfd.take_tcp_listener(i)? {
507+
let _ = stdlistener.set_nonblocking(true)?;
508+
let listener = TcpListener::from_std(stdlistener);
509+
builder = builder.preopened_listener((3 + i) as _, listener)?;
510+
num_fd = 3 + i;
511+
}
512+
}
513+
514+
if num_fd > 3 {
515+
builder = builder.env("LISTEN_FDS", &(num_fd - 3).to_string())?;
516+
}
517+
518+
Ok((num_fd, builder))
519+
}
520+
521+
#[cfg(unix)]
522+
fn ctx_set_listenfd(num_fd: usize, builder: WasiCtxBuilder) -> Result<(usize, WasiCtxBuilder)> {
523+
use listenfd::ListenFd;
524+
525+
let mut builder = builder;
526+
let mut num_fd = num_fd;
527+
528+
for env in ["LISTEN_FDS", "LISTEN_FDNAMES"] {
529+
if let Ok(val) = std::env::var(env) {
530+
builder = builder.env(env, &val)?;
531+
}
532+
}
533+
534+
let mut listenfd = ListenFd::from_env();
535+
536+
for i in 0..listenfd.len() {
537+
if let Some(stdlistener) = listenfd.take_tcp_listener(i)? {
538+
let _ = stdlistener.set_nonblocking(true)?;
539+
let listener = TcpListener::from_std(stdlistener);
540+
builder = builder.preopened_listener((3 + i) as _, listener)?;
541+
num_fd = 3 + i;
542+
}
543+
}
544+
545+
Ok((num_fd, builder))
546+
}

0 commit comments

Comments
 (0)