diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index d7a0995c8..6f85f6076 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -22,13 +22,22 @@ use hbb_common::tokio::{ sync::mpsc, time::{self, Duration, Instant, Interval}, }; -use hbb_common::{allow_err, message_proto::*, sleep}; +use hbb_common::{ + allow_err, + message_proto::{self, *}, + sleep, +}; use hbb_common::{fs, log, Stream}; use std::collections::HashMap; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, Mutex}; +lazy_static::lazy_static! { + #[cfg(windows)] + static ref CLIPBOARD_FILE_CONTEXT: Mutex = Mutex::new(0); +} + pub struct Remote { handler: Session, video_sender: MediaSender, @@ -43,14 +52,42 @@ pub struct Remote { last_update_jobs_status: (Instant, HashMap), first_frame: bool, #[cfg(windows)] - clipboard_file_context: Option>, - #[cfg(windows)] client_conn_id: i32, // used for clipboard data_count: Arc, frame_count: Arc, video_format: CodecFormat, } +#[cfg(windows)] +fn check_clipboard_file_context(enable_file_transfer: bool) { + let enabled = SERVER_FILE_TRANSFER_ENABLED.load(Ordering::SeqCst) && enable_file_transfer; + let mut lock = CLIPBOARD_FILE_CONTEXT.lock().unwrap(); + if enabled { + if *lock == 0 { + match clipboard::create_cliprdr_context(true, false) { + Ok(context) => { + log::info!("clipboard context for file transfer created."); + *lock = Box::into_raw(context) as _; + } + Err(err) => { + log::error!( + "Create clipboard context for file transfer: {}", + err.to_string() + ); + } + } + } + } else { + if *lock != 0 { + unsafe { + let _ = Box::from_raw(*lock as *mut clipboard::cliprdr::CliprdrClientContext); + } + log::info!("clipboard context for file transfer destroyed."); + *lock = 0; + } + } +} + impl Remote { pub fn new( handler: Session, @@ -74,8 +111,6 @@ impl Remote { last_update_jobs_status: (Instant::now(), Default::default()), first_frame: false, #[cfg(windows)] - clipboard_file_context: None, - #[cfg(windows)] client_conn_id: 0, data_count: Arc::new(AtomicUsize::new(0)), frame_count, @@ -789,13 +824,7 @@ impl Remote { } #[cfg(windows)] Some(message::Union::Cliprdr(clip)) => { - if !self.handler.lc.read().unwrap().disable_clipboard { - if let Some(context) = &mut self.clipboard_file_context { - if let Some(clip) = crate::clipboard_file::msg_2_clip(clip) { - clipboard::server_clip_file(context, self.client_conn_id, clip); - } - } - } + self.handle_cliprdr_msg(clip); } Some(message::Union::FileResponse(fr)) => { match fr.union { @@ -1169,30 +1198,25 @@ impl Remote { true } - fn check_clipboard_file_context(&mut self) { + fn check_clipboard_file_context(&self) { #[cfg(windows)] { - let enabled = SERVER_FILE_TRANSFER_ENABLED.load(Ordering::SeqCst) - && self.handler.lc.read().unwrap().enable_file_transfer; - if enabled == self.clipboard_file_context.is_none() { - self.clipboard_file_context = if enabled { - match clipboard::create_cliprdr_context(true, false) { - Ok(context) => { - log::info!("clipboard context for file transfer created."); - Some(context) - } - Err(err) => { - log::error!( - "Create clipboard context for file transfer: {}", - err.to_string() - ); - None - } + check_clipboard_file_context(self.handler.lc.read().unwrap().enable_file_transfer); + } + } + + fn handle_cliprdr_msg(&self, clip: message_proto::Cliprdr) { + if !self.handler.lc.read().unwrap().disable_clipboard { + let mut lock = CLIPBOARD_FILE_CONTEXT.lock().unwrap(); + if *lock != 0 { + unsafe { + let mut context = + Box::from_raw(*lock as *mut clipboard::cliprdr::CliprdrClientContext); + if let Some(clip) = crate::clipboard_file::msg_2_clip(clip) { + clipboard::server_clip_file(&mut context, self.client_conn_id, clip); } - } else { - log::info!("clipboard context for file transfer destroyed."); - None - }; + *lock = Box::into_raw(context) as _; + } } } } diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs index 886babe0f..188398bb2 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -220,7 +220,7 @@ pub fn get_clients_length() -> usize { #[derive(Debug)] pub enum ClipboardFileData { #[cfg(windows)] - Clip(ipc::ClipbaordFile), + Clip((i32, ipc::ClipbaordFile)), Enable((i32, bool)), } @@ -267,30 +267,10 @@ async fn cm_ipc_task_wait_login( (stream, cm, ret) } -#[cfg(windows)] -fn create_cliprdr_context_(enabled: bool) -> Option> { - if enabled { - match clipboard::create_cliprdr_context(true, false) { - Ok(context) => { - log::info!("clipboard context for file transfer created."); - Some(context) - } - Err(err) => { - log::error!( - "Create clipboard context for file transfer: {}", - err.to_string() - ); - None - } - } - } else { - None - } -} - async fn cm_ipc_task_loop( mut stream: Connection, cm: ConnectionManager, + tx_file: mpsc::UnboundedSender, tx: mpsc::UnboundedSender, mut rx: mpsc::UnboundedReceiver, mut conn_id: i32, @@ -303,14 +283,14 @@ async fn cm_ipc_task_loop( let mut write_jobs: Vec = Vec::new(); let mut close = true; - let (tx_file, _rx_file) = mpsc::unbounded_channel::(); - #[cfg(windows)] - std::thread::spawn(move || { - start_clipboard_file(conn_id, _rx_file); - }); #[cfg(windows)] allow_err!(tx_file.send(ClipboardFileData::Enable((conn_id, file_transfer_enabled)))); + #[cfg(windows)] + let rx_clip_client1 = clipboard::get_rx_cliprdr_server(conn_id); + #[cfg(windows)] + let mut rx_clip_client = rx_clip_client1.lock().await; + loop { tokio::select! { res = stream.next() => { @@ -347,7 +327,7 @@ async fn cm_ipc_task_loop( } #[cfg(windows)] Data::ClipbaordFile(_clip) => { - allow_err!(tx_file.send(ClipboardFileData::Clip(_clip))); + allow_err!(tx_file.send(ClipboardFileData::Clip((conn_id, _clip)))); } #[cfg(windows)] Data::ClipboardFileEnabled(enabled) => { @@ -373,6 +353,14 @@ async fn cm_ipc_task_loop( break; } } + clip_file = rx_clip_client.recv() => match clip_file { + Some(clip) => { + allow_err!(tx.send(Data::ClipbaordFile(clip))); + } + None => { + // + } + }, } } if conn_id != conn_id_tmp { @@ -380,11 +368,15 @@ async fn cm_ipc_task_loop( } } -async fn cm_ipc_task(stream: Connection, cm: ConnectionManager) { +async fn cm_ipc_task( + stream: Connection, + cm: ConnectionManager, + tx_file: mpsc::UnboundedSender, +) { let (tx, rx) = mpsc::unbounded_channel::(); let (stream, cm, wait_res) = cm_ipc_task_wait_login(stream, cm, tx.clone()).await; if let Some((conn_id, file_transfer_enabled)) = wait_res { - cm_ipc_task_loop(stream, cm, tx, rx, conn_id, file_transfer_enabled).await; + cm_ipc_task_loop(stream, cm, tx_file, tx, rx, conn_id, file_transfer_enabled).await; } } @@ -394,6 +386,9 @@ pub async fn start_ipc(cm: ConnectionManager) { #[cfg(windows)] let cm_clip = cm.clone(); + let (tx_file, _rx_file) = mpsc::unbounded_channel::(); + std::thread::spawn(move || start_clipboard_file(_rx_file)); + #[cfg(windows)] std::thread::spawn(move || { log::info!("try create privacy mode window"); @@ -415,7 +410,11 @@ pub async fn start_ipc(cm: ConnectionManager) { match result { Ok(stream) => { log::debug!("Got new connection"); - tokio::spawn(cm_ipc_task(Connection::new(stream), cm.clone())); + tokio::spawn(cm_ipc_task( + Connection::new(stream), + cm.clone(), + tx_file.clone(), + )); } Err(err) => { log::error!("Couldn't get cm client: {:?}", err); @@ -718,29 +717,13 @@ fn send_raw(msg: Message, tx: &UnboundedSender) { #[cfg(windows)] #[tokio::main(flavor = "current_thread")] -pub async fn start_clipboard_file( - conn_id: i32, - mut rx: mpsc::UnboundedReceiver, -) { +pub async fn start_clipboard_file(mut rx: mpsc::UnboundedReceiver) { let mut cliprdr_context = None; - let rx_clip_client1 = clipboard::get_rx_cliprdr_server(conn_id); - let mut rx_clip_client = rx_clip_client1.lock().await; loop { tokio::select! { - clip_file = rx_clip_client.recv() => match clip_file { - Some(clip) => { - cmd_inner_send( - conn_id, - Data::ClipbaordFile(clip) - ); - } - None => { - // - } - }, server_msg = rx.recv() => match server_msg { - Some(ClipboardFileData::Clip(clip)) => { + Some(ClipboardFileData::Clip((conn_id, clip))) => { if let Some(ctx) = cliprdr_context.as_mut() { clipboard::server_clip_file(ctx, conn_id, clip); } @@ -775,17 +758,3 @@ pub async fn start_clipboard_file( } } } - -#[cfg(windows)] -fn cmd_inner_send(id: i32, data: Data) { - let lock = CLIENTS.read().unwrap(); - if id != 0 { - if let Some(s) = lock.get(&id) { - allow_err!(s.tx.send(data)); - } - } else { - for s in lock.values() { - allow_err!(s.tx.send(data.clone())); - } - } -}