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:
		
							parent
							
								
									d4377a13c5
								
							
						
					
					
						commit
						ec28567362
					
				| @ -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)] | ||||||
|  | |||||||
| @ -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 | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -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,8 +1458,15 @@ 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) | ||||||
| 		{ | 		{ | ||||||
|  | 			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; | 				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); | ||||||
|  | |||||||
| @ -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); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user