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:
Connor Peet
2023-04-10 12:25:14 -07:00
committed by GitHub
parent 116293e65e
commit b547b58db6
11 changed files with 104 additions and 8 deletions

58
cli/src/util/app_lock.rs Normal file
View 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)
};
}
}

View File

@@ -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!(