@@ -13,7 +13,7 @@ use std::{
13
13
} ;
14
14
use structopt:: { clap:: AppSettings , StructOpt } ;
15
15
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 } ;
17
17
18
18
#[ cfg( feature = "wasi-nn" ) ]
19
19
use wasmtime_wasi_nn:: WasiNnCtx ;
@@ -91,6 +91,19 @@ pub struct RunCommand {
91
91
#[ structopt( long = "allow-precompiled" ) ]
92
92
allow_precompiled : bool ,
93
93
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
+
94
107
/// Grant access to the given host directory
95
108
#[ structopt( long = "dir" , number_of_values = 1 , value_name = "DIRECTORY" ) ]
96
109
dirs : Vec < String > ,
@@ -165,6 +178,8 @@ impl RunCommand {
165
178
& argv,
166
179
& self . vars ,
167
180
& self . common . wasi_modules . unwrap_or ( WasiModules :: default ( ) ) ,
181
+ self . listenfd ,
182
+ & self . tcplisten ,
168
183
) ?;
169
184
170
185
// Load the preload wasm modules.
@@ -415,16 +430,39 @@ fn populate_with_wasi(
415
430
argv : & [ String ] ,
416
431
vars : & [ ( String , String ) ] ,
417
432
wasi_modules : & WasiModules ,
433
+ listenfd : bool ,
434
+ tcplisten : & Vec < String > ,
418
435
) -> Result < ( ) > {
419
436
if wasi_modules. wasi_common {
420
437
wasmtime_wasi:: add_to_linker ( linker, |host| host. wasi . as_mut ( ) . unwrap ( ) ) ?;
421
438
422
439
let mut builder = WasiCtxBuilder :: new ( ) ;
423
440
builder = builder. inherit_stdio ( ) . args ( argv) ?. envs ( vars) ?;
424
441
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
+
425
462
for ( name, dir) in preopen_dirs. into_iter ( ) {
426
463
builder = builder. preopened_dir ( dir, name) ?;
427
464
}
465
+
428
466
store. data_mut ( ) . wasi = Some ( builder. build ( ) ) ;
429
467
}
430
468
@@ -454,3 +492,55 @@ fn populate_with_wasi(
454
492
455
493
Ok ( ( ) )
456
494
}
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