fix: win, file clipboard (#9243)

1. Return the result of `wait_response_event()` in
   `cliprdr_send_format_list()`
2. Add recv flags to avoid waiting a long time.

Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
fufesou 2024-09-03 20:55:45 +08:00 committed by GitHub
parent d4377a13c5
commit ec28567362
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 86 additions and 38 deletions

View File

@ -5,7 +5,7 @@ use std::{
}; };
#[cfg(any(target_os = "windows", feature = "unix-file-copy-paste",))] #[cfg(any(target_os = "windows", feature = "unix-file-copy-paste",))]
use hbb_common::{allow_err, log}; use hbb_common::{allow_err, bail};
use hbb_common::{ use hbb_common::{
lazy_static, lazy_static,
tokio::sync::{ tokio::sync::{
@ -25,6 +25,8 @@ pub use context_send::*;
const ERR_CODE_SERVER_FUNCTION_NONE: u32 = 0x00000001; const ERR_CODE_SERVER_FUNCTION_NONE: u32 = 0x00000001;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
const ERR_CODE_INVALID_PARAMETER: u32 = 0x00000002; const ERR_CODE_INVALID_PARAMETER: u32 = 0x00000002;
#[cfg(target_os = "windows")]
const ERR_CODE_SEND_MSG: u32 = 0x00000003;
pub(crate) use platform::create_cliprdr_context; pub(crate) use platform::create_cliprdr_context;
@ -198,7 +200,7 @@ pub fn get_rx_cliprdr_server(conn_id: i32) -> Arc<TokioMutex<UnboundedReceiver<C
#[cfg(any(target_os = "windows", feature = "unix-file-copy-paste",))] #[cfg(any(target_os = "windows", feature = "unix-file-copy-paste",))]
#[inline] #[inline]
fn send_data(conn_id: i32, data: ClipboardFile) { fn send_data(conn_id: i32, data: ClipboardFile) -> ResultType<()> {
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
return send_data_to_channel(conn_id, data); return send_data_to_channel(conn_id, data);
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
@ -210,25 +212,28 @@ fn send_data(conn_id: i32, data: ClipboardFile) {
} }
#[cfg(any(target_os = "windows", feature = "unix-file-copy-paste",))] #[cfg(any(target_os = "windows", feature = "unix-file-copy-paste",))]
#[inline] #[inline]
fn send_data_to_channel(conn_id: i32, data: ClipboardFile) { fn send_data_to_channel(conn_id: i32, data: ClipboardFile) -> ResultType<()> {
// no need to handle result here
if let Some(msg_channel) = VEC_MSG_CHANNEL if let Some(msg_channel) = VEC_MSG_CHANNEL
.read() .read()
.unwrap() .unwrap()
.iter() .iter()
.find(|x| x.conn_id == conn_id) .find(|x| x.conn_id == conn_id)
{ {
allow_err!(msg_channel.sender.send(data)); msg_channel.sender.send(data)?;
Ok(())
} else {
bail!("conn_id not found");
} }
} }
#[cfg(feature = "unix-file-copy-paste")] #[cfg(feature = "unix-file-copy-paste")]
#[inline] #[inline]
fn send_data_to_all(data: ClipboardFile) { fn send_data_to_all(data: ClipboardFile) -> ResultType<()> {
// no need to handle result here // Need more tests to see if it's necessary to handle the error.
for msg_channel in VEC_MSG_CHANNEL.read().unwrap().iter() { for msg_channel in VEC_MSG_CHANNEL.read().unwrap().iter() {
allow_err!(msg_channel.sender.send(data.clone())); allow_err!(msg_channel.sender.send(data.clone()));
} }
Ok(())
} }
#[cfg(test)] #[cfg(test)]

View File

@ -7,7 +7,7 @@
use crate::{ use crate::{
allow_err, send_data, ClipboardFile, CliprdrError, CliprdrServiceContext, ResultType, allow_err, send_data, ClipboardFile, CliprdrError, CliprdrServiceContext, ResultType,
ERR_CODE_INVALID_PARAMETER, ERR_CODE_SERVER_FUNCTION_NONE, VEC_MSG_CHANNEL, ERR_CODE_INVALID_PARAMETER, ERR_CODE_SEND_MSG, ERR_CODE_SERVER_FUNCTION_NONE, VEC_MSG_CHANNEL,
}; };
use hbb_common::log; use hbb_common::log;
use std::{ use std::{
@ -998,7 +998,7 @@ extern "C" fn notify_callback(conn_id: UINT32, msg: *const NOTIFICATION_MESSAGE)
} }
}; };
// no need to handle result here // no need to handle result here
send_data(conn_id as _, data); allow_err!(send_data(conn_id as _, data));
0 0
} }
@ -1045,7 +1045,13 @@ extern "C" fn client_format_list(
.iter() .iter()
.for_each(|msg_channel| allow_err!(msg_channel.sender.send(data.clone()))); .for_each(|msg_channel| allow_err!(msg_channel.sender.send(data.clone())));
} else { } else {
send_data(conn_id, data); match send_data(conn_id, data) {
Ok(_) => {}
Err(e) => {
log::error!("failed to send format list: {:?}", e);
return ERR_CODE_SEND_MSG;
}
}
} }
0 0
@ -1067,9 +1073,13 @@ extern "C" fn client_format_list_response(
msg_flags msg_flags
); );
let data = ClipboardFile::FormatListResponse { msg_flags }; let data = ClipboardFile::FormatListResponse { msg_flags };
send_data(conn_id, data); match send_data(conn_id, data) {
Ok(_) => 0,
0 Err(e) => {
log::error!("failed to send format list response: {:?}", e);
ERR_CODE_SEND_MSG
}
}
} }
extern "C" fn client_format_data_request( extern "C" fn client_format_data_request(
@ -1090,10 +1100,13 @@ extern "C" fn client_format_data_request(
conn_id, conn_id,
requested_format_id requested_format_id
); );
// no need to handle result here match send_data(conn_id, data) {
send_data(conn_id, data); Ok(_) => 0,
Err(e) => {
0 log::error!("failed to send format data request: {:?}", e);
ERR_CODE_SEND_MSG
}
}
} }
extern "C" fn client_format_data_response( extern "C" fn client_format_data_response(
@ -1125,9 +1138,13 @@ extern "C" fn client_format_data_response(
msg_flags, msg_flags,
format_data, format_data,
}; };
send_data(conn_id, data); match send_data(conn_id, data) {
Ok(_) => 0,
0 Err(e) => {
log::error!("failed to send format data response: {:?}", e);
ERR_CODE_SEND_MSG
}
}
} }
extern "C" fn client_file_contents_request( extern "C" fn client_file_contents_request(
@ -1175,9 +1192,13 @@ extern "C" fn client_file_contents_request(
clip_data_id, clip_data_id,
}; };
log::debug!("client_file_contents_request called, data: {:?}", &data); log::debug!("client_file_contents_request called, data: {:?}", &data);
send_data(conn_id, data); match send_data(conn_id, data) {
Ok(_) => 0,
0 Err(e) => {
log::error!("failed to send file contents request: {:?}", e);
ERR_CODE_SEND_MSG
}
}
} }
extern "C" fn client_file_contents_response( extern "C" fn client_file_contents_response(
@ -1213,7 +1234,11 @@ extern "C" fn client_file_contents_response(
msg_flags, msg_flags,
stream_id stream_id
); );
send_data(conn_id, data); match send_data(conn_id, data) {
Ok(_) => 0,
0 Err(e) => {
log::error!("failed to send file contents response: {:?}", e);
ERR_CODE_SEND_MSG
}
}
} }

