mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-24 10:38:59 +01:00
cli: use win32 app mutex to detect running tunnels and tunnel sevices (#179622)
* cli: fix distro mixin * cli: use win32 app mutex to detect running tunnels and tunnel sevices Fixes #179265 * cli: fix distro mixin more * fix * fix build
This commit is contained in:
@@ -20,7 +20,7 @@ use super::{
|
||||
use crate::{
|
||||
async_pipe::socket_stream_split,
|
||||
auth::Auth,
|
||||
constants::APPLICATION_NAME,
|
||||
constants::{APPLICATION_NAME, TUNNEL_NO_SERVICE_LOCK_NAME, TUNNEL_SERVICE_LOCK_NAME},
|
||||
json_rpc::{new_json_rpc, start_json_rpc},
|
||||
log,
|
||||
singleton::connect_as_client,
|
||||
@@ -37,6 +37,7 @@ use crate::{
|
||||
Next, ServiceContainer, ServiceManager,
|
||||
},
|
||||
util::{
|
||||
app_lock::AppMutex,
|
||||
errors::{wrap, AnyError, CodeError},
|
||||
prereqs::PreReqChecker,
|
||||
},
|
||||
@@ -148,6 +149,7 @@ pub async fn service(
|
||||
manager.show_logs().await?;
|
||||
}
|
||||
TunnelServiceSubCommands::InternalRun => {
|
||||
let _lock = AppMutex::new(TUNNEL_SERVICE_LOCK_NAME);
|
||||
manager
|
||||
.run(ctx.paths.clone(), TunnelServiceContainer::new(ctx.args))
|
||||
.await?;
|
||||
@@ -384,6 +386,7 @@ async fn serve_with_csa(
|
||||
let mut server =
|
||||
make_singleton_server(log_broadcast.clone(), log.clone(), server, shutdown.clone());
|
||||
let platform = spanf!(log, log.span("prereq"), PreReqChecker::new().verify())?;
|
||||
let _lock = AppMutex::new(TUNNEL_NO_SERVICE_LOCK_NAME).unwrap();
|
||||
|
||||
let auth = Auth::new(&paths, log.clone());
|
||||
let mut dt = dev_tunnels::DevTunnels::new(&log, auth, &paths);
|
||||
|
||||
@@ -34,6 +34,26 @@ pub const VSCODE_CLI_COMMIT: Option<&'static str> = option_env!("VSCODE_CLI_COMM
|
||||
pub const VSCODE_CLI_UPDATE_ENDPOINT: Option<&'static str> =
|
||||
option_env!("VSCODE_CLI_UPDATE_ENDPOINT");
|
||||
|
||||
/// Windows lock name for the running tunnel service. Used by the setup script
|
||||
/// to detect a tunnel process. See #179265.
|
||||
pub const TUNNEL_SERVICE_LOCK_NAME: &str = concatcp!(
|
||||
"code_tunnel_service_",
|
||||
match VSCODE_CLI_QUALITY {
|
||||
Some(n) => n,
|
||||
None => "oss",
|
||||
}
|
||||
);
|
||||
|
||||
/// Windows lock name for the running tunnel without a service. Used by the setup
|
||||
/// script to detect a tunnel process. See #179265.
|
||||
pub const TUNNEL_NO_SERVICE_LOCK_NAME: &str = concatcp!(
|
||||
"code_tunnel_",
|
||||
match VSCODE_CLI_QUALITY {
|
||||
Some(n) => n,
|
||||
None => "oss",
|
||||
}
|
||||
);
|
||||
|
||||
pub const TUNNEL_SERVICE_USER_AGENT_ENV_VAR: &str = "TUNNEL_SERVICE_USER_AGENT";
|
||||
|
||||
/// Application name as it appears on the CLI.
|
||||
|
||||
@@ -15,6 +15,7 @@ pub mod prereqs;
|
||||
pub mod ring_buffer;
|
||||
pub mod sync;
|
||||
pub use is_integrated::*;
|
||||
pub mod app_lock;
|
||||
pub mod file_lock;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
|
||||
58
cli/src/util/app_lock.rs
Normal file
58
cli/src/util/app_lock.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
#[cfg(windows)]
|
||||
use std::{io, ptr};
|
||||
|
||||
#[cfg(windows)]
|
||||
use winapi::{
|
||||
shared::winerror::ERROR_ALREADY_EXISTS,
|
||||
um::{handleapi::CloseHandle, synchapi::CreateMutexA, winnt::HANDLE},
|
||||
};
|
||||
|
||||
use super::errors::CodeError;
|
||||
|
||||
pub struct AppMutex {
|
||||
#[cfg(windows)]
|
||||
handle: HANDLE,
|
||||
}
|
||||
|
||||
#[cfg(windows)] // handle is thread-safe, mark it so with this
|
||||
unsafe impl Send for AppMutex {}
|
||||
|
||||
impl AppMutex {
|
||||
#[cfg(unix)]
|
||||
pub fn new(_name: &str) -> Result<Self, CodeError> {
|
||||
Ok(Self {})
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn new(name: &str) -> Result<Self, CodeError> {
|
||||
let handle = unsafe { CreateMutexA(ptr::null_mut(), 0, name.as_ptr() as _) };
|
||||
|
||||
if !handle.is_null() {
|
||||
return Ok(Self { handle });
|
||||
}
|
||||
|
||||
let err = io::Error::last_os_error();
|
||||
let raw = err.raw_os_error();
|
||||
// docs report it should return ERROR_IO_PENDING, but in my testing it actually
|
||||
// returns ERROR_LOCK_VIOLATION. Or maybe winapi is wrong?
|
||||
if raw == Some(ERROR_ALREADY_EXISTS as i32) {
|
||||
return Err(CodeError::AppAlreadyLocked(name.to_string()));
|
||||
}
|
||||
|
||||
Err(CodeError::AppLockFailed(err))
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for AppMutex {
|
||||
fn drop(&mut self) {
|
||||
#[cfg(windows)]
|
||||
unsafe {
|
||||
CloseHandle(self.handle)
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -494,6 +494,12 @@ pub enum CodeError {
|
||||
NoRunningTunnel,
|
||||
#[error("rpc call failed: {0:?}")]
|
||||
TunnelRpcCallFailed(ResponseError),
|
||||
#[cfg(windows)]
|
||||
#[error("the windows app lock {0} already exists")]
|
||||
AppAlreadyLocked(String),
|
||||
#[cfg(windows)]
|
||||
#[error("could not get windows app lock: {0:?}")]
|
||||
AppLockFailed(std::io::Error),
|
||||
}
|
||||
|
||||
makeAnyError!(
|
||||
|
||||
Reference in New Issue
Block a user