diff --git a/channels/rdpgfx/server/CMakeLists.txt b/channels/rdpgfx/server/CMakeLists.txt index b4aadc24f..1b1f48b20 100644 --- a/channels/rdpgfx/server/CMakeLists.txt +++ b/channels/rdpgfx/server/CMakeLists.txt @@ -1,7 +1,7 @@ # FreeRDP: A Remote Desktop Protocol Implementation # FreeRDP cmake build script # -# Copyright 2012 Marc-Andre Moreau +# Copyright 2016 Jiang Zihao # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/channels/rdpgfx/server/rdpgfx_main.c b/channels/rdpgfx/server/rdpgfx_main.c index ee3126290..547b41758 100644 --- a/channels/rdpgfx/server/rdpgfx_main.c +++ b/channels/rdpgfx/server/rdpgfx_main.c @@ -42,46 +42,52 @@ /** * Function description - * Create new stream for rdpgfx packet. The new stream length - * would be required data length + header. The header will be written - * to the stream before return, but the pduLength field might be - * changed in rdpgfx_server_packet_send. + * Calculate packet size from data length. + * It would be data length + header. + * + * @param dataLen estimated data length without header * * @return new stream */ -static wStream* rdpgfx_server_packet_new(UINT16 cmdId, UINT32 dataLen) +static INLINE UINT32 rdpgfx_pdu_length(UINT32 dataLen) +{ + return RDPGFX_HEADER_SIZE + dataLen; +} + +static INLINE UINT rdpgfx_server_packet_init_header(wStream* s, UINT16 cmdId, UINT32 pduLength) { - UINT error; - wStream* s; RDPGFX_HEADER header; header.flags = 0; header.cmdId = cmdId; - header.pduLength = RDPGFX_HEADER_SIZE + dataLen; + header.pduLength = pduLength; - s = Stream_New(NULL, header.pduLength); - - if(!s) - { - WLog_ERR(TAG, "Stream_New failed!"); - return NULL; - } - - /* Write header. Note that actual length will be filled + /* Write header. Note that actual length might be changed * after the entire packet has been constructed. */ - if ((error = rdpgfx_write_header(s, &header))) - { - WLog_ERR(TAG, "rdpgfx_write_header failed with error %lu!", error); - return NULL; - } - - return s; + return rdpgfx_write_header(s, &header); } /** * Function description - * Send the stream for rdpgfx packet. The packet would be compressed - * according to [MS-RDPEGFX]. + * Complete the rdpgfx packet header. + * + * @param s stream + * @param start saved start pos of the packet in the stream + */ +static INLINE void rdpgfx_server_packet_complete_header(wStream* s, size_t start) +{ + size_t current = Stream_GetPosition(s); + + /* Fill actual length */ + Stream_SetPosition(s, start + RDPGFX_HEADER_SIZE - sizeof(UINT32)); + Stream_Write_UINT32(s, current - start); /* pduLength (4 bytes) */ + Stream_SetPosition(s, current); +} + +/** + * Function description + * Send the stream for rdpgfx server packet. + * The packet would be compressed according to [MS-RDPEGFX]. * * @return 0 on success, otherwise a Win32 error code */ @@ -94,16 +100,19 @@ static UINT rdpgfx_server_packet_send(RdpgfxServerContext* context, wStream* s) UINT32 SrcSize = Stream_GetPosition(s); wStream* fs; - /* Fill actual length */ - Stream_SetPosition(s, sizeof(RDPGFX_HEADER) - sizeof(UINT32)); - Stream_Write_UINT32(s, SrcSize); /* pduLength (4 bytes) */ - /* Allocate new stream with enough capacity. Additional overhead is * descriptor (1 bytes) + segmentCount (2 bytes) + uncompressedSize (4 bytes) * + segmentCount * size (4 bytes) */ fs = Stream_New(NULL, SrcSize + 7 + (SrcSize/ZGFX_SEGMENTED_MAXSIZE + 1) * 4); + if(!fs) + { + WLog_ERR(TAG, "Stream_New failed!"); + error = CHANNEL_RC_NO_MEMORY; + goto out; + } + if (zgfx_compress_to_stream(context->priv->zgfx, fs, pSrcData, SrcSize, &flags) < 0) { WLog_ERR(TAG, "zgfx_compress_to_stream failed!"); @@ -111,9 +120,22 @@ static UINT rdpgfx_server_packet_send(RdpgfxServerContext* context, wStream* s) goto out; } - error = WTSVirtualChannelWrite(context->priv->rdpgfx_channel, (PCHAR) Stream_Buffer(fs), - Stream_GetPosition(fs), &written) - ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; + if (!WTSVirtualChannelWrite(context->priv->rdpgfx_channel, + (PCHAR) Stream_Buffer(fs), + Stream_GetPosition(fs), &written)) + { + WLog_ERR(TAG, "WTSVirtualChannelWrite failed!"); + error = ERROR_INTERNAL_ERROR; + goto out; + } + + if (written < Stream_GetPosition(fs)) + { + WLog_WARN(TAG, "Unexpected bytes written: %lu/%lu", + written, Stream_GetPosition(fs)); + } + + error = CHANNEL_RC_OK; out: Stream_Free(fs, TRUE); @@ -122,6 +144,62 @@ out: return error; } +/** + * Function description + * Create new stream for single rdpgfx packet. The new stream length + * would be required data length + header. The header will be written + * to the stream before return, but the pduLength field might be + * changed in rdpgfx_server_single_packet_send. + * + * @param cmdId + * @param dataLen estimated data length without header + * + * @return new stream + */ +static wStream* rdpgfx_server_single_packet_new(UINT16 cmdId, UINT32 dataLen) +{ + UINT error; + wStream* s; + UINT32 pduLength = rdpgfx_pdu_length(dataLen); + + s = Stream_New(NULL, pduLength); + + if(!s) + { + WLog_ERR(TAG, "Stream_New failed!"); + goto error; + } + + if ((error = rdpgfx_server_packet_init_header(s, cmdId, pduLength))) + { + WLog_ERR(TAG, "Failed to init header with error %lu!", error); + goto error; + } + + return s; + +error: + Stream_Free(s, TRUE); + + return NULL; +} + +/** + * Function description + * Send the stream for single rdpgfx packet. + * The header will be filled with actual length. + * The packet would be compressed according to [MS-RDPEGFX]. + * + * @return 0 on success, otherwise a Win32 error code + */ +static INLINE UINT rdpgfx_server_single_packet_send(RdpgfxServerContext* context, wStream* s) +{ + /* Fill actual length */ + rdpgfx_server_packet_complete_header(s, 0); + + return rdpgfx_server_packet_send(context, s); +} + /** * Function description * @@ -130,13 +208,13 @@ out: static UINT rdpgfx_send_caps_confirm_pdu(RdpgfxServerContext* context, RDPGFX_CAPS_CONFIRM_PDU* capsConfirm) { RDPGFX_CAPSET* capsSet = capsConfirm->capsSet; - wStream* s = rdpgfx_server_packet_new( + wStream* s = rdpgfx_server_single_packet_new( RDPGFX_CMDID_CAPSCONFIRM, sizeof(RDPGFX_CAPSET) + sizeof(capsSet->flags)); if (!s) { - WLog_ERR(TAG, "rdpgfx_server_packet_new failed!"); + WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!"); return CHANNEL_RC_NO_MEMORY; } @@ -144,7 +222,7 @@ static UINT rdpgfx_send_caps_confirm_pdu(RdpgfxServerContext* context, RDPGFX_CA Stream_Write_UINT32(s, sizeof(capsSet->flags)); /* capsDataLength (4 bytes) */ Stream_Write_UINT32(s, capsSet->flags); /* capsData (4 bytes) */ - return rdpgfx_server_packet_send(context, s); + return rdpgfx_server_single_packet_send(context, s); } /** @@ -156,13 +234,23 @@ static UINT rdpgfx_send_reset_graphics_pdu(RdpgfxServerContext* context, RDPGFX_ { UINT32 index; MONITOR_DEF* monitor; - wStream* s = rdpgfx_server_packet_new( - RDPGFX_CMDID_RESETGRAPHICS, - RDPGFX_RESET_GRAPHICS_PDU_SIZE - RDPGFX_HEADER_SIZE); + wStream* s; + + /* Check monitorCount. This ensures total size within 340 bytes) */ + if (pdu->monitorCount >= 16) + { + WLog_ERR(TAG, "Monitor count MUST be less than or equal to 16: %lu", + pdu->monitorCount); + return ERROR_INVALID_DATA; + } + + s = rdpgfx_server_single_packet_new( + RDPGFX_CMDID_RESETGRAPHICS, + RDPGFX_RESET_GRAPHICS_PDU_SIZE - RDPGFX_HEADER_SIZE); if (!s) { - WLog_ERR(TAG, "rdpgfx_server_packet_new failed!"); + WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!"); return CHANNEL_RC_NO_MEMORY; } @@ -181,14 +269,9 @@ static UINT rdpgfx_send_reset_graphics_pdu(RdpgfxServerContext* context, RDPGFX_ } /* pad (total size must be 340 bytes) */ - if (Stream_GetPosition(s) > RDPGFX_RESET_GRAPHICS_PDU_SIZE) - { - WLog_ERR(TAG, "Invalid RDPGFX_RESET_GRAPHICS_PDU data!"); - return CHANNEL_RC_NO_BUFFER; - } Stream_SetPosition(s, RDPGFX_RESET_GRAPHICS_PDU_SIZE); - return rdpgfx_server_packet_send(context, s); + return rdpgfx_server_single_packet_send(context, s); } /** @@ -198,19 +281,19 @@ static UINT rdpgfx_send_reset_graphics_pdu(RdpgfxServerContext* context, RDPGFX_ */ static UINT rdpgfx_send_evict_cache_entry_pdu(RdpgfxServerContext* context, RDPGFX_EVICT_CACHE_ENTRY_PDU* pdu) { - wStream* s = rdpgfx_server_packet_new( + wStream* s = rdpgfx_server_single_packet_new( RDPGFX_CMDID_EVICTCACHEENTRY, sizeof(RDPGFX_EVICT_CACHE_ENTRY_PDU)); if (!s) { - WLog_ERR(TAG, "rdpgfx_server_packet_new failed!"); + WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!"); return CHANNEL_RC_NO_MEMORY; } Stream_Write_UINT16(s, pdu->cacheSlot); /* cacheSlot (2 bytes) */ - return rdpgfx_server_packet_send(context, s); + return rdpgfx_server_single_packet_send(context, s); } /** @@ -221,13 +304,13 @@ static UINT rdpgfx_send_evict_cache_entry_pdu(RdpgfxServerContext* context, RDPG static UINT rdpgfx_send_cache_import_reply_pdu(RdpgfxServerContext* context, RDPGFX_CACHE_IMPORT_REPLY_PDU* pdu) { UINT16 index; - wStream* s = rdpgfx_server_packet_new( + wStream* s = rdpgfx_server_single_packet_new( RDPGFX_CMDID_CACHEIMPORTREPLY, sizeof(RDPGFX_CACHE_IMPORT_REPLY_PDU) + sizeof(UINT16) * pdu->importedEntriesCount); if (!s) { - WLog_ERR(TAG, "rdpgfx_server_packet_new failed!"); + WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!"); return CHANNEL_RC_NO_MEMORY; } @@ -237,7 +320,7 @@ static UINT rdpgfx_send_cache_import_reply_pdu(RdpgfxServerContext* context, RDP Stream_Write_UINT16(s, pdu->cacheSlots[index]); /* cacheSlot (2 bytes) */ } - return rdpgfx_server_packet_send(context, s); + return rdpgfx_server_single_packet_send(context, s); } /** @@ -247,13 +330,13 @@ static UINT rdpgfx_send_cache_import_reply_pdu(RdpgfxServerContext* context, RDP */ static UINT rdpgfx_send_create_surface_pdu(RdpgfxServerContext* context, RDPGFX_CREATE_SURFACE_PDU* pdu) { - wStream* s = rdpgfx_server_packet_new( + wStream* s = rdpgfx_server_single_packet_new( RDPGFX_CMDID_CREATESURFACE, sizeof(RDPGFX_CREATE_SURFACE_PDU)); if (!s) { - WLog_ERR(TAG, "rdpgfx_server_packet_new failed!"); + WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!"); return CHANNEL_RC_NO_MEMORY; } @@ -262,7 +345,7 @@ static UINT rdpgfx_send_create_surface_pdu(RdpgfxServerContext* context, RDPGFX_ Stream_Write_UINT16(s, pdu->height); /* height (2 bytes) */ Stream_Write_UINT8(s, pdu->pixelFormat); /* RDPGFX_PIXELFORMAT (1 byte) */ - return rdpgfx_server_packet_send(context, s); + return rdpgfx_server_single_packet_send(context, s); } /** @@ -272,19 +355,30 @@ static UINT rdpgfx_send_create_surface_pdu(RdpgfxServerContext* context, RDPGFX_ */ UINT rdpgfx_send_delete_surface_pdu(RdpgfxServerContext* context, RDPGFX_DELETE_SURFACE_PDU* pdu) { - wStream* s = rdpgfx_server_packet_new( + wStream* s = rdpgfx_server_single_packet_new( RDPGFX_CMDID_DELETESURFACE, sizeof(RDPGFX_DELETE_SURFACE_PDU)); if (!s) { - WLog_ERR(TAG, "rdpgfx_server_packet_new failed!"); + WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!"); return CHANNEL_RC_NO_MEMORY; } Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */ - return rdpgfx_server_packet_send(context, s); + return rdpgfx_server_single_packet_send(context, s); +} + +static INLINE void rdpgfx_write_start_frame_pdu(wStream* s, RDPGFX_START_FRAME_PDU* pdu) +{ + Stream_Write_UINT32(s, pdu->timestamp); /* timestamp (4 bytes) */ + Stream_Write_UINT32(s, pdu->frameId); /* frameId (4 bytes) */ +} + +static INLINE void rdpgfx_write_end_frame_pdu(wStream* s, RDPGFX_END_FRAME_PDU* pdu) +{ + Stream_Write_UINT32(s, pdu->frameId); /* frameId (4 bytes) */ } /** @@ -294,20 +388,19 @@ UINT rdpgfx_send_delete_surface_pdu(RdpgfxServerContext* context, RDPGFX_DELETE_ */ static UINT rdpgfx_send_start_frame_pdu(RdpgfxServerContext* context, RDPGFX_START_FRAME_PDU* pdu) { - wStream* s = rdpgfx_server_packet_new( + wStream* s = rdpgfx_server_single_packet_new( RDPGFX_CMDID_STARTFRAME, sizeof(RDPGFX_START_FRAME_PDU)); if (!s) { - WLog_ERR(TAG, "rdpgfx_server_packet_new failed!"); + WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!"); return CHANNEL_RC_NO_MEMORY; } - Stream_Write_UINT32(s, pdu->timestamp); /* timestamp (4 bytes) */ - Stream_Write_UINT32(s, pdu->frameId); /* frameId (4 bytes) */ + rdpgfx_write_start_frame_pdu(s, pdu); - return rdpgfx_server_packet_send(context, s); + return rdpgfx_server_single_packet_send(context, s); } /** @@ -317,19 +410,100 @@ static UINT rdpgfx_send_start_frame_pdu(RdpgfxServerContext* context, RDPGFX_STA */ static UINT rdpgfx_send_end_frame_pdu(RdpgfxServerContext* context, RDPGFX_END_FRAME_PDU* pdu) { - wStream* s = rdpgfx_server_packet_new( + wStream* s = rdpgfx_server_single_packet_new( RDPGFX_CMDID_ENDFRAME, sizeof(RDPGFX_END_FRAME_PDU)); if (!s) { - WLog_ERR(TAG, "rdpgfx_server_packet_new failed!"); + WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!"); return CHANNEL_RC_NO_MEMORY; } - Stream_Write_UINT32(s, pdu->frameId); /* frameId (4 bytes) */ + rdpgfx_write_end_frame_pdu(s, pdu); - return rdpgfx_server_packet_send(context, s); + return rdpgfx_server_single_packet_send(context, s); +} + +/** + * Function description + * Estimate RFX_AVC420_BITMAP_STREAM structure size in stream + * + * @return estimated size + */ +static INLINE UINT32 rdpgfx_estimate_h264_avc420(RDPGFX_AVC420_BITMAP_STREAM *havc420) +{ + return sizeof(UINT32) /* numRegionRects */ + + (sizeof(RECTANGLE_16) + 2) /* regionRects + quantQualityVals */ + * havc420->meta.numRegionRects + + havc420->length; +} + +/** + * Function description + * Estimate surface command packet size in stream without header + * + * @return estimated size + */ +static INLINE UINT32 rdpgfx_estimate_surface_command(RDPGFX_SURFACE_COMMAND* cmd) +{ + RDPGFX_AVC420_BITMAP_STREAM *havc420 = NULL; + RDPGFX_AVC444_BITMAP_STREAM *havc444 = NULL; + UINT32 h264Size = 0; + + /* Create new stream according to codec. */ + if (cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE || + cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE_V2) + { + return sizeof(RDPGFX_WIRE_TO_SURFACE_PDU_2) + cmd->length; + } + else if (cmd->codecId == RDPGFX_CODECID_AVC420) + { + havc420 = (RDPGFX_AVC420_BITMAP_STREAM *)cmd->extra; + h264Size = rdpgfx_estimate_h264_avc420(havc420); + + return sizeof(RDPGFX_WIRE_TO_SURFACE_PDU_1) + h264Size; + } + else if (cmd->codecId == RDPGFX_CODECID_AVC444) + { + havc444 = (RDPGFX_AVC444_BITMAP_STREAM *)cmd->extra; + h264Size = sizeof(UINT32); /* cbAvc420EncodedBitstream1 */ + + /* avc420EncodedBitstream1 */ + havc420 = &(havc444->bitstream[0]); + h264Size += rdpgfx_estimate_h264_avc420(havc420); + + /* avc420EncodedBitstream2 */ + if (havc444->LC == 0) + { + havc420 = &(havc444->bitstream[1]); + h264Size += rdpgfx_estimate_h264_avc420(havc420); + } + + return sizeof(RDPGFX_WIRE_TO_SURFACE_PDU_1) + h264Size; + } + else + { + return sizeof(RDPGFX_WIRE_TO_SURFACE_PDU_1) + cmd->length; + } +} + +/** + * Function description + * Resolve RDPGFX_CMDID_WIRETOSURFACE_1 or RDPGFX_CMDID_WIRETOSURFACE_2 + * according to codecId + * + * @return 0 on success, otherwise a Win32 error code + */ +static INLINE UINT16 rdpgfx_surface_command_cmdid(RDPGFX_SURFACE_COMMAND* cmd) +{ + if (cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE || + cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE_V2) + { + return RDPGFX_CMDID_WIRETOSURFACE_2; + } + + return RDPGFX_CMDID_WIRETOSURFACE_1; } /** @@ -337,8 +511,7 @@ static UINT rdpgfx_send_end_frame_pdu(RdpgfxServerContext* context, RDPGFX_END_F * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_write_h264_metablock(RdpgfxServerContext* context, wStream* s, - RDPGFX_H264_METABLOCK* meta) +static UINT rdpgfx_write_h264_metablock(wStream* s, RDPGFX_H264_METABLOCK* meta) { UINT32 index; RECTANGLE_16* regionRect; @@ -362,8 +535,8 @@ static UINT rdpgfx_write_h264_metablock(RdpgfxServerContext* context, wStream* s quantQualityVal = &(meta->quantQualityVals[index]); Stream_Write_UINT8(s, quantQualityVal->qp - | (quantQualityVal->r << 6) - | (quantQualityVal->p << 7)); /* qpVal (1 byte) */ + | (quantQualityVal->r << 6) + | (quantQualityVal->p << 7)); /* qpVal (1 byte) */ Stream_Write_UINT8(s, quantQualityVal->qualityVal); /* qualityVal (1 byte) */ } @@ -376,11 +549,10 @@ static UINT rdpgfx_write_h264_metablock(RdpgfxServerContext* context, wStream* s * * @return 0 on success, otherwise a Win32 error code */ -static INLINE UINT rdpgfx_write_h264_avc420(RdpgfxServerContext* context, wStream* s, - RDPGFX_AVC420_BITMAP_STREAM* havc420) +static INLINE UINT rdpgfx_write_h264_avc420(wStream* s, RDPGFX_AVC420_BITMAP_STREAM* havc420) { UINT error = CHANNEL_RC_OK; - if ((error = rdpgfx_write_h264_metablock(context, s, &(havc420->meta)))) + if ((error = rdpgfx_write_h264_metablock(s, &(havc420->meta)))) { WLog_ERR(TAG, "rdpgfx_write_h264_metablock failed with error %lu!", error); return error; @@ -392,87 +564,24 @@ static INLINE UINT rdpgfx_write_h264_avc420(RdpgfxServerContext* context, wStrea /** * Function description - * Estimate RFX_AVC420_BITMAP_STREAM structure size in stream - * - * @return estimated size - */ -static INLINE UINT32 rdpgfx_estimate_h264_avc420(RDPGFX_AVC420_BITMAP_STREAM* havc420) -{ - return sizeof(UINT32) /* numRegionRects */ - + (sizeof(RECTANGLE_16) + 2) /* regionRects + quantQualityVals */ - * havc420->meta.numRegionRects - + havc420->length; -} -/** - * Function description - * Send RDPGFX_CMDID_WIRETOSURFACE_1 or RDPGFX_CMDID_WIRETOSURFACE_2 - * message according to codecId + * Write RDPGFX_CMDID_WIRETOSURFACE_1 or RDPGFX_CMDID_WIRETOSURFACE_2 + * to the stream according to RDPGFX_SURFACE_COMMAND message * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_send_surface_command(RdpgfxServerContext* context, RDPGFX_SURFACE_COMMAND* cmd) +static UINT rdpgfx_write_surface_command(wStream* s, RDPGFX_SURFACE_COMMAND* cmd) { - wStream* s; + UINT error = CHANNEL_RC_OK; RDPGFX_AVC420_BITMAP_STREAM *havc420 = NULL; RDPGFX_AVC444_BITMAP_STREAM *havc444 = NULL; - UINT32 h264Size = 0; UINT32 bitmapDataStart = 0; UINT32 bitmapDataLength = 0; - /* Create new stream according to codec. */ - if (cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE || - cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE_V2) - { - s = rdpgfx_server_packet_new( - RDPGFX_CMDID_WIRETOSURFACE_2, - sizeof(RDPGFX_WIRE_TO_SURFACE_PDU_2) + cmd->length); - } - else if (cmd->codecId == RDPGFX_CODECID_AVC420) - { - havc420 = (RDPGFX_AVC420_BITMAP_STREAM *)cmd->extra; - h264Size = rdpgfx_estimate_h264_avc420(havc420); - - s = rdpgfx_server_packet_new( - RDPGFX_CMDID_WIRETOSURFACE_1, - sizeof(RDPGFX_WIRE_TO_SURFACE_PDU_1) + h264Size); - } - else if (cmd->codecId == RDPGFX_CODECID_AVC444) - { - havc444 = (RDPGFX_AVC444_BITMAP_STREAM *)cmd->extra; - h264Size = sizeof(UINT32); /* cbAvc420EncodedBitstream1 */ - - /* avc420EncodedBitstream1 */ - havc420 = &(havc444->bitstream[0]); - h264Size += rdpgfx_estimate_h264_avc420(havc420); - - /* avc420EncodedBitstream2 */ - if (havc444->LC == 0) - { - havc420 = &(havc444->bitstream[1]); - h264Size += rdpgfx_estimate_h264_avc420(havc420); - } - - s = rdpgfx_server_packet_new( - RDPGFX_CMDID_WIRETOSURFACE_1, - sizeof(RDPGFX_WIRE_TO_SURFACE_PDU_1) + h264Size); - } - else - { - s = rdpgfx_server_packet_new( - RDPGFX_CMDID_WIRETOSURFACE_1, - sizeof(RDPGFX_WIRE_TO_SURFACE_PDU_1) + sizeof(cmd->length)); - } - - if (!s) - { - WLog_ERR(TAG, "rdpgfx_server_packet_new failed!"); - return CHANNEL_RC_NO_MEMORY; - } - - /* Reformat and send */ if (cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE || cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE_V2) { + /* Write RDPGFX_CMDID_WIRETOSURFACE_2 format for CAPROGRESSIVE */ + Stream_Write_UINT16(s, cmd->surfaceId); /* surfaceId (2 bytes) */ Stream_Write_UINT16(s, cmd->codecId); /* codecId (2 bytes) */ Stream_Write_UINT32(s, cmd->contextId); /* codecContextId (4 bytes) */ @@ -480,11 +589,11 @@ static UINT rdpgfx_send_surface_command(RdpgfxServerContext* context, RDPGFX_SUR Stream_Write_UINT32(s, cmd->length); /* bitmapDataLength (4 bytes) */ Stream_Write(s, cmd->data, cmd->length); - - return rdpgfx_server_packet_send(context, s); } else { + /* Write RDPGFX_CMDID_WIRETOSURFACE_1 format for others */ + Stream_Write_UINT16(s, cmd->surfaceId); /* surfaceId (2 bytes) */ Stream_Write_UINT16(s, cmd->codecId); /* codecId (2 bytes) */ Stream_Write_UINT8(s, cmd->format); /* pixelFormat (1 byte) */ @@ -500,7 +609,12 @@ static UINT rdpgfx_send_surface_command(RdpgfxServerContext* context, RDPGFX_SUR if (cmd->codecId == RDPGFX_CODECID_AVC420) { havc420 = (RDPGFX_AVC420_BITMAP_STREAM *)cmd->extra; - rdpgfx_write_h264_avc420(context, s, havc420); + error = rdpgfx_write_h264_avc420(s, havc420); + if (error != CHANNEL_RC_OK) + { + WLog_ERR(TAG, "rdpgfx_write_h264_avc420 failed!"); + return error; + } } else if (cmd->codecId == RDPGFX_CODECID_AVC444) { @@ -511,13 +625,23 @@ static UINT rdpgfx_send_surface_command(RdpgfxServerContext* context, RDPGFX_SUR Stream_Write_UINT32(s, havc420->length | (havc444->LC << 30UL)); /* avc420EncodedBitstream1 */ - rdpgfx_write_h264_avc420(context, s, havc420); + error = rdpgfx_write_h264_avc420(s, havc420); + if (error != CHANNEL_RC_OK) + { + WLog_ERR(TAG, "rdpgfx_write_h264_avc420 failed!"); + return error; + } /* avc420EncodedBitstream2 */ if (havc444->LC == 0) { havc420 = &(havc444->bitstream[0]); - rdpgfx_write_h264_avc420(context, s, havc420); + error = rdpgfx_write_h264_avc420(s, havc420); + if (error != CHANNEL_RC_OK) + { + WLog_ERR(TAG, "rdpgfx_write_h264_avc420 failed!"); + return error; + } } } else @@ -532,9 +656,141 @@ static UINT rdpgfx_send_surface_command(RdpgfxServerContext* context, RDPGFX_SUR Stream_SetPosition(s, bitmapDataStart - sizeof(UINT32)); Stream_Write_UINT32(s, bitmapDataLength); /* bitmapDataLength (4 bytes) */ Stream_Seek(s, bitmapDataLength); - - return rdpgfx_server_packet_send(context, s); } + + return error; +} + +/** + * Function description + * Send RDPGFX_CMDID_WIRETOSURFACE_1 or RDPGFX_CMDID_WIRETOSURFACE_2 + * message according to codecId + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpgfx_send_surface_command(RdpgfxServerContext* context, RDPGFX_SURFACE_COMMAND* cmd) +{ + UINT error = CHANNEL_RC_OK; + wStream* s; + + s = rdpgfx_server_single_packet_new( + rdpgfx_surface_command_cmdid(cmd), + rdpgfx_estimate_surface_command(cmd)); + + if (!s) + { + WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + error = rdpgfx_write_surface_command(s, cmd); + if (error != CHANNEL_RC_OK) + { + WLog_ERR(TAG, "rdpgfx_write_surface_command failed!"); + goto error; + } + + return rdpgfx_server_single_packet_send(context, s); + +error: + Stream_Free(s, TRUE); + + return error; +} + +/** + * Function description + * Send RDPGFX_CMDID_WIRETOSURFACE_1 or RDPGFX_CMDID_WIRETOSURFACE_2 + * message according to codecId. + * Prepend/append start/end frame message in same packet if exists. + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpgfx_send_surface_frame_command(RdpgfxServerContext* context, + RDPGFX_SURFACE_COMMAND* cmd, RDPGFX_START_FRAME_PDU* startFrame, + RDPGFX_END_FRAME_PDU* endFrame) + +{ + UINT error = CHANNEL_RC_OK; + wStream* s; + UINT32 position = 0; + UINT32 size = rdpgfx_pdu_length(rdpgfx_estimate_surface_command(cmd)); + + if (startFrame) + { + size += rdpgfx_pdu_length(sizeof(RDPGFX_START_FRAME_PDU)); + } + + if (endFrame) + { + size += rdpgfx_pdu_length(sizeof(RDPGFX_END_FRAME_PDU)); + } + + s = Stream_New(NULL, size); + + if(!s) + { + WLog_ERR(TAG, "Stream_New failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + /* Write start frame if exists */ + if (startFrame) + { + position = Stream_GetPosition(s); + error = rdpgfx_server_packet_init_header(s, + RDPGFX_CMDID_STARTFRAME, 0); + if (error != CHANNEL_RC_OK) + { + WLog_ERR(TAG, "Failed to init header with error %lu!", error); + goto error; + } + + rdpgfx_write_start_frame_pdu(s, startFrame); + rdpgfx_server_packet_complete_header(s, position); + } + + /* Write RDPGFX_CMDID_WIRETOSURFACE_1 or RDPGFX_CMDID_WIRETOSURFACE_2 */ + position = Stream_GetPosition(s); + error = rdpgfx_server_packet_init_header(s, + rdpgfx_surface_command_cmdid(cmd), + 0); // Actual length will be filled later + if (error != CHANNEL_RC_OK) + { + WLog_ERR(TAG, "Failed to init header with error %lu!", error); + goto error; + } + + error = rdpgfx_write_surface_command(s, cmd); + if (error != CHANNEL_RC_OK) + { + WLog_ERR(TAG, "rdpgfx_write_surface_command failed!"); + goto error; + } + rdpgfx_server_packet_complete_header(s, position); + + /* Write end frame if exists */ + if (endFrame) + { + position = Stream_GetPosition(s); + error = rdpgfx_server_packet_init_header(s, + RDPGFX_CMDID_ENDFRAME, 0); + if (error != CHANNEL_RC_OK) + { + WLog_ERR(TAG, "Failed to init header with error %lu!", error); + goto error; + } + + rdpgfx_write_end_frame_pdu(s, endFrame); + rdpgfx_server_packet_complete_header(s, position); + } + + return rdpgfx_server_packet_send(context, s); + +error: + Stream_Free(s, TRUE); + + return error; } /** @@ -544,20 +800,20 @@ static UINT rdpgfx_send_surface_command(RdpgfxServerContext* context, RDPGFX_SUR */ static UINT rdpgfx_send_delete_encoding_context_pdu(RdpgfxServerContext* context, RDPGFX_DELETE_ENCODING_CONTEXT_PDU* pdu) { - wStream* s = rdpgfx_server_packet_new( + wStream* s = rdpgfx_server_single_packet_new( RDPGFX_CMDID_DELETEENCODINGCONTEXT, sizeof(RDPGFX_DELETE_ENCODING_CONTEXT_PDU)); if (!s) { - WLog_ERR(TAG, "rdpgfx_server_packet_new failed!"); + WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!"); return CHANNEL_RC_NO_MEMORY; } Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */ Stream_Write_UINT32(s, pdu->codecContextId); /* codecContextId (4 bytes) */ - return rdpgfx_server_packet_send(context, s); + return rdpgfx_server_single_packet_send(context, s); } /** @@ -567,16 +823,16 @@ static UINT rdpgfx_send_delete_encoding_context_pdu(RdpgfxServerContext* context */ UINT rdpgfx_send_solid_fill_pdu(RdpgfxServerContext* context, RDPGFX_SOLID_FILL_PDU* pdu) { + UINT error = CHANNEL_RC_OK; UINT16 index; RECTANGLE_16* fillRect; - UINT error; - wStream* s = rdpgfx_server_packet_new( + wStream* s = rdpgfx_server_single_packet_new( RDPGFX_CMDID_SOLIDFILL, sizeof(RDPGFX_SOLID_FILL_PDU) + sizeof(RECTANGLE_16) * pdu->fillRectCount); if (!s) { - WLog_ERR(TAG, "rdpgfx_server_packet_new failed!"); + WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!"); return CHANNEL_RC_NO_MEMORY; } @@ -584,7 +840,7 @@ UINT rdpgfx_send_solid_fill_pdu(RdpgfxServerContext* context, RDPGFX_SOLID_FILL_ if ((error = rdpgfx_write_color32(s, &(pdu->fillPixel)))) /* fillPixel (4 bytes) */ { WLog_ERR(TAG, "rdpgfx_write_color32 failed with error %lu!", error); - return error; + goto error; } Stream_Write_UINT16(s, pdu->fillRectCount); /* fillRectCount (2 bytes) */ @@ -594,11 +850,16 @@ UINT rdpgfx_send_solid_fill_pdu(RdpgfxServerContext* context, RDPGFX_SOLID_FILL_ if ((error = rdpgfx_write_rect16(s, fillRect))) { WLog_ERR(TAG, "rdpgfx_write_rect16 failed with error %lu!", error); - return error; + goto error; } } - return rdpgfx_server_packet_send(context, s); + return rdpgfx_server_single_packet_send(context, s); + +error: + Stream_Free(s, TRUE); + + return error; } /** @@ -608,16 +869,16 @@ UINT rdpgfx_send_solid_fill_pdu(RdpgfxServerContext* context, RDPGFX_SOLID_FILL_ */ static UINT rdpgfx_send_surface_to_surface_pdu(RdpgfxServerContext* context, RDPGFX_SURFACE_TO_SURFACE_PDU* pdu) { + UINT error = CHANNEL_RC_OK; UINT16 index; - UINT error; RDPGFX_POINT16* destPt; - wStream* s = rdpgfx_server_packet_new( + wStream* s = rdpgfx_server_single_packet_new( RDPGFX_CMDID_SURFACETOSURFACE, sizeof(RDPGFX_SURFACE_TO_SURFACE_PDU) + sizeof(RDPGFX_POINT16) * pdu->destPtsCount); if (!s) { - WLog_ERR(TAG, "rdpgfx_server_packet_new failed!"); + WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!"); return CHANNEL_RC_NO_MEMORY; } @@ -627,7 +888,7 @@ static UINT rdpgfx_send_surface_to_surface_pdu(RdpgfxServerContext* context, RDP if ((error = rdpgfx_write_rect16(s, &(pdu->rectSrc)))) /* rectSrc (8 bytes ) */ { WLog_ERR(TAG, "rdpgfx_write_rect16 failed with error %lu!", error); - return error; + goto error; } Stream_Write_UINT16(s, pdu->destPtsCount); /* destPtsCount (2 bytes) */ @@ -637,11 +898,16 @@ static UINT rdpgfx_send_surface_to_surface_pdu(RdpgfxServerContext* context, RDP if ((error = rdpgfx_write_point16(s, destPt))) { WLog_ERR(TAG, "rdpgfx_write_point16 failed with error %lu!", error); - return error; + goto error; } } - return rdpgfx_server_packet_send(context, s); + return rdpgfx_server_single_packet_send(context, s); + +error: + Stream_Free(s, TRUE); + + return error; } /** @@ -651,14 +917,14 @@ static UINT rdpgfx_send_surface_to_surface_pdu(RdpgfxServerContext* context, RDP */ static UINT rdpgfx_send_surface_to_cache_pdu(RdpgfxServerContext* context, RDPGFX_SURFACE_TO_CACHE_PDU* pdu) { - UINT error; - wStream* s = rdpgfx_server_packet_new( + UINT error = CHANNEL_RC_OK; + wStream* s = rdpgfx_server_single_packet_new( RDPGFX_CMDID_SURFACETOCACHE, sizeof(RDPGFX_SURFACE_TO_CACHE_PDU)); if (!s) { - WLog_ERR(TAG, "rdpgfx_server_packet_new failed!"); + WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!"); return CHANNEL_RC_NO_MEMORY; } @@ -668,10 +934,15 @@ static UINT rdpgfx_send_surface_to_cache_pdu(RdpgfxServerContext* context, RDPGF if ((error = rdpgfx_write_rect16(s, &(pdu->rectSrc)))) /* rectSrc (8 bytes ) */ { WLog_ERR(TAG, "rdpgfx_write_rect16 failed with error %lu!", error); - return error; + goto error; } - return rdpgfx_server_packet_send(context, s); + return rdpgfx_server_single_packet_send(context, s); + +error: + Stream_Free(s, TRUE); + + return error; } /** @@ -681,16 +952,16 @@ static UINT rdpgfx_send_surface_to_cache_pdu(RdpgfxServerContext* context, RDPGF */ static UINT rdpgfx_send_cache_to_surface_pdu(RdpgfxServerContext* context, RDPGFX_CACHE_TO_SURFACE_PDU* pdu) { + UINT error = CHANNEL_RC_OK; UINT16 index; - UINT error; RDPGFX_POINT16* destPt; - wStream* s = rdpgfx_server_packet_new( + wStream* s = rdpgfx_server_single_packet_new( RDPGFX_CMDID_CACHETOSURFACE, sizeof(RDPGFX_CACHE_TO_SURFACE_PDU) + sizeof(RDPGFX_POINT16) * pdu->destPtsCount); if (!s) { - WLog_ERR(TAG, "rdpgfx_server_packet_new failed!"); + WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!"); return CHANNEL_RC_NO_MEMORY; } @@ -704,11 +975,16 @@ static UINT rdpgfx_send_cache_to_surface_pdu(RdpgfxServerContext* context, RDPGF if ((error = rdpgfx_write_point16(s, destPt))) { WLog_ERR(TAG, "rdpgfx_write_point16 failed with error %lu", error); - return error; + goto error; } } - return rdpgfx_server_packet_send(context, s); + return rdpgfx_server_single_packet_send(context, s); + +error: + Stream_Free(s, TRUE); + + return error; } /** @@ -718,13 +994,13 @@ static UINT rdpgfx_send_cache_to_surface_pdu(RdpgfxServerContext* context, RDPGF */ static UINT rdpgfx_send_map_surface_to_output_pdu(RdpgfxServerContext* context, RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU* pdu) { - wStream* s = rdpgfx_server_packet_new( + wStream* s = rdpgfx_server_single_packet_new( RDPGFX_CMDID_MAPSURFACETOOUTPUT, sizeof(RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU)); if (!s) { - WLog_ERR(TAG, "rdpgfx_server_packet_new failed!"); + WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!"); return CHANNEL_RC_NO_MEMORY; } @@ -733,7 +1009,7 @@ static UINT rdpgfx_send_map_surface_to_output_pdu(RdpgfxServerContext* context, Stream_Write_UINT32(s, pdu->outputOriginX); /* outputOriginX (4 bytes) */ Stream_Write_UINT32(s, pdu->outputOriginY); /* outputOriginY (4 bytes) */ - return rdpgfx_server_packet_send(context, s); + return rdpgfx_server_single_packet_send(context, s); } /** @@ -743,13 +1019,13 @@ static UINT rdpgfx_send_map_surface_to_output_pdu(RdpgfxServerContext* context, */ static UINT rdpgfx_send_map_surface_to_window_pdu(RdpgfxServerContext* context, RDPGFX_MAP_SURFACE_TO_WINDOW_PDU* pdu) { - wStream* s = rdpgfx_server_packet_new( + wStream* s = rdpgfx_server_single_packet_new( RDPGFX_CMDID_MAPSURFACETOWINDOW, sizeof(RDPGFX_MAP_SURFACE_TO_WINDOW_PDU)); if (!s) { - WLog_ERR(TAG, "rdpgfx_server_packet_new failed!"); + WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!"); return CHANNEL_RC_NO_MEMORY; } @@ -758,7 +1034,7 @@ static UINT rdpgfx_send_map_surface_to_window_pdu(RdpgfxServerContext* context, Stream_Write_UINT32(s, pdu->mappedWidth); /* mappedWidth (4 bytes) */ Stream_Write_UINT32(s, pdu->mappedHeight); /* mappedHeight (4 bytes) */ - return rdpgfx_server_packet_send(context, s); + return rdpgfx_server_single_packet_send(context, s); } /** @@ -771,6 +1047,12 @@ static UINT rdpgfx_recv_frame_acknowledge_pdu(RdpgfxServerContext* context, wStr RDPGFX_FRAME_ACKNOWLEDGE_PDU pdu; UINT error = CHANNEL_RC_OK; + if (Stream_GetRemainingLength(s) < sizeof(RDPGFX_FRAME_ACKNOWLEDGE_PDU)) + { + WLog_ERR(TAG, "not enough data!"); + return ERROR_INVALID_DATA; + } + Stream_Read_UINT32(s, pdu.queueDepth); /* queueDepth (4 bytes) */ Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */ Stream_Read_UINT32(s, pdu.totalFramesDecoded); /* totalFramesDecoded (4 bytes) */ @@ -797,9 +1079,30 @@ static UINT rdpgfx_recv_cache_import_offer_pdu(RdpgfxServerContext* context, wSt RDPGFX_CACHE_ENTRY_METADATA* cacheEntries; UINT error = CHANNEL_RC_OK; + if (Stream_GetRemainingLength(s) < sizeof(UINT16)) + { + WLog_ERR(TAG, "not enough data!"); + return ERROR_INVALID_DATA; + } + Stream_Read_UINT16(s, pdu.cacheEntriesCount); /* cacheEntriesCount (2 bytes) */ + if (pdu.cacheEntriesCount <= 0) + { + /* According to the latest spec, capsSetCount <= 3 */ + WLog_ERR(TAG, "Invalid cacheEntriesCount: %u", pdu.cacheEntriesCount); + return ERROR_INVALID_DATA; + } + + if (Stream_GetRemainingLength(s) < + (pdu.cacheEntriesCount * sizeof(RDPGFX_CACHE_ENTRY_METADATA))) + { + WLog_ERR(TAG, "not enough data!"); + return ERROR_INVALID_DATA; + } + pdu.cacheEntries = (RDPGFX_CACHE_ENTRY_METADATA*) - calloc(pdu.cacheEntriesCount, sizeof(RDPGFX_CACHE_ENTRY_METADATA)); + calloc(pdu.cacheEntriesCount, + sizeof(RDPGFX_CACHE_ENTRY_METADATA)); if (!pdu.cacheEntries) { @@ -838,15 +1141,41 @@ static UINT rdpgfx_recv_caps_advertise_pdu(RdpgfxServerContext* context, wStream RDPGFX_CAPSET capsSets[3]; RDPGFX_CAPS_ADVERTISE_PDU pdu; UINT error = CHANNEL_RC_OK; + UINT32 capsDataLength; + + if (Stream_GetRemainingLength(s) < sizeof(UINT16)) + { + WLog_ERR(TAG, "not enough data!"); + return ERROR_INVALID_DATA; + } Stream_Read_UINT16(s, pdu.capsSetCount); /* capsSetCount (2 bytes) */ + if (pdu.capsSetCount > 3) + { + /* According to the latest spec, capsSetCount <= 3 */ + WLog_ERR(TAG, "capsSetCount is greater than 3: %u", pdu.capsSetCount); + return ERROR_INVALID_DATA; + } + + if (Stream_GetRemainingLength(s) < + (pdu.capsSetCount * (sizeof(RDPGFX_CAPSET) + sizeof(UINT32)))) + { + WLog_ERR(TAG, "not enough data!"); + return ERROR_INVALID_DATA; + } + pdu.capsSets = (RDPGFX_CAPSET*) capsSets; for (index = 0; index < pdu.capsSetCount; index++) { capsSet = &(pdu.capsSets[index]); Stream_Read_UINT32(s, capsSet->version); /* version (4 bytes) */ - Stream_Seek(s, 4); /* capsDataLength (4 bytes) */ + Stream_Read_UINT32(s, capsDataLength); /* capsDataLength (4 bytes) */ + if (capsDataLength != 4) + { + WLog_ERR(TAG, "capsDataLength does not equal to 4: %lu", capsDataLength); + return ERROR_INVALID_DATA; + } Stream_Read_UINT32(s, capsSet->flags); /* capsData (4 bytes) */ } @@ -870,6 +1199,12 @@ static UINT rdpgfx_recv_qoe_frame_acknowledge_pdu(RdpgfxServerContext* context, RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU pdu; UINT error = CHANNEL_RC_OK; + if (Stream_GetRemainingLength(s) < sizeof(RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU)) + { + WLog_ERR(TAG, "not enough data!"); + return ERROR_INVALID_DATA; + } + Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */ Stream_Read_UINT32(s, pdu.timestamp); /* timestamp (4 bytes) */ Stream_Read_UINT16(s, pdu.timeDiffSE); /* timeDiffSE (2 bytes) */ @@ -1074,12 +1409,20 @@ static void* rdpgfx_server_thread_func(void* arg) Stream_SetLength(s, BytesReturned); Stream_SetPosition(s, 0); - if ((error = rdpgfx_server_receive_pdu(context, s))) + + while (((size_t) Stream_GetPosition(s)) < Stream_Length(s)) + { + if ((error = rdpgfx_server_receive_pdu(context, s))) + { + WLog_ERR(TAG, "rdpgfx_server_receive_pdu failed with error %lu!", error); + break; + } + } + + if (error != CHANNEL_RC_OK) { - WLog_ERR(TAG, "rdpgfx_server_receive_pdu failed with error %lu!", error); break; } - Stream_SetPosition(s, 0); } Stream_Free(s, TRUE); @@ -1123,28 +1466,41 @@ static BOOL rdpgfx_server_open(RdpgfxServerContext* context) if (!(priv->zgfx = zgfx_context_new(TRUE))) { WLog_ERR(TAG, "Create zgfx context failed!"); - return FALSE; + goto out_close; } if (!(priv->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) { WLog_ERR(TAG, "CreateEvent failed!"); - return FALSE; + goto out_zgfx; } if (!(priv->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) rdpgfx_server_thread_func, (void*) context, 0, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); - CloseHandle(priv->stopEvent); - priv->stopEvent = NULL; - return FALSE; + goto out_stopEvent; } return TRUE; } + WLog_ERR(TAG, "thread already running!"); return FALSE; + +out_stopEvent: + CloseHandle(priv->stopEvent); + priv->stopEvent = NULL; + +out_zgfx: + zgfx_context_free(priv->zgfx); + priv->zgfx = NULL; + +out_close: + WTSVirtualChannelClose(priv->rdpgfx_channel); + priv->rdpgfx_channel = NULL; + + return FALSE; } static BOOL rdpgfx_server_close(RdpgfxServerContext* context) @@ -1198,6 +1554,7 @@ RdpgfxServerContext* rdpgfx_server_context_new(HANDLE vcm) context->StartFrame = rdpgfx_send_start_frame_pdu; context->EndFrame = rdpgfx_send_end_frame_pdu; context->SurfaceCommand = rdpgfx_send_surface_command; + context->SurfaceFrameCommand = rdpgfx_send_surface_frame_command; context->DeleteEncodingContext = rdpgfx_send_delete_encoding_context_pdu; context->CreateSurface = rdpgfx_send_create_surface_pdu; context->DeleteSurface = rdpgfx_send_delete_surface_pdu; diff --git a/channels/server/channels.c b/channels/server/channels.c index 84ccf6e15..9f99ebbda 100644 --- a/channels/server/channels.c +++ b/channels/server/channels.c @@ -49,6 +49,7 @@ #include #include #include +#include void freerdp_channels_dummy() { @@ -79,6 +80,8 @@ void freerdp_channels_dummy() encomsp_server_context_new(NULL); encomsp_server_context_free(NULL); + rdpgfx_server_context_new(NULL); + rdpgfx_server_context_free(NULL); } /** diff --git a/include/freerdp/channels/wtsvc.h b/include/freerdp/channels/wtsvc.h index 66ee9eb24..ac3bd8410 100644 --- a/include/freerdp/channels/wtsvc.h +++ b/include/freerdp/channels/wtsvc.h @@ -43,6 +43,13 @@ extern "C" { #endif +enum +{ + DRDYNVC_STATE_NONE = 0, + DRDYNVC_STATE_INITIALIZED = 1, + DRDYNVC_STATE_READY = 2 +}; + /** * WTSVirtualChannelManager functions are FreeRDP extensions to the API. */ @@ -51,6 +58,7 @@ FREERDP_API void WTSVirtualChannelManagerGetFileDescriptor(HANDLE hServer, void* FREERDP_API BOOL WTSVirtualChannelManagerCheckFileDescriptor(HANDLE hServer); FREERDP_API HANDLE WTSVirtualChannelManagerGetEventHandle(HANDLE hServer); FREERDP_API BOOL WTSVirtualChannelManagerIsChannelJoined(HANDLE hServer, const char* name); +FREERDP_API BYTE WTSVirtualChannelManagerGetDrdynvcState(HANDLE hServer); /** * Extended FreeRDP WTS functions for channel handling diff --git a/include/freerdp/codec/zgfx.h b/include/freerdp/codec/zgfx.h index 53a41f8f4..b5c65319c 100644 --- a/include/freerdp/codec/zgfx.h +++ b/include/freerdp/codec/zgfx.h @@ -36,8 +36,8 @@ struct _ZGFX_CONTEXT { BOOL Compressor; - BYTE* pbInputCurrent; - BYTE* pbInputEnd; + const BYTE* pbInputCurrent; + const BYTE* pbInputEnd; UINT32 bits; UINT32 cBitsRemaining; @@ -57,9 +57,9 @@ typedef struct _ZGFX_CONTEXT ZGFX_CONTEXT; extern "C" { #endif -FREERDP_API int zgfx_decompress(ZGFX_CONTEXT* zgfx, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32 flags); -FREERDP_API int zgfx_compress(ZGFX_CONTEXT* zgfx, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags); -FREERDP_API int zgfx_compress_to_stream(ZGFX_CONTEXT* zgfx, wStream* sDst, BYTE* pUncompressed, UINT32 uncompressedSize, UINT32* pFlags); +FREERDP_API int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32 flags); +FREERDP_API int zgfx_compress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags); +FREERDP_API int zgfx_compress_to_stream(ZGFX_CONTEXT* zgfx, wStream* sDst, const BYTE* pUncompressed, UINT32 uncompressedSize, UINT32* pFlags); FREERDP_API void zgfx_context_reset(ZGFX_CONTEXT* zgfx, BOOL flush); diff --git a/include/freerdp/server/rdpgfx.h b/include/freerdp/server/rdpgfx.h index 7f4d033bc..983779e11 100644 --- a/include/freerdp/server/rdpgfx.h +++ b/include/freerdp/server/rdpgfx.h @@ -28,26 +28,27 @@ typedef struct _rdpgfx_server_private RdpgfxServerPrivate; typedef BOOL (*psRdpgfxServerOpen)(RdpgfxServerContext* context); typedef BOOL (*psRdpgfxServerClose)(RdpgfxServerContext* context); -typedef UINT (*pcRdpgfxResetGraphics)(RdpgfxServerContext* context, RDPGFX_RESET_GRAPHICS_PDU* resetGraphics); -typedef UINT (*pcRdpgfxStartFrame)(RdpgfxServerContext* context, RDPGFX_START_FRAME_PDU* startFrame); -typedef UINT (*pcRdpgfxEndFrame)(RdpgfxServerContext* context, RDPGFX_END_FRAME_PDU* endFrame); -typedef UINT (*pcRdpgfxSurfaceCommand)(RdpgfxServerContext* context, RDPGFX_SURFACE_COMMAND* cmd); -typedef UINT (*pcRdpgfxDeleteEncodingContext)(RdpgfxServerContext* context, RDPGFX_DELETE_ENCODING_CONTEXT_PDU* deleteEncodingContext); -typedef UINT (*pcRdpgfxCreateSurface)(RdpgfxServerContext* context, RDPGFX_CREATE_SURFACE_PDU* createSurface); -typedef UINT (*pcRdpgfxDeleteSurface)(RdpgfxServerContext* context, RDPGFX_DELETE_SURFACE_PDU* deleteSurface); -typedef UINT (*pcRdpgfxSolidFill)(RdpgfxServerContext* context, RDPGFX_SOLID_FILL_PDU* solidFill); -typedef UINT (*pcRdpgfxSurfaceToSurface)(RdpgfxServerContext* context, RDPGFX_SURFACE_TO_SURFACE_PDU* surfaceToSurface); -typedef UINT (*pcRdpgfxSurfaceToCache)(RdpgfxServerContext* context, RDPGFX_SURFACE_TO_CACHE_PDU* surfaceToCache); -typedef UINT (*pcRdpgfxCacheToSurface)(RdpgfxServerContext* context, RDPGFX_CACHE_TO_SURFACE_PDU* cacheToSurface); -typedef UINT (*pcRdpgfxCacheImportOffer)(RdpgfxServerContext* context, RDPGFX_CACHE_IMPORT_OFFER_PDU* cacheImportOffer); -typedef UINT (*pcRdpgfxCacheImportReply)(RdpgfxServerContext* context, RDPGFX_CACHE_IMPORT_REPLY_PDU* cacheImportReply); -typedef UINT (*pcRdpgfxEvictCacheEntry)(RdpgfxServerContext* context, RDPGFX_EVICT_CACHE_ENTRY_PDU* evictCacheEntry); -typedef UINT (*pcRdpgfxMapSurfaceToOutput)(RdpgfxServerContext* context, RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU* surfaceToOutput); -typedef UINT (*pcRdpgfxMapSurfaceToWindow)(RdpgfxServerContext* context, RDPGFX_MAP_SURFACE_TO_WINDOW_PDU* surfaceToWindow); -typedef UINT (*pcRdpgfxCapsAdvertise)(RdpgfxServerContext* context, RDPGFX_CAPS_ADVERTISE_PDU* capsAdvertise); -typedef UINT (*pcRdpgfxCapsConfirm)(RdpgfxServerContext* context, RDPGFX_CAPS_CONFIRM_PDU* capsConfirm); -typedef UINT (*pcRdpgfxFrameAcknowledge)(RdpgfxServerContext* context, RDPGFX_FRAME_ACKNOWLEDGE_PDU* frameAcknowledge); -typedef UINT (*pcRdpgfxQoeFrameAcknowledge)(RdpgfxServerContext* context, RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU* qoeFrameAcknowledge); +typedef UINT (*psRdpgfxResetGraphics)(RdpgfxServerContext* context, RDPGFX_RESET_GRAPHICS_PDU* resetGraphics); +typedef UINT (*psRdpgfxStartFrame)(RdpgfxServerContext* context, RDPGFX_START_FRAME_PDU* startFrame); +typedef UINT (*psRdpgfxEndFrame)(RdpgfxServerContext* context, RDPGFX_END_FRAME_PDU* endFrame); +typedef UINT (*psRdpgfxSurfaceCommand)(RdpgfxServerContext* context, RDPGFX_SURFACE_COMMAND* cmd); +typedef UINT (*psRdpgfxSurfaceFrameCommand)(RdpgfxServerContext* context, RDPGFX_SURFACE_COMMAND* cmd, RDPGFX_START_FRAME_PDU* startFrame, RDPGFX_END_FRAME_PDU* endFrame); +typedef UINT (*psRdpgfxDeleteEncodingContext)(RdpgfxServerContext* context, RDPGFX_DELETE_ENCODING_CONTEXT_PDU* deleteEncodingContext); +typedef UINT (*psRdpgfxCreateSurface)(RdpgfxServerContext* context, RDPGFX_CREATE_SURFACE_PDU* createSurface); +typedef UINT (*psRdpgfxDeleteSurface)(RdpgfxServerContext* context, RDPGFX_DELETE_SURFACE_PDU* deleteSurface); +typedef UINT (*psRdpgfxSolidFill)(RdpgfxServerContext* context, RDPGFX_SOLID_FILL_PDU* solidFill); +typedef UINT (*psRdpgfxSurfaceToSurface)(RdpgfxServerContext* context, RDPGFX_SURFACE_TO_SURFACE_PDU* surfaceToSurface); +typedef UINT (*psRdpgfxSurfaceToCache)(RdpgfxServerContext* context, RDPGFX_SURFACE_TO_CACHE_PDU* surfaceToCache); +typedef UINT (*psRdpgfxCacheToSurface)(RdpgfxServerContext* context, RDPGFX_CACHE_TO_SURFACE_PDU* cacheToSurface); +typedef UINT (*psRdpgfxCacheImportOffer)(RdpgfxServerContext* context, RDPGFX_CACHE_IMPORT_OFFER_PDU* cacheImportOffer); +typedef UINT (*psRdpgfxCacheImportReply)(RdpgfxServerContext* context, RDPGFX_CACHE_IMPORT_REPLY_PDU* cacheImportReply); +typedef UINT (*psRdpgfxEvictCacheEntry)(RdpgfxServerContext* context, RDPGFX_EVICT_CACHE_ENTRY_PDU* evictCacheEntry); +typedef UINT (*psRdpgfxMapSurfaceToOutput)(RdpgfxServerContext* context, RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU* surfaceToOutput); +typedef UINT (*psRdpgfxMapSurfaceToWindow)(RdpgfxServerContext* context, RDPGFX_MAP_SURFACE_TO_WINDOW_PDU* surfaceToWindow); +typedef UINT (*psRdpgfxCapsAdvertise)(RdpgfxServerContext* context, RDPGFX_CAPS_ADVERTISE_PDU* capsAdvertise); +typedef UINT (*psRdpgfxCapsConfirm)(RdpgfxServerContext* context, RDPGFX_CAPS_CONFIRM_PDU* capsConfirm); +typedef UINT (*psRdpgfxFrameAcknowledge)(RdpgfxServerContext* context, RDPGFX_FRAME_ACKNOWLEDGE_PDU* frameAcknowledge); +typedef UINT (*psRdpgfxQoeFrameAcknowledge)(RdpgfxServerContext* context, RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU* qoeFrameAcknowledge); struct _rdpgfx_server_context { @@ -57,26 +58,27 @@ struct _rdpgfx_server_context psRdpgfxServerOpen Open; psRdpgfxServerClose Close; - pcRdpgfxResetGraphics ResetGraphics; - pcRdpgfxStartFrame StartFrame; - pcRdpgfxEndFrame EndFrame; - pcRdpgfxSurfaceCommand SurfaceCommand; - pcRdpgfxDeleteEncodingContext DeleteEncodingContext; - pcRdpgfxCreateSurface CreateSurface; - pcRdpgfxDeleteSurface DeleteSurface; - pcRdpgfxSolidFill SolidFill; - pcRdpgfxSurfaceToSurface SurfaceToSurface; - pcRdpgfxSurfaceToCache SurfaceToCache; - pcRdpgfxCacheToSurface CacheToSurface; - pcRdpgfxCacheImportOffer CacheImportOffer; - pcRdpgfxCacheImportReply CacheImportReply; - pcRdpgfxEvictCacheEntry EvictCacheEntry; - pcRdpgfxMapSurfaceToOutput MapSurfaceToOutput; - pcRdpgfxMapSurfaceToWindow MapSurfaceToWindow; - pcRdpgfxCapsAdvertise CapsAdvertise; - pcRdpgfxCapsConfirm CapsConfirm; - pcRdpgfxFrameAcknowledge FrameAcknowledge; - pcRdpgfxQoeFrameAcknowledge QoeFrameAcknowledge; + psRdpgfxResetGraphics ResetGraphics; + psRdpgfxStartFrame StartFrame; + psRdpgfxEndFrame EndFrame; + psRdpgfxSurfaceCommand SurfaceCommand; + psRdpgfxSurfaceFrameCommand SurfaceFrameCommand; + psRdpgfxDeleteEncodingContext DeleteEncodingContext; + psRdpgfxCreateSurface CreateSurface; + psRdpgfxDeleteSurface DeleteSurface; + psRdpgfxSolidFill SolidFill; + psRdpgfxSurfaceToSurface SurfaceToSurface; + psRdpgfxSurfaceToCache SurfaceToCache; + psRdpgfxCacheToSurface CacheToSurface; + psRdpgfxCacheImportOffer CacheImportOffer; + psRdpgfxCacheImportReply CacheImportReply; + psRdpgfxEvictCacheEntry EvictCacheEntry; + psRdpgfxMapSurfaceToOutput MapSurfaceToOutput; + psRdpgfxMapSurfaceToWindow MapSurfaceToWindow; + psRdpgfxCapsAdvertise CapsAdvertise; + psRdpgfxCapsConfirm CapsConfirm; + psRdpgfxFrameAcknowledge FrameAcknowledge; + psRdpgfxQoeFrameAcknowledge QoeFrameAcknowledge; RdpgfxServerPrivate* priv; rdpContext* rdpcontext; diff --git a/libfreerdp/codec/zgfx.c b/libfreerdp/codec/zgfx.c index 4d5373454..e5c6c3cfe 100644 --- a/libfreerdp/codec/zgfx.c +++ b/libfreerdp/codec/zgfx.c @@ -108,7 +108,7 @@ static const ZGFX_TOKEN ZGFX_TOKEN_TABLE[] = _zgfx->bits = _zgfx->BitsCurrent >> _zgfx->cBitsCurrent; \ _zgfx->BitsCurrent &= ((1 << _zgfx->cBitsCurrent) - 1); -void zgfx_history_buffer_ring_write(ZGFX_CONTEXT* zgfx, BYTE* src, UINT32 count) +void zgfx_history_buffer_ring_write(ZGFX_CONTEXT* zgfx, const BYTE* src, UINT32 count) { UINT32 front; UINT32 residue; @@ -191,7 +191,7 @@ void zgfx_history_buffer_ring_read(ZGFX_CONTEXT* zgfx, int offset, BYTE* dst, UI while ((bytesLeft -= bytes) > 0); } -static int zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, BYTE* pbSegment, UINT32 cbSegment) +static int zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, const BYTE* pbSegment, UINT32 cbSegment) { BYTE c; BYTE flags; @@ -325,7 +325,7 @@ static int zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, BYTE* pbSegment, UINT32 c return 1; } -int zgfx_decompress(ZGFX_CONTEXT* zgfx, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32 flags) +int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32 flags) { int status; BYTE descriptor; @@ -386,7 +386,7 @@ int zgfx_decompress(ZGFX_CONTEXT* zgfx, BYTE* pSrcData, UINT32 SrcSize, BYTE** p return 1; } -static int zgfx_compress_segment(ZGFX_CONTEXT* zgfx, wStream* s, BYTE* pSrcData, UINT32 SrcSize, UINT32* pFlags) +static int zgfx_compress_segment(ZGFX_CONTEXT* zgfx, wStream* s, const BYTE* pSrcData, UINT32 SrcSize, UINT32* pFlags) { /* FIXME: Currently compression not implemented. Just copy the raw source */ @@ -402,13 +402,13 @@ static int zgfx_compress_segment(ZGFX_CONTEXT* zgfx, wStream* s, BYTE* pSrcData, return 1; } -int zgfx_compress_to_stream(ZGFX_CONTEXT* zgfx, wStream* sDst, BYTE* pUncompressed, UINT32 uncompressedSize, UINT32* pFlags) +int zgfx_compress_to_stream(ZGFX_CONTEXT* zgfx, wStream* sDst, const BYTE* pUncompressed, UINT32 uncompressedSize, UINT32* pFlags) { int fragment; UINT16 maxLength; UINT32 totalLength; - UINT16* pSegmentCount = NULL; - BYTE* pSrcData; + size_t posSegmentCount = 0; + const BYTE* pSrcData; int status = 0; maxLength = ZGFX_SEGMENTED_MAXSIZE; @@ -418,13 +418,21 @@ int zgfx_compress_to_stream(ZGFX_CONTEXT* zgfx, wStream* sDst, BYTE* pUncompress for (fragment = 0; (totalLength > 0) || (fragment == 0); fragment++) { UINT32 SrcSize; - UINT32* pDstSize; - UINT32 position; + size_t posDstSize; + size_t posDataStart; + UINT32 DstSize; SrcSize = (totalLength > maxLength) ? maxLength : totalLength; - pDstSize = NULL; + posDstSize = 0; totalLength -= SrcSize; + /* Ensure we have enough space for headers */ + if (!Stream_EnsureRemainingCapacity(sDst, 12)) + { + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + return -1; + } + if (fragment == 0) { /* First fragment */ @@ -434,45 +442,51 @@ int zgfx_compress_to_stream(ZGFX_CONTEXT* zgfx, wStream* sDst, BYTE* pUncompress ZGFX_SEGMENTED_SINGLE : ZGFX_SEGMENTED_MULTIPART); if (totalLength > 0) { - pSegmentCount = (UINT16*)Stream_Pointer(sDst); /* segmentCount (2 bytes) */ + posSegmentCount = Stream_GetPosition(sDst); /* segmentCount (2 bytes) */ Stream_Seek(sDst, 2); Stream_Write_UINT32(sDst, uncompressedSize); /* uncompressedSize (4 bytes) */ } } - else if (totalLength == 0) - { - /* Last fragment */ - if (pSegmentCount) - { - (*pSegmentCount) = fragment + 1; - } - } if (fragment > 0 || totalLength > 0) { /* Multipart */ - pDstSize = (UINT32*)Stream_Pointer(sDst); /* size (4 bytes) */ + posDstSize = Stream_GetPosition(sDst); /* size (4 bytes) */ Stream_Seek(sDst, 4); } - position = Stream_GetPosition(sDst); + posDataStart = Stream_GetPosition(sDst); if ((status = zgfx_compress_segment(zgfx, sDst, pSrcData, SrcSize, pFlags)) < 0) { return status; } - if (pDstSize) + if (posDstSize) { - (*pDstSize) = Stream_GetPosition(sDst) - position; + /* Fill segment data size */ + DstSize = Stream_GetPosition(sDst) - posDataStart; + Stream_SetPosition(sDst, posDstSize); + Stream_Write_UINT32(sDst, DstSize); + Stream_SetPosition(sDst, posDataStart + DstSize); } pSrcData += SrcSize; } + Stream_SealLength(sDst); + + /* fill back segmentCount */ + if (posSegmentCount) + { + Stream_SetPosition(sDst, posSegmentCount); + Stream_Write_UINT16(sDst, fragment); + Stream_SetPosition(sDst, Stream_Length(sDst)); + } + return status; } -int zgfx_compress(ZGFX_CONTEXT* zgfx, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags) +int zgfx_compress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags) { int status; wStream* s = Stream_New(NULL, SrcSize); diff --git a/libfreerdp/core/server.c b/libfreerdp/core/server.c index 625585e94..fb1a740fd 100644 --- a/libfreerdp/core/server.c +++ b/libfreerdp/core/server.c @@ -557,6 +557,13 @@ BOOL WTSVirtualChannelManagerIsChannelJoined(HANDLE hServer, const char* name) return wts_get_joined_channel_by_name(vcm->rdp->mcs, name) == NULL ? FALSE : TRUE; } +BYTE WTSVirtualChannelManagerGetDrdynvcState(HANDLE hServer) +{ + WTSVirtualChannelManager* vcm = (WTSVirtualChannelManager*) hServer; + + return vcm->drdynvc_state; +} + UINT16 WTSChannelGetId(freerdp_peer* client, const char* channel_name) { rdpMcsChannel* channel; @@ -1205,6 +1212,7 @@ BOOL WINAPI FreeRDP_WTSVirtualChannelWrite(HANDLE hChannelHandle, PCHAR Buffer, BYTE* buffer; UINT32 length; UINT32 written; + UINT32 totalWritten = 0; rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle; BOOL ret = TRUE; @@ -1222,6 +1230,8 @@ BOOL WINAPI FreeRDP_WTSVirtualChannelWrite(HANDLE hChannelHandle, PCHAR Buffer, } CopyMemory(buffer, Buffer, length); + totalWritten = Length; + ret = wts_queue_send_item(channel, buffer, length); } else if (!channel->vcm->drdynvc_channel || (channel->vcm->drdynvc_state != DRDYNVC_STATE_READY)) @@ -1270,13 +1280,14 @@ BOOL WINAPI FreeRDP_WTSVirtualChannelWrite(HANDLE hChannelHandle, PCHAR Buffer, Length -= written; Buffer += written; + totalWritten += written; ret = wts_queue_send_item(channel->vcm->drdynvc_channel, buffer, length); } } if (pBytesWritten) - *pBytesWritten = Length; + *pBytesWritten = totalWritten; return ret; } diff --git a/libfreerdp/core/server.h b/libfreerdp/core/server.h index aa165557e..35a9883c6 100644 --- a/libfreerdp/core/server.h +++ b/libfreerdp/core/server.h @@ -47,13 +47,6 @@ enum RDP_PEER_CHANNEL_TYPE_DVC = 1 }; -enum -{ - DRDYNVC_STATE_NONE = 0, - DRDYNVC_STATE_INITIALIZED = 1, - DRDYNVC_STATE_READY = 2 -}; - enum { DVC_OPEN_STATE_NONE = 0, diff --git a/server/shadow/Mac/mac_shadow.c b/server/shadow/Mac/mac_shadow.c index e281ffdc9..0f6c23a71 100644 --- a/server/shadow/Mac/mac_shadow.c +++ b/server/shadow/Mac/mac_shadow.c @@ -317,9 +317,6 @@ void (^mac_capture_stream_handler)(CGDisplayStreamFrameStatus, uint64_t, IOSurfa if (count < 1) return; - if ((count == 1) && subsystem->suppressOutput) - return; - mac_shadow_capture_get_dirty_region(subsystem); surfaceRect.left = 0; @@ -360,7 +357,9 @@ void (^mac_capture_stream_handler)(CGDisplayStreamFrameStatus, uint64_t, IOSurfa count = ArrayList_Count(server->clients); + EnterCriticalSection(&(surface->lock)); shadow_subsystem_frame_update((rdpShadowSubsystem *)subsystem); + LeaveCriticalSection(&(surface->lock)); if (count == 1) { @@ -445,10 +444,14 @@ int mac_shadow_screen_grab(macShadowSubsystem* subsystem) int mac_shadow_subsystem_process_message(macShadowSubsystem* subsystem, wMessage* message) { + rdpShadowServer* server = subsystem->server; + rdpShadowSurface* surface = server->surface; switch(message->id) { case SHADOW_MSG_IN_REFRESH_REQUEST_ID: + EnterCriticalSection(&(surface->lock)); shadow_subsystem_frame_update((rdpShadowSubsystem *)subsystem); + LeaveCriticalSection(&(surface->lock)); break; default: WLog_ERR(TAG, "Unknown message id: %u", message->id); diff --git a/server/shadow/shadow_client.c b/server/shadow/shadow_client.c index 010289cc8..ba0a80365 100644 --- a/server/shadow/shadow_client.c +++ b/server/shadow/shadow_client.c @@ -30,7 +30,6 @@ #include -#include "libfreerdp/core/server.h" #include "shadow.h" #define TAG CLIENT_TAG("shadow") @@ -42,8 +41,9 @@ struct _SHADOW_GFX_STATUS }; typedef struct _SHADOW_GFX_STATUS SHADOW_GFX_STATUS; -static void shadow_client_rdpgfx_new_surface(rdpShadowClient *client) +static INLINE BOOL shadow_client_rdpgfx_new_surface(rdpShadowClient *client) { + UINT error = CHANNEL_RC_OK; RDPGFX_CREATE_SURFACE_PDU createSurface; RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU surfaceToOutput; RdpgfxServerContext* context = client->rdpgfx; @@ -59,21 +59,43 @@ static void shadow_client_rdpgfx_new_surface(rdpShadowClient *client) surfaceToOutput.surfaceId = 0; surfaceToOutput.reserved = 0; - IFCALL(context->CreateSurface, context, &createSurface); - IFCALL(context->MapSurfaceToOutput, context, &surfaceToOutput); + IFCALLRET(context->CreateSurface, error, context, &createSurface); + if (error) + { + WLog_ERR(TAG, "CreateSurface failed with error %lu", error); + return FALSE; + } + + IFCALLRET(context->MapSurfaceToOutput, error, context, &surfaceToOutput); + if (error) + { + WLog_ERR(TAG, "MapSurfaceToOutput failed with error %lu", error); + return FALSE; + } + + return TRUE; } -static void shadow_client_rdpgfx_release_surface(rdpShadowClient *client) +static INLINE BOOL shadow_client_rdpgfx_release_surface(rdpShadowClient *client) { + UINT error = CHANNEL_RC_OK; RDPGFX_DELETE_SURFACE_PDU pdu; RdpgfxServerContext* context = client->rdpgfx; pdu.surfaceId = 0; - IFCALL(context->DeleteSurface, context, &pdu); + IFCALLRET(context->DeleteSurface, error, context, &pdu); + if (error) + { + WLog_ERR(TAG, "DeleteSurface failed with error %lu", error); + return FALSE; + } + + return TRUE; } -static void shadow_client_rdpgfx_reset_graphic(rdpShadowClient *client) +static INLINE BOOL shadow_client_rdpgfx_reset_graphic(rdpShadowClient *client) { + UINT error = CHANNEL_RC_OK; RDPGFX_RESET_GRAPHICS_PDU pdu; RdpgfxServerContext* context = client->rdpgfx; rdpSettings* settings = ((rdpContext*) client)->settings; @@ -83,10 +105,17 @@ static void shadow_client_rdpgfx_reset_graphic(rdpShadowClient *client) pdu.monitorCount = client->subsystem->numMonitors; pdu.monitorDefArray = client->subsystem->monitors; - IFCALL(context->ResetGraphics, context, &pdu); + IFCALLRET(context->ResetGraphics, error, context, &pdu); + if (error) + { + WLog_ERR(TAG, "ResetGraphics failed with error %lu", error); + return FALSE; + } + + return TRUE; } -static void shadow_client_free_queued_message(void *obj) +static INLINE void shadow_client_free_queued_message(void *obj) { wMessage *message = (wMessage*)obj; if (message->Free) @@ -222,7 +251,7 @@ void shadow_client_message_free(wMessage* message) } } -static void shadow_client_mark_invalid(rdpShadowClient* client, int numRects, const RECTANGLE_16* rects) +static INLINE void shadow_client_mark_invalid(rdpShadowClient* client, int numRects, const RECTANGLE_16* rects) { int index; RECTANGLE_16 screenRegion; @@ -254,11 +283,11 @@ static void shadow_client_mark_invalid(rdpShadowClient* client, int numRects, co /** * Function description - * Recalculate client desktop size + * Recalculate client desktop size and update to rdpSettings * * @return TRUE if width/height changed. */ -static BOOL shadow_client_recalc_desktop_size(rdpShadowClient* client) +static INLINE BOOL shadow_client_recalc_desktop_size(rdpShadowClient* client) { int width, height; rdpShadowServer* server = client->server; @@ -268,7 +297,7 @@ static BOOL shadow_client_recalc_desktop_size(rdpShadowClient* client) if (server->shareSubRect) { - rectangles_intersection(&viewport, &(server->subRect), &viewport); + rectangles_intersection(&viewport, &(server->subRect), &viewport); } width = viewport.right - viewport.left; @@ -288,16 +317,20 @@ static BOOL shadow_client_capabilities(freerdp_peer* peer) { rdpShadowSubsystem* subsystem; rdpShadowClient* client; + BOOL ret = TRUE; client = (rdpShadowClient*) peer->context; subsystem = client->server->subsystem; - IFCALL(subsystem->ClientCapabilities, subsystem, client); + IFCALLRET(subsystem->ClientCapabilities, ret, subsystem, client); + if (!ret) + WLog_WARN(TAG, "subsystem->ClientCapabilities failed"); - /* Make sure we send correct width/height to client */ + /* Recalculate desktop size regardless whether previous call fail + * or not. Make sure we send correct width/height to client */ (void)shadow_client_recalc_desktop_size(client); - return TRUE; + return ret; } static BOOL shadow_client_post_connect(freerdp_peer* peer) @@ -366,7 +399,7 @@ static BOOL shadow_client_post_connect(freerdp_peer* peer) } /* Convert rects in sub rect coordinate to client/surface coordinate */ -static INLINE void shadow_client_convert_rects(rdpShadowClient* client, +static INLINE void shadow_client_convert_rects(rdpShadowClient* client, RECTANGLE_16* dst, const RECTANGLE_16* src, UINT32 numRects) { if (client->server->shareSubRect) @@ -477,7 +510,11 @@ static BOOL shadow_client_activate(freerdp_peer* peer) client->activated = TRUE; client->inLobby = client->mayView ? FALSE : TRUE; - shadow_encoder_reset(client->encoder); + if (shadow_encoder_reset(client->encoder) < 0) + { + WLog_ERR(TAG, "Failed to reset encoder"); + return FALSE; + } /* Update full screen in next update */ return shadow_client_refresh_rect(client, 0, NULL); @@ -544,31 +581,41 @@ BOOL shadow_client_logon(freerdp_peer* peer, SEC_WINNT_AUTH_IDENTITY* identity, return TRUE; } -static BOOL shadow_client_surface_frame_acknowledge(rdpShadowClient* client, UINT32 frameId) +static INLINE void shadow_client_common_frame_acknowledge(rdpShadowClient* client, UINT32 frameId) { /* - * Record the last client acknowledged frame id to + * Record the last client acknowledged frame id to * calculate how much frames are in progress. - * Some rdp clients (win7 mstsc) skips frame ACK if it is - * inactive, we should not expect ACK for each frame. + * Some rdp clients (win7 mstsc) skips frame ACK if it is + * inactive, we should not expect ACK for each frame. * So it is OK to calculate inflight frame count according to * a latest acknowledged frame id. */ client->encoder->lastAckframeId = frameId; +} +static BOOL shadow_client_surface_frame_acknowledge(rdpShadowClient* client, UINT32 frameId) +{ + shadow_client_common_frame_acknowledge(client, frameId); return TRUE; } static UINT shadow_client_rdpgfx_frame_acknowledge(RdpgfxServerContext* context, RDPGFX_FRAME_ACKNOWLEDGE_PDU* frameAcknowledge) { - shadow_client_surface_frame_acknowledge((rdpShadowClient *)context->custom, - frameAcknowledge->frameId); + shadow_client_common_frame_acknowledge((rdpShadowClient *)context->custom, + frameAcknowledge->frameId); return CHANNEL_RC_OK; } -static int shadow_client_send_surface_gfx(rdpShadowClient* client, +/** + * Function description + * + * @return TRUE on success + */ +static BOOL shadow_client_send_surface_gfx(rdpShadowClient* client, BYTE* pSrcData, int nSrcStep, int nXSrc, int nYSrc, int nWidth, int nHeight) { + UINT error = CHANNEL_RC_OK; rdpUpdate* update; rdpContext* context; rdpSettings* settings; @@ -610,7 +657,11 @@ static int shadow_client_send_surface_gfx(rdpShadowClient* client, RECTANGLE_16 regionRect; RDPGFX_H264_QUANT_QUALITY quantQualityVal; - shadow_encoder_prepare(encoder, FREERDP_CODEC_AVC420); + if (shadow_encoder_prepare(encoder, FREERDP_CODEC_AVC420) < 0) + { + WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_AVC420"); + return FALSE; + } avc420_compress(encoder->h264, pSrcData, PIXEL_FORMAT_RGB32, nSrcStep, nWidth, nHeight, &avc420.data, &avc420.length); @@ -629,17 +680,26 @@ static int shadow_client_send_surface_gfx(rdpShadowClient* client, avc420.meta.regionRects = ®ionRect; avc420.meta.quantQualityVals = &quantQualityVal; - IFCALL(client->rdpgfx->StartFrame, client->rdpgfx, &cmdstart); - IFCALL(client->rdpgfx->SurfaceCommand, client->rdpgfx, &cmd); - IFCALL(client->rdpgfx->EndFrame, client->rdpgfx, &cmdend); + IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, &cmd, &cmdstart, &cmdend); + if (error) + { + WLog_ERR(TAG, "SurfaceFrameCommand failed with error %lu", error); + return FALSE; + } } - return 1; + return TRUE; } -static int shadow_client_send_surface_bits(rdpShadowClient* client, +/** + * Function description + * + * @return TRUE on success + */ +static BOOL shadow_client_send_surface_bits(rdpShadowClient* client, BYTE* pSrcData, int nSrcStep, int nXSrc, int nYSrc, int nWidth, int nHeight) { + BOOL ret = TRUE; int i; BOOL first; BOOL last; @@ -669,7 +729,11 @@ static int shadow_client_send_surface_bits(rdpShadowClient* client, RFX_MESSAGE* messages; RFX_RECT *messageRects = NULL; - shadow_encoder_prepare(encoder, FREERDP_CODEC_REMOTEFX); + if (shadow_encoder_prepare(encoder, FREERDP_CODEC_REMOTEFX) < 0) + { + WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_REMOTEFX"); + return FALSE; + } s = encoder->bs; @@ -682,7 +746,8 @@ static int shadow_client_send_surface_bits(rdpShadowClient* client, settings->DesktopWidth, settings->DesktopHeight, nSrcStep, &numMessages, settings->MultifragMaxRequestSize))) { - return 0; + WLog_ERR(TAG, "rfx_encode_messages failed"); + return FALSE; } cmd.codecID = settings->RemoteFxCodecId; @@ -709,6 +774,8 @@ static int shadow_client_send_surface_bits(rdpShadowClient* client, { rfx_message_free(encoder->rfx, &messages[i++]); } + WLog_ERR(TAG, "rfx_write_message failed"); + ret = FALSE; break; } rfx_message_free(encoder->rfx, &messages[i]); @@ -720,9 +787,15 @@ static int shadow_client_send_surface_bits(rdpShadowClient* client, last = ((i + 1) == numMessages) ? TRUE : FALSE; if (!encoder->frameAck) - IFCALL(update->SurfaceBits, update->context, &cmd); + IFCALLRET(update->SurfaceBits, ret, update->context, &cmd); else - IFCALL(update->SurfaceFrameBits, update->context, &cmd, first, last, frameId); + IFCALLRET(update->SurfaceFrameBits, ret, update->context, &cmd, first, last, frameId); + + if (!ret) + { + WLog_ERR(TAG, "Send surface bits(RemoteFxCodec) failed"); + break; + } } free(messageRects); @@ -730,7 +803,11 @@ static int shadow_client_send_surface_bits(rdpShadowClient* client, } else if (settings->NSCodec) { - shadow_encoder_prepare(encoder, FREERDP_CODEC_NSCODEC); + if (shadow_encoder_prepare(encoder, FREERDP_CODEC_NSCODEC) < 0) + { + WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_NSCODEC"); + return FALSE; + } s = encoder->bs; Stream_SetPosition(s, 0); @@ -755,17 +832,28 @@ static int shadow_client_send_surface_bits(rdpShadowClient* client, last = TRUE; if (!encoder->frameAck) - IFCALL(update->SurfaceBits, update->context, &cmd); + IFCALLRET(update->SurfaceBits, ret, update->context, &cmd); else - IFCALL(update->SurfaceFrameBits, update->context, &cmd, first, last, frameId); + IFCALLRET(update->SurfaceFrameBits, ret, update->context, &cmd, first, last, frameId); + + if (!ret) + { + WLog_ERR(TAG, "Send surface bits(NSCodec) failed"); + } } - return 1; + return ret; } -static int shadow_client_send_bitmap_update(rdpShadowClient* client, +/** + * Function description + * + * @return TRUE on success + */ +static BOOL shadow_client_send_bitmap_update(rdpShadowClient* client, BYTE* pSrcData, int nSrcStep, int nXSrc, int nYSrc, int nWidth, int nHeight) { + BOOL ret = TRUE; BYTE* data; BYTE* buffer; int yIdx, xIdx, k; @@ -794,9 +882,21 @@ static int shadow_client_send_bitmap_update(rdpShadowClient* client, maxUpdateSize = settings->MultifragMaxRequestSize; if (settings->ColorDepth < 32) - shadow_encoder_prepare(encoder, FREERDP_CODEC_INTERLEAVED); + { + if (shadow_encoder_prepare(encoder, FREERDP_CODEC_INTERLEAVED) < 0) + { + WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_INTERLEAVED"); + return FALSE; + } + } else - shadow_encoder_prepare(encoder, FREERDP_CODEC_PLANAR); + { + if (shadow_encoder_prepare(encoder, FREERDP_CODEC_PLANAR) < 0) + { + WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_PLANAR"); + return FALSE; + } + } SrcFormat = PIXEL_FORMAT_RGB32; @@ -820,7 +920,7 @@ static int shadow_client_send_bitmap_update(rdpShadowClient* client, bitmapUpdate.count = bitmapUpdate.number = rows * cols; if (!(bitmapData = (BITMAP_DATA*) malloc(sizeof(BITMAP_DATA) * bitmapUpdate.number))) - return -1; + return FALSE; bitmapUpdate.rectangles = bitmapData; if ((nWidth % 4) != 0) @@ -915,8 +1015,9 @@ static int shadow_client_send_bitmap_update(rdpShadowClient* client, if (!fragBitmapData) { - free(bitmapData); - return -1; + WLog_ERR(TAG, "Failed to allocate memory for fragBitmapData"); + ret = FALSE; + goto out; } bitmapUpdate.rectangles = fragBitmapData; @@ -939,9 +1040,15 @@ static int shadow_client_send_bitmap_update(rdpShadowClient* client, CopyMemory(&fragBitmapData[j++], &bitmapData[i++], sizeof(BITMAP_DATA)); updateSize = newUpdateSize; } - + bitmapUpdate.count = bitmapUpdate.number = j; - IFCALL(update->BitmapUpdate, context, &bitmapUpdate); + IFCALLRET(update->BitmapUpdate, ret, context, &bitmapUpdate); + if (!ret) + { + WLog_ERR(TAG, "BitmapUpdate failed"); + break; + } + updateSize = 1024; j = 0; } @@ -951,17 +1058,27 @@ static int shadow_client_send_bitmap_update(rdpShadowClient* client, } else { - IFCALL(update->BitmapUpdate, context, &bitmapUpdate); + IFCALLRET(update->BitmapUpdate, ret, context, &bitmapUpdate); + if (!ret) + { + WLog_ERR(TAG, "BitmapUpdate failed"); + } } +out: free(bitmapData); - return 1; + return ret; } -static int shadow_client_send_surface_update(rdpShadowClient* client, SHADOW_GFX_STATUS* pStatus) +/** + * Function description + * + * @return TRUE on success (or nothing need to be updated) + */ +static BOOL shadow_client_send_surface_update(rdpShadowClient* client, SHADOW_GFX_STATUS* pStatus) { - int status = -1; + BOOL ret = TRUE; int nXSrc, nYSrc; int nWidth, nHeight; rdpContext* context; @@ -1013,9 +1130,8 @@ static int shadow_client_send_surface_update(rdpShadowClient* client, SHADOW_GFX if (region16_is_empty(&invalidRegion)) { - /* No image region need to be updated */ - region16_uninit(&invalidRegion); - return 1; + /* No image region need to be updated. Success */ + goto out; } extents = region16_extents(&invalidRegion); @@ -1056,28 +1172,40 @@ static int shadow_client_send_surface_update(rdpShadowClient* client, SHADOW_GFX if (!pStatus->gfxSurfaceCreated) { /* Only init surface when we have h264 supported */ - shadow_client_rdpgfx_new_surface(client); - shadow_client_rdpgfx_reset_graphic(client); + if (!(ret = shadow_client_rdpgfx_new_surface(client))) + goto out; + + if (!(ret = shadow_client_rdpgfx_reset_graphic(client))) + goto out; + pStatus->gfxSurfaceCreated = TRUE; } - status = shadow_client_send_surface_gfx(client, pSrcData, nSrcStep, 0, 0, nWidth, nHeight); + ret = shadow_client_send_surface_gfx(client, pSrcData, nSrcStep, 0, 0, nWidth, nHeight); } else if (settings->RemoteFxCodec || settings->NSCodec) { - status = shadow_client_send_surface_bits(client, pSrcData, nSrcStep, nXSrc, nYSrc, nWidth, nHeight); + ret = shadow_client_send_surface_bits(client, pSrcData, nSrcStep, nXSrc, nYSrc, nWidth, nHeight); } else { - status = shadow_client_send_bitmap_update(client, pSrcData, nSrcStep, nXSrc, nYSrc, nWidth, nHeight); + ret = shadow_client_send_bitmap_update(client, pSrcData, nSrcStep, nXSrc, nYSrc, nWidth, nHeight); } +out: region16_uninit(&invalidRegion); - return status; + return ret; } -static void shadow_client_send_resize(rdpShadowClient* client, SHADOW_GFX_STATUS* pStatus) +/** + * Function description + * Notify client for resize. The new desktop width/height + * should have already been updated in rdpSettings. + * + * @return TRUE on success + */ +static BOOL shadow_client_send_resize(rdpShadowClient* client, SHADOW_GFX_STATUS* pStatus) { rdpContext* context; rdpSettings* settings; @@ -1091,7 +1219,7 @@ static void shadow_client_send_resize(rdpShadowClient* client, SHADOW_GFX_STATUS /** * Unset client activated flag to avoid sending update message during - * resize. DesktopResize will reactive the client and + * resize. DesktopResize will reactive the client and * shadow_client_activate would be invoked later. */ client->activated = FALSE; @@ -1099,12 +1227,18 @@ static void shadow_client_send_resize(rdpShadowClient* client, SHADOW_GFX_STATUS /* Close Gfx surfaces */ if (pStatus->gfxSurfaceCreated) { - shadow_client_rdpgfx_release_surface(client); + if (!shadow_client_rdpgfx_release_surface(client)) + return FALSE; + pStatus->gfxSurfaceCreated = FALSE; } /* Send Resize */ - peer->update->DesktopResize(peer->update->context); // update_send_desktop_resize + if (!peer->update->DesktopResize(peer->update->context)) + { + WLog_ERR(TAG, "DesktopResize failed"); + return FALSE; + } /* Clear my invalidRegion. shadow_client_activate refreshes fullscreen */ EnterCriticalSection(&(client->lock)); @@ -1113,20 +1247,17 @@ static void shadow_client_send_resize(rdpShadowClient* client, SHADOW_GFX_STATUS WLog_INFO(TAG, "Client from %s is resized (%dx%d@%d)", peer->hostname, settings->DesktopWidth, settings->DesktopHeight, settings->ColorDepth); + + return TRUE; } -static INLINE void shadow_client_no_surface_update(rdpShadowClient* client, SHADOW_GFX_STATUS* pStatus) -{ - rdpShadowServer* server; - rdpShadowSurface* surface; - - server = client->server; - surface = client->inLobby ? server->lobby : server->surface; - - shadow_client_surface_update(client, &(surface->invalidRegion)); -} - -int shadow_client_surface_update(rdpShadowClient* client, REGION16* region) +/** + * Function description + * Mark invalid region for client + * + * @return TRUE on success + */ +BOOL shadow_client_surface_update(rdpShadowClient* client, REGION16* region) { int numRects = 0; const RECTANGLE_16* rects; @@ -1134,7 +1265,24 @@ int shadow_client_surface_update(rdpShadowClient* client, REGION16* region) rects = region16_rects(region, &numRects); shadow_client_mark_invalid(client, numRects, rects); - return 1; + return TRUE; +} + +/** + * Function description + * Only union invalid region from server surface + * + * @return TRUE on success + */ +static INLINE BOOL shadow_client_no_surface_update(rdpShadowClient* client, SHADOW_GFX_STATUS* pStatus) +{ + rdpShadowServer* server; + rdpShadowSurface* surface; + + server = client->server; + surface = client->inLobby ? server->lobby : server->surface; + + return shadow_client_surface_update(client, &(surface->invalidRegion)); } static int shadow_client_subsystem_process_message(rdpShadowClient* client, wMessage* message) @@ -1320,23 +1468,35 @@ static void* shadow_client_thread(rdpShadowClient* client) if (shadow_client_recalc_desktop_size(client)) { /* Screen size changed, do resize */ - shadow_client_send_resize(client, &gfxstatus); + if (!shadow_client_send_resize(client, &gfxstatus)) + { + WLog_ERR(TAG, "Failed to send resize message"); + break; + } } - else + else { /* Send frame */ - shadow_client_send_surface_update(client, &gfxstatus); + if (!shadow_client_send_surface_update(client, &gfxstatus)) + { + WLog_ERR(TAG, "Failed to send surface update"); + break; + } } } else { /* Our client don't receive graphic updates. Just save the invalid region */ - shadow_client_no_surface_update(client, &gfxstatus); + if (!shadow_client_no_surface_update(client, &gfxstatus)) + { + WLog_ERR(TAG, "Failed to handle surface update"); + break; + } } - /* - * The return value of shadow_multiclient_consume is whether or not the subscriber really consumes the event. - * It's not cared currently. + /* + * The return value of shadow_multiclient_consume is whether or not + * the subscriber really consumes the event. It's not cared currently. */ (void)shadow_multiclient_consume(UpdateSubscriber); } @@ -1352,7 +1512,7 @@ static void* shadow_client_thread(rdpShadowClient* client) if (WTSVirtualChannelManagerIsChannelJoined(client->vcm, "drdynvc")) { /* Dynamic channel status may have been changed after processing */ - if (((WTSVirtualChannelManager*)(client->vcm))->drdynvc_state == DRDYNVC_STATE_NONE) + if (WTSVirtualChannelManagerGetDrdynvcState(client->vcm) == DRDYNVC_STATE_NONE) { /* Call this routine to Initialize drdynvc channel */ if (!WTSVirtualChannelManagerCheckFileDescriptor(client->vcm)) @@ -1361,7 +1521,7 @@ static void* shadow_client_thread(rdpShadowClient* client) break; } } - else if (((WTSVirtualChannelManager*)(client->vcm))->drdynvc_state == DRDYNVC_STATE_READY) + else if (WTSVirtualChannelManagerGetDrdynvcState(client->vcm) == DRDYNVC_STATE_READY) { /* Init RDPGFX dynamic channel */ if (settings->SupportGraphicsPipeline && client->rdpgfx && @@ -1369,7 +1529,7 @@ static void* shadow_client_thread(rdpShadowClient* client) { if (!client->rdpgfx->Open(client->rdpgfx)) { - WLog_ERR(TAG, "Failed to open GraphicsPipeline"); + WLog_WARN(TAG, "Failed to open GraphicsPipeline"); settings->SupportGraphicsPipeline = FALSE; } @@ -1465,7 +1625,8 @@ static void* shadow_client_thread(rdpShadowClient* client) { if (gfxstatus.gfxSurfaceCreated) { - shadow_client_rdpgfx_release_surface(client); + if (!shadow_client_rdpgfx_release_surface(client)) + WLog_WARN(TAG, "GFX release surface failure!"); } (void)client->rdpgfx->Close(client->rdpgfx); } @@ -1484,7 +1645,7 @@ static void* shadow_client_thread(rdpShadowClient* client) out: peer->Disconnect(peer); - + freerdp_peer_context_free(peer); freerdp_peer_free(peer); ExitThread(0); diff --git a/server/shadow/shadow_client.h b/server/shadow/shadow_client.h index a78e5411a..789dde5cc 100644 --- a/server/shadow/shadow_client.h +++ b/server/shadow/shadow_client.h @@ -25,7 +25,7 @@ extern "C" { #endif -int shadow_client_surface_update(rdpShadowClient* client, REGION16* region); +BOOL shadow_client_surface_update(rdpShadowClient* client, REGION16* region); BOOL shadow_client_accepted(freerdp_listener* instance, freerdp_peer* client); #ifdef __cplusplus