mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-04-05 23:31:29 +03:00
Merge remote-tracking branch 'upstream/master'
# Conflicts: # Cargo.lock # src/server/connection.rs
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
use super::{input_service::*, *};
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
use crate::clipboard_file::*;
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
use crate::common::update_clipboard;
|
||||
@@ -44,12 +44,14 @@ use hbb_common::{
|
||||
use scrap::android::{call_main_service_pointer_input, call_main_service_key_event};
|
||||
#[cfg(target_os = "android")]
|
||||
use crate::keyboard::client::map_key_to_control_key;
|
||||
use serde_derive::Serialize;
|
||||
use serde_json::{json, value::Value};
|
||||
use sha2::{Digest, Sha256};
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::{
|
||||
num::NonZeroI64,
|
||||
path::PathBuf,
|
||||
sync::{atomic::AtomicI64, mpsc as std_mpsc},
|
||||
};
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
@@ -181,6 +183,7 @@ pub struct Connection {
|
||||
file: bool,
|
||||
restart: bool,
|
||||
recording: bool,
|
||||
block_input: bool,
|
||||
last_test_delay: i64,
|
||||
network_delay: Option<u32>,
|
||||
lock_after_session_end: bool,
|
||||
@@ -194,7 +197,7 @@ pub struct Connection {
|
||||
// by peer
|
||||
disable_audio: bool,
|
||||
// by peer
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
enable_file_transfer: bool,
|
||||
// by peer
|
||||
audio_sender: Option<MediaSender>,
|
||||
@@ -225,6 +228,7 @@ pub struct Connection {
|
||||
start_cm_ipc_para: Option<StartCmIpcPara>,
|
||||
auto_disconnect_timer: Option<(Instant, u64)>,
|
||||
authed_conn_id: Option<self::raii::AuthedConnID>,
|
||||
file_remove_log_control: FileRemoveLogControl,
|
||||
}
|
||||
|
||||
impl ConnInner {
|
||||
@@ -326,13 +330,14 @@ impl Connection {
|
||||
file: Connection::permission("enable-file-transfer"),
|
||||
restart: Connection::permission("enable-remote-restart"),
|
||||
recording: Connection::permission("enable-record-session"),
|
||||
block_input: Connection::permission("enable-block-input"),
|
||||
last_test_delay: 0,
|
||||
network_delay: None,
|
||||
lock_after_session_end: false,
|
||||
show_remote_cursor: false,
|
||||
ip: "".to_owned(),
|
||||
disable_audio: false,
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
enable_file_transfer: false,
|
||||
disable_clipboard: false,
|
||||
disable_keyboard: false,
|
||||
@@ -367,6 +372,7 @@ impl Connection {
|
||||
}),
|
||||
auto_disconnect_timer: None,
|
||||
authed_conn_id: None,
|
||||
file_remove_log_control: FileRemoveLogControl::new(id),
|
||||
};
|
||||
let addr = hbb_common::try_into_v4(addr);
|
||||
if !conn.on_open(addr).await {
|
||||
@@ -395,6 +401,9 @@ impl Connection {
|
||||
if !conn.recording {
|
||||
conn.send_permission(Permission::Recording, false).await;
|
||||
}
|
||||
if !conn.block_input {
|
||||
conn.send_permission(Permission::BlockInput, false).await;
|
||||
}
|
||||
let mut test_delay_timer =
|
||||
time::interval_at(Instant::now() + TEST_DELAY_TIMEOUT, TEST_DELAY_TIMEOUT);
|
||||
let mut last_recv_time = Instant::now();
|
||||
@@ -476,12 +485,15 @@ impl Connection {
|
||||
} else if &name == "recording" {
|
||||
conn.recording = enabled;
|
||||
conn.send_permission(Permission::Recording, enabled).await;
|
||||
} else if &name == "block_input" {
|
||||
conn.block_input = enabled;
|
||||
conn.send_permission(Permission::BlockInput, enabled).await;
|
||||
}
|
||||
}
|
||||
ipc::Data::RawMessage(bytes) => {
|
||||
allow_err!(conn.stream.send_raw(bytes).await);
|
||||
}
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os="windows", target_os="linux", target_os = "macos"))]
|
||||
ipc::Data::ClipboardFile(clip) => {
|
||||
allow_err!(conn.stream.send(&clip_2_msg(clip)).await);
|
||||
}
|
||||
@@ -558,11 +570,11 @@ impl Connection {
|
||||
},
|
||||
_ = conn.file_timer.tick() => {
|
||||
if !conn.read_jobs.is_empty() {
|
||||
conn.send_to_cm(ipc::Data::FileTransferLog(fs::serialize_transfer_jobs(&conn.read_jobs)));
|
||||
conn.send_to_cm(ipc::Data::FileTransferLog(("transfer".to_string(), fs::serialize_transfer_jobs(&conn.read_jobs))));
|
||||
match fs::handle_read_jobs(&mut conn.read_jobs, &mut conn.stream).await {
|
||||
Ok(log) => {
|
||||
if !log.is_empty() {
|
||||
conn.send_to_cm(ipc::Data::FileTransferLog(log));
|
||||
conn.send_to_cm(ipc::Data::FileTransferLog(("transfer".to_string(), log)));
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
@@ -634,6 +646,7 @@ impl Connection {
|
||||
break;
|
||||
}
|
||||
}
|
||||
conn.file_remove_log_control.on_timer().drain(..).map(|x| conn.send_to_cm(x)).count();
|
||||
}
|
||||
_ = test_delay_timer.tick() => {
|
||||
if last_recv_time.elapsed() >= SEC30 {
|
||||
@@ -672,7 +685,6 @@ impl Connection {
|
||||
conn.lr.my_id.clone(),
|
||||
);
|
||||
video_service::notify_video_frame_fetched(id, None);
|
||||
scrap::codec::Encoder::update(id, scrap::codec::EncodingUpdate::Remove);
|
||||
if conn.authorized {
|
||||
password::update_temporary_password();
|
||||
}
|
||||
@@ -1034,7 +1046,7 @@ impl Connection {
|
||||
pi.hostname = DEVICE_NAME.lock().unwrap().clone();
|
||||
pi.platform = "Android".into();
|
||||
}
|
||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||
#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
|
||||
let mut platform_additions = serde_json::Map::new();
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
@@ -1064,7 +1076,18 @@ impl Connection {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||
#[cfg(any(
|
||||
target_os = "windows",
|
||||
all(
|
||||
any(target_os = "linux", target_os = "macos"),
|
||||
feature = "unix-file-copy-paste"
|
||||
)
|
||||
))]
|
||||
{
|
||||
platform_additions.insert("has_file_clipboard".into(), json!(true));
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
|
||||
if !platform_additions.is_empty() {
|
||||
pi.platform_additions = serde_json::to_string(&platform_additions).unwrap_or("".into());
|
||||
}
|
||||
@@ -1164,7 +1187,7 @@ impl Connection {
|
||||
sub_service = true;
|
||||
}
|
||||
}
|
||||
Self::on_remote_authorized();
|
||||
self.on_remote_authorized();
|
||||
}
|
||||
let mut msg_out = Message::new();
|
||||
msg_out.set_login_response(res);
|
||||
@@ -1203,9 +1226,10 @@ impl Connection {
|
||||
}
|
||||
}
|
||||
|
||||
fn on_remote_authorized() {
|
||||
fn on_remote_authorized(&self) {
|
||||
use std::sync::Once;
|
||||
static ONCE: Once = Once::new();
|
||||
static _ONCE: Once = Once::new();
|
||||
self.update_codec_on_login();
|
||||
#[cfg(any(target_os = "windows", target_os = "linux"))]
|
||||
if !Config::get_option("allow-remove-wallpaper").is_empty() {
|
||||
// multi connections set once
|
||||
@@ -1214,7 +1238,7 @@ impl Connection {
|
||||
match crate::platform::WallPaperRemover::new() {
|
||||
Ok(remover) => {
|
||||
*wallpaper = Some(remover);
|
||||
ONCE.call_once(|| {
|
||||
_ONCE.call_once(|| {
|
||||
shutdown_hooks::add_shutdown_hook(shutdown_hook);
|
||||
});
|
||||
}
|
||||
@@ -1238,7 +1262,7 @@ impl Connection {
|
||||
self.audio && !self.disable_audio
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
fn file_transfer_enabled(&self) -> bool {
|
||||
self.file && self.enable_file_transfer
|
||||
}
|
||||
@@ -1258,6 +1282,7 @@ impl Connection {
|
||||
file_transfer_enabled: self.file,
|
||||
restart: self.restart,
|
||||
recording: self.recording,
|
||||
block_input: self.block_input,
|
||||
from_switch: self.from_switch,
|
||||
});
|
||||
}
|
||||
@@ -1403,8 +1428,8 @@ impl Connection {
|
||||
return Config::get_option(enable_prefix_option).is_empty();
|
||||
}
|
||||
|
||||
fn update_codec_on_login(&self, lr: &LoginRequest) {
|
||||
if let Some(o) = lr.option.as_ref() {
|
||||
fn update_codec_on_login(&self) {
|
||||
if let Some(o) = self.lr.clone().option.as_ref() {
|
||||
if let Some(q) = o.supported_decoding.clone().take() {
|
||||
scrap::codec::Encoder::update(
|
||||
self.inner.id(),
|
||||
@@ -1429,9 +1454,6 @@ impl Connection {
|
||||
if let Some(o) = lr.option.as_ref() {
|
||||
self.options_in_login = Some(o.clone());
|
||||
}
|
||||
if lr.union.is_none() {
|
||||
self.update_codec_on_login(&lr);
|
||||
}
|
||||
self.video_ack_required = lr.video_ack_required;
|
||||
}
|
||||
|
||||
@@ -1856,8 +1878,9 @@ impl Connection {
|
||||
}
|
||||
Some(message::Union::Cliprdr(_clip)) =>
|
||||
{
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
if let Some(clip) = msg_2_clip(_clip) {
|
||||
log::debug!("got clipfile from client peer");
|
||||
self.send_to_cm(ipc::Data::ClipboardFile(clip))
|
||||
}
|
||||
}
|
||||
@@ -1952,30 +1975,43 @@ impl Connection {
|
||||
}
|
||||
Some(file_action::Union::RemoveDir(d)) => {
|
||||
self.send_fs(ipc::FS::RemoveDir {
|
||||
path: d.path,
|
||||
path: d.path.clone(),
|
||||
id: d.id,
|
||||
recursive: d.recursive,
|
||||
});
|
||||
self.file_remove_log_control.on_remove_dir(d);
|
||||
}
|
||||
Some(file_action::Union::RemoveFile(f)) => {
|
||||
self.send_fs(ipc::FS::RemoveFile {
|
||||
path: f.path,
|
||||
path: f.path.clone(),
|
||||
id: f.id,
|
||||
file_num: f.file_num,
|
||||
});
|
||||
self.file_remove_log_control.on_remove_file(f);
|
||||
}
|
||||
Some(file_action::Union::Create(c)) => {
|
||||
self.send_fs(ipc::FS::CreateDir {
|
||||
path: c.path,
|
||||
path: c.path.clone(),
|
||||
id: c.id,
|
||||
});
|
||||
self.send_to_cm(ipc::Data::FileTransferLog((
|
||||
"create_dir".to_string(),
|
||||
serde_json::to_string(&FileActionLog {
|
||||
id: c.id,
|
||||
conn_id: self.inner.id(),
|
||||
path: c.path,
|
||||
dir: true,
|
||||
})
|
||||
.unwrap_or_default(),
|
||||
)));
|
||||
}
|
||||
Some(file_action::Union::Cancel(c)) => {
|
||||
self.send_fs(ipc::FS::CancelWrite { id: c.id });
|
||||
if let Some(job) = fs::get_job_immutable(c.id, &self.read_jobs) {
|
||||
self.send_to_cm(ipc::Data::FileTransferLog(
|
||||
self.send_to_cm(ipc::Data::FileTransferLog((
|
||||
"transfer".to_string(),
|
||||
fs::serialize_transfer_job(job, false, true, ""),
|
||||
));
|
||||
)));
|
||||
}
|
||||
fs::remove_job(c.id, &mut self.read_jobs);
|
||||
}
|
||||
@@ -2215,8 +2251,9 @@ impl Connection {
|
||||
}
|
||||
|
||||
// Send display changed message.
|
||||
// For compatibility with old versions ( < 1.2.4 ).
|
||||
// sciter need it in new version
|
||||
// 1. For compatibility with old versions ( < 1.2.4 ).
|
||||
// 2. Sciter version.
|
||||
// 3. Update `SupportedResolutions`.
|
||||
if let Some(msg_out) = video_service::make_display_changed_msg(self.display_idx, None) {
|
||||
self.send(msg_out).await;
|
||||
}
|
||||
@@ -2232,7 +2269,11 @@ impl Connection {
|
||||
lock.add_service(Box::new(video_service::new(display_idx)));
|
||||
}
|
||||
}
|
||||
lock.subscribe(&old_service_name, self.inner.clone(), false);
|
||||
// For versions greater than 1.2.4, a `CaptureDisplays` message will be sent immediately.
|
||||
// Unnecessary capturers will be removed then.
|
||||
if !crate::common::is_support_multi_ui_session(&self.lr.version) {
|
||||
lock.subscribe(&old_service_name, self.inner.clone(), false);
|
||||
}
|
||||
lock.subscribe(&new_service_name, self.inner.clone(), true);
|
||||
self.display_idx = display_idx;
|
||||
}
|
||||
@@ -2439,7 +2480,7 @@ impl Connection {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
if let Ok(q) = o.enable_file_transfer.enum_value() {
|
||||
if q != BoolOption::NotSet {
|
||||
self.enable_file_transfer = q == BoolOption::Yes;
|
||||
@@ -2544,8 +2585,8 @@ impl Connection {
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.keyboard {
|
||||
if let Ok(q) = o.block_input.enum_value() {
|
||||
if let Ok(q) = o.block_input.enum_value() {
|
||||
if self.keyboard && self.block_input {
|
||||
match q {
|
||||
BoolOption::Yes => {
|
||||
self.tx_input.send(MessageInput::BlockOn).ok();
|
||||
@@ -2555,6 +2596,17 @@ impl Connection {
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
if q != BoolOption::NotSet {
|
||||
let state = if q == BoolOption::Yes {
|
||||
back_notification::BlockInputState::BlkOnFailed
|
||||
} else {
|
||||
back_notification::BlockInputState::BlkOffFailed
|
||||
};
|
||||
if let Some(tx) = &self.inner.tx {
|
||||
Self::send_block_input_error(tx, state, "No permission".to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2909,6 +2961,114 @@ pub enum FileAuditType {
|
||||
RemoteReceive = 1,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct FileActionLog {
|
||||
id: i32,
|
||||
conn_id: i32,
|
||||
path: String,
|
||||
dir: bool,
|
||||
}
|
||||
|
||||
struct FileRemoveLogControl {
|
||||
conn_id: i32,
|
||||
instant: Instant,
|
||||
removed_files: Vec<FileRemoveFile>,
|
||||
removed_dirs: Vec<FileRemoveDir>,
|
||||
}
|
||||
|
||||
impl FileRemoveLogControl {
|
||||
fn new(conn_id: i32) -> Self {
|
||||
FileRemoveLogControl {
|
||||
conn_id,
|
||||
instant: Instant::now(),
|
||||
removed_files: vec![],
|
||||
removed_dirs: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
fn on_remove_file(&mut self, f: FileRemoveFile) -> Option<ipc::Data> {
|
||||
self.instant = Instant::now();
|
||||
self.removed_files.push(f.clone());
|
||||
Some(ipc::Data::FileTransferLog((
|
||||
"remove".to_string(),
|
||||
serde_json::to_string(&FileActionLog {
|
||||
id: f.id,
|
||||
conn_id: self.conn_id,
|
||||
path: f.path,
|
||||
dir: false,
|
||||
})
|
||||
.unwrap_or_default(),
|
||||
)))
|
||||
}
|
||||
|
||||
fn on_remove_dir(&mut self, d: FileRemoveDir) -> Option<ipc::Data> {
|
||||
self.instant = Instant::now();
|
||||
let direct_child = |parent: &str, child: &str| {
|
||||
PathBuf::from(child).parent().map(|x| x.to_path_buf()) == Some(PathBuf::from(parent))
|
||||
};
|
||||
self.removed_files
|
||||
.retain(|f| !direct_child(&f.path, &d.path));
|
||||
self.removed_dirs
|
||||
.retain(|x| !direct_child(&d.path, &x.path));
|
||||
if !self
|
||||
.removed_dirs
|
||||
.iter()
|
||||
.any(|x| direct_child(&x.path, &d.path))
|
||||
{
|
||||
self.removed_dirs.push(d.clone());
|
||||
}
|
||||
Some(ipc::Data::FileTransferLog((
|
||||
"remove".to_string(),
|
||||
serde_json::to_string(&FileActionLog {
|
||||
id: d.id,
|
||||
conn_id: self.conn_id,
|
||||
path: d.path,
|
||||
dir: true,
|
||||
})
|
||||
.unwrap_or_default(),
|
||||
)))
|
||||
}
|
||||
|
||||
fn on_timer(&mut self) -> Vec<ipc::Data> {
|
||||
if self.instant.elapsed().as_secs() < 1 {
|
||||
return vec![];
|
||||
}
|
||||
let mut v: Vec<ipc::Data> = vec![];
|
||||
self.removed_files
|
||||
.drain(..)
|
||||
.map(|f| {
|
||||
v.push(ipc::Data::FileTransferLog((
|
||||
"remove".to_string(),
|
||||
serde_json::to_string(&FileActionLog {
|
||||
id: f.id,
|
||||
conn_id: self.conn_id,
|
||||
path: f.path,
|
||||
dir: false,
|
||||
})
|
||||
.unwrap_or_default(),
|
||||
)));
|
||||
})
|
||||
.count();
|
||||
self.removed_dirs
|
||||
.drain(..)
|
||||
.map(|d| {
|
||||
v.push(ipc::Data::FileTransferLog((
|
||||
"remove".to_string(),
|
||||
serde_json::to_string(&FileActionLog {
|
||||
id: d.id,
|
||||
conn_id: self.conn_id,
|
||||
path: d.path,
|
||||
dir: true,
|
||||
})
|
||||
.unwrap_or_default(),
|
||||
)));
|
||||
})
|
||||
.count();
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub struct PortableState {
|
||||
pub last_uac: bool,
|
||||
@@ -3002,18 +3162,6 @@ mod raii {
|
||||
fn drop(&mut self) {
|
||||
let mut active_conns_lock = ALIVE_CONNS.lock().unwrap();
|
||||
active_conns_lock.retain(|&c| c != self.0);
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
if active_conns_lock.is_empty() {
|
||||
display_service::reset_resolutions();
|
||||
}
|
||||
#[cfg(all(windows, feature = "virtual_display_driver"))]
|
||||
if active_conns_lock.is_empty() {
|
||||
let _ = virtual_display_manager::reset_all();
|
||||
}
|
||||
#[cfg(all(windows))]
|
||||
if active_conns_lock.is_empty() {
|
||||
crate::privacy_win_mag::stop();
|
||||
}
|
||||
video_service::VIDEO_QOS
|
||||
.lock()
|
||||
.unwrap()
|
||||
@@ -3021,17 +3169,20 @@ mod raii {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AuthedConnID(i32);
|
||||
pub struct AuthedConnID(i32, AuthConnType);
|
||||
|
||||
impl AuthedConnID {
|
||||
pub fn new(id: i32, conn_type: AuthConnType) -> Self {
|
||||
AUTHED_CONNS.lock().unwrap().push((id, conn_type));
|
||||
Self(id)
|
||||
Self(id, conn_type)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for AuthedConnID {
|
||||
fn drop(&mut self) {
|
||||
if self.1 == AuthConnType::Remote {
|
||||
scrap::codec::Encoder::update(self.0, scrap::codec::EncodingUpdate::Remove);
|
||||
}
|
||||
let mut lock = AUTHED_CONNS.lock().unwrap();
|
||||
lock.retain(|&c| c.0 != self.0);
|
||||
if lock.iter().filter(|c| c.1 == AuthConnType::Remote).count() == 0 {
|
||||
@@ -3039,6 +3190,12 @@ mod raii {
|
||||
{
|
||||
*WALLPAPER_REMOVER.lock().unwrap() = None;
|
||||
}
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
display_service::reset_resolutions();
|
||||
#[cfg(all(windows, feature = "virtual_display_driver"))]
|
||||
let _ = virtual_display_manager::reset_all();
|
||||
#[cfg(all(windows))]
|
||||
crate::privacy_win_mag::stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user