mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-06-22 10:02:20 +00:00
Merge branch 'rustdesk:master' into master
This commit is contained in:
commit
a49f558dd6
5 changed files with 128 additions and 24 deletions
15
Cargo.lock
generated
15
Cargo.lock
generated
|
|
@ -1324,7 +1324,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "clipboard-master"
|
||||
version = "4.0.0-beta.6"
|
||||
source = "git+https://github.com/rustdesk-org/clipboard-master#ddc39f00a6211959489ae683aa6ae6eedf03a809"
|
||||
source = "git+https://github.com/rustdesk-org/clipboard-master#7762d74e38db37cfeb6ded88c964b9cdbddfb6db"
|
||||
dependencies = [
|
||||
"objc",
|
||||
"objc-foundation",
|
||||
|
|
@ -9733,9 +9733,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wayland-protocols-wlr"
|
||||
version = "0.3.3"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd993de54a40a40fbe5601d9f1fbcaef0aebcc5fda447d7dc8f6dcbaae4f8953"
|
||||
checksum = "efd94963ed43cf9938a090ca4f7da58eb55325ec8200c3848963e98dc25b78ec"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"wayland-backend",
|
||||
|
|
@ -10838,16 +10838,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wl-clipboard-rs"
|
||||
version = "0.9.0"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4de22eebb1d1e2bad2d970086e96da0e12cde0b411321e5b0f7b2a1f876aa26f"
|
||||
checksum = "e9651471a32e87d96ef3a127715382b2d11cc7c8bb9822ded8a7cc94072eb0a3"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"os_pipe",
|
||||
"rustix 0.38.34",
|
||||
"tempfile",
|
||||
"thiserror 1.0.61",
|
||||
"rustix 1.1.2",
|
||||
"thiserror 2.0.17",
|
||||
"tree_magic_mini",
|
||||
"wayland-backend",
|
||||
"wayland-client",
|
||||
|
|
|
|||
|
|
@ -868,6 +868,7 @@ pub mod clipboard_listener {
|
|||
.unwrap()
|
||||
.insert(name.clone(), tx);
|
||||
|
||||
cleanup_stale_listener(&mut listener_lock);
|
||||
if listener_lock.handle.is_none() {
|
||||
log::info!("Start clipboard listener thread");
|
||||
let handler = Handler {
|
||||
|
|
@ -893,6 +894,24 @@ pub mod clipboard_listener {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn cleanup_stale_listener(listener: &mut ClipboardListener) {
|
||||
if !listener
|
||||
.handle
|
||||
.as_ref()
|
||||
.map(|(_, h)| h.is_finished())
|
||||
.unwrap_or(false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if let Some((shutdown, h)) = listener.handle.take() {
|
||||
log::warn!("Cleaning up stale clipboard listener handle");
|
||||
if let Err(e) = h.join() {
|
||||
log::error!("Clipboard listener thread panicked during stale cleanup: {:?}", e);
|
||||
}
|
||||
drop(shutdown);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unsubscribe(name: &str) {
|
||||
log::info!("Unsubscribe clipboard listener: {}", name);
|
||||
let mut listener_lock = CLIPBOARD_LISTENER.lock().unwrap();
|
||||
|
|
|
|||
|
|
@ -759,7 +759,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remember-wayland-keyboard-choice-tip", "Non chiedere più per questo computer remoto"),
|
||||
("Why this happens", "Perché accade questo"),
|
||||
("Switch display", "Cambia schermo"),
|
||||
("Show monitor switch button on the main toolbar", "Mostra il pulsante di cambio monitor nella barra degli strumenti principale"),
|
||||
("Show on the minimized toolbar", "Mostra nella barra degli strumenti ridotta a icona"),
|
||||
("Show monitor switch button on the main toolbar", "Visualizza nella barra strumenti principale il pulsante per il cambio schermo"),
|
||||
("Show on the minimized toolbar", "Visualizza nella barra strumenti ridotta a icona"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,18 +16,18 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Control Remote Desktop", "Controle um Computador Remoto"),
|
||||
("Transfer file", "Transferir arquivos"),
|
||||
("Connect", "Conectar"),
|
||||
("Recent sessions", "Sessões Recentes"),
|
||||
("Address book", "Lista de Endereços"),
|
||||
("Recent sessions", "Sessões recentes"),
|
||||
("Address book", "Lista de endereços"),
|
||||
("Confirmation", "Confirmação"),
|
||||
("TCP tunneling", "Tunelamento TCP"),
|
||||
("Remove", "Remover"),
|
||||
("Refresh random password", "Atualizar senha aleatória"),
|
||||
("Set your own password", "Configure sua própria senha"),
|
||||
("Refresh random password", "Gerar nova senha aleatória"),
|
||||
("Set your own password", "Definir sua própria senha"),
|
||||
("Enable keyboard/mouse", "Habilitar teclado/mouse"),
|
||||
("Enable clipboard", "Habilitar área de transferência"),
|
||||
("Enable file transfer", "Habilitar transferência de arquivos"),
|
||||
("Enable TCP tunneling", "Habilitar tunelamento TCP"),
|
||||
("IP Whitelisting", "Lista de IPs Confiáveis"),
|
||||
("IP Whitelisting", "Lista de IPs Permitidos"),
|
||||
("ID/Relay Server", "Servidor ID/Relay"),
|
||||
("Import server config", "Importar Configuração do Servidor"),
|
||||
("Export Server Config", "Exportar Configuração do Servidor"),
|
||||
|
|
@ -320,12 +320,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Exit Fullscreen", "Sair da Tela Cheia"),
|
||||
("Fullscreen", "Tela Cheia"),
|
||||
("Mobile Actions", "Ações móveis"),
|
||||
("Select Monitor", "Selecionar monitor"),
|
||||
("Select Monitor", "Selecionar tela"),
|
||||
("Control Actions", "Controlar ações"),
|
||||
("Display Settings", "Configurações de exibição"),
|
||||
("Ratio", "Proporção"),
|
||||
("Image Quality", "Qualidade de imagem"),
|
||||
("Scroll Style", "Estilo de Rolagem"),
|
||||
("Scroll Style", "Estilo de rolagem"),
|
||||
("Show Toolbar", "Mostrar barra de ferramentas"),
|
||||
("Hide Toolbar", "Ocultar barra de ferramentas"),
|
||||
("Direct Connection", "Conexão Direta"),
|
||||
|
|
@ -353,7 +353,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Disconnect all devices?", "Desconectar todos os dispositivos?"),
|
||||
("Clear", "Limpar"),
|
||||
("Audio Input Device", "Dispositivo de entrada de áudio"),
|
||||
("Use IP Whitelisting", "Utilizar lista de IPs confiáveis"),
|
||||
("Use IP Whitelisting", "Utilizar lista de IPs permitidos"),
|
||||
("Network", "Rede"),
|
||||
("Pin Toolbar", "Fixar barra de ferramentas"),
|
||||
("Unpin Toolbar", "Desafixar barra de ferramentas"),
|
||||
|
|
@ -463,7 +463,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Empty Password", "Senha Vazia"),
|
||||
("Me", "Eu"),
|
||||
("identical_file_tip", "Este arquivo é idêntico ao do parceiro."),
|
||||
("show_monitors_tip", "Mostrar monitores na barra de ferramentas"),
|
||||
("show_monitors_tip", "Mostrar telas na barra de ferramentas"),
|
||||
("View Mode", "Modo de visualização"),
|
||||
("login_linux_tip", "Você precisa fazer login na conta Linux remota para habilitar uma sessão de desktop X"),
|
||||
("verify_rustdesk_password_tip", "Verifique a senha do RustDesk"),
|
||||
|
|
@ -674,7 +674,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("dont-show-again-tip", "Não mostrar novamente"),
|
||||
("Take screenshot", "Capturar tela"),
|
||||
("Taking screenshot", "Capturando tela"),
|
||||
("screenshot-merged-screen-not-supported-tip", "Mesclar a captura de tela de múltiplos monitores não é suportada no momento. Por favor, alterne para um único monitor e tente novamente."),
|
||||
("screenshot-merged-screen-not-supported-tip", "A captura de tela de múltiplas telas não é suportada no momento. Por favor, alterne para uma única tela e tente novamente."),
|
||||
("screenshot-action-tip", "Por favor, selecione como deseja continuar com a captura de tela."),
|
||||
("Save as", "Salvar como"),
|
||||
("Copy to clipboard", "Copiar para área de transferência"),
|
||||
|
|
@ -694,7 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Enable UDP hole punching", "Habilitar UDP hole punching"),
|
||||
("View camera", "Visualizar câmera"),
|
||||
("Enable camera", "Habilitar câmera"),
|
||||
("No cameras", "Nenhuma câmeras"),
|
||||
("No cameras", "Nenhuma câmera"),
|
||||
("view_camera_unsupported_tip", "O dispositivo remoto não suporta visualização da câmera."),
|
||||
("Terminal", "Terminal"),
|
||||
("Enable terminal", "Habilitar terminal"),
|
||||
|
|
@ -759,7 +759,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remember-wayland-keyboard-choice-tip", "Não perguntar novamente para este computador remoto"),
|
||||
("Why this happens", "Por que isso acontece"),
|
||||
("Switch display", "Trocar de tela"),
|
||||
("Show monitor switch button on the main toolbar", "Mostrar o botão de troca de monitor na barra de ferramentas principal"),
|
||||
("Show monitor switch button on the main toolbar", "Mostrar botão de troca de tela na barra de ferramentas"),
|
||||
("Show on the minimized toolbar", "Mostrar na barra de ferramentas minimizada"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ fn check_desktop_manager() {
|
|||
pub fn start_xdesktop() {
|
||||
debug_assert!(crate::is_server());
|
||||
std::thread::spawn(|| {
|
||||
DesktopManager::recover_orphaned_session();
|
||||
*DESKTOP_MANAGER.lock().unwrap() = Some(DesktopManager::new());
|
||||
|
||||
let interval = time::Duration::from_millis(super::SERVICE_INTERVAL);
|
||||
|
|
@ -462,9 +463,10 @@ impl DesktopManager {
|
|||
let (child_xorg, child_wm) = Self::start_x11(uid, gid, username, display_num, &envs)?;
|
||||
is_child_running.store(true, Ordering::SeqCst);
|
||||
|
||||
// capture the logind session scope (from a live child) for teardown, see
|
||||
// reap_session_scope.
|
||||
// capture the logind session scope (from a live child) for teardown and crash
|
||||
// recovery, see reap_session_scope and recover_orphaned_session.
|
||||
let scope_dir = Self::session_scope_dir(child_xorg.id());
|
||||
Self::save_orphaned_marker(&scope_dir, display_num);
|
||||
|
||||
log::info!("Start xorg and wm done, notify and wait xtop x11");
|
||||
allow_err!(tx_res.send("".to_owned()));
|
||||
|
|
@ -879,6 +881,66 @@ impl DesktopManager {
|
|||
std::io::Error::last_os_error().raw_os_error() == Some(hbb_common::libc::EPERM)
|
||||
}
|
||||
|
||||
const ORPHANED_SESSION_KEY: &'static str = "headless-orphaned-session";
|
||||
|
||||
fn save_orphaned_marker(scope_dir: &str, display_num: u32) {
|
||||
// tag the marker with this boot's id: a logind session id is only unique within a
|
||||
// boot (the counter lives in /run and resets), so recovery must not reap a recorded
|
||||
// scope path after a reboot, when it may name a different live session.
|
||||
let boot_id = Self::current_boot_id().unwrap_or_default();
|
||||
hbb_common::config::LocalConfig::set_option(
|
||||
Self::ORPHANED_SESSION_KEY.to_owned(),
|
||||
format!("{};{};{}", scope_dir, display_num, boot_id),
|
||||
);
|
||||
}
|
||||
|
||||
fn current_boot_id() -> Option<String> {
|
||||
std::fs::read_to_string("/proc/sys/kernel/random/boot_id")
|
||||
.ok()
|
||||
.map(|s| s.trim().to_owned())
|
||||
}
|
||||
|
||||
fn clear_orphaned_marker() {
|
||||
hbb_common::config::LocalConfig::set_option(
|
||||
Self::ORPHANED_SESSION_KEY.to_owned(),
|
||||
String::new(),
|
||||
);
|
||||
}
|
||||
|
||||
fn parse_orphaned_marker(marker: &str) -> Option<(&str, u32, &str)> {
|
||||
let (rest, boot_id) = marker.rsplit_once(';')?;
|
||||
let (scope_dir, display) = rest.rsplit_once(';')?;
|
||||
Some((scope_dir, display.trim().parse::<u32>().ok()?, boot_id))
|
||||
}
|
||||
|
||||
// a run that dies before wait_stop_x11 (service or --server crash) leaks the headless
|
||||
// session scope + X lock files, the same as a missed teardown (rustdesk/rustdesk#15183).
|
||||
// reap exactly what the dead run recorded - never a scan, so unrelated sessions are safe.
|
||||
fn recover_orphaned_session() {
|
||||
let marker = hbb_common::config::LocalConfig::get_option(Self::ORPHANED_SESSION_KEY);
|
||||
if marker.is_empty() {
|
||||
return;
|
||||
}
|
||||
if let Some((scope_dir, display_num, boot_id)) = Self::parse_orphaned_marker(&marker) {
|
||||
// only reap the recorded scope when the marker is from this same boot: a leaked
|
||||
// cgroup cannot outlive a reboot, so cross-boot there is nothing legitimate to
|
||||
// reap, and the recorded "session-N.scope" may by then name a different live
|
||||
// session. the X lock cleanup is pid-guarded, so run it either way.
|
||||
let same_boot = Self::current_boot_id().map_or(false, |b| b == boot_id);
|
||||
log::info!(
|
||||
"Recovering leaked headless session from a previous run: scope {}, display {} (same boot: {})",
|
||||
scope_dir,
|
||||
display_num,
|
||||
same_boot
|
||||
);
|
||||
if same_boot {
|
||||
Self::reap_session_scope(scope_dir);
|
||||
}
|
||||
Self::cleanup_x_display_files(display_num);
|
||||
}
|
||||
Self::clear_orphaned_marker();
|
||||
}
|
||||
|
||||
fn try_wait_stop_x11(
|
||||
child_xorg: &mut Child,
|
||||
child_wm: &mut Child,
|
||||
|
|
@ -898,6 +960,7 @@ impl DesktopManager {
|
|||
Self::wait_x11_children_exit(child_xorg, child_wm);
|
||||
Self::reap_session_scope(scope_dir);
|
||||
Self::cleanup_x_display_files(display_num);
|
||||
Self::clear_orphaned_marker();
|
||||
desktop_manager
|
||||
.is_child_running
|
||||
.store(false, Ordering::SeqCst);
|
||||
|
|
@ -1082,4 +1145,27 @@ mod tests {
|
|||
|
||||
assert_eq!(pids, vec![100, 101, 200, 300]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parses_orphaned_session_marker() {
|
||||
assert_eq!(
|
||||
DesktopManager::parse_orphaned_marker(
|
||||
"/sys/fs/cgroup/user.slice/user-1000.slice/session-3.scope;7;abc-123"
|
||||
),
|
||||
Some((
|
||||
"/sys/fs/cgroup/user.slice/user-1000.slice/session-3.scope",
|
||||
7,
|
||||
"abc-123"
|
||||
))
|
||||
);
|
||||
// an empty scope still carries the display so its stale X lock can be cleaned
|
||||
assert_eq!(DesktopManager::parse_orphaned_marker(";5;abc-123"), Some(("", 5, "abc-123")));
|
||||
// an empty boot id never matches the live one, so the scope reap is skipped
|
||||
assert_eq!(DesktopManager::parse_orphaned_marker("/scope;5;"), Some(("/scope", 5, "")));
|
||||
assert_eq!(DesktopManager::parse_orphaned_marker(""), None);
|
||||
assert_eq!(DesktopManager::parse_orphaned_marker("garbage"), None);
|
||||
// the pre-boot-id two-field format no longer parses, recovery just skips it
|
||||
assert_eq!(DesktopManager::parse_orphaned_marker("/scope;7"), None);
|
||||
assert_eq!(DesktopManager::parse_orphaned_marker("/scope;notnum;abc"), None);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue