From 2b6bd2626dee3ecd1db28f6ef01a404285d7dfa6 Mon Sep 17 00:00:00 2001 From: "zihao.jiang" Date: Wed, 4 May 2016 00:48:59 +0800 Subject: [PATCH] rdpgfx: various fixes according to comments 1. Fix stream leak in rdpgfx 2. Make src data const in zgfx. Harden zgfx to be independent to byte order 3. Fix written bytes return value in channel write 4. Add check for return value in shadow_client.c 5. Add gfx callback to send surface command with frame marker pdu. 6. Check remain length for recv subroutine 7. Fix compile errors --- channels/rdpgfx/server/CMakeLists.txt | 2 +- channels/rdpgfx/server/rdpgfx_main.c | 739 +++++++++++++++++++------- channels/server/channels.c | 3 + include/freerdp/channels/wtsvc.h | 8 + include/freerdp/codec/zgfx.h | 10 +- include/freerdp/server/rdpgfx.h | 82 +-- libfreerdp/codec/zgfx.c | 62 ++- libfreerdp/core/server.c | 13 +- libfreerdp/core/server.h | 7 - server/shadow/Mac/mac_shadow.c | 9 +- server/shadow/shadow_client.c | 339 ++++++++---- server/shadow/shadow_client.h | 2 +- 12 files changed, 914 insertions(+), 362 deletions(-) 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