fix hang up

Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
fufesou 2022-02-24 02:32:29 +08:00
parent 128a4aca69
commit 01591d1abf
3 changed files with 303 additions and 112 deletions

View File

@ -605,11 +605,15 @@ extern "C" fn client_format_data_response(
server_conn_id = (*format_data_response).serverConnID as i32;
remote_conn_id = (*format_data_response).remoteConnID as i32;
msg_flags = (*format_data_response).msgFlags as i32;
format_data = std::slice::from_raw_parts(
(*format_data_response).requestedFormatData,
(*format_data_response).dataLen as usize,
)
.to_vec();
if (*format_data_response).requestedFormatData.is_null() {
format_data = Vec::new();
} else {
format_data = std::slice::from_raw_parts(
(*format_data_response).requestedFormatData,
(*format_data_response).dataLen as usize,
)
.to_vec();
}
}
let conn_id = ConnID {
server_conn_id: server_conn_id as u32,
@ -704,11 +708,15 @@ extern "C" fn client_file_contents_response(
remote_conn_id = (*file_contents_response).remoteConnID as i32;
msg_flags = (*file_contents_response).msgFlags as i32;
stream_id = (*file_contents_response).streamId as i32;
requested_data = std::slice::from_raw_parts(
(*file_contents_response).requestedData,
(*file_contents_response).cbRequested as usize,
)
.to_vec();
if (*file_contents_response).requestedData.is_null() {
requested_data = Vec::new();
} else {
requested_data = std::slice::from_raw_parts(
(*file_contents_response).requestedData,
(*file_contents_response).cbRequested as usize,
)
.to_vec();
}
}
let conn_id = ConnID {
server_conn_id: server_conn_id as u32,

View File

@ -254,6 +254,7 @@ typedef struct wf_clipboard wfClipboard;
BOOL wf_cliprdr_init(wfClipboard *clipboard, CliprdrClientContext *cliprdr);
BOOL wf_cliprdr_uninit(wfClipboard *clipboard, CliprdrClientContext *cliprdr);
BOOL wf_do_empty_cliprdr(wfClipboard *clipboard);
static BOOL wf_create_file_obj(UINT32 serverConnID, UINT32 remoteConnID, wfClipboard *cliprdrrdr, IDataObject **ppDataObject);
static void wf_destroy_file_obj(IDataObject *instance);
@ -708,6 +709,10 @@ static HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetData(IDataObject *This, FO
{
return E_UNEXPECTED;
}
if (!clipboard->hmem)
{
return E_UNEXPECTED;
}
pMedium->hGlobal = clipboard->hmem; /* points to a FILEGROUPDESCRIPTOR structure */
/* GlobalLock returns a pointer to the first byte of the memory block,
@ -1462,12 +1467,20 @@ static UINT cliprdr_send_data_request(UINT32 serverConnID, UINT32 remoteConnID,
return rc;
}
while (clipboard->context->CheckEnabled(serverConnID, remoteConnID))
// with default 3min timeout
for (int i = 0; i < 20 * 60 * 3; i++)
{
DWORD waitRes = WaitForSingleObject(clipboard->response_data_event, 50);
if (waitRes == WAIT_TIMEOUT)
{
continue;
if (clipboard->context->CheckEnabled(serverConnID, remoteConnID))
{
continue;
}
else
{
break;
}
}
if (waitRes != WAIT_OBJECT_0)
@ -1480,8 +1493,24 @@ static UINT cliprdr_send_data_request(UINT32 serverConnID, UINT32 remoteConnID,
// NOTE: critical error here, crash may be better
rc = ERROR_INTERNAL_ERROR;
}
if (!clipboard->hmem)
{
rc = ERROR_INTERNAL_ERROR;
}
return rc;
}
if (clipboard->hmem)
{
if (!ResetEvent(clipboard->response_data_event))
{
// NOTE: critical error here, crash may be better
}
return ERROR_SUCCESS;
}
return ERROR_INTERNAL_ERROR;
}
@ -1511,12 +1540,20 @@ UINT cliprdr_send_request_filecontents(wfClipboard *clipboard, UINT32 serverConn
return rc;
}
while (clipboard->context->CheckEnabled(serverConnID, remoteConnID))
// with default 3min timeout
for (int i = 0; i < 20 * 60 * 3; i++)
{
DWORD waitRes = WaitForSingleObject(clipboard->req_fevent, 50);
if (waitRes == WAIT_TIMEOUT)
{
continue;
if (clipboard->context->CheckEnabled(serverConnID, remoteConnID))
{
continue;
}
else
{
break;
}
}
if (waitRes != WAIT_OBJECT_0)
@ -1529,25 +1566,50 @@ UINT cliprdr_send_request_filecontents(wfClipboard *clipboard, UINT32 serverConn
// NOTE: critical error here, crash may be better
rc = ERROR_INTERNAL_ERROR;
}
if (!clipboard->req_fdata)
{
rc = ERROR_INTERNAL_ERROR;
}
return rc;
}
if (clipboard->req_fdata)
{
if (!ResetEvent(clipboard->req_fevent))
{
// NOTE: critical error here, crash may be better
}
return ERROR_SUCCESS;
}
return ERROR_INTERNAL_ERROR;
}
static UINT cliprdr_send_response_filecontents(wfClipboard *clipboard, UINT32 serverConnID, UINT32 remoteConnID, UINT32 streamId, UINT32 size,
BYTE *data)
static UINT cliprdr_send_response_filecontents(
wfClipboard *clipboard,
UINT32 serverConnID,
UINT32 remoteConnID,
UINT16 msgFlags,
UINT32 streamId,
UINT32 size,
BYTE *data)
{
CLIPRDR_FILE_CONTENTS_RESPONSE fileContentsResponse;
if (!clipboard || !clipboard->context || !clipboard->context->ClientFileContentsResponse)
return ERROR_INTERNAL_ERROR;
{
data = NULL;
size = 0;
msgFlags = CB_RESPONSE_FAIL;
}
fileContentsResponse.serverConnID = serverConnID;
fileContentsResponse.remoteConnID = remoteConnID;
fileContentsResponse.streamId = streamId;
fileContentsResponse.cbRequested = size;
fileContentsResponse.requestedData = data;
fileContentsResponse.msgFlags = CB_RESPONSE_OK;
fileContentsResponse.msgFlags = msgFlags;
return clipboard->context->ClientFileContentsResponse(clipboard->context,
&fileContentsResponse);
}
@ -2343,7 +2405,7 @@ static UINT
wf_cliprdr_server_format_data_request(CliprdrClientContext *context,
const CLIPRDR_FORMAT_DATA_REQUEST *formatDataRequest)
{
UINT rc;
UINT rc = ERROR_SUCCESS;
size_t size = 0;
void *buff = NULL;
char *globlemem = NULL;
@ -2353,12 +2415,18 @@ wf_cliprdr_server_format_data_request(CliprdrClientContext *context,
wfClipboard *clipboard;
if (!context || !formatDataRequest)
return ERROR_INTERNAL_ERROR;
{
rc = ERROR_INTERNAL_ERROR;
goto exit;
}
clipboard = (wfClipboard *)context->custom;
if (!clipboard)
return ERROR_INTERNAL_ERROR;
{
rc = ERROR_INTERNAL_ERROR;
goto exit;
}
requestedFormatId = formatDataRequest->requestedFormatId;
@ -2376,7 +2444,10 @@ wf_cliprdr_server_format_data_request(CliprdrClientContext *context,
result = OleGetClipboard(&dataObj);
if (FAILED(result))
return ERROR_INTERNAL_ERROR;
{
rc = ERROR_INTERNAL_ERROR;
goto exit;
}
ZeroMemory(&format_etc, sizeof(FORMATETC));
ZeroMemory(&stg_medium, sizeof(STGMEDIUM));
@ -2389,7 +2460,7 @@ wf_cliprdr_server_format_data_request(CliprdrClientContext *context,
if (FAILED(result))
{
DEBUG_CLIPRDR("dataObj->GetData failed.");
rc = ERROR_INTERNAL_ERROR;
goto exit;
}
@ -2400,7 +2471,7 @@ wf_cliprdr_server_format_data_request(CliprdrClientContext *context,
GlobalUnlock(stg_medium.hGlobal);
ReleaseStgMedium(&stg_medium);
clipboard->nFiles = 0;
goto exit;
goto resp;
}
clear_file_array(clipboard);
@ -2417,7 +2488,6 @@ wf_cliprdr_server_format_data_request(CliprdrClientContext *context,
else
{
char *p;
for (p = (char *)((char *)dropFiles + dropFiles->pFiles); (len = strlen(p)) > 0;
p += len + 1, clipboard->nFiles++)
{
@ -2432,7 +2502,7 @@ wf_cliprdr_server_format_data_request(CliprdrClientContext *context,
GlobalUnlock(stg_medium.hGlobal);
ReleaseStgMedium(&stg_medium);
exit:
resp:
size = 4 + clipboard->nFiles * sizeof(FILEDESCRIPTORW);
groupDsc = (FILEGROUPDESCRIPTORW *)malloc(size);
@ -2450,6 +2520,7 @@ wf_cliprdr_server_format_data_request(CliprdrClientContext *context,
}
IDataObject_Release(dataObj);
rc = ERROR_SUCCESS;
}
else
{
@ -2461,26 +2532,50 @@ wf_cliprdr_server_format_data_request(CliprdrClientContext *context,
if (!hClipdata)
{
CloseClipboard();
return ERROR_INTERNAL_ERROR;
{
rc = ERROR_INTERNAL_ERROR;
goto exit;
}
}
globlemem = (char *)GlobalLock(hClipdata);
size = (int)GlobalSize(hClipdata);
buff = malloc(size);
CopyMemory(buff, globlemem, size);
GlobalUnlock(hClipdata);
CloseClipboard();
else
{
globlemem = (char *)GlobalLock(hClipdata);
size = (int)GlobalSize(hClipdata);
buff = malloc(size);
CopyMemory(buff, globlemem, size);
GlobalUnlock(hClipdata);
CloseClipboard();
rc = ERROR_SUCCESS;
}
}
else
{
rc = ERROR_INTERNAL_ERROR;
}
}
exit:
if (rc == ERROR_SUCCESS)
{
response.msgFlags = CB_RESPONSE_OK;
}
else
{
response.msgFlags = CB_RESPONSE_FAIL;
}
response.serverConnID = formatDataRequest->serverConnID;
response.remoteConnID = formatDataRequest->remoteConnID;
response.msgFlags = CB_RESPONSE_OK;
response.dataLen = size;
response.requestedFormatData = (BYTE *)buff;
rc = 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
}
free(buff);
if (buff)
{
free(buff);
}
return rc;
}
@ -2493,48 +2588,69 @@ static UINT
wf_cliprdr_server_format_data_response(CliprdrClientContext *context,
const CLIPRDR_FORMAT_DATA_RESPONSE *formatDataResponse)
{
UINT rc = ERROR_INTERNAL_ERROR;
BYTE *data;
HANDLE hMem;
wfClipboard *clipboard;
if (!context || !formatDataResponse)
return ERROR_INTERNAL_ERROR;
if (formatDataResponse->msgFlags != CB_RESPONSE_OK)
return E_FAIL;
clipboard = (wfClipboard *)context->custom;
if (!clipboard)
return ERROR_INTERNAL_ERROR;
hMem = GlobalAlloc(GMEM_MOVEABLE, formatDataResponse->dataLen);
if (!hMem)
return ERROR_INTERNAL_ERROR;
data = (BYTE *)GlobalLock(hMem);
if (!data)
do
{
GlobalFree(hMem);
return ERROR_INTERNAL_ERROR;
}
if (!context || !formatDataResponse)
{
rc = ERROR_INTERNAL_ERROR;
break;
}
CopyMemory(data, formatDataResponse->requestedFormatData, formatDataResponse->dataLen);
clipboard = (wfClipboard *)context->custom;
if (!clipboard)
{
rc = ERROR_INTERNAL_ERROR;
break;
}
clipboard->hmem = NULL;
if (!GlobalUnlock(hMem) && GetLastError())
{
GlobalFree(hMem);
return ERROR_INTERNAL_ERROR;
}
if (formatDataResponse->msgFlags != CB_RESPONSE_OK)
{
// BOOL emptyRes = wf_do_empty_cliprdr((wfClipboard *)context->custom);
// (void)emptyRes;
rc = E_FAIL;
break;
}
clipboard->hmem = hMem;
hMem = GlobalAlloc(GMEM_MOVEABLE, formatDataResponse->dataLen);
if (!hMem)
{
rc = ERROR_INTERNAL_ERROR;
break;
}
data = (BYTE *)GlobalLock(hMem);
if (!data)
{
GlobalFree(hMem);
rc = ERROR_INTERNAL_ERROR;
break;
}
CopyMemory(data, formatDataResponse->requestedFormatData, formatDataResponse->dataLen);
if (!GlobalUnlock(hMem) && GetLastError())
{
GlobalFree(hMem);
rc = ERROR_INTERNAL_ERROR;
break;
}
clipboard->hmem = hMem;
rc = CHANNEL_RC_OK;
} while (0);
if (!SetEvent(clipboard->response_data_event))
return ERROR_INTERNAL_ERROR;
return CHANNEL_RC_OK;
{
// CAUTION: critical error here, process will hang up until wait timeout default 3min.
rc = ERROR_INTERNAL_ERROR;
}
return rc;
}
/**
@ -2561,12 +2677,18 @@ wf_cliprdr_server_file_contents_request(CliprdrClientContext *context,
UINT32 cbRequested;
if (!context || !fileContentsRequest)
return ERROR_INTERNAL_ERROR;
{
rc = ERROR_INTERNAL_ERROR;
goto exit;
}
clipboard = (wfClipboard *)context->custom;
if (!clipboard)
return ERROR_INTERNAL_ERROR;
{
rc = ERROR_INTERNAL_ERROR;
goto exit;
}
cbRequested = fileContentsRequest->cbRequested;
if (fileContentsRequest->dwFlags == FILECONTENTS_SIZE)
@ -2575,14 +2697,18 @@ wf_cliprdr_server_file_contents_request(CliprdrClientContext *context,
pData = (BYTE *)calloc(1, cbRequested);
if (!pData)
goto error;
{
rc = ERROR_INTERNAL_ERROR;
goto exit;
}
hRet = OleGetClipboard(&pDataObj);
if (FAILED(hRet))
{
printf("filecontents: get ole clipboard failed.\n");
goto error;
rc = ERROR_INTERNAL_ERROR;
goto exit;
}
ZeroMemory(&vFormatEtc, sizeof(FORMATETC));
@ -2666,7 +2792,10 @@ wf_cliprdr_server_file_contents_request(CliprdrClientContext *context,
if (fileContentsRequest->dwFlags == FILECONTENTS_SIZE)
{
if (clipboard->nFiles <= fileContentsRequest->listIndex)
goto error;
{
rc = ERROR_INTERNAL_ERROR;
goto exit;
}
*((UINT32 *)&pData[0]) =
clipboard->fileDescriptor[fileContentsRequest->listIndex]->nFileSizeLow;
*((UINT32 *)&pData[4]) =
@ -2677,7 +2806,10 @@ wf_cliprdr_server_file_contents_request(CliprdrClientContext *context,
{
BOOL bRet;
if (clipboard->nFiles <= fileContentsRequest->listIndex)
goto error;
{
rc = ERROR_INTERNAL_ERROR;
goto exit;
}
bRet = wf_cliprdr_get_file_contents(
clipboard->file_names[fileContentsRequest->listIndex], pData,
fileContentsRequest->nPositionLow, fileContentsRequest->nPositionHigh, cbRequested,
@ -2687,21 +2819,30 @@ wf_cliprdr_server_file_contents_request(CliprdrClientContext *context,
{
printf("get file contents failed.\n");
uSize = 0;
goto error;
rc = ERROR_INTERNAL_ERROR;
goto exit;
}
}
}
rc = CHANNEL_RC_OK;
error:
exit:
if (pDataObj)
IDataObject_Release(pDataObj);
if (rc != CHANNEL_RC_OK)
{
uSize = 0;
}
if (uSize == 0)
{
free(pData);
pData = NULL;
if (pData)
{
free(pData);
pData = NULL;
}
}
sRc =
@ -2709,13 +2850,18 @@ error:
clipboard,
fileContentsRequest->serverConnID,
fileContentsRequest->remoteConnID,
rc == CHANNEL_RC_OK ? CB_RESPONSE_OK : CB_RESPONSE_FAIL,
fileContentsRequest->streamId,
uSize,
pData);
free(pData);
if (sRc != CHANNEL_RC_OK)
return sRc;
if (pData)
{
free(pData);
}
// if (sRc != CHANNEL_RC_OK)
// return sRc;
return rc;
}
@ -2730,34 +2876,50 @@ wf_cliprdr_server_file_contents_response(CliprdrClientContext *context,
const CLIPRDR_FILE_CONTENTS_RESPONSE *fileContentsResponse)
{
wfClipboard *clipboard;
UINT rc = ERROR_INTERNAL_ERROR;
if (!context || !fileContentsResponse)
return ERROR_INTERNAL_ERROR;
do
{
if (!context || !fileContentsResponse)
{
rc = ERROR_INTERNAL_ERROR;
break;
}
if (fileContentsResponse->msgFlags != CB_RESPONSE_OK)
return E_FAIL;
clipboard = (wfClipboard *)context->custom;
if (!clipboard)
{
rc = ERROR_INTERNAL_ERROR;
break;
}
clipboard->req_fsize = 0;
clipboard->req_fdata = NULL;
clipboard = (wfClipboard *)context->custom;
if (fileContentsResponse->msgFlags != CB_RESPONSE_OK)
{
rc = E_FAIL;
break;
}
if (!clipboard)
return ERROR_INTERNAL_ERROR;
clipboard->req_fsize = fileContentsResponse->cbRequested;
clipboard->req_fdata = (char *)malloc(fileContentsResponse->cbRequested);
if (!clipboard->req_fdata)
{
rc = ERROR_INTERNAL_ERROR;
break;
}
clipboard->req_fsize = fileContentsResponse->cbRequested;
clipboard->req_fdata = (char *)malloc(fileContentsResponse->cbRequested);
CopyMemory(clipboard->req_fdata, fileContentsResponse->requestedData,
fileContentsResponse->cbRequested);
if (!clipboard->req_fdata)
return ERROR_INTERNAL_ERROR;
CopyMemory(clipboard->req_fdata, fileContentsResponse->requestedData,
fileContentsResponse->cbRequested);
rc = CHANNEL_RC_OK;
} while (0);
if (!SetEvent(clipboard->req_fevent))
{
free(clipboard->req_fdata);
return ERROR_INTERNAL_ERROR;
// CAUTION: critical error here, process will hang up until wait timeout default 3min.
}
return CHANNEL_RC_OK;
return rc;
}
BOOL wf_cliprdr_init(wfClipboard *clipboard, CliprdrClientContext *cliprdr)
@ -2888,6 +3050,7 @@ BOOL uninit_cliprdr(CliprdrClientContext *context)
BOOL empty_cliprdr(CliprdrClientContext *context, UINT32 server_conn_id, UINT32 remote_conn_id)
{
wfClipboard *clipboard = NULL;
CliprdrDataObject *instance = NULL;
BOOL rc = FALSE;
if (!context)
{
@ -2899,6 +3062,34 @@ BOOL empty_cliprdr(CliprdrClientContext *context, UINT32 server_conn_id, UINT32
}
clipboard = (wfClipboard *)context->custom;
if (!clipboard)
{
return FALSE;
}
instance = clipboard->data_obj;
if (instance)
{
if (server_conn_id != 0 && instance->m_serverConnID != server_conn_id)
{
return TRUE;
}
if (remote_conn_id != 0 && instance->m_remoteConnID != remote_conn_id)
{
return TRUE;
}
}
return wf_do_empty_cliprdr(clipboard);
}
BOOL wf_do_empty_cliprdr(wfClipboard *clipboard)
{
BOOL rc = FALSE;
if (!clipboard)
{
return FALSE;
}
if (WaitForSingleObject(clipboard->data_obj_mutex, INFINITE) != WAIT_OBJECT_0)
{
@ -2909,18 +3100,6 @@ BOOL empty_cliprdr(CliprdrClientContext *context, UINT32 server_conn_id, UINT32
{
if (clipboard->data_obj != NULL)
{
CliprdrDataObject *instance = clipboard->data_obj;
if (server_conn_id != 0 && instance->m_serverConnID != server_conn_id)
{
rc = TRUE;
break;
}
if (remote_conn_id != 0 && instance->m_remoteConnID != remote_conn_id)
{
rc = TRUE;
break;
}
wf_destroy_file_obj(clipboard->data_obj);
clipboard->data_obj = NULL;
}

View File

@ -198,6 +198,7 @@ impl ConnectionManager {
allow_err!(_tx_clip_file.send((id, _clip)));
}
Data::ClipboardFileEnabled(enabled) => {
#[cfg(windows)]
set_conn_enabled(id, 0, enabled);
if !enabled {
allow_err!(_tx_clip_empty.send(id));
@ -375,11 +376,14 @@ async fn start_ipc(cm: ConnectionManager) {
match data {
Data::Login{id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, file_transfer_enabled} => {
conn_id = id;
#[cfg(windows)]
set_conn_enabled(id, 0, file_transfer_enabled);
let _ = file_transfer_enabled;
cm.add_connection(id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, tx.clone());
}
Data::Close => {
allow_err!(tx_clip_empty.send(conn_id));
#[cfg(windows)]
set_conn_enabled(conn_id, 0, false);
log::info!("cm ipc connection closed from connection request");
break;