Skip to content

Commit 3e07866

Browse files
authored
cli: allow exec server to listen on socket (microsoft#188123)
* cli: allow exec server to listen on socket For remote ssh * fix lint
1 parent a40a4f7 commit 3e07866

File tree

4 files changed

+63
-19
lines changed

4 files changed

+63
-19
lines changed

cli/src/bin/code/main.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,9 @@ async fn main() -> Result<(), std::convert::Infallible> {
9595
args::VersionSubcommand::Show => version::show(context!()).await,
9696
},
9797

98-
Some(args::Commands::CommandShell) => tunnels::command_shell(context!()).await,
98+
Some(args::Commands::CommandShell(cs_args)) => {
99+
tunnels::command_shell(context!(), cs_args).await
100+
}
99101

100102
Some(args::Commands::Tunnel(tunnel_args)) => match tunnel_args.subcommand {
101103
Some(args::TunnelSubcommand::Prune) => tunnels::prune(context!()).await,

cli/src/commands/args.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,14 @@ pub enum Commands {
174174

175175
/// Runs the control server on process stdin/stdout
176176
#[clap(hide = true)]
177-
CommandShell,
177+
CommandShell(CommandShellArgs),
178+
}
179+
180+
#[derive(Args, Debug, Clone)]
181+
pub struct CommandShellArgs {
182+
/// Listen on a socket instead of stdin/stdout.
183+
#[clap(long)]
184+
pub on_socket: bool,
178185
}
179186

180187
#[derive(Args, Debug, Clone)]

cli/src/commands/tunnels.rs

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,22 @@
55

66
use async_trait::async_trait;
77
use base64::{engine::general_purpose as b64, Engine as _};
8+
use futures::{stream::FuturesUnordered, StreamExt};
89
use serde::Serialize;
910
use sha2::{Digest, Sha256};
1011
use std::{str::FromStr, time::Duration};
1112
use sysinfo::Pid;
1213

1314
use super::{
1415
args::{
15-
AuthProvider, CliCore, ExistingTunnelArgs, TunnelRenameArgs, TunnelServeArgs,
16-
TunnelServiceSubCommands, TunnelUserSubCommands,
16+
AuthProvider, CliCore, CommandShellArgs, ExistingTunnelArgs, TunnelRenameArgs,
17+
TunnelServeArgs, TunnelServiceSubCommands, TunnelUserSubCommands,
1718
},
1819
CommandContext,
1920
};
2021

2122
use crate::{
23+
async_pipe::{get_socket_name, listen_socket_rw_stream, socket_stream_split},
2224
auth::Auth,
2325
constants::{APPLICATION_NAME, TUNNEL_CLI_LOCK_NAME, TUNNEL_SERVICE_LOCK_NAME},
2426
log,
@@ -120,23 +122,55 @@ impl ServiceContainer for TunnelServiceContainer {
120122
}
121123
}
122124

123-
pub async fn command_shell(ctx: CommandContext) -> Result<i32, AnyError> {
125+
pub async fn command_shell(ctx: CommandContext, args: CommandShellArgs) -> Result<i32, AnyError> {
124126
let platform = PreReqChecker::new().verify().await?;
125-
serve_stream(
126-
tokio::io::stdin(),
127-
tokio::io::stderr(),
128-
ServeStreamParams {
129-
log: ctx.log,
130-
launcher_paths: ctx.paths,
131-
platform,
132-
requires_auth: true,
133-
exit_barrier: ShutdownRequest::create_rx([ShutdownRequest::CtrlC]),
134-
code_server_args: (&ctx.args).into(),
135-
},
136-
)
137-
.await;
127+
let mut params = ServeStreamParams {
128+
log: ctx.log,
129+
launcher_paths: ctx.paths,
130+
platform,
131+
requires_auth: true,
132+
exit_barrier: ShutdownRequest::create_rx([ShutdownRequest::CtrlC]),
133+
code_server_args: (&ctx.args).into(),
134+
};
138135

139-
Ok(0)
136+
if !args.on_socket {
137+
serve_stream(tokio::io::stdin(), tokio::io::stderr(), params).await;
138+
return Ok(0);
139+
}
140+
141+
let socket = get_socket_name();
142+
let mut listener = listen_socket_rw_stream(&socket)
143+
.await
144+
.map_err(|e| wrap(e, "error listening on socket"))?;
145+
146+
params
147+
.log
148+
.result(format!("Listening on {}", socket.display()));
149+
150+
let mut servers = FuturesUnordered::new();
151+
152+
loop {
153+
tokio::select! {
154+
Some(_) = servers.next() => {},
155+
socket = listener.accept() => {
156+
match socket {
157+
Ok(s) => {
158+
let (read, write) = socket_stream_split(s);
159+
servers.push(serve_stream(read, write, params.clone()));
160+
},
161+
Err(e) => {
162+
error!(params.log, &format!("Error accepting connection: {}", e));
163+
return Ok(1);
164+
}
165+
}
166+
},
167+
_ = params.exit_barrier.wait() => {
168+
// wait for all servers to finish up:
169+
while (servers.next().await).is_some() { }
170+
return Ok(0);
171+
}
172+
}
173+
}
140174
}
141175

142176
pub async fn service(

cli/src/tunnels/control_server.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ pub async fn serve(
233233
}
234234
}
235235

236+
#[derive(Clone)]
236237
pub struct ServeStreamParams {
237238
pub log: log::Logger,
238239
pub launcher_paths: LauncherPaths,

0 commit comments

Comments
 (0)