diff --git a/channels/cliprdr/client/cliprdr_format.c b/channels/cliprdr/client/cliprdr_format.c index 3a52a0a8e..0f85f3ba6 100644 --- a/channels/cliprdr/client/cliprdr_format.c +++ b/channels/cliprdr/client/cliprdr_format.c @@ -32,127 +32,109 @@ #include "cliprdr_main.h" #include "cliprdr_format.h" -void cliprdr_process_short_format_names(cliprdrPlugin* cliprdr, wStream* s, UINT32 length, UINT16 flags) -{ - int i; - BOOL ascii; - int num_formats; - CLIPRDR_FORMAT_NAME* format_name; - - num_formats = length / 36; - - if (num_formats <= 0) - { - cliprdr->format_names = NULL; - cliprdr->num_format_names = 0; - return; - } - - if (num_formats * 36 != length) - WLog_ERR(TAG, "dataLen %d not divided by 36!", length); - - ascii = (flags & CB_ASCII_NAMES) ? TRUE : FALSE; - - cliprdr->format_names = (CLIPRDR_FORMAT_NAME*) malloc(sizeof(CLIPRDR_FORMAT_NAME) * num_formats); - cliprdr->num_format_names = num_formats; - - for (i = 0; i < num_formats; i++) - { - format_name = &cliprdr->format_names[i]; - - Stream_Read_UINT32(s, format_name->id); - - if (ascii) - { - format_name->name = _strdup((char*) s->pointer); - format_name->length = strlen(format_name->name); - } - else - { - format_name->name = NULL; - format_name->length = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) s->pointer, 32 / 2, &format_name->name, 0, NULL, NULL); - } - - Stream_Seek(s, 32); - } -} - -void cliprdr_process_long_format_names(cliprdrPlugin* cliprdr, wStream* s, UINT32 length, UINT16 flags) -{ - int allocated_formats = 8; - BYTE* end_mark; - CLIPRDR_FORMAT_NAME* format_name; - - Stream_GetPointer(s, end_mark); - end_mark += length; - - cliprdr->format_names = (CLIPRDR_FORMAT_NAME*) malloc(sizeof(CLIPRDR_FORMAT_NAME) * allocated_formats); - cliprdr->num_format_names = 0; - - while (Stream_GetRemainingLength(s) >= 6) - { - BYTE* p; - int name_len; - - if (cliprdr->num_format_names >= allocated_formats) - { - allocated_formats *= 2; - cliprdr->format_names = (CLIPRDR_FORMAT_NAME*) realloc(cliprdr->format_names, - sizeof(CLIPRDR_FORMAT_NAME) * allocated_formats); - } - - format_name = &cliprdr->format_names[cliprdr->num_format_names++]; - Stream_Read_UINT32(s, format_name->id); - - format_name->name = NULL; - format_name->length = 0; - - for (p = Stream_Pointer(s), name_len = 0; p + 1 < end_mark; p += 2, name_len += 2) - { - if (*((unsigned short*) p) == 0) - break; - } - - format_name->length = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), name_len / 2, &format_name->name, 0, NULL, NULL); - - Stream_Seek(s, name_len + 2); - } -} - void cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags) { + UINT32 index; + UINT32 position; + BOOL asciiNames; + int formatNameLength; + char* szFormatName; + WCHAR* wszFormatName; + CLIPRDR_FORMAT* formats = NULL; + CLIPRDR_FORMAT_LIST formatList; CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); - if (context->custom) + if (!context->custom) + return; + + asciiNames = (msgFlags & CB_ASCII_NAMES) ? TRUE : FALSE; + + formatList.msgType = CB_FORMAT_LIST; + formatList.msgFlags = msgFlags; + formatList.dataLen = dataLen; + + index = 0; + formatList.numFormats = 0; + position = Stream_GetPosition(s); + + if (!cliprdr->useLongFormatNames) { - UINT32 index; - int formatNameLength; - CLIPRDR_FORMAT* formats = NULL; - CLIPRDR_FORMAT_LIST formatList; - - formatList.msgType = CB_FORMAT_LIST; - formatList.msgFlags = msgFlags; - formatList.dataLen = dataLen; - - formatList.numFormats = 0; - + formatList.numFormats = (dataLen / 36); + + if ((formatList.numFormats * 36) != dataLen) + { + WLog_ERR(TAG, "Invalid short format list length: %d", dataLen); + return; + } + + if (formatList.numFormats) + formats = (CLIPRDR_FORMAT*) calloc(formatList.numFormats, sizeof(CLIPRDR_FORMAT)); + + if (!formats) + return; + + formatList.formats = formats; + while (dataLen) { - Stream_Seek(s, 4); /* formatId */ + Stream_Read_UINT32(s, formats[index].formatId); /* formatId (4 bytes) */ dataLen -= 4; - - formatNameLength = _wcslen((WCHAR*) Stream_Pointer(s)); + + formats[index].formatName = NULL; + + if (asciiNames) + { + szFormatName = (char*) Stream_Pointer(s); + + if (szFormatName[0]) + { + formats[index].formatName = (char*) malloc(32 + 1); + CopyMemory(formats[index].formatName, szFormatName, 32); + formats[index].formatName[32] = '\0'; + } + } + else + { + wszFormatName = (WCHAR*) Stream_Pointer(s); + + if (wszFormatName[0]) + { + ConvertFromUnicode(CP_UTF8, 0, wszFormatName, + 16, &(formats[index].formatName), 0, NULL, NULL); + } + } + + Stream_Seek(s, 32); + dataLen -= 32; + index++; + } + } + else + { + while (dataLen) + { + Stream_Seek(s, 4); /* formatId (4 bytes) */ + dataLen -= 4; + + wszFormatName = (WCHAR*) Stream_Pointer(s); + + if (!wszFormatName[0]) + formatNameLength = 0; + else + formatNameLength = _wcslen(wszFormatName); + Stream_Seek(s, (formatNameLength + 1) * 2); dataLen -= ((formatNameLength + 1) * 2); + formatList.numFormats++; } - index = 0; dataLen = formatList.dataLen; - Stream_Rewind(s, dataLen); + Stream_SetPosition(s, position); if (formatList.numFormats) formats = (CLIPRDR_FORMAT*) calloc(formatList.numFormats, sizeof(CLIPRDR_FORMAT)); + if (!formats) return; @@ -160,110 +142,107 @@ void cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data while (dataLen) { - Stream_Read_UINT32(s, formats[index].formatId); /* formatId */ + Stream_Read_UINT32(s, formats[index].formatId); /* formatId (4 bytes) */ dataLen -= 4; formats[index].formatName = NULL; - formatNameLength = _wcslen((WCHAR*) Stream_Pointer(s)); + + wszFormatName = (WCHAR*) Stream_Pointer(s); + + if (!wszFormatName[0]) + formatNameLength = 0; + else + formatNameLength = _wcslen(wszFormatName); if (formatNameLength) { - formatNameLength = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), + formatNameLength = ConvertFromUnicode(CP_UTF8, 0, wszFormatName, -1, &(formats[index].formatName), 0, NULL, NULL); - - Stream_Seek(s, formatNameLength * 2); - dataLen -= (formatNameLength * 2); - } - else - { - formats[index].formatName = NULL; - Stream_Seek(s, 2); - dataLen -= 2; } + + Stream_Seek(s, (formatNameLength + 1) * 2); + dataLen -= ((formatNameLength + 1) * 2); index++; } - - WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatList: numFormats: %d", - formatList.numFormats); - - if (context->ServerFormatList) - context->ServerFormatList(context, &formatList); - - for (index = 0; index < formatList.numFormats; index++) - { - if (formats[index].formatName) - free(formats[index].formatName); - } - - free(formats); } + + WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatList: numFormats: %d", + formatList.numFormats); + + if (context->ServerFormatList) + context->ServerFormatList(context, &formatList); + + for (index = 0; index < formatList.numFormats; index++) + { + if (formats[index].formatName) + free(formats[index].formatName); + } + + free(formats); } void cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags) { + CLIPRDR_FORMAT_LIST_RESPONSE formatListResponse; CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatListResponse"); - if (context->custom) - { - CLIPRDR_FORMAT_LIST_RESPONSE formatListResponse; + if (!context->custom) + return; - formatListResponse.msgType = CB_FORMAT_LIST_RESPONSE; - formatListResponse.msgFlags = msgFlags; - formatListResponse.dataLen = dataLen; + formatListResponse.msgType = CB_FORMAT_LIST_RESPONSE; + formatListResponse.msgFlags = msgFlags; + formatListResponse.dataLen = dataLen; - if (context->ServerFormatListResponse) - context->ServerFormatListResponse(context, &formatListResponse); - } + if (context->ServerFormatListResponse) + context->ServerFormatListResponse(context, &formatListResponse); } void cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags) { + CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest; CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatDataRequest"); - if (context->custom) - { - CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest; + if (!context->custom) + return; - formatDataRequest.msgType = CB_FORMAT_DATA_REQUEST; - formatDataRequest.msgFlags = msgFlags; - formatDataRequest.dataLen = dataLen; + formatDataRequest.msgType = CB_FORMAT_DATA_REQUEST; + formatDataRequest.msgFlags = msgFlags; + formatDataRequest.dataLen = dataLen; - Stream_Read_UINT32(s, formatDataRequest.requestedFormatId); /* requestedFormatId (4 bytes) */ + Stream_Read_UINT32(s, formatDataRequest.requestedFormatId); /* requestedFormatId (4 bytes) */ - if (context->ServerFormatDataRequest) - context->ServerFormatDataRequest(context, &formatDataRequest); - } + if (context->ServerFormatDataRequest) + context->ServerFormatDataRequest(context, &formatDataRequest); } void cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags) { + CLIPRDR_FORMAT_DATA_RESPONSE formatDataResponse; CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatDataResponse"); - if (context->custom) + if (!context->custom) + return; + + formatDataResponse.msgType = CB_FORMAT_DATA_RESPONSE; + formatDataResponse.msgFlags = msgFlags; + formatDataResponse.dataLen = dataLen; + formatDataResponse.requestedFormatData = NULL; + + if (dataLen) { - CLIPRDR_FORMAT_DATA_RESPONSE formatDataResponse; - - formatDataResponse.msgType = CB_FORMAT_DATA_RESPONSE; - formatDataResponse.msgFlags = msgFlags; - formatDataResponse.dataLen = dataLen; - formatDataResponse.requestedFormatData = NULL; - - if (dataLen) - { - formatDataResponse.requestedFormatData = (BYTE*) malloc(dataLen); - Stream_Read(s, formatDataResponse.requestedFormatData, dataLen); - } - - if (context->ServerFormatDataResponse) - context->ServerFormatDataResponse(context, &formatDataResponse); - - free(formatDataResponse.requestedFormatData); + formatDataResponse.requestedFormatData = (BYTE*) malloc(dataLen); + Stream_Read(s, formatDataResponse.requestedFormatData, dataLen); } + + if (context->ServerFormatDataResponse) + context->ServerFormatDataResponse(context, &formatDataResponse); + + free(formatDataResponse.requestedFormatData); } diff --git a/channels/cliprdr/client/cliprdr_main.c b/channels/cliprdr/client/cliprdr_main.c index a481e9aaa..c604840a8 100644 --- a/channels/cliprdr/client/cliprdr_main.c +++ b/channels/cliprdr/client/cliprdr_main.c @@ -32,7 +32,7 @@ #include "cliprdr_main.h" #include "cliprdr_format.h" -static const char* const CB_MSG_TYPE_STRINGS[] = +const char* const CB_MSG_TYPE_STRINGS[] = { "", "CB_MONITOR_READY", @@ -129,59 +129,61 @@ static int cliprdr_process_general_capability(cliprdrPlugin* cliprdr, wStream* s { UINT32 version; UINT32 generalFlags; - CliprdrClientContext* context; - context = cliprdr_get_client_interface(cliprdr); + CLIPRDR_CAPABILITIES capabilities; + CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet; + CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); + Stream_Read_UINT32(s, version); /* version (4 bytes) */ Stream_Read_UINT32(s, generalFlags); /* generalFlags (4 bytes) */ + DEBUG_CLIPRDR("Version: %d", version); #ifdef WITH_DEBUG_CLIPRDR cliprdr_print_general_capability_flags(generalFlags); #endif - if (generalFlags & CB_USE_LONG_FORMAT_NAMES) - cliprdr->use_long_format_names = TRUE; + if (cliprdr->useLongFormatNames) + cliprdr->useLongFormatNames = (generalFlags & CB_USE_LONG_FORMAT_NAMES) ? TRUE : FALSE; - if (generalFlags & CB_STREAM_FILECLIP_ENABLED) - cliprdr->stream_fileclip_enabled = TRUE; + if (cliprdr->streamFileClipEnabled) + cliprdr->streamFileClipEnabled = (generalFlags & CB_STREAM_FILECLIP_ENABLED) ? TRUE : FALSE; - if (generalFlags & CB_FILECLIP_NO_FILE_PATHS) - cliprdr->fileclip_no_file_paths = TRUE; + if (cliprdr->fileClipNoFilePaths) + cliprdr->fileClipNoFilePaths = (generalFlags & CB_FILECLIP_NO_FILE_PATHS) ? TRUE : FALSE; - if (generalFlags & CB_CAN_LOCK_CLIPDATA) - cliprdr->can_lock_clipdata = TRUE; + if (cliprdr->canLockClipData) + cliprdr->canLockClipData = (generalFlags & CB_CAN_LOCK_CLIPDATA) ? TRUE : FALSE; + + cliprdr->capabilitiesReceived = TRUE; - cliprdr->received_caps = TRUE; + if (!context->custom) + return -1; + + capabilities.cCapabilitiesSets = 1; + capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*) &(generalCapabilitySet); + generalCapabilitySet.capabilitySetType = CB_CAPSTYPE_GENERAL; + generalCapabilitySet.capabilitySetLength = 12; + generalCapabilitySet.version = version; + generalCapabilitySet.generalFlags = generalFlags; - if (context->custom) - { - CLIPRDR_CAPABILITIES capabilities; - CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet; - capabilities.cCapabilitiesSets = 1; - capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*) &(generalCapabilitySet); - generalCapabilitySet.capabilitySetType = CB_CAPSTYPE_GENERAL; - generalCapabilitySet.capabilitySetLength = 12; - generalCapabilitySet.version = version; - generalCapabilitySet.generalFlags = generalFlags; - - if (context->ServerCapabilities) - context->ServerCapabilities(context, &capabilities); - } + if (context->ServerCapabilities) + context->ServerCapabilities(context, &capabilities); return 1; } static int cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s, UINT16 length, UINT16 flags) { - int i; + UINT16 index; UINT16 lengthCapability; UINT16 cCapabilitiesSets; UINT16 capabilitySetType; + Stream_Read_UINT16(s, cCapabilitiesSets); /* cCapabilitiesSets (2 bytes) */ Stream_Seek_UINT16(s); /* pad1 (2 bytes) */ WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerCapabilities"); - for (i = 0; i < cCapabilitiesSets; i++) + for (index = 0; index < cCapabilitiesSets; index++) { Stream_Read_UINT16(s, capabilitySetType); /* capabilitySetType (2 bytes) */ Stream_Read_UINT16(s, lengthCapability); /* lengthCapability (2 bytes) */ @@ -191,6 +193,7 @@ static int cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s, UINT16 case CB_CAPSTYPE_GENERAL: cliprdr_process_general_capability(cliprdr, s); break; + default: WLog_ERR(TAG, "unknown cliprdr capability set: %d", capabilitySetType); break; @@ -202,133 +205,144 @@ static int cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s, UINT16 static int cliprdr_process_monitor_ready(cliprdrPlugin* cliprdr, wStream* s, UINT16 length, UINT16 flags) { + CLIPRDR_MONITOR_READY monitorReady; CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); WLog_Print(cliprdr->log, WLOG_DEBUG, "MonitorReady"); - if (context->custom) - { - CLIPRDR_MONITOR_READY monitorReady; - monitorReady.msgType = CB_MONITOR_READY; - monitorReady.msgFlags = flags; - monitorReady.dataLen = length; + if (!context->custom) + return -1; - if (context->MonitorReady) - context->MonitorReady(context, &monitorReady); + if (!cliprdr->capabilitiesReceived) + { + /** + * The clipboard capabilities pdu from server to client is optional, + * but a server using it must send it before sending the monitor ready pdu. + * When the server capabilities pdu is not used, default capabilities + * corresponding to a generalFlags field set to zero are assumed. + */ + + cliprdr->useLongFormatNames = FALSE; + cliprdr->streamFileClipEnabled = FALSE; + cliprdr->fileClipNoFilePaths = TRUE; + cliprdr->canLockClipData = FALSE; } + + monitorReady.msgType = CB_MONITOR_READY; + monitorReady.msgFlags = flags; + monitorReady.dataLen = length; + + if (context->MonitorReady) + context->MonitorReady(context, &monitorReady); return 1; } static int cliprdr_process_filecontents_request(cliprdrPlugin* cliprdr, wStream* s, UINT32 length, UINT16 flags) { + CLIPRDR_FILE_CONTENTS_REQUEST request; CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); WLog_Print(cliprdr->log, WLOG_DEBUG, "FileContentsRequest"); - if (context->custom) - { - CLIPRDR_FILE_CONTENTS_REQUEST request; + if (!context->custom) + return -1; - if (Stream_GetRemainingLength(s) < 28) - return -1; + if (Stream_GetRemainingLength(s) < 28) + return -1; - request.msgType = CB_FILECONTENTS_REQUEST; - request.msgFlags = flags; - request.dataLen = length; + request.msgType = CB_FILECONTENTS_REQUEST; + request.msgFlags = flags; + request.dataLen = length; - Stream_Read_UINT32(s, request.streamId); /* streamId (4 bytes) */ - Stream_Read_UINT32(s, request.listIndex); /* listIndex (4 bytes) */ - Stream_Read_UINT32(s, request.dwFlags); /* dwFlags (4 bytes) */ - Stream_Read_UINT32(s, request.nPositionLow); /* nPositionLow (4 bytes) */ - Stream_Read_UINT32(s, request.nPositionHigh); /* nPositionHigh (4 bytes) */ - Stream_Read_UINT32(s, request.cbRequested); /* cbRequested (4 bytes) */ - Stream_Read_UINT32(s, request.clipDataId); /* clipDataId (4 bytes) */ + Stream_Read_UINT32(s, request.streamId); /* streamId (4 bytes) */ + Stream_Read_UINT32(s, request.listIndex); /* listIndex (4 bytes) */ + Stream_Read_UINT32(s, request.dwFlags); /* dwFlags (4 bytes) */ + Stream_Read_UINT32(s, request.nPositionLow); /* nPositionLow (4 bytes) */ + Stream_Read_UINT32(s, request.nPositionHigh); /* nPositionHigh (4 bytes) */ + Stream_Read_UINT32(s, request.cbRequested); /* cbRequested (4 bytes) */ + Stream_Read_UINT32(s, request.clipDataId); /* clipDataId (4 bytes) */ - if (context->ServerFileContentsRequest) - context->ServerFileContentsRequest(context, &request); - } + if (context->ServerFileContentsRequest) + context->ServerFileContentsRequest(context, &request); return 1; } static int cliprdr_process_filecontents_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 length, UINT16 flags) { + CLIPRDR_FILE_CONTENTS_RESPONSE response; CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); WLog_Print(cliprdr->log, WLOG_DEBUG, "FileContentsResponse"); - if (context->custom) - { - CLIPRDR_FILE_CONTENTS_RESPONSE response; - - if (Stream_GetRemainingLength(s) < 4) - return -1; - - response.msgType = CB_FILECONTENTS_RESPONSE; - response.msgFlags = flags; - response.dataLen = length; - - Stream_Read_UINT32(s, response.streamId); /* streamId (4 bytes) */ + if (!context->custom) + return -1; - response.cbRequested = length - 4; - response.requestedData = Stream_Pointer(s); /* requestedFileContentsData */ + if (Stream_GetRemainingLength(s) < 4) + return -1; - if (context->ServerFileContentsResponse) - context->ServerFileContentsResponse(context, &response); - } + response.msgType = CB_FILECONTENTS_RESPONSE; + response.msgFlags = flags; + response.dataLen = length; + + Stream_Read_UINT32(s, response.streamId); /* streamId (4 bytes) */ + + response.cbRequested = length - 4; + response.requestedData = Stream_Pointer(s); /* requestedFileContentsData */ + + if (context->ServerFileContentsResponse) + context->ServerFileContentsResponse(context, &response); return 1; } static int cliprdr_process_lock_clipdata(cliprdrPlugin* cliprdr, wStream* s, UINT32 length, UINT16 flags) { + CLIPRDR_LOCK_CLIPBOARD_DATA lockClipboardData; CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); WLog_Print(cliprdr->log, WLOG_DEBUG, "LockClipData"); - if (context->custom) - { - CLIPRDR_LOCK_CLIPBOARD_DATA lockClipboardData; + if (!context->custom) + return -1; + + if (Stream_GetRemainingLength(s) < 4) + return -1; - if (Stream_GetRemainingLength(s) < 4) - return -1; + lockClipboardData.msgType = CB_LOCK_CLIPDATA; + lockClipboardData.msgFlags = flags; + lockClipboardData.dataLen = length; - lockClipboardData.msgType = CB_LOCK_CLIPDATA; - lockClipboardData.msgFlags = flags; - lockClipboardData.dataLen = length; + Stream_Read_UINT32(s, lockClipboardData.clipDataId); /* clipDataId (4 bytes) */ - Stream_Read_UINT32(s, lockClipboardData.clipDataId); /* clipDataId (4 bytes) */ - - if (context->ServerLockClipboardData) - context->ServerLockClipboardData(context, &lockClipboardData); - } + if (context->ServerLockClipboardData) + context->ServerLockClipboardData(context, &lockClipboardData); return 1; } static int cliprdr_process_unlock_clipdata(cliprdrPlugin* cliprdr, wStream* s, UINT32 length, UINT16 flags) { + CLIPRDR_UNLOCK_CLIPBOARD_DATA unlockClipboardData; CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); WLog_Print(cliprdr->log, WLOG_DEBUG, "UnlockClipData"); - if (context->custom) - { - CLIPRDR_UNLOCK_CLIPBOARD_DATA unlockClipboardData; + if (!context->custom) + return -1; + + if (Stream_GetRemainingLength(s) < 4) + return -1; - if (Stream_GetRemainingLength(s) < 4) - return -1; + unlockClipboardData.msgType = CB_UNLOCK_CLIPDATA; + unlockClipboardData.msgFlags = flags; + unlockClipboardData.dataLen = length; - unlockClipboardData.msgType = CB_UNLOCK_CLIPDATA; - unlockClipboardData.msgFlags = flags; - unlockClipboardData.dataLen = length; + Stream_Read_UINT32(s, unlockClipboardData.clipDataId); /* clipDataId (4 bytes) */ - Stream_Read_UINT32(s, unlockClipboardData.clipDataId); /* clipDataId (4 bytes) */ - - if (context->ServerUnlockClipboardData) - context->ServerUnlockClipboardData(context, &unlockClipboardData); - } + if (context->ServerUnlockClipboardData) + context->ServerUnlockClipboardData(context, &unlockClipboardData); return 1; } @@ -339,9 +353,9 @@ static void cliprdr_order_recv(cliprdrPlugin* cliprdr, wStream* s) UINT16 msgFlags; UINT32 dataLen; - Stream_Read_UINT16(s, msgType); - Stream_Read_UINT16(s, msgFlags); - Stream_Read_UINT32(s, dataLen); + Stream_Read_UINT16(s, msgType); /* msgType (2 bytes) */ + Stream_Read_UINT16(s, msgFlags); /* msgFlags (2 bytes) */ + Stream_Read_UINT32(s, dataLen); /* dataLen (4 bytes) */ DEBUG_CLIPRDR("msgType: %s (%d), msgFlags: %d dataLen: %d", CB_MSG_TYPE_STRINGS[msgType], msgType, msgFlags, dataLen); @@ -406,7 +420,7 @@ int cliprdr_client_capabilities(CliprdrClientContext* context, CLIPRDR_CAPABILIT wStream* s; CLIPRDR_GENERAL_CAPABILITY_SET* generalCapabilitySet; cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle; - + s = cliprdr_packet_new(CB_CLIP_CAPS, 0, 4 + CB_CAPSTYPE_GENERAL_LEN); Stream_Write_UINT16(s, 1); /* cCapabilitiesSets */ @@ -459,47 +473,100 @@ int cliprdr_client_format_list(CliprdrClientContext* context, CLIPRDR_FORMAT_LIS wStream* s; UINT32 index; int length = 0; + int cchWideChar; + LPWSTR lpWideCharStr; int formatNameSize; + int formatNameLength; + char* szFormatName; + WCHAR* wszFormatName; + BOOL asciiNames = FALSE; CLIPRDR_FORMAT* format; cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle; - for (index = 0; index < formatList->numFormats; index++) + if (!cliprdr->useLongFormatNames) { - format = (CLIPRDR_FORMAT*) &(formatList->formats[index]); - length += 4; - formatNameSize = 2; - - if (format->formatName) - formatNameSize = MultiByteToWideChar(CP_UTF8, 0, format->formatName, -1, NULL, 0) * 2; - - length += formatNameSize; - } - - s = cliprdr_packet_new(CB_FORMAT_LIST, 0, length); - - for (index = 0; index < formatList->numFormats; index++) - { - format = (CLIPRDR_FORMAT*) &(formatList->formats[index]); - Stream_Write_UINT32(s, format->formatId); /* formatId (4 bytes) */ - - if (format->formatName) + length = formatList->numFormats * 36; + + s = cliprdr_packet_new(CB_FORMAT_LIST, 0, length); + + for (index = 0; index < formatList->numFormats; index++) { - int cchWideChar; - LPWSTR lpWideCharStr; - lpWideCharStr = (LPWSTR) Stream_Pointer(s); - cchWideChar = (Stream_Capacity(s) - Stream_GetPosition(s)) / 2; - formatNameSize = MultiByteToWideChar(CP_UTF8, 0, - format->formatName, -1, lpWideCharStr, cchWideChar) * 2; - Stream_Seek(s, formatNameSize); + format = (CLIPRDR_FORMAT*) &(formatList->formats[index]); + + Stream_Write_UINT32(s, format->formatId); /* formatId (4 bytes) */ + + formatNameSize = 0; + formatNameLength = 0; + + szFormatName = format->formatName; + + if (asciiNames) + { + if (szFormatName) + formatNameLength = strlen(szFormatName); + + if (formatNameLength > 31) + formatNameLength = 31; + + Stream_Write(s, szFormatName, formatNameLength); + Stream_Zero(s, 32 - formatNameLength); + } + else + { + wszFormatName = NULL; + + if (szFormatName) + formatNameSize = ConvertToUnicode(CP_UTF8, 0, szFormatName, -1, &wszFormatName, 0); + + if (formatNameSize > 15) + formatNameSize = 15; + + Stream_Write(s, wszFormatName, formatNameSize * 2); + Stream_Zero(s, 32 - (formatNameSize * 2)); + + free(wszFormatName); + } } - else + } + else + { + for (index = 0; index < formatList->numFormats; index++) { - Stream_Write_UINT16(s, 0); + format = (CLIPRDR_FORMAT*) &(formatList->formats[index]); + length += 4; + formatNameSize = 2; + + if (format->formatName) + formatNameSize = MultiByteToWideChar(CP_UTF8, 0, format->formatName, -1, NULL, 0) * 2; + + length += formatNameSize; + } + + s = cliprdr_packet_new(CB_FORMAT_LIST, 0, length); + + for (index = 0; index < formatList->numFormats; index++) + { + format = (CLIPRDR_FORMAT*) &(formatList->formats[index]); + Stream_Write_UINT32(s, format->formatId); /* formatId (4 bytes) */ + + if (format->formatName) + { + lpWideCharStr = (LPWSTR) Stream_Pointer(s); + cchWideChar = (Stream_Capacity(s) - Stream_GetPosition(s)) / 2; + formatNameSize = MultiByteToWideChar(CP_UTF8, 0, + format->formatName, -1, lpWideCharStr, cchWideChar) * 2; + Stream_Seek(s, formatNameSize); + } + else + { + Stream_Write_UINT16(s, 0); + } } } WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFormatList: numFormats: %d", formatList->numFormats); + cliprdr_packet_send(cliprdr, s); return 0; @@ -897,6 +964,11 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints) cliprdr->log = WLog_Get("com.freerdp.channels.cliprdr.client"); + cliprdr->useLongFormatNames = TRUE; + cliprdr->streamFileClipEnabled = FALSE; + cliprdr->fileClipNoFilePaths = TRUE; + cliprdr->canLockClipData = FALSE; + WLog_Print(cliprdr->log, WLOG_DEBUG, "VirtualChannelEntry"); CopyMemory(&(cliprdr->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP)); diff --git a/channels/cliprdr/client/cliprdr_main.h b/channels/cliprdr/client/cliprdr_main.h index 28ff62d42..65926dd16 100644 --- a/channels/cliprdr/client/cliprdr_main.h +++ b/channels/cliprdr/client/cliprdr_main.h @@ -41,14 +41,11 @@ struct cliprdr_plugin DWORD OpenHandle; wMessagePipe* MsgPipe; - int num_format_names; - CLIPRDR_FORMAT_NAME* format_names; - - BOOL received_caps; - BOOL use_long_format_names; - BOOL stream_fileclip_enabled; - BOOL fileclip_no_file_paths; - BOOL can_lock_clipdata; + BOOL capabilitiesReceived; + BOOL useLongFormatNames; + BOOL streamFileClipEnabled; + BOOL fileClipNoFilePaths; + BOOL canLockClipData; }; typedef struct cliprdr_plugin cliprdrPlugin; diff --git a/channels/rdpei/CMakeLists.txt b/channels/rdpei/CMakeLists.txt index e5ffe6afc..a93af67c5 100644 --- a/channels/rdpei/CMakeLists.txt +++ b/channels/rdpei/CMakeLists.txt @@ -21,3 +21,6 @@ if(WITH_CLIENT_CHANNELS) add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME}) endif() +if(WITH_SERVER_CHANNELS) + add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME}) +endif() \ No newline at end of file diff --git a/channels/rdpei/client/CMakeLists.txt b/channels/rdpei/client/CMakeLists.txt index db3794621..875efac86 100644 --- a/channels/rdpei/client/CMakeLists.txt +++ b/channels/rdpei/client/CMakeLists.txt @@ -20,11 +20,10 @@ define_channel_client("rdpei") set(${MODULE_PREFIX}_SRCS rdpei_main.c rdpei_main.h - rdpei_common.c - rdpei_common.h) + ../rdpei_common.c + ../rdpei_common.h) include_directories(..) - add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry") diff --git a/channels/rdpei/client/rdpei_main.h b/channels/rdpei/client/rdpei_main.h index 4da19ee84..bc7c63da3 100644 --- a/channels/rdpei/client/rdpei_main.h +++ b/channels/rdpei/client/rdpei_main.h @@ -29,31 +29,11 @@ #include #include +#include #include #define TAG CHANNELS_TAG("rdpei.client") -#define RDPINPUT_HEADER_LENGTH 6 - -/* Protocol Version */ - -#define RDPINPUT_PROTOCOL_V10 0x00010000 -#define RDPINPUT_PROTOCOL_V101 0x00010001 - -/* Client Ready Flags */ - -#define READY_FLAGS_SHOW_TOUCH_VISUALS 0x00000001 -#define READY_FLAGS_DISABLE_TIMESTAMP_INJECTION 0x00000002 - -/* Input Event Ids */ - -#define EVENTID_SC_READY 0x0001 -#define EVENTID_CS_READY 0x0002 -#define EVENTID_TOUCH 0x0003 -#define EVENTID_SUSPEND_TOUCH 0x0004 -#define EVENTID_RESUME_TOUCH 0x0005 -#define EVENTID_DISMISS_HOVERING_CONTACT 0x0006 - #define RDPINPUT_CONTACT_STATE_INITIAL 0x0000 #define RDPINPUT_CONTACT_STATE_ENGAGED 0x0001 #define RDPINPUT_CONTACT_STATE_HOVERING 0x0002 diff --git a/channels/rdpei/client/rdpei_common.c b/channels/rdpei/rdpei_common.c similarity index 96% rename from channels/rdpei/client/rdpei_common.c rename to channels/rdpei/rdpei_common.c index 3f6b3d819..62625eccc 100644 --- a/channels/rdpei/client/rdpei_common.c +++ b/channels/rdpei/rdpei_common.c @@ -3,6 +3,7 @@ * Input Virtual Channel Extension * * Copyright 2013 Marc-Andre Moreau + * Copyright 2014 David Fort * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -587,3 +588,23 @@ BOOL rdpei_write_8byte_unsigned(wStream* s, UINT64 value) return TRUE; } + +void touch_event_reset(RDPINPUT_TOUCH_EVENT *event) +{ + int i; + + for (i = 0; i < event->frameCount; i++) + touch_frame_reset(&event->frames[i]); + + free(event->frames); + event->frames = NULL; + event->frameCount = 0; +} + + +void touch_frame_reset(RDPINPUT_TOUCH_FRAME *frame) +{ + free(frame->contacts); + frame->contacts = NULL; + frame->contactCount = 0; +} diff --git a/channels/rdpei/client/rdpei_common.h b/channels/rdpei/rdpei_common.h similarity index 70% rename from channels/rdpei/client/rdpei_common.h rename to channels/rdpei/rdpei_common.h index 293919f67..34d1edd64 100644 --- a/channels/rdpei/client/rdpei_common.h +++ b/channels/rdpei/rdpei_common.h @@ -3,6 +3,7 @@ * Input Virtual Channel Extension * * Copyright 2013 Marc-Andre Moreau + * Copyright 2014 David Fort * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,11 +18,22 @@ * limitations under the License. */ -#ifndef FREERDP_CHANNEL_RDPEI_CLIENT_COMMON_H -#define FREERDP_CHANNEL_RDPEI_CLIENT_COMMON_H +#ifndef FREERDP_CHANNEL_RDPEI_COMMON_H +#define FREERDP_CHANNEL_RDPEI_COMMON_H #include #include +#include + +/** @brief input event ids */ +enum { + EVENTID_SC_READY = 0x0001, + EVENTID_CS_READY = 0x0002, + EVENTID_TOUCH = 0x0003, + EVENTID_SUSPEND_TOUCH = 0x0004, + EVENTID_RESUME_TOUCH = 0x0005, + EVENTID_DISMISS_HOVERING_CONTACT = 0x0006 +}; BOOL rdpei_read_2byte_unsigned(wStream* s, UINT32* value); BOOL rdpei_write_2byte_unsigned(wStream* s, UINT32 value); @@ -34,5 +46,8 @@ BOOL rdpei_write_4byte_signed(wStream* s, INT32 value); BOOL rdpei_read_8byte_unsigned(wStream* s, UINT64* value); BOOL rdpei_write_8byte_unsigned(wStream* s, UINT64 value); -#endif /* FREERDP_CHANNEL_RDPEI_CLIENT_COMMON_H */ +void touch_event_reset(RDPINPUT_TOUCH_EVENT *event); +void touch_frame_reset(RDPINPUT_TOUCH_FRAME *frame); + +#endif /* FREERDP_CHANNEL_RDPEI_COMMON_H */ diff --git a/channels/rdpei/server/CMakeLists.txt b/channels/rdpei/server/CMakeLists.txt new file mode 100644 index 000000000..e98c4576f --- /dev/null +++ b/channels/rdpei/server/CMakeLists.txt @@ -0,0 +1,38 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2014 Thincast Technologies Gmbh. +# Copyright 2014 David FORT +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +define_channel_server("rdpei") + +set(${MODULE_PREFIX}_SRCS + rdpei_main.c + rdpei_main.h + ../rdpei_common.c + ../rdpei_common.h +) + +add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry") + +set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") + +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr) + +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) + +install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server") diff --git a/channels/rdpei/server/rdpei_main.c b/channels/rdpei/server/rdpei_main.c new file mode 100644 index 000000000..95f70f567 --- /dev/null +++ b/channels/rdpei/server/rdpei_main.c @@ -0,0 +1,460 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Extended Input channel server-side implementation + * + * Copyright 2014 Thincast Technologies Gmbh. + * Copyright 2014 David FORT + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "rdpei_main.h" +#include "../rdpei_common.h" +#include +#include + +/** @brief */ +enum RdpEiState { + STATE_INITIAL, + STATE_WAITING_CLIENT_READY, + STATE_WAITING_FRAME, + STATE_SUSPENDED, +}; + +struct _rdpei_server_private +{ + HANDLE channelHandle; + HANDLE eventHandle; + + UINT32 expectedBytes; + BOOL waitingHeaders; + wStream *inputStream; + wStream *outputStream; + + UINT16 currentMsgType; + + RDPINPUT_TOUCH_EVENT touchEvent; + + enum RdpEiState automataState; +}; + + +RdpeiServerContext* rdpei_server_context_new(HANDLE vcm) +{ + RdpeiServerContext *ret = calloc(1, sizeof(*ret)); + RdpeiServerPrivate *priv; + + if (!ret) + return NULL; + + ret->priv = priv = calloc(1, sizeof(*ret->priv)); + if (!priv) + goto out_free; + + priv->inputStream = Stream_New(NULL, 256); + if (!priv->inputStream) + goto out_free_priv; + + priv->outputStream = Stream_New(NULL, 200); + if (!priv->inputStream) + goto out_free_input_stream; + + ret->vcm = vcm; + rdpei_server_context_reset(ret); + return ret; + +out_free_input_stream: + Stream_Free(priv->inputStream, TRUE); +out_free_priv: + free(ret->priv); +out_free: + free(ret); + return NULL; +} + +int rdpei_server_init(RdpeiServerContext *context) +{ + void *buffer = NULL; + DWORD bytesReturned; + RdpeiServerPrivate *priv = context->priv; + + priv->channelHandle = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, RDPEI_DVC_CHANNEL_NAME, WTS_CHANNEL_OPTION_DYNAMIC); + if (!priv->channelHandle) + { + fprintf(stderr, "%s: unable to open channel\n", __FUNCTION__); + return -1; + } + + if (!WTSVirtualChannelQuery(priv->channelHandle, WTSVirtualEventHandle, &buffer, &bytesReturned) || (bytesReturned != sizeof(HANDLE))) + { + fprintf(stderr, "%s: error during WTSVirtualChannelQuery(WTSVirtualEventHandle) or invalid returned size(%d)\n", + __FUNCTION__, bytesReturned); + if (buffer) + WTSFreeMemory(buffer); + goto out_close; + } + CopyMemory(&priv->eventHandle, buffer, sizeof(HANDLE)); + WTSFreeMemory(buffer); + + return 0; + +out_close: + WTSVirtualChannelClose(priv->channelHandle); + return -1; +} + + +void rdpei_server_context_reset(RdpeiServerContext *context) +{ + RdpeiServerPrivate *priv = context->priv; + + priv->expectedBytes = RDPINPUT_HEADER_LENGTH; + priv->waitingHeaders = TRUE; + priv->automataState = STATE_INITIAL; + Stream_SetPosition(priv->inputStream, 0); +} + +void rdpei_server_context_free(RdpeiServerContext* context) +{ + Stream_Free(context->priv->inputStream, TRUE); + free(context->priv); + free(context); +} + +HANDLE rdpei_server_get_event_handle(RdpeiServerContext *context) +{ + return context->priv->eventHandle; +} + + +static int read_cs_ready_message(RdpeiServerContext *context, wStream *s) +{ + if (Stream_GetRemainingLength(s) < 10) + return -1; + + Stream_Read_UINT32(s, context->protocolFlags); + Stream_Read_UINT32(s, context->clientVersion); + Stream_Read_UINT16(s, context->maxTouchPoints); + + switch (context->clientVersion) + { + case RDPINPUT_PROTOCOL_V10: + case RDPINPUT_PROTOCOL_V101: + break; + default: + fprintf(stderr, "%s: unhandled RPDEI protocol version 0x%x\n", __FUNCTION__, context->clientVersion); + break; + } + + if (context->onClientReady) + context->onClientReady(context); + return 0; +} + +static int read_touch_contact_data(RdpeiServerContext *context, wStream *s, RDPINPUT_CONTACT_DATA *contactData) +{ + if (Stream_GetRemainingLength(s) < 1) + return -1; + + Stream_Read_UINT8(s, contactData->contactId); + if (!rdpei_read_2byte_unsigned(s, &contactData->fieldsPresent) || + !rdpei_read_4byte_signed(s, &contactData->x) || + !rdpei_read_4byte_signed(s, &contactData->y) || + !rdpei_read_4byte_unsigned(s, &contactData->contactFlags)) + return -1; + + if (contactData->fieldsPresent & CONTACT_DATA_CONTACTRECT_PRESENT) + { + if (!rdpei_read_2byte_signed(s, &contactData->contactRectLeft) || + !rdpei_read_2byte_signed(s, &contactData->contactRectTop) || + !rdpei_read_2byte_signed(s, &contactData->contactRectRight) || + !rdpei_read_2byte_signed(s, &contactData->contactRectBottom)) + return -1; + } + + if ((contactData->fieldsPresent & CONTACT_DATA_ORIENTATION_PRESENT) && + !rdpei_read_4byte_unsigned(s, &contactData->orientation)) + return -1; + + if ((contactData->fieldsPresent & CONTACT_DATA_PRESSURE_PRESENT) && + !rdpei_read_4byte_unsigned(s, &contactData->pressure)) + return -1; + + return 0; +} + +static int read_touch_frame(RdpeiServerContext *context, wStream *s, RDPINPUT_TOUCH_FRAME *frame) +{ + int i; + RDPINPUT_CONTACT_DATA *contact; + + if (!rdpei_read_2byte_unsigned(s, &frame->contactCount) || !rdpei_read_8byte_unsigned(s, &frame->frameOffset)) + return -1; + + frame->contacts = contact = calloc(frame->contactCount, sizeof(RDPINPUT_CONTACT_DATA)); + if (!frame->contacts) + return -1; + + for (i = 0; i < frame->contactCount; i++, contact++) + { + if (read_touch_contact_data(context, s, contact) < 0) + { + frame->contactCount = i; + goto out_cleanup; + } + } + return 0; + +out_cleanup: + touch_frame_reset(frame); + return -1; +} + +static int read_touch_event(RdpeiServerContext *context, wStream *s) +{ + UINT32 frameCount; + int i, ret; + RDPINPUT_TOUCH_EVENT *event = &context->priv->touchEvent; + RDPINPUT_TOUCH_FRAME *frame; + + ret = -1; + if (!rdpei_read_4byte_unsigned(s, &event->encodeTime) || !rdpei_read_2byte_unsigned(s, &frameCount)) + return -1; + + event->frameCount = frameCount; + event->frames = frame = calloc(event->frameCount, sizeof(RDPINPUT_TOUCH_FRAME)); + if (!event->frames) + return -1; + + for (i = 0; i < frameCount; i++, frame++) + { + if (read_touch_frame(context, s, frame) < 0) + { + event->frameCount = i; + goto out_cleanup; + } + } + + if (context->onTouchEvent) + context->onTouchEvent(context, event); + + ret = 0; + +out_cleanup: + touch_event_reset(event); + return ret; +} + + +static int read_dismiss_hovering_contact(RdpeiServerContext *context, wStream *s) { + BYTE contactId; + if (Stream_GetRemainingLength(s) < 1) + return -1; + + Stream_Read_UINT8(s, contactId); + if (context->onTouchReleased) + context->onTouchReleased(context, contactId); + return 0; +} + + +int rdpei_server_handle_messages(RdpeiServerContext *context) { + DWORD bytesReturned; + RdpeiServerPrivate *priv = context->priv; + wStream *s = priv->inputStream; + + if (!WTSVirtualChannelRead(priv->channelHandle, 0, (PCHAR)Stream_Pointer(s), priv->expectedBytes, &bytesReturned)) + { + if (GetLastError() == ERROR_NO_DATA) + return -1; + + fprintf(stderr, "%s: channel connection closed\n", __FUNCTION__); + return 0; + } + priv->expectedBytes -= bytesReturned; + Stream_Seek(s, bytesReturned); + + if (priv->expectedBytes) + return 1; + + Stream_SealLength(s); + Stream_SetPosition(s, 0); + + if (priv->waitingHeaders) + { + UINT32 pduLen; + + /* header case */ + Stream_Read_UINT16(s, priv->currentMsgType); + Stream_Read_UINT16(s, pduLen); + + if (pduLen < RDPINPUT_HEADER_LENGTH) + { + fprintf(stderr, "%s: invalid pduLength %d\n", __FUNCTION__, pduLen); + return -1; + } + priv->expectedBytes = pduLen - RDPINPUT_HEADER_LENGTH; + priv->waitingHeaders = FALSE; + Stream_SetPosition(s, 0); + if (priv->expectedBytes) + { + Stream_EnsureCapacity(s, priv->expectedBytes); + return 1; + } + } + + /* when here we have the header + the body */ + switch (priv->currentMsgType) + { + case EVENTID_CS_READY: + if (priv->automataState != STATE_WAITING_CLIENT_READY) + { + fprintf(stderr, "%s: not expecting a CS_READY packet in this state(%d)\n", __FUNCTION__, (int)priv->automataState); + return 0; + } + + if (read_cs_ready_message(context, s) < 0) + return 0; + break; + + case EVENTID_TOUCH: + if (read_touch_event(context, s) < 0) + { + fprintf(stderr, "%s: error in touch event packet\n", __FUNCTION__); + return 0; + } + break; + case EVENTID_DISMISS_HOVERING_CONTACT: + if (read_dismiss_hovering_contact(context, s) < 0) + { + fprintf(stderr, "%s: error reading read_dismiss_hovering_contact\n", __FUNCTION__); + return 0; + } + break; + default: + fprintf(stderr, "%s: unexpected message type 0x%x\n", __FUNCTION__, priv->currentMsgType); + } + + Stream_SetPosition(s, 0); + priv->waitingHeaders = TRUE; + priv->expectedBytes = RDPINPUT_HEADER_LENGTH; + return 1; +} + + +int rdpei_server_send_sc_ready(RdpeiServerContext *context, UINT32 version) +{ + ULONG written; + RdpeiServerPrivate *priv = context->priv; + + if (priv->automataState != STATE_INITIAL) + { + fprintf(stderr, "%s: called from unexpected state %d\n", __FUNCTION__, priv->automataState); + return -1; + } + + Stream_SetPosition(priv->outputStream, 0); + Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH + 4); + + Stream_Write_UINT16(priv->outputStream, EVENTID_SC_READY); + Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH + 4); + Stream_Write_UINT32(priv->outputStream, version); + + if (!WTSVirtualChannelWrite(priv->channelHandle, (PCHAR)Stream_Buffer(priv->outputStream), + Stream_GetPosition(priv->outputStream), &written)) + { + fprintf(stderr, "%s: error writing ready message\n", __FUNCTION__); + return -1; + } + + priv->automataState = STATE_WAITING_CLIENT_READY; + return 0; +} + +int rdpei_server_suspend(RdpeiServerContext *context) +{ + ULONG written; + RdpeiServerPrivate *priv = context->priv; + + switch (priv->automataState) + { + case STATE_SUSPENDED: + fprintf(stderr, "%s: already suspended\n", __FUNCTION__); + return 0; + case STATE_WAITING_FRAME: + break; + default: + fprintf(stderr, "%s: called from unexpected state %d\n", __FUNCTION__, priv->automataState); + return -1; + } + + Stream_SetPosition(priv->outputStream, 0); + Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH); + + Stream_Write_UINT16(priv->outputStream, EVENTID_SUSPEND_TOUCH); + Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH); + + if (!WTSVirtualChannelWrite(priv->channelHandle, (PCHAR)Stream_Buffer(priv->outputStream), + Stream_GetPosition(priv->outputStream), &written)) + { + fprintf(stderr, "%s: error writing suspendTouch message\n", __FUNCTION__); + return -1; + } + + priv->automataState = STATE_SUSPENDED; + return 0; +} + + +int rdpei_server_resume(RdpeiServerContext *context) +{ + ULONG written; + RdpeiServerPrivate *priv = context->priv; + + switch (priv->automataState) + { + case STATE_WAITING_FRAME: + fprintf(stderr, "%s: not suspended\n", __FUNCTION__); + return 0; + case STATE_SUSPENDED: + break; + default: + fprintf(stderr, "%s: called from unexpected state %d\n", __FUNCTION__, priv->automataState); + return -1; + } + + Stream_SetPosition(priv->outputStream, 0); + Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH); + + Stream_Write_UINT16(priv->outputStream, EVENTID_RESUME_TOUCH); + Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH); + + if (!WTSVirtualChannelWrite(priv->channelHandle, (PCHAR)Stream_Buffer(priv->outputStream), + Stream_GetPosition(priv->outputStream), &written)) + { + fprintf(stderr, "%s: error writing resumeTouch message\n", __FUNCTION__); + return -1; + } + + priv->automataState = STATE_WAITING_FRAME; + return 0; +} + diff --git a/channels/rdpei/server/rdpei_main.h b/channels/rdpei/server/rdpei_main.h new file mode 100644 index 000000000..44dd03ed3 --- /dev/null +++ b/channels/rdpei/server/rdpei_main.h @@ -0,0 +1,29 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Extended Input channel server-side implementation + * + * Copyright 2014 David Fort + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __FREERDP_CHANNEL_SERVER_RDPEI_MAIN_H_ +#define __FREERDP_CHANNEL_SERVER_RDPEI_MAIN_H_ + +#include +#include +#include + + +#endif /* FREERDP_CHANNEL_SERVER_RDPEI_MAIN_H_ */ + diff --git a/channels/server/channels.c b/channels/server/channels.c index cac4243bd..cb312c849 100644 --- a/channels/server/channels.c +++ b/channels/server/channels.c @@ -45,9 +45,10 @@ #include #include #include +#include #include -void freerdp_channels_dummy() +void freerdp_channels_dummy() { audin_server_context_new(NULL); audin_server_context_free(NULL); @@ -66,6 +67,9 @@ void freerdp_channels_dummy() drdynvc_server_context_new(NULL); drdynvc_server_context_free(NULL); + + rdpei_server_context_new(NULL); + rdpei_server_context_free(NULL); } /** diff --git a/client/Mac/Clipboard.m b/client/Mac/Clipboard.m index d0e9575b0..0cd3546e3 100644 --- a/client/Mac/Clipboard.m +++ b/client/Mac/Clipboard.m @@ -57,12 +57,30 @@ int mac_cliprdr_send_client_format_list(CliprdrClientContext* cliprdr) mfc->cliprdr->ClientFormatList(mfc->cliprdr, &formatList); + for (index = 0; index < numFormats; index++) + { + free(formats[index].formatName); + } + free(pFormatIds); free(formats); return 1; } +int mac_cliprdr_send_client_format_list_response(CliprdrClientContext* cliprdr, BOOL status) +{ + CLIPRDR_FORMAT_LIST_RESPONSE formatListResponse; + + formatListResponse.msgType = CB_FORMAT_LIST_RESPONSE; + formatListResponse.msgFlags = status ? CB_RESPONSE_OK : CB_RESPONSE_FAIL; + formatListResponse.dataLen = 0; + + cliprdr->ClientFormatListResponse(cliprdr, &formatListResponse); + + return 1; +} + int mac_cliprdr_send_client_format_data_request(CliprdrClientContext* cliprdr, UINT32 formatId) { CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest; @@ -172,6 +190,8 @@ int mac_cliprdr_server_format_list(CliprdrClientContext* cliprdr, CLIPRDR_FORMAT mfc->serverFormats[index].formatName = _strdup(formatList->formats[index].formatName); } + mac_cliprdr_send_client_format_list_response(cliprdr, TRUE); + for (index = 0; index < mfc->numServerFormats; index++) { format = &(mfc->serverFormats[index]); @@ -247,6 +267,12 @@ int mac_cliprdr_server_format_data_response(CliprdrClientContext* cliprdr, CLIPR mfContext* mfc = (mfContext*) cliprdr->custom; MRDPView* view = (MRDPView*) mfc->view; + if (formatDataResponse->msgFlags & CB_RESPONSE_FAIL) + { + SetEvent(mfc->clipboardRequestEvent); + return -1; + } + for (index = 0; index < mfc->numServerFormats; index++) { if (mfc->requestedFormatId == mfc->serverFormats[index].formatId) @@ -266,6 +292,13 @@ int mac_cliprdr_server_format_data_response(CliprdrClientContext* cliprdr, CLIPR size = formatDataResponse->dataLen; data = (BYTE*) malloc(size); + + if (!data) + { + SetEvent(mfc->clipboardRequestEvent); + return -1; + } + CopyMemory(data, formatDataResponse->requestedFormatData, size); ClipboardSetData(mfc->clipboard, formatId, data, size); diff --git a/client/Mac/MRDPView.m b/client/Mac/MRDPView.m index 4d963253b..42c6dbe2d 100644 --- a/client/Mac/MRDPView.m +++ b/client/Mac/MRDPView.m @@ -146,6 +146,9 @@ DWORD mac_client_input_thread(void* param) if (!status) break; } + + if (!status) + break; } ExitThread(0); diff --git a/client/iOS/FreeRDP/ios_freerdp_ui.m b/client/iOS/FreeRDP/ios_freerdp_ui.m index ada0e9cbc..6030fc6f0 100644 --- a/client/iOS/FreeRDP/ios_freerdp_ui.m +++ b/client/iOS/FreeRDP/ios_freerdp_ui.m @@ -106,7 +106,8 @@ void ios_ui_end_paint(rdpContext * context) rdpGdi *gdi = context->gdi; CGRect dirty_rect = CGRectMake(gdi->primary->hdc->hwnd->invalid->x, gdi->primary->hdc->hwnd->invalid->y, gdi->primary->hdc->hwnd->invalid->w, gdi->primary->hdc->hwnd->invalid->h); - [mfi->session performSelectorOnMainThread:@selector(setNeedsDisplayInRectAsValue:) withObject:[NSValue valueWithCGRect:dirty_rect] waitUntilDone:NO]; + if (gdi->primary->hdc->hwnd->invalid->null == 0) + [mfi->session performSelectorOnMainThread:@selector(setNeedsDisplayInRectAsValue:) withObject:[NSValue valueWithCGRect:dirty_rect] waitUntilDone:NO]; } diff --git a/include/freerdp/channels/rdpei.h b/include/freerdp/channels/rdpei.h new file mode 100644 index 000000000..ac76bf364 --- /dev/null +++ b/include/freerdp/channels/rdpei.h @@ -0,0 +1,91 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Extended Input channel common definitions + * + * Copyright 2013 Marc-Andre Moreau + * Copyright 2014 Thincast Technologies Gmbh. + * Copyright 2014 David FORT + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __FREERDP_CHANNEL_RDPEI_H_ +#define __FREERDP_CHANNEL_RDPEI_H_ + +#include + +#define RDPINPUT_HEADER_LENGTH 6 + +#define RDPEI_DVC_CHANNEL_NAME "Microsoft::Windows::RDS::Input" + +/** @brief protocol version */ +enum { + RDPINPUT_PROTOCOL_V10 = 0x00010000, + RDPINPUT_PROTOCOL_V101 = 0x00010001 +}; + +/* Client Ready Flags */ +#define READY_FLAGS_SHOW_TOUCH_VISUALS 0x00000001 +#define READY_FLAGS_DISABLE_TIMESTAMP_INJECTION 0x00000002 + + +#define CONTACT_DATA_CONTACTRECT_PRESENT 0x0001 +#define CONTACT_DATA_ORIENTATION_PRESENT 0x0002 +#define CONTACT_DATA_PRESSURE_PRESENT 0x0004 + +#define CONTACT_FLAG_DOWN 0x0001 +#define CONTACT_FLAG_UPDATE 0x0002 +#define CONTACT_FLAG_UP 0x0004 +#define CONTACT_FLAG_INRANGE 0x0008 +#define CONTACT_FLAG_INCONTACT 0x0010 +#define CONTACT_FLAG_CANCELED 0x0020 + +/** @brief a contact point */ +struct _RDPINPUT_CONTACT_DATA +{ + UINT32 contactId; + UINT32 fieldsPresent; + INT32 x; + INT32 y; + UINT32 contactFlags; + INT32 contactRectLeft; + INT32 contactRectTop; + INT32 contactRectRight; + INT32 contactRectBottom; + UINT32 orientation; + UINT32 pressure; +}; +typedef struct _RDPINPUT_CONTACT_DATA RDPINPUT_CONTACT_DATA; + +/** @brief a frame containing contact points */ +struct _RDPINPUT_TOUCH_FRAME +{ + UINT32 contactCount; + UINT64 frameOffset; + RDPINPUT_CONTACT_DATA* contacts; +}; +typedef struct _RDPINPUT_TOUCH_FRAME RDPINPUT_TOUCH_FRAME; + + +/** @brief a touch event with some frames*/ +struct _RDPINPUT_TOUCH_EVENT +{ + UINT32 encodeTime; + UINT16 frameCount; + RDPINPUT_TOUCH_FRAME* frames; +}; +typedef struct _RDPINPUT_TOUCH_EVENT RDPINPUT_TOUCH_EVENT; + + +#endif /* __FREERDP_CHANNEL_RDPEI_H_ */ + diff --git a/include/freerdp/client/rdpei.h b/include/freerdp/client/rdpei.h index 76b889829..1dec61313 100644 --- a/include/freerdp/client/rdpei.h +++ b/include/freerdp/client/rdpei.h @@ -20,51 +20,15 @@ #ifndef FREERDP_CHANNEL_CLIENT_RDPEI_H #define FREERDP_CHANNEL_CLIENT_RDPEI_H -#define CONTACT_DATA_CONTACTRECT_PRESENT 0x0001 -#define CONTACT_DATA_ORIENTATION_PRESENT 0x0002 -#define CONTACT_DATA_PRESSURE_PRESENT 0x0004 - -#define CONTACT_FLAG_DOWN 0x0001 -#define CONTACT_FLAG_UPDATE 0x0002 -#define CONTACT_FLAG_UP 0x0004 -#define CONTACT_FLAG_INRANGE 0x0008 -#define CONTACT_FLAG_INCONTACT 0x0010 -#define CONTACT_FLAG_CANCELED 0x0020 - -struct _RDPINPUT_CONTACT_DATA -{ - UINT32 contactId; - UINT32 fieldsPresent; - INT32 x; - INT32 y; - UINT32 contactFlags; - INT32 contactRectLeft; - INT32 contactRectTop; - INT32 contactRectRight; - INT32 contactRectBottom; - UINT32 orientation; - UINT32 pressure; -}; -typedef struct _RDPINPUT_CONTACT_DATA RDPINPUT_CONTACT_DATA; - -struct _RDPINPUT_TOUCH_FRAME -{ - UINT32 contactCount; - UINT64 frameOffset; - RDPINPUT_CONTACT_DATA* contacts; -}; -typedef struct _RDPINPUT_TOUCH_FRAME RDPINPUT_TOUCH_FRAME; +#include /** * Client Interface */ -#define RDPEI_DVC_CHANNEL_NAME "Microsoft::Windows::RDS::Input" - typedef struct _rdpei_client_context RdpeiClientContext; -typedef int (*pcRdpeiGetVersion)(RdpeiClientContext* context); -typedef int (*pcRdpeiAddContact)(RdpeiClientContext* context, RDPINPUT_CONTACT_DATA* contact); +typedef int (*pcRdpeiGetVersion)(RdpeiClientContext* context);typedef int (*pcRdpeiAddContact)(RdpeiClientContext* context, RDPINPUT_CONTACT_DATA* contact); typedef int (*pcRdpeiTouchBegin)(RdpeiClientContext* context, int externalId, int x, int y); typedef int (*pcRdpeiTouchUpdate)(RdpeiClientContext* context, int externalId, int x, int y); diff --git a/include/freerdp/server/rdpei.h b/include/freerdp/server/rdpei.h new file mode 100644 index 000000000..c447b0d73 --- /dev/null +++ b/include/freerdp/server/rdpei.h @@ -0,0 +1,70 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Extended Input channel server-side definitions + * + * Copyright 2014 Thincast Technologies Gmbh. + * Copyright 2014 David FORT + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __FREERDP_CHANNEL_RDPEI_SERVER_H__ +#define __FREERDP_CHANNEL_RDPEI_SERVER_H__ + +#include +#include + + +typedef struct _rdpei_server_context RdpeiServerContext; +typedef struct _rdpei_server_private RdpeiServerPrivate; + +struct _rdpei_server_context +{ + HANDLE vcm; + + RdpeiServerPrivate* priv; + + UINT32 clientVersion; + UINT16 maxTouchPoints; + UINT32 protocolFlags; + + /** callbacks that can be set by the user */ + void (*onClientReady)(RdpeiServerContext *context); + void (*onTouchEvent)(RdpeiServerContext *context, RDPINPUT_TOUCH_EVENT *touchEvent); + void (*onTouchReleased)(RdpeiServerContext *context, BYTE contactId); + + void *user_data; /* user data, useful for callbacks */ +}; + +#ifdef __cplusplus +extern "C" { +#endif + +FREERDP_API RdpeiServerContext* rdpei_server_context_new(HANDLE vcm); +FREERDP_API void rdpei_server_context_reset(RdpeiServerContext *context); +FREERDP_API void rdpei_server_context_free(RdpeiServerContext* context); +FREERDP_API HANDLE rdpei_server_get_event_handle(RdpeiServerContext *context); +FREERDP_API int rdpei_server_init(RdpeiServerContext *context); +FREERDP_API int rdpei_server_handle_messages(RdpeiServerContext *context); + +FREERDP_API int rdpei_server_send_sc_ready(RdpeiServerContext *context, UINT32 version); +FREERDP_API int rdpei_server_suspend(RdpeiServerContext *context); +FREERDP_API int rdpei_server_resume(RdpeiServerContext *context); + +#ifdef __cplusplus +} +#endif + + + +#endif /* __FREERDP_CHANNEL_RDPEI_SERVER_H__ */ diff --git a/winpr/libwinpr/clipboard/clipboard.c b/winpr/libwinpr/clipboard/clipboard.c index 7c0333e78..0817b408f 100644 --- a/winpr/libwinpr/clipboard/clipboard.c +++ b/winpr/libwinpr/clipboard/clipboard.c @@ -63,6 +63,9 @@ wClipboardFormat* ClipboardFindFormat(wClipboard* clipboard, UINT32 formatId, co UINT32 index; wClipboardFormat* format = NULL; + if (!clipboard) + return NULL; + if (formatId) { for (index = 0; index < clipboard->numFormats; index++) @@ -128,16 +131,25 @@ wClipboardSynthesizer* ClipboardFindSynthesizer(wClipboardFormat* format, UINT32 void ClipboardLock(wClipboard* clipboard) { + if (!clipboard) + return; + EnterCriticalSection(&(clipboard->lock)); } void ClipboardUnlock(wClipboard* clipboard) { + if (!clipboard) + return; + LeaveCriticalSection(&(clipboard->lock)); } BOOL ClipboardEmpty(wClipboard* clipboard) { + if (!clipboard) + return NULL; + if (clipboard->data) { free((void*) clipboard->data); @@ -152,6 +164,9 @@ BOOL ClipboardEmpty(wClipboard* clipboard) UINT32 ClipboardCountRegisteredFormats(wClipboard* clipboard) { + if (!clipboard) + return 0; + return clipboard->numFormats; } @@ -160,6 +175,9 @@ UINT32 ClipboardGetRegisteredFormatIds(wClipboard* clipboard, UINT32** ppFormatI UINT32 index; UINT32* pFormatIds; wClipboardFormat* format; + + if (!clipboard) + return 0; if (!ppFormatIds) return 0; @@ -188,6 +206,9 @@ UINT32 ClipboardGetRegisteredFormatIds(wClipboard* clipboard, UINT32** ppFormatI UINT32 ClipboardRegisterFormat(wClipboard* clipboard, const char* name) { wClipboardFormat* format; + + if (!clipboard) + return 0; format = ClipboardFindFormat(clipboard, 0, name); @@ -228,6 +249,9 @@ BOOL ClipboardRegisterSynthesizer(wClipboard* clipboard, UINT32 formatId, UINT32 index; wClipboardFormat* format; wClipboardSynthesizer* synthesizer; + + if (!clipboard) + return FALSE; format = ClipboardFindFormat(clipboard, formatId, NULL); @@ -264,6 +288,9 @@ UINT32 ClipboardCountFormats(wClipboard* clipboard) { UINT32 count; wClipboardFormat* format; + + if (!clipboard) + return 0; format = ClipboardFindFormat(clipboard, clipboard->formatId, NULL); @@ -282,6 +309,9 @@ UINT32 ClipboardGetFormatIds(wClipboard* clipboard, UINT32** ppFormatIds) UINT32* pFormatIds; wClipboardFormat* format; wClipboardSynthesizer* synthesizer; + + if (!clipboard) + return 0; format = ClipboardFindFormat(clipboard, clipboard->formatId, NULL); @@ -320,6 +350,9 @@ BOOL ClipboardInitFormats(wClipboard* clipboard) { UINT32 formatId = 0; wClipboardFormat* format; + + if (!clipboard) + return FALSE; for (formatId = 0; formatId < CF_MAX; formatId++) { @@ -342,6 +375,9 @@ UINT32 ClipboardGetFormatId(wClipboard* clipboard, const char* name) { wClipboardFormat* format; + if (!clipboard) + return 0; + format = ClipboardFindFormat(clipboard, 0, name); if (!format) @@ -353,6 +389,9 @@ UINT32 ClipboardGetFormatId(wClipboard* clipboard, const char* name) const char* ClipboardGetFormatName(wClipboard* clipboard, UINT32 formatId) { wClipboardFormat* format; + + if (!clipboard) + return NULL; format = ClipboardFindFormat(clipboard, formatId, NULL); @@ -370,6 +409,9 @@ void* ClipboardGetData(wClipboard* clipboard, UINT32 formatId, UINT32* pSize) void* pDstData = NULL; wClipboardFormat* format; wClipboardSynthesizer* synthesizer; + + if (!clipboard) + return NULL; if (!pSize) return NULL; @@ -413,6 +455,9 @@ void* ClipboardGetData(wClipboard* clipboard, UINT32 formatId, UINT32* pSize) BOOL ClipboardSetData(wClipboard* clipboard, UINT32 formatId, const void* data, UINT32 size) { wClipboardFormat* format; + + if (!clipboard) + return FALSE; format = ClipboardFindFormat(clipboard, formatId, NULL); @@ -431,11 +476,17 @@ BOOL ClipboardSetData(wClipboard* clipboard, UINT32 formatId, const void* data, UINT64 ClipboardGetOwner(wClipboard* clipboard) { + if (!clipboard) + return 0; + return clipboard->ownerId; } void ClipboardSetOwner(wClipboard* clipboard, UINT64 ownerId) { + if (!clipboard) + return; + clipboard->ownerId = ownerId; } diff --git a/winpr/libwinpr/thread/thread.c b/winpr/libwinpr/thread/thread.c index aeae97aa5..7ff53214d 100644 --- a/winpr/libwinpr/thread/thread.c +++ b/winpr/libwinpr/thread/thread.c @@ -83,6 +83,7 @@ #include #include +#include #include @@ -95,14 +96,14 @@ static pthread_once_t thread_initialized = PTHREAD_ONCE_INIT; static HANDLE_CLOSE_CB _ThreadHandleCloseCb; -static wListDictionary *thread_list = NULL; +static wListDictionary* thread_list = NULL; static BOOL ThreadCloseHandle(HANDLE handle); -static void cleanup_handle(void *obj); +static void cleanup_handle(void* obj); static BOOL ThreadIsHandled(HANDLE handle) { - WINPR_THREAD *pThread = (WINPR_THREAD *)handle; + WINPR_THREAD* pThread = (WINPR_THREAD*) handle; if (!pThread || pThread->Type != HANDLE_TYPE_THREAD) { @@ -113,7 +114,6 @@ static BOOL ThreadIsHandled(HANDLE handle) return TRUE; } - static void ThreadInitialize(void) { _ThreadHandleCloseCb.IsHandled = ThreadIsHandled; @@ -130,7 +130,7 @@ static void dump_thread(WINPR_THREAD* thread) WLog_DBG(TAG, "Called from:"); msg = winpr_backtrace_symbols(stack, &used); - for (i=0; icreate_stack, &used); - for (i=0; istarted) + { WLog_DBG(TAG, "Thread still running!"); + } else if (!thread->exit_stack) + { WLog_DBG(TAG, "Thread suspended."); + } else { WLog_DBG(TAG, "Thread exited at:"); msg = winpr_backtrace_symbols(thread->exit_stack, &used); - for (i=0; ipipe_fd[1], "-", 1); @@ -192,7 +194,6 @@ static BOOL set_event(WINPR_THREAD *thread) { status = TRUE; } - #endif return status; } @@ -223,22 +224,22 @@ static BOOL reset_event(WINPR_THREAD *thread) return status; } -static int thread_compare(void *a, void *b) +static BOOL thread_compare(void* a, void* b) { - pthread_t *p1 = a; - pthread_t *p2 = b; - int rc = pthread_equal(*p1, *p2); + pthread_t* p1 = a; + pthread_t* p2 = b; + BOOL rc = pthread_equal(*p1, *p2); return rc; } /* Thread launcher function responsible for registering * cleanup handlers and calling pthread_exit, if not done * in thread function. */ -static void *thread_launcher(void *arg) +static void* thread_launcher(void* arg) { DWORD res = -1; - void *rc = NULL; - WINPR_THREAD *thread = (WINPR_THREAD *)arg; + void* rc = NULL; + WINPR_THREAD* thread = (WINPR_THREAD*) arg; if (!thread) { @@ -247,7 +248,7 @@ static void *thread_launcher(void *arg) } else { - void *(*fkt)(void *) = (void *)thread->lpStartAddress; + void *(*fkt)(void*) = (void*) thread->lpStartAddress; if (!fkt) { @@ -295,9 +296,10 @@ static void winpr_StartThread(WINPR_THREAD *thread) HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId) { + int flags; HANDLE handle; - WINPR_THREAD *thread; - thread = (WINPR_THREAD *) calloc(1, sizeof(WINPR_THREAD)); + WINPR_THREAD* thread; + thread = (WINPR_THREAD*) calloc(1, sizeof(WINPR_THREAD)); if (!thread) return NULL; @@ -307,10 +309,12 @@ HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize thread->lpParameter = lpParameter; thread->lpStartAddress = lpStartAddress; thread->lpThreadAttributes = lpThreadAttributes; + #if defined(WITH_DEBUG_THREADS) thread->create_stack = winpr_backtrace(20); dump_thread(thread); #endif + #ifdef HAVE_EVENTFD_H thread->pipe_fd[0] = eventfd(0, EFD_NONBLOCK); @@ -320,22 +324,23 @@ HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize free(thread); return NULL; } - #else - if (pipe(thread->pipe_fd) < 0) { WLog_ERR(TAG, "failed to create thread"); free(thread); return NULL; } - + + flags = fcntl(thread->pipe_fd[0], F_GETFL); + fcntl(thread->pipe_fd[0], F_SETFL, flags | O_NONBLOCK); #endif + pthread_mutex_init(&thread->mutex, 0); WINPR_HANDLE_SET_TYPE(thread, HANDLE_TYPE_THREAD); handle = (HANDLE) thread; - if (NULL == thread_list) + if (!thread_list) { thread_list = ListDictionary_New(TRUE); thread_list->objectKey.fnObjectEquals = thread_compare; @@ -351,7 +356,7 @@ HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize void cleanup_handle(void *obj) { - WINPR_THREAD *thread = (WINPR_THREAD *)obj; + WINPR_THREAD* thread = (WINPR_THREAD*) obj; int rc = pthread_mutex_destroy(&thread->mutex); if (rc) @@ -381,7 +386,7 @@ void cleanup_handle(void *obj) BOOL ThreadCloseHandle(HANDLE handle) { - WINPR_THREAD *thread = (WINPR_THREAD *)handle; + WINPR_THREAD* thread = (WINPR_THREAD*) handle; if (!thread_list) { @@ -405,7 +410,9 @@ BOOL ThreadCloseHandle(HANDLE handle) pthread_detach(thread->thread); } else + { cleanup_handle(thread); + } ListDictionary_Unlock(thread_list); @@ -475,12 +482,12 @@ BOOL GetExitCodeThread(HANDLE hThread, LPDWORD lpExitCode) { ULONG Type; PVOID Object; - WINPR_THREAD *thread; + WINPR_THREAD* thread; if (!winpr_Handle_GetInfo(hThread, &Type, &Object)) return FALSE; - thread = (WINPR_THREAD *) Object; + thread = (WINPR_THREAD*) Object; *lpExitCode = thread->dwExitCode; return TRUE; } @@ -490,7 +497,7 @@ HANDLE _GetCurrentThread(VOID) HANDLE hdl = NULL; pthread_t tid = pthread_self(); - if (NULL == thread_list) + if (!thread_list) { WLog_ERR(TAG, "function called without existing thread list!"); #if defined(WITH_DEBUG_THREADS) @@ -528,7 +535,7 @@ DWORD ResumeThread(HANDLE hThread) if (!winpr_Handle_GetInfo(hThread, &Type, &Object)) return 0; - thread = (WINPR_THREAD *) Object; + thread = (WINPR_THREAD*) Object; pthread_mutex_lock(&thread->mutex); if (!thread->started) @@ -555,12 +562,12 @@ BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode) { ULONG Type; PVOID Object; - WINPR_THREAD *thread; + WINPR_THREAD* thread; if (!winpr_Handle_GetInfo(hThread, &Type, &Object)) return 0; - thread = (WINPR_THREAD *) Object; + thread = (WINPR_THREAD*) Object; thread->exited = TRUE; thread->dwExitCode = dwExitCode; pthread_mutex_lock(&thread->mutex); @@ -582,15 +589,19 @@ VOID DumpThreadHandles(void) WLog_DBG(TAG, "---------------- Called from ----------------------------"); msg = winpr_backtrace_symbols(stack, &used); - for (i=0; icreate_stack, &used); - for (i=0; istarted) + { WLog_DBG(TAG, "Thread [%d] still running!", x); + } else { WLog_DBG(TAG, "Thread [%d] exited at:", x);