View File

@ -220,7 +220,8 @@ struct wf_clipboard
HWND hwnd; HWND hwnd;
HANDLE hmem; HANDLE hmem;
HANDLE thread; HANDLE thread;
HANDLE response_data_event; HANDLE formatDataRespEvent;
BOOL formatDataRespReceived;
LPDATAOBJECT data_obj; LPDATAOBJECT data_obj;
HANDLE data_obj_mutex; HANDLE data_obj_mutex;
@ -228,6 +229,7 @@ struct wf_clipboard
ULONG req_fsize; ULONG req_fsize;
char *req_fdata; char *req_fdata;
HANDLE req_fevent; HANDLE req_fevent;
BOOL req_f_received;
size_t nFiles; size_t nFiles;
size_t file_array_size; size_t file_array_size;
@ -1444,7 +1446,7 @@ static UINT cliprdr_send_format_list(wfClipboard *clipboard, UINT32 connID)
return rc; return rc;
} }
UINT wait_response_event(UINT32 connID, wfClipboard *clipboard, HANDLE event, void **data) UINT wait_response_event(UINT32 connID, wfClipboard *clipboard, HANDLE event, BOOL* recvedFlag, void **data)
{ {
UINT rc = ERROR_SUCCESS; UINT rc = ERROR_SUCCESS;
clipboard->context->IsStopped = FALSE; clipboard->context->IsStopped = FALSE;
@ -1456,7 +1458,14 @@ UINT wait_response_event(UINT32 connID, wfClipboard *clipboard, HANDLE event, vo
DWORD waitRes = WaitForSingleObject(event, waitOnceTimeoutMillis); DWORD waitRes = WaitForSingleObject(event, waitOnceTimeoutMillis);
if (waitRes == WAIT_TIMEOUT && clipboard->context->IsStopped == FALSE) if (waitRes == WAIT_TIMEOUT && clipboard->context->IsStopped == FALSE)
{ {
continue; if ((*recvedFlag) == TRUE) {
// The data has been received, but the event is still not signaled.
// We just skip the rest of the waiting and reset the flag.
*recvedFlag = FALSE;
} else {
// The data has not been received yet, we should continue to wait.
continue;
}
} }
if (clipboard->context->IsStopped == TRUE) if (clipboard->context->IsStopped == TRUE)
@ -1524,13 +1533,14 @@ static UINT cliprdr_send_data_request(UINT32 connID, wfClipboard *clipboard, UIN
formatDataRequest.connID = connID; formatDataRequest.connID = connID;
formatDataRequest.requestedFormatId = remoteFormatId; formatDataRequest.requestedFormatId = remoteFormatId;
clipboard->requestedFormatId = formatId; clipboard->requestedFormatId = formatId;
clipboard->formatDataRespReceived = FALSE;
rc = clipboard->context->ClientFormatDataRequest(clipboard->context, &formatDataRequest); rc = clipboard->context->ClientFormatDataRequest(clipboard->context, &formatDataRequest);
if (rc != ERROR_SUCCESS) if (rc != ERROR_SUCCESS)
{ {
return rc; return rc;
} }
wait_response_event(connID, clipboard, clipboard->response_data_event, &clipboard->hmem); return wait_response_event(connID, clipboard, clipboard->formatDataRespEvent, &clipboard->formatDataRespReceived, &clipboard->hmem);
} }
UINT cliprdr_send_request_filecontents(wfClipboard *clipboard, UINT32 connID, const void *streamid, ULONG index, UINT cliprdr_send_request_filecontents(wfClipboard *clipboard, UINT32 connID, const void *streamid, ULONG index,
@ -1552,13 +1562,14 @@ UINT cliprdr_send_request_filecontents(wfClipboard *clipboard, UINT32 connID, co
fileContentsRequest.cbRequested = nreq; fileContentsRequest.cbRequested = nreq;
fileContentsRequest.clipDataId = 0; fileContentsRequest.clipDataId = 0;
fileContentsRequest.msgFlags = 0; fileContentsRequest.msgFlags = 0;
clipboard->req_f_received = FALSE;
rc = clipboard->context->ClientFileContentsRequest(clipboard->context, &fileContentsRequest); rc = clipboard->context->ClientFileContentsRequest(clipboard->context, &fileContentsRequest);
if (rc != ERROR_SUCCESS) if (rc != ERROR_SUCCESS)
{ {
return rc; return rc;
} }
return wait_response_event(connID, clipboard, clipboard->req_fevent, (void **)&clipboard->req_fdata); return wait_response_event(connID, clipboard, clipboard->req_fevent, &clipboard->req_f_received, (void **)&clipboard->req_fdata);
} }
static UINT cliprdr_send_response_filecontents( static UINT cliprdr_send_response_filecontents(
@ -2545,7 +2556,7 @@ exit:
response.requestedFormatData = (BYTE *)buff; response.requestedFormatData = (BYTE *)buff;
if (ERROR_SUCCESS != clipboard->context->ClientFormatDataResponse(clipboard->context, &response)) if (ERROR_SUCCESS != clipboard->context->ClientFormatDataResponse(clipboard->context, &response))
{ {
// CAUTION: if failed to send, server will wait a long time // CAUTION: if failed to send, server will wait a long time, default 30 seconds.
} }
if (buff) if (buff)
@ -2621,9 +2632,11 @@ wf_cliprdr_server_format_data_response(CliprdrClientContext *context,
rc = CHANNEL_RC_OK; rc = CHANNEL_RC_OK;
} while (0); } while (0);
if (!SetEvent(clipboard->response_data_event)) if (!SetEvent(clipboard->formatDataRespEvent))
{ {
// CAUTION: critical error here, process will hang up until wait timeout default 3min. // If failed to set event, set flag to indicate the event is received.
DEBUG_CLIPRDR("wf_cliprdr_server_format_data_response(), SetEvent failed with 0x%x", GetLastError());
clipboard->formatDataRespReceived = TRUE;
rc = ERROR_INTERNAL_ERROR; rc = ERROR_INTERNAL_ERROR;
} }
return rc; return rc;
@ -2899,7 +2912,9 @@ wf_cliprdr_server_file_contents_response(CliprdrClientContext *context,
if (!SetEvent(clipboard->req_fevent)) if (!SetEvent(clipboard->req_fevent))
{ {
// CAUTION: critical error here, process will hang up until wait timeout default 3min. // If failed to set event, set flag to indicate the event is received.
DEBUG_CLIPRDR("wf_cliprdr_server_file_contents_response(), SetEvent failed with 0x%x", GetLastError());
clipboard->req_f_received = TRUE;
} }
return rc; return rc;
} }
@ -2934,14 +2949,16 @@ BOOL wf_cliprdr_init(wfClipboard *clipboard, CliprdrClientContext *cliprdr)
(formatMapping *)calloc(clipboard->map_capacity, sizeof(formatMapping)))) (formatMapping *)calloc(clipboard->map_capacity, sizeof(formatMapping))))
goto error; goto error;
if (!(clipboard->response_data_event = CreateEvent(NULL, TRUE, FALSE, NULL))) if (!(clipboard->formatDataRespEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
goto error; goto error;
clipboard->formatDataRespReceived = FALSE;
if (!(clipboard->data_obj_mutex = CreateMutex(NULL, FALSE, "data_obj_mutex"))) if (!(clipboard->data_obj_mutex = CreateMutex(NULL, FALSE, "data_obj_mutex")))
goto error; goto error;
if (!(clipboard->req_fevent = CreateEvent(NULL, TRUE, FALSE, NULL))) if (!(clipboard->req_fevent = CreateEvent(NULL, TRUE, FALSE, NULL)))
goto error; goto error;
clipboard->req_f_received = FALSE;
if (!(clipboard->thread = CreateThread(NULL, 0, cliprdr_thread_func, clipboard, 0, NULL))) if (!(clipboard->thread = CreateThread(NULL, 0, cliprdr_thread_func, clipboard, 0, NULL)))
goto error; goto error;
@ -3002,8 +3019,8 @@ BOOL wf_cliprdr_uninit(wfClipboard *clipboard, CliprdrClientContext *cliprdr)
clipboard->data_obj = NULL; clipboard->data_obj = NULL;
} }
if (clipboard->response_data_event) if (clipboard->formatDataRespEvent)
CloseHandle(clipboard->response_data_event); CloseHandle(clipboard->formatDataRespEvent);
if (clipboard->data_obj_mutex) if (clipboard->data_obj_mutex)
CloseHandle(clipboard->data_obj_mutex); CloseHandle(clipboard->data_obj_mutex);

View File

@ -353,6 +353,7 @@ impl<T: InvokeUiSession> Remote<T> {
} else { } else {
if let Err(e) = ContextSend::make_sure_enabled() { if let Err(e) = ContextSend::make_sure_enabled() {
log::error!("failed to restart clipboard context: {}", e); log::error!("failed to restart clipboard context: {}", e);
// to-do: Show msgbox with "Don't show again" option
}; };
log::debug!("Send system clipboard message to remote"); log::debug!("Send system clipboard message to remote");
let msg = crate::clipboard_file::clip_2_msg(clip); let msg = crate::clipboard_file::clip_2_msg(clip);