From 746a754244af9310119251e8436cdbd2a90a6caa Mon Sep 17 00:00:00 2001 From: "zihao.jiang" Date: Sun, 24 Apr 2016 01:49:10 +0800 Subject: [PATCH 1/8] rdpgfx: Implementation for server side channel server/shadow: support h264 codec with gfx channel --- channels/rdpgfx/CMakeLists.txt | 3 + channels/rdpgfx/client/CMakeLists.txt | 4 +- channels/rdpgfx/{client => }/rdpgfx_common.c | 3 +- channels/rdpgfx/{client => }/rdpgfx_common.h | 0 channels/rdpgfx/server/CMakeLists.txt | 34 + channels/rdpgfx/server/rdpgfx_main.c | 1239 ++++++++++++++++++ channels/rdpgfx/server/rdpgfx_main.h | 36 + include/freerdp/channels/rdpgfx.h | 9 + include/freerdp/codec/zgfx.h | 7 +- include/freerdp/server/rdpgfx.h | 96 ++ include/freerdp/server/shadow.h | 27 +- libfreerdp/codec/test/TestFreeRDPCodecZGfx.c | 209 ++- libfreerdp/codec/zgfx.c | 102 +- server/shadow/CMakeLists.txt | 2 + server/shadow/Mac/mac_shadow.c | 52 +- server/shadow/Win/win_dxgi.c | 5 +- server/shadow/Win/win_rdp.c | 3 +- server/shadow/Win/win_shadow.c | 10 +- server/shadow/X11/x11_shadow.c | 54 +- server/shadow/shadow_channels.c | 10 + server/shadow/shadow_channels.h | 1 + server/shadow/shadow_client.c | 641 ++++++--- server/shadow/shadow_encoder.c | 98 +- server/shadow/shadow_encoder.h | 1 + server/shadow/shadow_rdpgfx.c | 87 ++ server/shadow/shadow_rdpgfx.h | 38 + server/shadow/shadow_subsystem.c | 5 - 27 files changed, 2432 insertions(+), 344 deletions(-) rename channels/rdpgfx/{client => }/rdpgfx_common.c (98%) rename channels/rdpgfx/{client => }/rdpgfx_common.h (100%) create mode 100644 channels/rdpgfx/server/CMakeLists.txt create mode 100644 channels/rdpgfx/server/rdpgfx_main.c create mode 100644 channels/rdpgfx/server/rdpgfx_main.h create mode 100644 include/freerdp/server/rdpgfx.h create mode 100644 server/shadow/shadow_rdpgfx.c create mode 100644 server/shadow/shadow_rdpgfx.h diff --git a/channels/rdpgfx/CMakeLists.txt b/channels/rdpgfx/CMakeLists.txt index acc50da70..04820de9d 100644 --- a/channels/rdpgfx/CMakeLists.txt +++ b/channels/rdpgfx/CMakeLists.txt @@ -21,3 +21,6 @@ if(WITH_CLIENT_CHANNELS) add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME}) endif() +if(WITH_SERVER_CHANNELS) + add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME}) +endif() diff --git a/channels/rdpgfx/client/CMakeLists.txt b/channels/rdpgfx/client/CMakeLists.txt index 19c5d21b0..0de358a2e 100644 --- a/channels/rdpgfx/client/CMakeLists.txt +++ b/channels/rdpgfx/client/CMakeLists.txt @@ -22,8 +22,8 @@ set(${MODULE_PREFIX}_SRCS rdpgfx_main.h rdpgfx_codec.c rdpgfx_codec.h - rdpgfx_common.c - rdpgfx_common.h) + ../rdpgfx_common.c + ../rdpgfx_common.h) include_directories(..) diff --git a/channels/rdpgfx/client/rdpgfx_common.c b/channels/rdpgfx/rdpgfx_common.c similarity index 98% rename from channels/rdpgfx/client/rdpgfx_common.c rename to channels/rdpgfx/rdpgfx_common.c index a7518a5f0..849554dd3 100644 --- a/channels/rdpgfx/client/rdpgfx_common.c +++ b/channels/rdpgfx/rdpgfx_common.c @@ -54,7 +54,8 @@ const char* RDPGFX_CMDID_STRINGS[] = "RDPGFX_CMDID_CAPSADVERTISE", "RDPGFX_CMDID_CAPSCONFIRM", "RDPGFX_CMDID_UNUSED_0014", - "RDPGFX_CMDID_MAPSURFACETOWINDOW" + "RDPGFX_CMDID_MAPSURFACETOWINDOW", + "RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE" }; const char* rdpgfx_get_cmd_id_string(UINT16 cmdId) diff --git a/channels/rdpgfx/client/rdpgfx_common.h b/channels/rdpgfx/rdpgfx_common.h similarity index 100% rename from channels/rdpgfx/client/rdpgfx_common.h rename to channels/rdpgfx/rdpgfx_common.h diff --git a/channels/rdpgfx/server/CMakeLists.txt b/channels/rdpgfx/server/CMakeLists.txt new file mode 100644 index 000000000..b4aadc24f --- /dev/null +++ b/channels/rdpgfx/server/CMakeLists.txt @@ -0,0 +1,34 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2012 Marc-Andre Moreau +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +define_channel_server("rdpgfx") + +set(${MODULE_PREFIX}_SRCS + rdpgfx_main.c + rdpgfx_main.h + ../rdpgfx_common.c + ../rdpgfx_common.h) + +include_directories(..) + +add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "DVCPluginEntry") + + + +target_link_libraries(${MODULE_NAME} freerdp) + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server") diff --git a/channels/rdpgfx/server/rdpgfx_main.c b/channels/rdpgfx/server/rdpgfx_main.c new file mode 100644 index 000000000..ee3126290 --- /dev/null +++ b/channels/rdpgfx/server/rdpgfx_main.c @@ -0,0 +1,1239 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Graphics Pipeline Extension + * + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "rdpgfx_common.h" +#include "rdpgfx_main.h" + +#define TAG CHANNELS_TAG("rdpgfx.server") +#define RDPGFX_RESET_GRAPHICS_PDU_SIZE 340 + +/** + * 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. + * + * @return new stream + */ +static wStream* rdpgfx_server_packet_new(UINT16 cmdId, UINT32 dataLen) +{ + UINT error; + wStream* s; + RDPGFX_HEADER header; + + header.flags = 0; + header.cmdId = cmdId; + header.pduLength = RDPGFX_HEADER_SIZE + dataLen; + + 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 + * 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; +} + +/** + * Function description + * Send the stream for rdpgfx packet. The packet would be compressed + * according to [MS-RDPEGFX]. + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpgfx_server_packet_send(RdpgfxServerContext* context, wStream* s) +{ + UINT error; + UINT32 flags = 0; + ULONG written; + BYTE* pSrcData = Stream_Buffer(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 (zgfx_compress_to_stream(context->priv->zgfx, fs, pSrcData, SrcSize, &flags) < 0) + { + WLog_ERR(TAG, "zgfx_compress_to_stream failed!"); + error = ERROR_INTERNAL_ERROR; + goto out; + } + + error = WTSVirtualChannelWrite(context->priv->rdpgfx_channel, (PCHAR) Stream_Buffer(fs), + Stream_GetPosition(fs), &written) + ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; + +out: + Stream_Free(fs, TRUE); + Stream_Free(s, TRUE); + + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +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( + RDPGFX_CMDID_CAPSCONFIRM, + sizeof(RDPGFX_CAPSET) + sizeof(capsSet->flags)); + + if (!s) + { + WLog_ERR(TAG, "rdpgfx_server_packet_new failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + Stream_Write_UINT32(s, capsSet->version); /* version (4 bytes) */ + 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); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpgfx_send_reset_graphics_pdu(RdpgfxServerContext* context, RDPGFX_RESET_GRAPHICS_PDU* pdu) +{ + UINT32 index; + MONITOR_DEF* monitor; + wStream* s = rdpgfx_server_packet_new( + RDPGFX_CMDID_RESETGRAPHICS, + RDPGFX_RESET_GRAPHICS_PDU_SIZE - RDPGFX_HEADER_SIZE); + + if (!s) + { + WLog_ERR(TAG, "rdpgfx_server_packet_new failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + Stream_Write_UINT32(s, pdu->width); /* width (4 bytes) */ + Stream_Write_UINT32(s, pdu->height); /* height (4 bytes) */ + Stream_Write_UINT32(s, pdu->monitorCount); /* monitorCount (4 bytes) */ + + for (index = 0; index < pdu->monitorCount; index++) + { + monitor = &(pdu->monitorDefArray[index]); + Stream_Write_UINT32(s, monitor->left); /* left (4 bytes) */ + Stream_Write_UINT32(s, monitor->top); /* top (4 bytes) */ + Stream_Write_UINT32(s, monitor->right); /* right (4 bytes) */ + Stream_Write_UINT32(s, monitor->bottom); /* bottom (4 bytes) */ + Stream_Write_UINT32(s, monitor->flags); /* flags (4 bytes) */ + } + + /* 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); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpgfx_send_evict_cache_entry_pdu(RdpgfxServerContext* context, RDPGFX_EVICT_CACHE_ENTRY_PDU* pdu) +{ + wStream* s = rdpgfx_server_packet_new( + RDPGFX_CMDID_EVICTCACHEENTRY, + sizeof(RDPGFX_EVICT_CACHE_ENTRY_PDU)); + + if (!s) + { + WLog_ERR(TAG, "rdpgfx_server_packet_new failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + Stream_Write_UINT16(s, pdu->cacheSlot); /* cacheSlot (2 bytes) */ + + return rdpgfx_server_packet_send(context, s); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpgfx_send_cache_import_reply_pdu(RdpgfxServerContext* context, RDPGFX_CACHE_IMPORT_REPLY_PDU* pdu) +{ + UINT16 index; + wStream* s = rdpgfx_server_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!"); + return CHANNEL_RC_NO_MEMORY; + } + + Stream_Write_UINT16(s, pdu->importedEntriesCount); /* importedEntriesCount (2 bytes) */ + for (index = 0; index < pdu->importedEntriesCount; index++) + { + Stream_Write_UINT16(s, pdu->cacheSlots[index]); /* cacheSlot (2 bytes) */ + } + + return rdpgfx_server_packet_send(context, s); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpgfx_send_create_surface_pdu(RdpgfxServerContext* context, RDPGFX_CREATE_SURFACE_PDU* pdu) +{ + wStream* s = rdpgfx_server_packet_new( + RDPGFX_CMDID_CREATESURFACE, + sizeof(RDPGFX_CREATE_SURFACE_PDU)); + + if (!s) + { + WLog_ERR(TAG, "rdpgfx_server_packet_new failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */ + Stream_Write_UINT16(s, pdu->width); /* width (2 bytes) */ + 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); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +UINT rdpgfx_send_delete_surface_pdu(RdpgfxServerContext* context, RDPGFX_DELETE_SURFACE_PDU* pdu) +{ + wStream* s = rdpgfx_server_packet_new( + RDPGFX_CMDID_DELETESURFACE, + sizeof(RDPGFX_DELETE_SURFACE_PDU)); + + if (!s) + { + WLog_ERR(TAG, "rdpgfx_server_packet_new failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */ + + return rdpgfx_server_packet_send(context, s); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpgfx_send_start_frame_pdu(RdpgfxServerContext* context, RDPGFX_START_FRAME_PDU* pdu) +{ + wStream* s = rdpgfx_server_packet_new( + RDPGFX_CMDID_STARTFRAME, + sizeof(RDPGFX_START_FRAME_PDU)); + + if (!s) + { + WLog_ERR(TAG, "rdpgfx_server_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) */ + + return rdpgfx_server_packet_send(context, s); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpgfx_send_end_frame_pdu(RdpgfxServerContext* context, RDPGFX_END_FRAME_PDU* pdu) +{ + wStream* s = rdpgfx_server_packet_new( + RDPGFX_CMDID_ENDFRAME, + sizeof(RDPGFX_END_FRAME_PDU)); + + if (!s) + { + WLog_ERR(TAG, "rdpgfx_server_packet_new failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + Stream_Write_UINT32(s, pdu->frameId); /* frameId (4 bytes) */ + + return rdpgfx_server_packet_send(context, s); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpgfx_write_h264_metablock(RdpgfxServerContext* context, wStream* s, + RDPGFX_H264_METABLOCK* meta) +{ + UINT32 index; + RECTANGLE_16* regionRect; + RDPGFX_H264_QUANT_QUALITY* quantQualityVal; + UINT error = CHANNEL_RC_OK; + + Stream_Write_UINT32(s, meta->numRegionRects); /* numRegionRects (4 bytes) */ + + for (index = 0; index < meta->numRegionRects; index++) + { + regionRect = &(meta->regionRects[index]); + if ((error = rdpgfx_write_rect16(s, regionRect))) + { + WLog_ERR(TAG, "rdpgfx_write_rect16 failed with error %lu!", error); + return error; + } + } + + for (index = 0; index < meta->numRegionRects; index++) + { + quantQualityVal = &(meta->quantQualityVals[index]); + + Stream_Write_UINT8(s, quantQualityVal->qp + | (quantQualityVal->r << 6) + | (quantQualityVal->p << 7)); /* qpVal (1 byte) */ + Stream_Write_UINT8(s, quantQualityVal->qualityVal); /* qualityVal (1 byte) */ + } + + return error; +} + +/** + * Function description + * Write RFX_AVC420_BITMAP_STREAM structure to stream + * + * @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) +{ + UINT error = CHANNEL_RC_OK; + if ((error = rdpgfx_write_h264_metablock(context, s, &(havc420->meta)))) + { + WLog_ERR(TAG, "rdpgfx_write_h264_metablock failed with error %lu!", error); + return error; + } + + Stream_Write(s, havc420->data, havc420->length); + return error; +} + +/** + * 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 + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpgfx_send_surface_command(RdpgfxServerContext* context, RDPGFX_SURFACE_COMMAND* cmd) +{ + wStream* s; + 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) + { + 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) */ + Stream_Write_UINT8(s, cmd->format); /* pixelFormat (1 byte) */ + + Stream_Write_UINT32(s, cmd->length); /* bitmapDataLength (4 bytes) */ + Stream_Write(s, cmd->data, cmd->length); + + return rdpgfx_server_packet_send(context, s); + } + else + { + 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) */ + + Stream_Write_UINT16(s, cmd->left); /* left (2 bytes) */ + Stream_Write_UINT16(s, cmd->top); /* top (2 bytes) */ + Stream_Write_UINT16(s, cmd->right); /* right (2 bytes) */ + Stream_Write_UINT16(s, cmd->bottom); /* bottom (2 bytes) */ + + Stream_Write_UINT32(s, cmd->length); /* bitmapDataLength (4 bytes) */ + bitmapDataStart = Stream_GetPosition(s); + + if (cmd->codecId == RDPGFX_CODECID_AVC420) + { + havc420 = (RDPGFX_AVC420_BITMAP_STREAM *)cmd->extra; + rdpgfx_write_h264_avc420(context, s, havc420); + } + else if (cmd->codecId == RDPGFX_CODECID_AVC444) + { + havc444 = (RDPGFX_AVC444_BITMAP_STREAM *)cmd->extra; + havc420 = &(havc444->bitstream[0]); + + /* avc420EncodedBitstreamInfo (4 bytes) */ + Stream_Write_UINT32(s, havc420->length | (havc444->LC << 30UL)); + + /* avc420EncodedBitstream1 */ + rdpgfx_write_h264_avc420(context, s, havc420); + + /* avc420EncodedBitstream2 */ + if (havc444->LC == 0) + { + havc420 = &(havc444->bitstream[0]); + rdpgfx_write_h264_avc420(context, s, havc420); + } + } + else + { + Stream_Write(s, cmd->data, cmd->length); + } + + assert(Stream_GetPosition(s) <= Stream_Capacity(s)); + + /* Fill actual bitmap data length */ + bitmapDataLength = Stream_GetPosition(s) - bitmapDataStart; + 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); + } +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpgfx_send_delete_encoding_context_pdu(RdpgfxServerContext* context, RDPGFX_DELETE_ENCODING_CONTEXT_PDU* pdu) +{ + wStream* s = rdpgfx_server_packet_new( + RDPGFX_CMDID_DELETEENCODINGCONTEXT, + sizeof(RDPGFX_DELETE_ENCODING_CONTEXT_PDU)); + + if (!s) + { + WLog_ERR(TAG, "rdpgfx_server_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); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +UINT rdpgfx_send_solid_fill_pdu(RdpgfxServerContext* context, RDPGFX_SOLID_FILL_PDU* pdu) +{ + UINT16 index; + RECTANGLE_16* fillRect; + UINT error; + wStream* s = rdpgfx_server_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!"); + return CHANNEL_RC_NO_MEMORY; + } + + Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */ + if ((error = rdpgfx_write_color32(s, &(pdu->fillPixel)))) /* fillPixel (4 bytes) */ + { + WLog_ERR(TAG, "rdpgfx_write_color32 failed with error %lu!", error); + return error; + } + + Stream_Write_UINT16(s, pdu->fillRectCount); /* fillRectCount (2 bytes) */ + for (index = 0; index < pdu->fillRectCount; index++) + { + fillRect = &(pdu->fillRects[index]); + if ((error = rdpgfx_write_rect16(s, fillRect))) + { + WLog_ERR(TAG, "rdpgfx_write_rect16 failed with error %lu!", error); + return error; + } + } + + return rdpgfx_server_packet_send(context, s); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpgfx_send_surface_to_surface_pdu(RdpgfxServerContext* context, RDPGFX_SURFACE_TO_SURFACE_PDU* pdu) +{ + UINT16 index; + UINT error; + RDPGFX_POINT16* destPt; + wStream* s = rdpgfx_server_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!"); + return CHANNEL_RC_NO_MEMORY; + } + + Stream_Write_UINT16(s, pdu->surfaceIdSrc); /* surfaceIdSrc (2 bytes) */ + Stream_Write_UINT16(s, pdu->surfaceIdDest); /* surfaceIdDest (2 bytes) */ + + if ((error = rdpgfx_write_rect16(s, &(pdu->rectSrc)))) /* rectSrc (8 bytes ) */ + { + WLog_ERR(TAG, "rdpgfx_write_rect16 failed with error %lu!", error); + return error; + } + + Stream_Write_UINT16(s, pdu->destPtsCount); /* destPtsCount (2 bytes) */ + for (index = 0; index < pdu->destPtsCount; index++) + { + destPt = &(pdu->destPts[index]); + if ((error = rdpgfx_write_point16(s, destPt))) + { + WLog_ERR(TAG, "rdpgfx_write_point16 failed with error %lu!", error); + return error; + } + } + + return rdpgfx_server_packet_send(context, s); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpgfx_send_surface_to_cache_pdu(RdpgfxServerContext* context, RDPGFX_SURFACE_TO_CACHE_PDU* pdu) +{ + UINT error; + wStream* s = rdpgfx_server_packet_new( + RDPGFX_CMDID_SURFACETOCACHE, + sizeof(RDPGFX_SURFACE_TO_CACHE_PDU)); + + if (!s) + { + WLog_ERR(TAG, "rdpgfx_server_packet_new failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */ + Stream_Write_UINT64(s, pdu->cacheKey); /* cacheKey (8 bytes) */ + Stream_Write_UINT16(s, pdu->cacheSlot); /* cacheSlot (2 bytes) */ + if ((error = rdpgfx_write_rect16(s, &(pdu->rectSrc)))) /* rectSrc (8 bytes ) */ + { + WLog_ERR(TAG, "rdpgfx_write_rect16 failed with error %lu!", error); + return error; + } + + return rdpgfx_server_packet_send(context, s); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpgfx_send_cache_to_surface_pdu(RdpgfxServerContext* context, RDPGFX_CACHE_TO_SURFACE_PDU* pdu) +{ + UINT16 index; + UINT error; + RDPGFX_POINT16* destPt; + wStream* s = rdpgfx_server_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!"); + return CHANNEL_RC_NO_MEMORY; + } + + Stream_Write_UINT16(s, pdu->cacheSlot); /* cacheSlot (2 bytes) */ + Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */ + Stream_Write_UINT16(s, pdu->destPtsCount); /* destPtsCount (2 bytes) */ + + for (index = 0; index < pdu->destPtsCount; index++) + { + destPt = &(pdu->destPts[index]); + if ((error = rdpgfx_write_point16(s, destPt))) + { + WLog_ERR(TAG, "rdpgfx_write_point16 failed with error %lu", error); + return error; + } + } + + return rdpgfx_server_packet_send(context, s); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpgfx_send_map_surface_to_output_pdu(RdpgfxServerContext* context, RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU* pdu) +{ + wStream* s = rdpgfx_server_packet_new( + RDPGFX_CMDID_MAPSURFACETOOUTPUT, + sizeof(RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU)); + + if (!s) + { + WLog_ERR(TAG, "rdpgfx_server_packet_new failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */ + Stream_Write_UINT16(s, 0); /* reserved (2 bytes). Must be 0 */ + 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); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpgfx_send_map_surface_to_window_pdu(RdpgfxServerContext* context, RDPGFX_MAP_SURFACE_TO_WINDOW_PDU* pdu) +{ + wStream* s = rdpgfx_server_packet_new( + RDPGFX_CMDID_MAPSURFACETOWINDOW, + sizeof(RDPGFX_MAP_SURFACE_TO_WINDOW_PDU)); + + if (!s) + { + WLog_ERR(TAG, "rdpgfx_server_packet_new failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */ + Stream_Write_UINT64(s, pdu->windowId); /* windowId (8 bytes) */ + 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); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpgfx_recv_frame_acknowledge_pdu(RdpgfxServerContext* context, wStream* s) +{ + RDPGFX_FRAME_ACKNOWLEDGE_PDU pdu; + UINT error = CHANNEL_RC_OK; + + 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) */ + + if (context) + { + IFCALLRET(context->FrameAcknowledge, error, context, &pdu); + if (error) + WLog_ERR(TAG, "context->FrameAcknowledge failed with error %lu", error); + } + + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpgfx_recv_cache_import_offer_pdu(RdpgfxServerContext* context, wStream* s) +{ + UINT16 index; + RDPGFX_CACHE_IMPORT_OFFER_PDU pdu; + RDPGFX_CACHE_ENTRY_METADATA* cacheEntries; + UINT error = CHANNEL_RC_OK; + + Stream_Read_UINT16(s, pdu.cacheEntriesCount); /* cacheEntriesCount (2 bytes) */ + pdu.cacheEntries = (RDPGFX_CACHE_ENTRY_METADATA*) + calloc(pdu.cacheEntriesCount, sizeof(RDPGFX_CACHE_ENTRY_METADATA)); + + if (!pdu.cacheEntries) + { + WLog_ERR(TAG, "calloc failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + for (index = 0; index < pdu.cacheEntriesCount; index++) + { + cacheEntries = &(pdu.cacheEntries[index]); + Stream_Read_UINT64(s, cacheEntries->cacheKey); /* cacheKey (8 bytes) */ + Stream_Read_UINT32(s, cacheEntries->bitmapLength); /* bitmapLength (4 bytes) */ + } + + if (context) + { + IFCALLRET(context->CacheImportOffer, error, context, &pdu); + if (error) + WLog_ERR(TAG, "context->CacheImportOffer failed with error %lu", error); + } + + free(pdu.cacheEntries); + + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpgfx_recv_caps_advertise_pdu(RdpgfxServerContext* context, wStream* s) +{ + UINT16 index; + RDPGFX_CAPSET* capsSet; + RDPGFX_CAPSET capsSets[3]; + RDPGFX_CAPS_ADVERTISE_PDU pdu; + UINT error = CHANNEL_RC_OK; + + Stream_Read_UINT16(s, pdu.capsSetCount); /* capsSetCount (2 bytes) */ + 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, capsSet->flags); /* capsData (4 bytes) */ + } + + if (context) + { + IFCALLRET(context->CapsAdvertise, error, context, &pdu); + if (error) + WLog_ERR(TAG, "context->CapsAdvertise failed with error %lu", error); + } + + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpgfx_recv_qoe_frame_acknowledge_pdu(RdpgfxServerContext* context, wStream* s) +{ + RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU pdu; + UINT error = CHANNEL_RC_OK; + + 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) */ + Stream_Read_UINT16(s, pdu.timeDiffEDR); /* timeDiffEDR (2 bytes) */ + + if (context) + { + IFCALLRET(context->QoeFrameAcknowledge, error, context, &pdu); + if (error) + WLog_ERR(TAG, "context->QoeFrameAcknowledge failed with error %lu", error); + } + + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpgfx_server_receive_pdu(RdpgfxServerContext* context, wStream* s) +{ + int beg, end; + RDPGFX_HEADER header; + UINT error = CHANNEL_RC_OK; + + beg = Stream_GetPosition(s); + + if ((error = rdpgfx_read_header(s, &header))) + { + WLog_ERR(TAG, "rdpgfx_read_header failed with error %lu!", error); + return error; + } + + WLog_DBG(TAG, "cmdId: %s (0x%04X) flags: 0x%04X pduLength: %d", + rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId, header.flags, header.pduLength); + + switch (header.cmdId) + { + case RDPGFX_CMDID_FRAMEACKNOWLEDGE: + if ((error = rdpgfx_recv_frame_acknowledge_pdu(context, s))) + WLog_ERR(TAG, "rdpgfx_recv_frame_acknowledge_pdu failed with error %lu!", error); + break; + + case RDPGFX_CMDID_CACHEIMPORTOFFER: + if ((error = rdpgfx_recv_cache_import_offer_pdu(context, s))) + WLog_ERR(TAG, "rdpgfx_recv_cache_import_offer_pdu failed with error %lu!", error); + break; + + case RDPGFX_CMDID_CAPSADVERTISE: + if ((error = rdpgfx_recv_caps_advertise_pdu(context, s))) + WLog_ERR(TAG, "rdpgfx_recv_caps_advertise_pdu failed with error %lu!", error); + break; + + case RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE: + if ((error = rdpgfx_recv_qoe_frame_acknowledge_pdu(context, s))) + WLog_ERR(TAG, "rdpgfx_recv_qoe_frame_acknowledge_pdu failed with error %lu!", error); + break; + + default: + error = CHANNEL_RC_BAD_PROC; + break; + } + + if (error) + { + WLog_ERR(TAG, "Error while parsing GFX cmdId: %s (0x%04X)", + rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId); + return error; + } + + end = Stream_GetPosition(s); + + if (end != (beg + header.pduLength)) + { + WLog_ERR(TAG, "Unexpected gfx pdu end: Actual: %d, Expected: %d", + end, (beg + header.pduLength)); + Stream_SetPosition(s, (beg + header.pduLength)); + } + + return error; + +} + +static void* rdpgfx_server_thread_func(void* arg) +{ + RdpgfxServerContext* context = (RdpgfxServerContext*) arg; + RdpgfxServerPrivate* priv = context->priv; + wStream* s; + DWORD status; + DWORD nCount; + void* buffer; + HANDLE events[8]; + HANDLE ChannelEvent; + DWORD BytesReturned = 0; + UINT error = CHANNEL_RC_OK; + BOOL ready = FALSE; + + buffer = NULL; + BytesReturned = 0; + ChannelEvent = NULL; + + /* Query for channel event handle */ + if (WTSVirtualChannelQuery(priv->rdpgfx_channel, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE) + { + if (BytesReturned == sizeof(HANDLE)) + CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); + + WTSFreeMemory(buffer); + } + else + { + WLog_ERR(TAG, "WTSVirtualChannelQuery failed"); + error = ERROR_INTERNAL_ERROR; + goto out; + } + + nCount = 0; + events[nCount++] = priv->stopEvent; + events[nCount++] = ChannelEvent; + + /* Wait for the client to confirm that the dynamic channel is ready */ + while (1) + { + if ((status = WaitForMultipleObjects(nCount, events, FALSE, 100)) == WAIT_OBJECT_0) + goto out; + + if (status == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %lu", error); + goto out; + } + + if (WTSVirtualChannelQuery(priv->rdpgfx_channel, WTSVirtualChannelReady, &buffer, &BytesReturned) == FALSE) + { + WLog_ERR(TAG, "WTSVirtualChannelQuery failed"); + error = ERROR_INTERNAL_ERROR; + goto out; + } + + ready = *((BOOL*) buffer); + + WTSFreeMemory(buffer); + + if (ready) + break; + } + + /* Create shared stream */ + s = Stream_New(NULL, 4096); + if (!s) + { + WLog_ERR(TAG, "Stream_New failed!"); + error = CHANNEL_RC_NO_MEMORY; + goto out; + } + + /* Main virtual channel loop. RDPGFX do not need version negotiation */ + while (ready) + { + status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); + + if (status == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %lu", error); + goto out; + } + + /* Stop Event */ + if (status == WAIT_OBJECT_0) + break; + + /* Channel Event */ + Stream_SetPosition(s, 0); + + if (!WTSVirtualChannelRead(priv->rdpgfx_channel, 0, NULL, 0, &BytesReturned)) + { + WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); + error = ERROR_INTERNAL_ERROR; + break; + } + + if (BytesReturned < 1) + continue; + + if (!Stream_EnsureRemainingCapacity(s, BytesReturned)) + { + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + error = CHANNEL_RC_NO_MEMORY; + break; + } + + if (WTSVirtualChannelRead(priv->rdpgfx_channel, 0, (PCHAR) Stream_Buffer(s), + Stream_Capacity(s), &BytesReturned) == FALSE) + { + WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); + error = ERROR_INTERNAL_ERROR; + break; + } + + Stream_SetLength(s, BytesReturned); + Stream_SetPosition(s, 0); + if ((error = rdpgfx_server_receive_pdu(context, s))) + { + WLog_ERR(TAG, "rdpgfx_server_receive_pdu failed with error %lu!", error); + break; + } + Stream_SetPosition(s, 0); + } + + Stream_Free(s, TRUE); +out: + WTSVirtualChannelClose(priv->rdpgfx_channel); + priv->rdpgfx_channel = NULL; + if (error && context->rdpcontext) + setChannelError(context->rdpcontext, error, "rdpgfx_server_thread_func reported an error"); + + ExitThread((DWORD)error); + return NULL; +} + +static BOOL rdpgfx_server_open(RdpgfxServerContext* context) +{ + RdpgfxServerPrivate* priv = (RdpgfxServerPrivate *) context->priv; + + if (!priv->thread) + { + PULONG pSessionId = NULL; + DWORD BytesReturned = 0; + + priv->SessionId = WTS_CURRENT_SESSION; + + if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, + WTSSessionId, (LPSTR*) &pSessionId, &BytesReturned)) + { + priv->SessionId = (DWORD) *pSessionId; + WTSFreeMemory(pSessionId); + } + + priv->rdpgfx_channel = WTSVirtualChannelOpenEx(priv->SessionId, + RDPGFX_DVC_CHANNEL_NAME, WTS_CHANNEL_OPTION_DYNAMIC); + + if (!priv->rdpgfx_channel) + { + WLog_ERR(TAG, "WTSVirtualChannelOpenEx failed!"); + return FALSE; + } + + if (!(priv->zgfx = zgfx_context_new(TRUE))) + { + WLog_ERR(TAG, "Create zgfx context failed!"); + return FALSE; + } + + if (!(priv->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) + { + WLog_ERR(TAG, "CreateEvent failed!"); + return FALSE; + } + + 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; + } + + return TRUE; + } + WLog_ERR(TAG, "thread already running!"); + return FALSE; +} + +static BOOL rdpgfx_server_close(RdpgfxServerContext* context) +{ + RdpgfxServerPrivate* priv = (RdpgfxServerPrivate *) context->priv; + + if (priv->thread) + { + SetEvent(priv->stopEvent); + if (WaitForSingleObject(priv->thread, INFINITE) == WAIT_FAILED) + { + WLog_ERR(TAG, "WaitForSingleObject failed with error %lu", GetLastError()); + return FALSE; + } + + CloseHandle(priv->thread); + CloseHandle(priv->stopEvent); + priv->thread = NULL; + priv->stopEvent = NULL; + } + + zgfx_context_free(priv->zgfx); + priv->zgfx = NULL; + + if (priv->rdpgfx_channel) + { + WTSVirtualChannelClose(priv->rdpgfx_channel); + priv->rdpgfx_channel = NULL; + } + + return TRUE; +} + +RdpgfxServerContext* rdpgfx_server_context_new(HANDLE vcm) +{ + RdpgfxServerContext* context; + RdpgfxServerPrivate *priv; + + context = (RdpgfxServerContext *)calloc(1, sizeof(RdpgfxServerContext)); + if (!context) + { + WLog_ERR(TAG, "calloc failed!"); + return NULL; + } + + context->vcm = vcm; + context->Open = rdpgfx_server_open; + context->Close = rdpgfx_server_close; + + context->ResetGraphics = rdpgfx_send_reset_graphics_pdu; + context->StartFrame = rdpgfx_send_start_frame_pdu; + context->EndFrame = rdpgfx_send_end_frame_pdu; + context->SurfaceCommand = rdpgfx_send_surface_command; + context->DeleteEncodingContext = rdpgfx_send_delete_encoding_context_pdu; + context->CreateSurface = rdpgfx_send_create_surface_pdu; + context->DeleteSurface = rdpgfx_send_delete_surface_pdu; + context->SolidFill = rdpgfx_send_solid_fill_pdu; + context->SurfaceToSurface = rdpgfx_send_surface_to_surface_pdu; + context->SurfaceToCache = rdpgfx_send_surface_to_cache_pdu; + context->CacheToSurface = rdpgfx_send_cache_to_surface_pdu; + context->CacheImportOffer = NULL; + context->CacheImportReply = rdpgfx_send_cache_import_reply_pdu; + context->EvictCacheEntry = rdpgfx_send_evict_cache_entry_pdu; + context->MapSurfaceToOutput = rdpgfx_send_map_surface_to_output_pdu; + context->MapSurfaceToWindow = rdpgfx_send_map_surface_to_window_pdu; + context->CapsAdvertise = NULL; + context->CapsConfirm = rdpgfx_send_caps_confirm_pdu; + context->FrameAcknowledge = NULL; + context->QoeFrameAcknowledge = NULL; + + context->priv = priv = (RdpgfxServerPrivate *)calloc(1, sizeof(RdpgfxServerPrivate)); + if (!priv) + { + WLog_ERR(TAG, "calloc failed!"); + goto out_free; + } + + return (RdpgfxServerContext*) context; + +out_free: + free(context); + return NULL; +} + +void rdpgfx_server_context_free(RdpgfxServerContext* context) +{ + rdpgfx_server_close(context); + + free(context->priv); + + free(context); +} diff --git a/channels/rdpgfx/server/rdpgfx_main.h b/channels/rdpgfx/server/rdpgfx_main.h new file mode 100644 index 000000000..caad8ccf1 --- /dev/null +++ b/channels/rdpgfx/server/rdpgfx_main.h @@ -0,0 +1,36 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Graphics Pipeline Extension + * + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_CHANNEL_RDPGFX_SERVER_MAIN_H +#define FREERDP_CHANNEL_RDPGFX_SERVER_MAIN_H + +#include +#include + +struct _rdpgfx_server_private +{ + ZGFX_CONTEXT* zgfx; + HANDLE thread; + HANDLE stopEvent; + void* rdpgfx_channel; + DWORD SessionId; + BOOL opened; +}; + +#endif /* FREERDP_CHANNEL_RDPGFX_SERVER_MAIN_H */ diff --git a/include/freerdp/channels/rdpgfx.h b/include/freerdp/channels/rdpgfx.h index e19714916..fdc643ba8 100644 --- a/include/freerdp/channels/rdpgfx.h +++ b/include/freerdp/channels/rdpgfx.h @@ -73,6 +73,7 @@ typedef BYTE RDPGFX_PIXELFORMAT; #define RDPGFX_CMDID_CAPSCONFIRM 0x0013 #define RDPGFX_CMDID_UNUSED_0014 0x0014 #define RDPGFX_CMDID_MAPSURFACETOWINDOW 0x0015 +#define RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE 0x0016 #define RDPGFX_HEADER_SIZE 8 @@ -372,6 +373,14 @@ struct _RDPGFX_AVC444_BITMAP_STREAM }; typedef struct _RDPGFX_AVC444_BITMAP_STREAM RDPGFX_AVC444_BITMAP_STREAM; +struct _RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU +{ + UINT32 frameId; + UINT32 timestamp; + UINT16 timeDiffSE; + UINT16 timeDiffEDR; +}; +typedef struct _RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU; #endif /* FREERDP_CHANNEL_RDPGFX_H */ diff --git a/include/freerdp/codec/zgfx.h b/include/freerdp/codec/zgfx.h index 6fd35825a..53a41f8f4 100644 --- a/include/freerdp/codec/zgfx.h +++ b/include/freerdp/codec/zgfx.h @@ -28,6 +28,10 @@ #define ZGFX_SEGMENTED_SINGLE 0xE0 #define ZGFX_SEGMENTED_MULTIPART 0xE1 +#define ZGFX_PACKET_COMPR_TYPE_RDP8 0x04 + +#define ZGFX_SEGMENTED_MAXSIZE 65535 + struct _ZGFX_CONTEXT { BOOL Compressor; @@ -53,8 +57,9 @@ typedef struct _ZGFX_CONTEXT ZGFX_CONTEXT; extern "C" { #endif -FREERDP_API int zgfx_compress(ZGFX_CONTEXT* zgfx, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags); 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 void zgfx_context_reset(ZGFX_CONTEXT* zgfx, BOOL flush); diff --git a/include/freerdp/server/rdpgfx.h b/include/freerdp/server/rdpgfx.h new file mode 100644 index 000000000..7f4d033bc --- /dev/null +++ b/include/freerdp/server/rdpgfx.h @@ -0,0 +1,96 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Graphics Pipeline Extension + * + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_CHANNEL_SERVER_RDPGFX_H +#define FREERDP_CHANNEL_SERVER_RDPGFX_H + +#include + +typedef struct _rdpgfx_server_context RdpgfxServerContext; +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); + +struct _rdpgfx_server_context +{ + HANDLE vcm; + void* custom; + + 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; + + RdpgfxServerPrivate* priv; + rdpContext* rdpcontext; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +FREERDP_API RdpgfxServerContext* rdpgfx_server_context_new(HANDLE vcm); +FREERDP_API void rdpgfx_server_context_free(RdpgfxServerContext* context); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_CHANNEL_SERVER_RDPGFX_H */ diff --git a/include/freerdp/server/shadow.h b/include/freerdp/server/shadow.h index 60bb87d79..e718ea015 100644 --- a/include/freerdp/server/shadow.h +++ b/include/freerdp/server/shadow.h @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -87,6 +88,7 @@ struct rdp_shadow_client BOOL inLobby; BOOL mayView; BOOL mayInteract; + BOOL suppressOutput; wMessageQueue* MsgQueue; CRITICAL_SECTION lock; REGION16 invalidRegion; @@ -102,6 +104,7 @@ struct rdp_shadow_client RemdeskServerContext* remdesk; RdpsndServerContext* rdpsnd; audin_server_context* audin; + RdpgfxServerContext* rdpgfx; }; struct rdp_shadow_server @@ -169,9 +172,12 @@ struct _RDP_SHADOW_ENTRY_POINTS int selectedMonitor; \ MONITOR_DEF monitors[16]; \ MONITOR_DEF virtualScreen; \ + \ + /* This event indicates that we have graphic change */ \ + /* such as screen update and resize. It should not be */ \ + /* used by subsystem implementation directly */ \ rdpShadowMultiClientEvent* updateEvent; \ - BOOL suppressOutput; \ - REGION16 invalidRegion; \ + \ wMessagePipe* MsgPipe; \ UINT32 pointerX; \ UINT32 pointerY; \ @@ -201,22 +207,7 @@ struct rdp_shadow_subsystem }; /* Definition of message between subsystem and clients */ -#define SHADOW_MSG_IN_REFRESH_OUTPUT_ID 1001 -#define SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID 1002 - -struct _SHADOW_MSG_IN_REFRESH_OUTPUT -{ - UINT32 numRects; - RECTANGLE_16* rects; -}; -typedef struct _SHADOW_MSG_IN_REFRESH_OUTPUT SHADOW_MSG_IN_REFRESH_OUTPUT; - -struct _SHADOW_MSG_IN_SUPPRESS_OUTPUT -{ - BOOL allow; - RECTANGLE_16 rect; -}; -typedef struct _SHADOW_MSG_IN_SUPPRESS_OUTPUT SHADOW_MSG_IN_SUPPRESS_OUTPUT; +#define SHADOW_MSG_IN_REFRESH_REQUEST_ID 1001 typedef struct _SHADOW_MSG_OUT SHADOW_MSG_OUT; typedef void (*MSG_OUT_FREE_FN)(UINT32 id, SHADOW_MSG_OUT* msg); /* function to free SHADOW_MSG_OUT */ diff --git a/libfreerdp/codec/test/TestFreeRDPCodecZGfx.c b/libfreerdp/codec/test/TestFreeRDPCodecZGfx.c index 7284424e5..ec71287c6 100644 --- a/libfreerdp/codec/test/TestFreeRDPCodecZGfx.c +++ b/libfreerdp/codec/test/TestFreeRDPCodecZGfx.c @@ -1,10 +1,217 @@ #include #include +#include +#include #include +#include -int TestFreeRDPCodecZGfx(int argc, char* argv[]) +/* Sample from [MS-RDPEGFX] */ +static const BYTE TEST_FOX_DATA[] = + "The quick brown " + "fox jumps over t" + "he lazy dog"; + +static const BYTE TEST_FOX_DATA_SINGLE[] = + "\xE0\x04\x54\x68\x65\x20\x71\x75\x69\x63\x6B\x20\x62\x72\x6F\x77" + "\x6E\x20\x66\x6F\x78\x20\x6A\x75\x6D\x70\x73\x20\x6F\x76\x65\x72" + "\x20\x74\x68\x65\x20\x6C\x61\x7A\x79\x20\x64\x6F\x67"; + +static const BYTE TEST_FOX_DATA_MULTIPART[] = + "\xE1\x03\x00\x2B\x00\x00\x00\x11\x00\x00\x00\x04\x54\x68\x65\x20" + "\x71\x75\x69\x63\x6B\x20\x62\x72\x6F\x77\x6E\x20\x0E\x00\x00\x00" + "\x04\x66\x6F\x78\x20\x6A\x75\x6D\x70\x73\x20\x6F\x76\x65\x10\x00" + "\x00\x00\x24\x39\x08\x0E\x91\xF8\xD8\x61\x3D\x1E\x44\x06\x43\x79" + "\x9C\x02"; + +int test_ZGfxCompressFox() { + int status; + UINT32 Flags; + BYTE* pSrcData; + UINT32 SrcSize; + UINT32 DstSize; + BYTE* pDstData; + ZGFX_CONTEXT* zgfx; + UINT32 expectedSize; + + zgfx = zgfx_context_new(TRUE); + SrcSize = sizeof(TEST_FOX_DATA) - 1; + pSrcData = (BYTE*) TEST_FOX_DATA; + Flags = 0; + expectedSize = sizeof(TEST_FOX_DATA_SINGLE) - 1; + status = zgfx_compress(zgfx, pSrcData, SrcSize, &pDstData, &DstSize, &Flags); + printf("flags: 0x%04X size: %d\n", Flags, DstSize); + + if (DstSize != expectedSize) + { + printf("test_ZGfxCompressFox: output size mismatch: Actual: %d, Expected: %d\n", DstSize, expectedSize); + return -1; + } + + if (memcmp(pDstData, TEST_FOX_DATA_SINGLE, DstSize) != 0) + { + printf("test_ZGfxCompressFox: output mismatch\n"); + printf("Actual\n"); + BitDump(__FUNCTION__, WLOG_INFO, pDstData, DstSize * 8, 0); + printf("Expected\n"); + BitDump(__FUNCTION__, WLOG_INFO, TEST_FOX_DATA_SINGLE, DstSize * 8, 0); + return -1; + } + + zgfx_context_free(zgfx); + return 0; +} + +int test_ZGfxDecompressFoxSingle() +{ + int status; + UINT32 Flags; + BYTE* pSrcData; + UINT32 SrcSize; + UINT32 DstSize; + BYTE* pDstData; + ZGFX_CONTEXT* zgfx; + UINT32 expectedSize; + + zgfx = zgfx_context_new(TRUE); + SrcSize = sizeof(TEST_FOX_DATA_SINGLE) - 1; + pSrcData = (BYTE*) TEST_FOX_DATA_SINGLE; + Flags = 0; + expectedSize = sizeof(TEST_FOX_DATA) - 1; + status = zgfx_decompress(zgfx, pSrcData, SrcSize, &pDstData, &DstSize, Flags); + printf("flags: 0x%04X size: %d\n", Flags, DstSize); + + if (DstSize != expectedSize) + { + printf("test_ZGfxDecompressFoxSingle: output size mismatch: Actual: %d, Expected: %d\n", DstSize, expectedSize); + return -1; + } + + if (memcmp(pDstData, TEST_FOX_DATA, DstSize) != 0) + { + printf("test_ZGfxDecompressFoxSingle: output mismatch\n"); + printf("Actual\n"); + BitDump(__FUNCTION__, WLOG_INFO, pDstData, DstSize * 8, 0); + printf("Expected\n"); + BitDump(__FUNCTION__, WLOG_INFO, TEST_FOX_DATA, DstSize * 8, 0); + return -1; + } + + zgfx_context_free(zgfx); + return 0; +} + +int test_ZGfxDecompressFoxMultipart() +{ + int status; + UINT32 Flags; + BYTE* pSrcData; + UINT32 SrcSize; + UINT32 DstSize; + BYTE* pDstData; + ZGFX_CONTEXT* zgfx; + UINT32 expectedSize; + + zgfx = zgfx_context_new(TRUE); + SrcSize = sizeof(TEST_FOX_DATA_MULTIPART) - 1; + pSrcData = (BYTE*) TEST_FOX_DATA_MULTIPART; + Flags = 0; + expectedSize = sizeof(TEST_FOX_DATA) - 1; + status = zgfx_decompress(zgfx, pSrcData, SrcSize, &pDstData, &DstSize, Flags); + printf("flags: 0x%04X size: %d\n", Flags, DstSize); + + if (DstSize != expectedSize) + { + printf("test_ZGfxDecompressFoxSingle: output size mismatch: Actual: %d, Expected: %d\n", DstSize, expectedSize); + return -1; + } + + if (memcmp(pDstData, TEST_FOX_DATA, DstSize) != 0) + { + printf("test_ZGfxDecompressFoxSingle: output mismatch\n"); + printf("Actual\n"); + BitDump(__FUNCTION__, WLOG_INFO, pDstData, DstSize * 8, 0); + printf("Expected\n"); + BitDump(__FUNCTION__, WLOG_INFO, TEST_FOX_DATA, DstSize * 8, 0); + return -1; + } + + zgfx_context_free(zgfx); + return 0; +} + +int test_ZGfxCompressConsistent() +{ + int status; + UINT32 Flags; + BYTE* pSrcData; + UINT32 SrcSize; + UINT32 DstSize; + BYTE* pDstData; + UINT32 DstSize2; + BYTE* pDstData2; + ZGFX_CONTEXT* zgfx; + UINT32 expectedSize; + BYTE BigBuffer[65536]; + + memset(BigBuffer, 0xaa, sizeof(BigBuffer)); + memcpy(BigBuffer, TEST_FOX_DATA, sizeof(TEST_FOX_DATA) - 1); + zgfx = zgfx_context_new(TRUE); + + /* Compress */ + expectedSize = SrcSize = sizeof(BigBuffer); + pSrcData = (BYTE*) BigBuffer; + Flags = 0; + status = zgfx_compress(zgfx, pSrcData, SrcSize, &pDstData2, &DstSize2, &Flags); + printf("Compress: flags: 0x%04X size: %d\n", Flags, DstSize2); + + /* Decompress */ + status = zgfx_decompress(zgfx, pDstData2, DstSize2, &pDstData, &DstSize, Flags); + printf("Decompress: flags: 0x%04X size: %d\n", Flags, DstSize); + + if (DstSize != expectedSize) + { + printf("test_ZGfxDecompressFoxSingle: output size mismatch: Actual: %d, Expected: %d\n", DstSize, expectedSize); + return -1; + } + + if (memcmp(pDstData, BigBuffer, DstSize) != 0) + { + printf("test_ZGfxDecompressFoxSingle: output mismatch\n"); + printf("Actual\n"); + BitDump(__FUNCTION__, WLOG_INFO, pDstData, 64 * 8, 0); + printf("...\n"); + BitDump(__FUNCTION__, WLOG_INFO, pDstData + DstSize - 64, 64 * 8, 0); + printf("Expected\n"); + BitDump(__FUNCTION__, WLOG_INFO, BigBuffer, 64 * 8, 0); + printf("...\n"); + BitDump(__FUNCTION__, WLOG_INFO, BigBuffer + DstSize - 64, 64 * 8, 0); + printf("Middle Result\n"); + BitDump(__FUNCTION__, WLOG_INFO, pDstData2, 64 * 8, 0); + printf("...\n"); + BitDump(__FUNCTION__, WLOG_INFO, pDstData2 + DstSize2 - 64, 64 * 8, 0); + return -1; + } + + zgfx_context_free(zgfx); + return 0; +} + +int TestFreeRDPCodecZGfx(int argc, char* argv[]) +{ + if (test_ZGfxCompressFox() < 0) + return -1; + + if (test_ZGfxDecompressFoxSingle() < 0) + return -1; + + if (test_ZGfxDecompressFoxMultipart() < 0) + return -1; + + if (test_ZGfxCompressConsistent() < 0) + return -1; + return 0; } diff --git a/libfreerdp/codec/zgfx.c b/libfreerdp/codec/zgfx.c index 604947988..4d5373454 100644 --- a/libfreerdp/codec/zgfx.c +++ b/libfreerdp/codec/zgfx.c @@ -25,8 +25,11 @@ #include #include +#include #include +#define TAG FREERDP_TAG("codec") + /** * RDP8 Compressor Limits: * @@ -188,7 +191,7 @@ void zgfx_history_buffer_ring_read(ZGFX_CONTEXT* zgfx, int offset, BYTE* dst, UI while ((bytesLeft -= bytes) > 0); } -int zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, BYTE* pbSegment, UINT32 cbSegment) +static int zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, BYTE* pbSegment, UINT32 cbSegment) { BYTE c; BYTE flags; @@ -383,11 +386,106 @@ int zgfx_decompress(ZGFX_CONTEXT* zgfx, BYTE* pSrcData, UINT32 SrcSize, BYTE** p return 1; } -int zgfx_compress(ZGFX_CONTEXT* zgfx, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags) +static int zgfx_compress_segment(ZGFX_CONTEXT* zgfx, wStream* s, BYTE* pSrcData, UINT32 SrcSize, UINT32* pFlags) { + /* FIXME: Currently compression not implemented. Just copy the raw source */ + + if (!Stream_EnsureRemainingCapacity(s, SrcSize + 1)) + { + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + return -1; + } + (*pFlags) |= ZGFX_PACKET_COMPR_TYPE_RDP8; /* RDP 8.0 compression format */ + Stream_Write_UINT8(s, (*pFlags)); /* header (1 byte) */ + Stream_Write(s, pSrcData, SrcSize); + return 1; } +int zgfx_compress_to_stream(ZGFX_CONTEXT* zgfx, wStream* sDst, BYTE* pUncompressed, UINT32 uncompressedSize, UINT32* pFlags) +{ + int fragment; + UINT16 maxLength; + UINT32 totalLength; + UINT16* pSegmentCount = NULL; + BYTE* pSrcData; + int status = 0; + + maxLength = ZGFX_SEGMENTED_MAXSIZE; + + totalLength = uncompressedSize; + pSrcData = pUncompressed; + for (fragment = 0; (totalLength > 0) || (fragment == 0); fragment++) + { + UINT32 SrcSize; + UINT32* pDstSize; + UINT32 position; + + SrcSize = (totalLength > maxLength) ? maxLength : totalLength; + pDstSize = NULL; + totalLength -= SrcSize; + + if (fragment == 0) + { + /* First fragment */ + + /* descriptor (1 byte) */ + Stream_Write_UINT8(sDst, (totalLength == 0) ? + ZGFX_SEGMENTED_SINGLE : ZGFX_SEGMENTED_MULTIPART); + if (totalLength > 0) + { + pSegmentCount = (UINT16*)Stream_Pointer(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) */ + Stream_Seek(sDst, 4); + } + + position = Stream_GetPosition(sDst); + if ((status = zgfx_compress_segment(zgfx, sDst, pSrcData, SrcSize, pFlags)) < 0) + { + return status; + } + + if (pDstSize) + { + (*pDstSize) = Stream_GetPosition(sDst) - position; + } + + pSrcData += SrcSize; + } + + return status; +} + +int zgfx_compress(ZGFX_CONTEXT* zgfx, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags) +{ + int status; + wStream* s = Stream_New(NULL, SrcSize); + + status = zgfx_compress_to_stream(zgfx, s, pSrcData, SrcSize, pFlags); + (*ppDstData) = Stream_Buffer(s); + (*pDstSize) = Stream_GetPosition(s); + + Stream_Free(s, FALSE); + return status; +} + + void zgfx_context_reset(ZGFX_CONTEXT* zgfx, BOOL flush) { zgfx->HistoryIndex = 0; diff --git a/server/shadow/CMakeLists.txt b/server/shadow/CMakeLists.txt index 55597dbf8..8e4e8e119 100644 --- a/server/shadow/CMakeLists.txt +++ b/server/shadow/CMakeLists.txt @@ -45,6 +45,8 @@ set(${MODULE_PREFIX}_SRCS shadow_rdpsnd.h shadow_audin.c shadow_audin.h + shadow_rdpgfx.c + shadow_rdpgfx.h shadow_subsystem.c shadow_subsystem.h shadow_mcevent.c diff --git a/server/shadow/Mac/mac_shadow.c b/server/shadow/Mac/mac_shadow.c index 10508c9fe..e281ffdc9 100644 --- a/server/shadow/Mac/mac_shadow.c +++ b/server/shadow/Mac/mac_shadow.c @@ -268,6 +268,7 @@ int mac_shadow_capture_get_dirty_region(macShadowSubsystem* subsystem) size_t numRects; const CGRect* rects; RECTANGLE_16 invalidRect; + rdpShadowSurface* surface = subsystem->server->surface; rects = CGDisplayStreamUpdateGetRects(subsystem->lastUpdate, kCGDisplayStreamUpdateDirtyRects, &numRects); @@ -290,7 +291,7 @@ int mac_shadow_capture_get_dirty_region(macShadowSubsystem* subsystem) invalidRect.bottom /= 2; } - region16_union_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &invalidRect); + region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect); } return 0; @@ -326,11 +327,11 @@ void (^mac_capture_stream_handler)(CGDisplayStreamFrameStatus, uint64_t, IOSurfa surfaceRect.right = surface->width; surfaceRect.bottom = surface->height; - region16_intersect_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &surfaceRect); + region16_intersect_rect(&(surface->invalidRegion), &(surface->invalidRegion), &surfaceRect); - if (!region16_is_empty(&(subsystem->invalidRegion))) + if (!region16_is_empty(&(surface->invalidRegion))) { - extents = region16_extents(&(subsystem->invalidRegion)); + extents = region16_extents(&(surface->invalidRegion)); x = extents->left; y = extents->top; @@ -375,7 +376,7 @@ void (^mac_capture_stream_handler)(CGDisplayStreamFrameStatus, uint64_t, IOSurfa ArrayList_Unlock(server->clients); - region16_clear(&(subsystem->invalidRegion)); + region16_clear(&(surface->invalidRegion)); } if (status != kCGDisplayStreamFrameStatusFrameComplete) @@ -446,46 +447,9 @@ int mac_shadow_subsystem_process_message(macShadowSubsystem* subsystem, wMessage { switch(message->id) { - case SHADOW_MSG_IN_REFRESH_OUTPUT_ID: - { - UINT32 index; - SHADOW_MSG_IN_REFRESH_OUTPUT* msg = (SHADOW_MSG_IN_REFRESH_OUTPUT*) message->wParam; - - if (msg->numRects) - { - for (index = 0; index < msg->numRects; index++) - { - region16_union_rect(&(subsystem->invalidRegion), - &(subsystem->invalidRegion), &msg->rects[index]); - } - } - else - { - RECTANGLE_16 refreshRect; - - refreshRect.left = 0; - refreshRect.top = 0; - refreshRect.right = subsystem->width; - refreshRect.bottom = subsystem->height; - - region16_union_rect(&(subsystem->invalidRegion), - &(subsystem->invalidRegion), &refreshRect); - } + case SHADOW_MSG_IN_REFRESH_REQUEST_ID: + shadow_subsystem_frame_update((rdpShadowSubsystem *)subsystem); break; - } - case SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID: - { - SHADOW_MSG_IN_SUPPRESS_OUTPUT* msg = (SHADOW_MSG_IN_SUPPRESS_OUTPUT*) message->wParam; - - subsystem->suppressOutput = (msg->allow) ? FALSE : TRUE; - - if (msg->allow) - { - region16_union_rect(&(subsystem->invalidRegion), - &(subsystem->invalidRegion), &(msg->rect)); - } - break; - } default: WLog_ERR(TAG, "Unknown message id: %u", message->id); break; diff --git a/server/shadow/Win/win_dxgi.c b/server/shadow/Win/win_dxgi.c index bd2f5d62b..50a1881d9 100644 --- a/server/shadow/Win/win_dxgi.c +++ b/server/shadow/Win/win_dxgi.c @@ -638,6 +638,7 @@ int win_shadow_dxgi_get_invalid_region(winShadowSubsystem* subsystem) RECT* pDirtyRectsBuffer; DXGI_OUTDUPL_MOVE_RECT* pMoveRect; DXGI_OUTDUPL_MOVE_RECT* pMoveRectBuffer; + rdpShadowSurface* surface = subsystem->server->surface; if (subsystem->dxgiFrameInfo.AccumulatedFrames == 0) return 0; @@ -704,7 +705,7 @@ int win_shadow_dxgi_get_invalid_region(winShadowSubsystem* subsystem) invalidRect.right = (UINT16) pDstRect->right; invalidRect.bottom = (UINT16) pDstRect->bottom; - region16_union_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &invalidRect); + region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect); } numDirtyRects = DirtyRectsBufferSize / sizeof(RECT); @@ -718,7 +719,7 @@ int win_shadow_dxgi_get_invalid_region(winShadowSubsystem* subsystem) invalidRect.right = (UINT16) pDirtyRect->right; invalidRect.bottom = (UINT16) pDirtyRect->bottom; - region16_union_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &invalidRect); + region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect); } return 1; diff --git a/server/shadow/Win/win_rdp.c b/server/shadow/Win/win_rdp.c index 231996ed7..0bfc9e680 100644 --- a/server/shadow/Win/win_rdp.c +++ b/server/shadow/Win/win_rdp.c @@ -63,6 +63,7 @@ BOOL shw_end_paint(rdpContext* context) rdpGdi* gdi = context->gdi; shwContext* shw = (shwContext*) context; winShadowSubsystem* subsystem = shw->subsystem; + rdpShadowSurface* surface = subsystem->server->surface; ninvalid = gdi->primary->hdc->hwnd->ninvalid; cinvalid = gdi->primary->hdc->hwnd->cinvalid; @@ -74,7 +75,7 @@ BOOL shw_end_paint(rdpContext* context) invalidRect.right = cinvalid[index].x + cinvalid[index].w; invalidRect.bottom = cinvalid[index].y + cinvalid[index].h; - region16_union_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &invalidRect); + region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect); } SetEvent(subsystem->RdpUpdateEnterEvent); diff --git a/server/shadow/Win/win_shadow.c b/server/shadow/Win/win_shadow.c index 0f23b9c05..4cc86cc3a 100644 --- a/server/shadow/Win/win_shadow.c +++ b/server/shadow/Win/win_shadow.c @@ -219,7 +219,7 @@ int win_shadow_surface_copy(winShadowSubsystem* subsystem) if (ArrayList_Count(server->clients) < 1) { - region16_clear(&(subsystem->invalidRegion)); + region16_clear(&(surface->invalidRegion)); return 1; } @@ -228,12 +228,12 @@ int win_shadow_surface_copy(winShadowSubsystem* subsystem) surfaceRect.right = surface->x + surface->width; surfaceRect.bottom = surface->y + surface->height; - region16_intersect_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &surfaceRect); + region16_intersect_rect(&(surface->invalidRegion), &(surface->invalidRegion), &surfaceRect); - if (region16_is_empty(&(subsystem->invalidRegion))) + if (region16_is_empty(&(surface->invalidRegion))) return 1; - extents = region16_extents(&(subsystem->invalidRegion)); + extents = region16_extents(&(surface->invalidRegion)); CopyMemory(&invalidRect, extents, sizeof(RECTANGLE_16)); shadow_capture_align_clip_rect(&invalidRect, &surfaceRect); @@ -286,7 +286,7 @@ int win_shadow_surface_copy(winShadowSubsystem* subsystem) ArrayList_Unlock(server->clients); - region16_clear(&(subsystem->invalidRegion)); + region16_clear(&(surface->invalidRegion)); return 1; } diff --git a/server/shadow/X11/x11_shadow.c b/server/shadow/X11/x11_shadow.c index 8c5e159ec..0d0f624d4 100644 --- a/server/shadow/X11/x11_shadow.c +++ b/server/shadow/X11/x11_shadow.c @@ -763,9 +763,6 @@ int x11_shadow_screen_grab(x11ShadowSubsystem* subsystem) if (count < 1) return 1; - if ((count == 1) && subsystem->suppressOutput) - return 1; - surfaceRect.left = 0; surfaceRect.top = 0; surfaceRect.right = surface->width; @@ -814,12 +811,12 @@ int x11_shadow_screen_grab(x11ShadowSubsystem* subsystem) XUnlockDisplay(subsystem->display); - region16_union_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &invalidRect); - region16_intersect_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &surfaceRect); + region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect); + region16_intersect_rect(&(surface->invalidRegion), &(surface->invalidRegion), &surfaceRect); - if (!region16_is_empty(&(subsystem->invalidRegion))) + if (!region16_is_empty(&(surface->invalidRegion))) { - extents = region16_extents(&(subsystem->invalidRegion)); + extents = region16_extents(&(surface->invalidRegion)); x = extents->left; y = extents->top; @@ -849,7 +846,7 @@ int x11_shadow_screen_grab(x11ShadowSubsystem* subsystem) } } - region16_clear(&(subsystem->invalidRegion)); + region16_clear(&(surface->invalidRegion)); } if (!subsystem->use_xshm) @@ -868,46 +865,9 @@ int x11_shadow_subsystem_process_message(x11ShadowSubsystem* subsystem, wMessage { switch(message->id) { - case SHADOW_MSG_IN_REFRESH_OUTPUT_ID: - { - UINT32 index; - SHADOW_MSG_IN_REFRESH_OUTPUT* msg = (SHADOW_MSG_IN_REFRESH_OUTPUT*) message->wParam; - - if (msg->numRects) - { - for (index = 0; index < msg->numRects; index++) - { - region16_union_rect(&(subsystem->invalidRegion), - &(subsystem->invalidRegion), &msg->rects[index]); - } - } - else - { - RECTANGLE_16 refreshRect; - - refreshRect.left = 0; - refreshRect.top = 0; - refreshRect.right = subsystem->width; - refreshRect.bottom = subsystem->height; - - region16_union_rect(&(subsystem->invalidRegion), - &(subsystem->invalidRegion), &refreshRect); - } + case SHADOW_MSG_IN_REFRESH_REQUEST_ID: + shadow_subsystem_frame_update((rdpShadowSubsystem *)subsystem); break; - } - case SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID: - { - SHADOW_MSG_IN_SUPPRESS_OUTPUT* msg = (SHADOW_MSG_IN_SUPPRESS_OUTPUT*) message->wParam; - - subsystem->suppressOutput = (msg->allow) ? FALSE : TRUE; - - if (msg->allow) - { - region16_union_rect(&(subsystem->invalidRegion), - &(subsystem->invalidRegion), &(msg->rect)); - } - break; - } default: WLog_ERR(TAG, "Unknown message id: %u", message->id); break; diff --git a/server/shadow/shadow_channels.c b/server/shadow/shadow_channels.c index bc90ab494..983b16f1d 100644 --- a/server/shadow/shadow_channels.c +++ b/server/shadow/shadow_channels.c @@ -43,11 +43,21 @@ UINT shadow_client_channels_post_connect(rdpShadowClient* client) shadow_client_audin_init(client); + if (client->context.settings->SupportGraphicsPipeline) + { + shadow_client_rdpgfx_init(client); + } + return CHANNEL_RC_OK; } void shadow_client_channels_free(rdpShadowClient* client) { + if (client->context.settings->SupportGraphicsPipeline) + { + shadow_client_rdpgfx_uninit(client); + } + shadow_client_audin_uninit(client); shadow_client_rdpsnd_uninit(client); diff --git a/server/shadow/shadow_channels.h b/server/shadow/shadow_channels.h index edba39cb7..e35b6f6ee 100644 --- a/server/shadow/shadow_channels.h +++ b/server/shadow/shadow_channels.h @@ -28,6 +28,7 @@ #include "shadow_remdesk.h" #include "shadow_rdpsnd.h" #include "shadow_audin.h" +#include "shadow_rdpgfx.h" #ifdef __cplusplus extern "C" { diff --git a/server/shadow/shadow_client.c b/server/shadow/shadow_client.c index 8d433e216..010289cc8 100644 --- a/server/shadow/shadow_client.c +++ b/server/shadow/shadow_client.c @@ -30,10 +30,62 @@ #include +#include "libfreerdp/core/server.h" #include "shadow.h" #define TAG CLIENT_TAG("shadow") +struct _SHADOW_GFX_STATUS +{ + BOOL gfxOpened; + BOOL gfxSurfaceCreated; +}; +typedef struct _SHADOW_GFX_STATUS SHADOW_GFX_STATUS; + +static void shadow_client_rdpgfx_new_surface(rdpShadowClient *client) +{ + RDPGFX_CREATE_SURFACE_PDU createSurface; + RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU surfaceToOutput; + RdpgfxServerContext* context = client->rdpgfx; + rdpSettings* settings = ((rdpContext*) client)->settings; + + createSurface.width = settings->DesktopWidth; + createSurface.height = settings->DesktopHeight; + createSurface.pixelFormat = PIXEL_FORMAT_XRGB_8888; + createSurface.surfaceId = 0; + + surfaceToOutput.outputOriginX = 0; + surfaceToOutput.outputOriginY = 0; + surfaceToOutput.surfaceId = 0; + surfaceToOutput.reserved = 0; + + IFCALL(context->CreateSurface, context, &createSurface); + IFCALL(context->MapSurfaceToOutput, context, &surfaceToOutput); +} + +static void shadow_client_rdpgfx_release_surface(rdpShadowClient *client) +{ + RDPGFX_DELETE_SURFACE_PDU pdu; + RdpgfxServerContext* context = client->rdpgfx; + + pdu.surfaceId = 0; + IFCALL(context->DeleteSurface, context, &pdu); +} + +static void shadow_client_rdpgfx_reset_graphic(rdpShadowClient *client) +{ + RDPGFX_RESET_GRAPHICS_PDU pdu; + RdpgfxServerContext* context = client->rdpgfx; + rdpSettings* settings = ((rdpContext*) client)->settings; + + pdu.width = settings->DesktopWidth; + pdu.height = settings->DesktopHeight; + pdu.monitorCount = client->subsystem->numMonitors; + pdu.monitorDefArray = client->subsystem->monitors; + + IFCALL(context->ResetGraphics, context, &pdu); +} + static void shadow_client_free_queued_message(void *obj) { wMessage *message = (wMessage*)obj; @@ -44,7 +96,7 @@ static void shadow_client_free_queued_message(void *obj) } } -BOOL shadow_client_context_new(freerdp_peer* peer, rdpShadowClient* client) +static BOOL shadow_client_context_new(freerdp_peer* peer, rdpShadowClient* client) { rdpSettings* settings; rdpShadowServer* server; @@ -62,7 +114,8 @@ BOOL shadow_client_context_new(freerdp_peer* peer, rdpShadowClient* client) settings->BitmapCacheV3Enabled = TRUE; settings->FrameMarkerCommandEnabled = TRUE; settings->SurfaceFrameMarkerEnabled = TRUE; - settings->SupportGraphicsPipeline = FALSE; + settings->SupportGraphicsPipeline = TRUE; + settings->GfxH264 = FALSE; settings->DrawAllowSkipAlpha = TRUE; settings->DrawAllowColorSubsampling = TRUE; @@ -130,40 +183,36 @@ fail_cert_file: return FALSE; } -void shadow_client_context_free(freerdp_peer* peer, rdpShadowClient* client) +static void shadow_client_context_free(freerdp_peer* peer, rdpShadowClient* client) { rdpShadowServer* server = client->server; ArrayList_Remove(server->clients, (void*) client); - DeleteCriticalSection(&(client->lock)); - - region16_uninit(&(client->invalidRegion)); - - WTSCloseServer((HANDLE) client->vcm); - - /* Clear queued messages and free resource */ - MessageQueue_Clear(client->MsgQueue); - MessageQueue_Free(client->MsgQueue); - if (client->encoder) { shadow_encoder_free(client->encoder); client->encoder = NULL; } + + /* Clear queued messages and free resource */ + MessageQueue_Clear(client->MsgQueue); + MessageQueue_Free(client->MsgQueue); + + WTSCloseServer((HANDLE) client->vcm); + client->vcm = NULL; + + region16_uninit(&(client->invalidRegion)); + + DeleteCriticalSection(&(client->lock)); } void shadow_client_message_free(wMessage* message) { switch(message->id) { - case SHADOW_MSG_IN_REFRESH_OUTPUT_ID: - free(((SHADOW_MSG_IN_REFRESH_OUTPUT*)message->wParam)->rects); - free(message->wParam); - break; - - case SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID: - free(message->wParam); + case SHADOW_MSG_IN_REFRESH_REQUEST_ID: + /* Refresh request do not have message to free */ break; default: @@ -173,7 +222,69 @@ void shadow_client_message_free(wMessage* message) } } -BOOL shadow_client_capabilities(freerdp_peer* peer) +static void shadow_client_mark_invalid(rdpShadowClient* client, int numRects, const RECTANGLE_16* rects) +{ + int index; + RECTANGLE_16 screenRegion; + rdpSettings* settings = ((rdpContext*) client)->settings; + + EnterCriticalSection(&(client->lock)); + + /* Mark client invalid region. No rectangle means full screen */ + if (numRects > 0) + { + for (index = 0; index < numRects; index++) + { + region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &rects[index]); + } + } + else + { + screenRegion.left = 0; + screenRegion.top = 0; + screenRegion.right = settings->DesktopWidth; + screenRegion.bottom = settings->DesktopHeight; + + region16_union_rect(&(client->invalidRegion), + &(client->invalidRegion), &screenRegion); + } + + LeaveCriticalSection(&(client->lock)); +} + +/** + * Function description + * Recalculate client desktop size + * + * @return TRUE if width/height changed. + */ +static BOOL shadow_client_recalc_desktop_size(rdpShadowClient* client) +{ + int width, height; + rdpShadowServer* server = client->server; + rdpSettings* settings = client->context.settings; + + RECTANGLE_16 viewport = {0, 0, server->surface->width, server->surface->height}; + + if (server->shareSubRect) + { + rectangles_intersection(&viewport, &(server->subRect), &viewport); + } + + width = viewport.right - viewport.left; + height = viewport.bottom - viewport.top; + + if (settings->DesktopWidth != (UINT32)width || settings->DesktopHeight != (UINT32)height) + { + settings->DesktopWidth = width; + settings->DesktopHeight = height; + return TRUE; + } + + return FALSE; +} + +static BOOL shadow_client_capabilities(freerdp_peer* peer) { rdpShadowSubsystem* subsystem; rdpShadowClient* client; @@ -181,34 +292,20 @@ BOOL shadow_client_capabilities(freerdp_peer* peer) client = (rdpShadowClient*) peer->context; subsystem = client->server->subsystem; - if (subsystem->ClientCapabilities) - { - return subsystem->ClientCapabilities(subsystem, client); - } + IFCALL(subsystem->ClientCapabilities, subsystem, client); + + /* Make sure we send correct width/height to client */ + (void)shadow_client_recalc_desktop_size(client); + return TRUE; } -static INLINE void shadow_client_calc_desktop_size(rdpShadowServer* server, int* pWidth, int* pHeight) -{ - RECTANGLE_16 viewport = {0, 0, server->screen->width, server->screen->height}; - - if (server->shareSubRect) - { - rectangles_intersection(&viewport, &(server->subRect), &viewport); - } - - (*pWidth) = viewport.right - viewport.left; - (*pHeight) = viewport.bottom - viewport.top; -} - -BOOL shadow_client_post_connect(freerdp_peer* peer) +static BOOL shadow_client_post_connect(freerdp_peer* peer) { int authStatus; - int width, height; rdpSettings* settings; rdpShadowClient* client; rdpShadowServer* server; - RECTANGLE_16 invalidRect; rdpShadowSubsystem* subsystem; client = (rdpShadowClient*) peer->context; @@ -216,30 +313,29 @@ BOOL shadow_client_post_connect(freerdp_peer* peer) server = client->server; subsystem = server->subsystem; - shadow_client_calc_desktop_size(server, &width, &height); - settings->DesktopWidth = width; - settings->DesktopHeight = height; - if (settings->ColorDepth == 24) settings->ColorDepth = 16; /* disable 24bpp */ if (settings->MultifragMaxRequestSize < 0x3F0000) settings->NSCodec = FALSE; /* NSCodec compressor does not support fragmentation yet */ - WLog_ERR(TAG, "Client from %s is activated (%dx%d@%d)", - peer->hostname, settings->DesktopWidth, settings->DesktopHeight, settings->ColorDepth); + WLog_INFO(TAG, "Client from %s is activated (%dx%d@%d)", + peer->hostname, settings->DesktopWidth, + settings->DesktopHeight, settings->ColorDepth); - peer->update->DesktopResize(peer->update->context); + /* Resize client if necessary */ + if (shadow_client_recalc_desktop_size(client)) + { + peer->update->DesktopResize(peer->update->context); + WLog_INFO(TAG, "Client from %s is resized (%dx%d@%d)", + peer->hostname, settings->DesktopWidth, + settings->DesktopHeight, settings->ColorDepth); + } if (shadow_client_channels_post_connect(client) != CHANNEL_RC_OK) return FALSE; - invalidRect.left = 0; - invalidRect.top = 0; - invalidRect.right = server->screen->width; - invalidRect.bottom = server->screen->height; - - region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &invalidRect); + shadow_client_mark_invalid(client, 0, NULL); authStatus = -1; @@ -271,7 +367,7 @@ 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, - RECTANGLE_16* dst, RECTANGLE_16* src, UINT32 numRects) + RECTANGLE_16* dst, const RECTANGLE_16* src, UINT32 numRects) { if (client->server->shareSubRect) { @@ -289,71 +385,79 @@ static INLINE void shadow_client_convert_rects(rdpShadowClient* client, } else { - CopyMemory(dst, src, numRects * sizeof(RECTANGLE_16)); + if (src != dst) + { + CopyMemory(dst, src, numRects * sizeof(RECTANGLE_16)); + } } } -BOOL shadow_client_refresh_rect(rdpShadowClient* client, BYTE count, RECTANGLE_16* areas) +static BOOL shadow_client_refresh_request(rdpShadowClient* client) { wMessage message = { 0 }; - SHADOW_MSG_IN_REFRESH_OUTPUT* wParam; wMessagePipe* MsgPipe = client->subsystem->MsgPipe; + message.id = SHADOW_MSG_IN_REFRESH_REQUEST_ID; + message.wParam = NULL; + message.lParam = NULL; + message.context = (void*) client; + message.Free = NULL; + + return MessageQueue_Dispatch(MsgPipe->In, &message); +} + +static BOOL shadow_client_refresh_rect(rdpShadowClient* client, BYTE count, RECTANGLE_16* areas) +{ + RECTANGLE_16* rects; + + /* It is invalid if we have area count but no actual area */ if (count && !areas) return FALSE; - if (!(wParam = (SHADOW_MSG_IN_REFRESH_OUTPUT*) calloc(1, sizeof(SHADOW_MSG_IN_REFRESH_OUTPUT)))) - return FALSE; - - wParam->numRects = (UINT32) count; - - if (wParam->numRects) + if (count) { - wParam->rects = (RECTANGLE_16*) calloc(wParam->numRects, sizeof(RECTANGLE_16)); + rects = (RECTANGLE_16*) calloc(count, sizeof(RECTANGLE_16)); - if (!wParam->rects) + if (!rects) { - free (wParam); return FALSE; } - shadow_client_convert_rects(client, wParam->rects, areas, wParam->numRects); + shadow_client_convert_rects(client, rects, areas, count); + + shadow_client_mark_invalid(client, count, rects); + + free(rects); + } + else + { + shadow_client_mark_invalid(client, 0, NULL); } - message.id = SHADOW_MSG_IN_REFRESH_OUTPUT_ID; - message.wParam = (void*) wParam; - message.lParam = NULL; - message.context = (void*) client; - message.Free = shadow_client_message_free; - - return MessageQueue_Dispatch(MsgPipe->In, &message); + return shadow_client_refresh_request(client); } -BOOL shadow_client_suppress_output(rdpShadowClient* client, BYTE allow, RECTANGLE_16* area) +static BOOL shadow_client_suppress_output(rdpShadowClient* client, BYTE allow, RECTANGLE_16* area) { - wMessage message = { 0 }; - SHADOW_MSG_IN_SUPPRESS_OUTPUT* wParam; - wMessagePipe* MsgPipe = client->subsystem->MsgPipe; + RECTANGLE_16 region; - wParam = (SHADOW_MSG_IN_SUPPRESS_OUTPUT*) calloc(1, sizeof(SHADOW_MSG_IN_SUPPRESS_OUTPUT)); - if (!wParam) - return FALSE; - - wParam->allow = (UINT32) allow; - - if (area) - shadow_client_convert_rects(client, &(wParam->rect), area, 1); - - message.id = SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID; - message.wParam = (void*) wParam; - message.lParam = NULL; - message.context = (void*) client; - message.Free = shadow_client_message_free; - - return MessageQueue_Dispatch(MsgPipe->In, &message); + client->suppressOutput = allow ? FALSE : TRUE; + if (allow) + { + if (area) + { + shadow_client_convert_rects(client, ®ion, area, 1); + shadow_client_mark_invalid(client, 1, ®ion); + } + else + { + shadow_client_mark_invalid(client, 0, NULL); + } + } + return shadow_client_refresh_request(client); } -BOOL shadow_client_activate(freerdp_peer* peer) +static BOOL shadow_client_activate(freerdp_peer* peer) { rdpSettings* settings = peer->settings; rdpShadowClient* client = (rdpShadowClient*) peer->context; @@ -375,6 +479,7 @@ BOOL shadow_client_activate(freerdp_peer* peer) shadow_encoder_reset(client->encoder); + /* Update full screen in next update */ return shadow_client_refresh_rect(client, 0, NULL); } @@ -439,7 +544,7 @@ BOOL shadow_client_logon(freerdp_peer* peer, SEC_WINNT_AUTH_IDENTITY* identity, return TRUE; } -BOOL shadow_client_surface_frame_acknowledge(rdpShadowClient* client, UINT32 frameId) +static BOOL shadow_client_surface_frame_acknowledge(rdpShadowClient* client, UINT32 frameId) { /* * Record the last client acknowledged frame id to @@ -454,28 +559,91 @@ BOOL shadow_client_surface_frame_acknowledge(rdpShadowClient* client, UINT32 fra return TRUE; } -int shadow_client_send_surface_frame_marker(rdpShadowClient* client, UINT32 action, UINT32 id) +static UINT shadow_client_rdpgfx_frame_acknowledge(RdpgfxServerContext* context, RDPGFX_FRAME_ACKNOWLEDGE_PDU* frameAcknowledge) { - SURFACE_FRAME_MARKER surfaceFrameMarker; - rdpContext* context = (rdpContext*) client; - rdpUpdate* update = context->update; + shadow_client_surface_frame_acknowledge((rdpShadowClient *)context->custom, + frameAcknowledge->frameId); + return CHANNEL_RC_OK; +} - surfaceFrameMarker.frameAction = action; - surfaceFrameMarker.frameId = id; +static int shadow_client_send_surface_gfx(rdpShadowClient* client, + BYTE* pSrcData, int nSrcStep, int nXSrc, int nYSrc, int nWidth, int nHeight) +{ + rdpUpdate* update; + rdpContext* context; + rdpSettings* settings; + rdpShadowServer* server; + rdpShadowEncoder* encoder; + RDPGFX_SURFACE_COMMAND cmd; + RDPGFX_START_FRAME_PDU cmdstart; + RDPGFX_END_FRAME_PDU cmdend; + SYSTEMTIME sTime; - IFCALL(update->SurfaceFrameMarker, context, &surfaceFrameMarker); + context = (rdpContext*) client; + update = context->update; + settings = context->settings; + + server = client->server; + encoder = client->encoder; + + cmdstart.frameId = shadow_encoder_create_frame_id(encoder); + + GetSystemTime(&sTime); + cmdstart.timestamp = sTime.wHour << 22 | sTime.wMinute << 16 | + sTime.wSecond << 10 | sTime.wMilliseconds; + + cmdend.frameId = cmdstart.frameId; + + cmd.surfaceId = 0; + cmd.contextId = 0; + cmd.format = PIXEL_FORMAT_XRGB_8888; + cmd.left = nXSrc; + cmd.top = nYSrc; + cmd.right = cmd.left + nWidth; + cmd.bottom = cmd.top + nHeight; + cmd.width = nWidth; + cmd.height = nHeight; + + if (settings->GfxH264) + { + RDPGFX_AVC420_BITMAP_STREAM avc420; + RECTANGLE_16 regionRect; + RDPGFX_H264_QUANT_QUALITY quantQualityVal; + + shadow_encoder_prepare(encoder, FREERDP_CODEC_AVC420); + + avc420_compress(encoder->h264, pSrcData, PIXEL_FORMAT_RGB32, nSrcStep, + nWidth, nHeight, &avc420.data, &avc420.length); + + cmd.codecId = RDPGFX_CODECID_AVC420; + cmd.extra = (void *)&avc420; + regionRect.left = cmd.left; + regionRect.top = cmd.top; + regionRect.right = cmd.right; + regionRect.bottom = cmd.bottom; + quantQualityVal.qp = encoder->h264->QP; + quantQualityVal.r = 0; + quantQualityVal.p = 0; + quantQualityVal.qualityVal = 100 - quantQualityVal.qp; + avc420.meta.numRegionRects = 1; + 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); + } return 1; } -int shadow_client_send_surface_bits(rdpShadowClient* client, rdpShadowSurface* surface, int nXSrc, int nYSrc, int nWidth, int nHeight) +static int shadow_client_send_surface_bits(rdpShadowClient* client, + BYTE* pSrcData, int nSrcStep, int nXSrc, int nYSrc, int nWidth, int nHeight) { int i; BOOL first; BOOL last; wStream* s; - int nSrcStep; - BYTE* pSrcData; int numMessages; UINT32 frameId = 0; rdpUpdate* update; @@ -492,24 +660,6 @@ int shadow_client_send_surface_bits(rdpShadowClient* client, rdpShadowSurface* s server = client->server; encoder = client->encoder; - pSrcData = surface->data; - nSrcStep = surface->scanline; - - if (server->shareSubRect) - { - int subX, subY; - int subWidth, subHeight; - - subX = server->subRect.left; - subY = server->subRect.top; - subWidth = server->subRect.right - server->subRect.left; - subHeight = server->subRect.bottom - server->subRect.top; - - nXSrc -= subX; - nYSrc -= subY; - pSrcData = &pSrcData[(subY * nSrcStep) + (subX * 4)]; - } - if (encoder->frameAck) frameId = shadow_encoder_create_frame_id(encoder); @@ -613,14 +763,13 @@ int shadow_client_send_surface_bits(rdpShadowClient* client, rdpShadowSurface* s return 1; } -int shadow_client_send_bitmap_update(rdpShadowClient* client, rdpShadowSurface* surface, int nXSrc, int nYSrc, int nWidth, int nHeight) +static int shadow_client_send_bitmap_update(rdpShadowClient* client, + BYTE* pSrcData, int nSrcStep, int nXSrc, int nYSrc, int nWidth, int nHeight) { BYTE* data; BYTE* buffer; int yIdx, xIdx, k; int rows, cols; - int nSrcStep; - BYTE* pSrcData; UINT32 DstSize; UINT32 SrcFormat; BITMAP_DATA* bitmap; @@ -649,25 +798,8 @@ int shadow_client_send_bitmap_update(rdpShadowClient* client, rdpShadowSurface* else shadow_encoder_prepare(encoder, FREERDP_CODEC_PLANAR); - pSrcData = surface->data; - nSrcStep = surface->scanline; SrcFormat = PIXEL_FORMAT_RGB32; - if (server->shareSubRect) - { - int subX, subY; - int subWidth, subHeight; - - subX = server->subRect.left; - subY = server->subRect.top; - subWidth = server->subRect.right - server->subRect.left; - subHeight = server->subRect.bottom - server->subRect.top; - - nXSrc -= subX; - nYSrc -= subY; - pSrcData = &pSrcData[(subY * nSrcStep) + (subX * 4)]; - } - if ((nXSrc % 4) != 0) { nWidth += (nXSrc % 4); @@ -827,7 +959,7 @@ int shadow_client_send_bitmap_update(rdpShadowClient* client, rdpShadowSurface* return 1; } -int shadow_client_send_surface_update(rdpShadowClient* client) +static int shadow_client_send_surface_update(rdpShadowClient* client, SHADOW_GFX_STATUS* pStatus) { int status = -1; int nXSrc, nYSrc; @@ -840,6 +972,11 @@ int shadow_client_send_surface_update(rdpShadowClient* client) REGION16 invalidRegion; RECTANGLE_16 surfaceRect; const RECTANGLE_16* extents; + BYTE* pSrcData; + int nSrcStep; + int index; + int numRects = 0; + const RECTANGLE_16* rects; context = (rdpContext*) client; settings = context->settings; @@ -856,6 +993,12 @@ int shadow_client_send_surface_update(rdpShadowClient* client) LeaveCriticalSection(&(client->lock)); + rects = region16_rects(&(surface->invalidRegion), &numRects); + for (index = 0; index < numRects; index++) + { + region16_union_rect(&invalidRegion, &invalidRegion, &rects[index]); + } + surfaceRect.left = 0; surfaceRect.top = 0; surfaceRect.right = surface->width; @@ -870,27 +1013,63 @@ int shadow_client_send_surface_update(rdpShadowClient* client) if (region16_is_empty(&invalidRegion)) { + /* No image region need to be updated */ region16_uninit(&invalidRegion); return 1; } extents = region16_extents(&invalidRegion); - nXSrc = extents->left - 0; - nYSrc = extents->top - 0; + nXSrc = extents->left; + nYSrc = extents->top; nWidth = extents->right - extents->left; nHeight = extents->bottom - extents->top; + pSrcData = surface->data; + nSrcStep = surface->scanline; + + /* Move to new pSrcData / nXSrc / nYSrc according to sub rect */ + if (server->shareSubRect) + { + int subX, subY; + + subX = server->subRect.left; + subY = server->subRect.top; + + nXSrc -= subX; + nYSrc -= subY; + pSrcData = &pSrcData[(subY * nSrcStep) + (subX * 4)]; + } + //WLog_INFO(TAG, "shadow_client_send_surface_update: x: %d y: %d width: %d height: %d right: %d bottom: %d", // nXSrc, nYSrc, nWidth, nHeight, nXSrc + nWidth, nYSrc + nHeight); - if (settings->RemoteFxCodec || settings->NSCodec) + if (settings->SupportGraphicsPipeline && + settings->GfxH264 && + pStatus->gfxOpened) { - status = shadow_client_send_surface_bits(client, surface, nXSrc, nYSrc, nWidth, nHeight); + /* GFX/h264 always full screen encoded */ + nWidth = settings->DesktopWidth; + nHeight = settings->DesktopHeight; + + /* Create primary surface if have not */ + if (!pStatus->gfxSurfaceCreated) + { + /* Only init surface when we have h264 supported */ + shadow_client_rdpgfx_new_surface(client); + shadow_client_rdpgfx_reset_graphic(client); + pStatus->gfxSurfaceCreated = TRUE; + } + + status = 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); } else { - status = shadow_client_send_bitmap_update(client, surface, nXSrc, nYSrc, nWidth, nHeight); + status = shadow_client_send_bitmap_update(client, pSrcData, nSrcStep, nXSrc, nYSrc, nWidth, nHeight); } region16_uninit(&invalidRegion); @@ -898,27 +1077,67 @@ int shadow_client_send_surface_update(rdpShadowClient* client) return status; } +static void shadow_client_send_resize(rdpShadowClient* client, SHADOW_GFX_STATUS* pStatus) +{ + rdpContext* context; + rdpSettings* settings; + rdpShadowServer* server; + freerdp_peer* peer; + + server = client->server; + context = (rdpContext*) client; + peer = context->peer; + settings = context->settings; + + /** + * Unset client activated flag to avoid sending update message during + * resize. DesktopResize will reactive the client and + * shadow_client_activate would be invoked later. + */ + client->activated = FALSE; + + /* Close Gfx surfaces */ + if (pStatus->gfxSurfaceCreated) + { + shadow_client_rdpgfx_release_surface(client); + pStatus->gfxSurfaceCreated = FALSE; + } + + /* Send Resize */ + peer->update->DesktopResize(peer->update->context); // update_send_desktop_resize + + /* Clear my invalidRegion. shadow_client_activate refreshes fullscreen */ + EnterCriticalSection(&(client->lock)); + region16_clear(&(client->invalidRegion)); + LeaveCriticalSection(&(client->lock)); + + WLog_INFO(TAG, "Client from %s is resized (%dx%d@%d)", + peer->hostname, settings->DesktopWidth, settings->DesktopHeight, settings->ColorDepth); +} + +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) { - int index; int numRects = 0; const RECTANGLE_16* rects; - EnterCriticalSection(&(client->lock)); - rects = region16_rects(region, &numRects); - - for (index = 0; index < numRects; index++) - { - region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &rects[index]); - } - - LeaveCriticalSection(&(client->lock)); + shadow_client_mark_invalid(client, numRects, rects); return 1; } -int shadow_client_subsystem_process_message(rdpShadowClient* client, wMessage* message) +static int shadow_client_subsystem_process_message(rdpShadowClient* client, wMessage* message) { rdpContext* context = (rdpContext*) client; rdpUpdate* update = context->update; @@ -1013,7 +1232,7 @@ int shadow_client_subsystem_process_message(rdpShadowClient* client, wMessage* m return 1; } -void* shadow_client_thread(rdpShadowClient* client) +static void* shadow_client_thread(rdpShadowClient* client) { DWORD status; DWORD nCount; @@ -1034,6 +1253,11 @@ void* shadow_client_thread(rdpShadowClient* client) rdpShadowEncoder* encoder; rdpShadowSubsystem* subsystem; wMessageQueue* MsgQueue = client->MsgQueue; + /* This should only be visited in client thread */ + SHADOW_GFX_STATUS gfxstatus; + + gfxstatus.gfxOpened = FALSE; + gfxstatus.gfxSurfaceCreated = FALSE; server = client->server; screen = server->screen; @@ -1080,50 +1304,35 @@ void* shadow_client_thread(rdpShadowClient* client) if (WaitForSingleObject(UpdateEvent, 0) == WAIT_OBJECT_0) { - if (client->activated) + /* The UpdateEvent means to start sending current frame. It is + * triggered from subsystem implementation and it should ensure + * that the screen and primary surface meta data (width, height, + * scanline, invalid region, etc) is not changed until it is reset + * (at shadow_multiclient_consume). As best practice, subsystem + * implementation should invoke shadow_subsystem_frame_update which + * triggers the event and then wait for completion */ + + if (client->activated && !client->suppressOutput) { - int index; - int numRects = 0; - const RECTANGLE_16* rects; - int width, height; + /* Send screen update or resize to this client */ /* Check resize */ - shadow_client_calc_desktop_size(server, &width, &height); - if (settings->DesktopWidth != (UINT32)width || settings->DesktopHeight != (UINT32)height) + if (shadow_client_recalc_desktop_size(client)) { /* Screen size changed, do resize */ - settings->DesktopWidth = width; - settings->DesktopHeight = height; - - /** - * Unset client activated flag to avoid sending update message during - * resize. DesktopResize will reactive the client and - * shadow_client_activate would be invoked later. - */ - client->activated = FALSE; - - /* Send Resize */ - peer->update->DesktopResize(peer->update->context); // update_send_desktop_resize - - /* Clear my invalidRegion. shadow_client_activate refreshes fullscreen */ - region16_clear(&(client->invalidRegion)); - - WLog_ERR(TAG, "Client from %s is resized (%dx%d@%d)", - peer->hostname, settings->DesktopWidth, settings->DesktopHeight, settings->ColorDepth); + shadow_client_send_resize(client, &gfxstatus); } else { /* Send frame */ - rects = region16_rects(&(subsystem->invalidRegion), &numRects); - - for (index = 0; index < numRects; index++) - { - region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &rects[index]); - } - - shadow_client_send_surface_update(client); + shadow_client_send_surface_update(client, &gfxstatus); } } + else + { + /* Our client don't receive graphic updates. Just save the invalid region */ + shadow_client_no_surface_update(client, &gfxstatus); + } /* * The return value of shadow_multiclient_consume is whether or not the subscriber really consumes the event. @@ -1139,6 +1348,38 @@ void* shadow_client_thread(rdpShadowClient* client) WLog_ERR(TAG, "Failed to check FreeRDP file descriptor"); break; } + + if (WTSVirtualChannelManagerIsChannelJoined(client->vcm, "drdynvc")) + { + /* Dynamic channel status may have been changed after processing */ + if (((WTSVirtualChannelManager*)(client->vcm))->drdynvc_state == DRDYNVC_STATE_NONE) + { + /* Call this routine to Initialize drdynvc channel */ + if (!WTSVirtualChannelManagerCheckFileDescriptor(client->vcm)) + { + WLog_ERR(TAG, "Failed to initialize drdynvc channel"); + break; + } + } + else if (((WTSVirtualChannelManager*)(client->vcm))->drdynvc_state == DRDYNVC_STATE_READY) + { + /* Init RDPGFX dynamic channel */ + if (settings->SupportGraphicsPipeline && client->rdpgfx && + !gfxstatus.gfxOpened) + { + if (!client->rdpgfx->Open(client->rdpgfx)) + { + WLog_ERR(TAG, "Failed to open GraphicsPipeline"); + settings->SupportGraphicsPipeline = FALSE; + } + + client->rdpgfx->FrameAcknowledge = shadow_client_rdpgfx_frame_acknowledge; + + gfxstatus.gfxOpened = TRUE; + WLog_INFO(TAG, "Gfx Pipeline Opened"); + } + } + } } if (WaitForSingleObject(ChannelEvent, 0) == WAIT_OBJECT_0) @@ -1220,6 +1461,14 @@ void* shadow_client_thread(rdpShadowClient* client) } /* Free channels early because we establish channels in post connect */ + if (gfxstatus.gfxOpened) + { + if (gfxstatus.gfxSurfaceCreated) + { + shadow_client_rdpgfx_release_surface(client); + } + (void)client->rdpgfx->Close(client->rdpgfx); + } shadow_client_channels_free(client); if (UpdateSubscriber) diff --git a/server/shadow/shadow_encoder.c b/server/shadow/shadow_encoder.c index 07bf880b2..be3194c6d 100644 --- a/server/shadow/shadow_encoder.c +++ b/server/shadow/shadow_encoder.c @@ -130,9 +130,6 @@ int shadow_encoder_uninit_grid(rdpShadowEncoder* encoder) int shadow_encoder_init_rfx(rdpShadowEncoder* encoder) { - rdpContext* context = (rdpContext*) encoder->client; - rdpSettings* settings = context->settings; - if (!encoder->rfx) encoder->rfx = rfx_context_new(TRUE); @@ -148,12 +145,6 @@ int shadow_encoder_init_rfx(rdpShadowEncoder* encoder) rfx_context_set_pixel_format(encoder->rfx, RDP_PIXEL_FORMAT_B8G8R8A8); - encoder->fps = 16; - encoder->maxFps = 32; - encoder->frameId = 0; - encoder->lastAckframeId = 0; - encoder->frameAck = settings->SurfaceFrameMarkerEnabled; - encoder->codecs |= FREERDP_CODEC_REMOTEFX; return 1; @@ -172,23 +163,24 @@ int shadow_encoder_init_nsc(rdpShadowEncoder* encoder) encoder->nsc = nsc_context_new(); if (!encoder->nsc) - return -1; + goto fail; - nsc_context_set_pixel_format(encoder->nsc, RDP_PIXEL_FORMAT_B8G8R8A8); - - encoder->fps = 16; - encoder->maxFps = 32; - encoder->frameId = 0; - encoder->lastAckframeId = 0; - encoder->frameAck = settings->SurfaceFrameMarkerEnabled; + if (!nsc_context_reset(encoder->nsc, encoder->width, encoder->height)) + goto fail; encoder->nsc->ColorLossLevel = settings->NSCodecColorLossLevel; encoder->nsc->ChromaSubsamplingLevel = settings->NSCodecAllowSubsampling ? 1 : 0; encoder->nsc->DynamicColorFidelity = settings->NSCodecAllowDynamicColorFidelity; + nsc_context_set_pixel_format(encoder->nsc, RDP_PIXEL_FORMAT_B8G8R8A8); + encoder->codecs |= FREERDP_CODEC_NSCODEC; return 1; + +fail: + nsc_context_free(encoder->nsc); + return -1; } int shadow_encoder_init_planar(rdpShadowEncoder* encoder) @@ -209,11 +201,18 @@ int shadow_encoder_init_planar(rdpShadowEncoder* encoder) } if (!encoder->planar) - return -1; + goto fail; + + if (!freerdp_bitmap_planar_context_reset(encoder->planar)) + goto fail; encoder->codecs |= FREERDP_CODEC_PLANAR; return 1; + +fail: + freerdp_bitmap_planar_context_free(encoder->planar); + return -1; } int shadow_encoder_init_interleaved(rdpShadowEncoder* encoder) @@ -222,11 +221,38 @@ int shadow_encoder_init_interleaved(rdpShadowEncoder* encoder) encoder->interleaved = bitmap_interleaved_context_new(TRUE); if (!encoder->interleaved) - return -1; + goto fail; + + if (!bitmap_interleaved_context_reset(encoder->interleaved)) + goto fail; encoder->codecs |= FREERDP_CODEC_INTERLEAVED; return 1; + +fail: + bitmap_interleaved_context_free(encoder->interleaved); + return -1; +} + +int shadow_encoder_init_h264(rdpShadowEncoder* encoder) +{ + if (!encoder->h264) + encoder->h264 = h264_context_new(TRUE); + + if (!encoder->h264) + goto fail; + + if (!h264_context_reset(encoder->h264, encoder->width, encoder->height)) + goto fail; + + encoder->codecs |= FREERDP_CODEC_AVC420; + + return 1; + +fail: + h264_context_free(encoder->h264); + return -1; } int shadow_encoder_init(rdpShadowEncoder* encoder) @@ -300,6 +326,19 @@ int shadow_encoder_uninit_interleaved(rdpShadowEncoder* encoder) return 1; } +int shadow_encoder_uninit_h264(rdpShadowEncoder* encoder) +{ + if (encoder->h264) + { + h264_context_free(encoder->h264); + encoder->h264= NULL; + } + + encoder->codecs &= ~FREERDP_CODEC_AVC420; + + return 1; +} + int shadow_encoder_uninit(rdpShadowEncoder* encoder) { shadow_encoder_uninit_grid(encoder); @@ -330,6 +369,11 @@ int shadow_encoder_uninit(rdpShadowEncoder* encoder) shadow_encoder_uninit_interleaved(encoder); } + if (encoder->codecs & FREERDP_CODEC_AVC420) + { + shadow_encoder_uninit_h264(encoder); + } + return 1; } @@ -337,6 +381,8 @@ int shadow_encoder_reset(rdpShadowEncoder* encoder) { int status; UINT32 codecs = encoder->codecs; + rdpContext* context = (rdpContext*) encoder->client; + rdpSettings* settings = context->settings; status = shadow_encoder_uninit(encoder); @@ -353,6 +399,12 @@ int shadow_encoder_reset(rdpShadowEncoder* encoder) if (status < 0) return -1; + encoder->fps = 16; + encoder->maxFps = 32; + encoder->frameId = 0; + encoder->lastAckframeId = 0; + encoder->frameAck = settings->SurfaceFrameMarkerEnabled; + return 1; } @@ -392,6 +444,14 @@ int shadow_encoder_prepare(rdpShadowEncoder* encoder, UINT32 codecs) return -1; } + if ((codecs & FREERDP_CODEC_AVC420) && !(encoder->codecs & FREERDP_CODEC_AVC420)) + { + status = shadow_encoder_init_h264(encoder); + + if (status < 0) + return -1; + } + return 1; } diff --git a/server/shadow/shadow_encoder.h b/server/shadow/shadow_encoder.h index fd7d46a11..b2c01b908 100644 --- a/server/shadow/shadow_encoder.h +++ b/server/shadow/shadow_encoder.h @@ -49,6 +49,7 @@ struct rdp_shadow_encoder NSC_CONTEXT* nsc; BITMAP_PLANAR_CONTEXT* planar; BITMAP_INTERLEAVED_CONTEXT* interleaved; + H264_CONTEXT* h264; int fps; int maxFps; diff --git a/server/shadow/shadow_rdpgfx.c b/server/shadow/shadow_rdpgfx.c new file mode 100644 index 000000000..51459eca4 --- /dev/null +++ b/server/shadow/shadow_rdpgfx.c @@ -0,0 +1,87 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "shadow.h" + +#include "shadow_rdpgfx.h" + +#define TAG SERVER_TAG("shadow") + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpgfx_caps_advertise(RdpgfxServerContext* context, RDPGFX_CAPS_ADVERTISE_PDU* capsAdvertise) +{ + UINT16 index; + RDPGFX_CAPS_CONFIRM_PDU pdu; + rdpSettings* settings = context->rdpcontext->settings; + UINT32 flags = 0; + + for (index = 0; index < capsAdvertise->capsSetCount; index++) + { + pdu.capsSet = &(capsAdvertise->capsSets[index]); + if (pdu.capsSet->version == RDPGFX_CAPVERSION_81) + { + if (settings) + { + flags = pdu.capsSet->flags; + settings->GfxThinClient = (flags & RDPGFX_CAPS_FLAG_THINCLIENT); + settings->GfxSmallCache = (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE); + settings->GfxH264 = (flags & RDPGFX_CAPS_FLAG_AVC420_ENABLED); + } + + return context->CapsConfirm(context, &pdu); + } + } + + return CHANNEL_RC_UNSUPPORTED_VERSION; +} + +int shadow_client_rdpgfx_init(rdpShadowClient* client) +{ + RdpgfxServerContext* rdpgfx; + rdpgfx = client->rdpgfx = rdpgfx_server_context_new(client->vcm); + if (!rdpgfx) + { + return 0; + } + + rdpgfx->rdpcontext = &client->context; + + rdpgfx->custom = client; + + rdpgfx->CapsAdvertise = rdpgfx_caps_advertise; + + return 1; +} + +void shadow_client_rdpgfx_uninit(rdpShadowClient* client) +{ + if (client->rdpgfx) + { + rdpgfx_server_context_free(client->rdpgfx); + client->rdpgfx = NULL; + } +} diff --git a/server/shadow/shadow_rdpgfx.h b/server/shadow/shadow_rdpgfx.h new file mode 100644 index 000000000..0ac810d74 --- /dev/null +++ b/server/shadow/shadow_rdpgfx.h @@ -0,0 +1,38 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_SHADOW_SERVER_RDPGFX_H +#define FREERDP_SHADOW_SERVER_RDPGFX_H + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int shadow_client_rdpgfx_init(rdpShadowClient* client); +void shadow_client_rdpgfx_uninit(rdpShadowClient* client); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_SHADOW_SERVER_RDPGFX_H */ diff --git a/server/shadow/shadow_subsystem.c b/server/shadow/shadow_subsystem.c index 0cbb46f5e..7f3173af6 100644 --- a/server/shadow/shadow_subsystem.c +++ b/server/shadow/shadow_subsystem.c @@ -86,8 +86,6 @@ int shadow_subsystem_init(rdpShadowSubsystem* subsystem, rdpShadowServer* server if (!(subsystem->updateEvent = shadow_multiclient_new())) goto fail; - region16_init(&(subsystem->invalidRegion)); - if ((status = subsystem->ep.Init(subsystem)) >= 0) return status; @@ -141,9 +139,6 @@ void shadow_subsystem_uninit(rdpShadowSubsystem* subsystem) shadow_multiclient_free(subsystem->updateEvent); subsystem->updateEvent = NULL; } - - if (subsystem->invalidRegion.data) - region16_uninit(&(subsystem->invalidRegion)); } int shadow_subsystem_start(rdpShadowSubsystem* subsystem) From 2b6bd2626dee3ecd1db28f6ef01a404285d7dfa6 Mon Sep 17 00:00:00 2001 From: "zihao.jiang" Date: Wed, 4 May 2016 00:48:59 +0800 Subject: [PATCH 2/8] 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 From 992e0e9f352272901919499dbd600feaf3c6198c Mon Sep 17 00:00:00 2001 From: "zihao.jiang" Date: Fri, 27 May 2016 02:11:52 +0800 Subject: [PATCH 3/8] rdpgfx: more minor changes 1. Fix style for channels/rdpgfx/server/rdpgfx_main.c according to scripts/format_code.sh 2. Refactor and introduce APIs to allow rdpgfx server channel running in existing thread (similar to rdpsnd) --- channels/rdpgfx/server/rdpgfx_main.c | 784 +++++++++++++++------------ channels/rdpgfx/server/rdpgfx_main.h | 6 +- include/freerdp/server/rdpgfx.h | 44 +- 3 files changed, 454 insertions(+), 380 deletions(-) diff --git a/channels/rdpgfx/server/rdpgfx_main.c b/channels/rdpgfx/server/rdpgfx_main.c index 547b41758..fbcf56b12 100644 --- a/channels/rdpgfx/server/rdpgfx_main.c +++ b/channels/rdpgfx/server/rdpgfx_main.c @@ -54,15 +54,14 @@ 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) +static INLINE UINT rdpgfx_server_packet_init_header(wStream* s, + UINT16 cmdId, UINT32 pduLength) { RDPGFX_HEADER header; - header.flags = 0; header.cmdId = cmdId; header.pduLength = pduLength; - - /* Write header. Note that actual length might be changed + /* Write header. Note that actual length might be changed * after the entire packet has been constructed. */ return rdpgfx_write_header(s, &header); } @@ -77,7 +76,6 @@ static INLINE UINT rdpgfx_server_packet_init_header(wStream* s, UINT16 cmdId, UI 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) */ @@ -86,7 +84,7 @@ static INLINE void rdpgfx_server_packet_complete_header(wStream* s, size_t start /** * Function description - * Send the stream for rdpgfx server packet. + * 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 @@ -99,30 +97,30 @@ static UINT rdpgfx_server_packet_send(RdpgfxServerContext* context, wStream* s) BYTE* pSrcData = Stream_Buffer(s); UINT32 SrcSize = Stream_GetPosition(s); wStream* fs; - /* 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); + fs = Stream_New(NULL, SrcSize + 7 + + (SrcSize/ZGFX_SEGMENTED_MAXSIZE + 1) * 4); - if(!fs) + if (!fs) { - WLog_ERR(TAG, "Stream_New failed!"); + WLog_ERR(TAG, "Stream_New failed!"); error = CHANNEL_RC_NO_MEMORY; - goto out; + goto out; } - if (zgfx_compress_to_stream(context->priv->zgfx, fs, pSrcData, SrcSize, &flags) < 0) + if (zgfx_compress_to_stream(context->priv->zgfx, fs, pSrcData, + SrcSize, &flags) < 0) { WLog_ERR(TAG, "zgfx_compress_to_stream failed!"); error = ERROR_INTERNAL_ERROR; goto out; } - if (!WTSVirtualChannelWrite(context->priv->rdpgfx_channel, - (PCHAR) Stream_Buffer(fs), - Stream_GetPosition(fs), &written)) + if (!WTSVirtualChannelWrite(context->priv->rdpgfx_channel, + (PCHAR) Stream_Buffer(fs), + Stream_GetPosition(fs), &written)) { WLog_ERR(TAG, "WTSVirtualChannelWrite failed!"); error = ERROR_INTERNAL_ERROR; @@ -131,16 +129,14 @@ static UINT rdpgfx_server_packet_send(RdpgfxServerContext* context, wStream* s) if (written < Stream_GetPosition(fs)) { - WLog_WARN(TAG, "Unexpected bytes written: %lu/%lu", - 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); Stream_Free(s, TRUE); - return error; } @@ -148,10 +144,10 @@ out: * 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 + * to the stream before return, but the pduLength field might be * changed in rdpgfx_server_single_packet_send. * - * @param cmdId + * @param cmdId * @param dataLen estimated data length without header * * @return new stream @@ -160,43 +156,40 @@ static wStream* rdpgfx_server_single_packet_new(UINT16 cmdId, UINT32 dataLen) { UINT error; wStream* s; - UINT32 pduLength = rdpgfx_pdu_length(dataLen); - + UINT32 pduLength = rdpgfx_pdu_length(dataLen); s = Stream_New(NULL, pduLength); - if(!s) + if (!s) { - WLog_ERR(TAG, "Stream_New failed!"); - goto error; + 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; + goto error; } return s; - error: Stream_Free(s, TRUE); - return NULL; } /** * Function description - * Send the stream for single rdpgfx packet. + * 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) +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); } @@ -205,12 +198,13 @@ static INLINE UINT rdpgfx_server_single_packet_send(RdpgfxServerContext* context * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_send_caps_confirm_pdu(RdpgfxServerContext* context, RDPGFX_CAPS_CONFIRM_PDU* capsConfirm) +static UINT rdpgfx_send_caps_confirm_pdu(RdpgfxServerContext* context, + RDPGFX_CAPS_CONFIRM_PDU* capsConfirm) { RDPGFX_CAPSET* capsSet = capsConfirm->capsSet; wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_CAPSCONFIRM, - sizeof(RDPGFX_CAPSET) + sizeof(capsSet->flags)); + RDPGFX_CMDID_CAPSCONFIRM, + sizeof(RDPGFX_CAPSET) + sizeof(capsSet->flags)); if (!s) { @@ -221,7 +215,6 @@ static UINT rdpgfx_send_caps_confirm_pdu(RdpgfxServerContext* context, RDPGFX_CA Stream_Write_UINT32(s, capsSet->version); /* version (4 bytes) */ Stream_Write_UINT32(s, sizeof(capsSet->flags)); /* capsDataLength (4 bytes) */ Stream_Write_UINT32(s, capsSet->flags); /* capsData (4 bytes) */ - return rdpgfx_server_single_packet_send(context, s); } @@ -230,23 +223,24 @@ static UINT rdpgfx_send_caps_confirm_pdu(RdpgfxServerContext* context, RDPGFX_CA * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_send_reset_graphics_pdu(RdpgfxServerContext* context, RDPGFX_RESET_GRAPHICS_PDU* pdu) +static UINT rdpgfx_send_reset_graphics_pdu(RdpgfxServerContext* context, + RDPGFX_RESET_GRAPHICS_PDU* pdu) { UINT32 index; MONITOR_DEF* monitor; 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); + pdu->monitorCount); return ERROR_INVALID_DATA; } s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_RESETGRAPHICS, - RDPGFX_RESET_GRAPHICS_PDU_SIZE - RDPGFX_HEADER_SIZE); + RDPGFX_CMDID_RESETGRAPHICS, + RDPGFX_RESET_GRAPHICS_PDU_SIZE - RDPGFX_HEADER_SIZE); if (!s) { @@ -270,7 +264,6 @@ static UINT rdpgfx_send_reset_graphics_pdu(RdpgfxServerContext* context, RDPGFX_ /* pad (total size must be 340 bytes) */ Stream_SetPosition(s, RDPGFX_RESET_GRAPHICS_PDU_SIZE); - return rdpgfx_server_single_packet_send(context, s); } @@ -279,11 +272,12 @@ static UINT rdpgfx_send_reset_graphics_pdu(RdpgfxServerContext* context, RDPGFX_ * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_send_evict_cache_entry_pdu(RdpgfxServerContext* context, RDPGFX_EVICT_CACHE_ENTRY_PDU* pdu) +static UINT rdpgfx_send_evict_cache_entry_pdu(RdpgfxServerContext* context, + RDPGFX_EVICT_CACHE_ENTRY_PDU* pdu) { wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_EVICTCACHEENTRY, - sizeof(RDPGFX_EVICT_CACHE_ENTRY_PDU)); + RDPGFX_CMDID_EVICTCACHEENTRY, + sizeof(RDPGFX_EVICT_CACHE_ENTRY_PDU)); if (!s) { @@ -292,7 +286,6 @@ static UINT rdpgfx_send_evict_cache_entry_pdu(RdpgfxServerContext* context, RDPG } Stream_Write_UINT16(s, pdu->cacheSlot); /* cacheSlot (2 bytes) */ - return rdpgfx_server_single_packet_send(context, s); } @@ -301,12 +294,14 @@ static UINT rdpgfx_send_evict_cache_entry_pdu(RdpgfxServerContext* context, RDPG * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_send_cache_import_reply_pdu(RdpgfxServerContext* context, RDPGFX_CACHE_IMPORT_REPLY_PDU* pdu) +static UINT rdpgfx_send_cache_import_reply_pdu(RdpgfxServerContext* context, + RDPGFX_CACHE_IMPORT_REPLY_PDU* pdu) { UINT16 index; wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_CACHEIMPORTREPLY, - sizeof(RDPGFX_CACHE_IMPORT_REPLY_PDU) + sizeof(UINT16) * pdu->importedEntriesCount); + RDPGFX_CMDID_CACHEIMPORTREPLY, + sizeof(RDPGFX_CACHE_IMPORT_REPLY_PDU) + + sizeof(UINT16) * pdu->importedEntriesCount); if (!s) { @@ -314,7 +309,9 @@ static UINT rdpgfx_send_cache_import_reply_pdu(RdpgfxServerContext* context, RDP return CHANNEL_RC_NO_MEMORY; } - Stream_Write_UINT16(s, pdu->importedEntriesCount); /* importedEntriesCount (2 bytes) */ + /* importedEntriesCount (2 bytes) */ + Stream_Write_UINT16(s, pdu->importedEntriesCount); + for (index = 0; index < pdu->importedEntriesCount; index++) { Stream_Write_UINT16(s, pdu->cacheSlots[index]); /* cacheSlot (2 bytes) */ @@ -328,11 +325,12 @@ static UINT rdpgfx_send_cache_import_reply_pdu(RdpgfxServerContext* context, RDP * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_send_create_surface_pdu(RdpgfxServerContext* context, RDPGFX_CREATE_SURFACE_PDU* pdu) +static UINT rdpgfx_send_create_surface_pdu(RdpgfxServerContext* context, + RDPGFX_CREATE_SURFACE_PDU* pdu) { wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_CREATESURFACE, - sizeof(RDPGFX_CREATE_SURFACE_PDU)); + RDPGFX_CMDID_CREATESURFACE, + sizeof(RDPGFX_CREATE_SURFACE_PDU)); if (!s) { @@ -344,7 +342,6 @@ static UINT rdpgfx_send_create_surface_pdu(RdpgfxServerContext* context, RDPGFX_ Stream_Write_UINT16(s, pdu->width); /* width (2 bytes) */ Stream_Write_UINT16(s, pdu->height); /* height (2 bytes) */ Stream_Write_UINT8(s, pdu->pixelFormat); /* RDPGFX_PIXELFORMAT (1 byte) */ - return rdpgfx_server_single_packet_send(context, s); } @@ -353,11 +350,12 @@ static UINT rdpgfx_send_create_surface_pdu(RdpgfxServerContext* context, RDPGFX_ * * @return 0 on success, otherwise a Win32 error code */ -UINT rdpgfx_send_delete_surface_pdu(RdpgfxServerContext* context, RDPGFX_DELETE_SURFACE_PDU* pdu) +UINT rdpgfx_send_delete_surface_pdu(RdpgfxServerContext* context, + RDPGFX_DELETE_SURFACE_PDU* pdu) { wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_DELETESURFACE, - sizeof(RDPGFX_DELETE_SURFACE_PDU)); + RDPGFX_CMDID_DELETESURFACE, + sizeof(RDPGFX_DELETE_SURFACE_PDU)); if (!s) { @@ -366,17 +364,18 @@ UINT rdpgfx_send_delete_surface_pdu(RdpgfxServerContext* context, RDPGFX_DELETE_ } Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */ - return rdpgfx_server_single_packet_send(context, s); } -static INLINE void rdpgfx_write_start_frame_pdu(wStream* s, RDPGFX_START_FRAME_PDU* pdu) +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) +static INLINE void rdpgfx_write_end_frame_pdu(wStream* s, + RDPGFX_END_FRAME_PDU* pdu) { Stream_Write_UINT32(s, pdu->frameId); /* frameId (4 bytes) */ } @@ -386,11 +385,12 @@ static INLINE void rdpgfx_write_end_frame_pdu(wStream* s, RDPGFX_END_FRAME_PDU* * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_send_start_frame_pdu(RdpgfxServerContext* context, RDPGFX_START_FRAME_PDU* pdu) +static UINT rdpgfx_send_start_frame_pdu(RdpgfxServerContext* context, + RDPGFX_START_FRAME_PDU* pdu) { wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_STARTFRAME, - sizeof(RDPGFX_START_FRAME_PDU)); + RDPGFX_CMDID_STARTFRAME, + sizeof(RDPGFX_START_FRAME_PDU)); if (!s) { @@ -399,7 +399,6 @@ static UINT rdpgfx_send_start_frame_pdu(RdpgfxServerContext* context, RDPGFX_STA } rdpgfx_write_start_frame_pdu(s, pdu); - return rdpgfx_server_single_packet_send(context, s); } @@ -408,11 +407,12 @@ static UINT rdpgfx_send_start_frame_pdu(RdpgfxServerContext* context, RDPGFX_STA * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_send_end_frame_pdu(RdpgfxServerContext* context, RDPGFX_END_FRAME_PDU* pdu) +static UINT rdpgfx_send_end_frame_pdu(RdpgfxServerContext* context, + RDPGFX_END_FRAME_PDU* pdu) { wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_ENDFRAME, - sizeof(RDPGFX_END_FRAME_PDU)); + RDPGFX_CMDID_ENDFRAME, + sizeof(RDPGFX_END_FRAME_PDU)); if (!s) { @@ -421,22 +421,22 @@ static UINT rdpgfx_send_end_frame_pdu(RdpgfxServerContext* context, RDPGFX_END_F } rdpgfx_write_end_frame_pdu(s, pdu); - return rdpgfx_server_single_packet_send(context, s); } /** * Function description - * Estimate RFX_AVC420_BITMAP_STREAM structure size in stream + * Estimate RFX_AVC420_BITMAP_STREAM structure size in stream * * @return estimated size */ -static INLINE UINT32 rdpgfx_estimate_h264_avc420(RDPGFX_AVC420_BITMAP_STREAM *havc420) +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; + + (sizeof(RECTANGLE_16) + 2) /* regionRects + quantQualityVals */ + * havc420->meta.numRegionRects + + havc420->length; } /** @@ -447,28 +447,26 @@ static INLINE UINT32 rdpgfx_estimate_h264_avc420(RDPGFX_AVC420_BITMAP_STREAM *ha */ static INLINE UINT32 rdpgfx_estimate_surface_command(RDPGFX_SURFACE_COMMAND* cmd) { - RDPGFX_AVC420_BITMAP_STREAM *havc420 = NULL; - RDPGFX_AVC444_BITMAP_STREAM *havc444 = NULL; + 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) + 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; + 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; + havc444 = (RDPGFX_AVC444_BITMAP_STREAM*)cmd->extra; h264Size = sizeof(UINT32); /* cbAvc420EncodedBitstream1 */ - /* avc420EncodedBitstream1 */ havc420 = &(havc444->bitstream[0]); h264Size += rdpgfx_estimate_h264_avc420(havc420); @@ -490,7 +488,7 @@ static INLINE UINT32 rdpgfx_estimate_surface_command(RDPGFX_SURFACE_COMMAND* cmd /** * Function description - * Resolve RDPGFX_CMDID_WIRETOSURFACE_1 or RDPGFX_CMDID_WIRETOSURFACE_2 + * Resolve RDPGFX_CMDID_WIRETOSURFACE_1 or RDPGFX_CMDID_WIRETOSURFACE_2 * according to codecId * * @return 0 on success, otherwise a Win32 error code @@ -498,7 +496,7 @@ static INLINE UINT32 rdpgfx_estimate_surface_command(RDPGFX_SURFACE_COMMAND* cmd static INLINE UINT16 rdpgfx_surface_command_cmdid(RDPGFX_SURFACE_COMMAND* cmd) { if (cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE || - cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE_V2) + cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE_V2) { return RDPGFX_CMDID_WIRETOSURFACE_2; } @@ -517,12 +515,12 @@ static UINT rdpgfx_write_h264_metablock(wStream* s, RDPGFX_H264_METABLOCK* meta) RECTANGLE_16* regionRect; RDPGFX_H264_QUANT_QUALITY* quantQualityVal; UINT error = CHANNEL_RC_OK; - Stream_Write_UINT32(s, meta->numRegionRects); /* numRegionRects (4 bytes) */ for (index = 0; index < meta->numRegionRects; index++) { regionRect = &(meta->regionRects[index]); + if ((error = rdpgfx_write_rect16(s, regionRect))) { WLog_ERR(TAG, "rdpgfx_write_rect16 failed with error %lu!", error); @@ -533,11 +531,11 @@ static UINT rdpgfx_write_h264_metablock(wStream* s, RDPGFX_H264_METABLOCK* meta) for (index = 0; index < meta->numRegionRects; index++) { quantQualityVal = &(meta->quantQualityVals[index]); - Stream_Write_UINT8(s, quantQualityVal->qp - | (quantQualityVal->r << 6) - | (quantQualityVal->p << 7)); /* qpVal (1 byte) */ - Stream_Write_UINT8(s, quantQualityVal->qualityVal); /* qualityVal (1 byte) */ + | (quantQualityVal->r << 6) + | (quantQualityVal->p << 7)); /* qpVal (1 byte) */ + /* qualityVal (1 byte) */ + Stream_Write_UINT8(s, quantQualityVal->qualityVal); } return error; @@ -549,12 +547,15 @@ static UINT rdpgfx_write_h264_metablock(wStream* s, RDPGFX_H264_METABLOCK* meta) * * @return 0 on success, otherwise a Win32 error code */ -static INLINE UINT rdpgfx_write_h264_avc420(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(s, &(havc420->meta)))) { - WLog_ERR(TAG, "rdpgfx_write_h264_metablock failed with error %lu!", error); + WLog_ERR(TAG, "rdpgfx_write_h264_metablock failed with error %lu!", + error); return error; } @@ -572,44 +573,40 @@ static INLINE UINT rdpgfx_write_h264_avc420(wStream* s, RDPGFX_AVC420_BITMAP_STR static UINT rdpgfx_write_surface_command(wStream* s, RDPGFX_SURFACE_COMMAND* cmd) { UINT error = CHANNEL_RC_OK; - RDPGFX_AVC420_BITMAP_STREAM *havc420 = NULL; - RDPGFX_AVC444_BITMAP_STREAM *havc444 = NULL; + RDPGFX_AVC420_BITMAP_STREAM* havc420 = NULL; + RDPGFX_AVC444_BITMAP_STREAM* havc444 = NULL; UINT32 bitmapDataStart = 0; UINT32 bitmapDataLength = 0; if (cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE || - cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE_V2) + 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) */ Stream_Write_UINT8(s, cmd->format); /* pixelFormat (1 byte) */ - Stream_Write_UINT32(s, cmd->length); /* bitmapDataLength (4 bytes) */ Stream_Write(s, cmd->data, cmd->length); } 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) */ - Stream_Write_UINT16(s, cmd->left); /* left (2 bytes) */ Stream_Write_UINT16(s, cmd->top); /* top (2 bytes) */ Stream_Write_UINT16(s, cmd->right); /* right (2 bytes) */ Stream_Write_UINT16(s, cmd->bottom); /* bottom (2 bytes) */ - Stream_Write_UINT32(s, cmd->length); /* bitmapDataLength (4 bytes) */ bitmapDataStart = Stream_GetPosition(s); if (cmd->codecId == RDPGFX_CODECID_AVC420) { - havc420 = (RDPGFX_AVC420_BITMAP_STREAM *)cmd->extra; + havc420 = (RDPGFX_AVC420_BITMAP_STREAM*)cmd->extra; error = rdpgfx_write_h264_avc420(s, havc420); + if (error != CHANNEL_RC_OK) { WLog_ERR(TAG, "rdpgfx_write_h264_avc420 failed!"); @@ -618,14 +615,13 @@ static UINT rdpgfx_write_surface_command(wStream* s, RDPGFX_SURFACE_COMMAND* cmd } else if (cmd->codecId == RDPGFX_CODECID_AVC444) { - havc444 = (RDPGFX_AVC444_BITMAP_STREAM *)cmd->extra; + havc444 = (RDPGFX_AVC444_BITMAP_STREAM*)cmd->extra; havc420 = &(havc444->bitstream[0]); - /* avc420EncodedBitstreamInfo (4 bytes) */ Stream_Write_UINT32(s, havc420->length | (havc444->LC << 30UL)); - /* avc420EncodedBitstream1 */ error = rdpgfx_write_h264_avc420(s, havc420); + if (error != CHANNEL_RC_OK) { WLog_ERR(TAG, "rdpgfx_write_h264_avc420 failed!"); @@ -637,6 +633,7 @@ static UINT rdpgfx_write_surface_command(wStream* s, RDPGFX_SURFACE_COMMAND* cmd { havc420 = &(havc444->bitstream[0]); error = rdpgfx_write_h264_avc420(s, havc420); + if (error != CHANNEL_RC_OK) { WLog_ERR(TAG, "rdpgfx_write_h264_avc420 failed!"); @@ -650,7 +647,6 @@ static UINT rdpgfx_write_surface_command(wStream* s, RDPGFX_SURFACE_COMMAND* cmd } assert(Stream_GetPosition(s) <= Stream_Capacity(s)); - /* Fill actual bitmap data length */ bitmapDataLength = Stream_GetPosition(s) - bitmapDataStart; Stream_SetPosition(s, bitmapDataStart - sizeof(UINT32)); @@ -663,19 +659,19 @@ static UINT rdpgfx_write_surface_command(wStream* s, RDPGFX_SURFACE_COMMAND* cmd /** * Function description - * Send RDPGFX_CMDID_WIRETOSURFACE_1 or RDPGFX_CMDID_WIRETOSURFACE_2 + * 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) +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)); + rdpgfx_surface_command_cmdid(cmd), + rdpgfx_estimate_surface_command(cmd)); if (!s) { @@ -684,6 +680,7 @@ static UINT rdpgfx_send_surface_command(RdpgfxServerContext* context, RDPGFX_SUR } error = rdpgfx_write_surface_command(s, cmd); + if (error != CHANNEL_RC_OK) { WLog_ERR(TAG, "rdpgfx_write_surface_command failed!"); @@ -691,24 +688,22 @@ static UINT rdpgfx_send_surface_command(RdpgfxServerContext* context, RDPGFX_SUR } 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 + * 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) + RDPGFX_SURFACE_COMMAND* cmd, RDPGFX_START_FRAME_PDU* startFrame, + RDPGFX_END_FRAME_PDU* endFrame) { UINT error = CHANNEL_RC_OK; @@ -728,9 +723,9 @@ static UINT rdpgfx_send_surface_frame_command(RdpgfxServerContext* context, s = Stream_New(NULL, size); - if(!s) + if (!s) { - WLog_ERR(TAG, "Stream_New failed!"); + WLog_ERR(TAG, "Stream_New failed!"); return CHANNEL_RC_NO_MEMORY; } @@ -738,8 +733,9 @@ static UINT rdpgfx_send_surface_frame_command(RdpgfxServerContext* context, if (startFrame) { position = Stream_GetPosition(s); - error = rdpgfx_server_packet_init_header(s, - RDPGFX_CMDID_STARTFRAME, 0); + 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); @@ -752,9 +748,10 @@ static UINT rdpgfx_send_surface_frame_command(RdpgfxServerContext* context, /* 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 + 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); @@ -762,19 +759,22 @@ static UINT rdpgfx_send_surface_frame_command(RdpgfxServerContext* context, } 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); + 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); @@ -786,10 +786,8 @@ static UINT rdpgfx_send_surface_frame_command(RdpgfxServerContext* context, } return rdpgfx_server_packet_send(context, s); - error: Stream_Free(s, TRUE); - return error; } @@ -798,11 +796,12 @@ error: * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_send_delete_encoding_context_pdu(RdpgfxServerContext* context, RDPGFX_DELETE_ENCODING_CONTEXT_PDU* pdu) +static UINT rdpgfx_send_delete_encoding_context_pdu(RdpgfxServerContext* context, + RDPGFX_DELETE_ENCODING_CONTEXT_PDU* pdu) { wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_DELETEENCODINGCONTEXT, - sizeof(RDPGFX_DELETE_ENCODING_CONTEXT_PDU)); + RDPGFX_CMDID_DELETEENCODINGCONTEXT, + sizeof(RDPGFX_DELETE_ENCODING_CONTEXT_PDU)); if (!s) { @@ -812,7 +811,6 @@ static UINT rdpgfx_send_delete_encoding_context_pdu(RdpgfxServerContext* context Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */ Stream_Write_UINT32(s, pdu->codecContextId); /* codecContextId (4 bytes) */ - return rdpgfx_server_single_packet_send(context, s); } @@ -821,14 +819,16 @@ static UINT rdpgfx_send_delete_encoding_context_pdu(RdpgfxServerContext* context * * @return 0 on success, otherwise a Win32 error code */ -UINT rdpgfx_send_solid_fill_pdu(RdpgfxServerContext* context, RDPGFX_SOLID_FILL_PDU* pdu) +UINT rdpgfx_send_solid_fill_pdu(RdpgfxServerContext* context, + RDPGFX_SOLID_FILL_PDU* pdu) { UINT error = CHANNEL_RC_OK; UINT16 index; RECTANGLE_16* fillRect; wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_SOLIDFILL, - sizeof(RDPGFX_SOLID_FILL_PDU) + sizeof(RECTANGLE_16) * pdu->fillRectCount); + RDPGFX_CMDID_SOLIDFILL, + sizeof(RDPGFX_SOLID_FILL_PDU) + + sizeof(RECTANGLE_16) * pdu->fillRectCount); if (!s) { @@ -837,16 +837,20 @@ UINT rdpgfx_send_solid_fill_pdu(RdpgfxServerContext* context, RDPGFX_SOLID_FILL_ } Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */ - if ((error = rdpgfx_write_color32(s, &(pdu->fillPixel)))) /* fillPixel (4 bytes) */ + + /* fillPixel (4 bytes) */ + if ((error = rdpgfx_write_color32(s, &(pdu->fillPixel)))) { WLog_ERR(TAG, "rdpgfx_write_color32 failed with error %lu!", error); goto error; } Stream_Write_UINT16(s, pdu->fillRectCount); /* fillRectCount (2 bytes) */ + for (index = 0; index < pdu->fillRectCount; index++) { fillRect = &(pdu->fillRects[index]); + if ((error = rdpgfx_write_rect16(s, fillRect))) { WLog_ERR(TAG, "rdpgfx_write_rect16 failed with error %lu!", error); @@ -855,10 +859,8 @@ UINT rdpgfx_send_solid_fill_pdu(RdpgfxServerContext* context, RDPGFX_SOLID_FILL_ } return rdpgfx_server_single_packet_send(context, s); - error: Stream_Free(s, TRUE); - return error; } @@ -867,14 +869,16 @@ error: * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_send_surface_to_surface_pdu(RdpgfxServerContext* context, RDPGFX_SURFACE_TO_SURFACE_PDU* pdu) +static UINT rdpgfx_send_surface_to_surface_pdu(RdpgfxServerContext* context, + RDPGFX_SURFACE_TO_SURFACE_PDU* pdu) { UINT error = CHANNEL_RC_OK; UINT16 index; RDPGFX_POINT16* destPt; wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_SURFACETOSURFACE, - sizeof(RDPGFX_SURFACE_TO_SURFACE_PDU) + sizeof(RDPGFX_POINT16) * pdu->destPtsCount); + RDPGFX_CMDID_SURFACETOSURFACE, + sizeof(RDPGFX_SURFACE_TO_SURFACE_PDU) + + sizeof(RDPGFX_POINT16) * pdu->destPtsCount); if (!s) { @@ -885,16 +889,19 @@ static UINT rdpgfx_send_surface_to_surface_pdu(RdpgfxServerContext* context, RDP Stream_Write_UINT16(s, pdu->surfaceIdSrc); /* surfaceIdSrc (2 bytes) */ Stream_Write_UINT16(s, pdu->surfaceIdDest); /* surfaceIdDest (2 bytes) */ - if ((error = rdpgfx_write_rect16(s, &(pdu->rectSrc)))) /* rectSrc (8 bytes ) */ + /* rectSrc (8 bytes ) */ + if ((error = rdpgfx_write_rect16(s, &(pdu->rectSrc)))) { WLog_ERR(TAG, "rdpgfx_write_rect16 failed with error %lu!", error); goto error; } Stream_Write_UINT16(s, pdu->destPtsCount); /* destPtsCount (2 bytes) */ + for (index = 0; index < pdu->destPtsCount; index++) { destPt = &(pdu->destPts[index]); + if ((error = rdpgfx_write_point16(s, destPt))) { WLog_ERR(TAG, "rdpgfx_write_point16 failed with error %lu!", error); @@ -903,10 +910,8 @@ static UINT rdpgfx_send_surface_to_surface_pdu(RdpgfxServerContext* context, RDP } return rdpgfx_server_single_packet_send(context, s); - error: Stream_Free(s, TRUE); - return error; } @@ -915,12 +920,13 @@ error: * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_send_surface_to_cache_pdu(RdpgfxServerContext* context, RDPGFX_SURFACE_TO_CACHE_PDU* pdu) +static UINT rdpgfx_send_surface_to_cache_pdu(RdpgfxServerContext* context, + RDPGFX_SURFACE_TO_CACHE_PDU* pdu) { UINT error = CHANNEL_RC_OK; wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_SURFACETOCACHE, - sizeof(RDPGFX_SURFACE_TO_CACHE_PDU)); + RDPGFX_CMDID_SURFACETOCACHE, + sizeof(RDPGFX_SURFACE_TO_CACHE_PDU)); if (!s) { @@ -931,17 +937,17 @@ static UINT rdpgfx_send_surface_to_cache_pdu(RdpgfxServerContext* context, RDPGF Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */ Stream_Write_UINT64(s, pdu->cacheKey); /* cacheKey (8 bytes) */ Stream_Write_UINT16(s, pdu->cacheSlot); /* cacheSlot (2 bytes) */ - if ((error = rdpgfx_write_rect16(s, &(pdu->rectSrc)))) /* rectSrc (8 bytes ) */ + + /* rectSrc (8 bytes ) */ + if ((error = rdpgfx_write_rect16(s, &(pdu->rectSrc)))) { WLog_ERR(TAG, "rdpgfx_write_rect16 failed with error %lu!", error); goto error; } return rdpgfx_server_single_packet_send(context, s); - error: Stream_Free(s, TRUE); - return error; } @@ -950,14 +956,16 @@ error: * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_send_cache_to_surface_pdu(RdpgfxServerContext* context, RDPGFX_CACHE_TO_SURFACE_PDU* pdu) +static UINT rdpgfx_send_cache_to_surface_pdu(RdpgfxServerContext* context, + RDPGFX_CACHE_TO_SURFACE_PDU* pdu) { UINT error = CHANNEL_RC_OK; UINT16 index; RDPGFX_POINT16* destPt; wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_CACHETOSURFACE, - sizeof(RDPGFX_CACHE_TO_SURFACE_PDU) + sizeof(RDPGFX_POINT16) * pdu->destPtsCount); + RDPGFX_CMDID_CACHETOSURFACE, + sizeof(RDPGFX_CACHE_TO_SURFACE_PDU) + + sizeof(RDPGFX_POINT16) * pdu->destPtsCount); if (!s) { @@ -972,6 +980,7 @@ static UINT rdpgfx_send_cache_to_surface_pdu(RdpgfxServerContext* context, RDPGF for (index = 0; index < pdu->destPtsCount; index++) { destPt = &(pdu->destPts[index]); + if ((error = rdpgfx_write_point16(s, destPt))) { WLog_ERR(TAG, "rdpgfx_write_point16 failed with error %lu", error); @@ -980,10 +989,8 @@ static UINT rdpgfx_send_cache_to_surface_pdu(RdpgfxServerContext* context, RDPGF } return rdpgfx_server_single_packet_send(context, s); - error: Stream_Free(s, TRUE); - return error; } @@ -992,11 +999,12 @@ error: * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_send_map_surface_to_output_pdu(RdpgfxServerContext* context, RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU* pdu) +static UINT rdpgfx_send_map_surface_to_output_pdu(RdpgfxServerContext* context, + RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU* pdu) { wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_MAPSURFACETOOUTPUT, - sizeof(RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU)); + RDPGFX_CMDID_MAPSURFACETOOUTPUT, + sizeof(RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU)); if (!s) { @@ -1008,7 +1016,6 @@ static UINT rdpgfx_send_map_surface_to_output_pdu(RdpgfxServerContext* context, Stream_Write_UINT16(s, 0); /* reserved (2 bytes). Must be 0 */ Stream_Write_UINT32(s, pdu->outputOriginX); /* outputOriginX (4 bytes) */ Stream_Write_UINT32(s, pdu->outputOriginY); /* outputOriginY (4 bytes) */ - return rdpgfx_server_single_packet_send(context, s); } @@ -1017,11 +1024,12 @@ static UINT rdpgfx_send_map_surface_to_output_pdu(RdpgfxServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_send_map_surface_to_window_pdu(RdpgfxServerContext* context, RDPGFX_MAP_SURFACE_TO_WINDOW_PDU* pdu) +static UINT rdpgfx_send_map_surface_to_window_pdu(RdpgfxServerContext* context, + RDPGFX_MAP_SURFACE_TO_WINDOW_PDU* pdu) { wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_MAPSURFACETOWINDOW, - sizeof(RDPGFX_MAP_SURFACE_TO_WINDOW_PDU)); + RDPGFX_CMDID_MAPSURFACETOWINDOW, + sizeof(RDPGFX_MAP_SURFACE_TO_WINDOW_PDU)); if (!s) { @@ -1033,7 +1041,6 @@ static UINT rdpgfx_send_map_surface_to_window_pdu(RdpgfxServerContext* context, Stream_Write_UINT64(s, pdu->windowId); /* windowId (8 bytes) */ Stream_Write_UINT32(s, pdu->mappedWidth); /* mappedWidth (4 bytes) */ Stream_Write_UINT32(s, pdu->mappedHeight); /* mappedHeight (4 bytes) */ - return rdpgfx_server_single_packet_send(context, s); } @@ -1042,26 +1049,30 @@ static UINT rdpgfx_send_map_surface_to_window_pdu(RdpgfxServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_recv_frame_acknowledge_pdu(RdpgfxServerContext* context, wStream* s) +static UINT rdpgfx_recv_frame_acknowledge_pdu(RdpgfxServerContext* context, + wStream* s) { 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; - } + 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) */ + /* totalFramesDecoded (4 bytes) */ + Stream_Read_UINT32(s, pdu.totalFramesDecoded); if (context) { IFCALLRET(context->FrameAcknowledge, error, context, &pdu); + if (error) - WLog_ERR(TAG, "context->FrameAcknowledge failed with error %lu", error); + WLog_ERR(TAG, "context->FrameAcknowledge failed with error %lu", + error); } return error; @@ -1072,20 +1083,23 @@ static UINT rdpgfx_recv_frame_acknowledge_pdu(RdpgfxServerContext* context, wStr * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_recv_cache_import_offer_pdu(RdpgfxServerContext* context, wStream* s) +static UINT rdpgfx_recv_cache_import_offer_pdu(RdpgfxServerContext* context, + wStream* s) { UINT16 index; RDPGFX_CACHE_IMPORT_OFFER_PDU pdu; 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; - } + if (Stream_GetRemainingLength(s) < sizeof(UINT16)) + { + WLog_ERR(TAG, "not enough data!"); + return ERROR_INVALID_DATA; + } + + /* cacheEntriesCount (2 bytes) */ + Stream_Read_UINT16(s, pdu.cacheEntriesCount); - Stream_Read_UINT16(s, pdu.cacheEntriesCount); /* cacheEntriesCount (2 bytes) */ if (pdu.cacheEntriesCount <= 0) { /* According to the latest spec, capsSetCount <= 3 */ @@ -1093,16 +1107,16 @@ static UINT rdpgfx_recv_cache_import_offer_pdu(RdpgfxServerContext* context, wSt 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; - } + 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)); + pdu.cacheEntries = (RDPGFX_CACHE_ENTRY_METADATA*) + calloc(pdu.cacheEntriesCount, + sizeof(RDPGFX_CACHE_ENTRY_METADATA)); if (!pdu.cacheEntries) { @@ -1114,18 +1128,20 @@ static UINT rdpgfx_recv_cache_import_offer_pdu(RdpgfxServerContext* context, wSt { cacheEntries = &(pdu.cacheEntries[index]); Stream_Read_UINT64(s, cacheEntries->cacheKey); /* cacheKey (8 bytes) */ - Stream_Read_UINT32(s, cacheEntries->bitmapLength); /* bitmapLength (4 bytes) */ + /* bitmapLength (4 bytes) */ + Stream_Read_UINT32(s, cacheEntries->bitmapLength); } if (context) { IFCALLRET(context->CacheImportOffer, error, context, &pdu); + if (error) - WLog_ERR(TAG, "context->CacheImportOffer failed with error %lu", error); + WLog_ERR(TAG, "context->CacheImportOffer failed with error %lu", + error); } free(pdu.cacheEntries); - return error; } @@ -1134,7 +1150,8 @@ static UINT rdpgfx_recv_cache_import_offer_pdu(RdpgfxServerContext* context, wSt * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_recv_caps_advertise_pdu(RdpgfxServerContext* context, wStream* s) +static UINT rdpgfx_recv_caps_advertise_pdu(RdpgfxServerContext* context, + wStream* s) { UINT16 index; RDPGFX_CAPSET* capsSet; @@ -1143,13 +1160,14 @@ static UINT rdpgfx_recv_caps_advertise_pdu(RdpgfxServerContext* context, wStream UINT error = CHANNEL_RC_OK; UINT32 capsDataLength; - if (Stream_GetRemainingLength(s) < sizeof(UINT16)) - { - WLog_ERR(TAG, "not enough data!"); - return ERROR_INVALID_DATA; - } + 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 */ @@ -1157,12 +1175,12 @@ static UINT rdpgfx_recv_caps_advertise_pdu(RdpgfxServerContext* context, wStream 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; - } + 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; @@ -1171,17 +1189,21 @@ static UINT rdpgfx_recv_caps_advertise_pdu(RdpgfxServerContext* context, wStream capsSet = &(pdu.capsSets[index]); Stream_Read_UINT32(s, capsSet->version); /* version (4 bytes) */ Stream_Read_UINT32(s, capsDataLength); /* capsDataLength (4 bytes) */ + if (capsDataLength != 4) { - WLog_ERR(TAG, "capsDataLength does not equal to 4: %lu", capsDataLength); + WLog_ERR(TAG, "capsDataLength does not equal to 4: %lu", + capsDataLength); return ERROR_INVALID_DATA; } + Stream_Read_UINT32(s, capsSet->flags); /* capsData (4 bytes) */ } if (context) { IFCALLRET(context->CapsAdvertise, error, context, &pdu); + if (error) WLog_ERR(TAG, "context->CapsAdvertise failed with error %lu", error); } @@ -1194,16 +1216,17 @@ static UINT rdpgfx_recv_caps_advertise_pdu(RdpgfxServerContext* context, wStream * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_recv_qoe_frame_acknowledge_pdu(RdpgfxServerContext* context, wStream* s) +static UINT rdpgfx_recv_qoe_frame_acknowledge_pdu(RdpgfxServerContext* context, + wStream* s) { 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; - } + 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) */ @@ -1213,8 +1236,10 @@ static UINT rdpgfx_recv_qoe_frame_acknowledge_pdu(RdpgfxServerContext* context, if (context) { IFCALLRET(context->QoeFrameAcknowledge, error, context, &pdu); + if (error) - WLog_ERR(TAG, "context->QoeFrameAcknowledge failed with error %lu", error); + WLog_ERR(TAG, "context->QoeFrameAcknowledge failed with error %lu", + error); } return error; @@ -1230,7 +1255,6 @@ static UINT rdpgfx_server_receive_pdu(RdpgfxServerContext* context, wStream* s) int beg, end; RDPGFX_HEADER header; UINT error = CHANNEL_RC_OK; - beg = Stream_GetPosition(s); if ((error = rdpgfx_read_header(s, &header))) @@ -1240,30 +1264,39 @@ static UINT rdpgfx_server_receive_pdu(RdpgfxServerContext* context, wStream* s) } WLog_DBG(TAG, "cmdId: %s (0x%04X) flags: 0x%04X pduLength: %d", - rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId, header.flags, header.pduLength); + rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId, + header.flags, header.pduLength); switch (header.cmdId) { case RDPGFX_CMDID_FRAMEACKNOWLEDGE: + if ((error = rdpgfx_recv_frame_acknowledge_pdu(context, s))) - WLog_ERR(TAG, "rdpgfx_recv_frame_acknowledge_pdu failed with error %lu!", error); - break; + WLog_ERR(TAG, "rdpgfx_recv_frame_acknowledge_pdu " + "failed with error %lu!", error); + break; case RDPGFX_CMDID_CACHEIMPORTOFFER: + if ((error = rdpgfx_recv_cache_import_offer_pdu(context, s))) - WLog_ERR(TAG, "rdpgfx_recv_cache_import_offer_pdu failed with error %lu!", error); - break; + WLog_ERR(TAG, "rdpgfx_recv_cache_import_offer_pdu " + "failed with error %lu!", error); + break; case RDPGFX_CMDID_CAPSADVERTISE: + if ((error = rdpgfx_recv_caps_advertise_pdu(context, s))) - WLog_ERR(TAG, "rdpgfx_recv_caps_advertise_pdu failed with error %lu!", error); - break; + WLog_ERR(TAG, "rdpgfx_recv_caps_advertise_pdu " + "failed with error %lu!", error); + break; case RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE: - if ((error = rdpgfx_recv_qoe_frame_acknowledge_pdu(context, s))) - WLog_ERR(TAG, "rdpgfx_recv_qoe_frame_acknowledge_pdu failed with error %lu!", error); - break; + if ((error = rdpgfx_recv_qoe_frame_acknowledge_pdu(context, s))) + WLog_ERR(TAG, "rdpgfx_recv_qoe_frame_acknowledge_pdu " + "failed with error %lu!", error); + + break; default: error = CHANNEL_RC_BAD_PROC; break; @@ -1281,90 +1314,31 @@ static UINT rdpgfx_server_receive_pdu(RdpgfxServerContext* context, wStream* s) if (end != (beg + header.pduLength)) { WLog_ERR(TAG, "Unexpected gfx pdu end: Actual: %d, Expected: %d", - end, (beg + header.pduLength)); + end, (beg + header.pduLength)); Stream_SetPosition(s, (beg + header.pduLength)); } return error; - } static void* rdpgfx_server_thread_func(void* arg) { RdpgfxServerContext* context = (RdpgfxServerContext*) arg; RdpgfxServerPrivate* priv = context->priv; - wStream* s; DWORD status; DWORD nCount; void* buffer; HANDLE events[8]; - HANDLE ChannelEvent; DWORD BytesReturned = 0; UINT error = CHANNEL_RC_OK; - BOOL ready = FALSE; - buffer = NULL; BytesReturned = 0; - ChannelEvent = NULL; - - /* Query for channel event handle */ - if (WTSVirtualChannelQuery(priv->rdpgfx_channel, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE) - { - if (BytesReturned == sizeof(HANDLE)) - CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); - - WTSFreeMemory(buffer); - } - else - { - WLog_ERR(TAG, "WTSVirtualChannelQuery failed"); - error = ERROR_INTERNAL_ERROR; - goto out; - } - nCount = 0; events[nCount++] = priv->stopEvent; - events[nCount++] = ChannelEvent; - - /* Wait for the client to confirm that the dynamic channel is ready */ - while (1) - { - if ((status = WaitForMultipleObjects(nCount, events, FALSE, 100)) == WAIT_OBJECT_0) - goto out; - - if (status == WAIT_FAILED) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %lu", error); - goto out; - } - - if (WTSVirtualChannelQuery(priv->rdpgfx_channel, WTSVirtualChannelReady, &buffer, &BytesReturned) == FALSE) - { - WLog_ERR(TAG, "WTSVirtualChannelQuery failed"); - error = ERROR_INTERNAL_ERROR; - goto out; - } - - ready = *((BOOL*) buffer); - - WTSFreeMemory(buffer); - - if (ready) - break; - } - - /* Create shared stream */ - s = Stream_New(NULL, 4096); - if (!s) - { - WLog_ERR(TAG, "Stream_New failed!"); - error = CHANNEL_RC_NO_MEMORY; - goto out; - } + events[nCount++] = priv->channelEvent; /* Main virtual channel loop. RDPGFX do not need version negotiation */ - while (ready) + while (TRUE) { status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); @@ -1372,65 +1346,24 @@ static void* rdpgfx_server_thread_func(void* arg) { error = GetLastError(); WLog_ERR(TAG, "WaitForMultipleObjects failed with error %lu", error); - goto out; + break; } - /* Stop Event */ + /* Stop Event */ if (status == WAIT_OBJECT_0) break; - /* Channel Event */ - Stream_SetPosition(s, 0); - - if (!WTSVirtualChannelRead(priv->rdpgfx_channel, 0, NULL, 0, &BytesReturned)) - { - WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); - error = ERROR_INTERNAL_ERROR; - break; - } - - if (BytesReturned < 1) - continue; - - if (!Stream_EnsureRemainingCapacity(s, BytesReturned)) - { - WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); - error = CHANNEL_RC_NO_MEMORY; - break; - } - - if (WTSVirtualChannelRead(priv->rdpgfx_channel, 0, (PCHAR) Stream_Buffer(s), - Stream_Capacity(s), &BytesReturned) == FALSE) - { - WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); - error = ERROR_INTERNAL_ERROR; - break; - } - - Stream_SetLength(s, BytesReturned); - Stream_SetPosition(s, 0); - - 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) + if ((error = rdpgfx_server_handle_messages(context))) { + WLog_ERR(TAG, "rdpgfx_server_handle_messages failed with error %lu", + error); break; } } - Stream_Free(s, TRUE); -out: - WTSVirtualChannelClose(priv->rdpgfx_channel); - priv->rdpgfx_channel = NULL; if (error && context->rdpcontext) - setChannelError(context->rdpcontext, error, "rdpgfx_server_thread_func reported an error"); + setChannelError(context->rdpcontext, error, + "rdpgfx_server_thread_func reported an error"); ExitThread((DWORD)error); return NULL; @@ -1438,24 +1371,28 @@ out: static BOOL rdpgfx_server_open(RdpgfxServerContext* context) { - RdpgfxServerPrivate* priv = (RdpgfxServerPrivate *) context->priv; + RdpgfxServerPrivate* priv = (RdpgfxServerPrivate*) context->priv; + void* buffer = NULL; - if (!priv->thread) + if (!priv->isOpened) { PULONG pSessionId = NULL; DWORD BytesReturned = 0; - priv->SessionId = WTS_CURRENT_SESSION; if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, - WTSSessionId, (LPSTR*) &pSessionId, &BytesReturned)) + WTSSessionId, (LPSTR*) &pSessionId, + &BytesReturned) == FALSE) { - priv->SessionId = (DWORD) *pSessionId; - WTSFreeMemory(pSessionId); + WLog_ERR(TAG, "WTSQuerySessionInformationA failed!"); + return FALSE; } + priv->SessionId = (DWORD) *pSessionId; + WTSFreeMemory(pSessionId); priv->rdpgfx_channel = WTSVirtualChannelOpenEx(priv->SessionId, - RDPGFX_DVC_CHANNEL_NAME, WTS_CHANNEL_OPTION_DYNAMIC); + RDPGFX_DVC_CHANNEL_NAME, + WTS_CHANNEL_OPTION_DYNAMIC); if (!priv->rdpgfx_channel) { @@ -1463,56 +1400,80 @@ static BOOL rdpgfx_server_open(RdpgfxServerContext* context) return FALSE; } + /* Query for channel event handle */ + if (!WTSVirtualChannelQuery(priv->rdpgfx_channel, WTSVirtualEventHandle, + &buffer, &BytesReturned) + || (BytesReturned != sizeof(HANDLE))) + { + WLog_ERR(TAG, "WTSVirtualChannelQuery failed " + "or invalid returned size(%d)", + BytesReturned); + + if (buffer) + WTSFreeMemory(buffer); + + goto out_close; + } + + CopyMemory(&priv->channelEvent, buffer, sizeof(HANDLE)); + WTSFreeMemory(buffer); + if (!(priv->zgfx = zgfx_context_new(TRUE))) { WLog_ERR(TAG, "Create zgfx context failed!"); goto out_close; } - if (!(priv->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) + if (priv->ownThread) { - WLog_ERR(TAG, "CreateEvent failed!"); - 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!"); - goto out_stopEvent; + if (!(priv->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) + { + WLog_ERR(TAG, "CreateEvent failed!"); + 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!"); + goto out_stopEvent; + } } + priv->isOpened = TRUE; + priv->isReady = FALSE; return TRUE; } - WLog_ERR(TAG, "thread already running!"); + WLog_ERR(TAG, "RDPGFX channel is already opened!"); 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; - + priv->channelEvent = NULL; return FALSE; } static BOOL rdpgfx_server_close(RdpgfxServerContext* context) { - RdpgfxServerPrivate* priv = (RdpgfxServerPrivate *) context->priv; + RdpgfxServerPrivate* priv = (RdpgfxServerPrivate*) context->priv; - if (priv->thread) + if (priv->ownThread && priv->thread) { SetEvent(priv->stopEvent); + if (WaitForSingleObject(priv->thread, INFINITE) == WAIT_FAILED) { - WLog_ERR(TAG, "WaitForSingleObject failed with error %lu", GetLastError()); + WLog_ERR(TAG, "WaitForSingleObject failed with error %lu", + GetLastError()); return FALSE; } @@ -1531,15 +1492,18 @@ static BOOL rdpgfx_server_close(RdpgfxServerContext* context) priv->rdpgfx_channel = NULL; } + priv->channelEvent = NULL; + priv->isOpened = FALSE; + priv->isReady = FALSE; return TRUE; } RdpgfxServerContext* rdpgfx_server_context_new(HANDLE vcm) { RdpgfxServerContext* context; - RdpgfxServerPrivate *priv; + RdpgfxServerPrivate* priv; + context = (RdpgfxServerContext*)calloc(1, sizeof(RdpgfxServerContext)); - context = (RdpgfxServerContext *)calloc(1, sizeof(RdpgfxServerContext)); if (!context) { WLog_ERR(TAG, "calloc failed!"); @@ -1549,7 +1513,6 @@ RdpgfxServerContext* rdpgfx_server_context_new(HANDLE vcm) context->vcm = vcm; context->Open = rdpgfx_server_open; context->Close = rdpgfx_server_close; - context->ResetGraphics = rdpgfx_send_reset_graphics_pdu; context->StartFrame = rdpgfx_send_start_frame_pdu; context->EndFrame = rdpgfx_send_end_frame_pdu; @@ -1571,16 +1534,30 @@ RdpgfxServerContext* rdpgfx_server_context_new(HANDLE vcm) context->CapsConfirm = rdpgfx_send_caps_confirm_pdu; context->FrameAcknowledge = NULL; context->QoeFrameAcknowledge = NULL; + context->priv = priv = (RdpgfxServerPrivate*) + calloc(1, sizeof(RdpgfxServerPrivate)); - context->priv = priv = (RdpgfxServerPrivate *)calloc(1, sizeof(RdpgfxServerPrivate)); if (!priv) { WLog_ERR(TAG, "calloc failed!"); goto out_free; } - return (RdpgfxServerContext*) context; + /* Create shared input stream */ + priv->input_stream = Stream_New(NULL, 4); + if (!priv->input_stream) + { + WLog_ERR(TAG, "Stream_New failed!"); + goto out_free_priv; + } + + priv->isOpened = FALSE; + priv->isReady = FALSE; + priv->ownThread = TRUE; + return (RdpgfxServerContext*) context; +out_free_priv: + free(context->priv); out_free: free(context); return NULL; @@ -1590,7 +1567,98 @@ void rdpgfx_server_context_free(RdpgfxServerContext* context) { rdpgfx_server_close(context); - free(context->priv); + if (context->priv) + Stream_Free(context->priv->input_stream, TRUE); + free(context->priv); free(context); } + +FREERDP_API HANDLE rdpgfx_server_get_event_handle(RdpgfxServerContext* context) +{ + return context->priv->channelEvent; +} + +/* + * Handle rpdgfx messages - server side + * + * @param Server side context + * + * @return 0 on success + * ERROR_NO_DATA if no data could be read this time + * otherwise a Win32 error code + */ +UINT rdpgfx_server_handle_messages(RdpgfxServerContext* context) +{ + DWORD BytesReturned; + void* buffer; + UINT ret = CHANNEL_RC_OK; + RdpgfxServerPrivate* priv = context->priv; + wStream* s = priv->input_stream; + + /* Check whether the dynamic channel is ready */ + if (!priv->isReady) + { + if (WTSVirtualChannelQuery(priv->rdpgfx_channel, + WTSVirtualChannelReady, + &buffer, &BytesReturned) == FALSE) + { + if (GetLastError() == ERROR_NO_DATA) + return ERROR_NO_DATA; + + WLog_ERR(TAG, "WTSVirtualChannelQuery failed"); + return ERROR_INTERNAL_ERROR; + } + + priv->isReady = *((BOOL*) buffer); + WTSFreeMemory(buffer); + } + + /* Consume channel event only after the gfx dynamic channel is ready */ + if (priv->isReady) + { + Stream_SetPosition(s, 0); + + if (!WTSVirtualChannelRead(priv->rdpgfx_channel, + 0, NULL, 0, &BytesReturned)) + { + if (GetLastError() == ERROR_NO_DATA) + return ERROR_NO_DATA; + + WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); + return ERROR_INTERNAL_ERROR; + } + + if (BytesReturned < 1) + return CHANNEL_RC_OK; + + if (!Stream_EnsureRemainingCapacity(s, BytesReturned)) + { + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + if (WTSVirtualChannelRead(priv->rdpgfx_channel, 0, + (PCHAR) Stream_Buffer(s), + Stream_Capacity(s), &BytesReturned) == FALSE) + { + WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); + return ERROR_INTERNAL_ERROR; + } + + Stream_SetLength(s, BytesReturned); + Stream_SetPosition(s, 0); + + while (((size_t) Stream_GetPosition(s)) < Stream_Length(s)) + { + if ((ret = rdpgfx_server_receive_pdu(context, s))) + { + WLog_ERR(TAG, "rdpgfx_server_receive_pdu " + "failed with error %lu!", ret); + return ret; + } + } + } + + return ret; +} diff --git a/channels/rdpgfx/server/rdpgfx_main.h b/channels/rdpgfx/server/rdpgfx_main.h index caad8ccf1..be29b7638 100644 --- a/channels/rdpgfx/server/rdpgfx_main.h +++ b/channels/rdpgfx/server/rdpgfx_main.h @@ -26,11 +26,15 @@ struct _rdpgfx_server_private { ZGFX_CONTEXT* zgfx; + BOOL ownThread; HANDLE thread; HANDLE stopEvent; + HANDLE channelEvent; void* rdpgfx_channel; DWORD SessionId; - BOOL opened; + wStream* input_stream; + BOOL isOpened; + BOOL isReady; }; #endif /* FREERDP_CHANNEL_RDPGFX_SERVER_MAIN_H */ diff --git a/include/freerdp/server/rdpgfx.h b/include/freerdp/server/rdpgfx.h index 983779e11..fad778935 100644 --- a/include/freerdp/server/rdpgfx.h +++ b/include/freerdp/server/rdpgfx.h @@ -28,27 +28,27 @@ typedef struct _rdpgfx_server_private RdpgfxServerPrivate; typedef BOOL (*psRdpgfxServerOpen)(RdpgfxServerContext* context); typedef BOOL (*psRdpgfxServerClose)(RdpgfxServerContext* context); -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); +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 { @@ -90,6 +90,8 @@ extern "C" { FREERDP_API RdpgfxServerContext* rdpgfx_server_context_new(HANDLE vcm); FREERDP_API void rdpgfx_server_context_free(RdpgfxServerContext* context); +FREERDP_API HANDLE rdpgfx_server_get_event_handle(RdpgfxServerContext* context); +FREERDP_API UINT rdpgfx_server_handle_messages(RdpgfxServerContext* context); #ifdef __cplusplus } From 26c98e4429c52128a3fa967783bcb8aaea2089aa Mon Sep 17 00:00:00 2001 From: "zihao.jiang" Date: Sat, 28 May 2016 13:43:33 +0800 Subject: [PATCH 4/8] rdpgfx/server: Minor fix: use switch for pdu length estimation --- channels/rdpgfx/server/rdpgfx_main.c | 51 +++++++++++++--------------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/channels/rdpgfx/server/rdpgfx_main.c b/channels/rdpgfx/server/rdpgfx_main.c index fbcf56b12..98e8e29fe 100644 --- a/channels/rdpgfx/server/rdpgfx_main.c +++ b/channels/rdpgfx/server/rdpgfx_main.c @@ -452,37 +452,32 @@ static INLINE UINT32 rdpgfx_estimate_surface_command(RDPGFX_SURFACE_COMMAND* cmd UINT32 h264Size = 0; /* Create new stream according to codec. */ - if (cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE || - cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE_V2) + switch (cmd->codecId) { - 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]); + case RDPGFX_CODECID_CAPROGRESSIVE: + case RDPGFX_CODECID_CAPROGRESSIVE_V2: + return sizeof(RDPGFX_WIRE_TO_SURFACE_PDU_2) + cmd->length; + case 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; + case 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); - } - return sizeof(RDPGFX_WIRE_TO_SURFACE_PDU_1) + h264Size; - } - else - { - return sizeof(RDPGFX_WIRE_TO_SURFACE_PDU_1) + cmd->length; + /* avc420EncodedBitstream2 */ + if (havc444->LC == 0) + { + havc420 = &(havc444->bitstream[1]); + h264Size += rdpgfx_estimate_h264_avc420(havc420); + } + + return sizeof(RDPGFX_WIRE_TO_SURFACE_PDU_1) + h264Size; + default: + return sizeof(RDPGFX_WIRE_TO_SURFACE_PDU_1) + cmd->length; } } From a15b8fff66d16bb1670e3bad447554e35b87eb11 Mon Sep 17 00:00:00 2001 From: "zihao.jiang" Date: Fri, 3 Jun 2016 02:33:31 +0800 Subject: [PATCH 5/8] rdpgfx/server: Minor fix: allow configurable codec parameter --- include/freerdp/server/shadow.h | 8 ++++++++ server/shadow/shadow_encoder.c | 9 ++++++--- server/shadow/shadow_server.c | 6 ++++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/include/freerdp/server/shadow.h b/include/freerdp/server/shadow.h index e718ea015..20c611537 100644 --- a/include/freerdp/server/shadow.h +++ b/include/freerdp/server/shadow.h @@ -127,6 +127,14 @@ struct rdp_shadow_server BOOL authentication; int selectedMonitor; RECTANGLE_16 subRect; + + /* Codec settings */ + RLGR_MODE rfxMode; + H264_RATECONTROL_MODE h264RateControlMode; + UINT32 h264BitRate; + FLOAT h264FrameRate; + UINT32 h264QP; + char* ipcSocket; char* ConfigPath; char* CertificateFile; diff --git a/server/shadow/shadow_encoder.c b/server/shadow/shadow_encoder.c index be3194c6d..44fb3ac16 100644 --- a/server/shadow/shadow_encoder.c +++ b/server/shadow/shadow_encoder.c @@ -139,9 +139,7 @@ int shadow_encoder_init_rfx(rdpShadowEncoder* encoder) if (!rfx_context_reset(encoder->rfx, encoder->width, encoder->height)) goto fail; - encoder->rfx->mode = RLGR3; - encoder->rfx->width = encoder->width; - encoder->rfx->height = encoder->height; + encoder->rfx->mode = encoder->server->rfxMode; rfx_context_set_pixel_format(encoder->rfx, RDP_PIXEL_FORMAT_B8G8R8A8); @@ -246,6 +244,11 @@ int shadow_encoder_init_h264(rdpShadowEncoder* encoder) if (!h264_context_reset(encoder->h264, encoder->width, encoder->height)) goto fail; + encoder->h264->RateControlMode = encoder->server->h264RateControlMode; + encoder->h264->BitRate = encoder->server->h264BitRate; + encoder->h264->FrameRate = encoder->server->h264FrameRate; + encoder->h264->QP = encoder->server->h264QP; + encoder->codecs |= FREERDP_CODEC_AVC420; return 1; diff --git a/server/shadow/shadow_server.c b/server/shadow/shadow_server.c index ad5ebbe78..cbbff4efd 100644 --- a/server/shadow/shadow_server.c +++ b/server/shadow/shadow_server.c @@ -769,6 +769,12 @@ rdpShadowServer* shadow_server_new() server->mayView = TRUE; server->mayInteract = TRUE; + server->rfxMode = RLGR3; + server->h264RateControlMode = H264_RATECONTROL_VBR; + server->h264BitRate = 1000000; + server->h264FrameRate = 30; + server->h264QP = 0; + server->authentication = FALSE; server->settings = freerdp_settings_new(FREERDP_SETTINGS_SERVER_MODE); From 7d0fa79f197124f09785ef10c0efe657ba2fcbf6 Mon Sep 17 00:00:00 2001 From: "zihao.jiang" Date: Tue, 16 Aug 2016 14:49:56 +0800 Subject: [PATCH 6/8] rdpgfx/server: More minor fix according to comments: Not use sizeof on packet memory structure for stream length check/estimating and use number directly. Most of the packet size could be obviously calculated/verified from code and comments in same function. Macro is defined for those were referenced multiple times. --- channels/rdpgfx/client/rdpgfx_main.c | 8 +-- channels/rdpgfx/server/rdpgfx_main.c | 74 +++++++++++----------------- include/freerdp/channels/rdpgfx.h | 8 +++ 3 files changed, 41 insertions(+), 49 deletions(-) diff --git a/channels/rdpgfx/client/rdpgfx_main.c b/channels/rdpgfx/client/rdpgfx_main.c index 50403eade..e2aa58607 100644 --- a/channels/rdpgfx/client/rdpgfx_main.c +++ b/channels/rdpgfx/client/rdpgfx_main.c @@ -457,7 +457,7 @@ static UINT rdpgfx_recv_start_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStre RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; UINT error = CHANNEL_RC_OK; - if (Stream_GetRemainingLength(s) < 8) + if (Stream_GetRemainingLength(s) < RDPGFX_START_FRAME_PDU_SIZE) { WLog_ERR(TAG, "not enough data!"); return ERROR_INVALID_DATA; @@ -494,7 +494,7 @@ static UINT rdpgfx_recv_end_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; UINT error = CHANNEL_RC_OK; - if (Stream_GetRemainingLength(s) < 4) + if (Stream_GetRemainingLength(s) < RDPGFX_END_FRAME_PDU_SIZE) { WLog_ERR(TAG, "not enough data!"); return ERROR_INVALID_DATA; @@ -550,7 +550,7 @@ static UINT rdpgfx_recv_wire_to_surface_1_pdu(RDPGFX_CHANNEL_CALLBACK* callback, RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; UINT error; - if (Stream_GetRemainingLength(s) < 17) + if (Stream_GetRemainingLength(s) < RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE) { WLog_ERR(TAG, "not enough data!"); return ERROR_INVALID_DATA; @@ -615,7 +615,7 @@ static UINT rdpgfx_recv_wire_to_surface_2_pdu(RDPGFX_CHANNEL_CALLBACK* callback, RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; UINT error = CHANNEL_RC_OK; - if (Stream_GetRemainingLength(s) < 13) + if (Stream_GetRemainingLength(s) < RDPGFX_WIRE_TO_SURFACE_PDU_2_SIZE) { WLog_ERR(TAG, "not enough data!"); return ERROR_INVALID_DATA; diff --git a/channels/rdpgfx/server/rdpgfx_main.c b/channels/rdpgfx/server/rdpgfx_main.c index 98e8e29fe..209a666aa 100644 --- a/channels/rdpgfx/server/rdpgfx_main.c +++ b/channels/rdpgfx/server/rdpgfx_main.c @@ -203,8 +203,7 @@ static UINT rdpgfx_send_caps_confirm_pdu(RdpgfxServerContext* context, { RDPGFX_CAPSET* capsSet = capsConfirm->capsSet; wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_CAPSCONFIRM, - sizeof(RDPGFX_CAPSET) + sizeof(capsSet->flags)); + RDPGFX_CMDID_CAPSCONFIRM, RDPGFX_CAPSET_SIZE); if (!s) { @@ -213,7 +212,7 @@ static UINT rdpgfx_send_caps_confirm_pdu(RdpgfxServerContext* context, } Stream_Write_UINT32(s, capsSet->version); /* version (4 bytes) */ - Stream_Write_UINT32(s, sizeof(capsSet->flags)); /* capsDataLength (4 bytes) */ + Stream_Write_UINT32(s, 4); /* capsDataLength (4 bytes) */ Stream_Write_UINT32(s, capsSet->flags); /* capsData (4 bytes) */ return rdpgfx_server_single_packet_send(context, s); } @@ -275,9 +274,7 @@ static UINT rdpgfx_send_reset_graphics_pdu(RdpgfxServerContext* context, static UINT rdpgfx_send_evict_cache_entry_pdu(RdpgfxServerContext* context, RDPGFX_EVICT_CACHE_ENTRY_PDU* pdu) { - wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_EVICTCACHEENTRY, - sizeof(RDPGFX_EVICT_CACHE_ENTRY_PDU)); + wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_EVICTCACHEENTRY, 2); if (!s) { @@ -300,8 +297,7 @@ static UINT rdpgfx_send_cache_import_reply_pdu(RdpgfxServerContext* context, UINT16 index; wStream* s = rdpgfx_server_single_packet_new( RDPGFX_CMDID_CACHEIMPORTREPLY, - sizeof(RDPGFX_CACHE_IMPORT_REPLY_PDU) + - sizeof(UINT16) * pdu->importedEntriesCount); + 2 + 2 * pdu->importedEntriesCount); if (!s) { @@ -328,9 +324,7 @@ static UINT rdpgfx_send_cache_import_reply_pdu(RdpgfxServerContext* context, static UINT rdpgfx_send_create_surface_pdu(RdpgfxServerContext* context, RDPGFX_CREATE_SURFACE_PDU* pdu) { - wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_CREATESURFACE, - sizeof(RDPGFX_CREATE_SURFACE_PDU)); + wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_CREATESURFACE, 7); if (!s) { @@ -353,9 +347,7 @@ static UINT rdpgfx_send_create_surface_pdu(RdpgfxServerContext* context, UINT rdpgfx_send_delete_surface_pdu(RdpgfxServerContext* context, RDPGFX_DELETE_SURFACE_PDU* pdu) { - wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_DELETESURFACE, - sizeof(RDPGFX_DELETE_SURFACE_PDU)); + wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_DELETESURFACE, 2); if (!s) { @@ -390,7 +382,7 @@ static UINT rdpgfx_send_start_frame_pdu(RdpgfxServerContext* context, { wStream* s = rdpgfx_server_single_packet_new( RDPGFX_CMDID_STARTFRAME, - sizeof(RDPGFX_START_FRAME_PDU)); + RDPGFX_START_FRAME_PDU_SIZE); if (!s) { @@ -412,7 +404,7 @@ static UINT rdpgfx_send_end_frame_pdu(RdpgfxServerContext* context, { wStream* s = rdpgfx_server_single_packet_new( RDPGFX_CMDID_ENDFRAME, - sizeof(RDPGFX_END_FRAME_PDU)); + RDPGFX_END_FRAME_PDU_SIZE); if (!s) { @@ -433,6 +425,7 @@ static UINT rdpgfx_send_end_frame_pdu(RdpgfxServerContext* context, static INLINE UINT32 rdpgfx_estimate_h264_avc420( RDPGFX_AVC420_BITMAP_STREAM* havc420) { + /* H264 metadata + H264 stream. See rdpgfx_write_h264_avc420 */ return sizeof(UINT32) /* numRegionRects */ + (sizeof(RECTANGLE_16) + 2) /* regionRects + quantQualityVals */ * havc420->meta.numRegionRects @@ -451,16 +444,16 @@ static INLINE UINT32 rdpgfx_estimate_surface_command(RDPGFX_SURFACE_COMMAND* cmd RDPGFX_AVC444_BITMAP_STREAM* havc444 = NULL; UINT32 h264Size = 0; - /* Create new stream according to codec. */ + /* Estimate stream size according to codec. */ switch (cmd->codecId) { case RDPGFX_CODECID_CAPROGRESSIVE: case RDPGFX_CODECID_CAPROGRESSIVE_V2: - return sizeof(RDPGFX_WIRE_TO_SURFACE_PDU_2) + cmd->length; + return RDPGFX_WIRE_TO_SURFACE_PDU_2_SIZE + cmd->length; case 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; + return RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE + h264Size; case RDPGFX_CODECID_AVC444: havc444 = (RDPGFX_AVC444_BITMAP_STREAM*)cmd->extra; h264Size = sizeof(UINT32); /* cbAvc420EncodedBitstream1 */ @@ -475,9 +468,9 @@ static INLINE UINT32 rdpgfx_estimate_surface_command(RDPGFX_SURFACE_COMMAND* cmd h264Size += rdpgfx_estimate_h264_avc420(havc420); } - return sizeof(RDPGFX_WIRE_TO_SURFACE_PDU_1) + h264Size; + return RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE + h264Size; default: - return sizeof(RDPGFX_WIRE_TO_SURFACE_PDU_1) + cmd->length; + return RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE + cmd->length; } } @@ -708,12 +701,12 @@ static UINT rdpgfx_send_surface_frame_command(RdpgfxServerContext* context, if (startFrame) { - size += rdpgfx_pdu_length(sizeof(RDPGFX_START_FRAME_PDU)); + size += rdpgfx_pdu_length(RDPGFX_START_FRAME_PDU_SIZE); } if (endFrame) { - size += rdpgfx_pdu_length(sizeof(RDPGFX_END_FRAME_PDU)); + size += rdpgfx_pdu_length(RDPGFX_END_FRAME_PDU_SIZE); } s = Stream_New(NULL, size); @@ -795,8 +788,7 @@ static UINT rdpgfx_send_delete_encoding_context_pdu(RdpgfxServerContext* context RDPGFX_DELETE_ENCODING_CONTEXT_PDU* pdu) { wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_DELETEENCODINGCONTEXT, - sizeof(RDPGFX_DELETE_ENCODING_CONTEXT_PDU)); + RDPGFX_CMDID_DELETEENCODINGCONTEXT, 6); if (!s) { @@ -822,8 +814,7 @@ UINT rdpgfx_send_solid_fill_pdu(RdpgfxServerContext* context, RECTANGLE_16* fillRect; wStream* s = rdpgfx_server_single_packet_new( RDPGFX_CMDID_SOLIDFILL, - sizeof(RDPGFX_SOLID_FILL_PDU) + - sizeof(RECTANGLE_16) * pdu->fillRectCount); + 8 + sizeof(RECTANGLE_16) * pdu->fillRectCount); if (!s) { @@ -872,8 +863,7 @@ static UINT rdpgfx_send_surface_to_surface_pdu(RdpgfxServerContext* context, RDPGFX_POINT16* destPt; wStream* s = rdpgfx_server_single_packet_new( RDPGFX_CMDID_SURFACETOSURFACE, - sizeof(RDPGFX_SURFACE_TO_SURFACE_PDU) + - sizeof(RDPGFX_POINT16) * pdu->destPtsCount); + 14 + 4 * pdu->destPtsCount); if (!s) { @@ -920,8 +910,7 @@ static UINT rdpgfx_send_surface_to_cache_pdu(RdpgfxServerContext* context, { UINT error = CHANNEL_RC_OK; wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_SURFACETOCACHE, - sizeof(RDPGFX_SURFACE_TO_CACHE_PDU)); + RDPGFX_CMDID_SURFACETOCACHE, 20); if (!s) { @@ -959,8 +948,7 @@ static UINT rdpgfx_send_cache_to_surface_pdu(RdpgfxServerContext* context, RDPGFX_POINT16* destPt; wStream* s = rdpgfx_server_single_packet_new( RDPGFX_CMDID_CACHETOSURFACE, - sizeof(RDPGFX_CACHE_TO_SURFACE_PDU) + - sizeof(RDPGFX_POINT16) * pdu->destPtsCount); + 6 + 4 * pdu->destPtsCount); if (!s) { @@ -998,8 +986,7 @@ static UINT rdpgfx_send_map_surface_to_output_pdu(RdpgfxServerContext* context, RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU* pdu) { wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_MAPSURFACETOOUTPUT, - sizeof(RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU)); + RDPGFX_CMDID_MAPSURFACETOOUTPUT, 12); if (!s) { @@ -1023,8 +1010,7 @@ static UINT rdpgfx_send_map_surface_to_window_pdu(RdpgfxServerContext* context, RDPGFX_MAP_SURFACE_TO_WINDOW_PDU* pdu) { wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_MAPSURFACETOWINDOW, - sizeof(RDPGFX_MAP_SURFACE_TO_WINDOW_PDU)); + RDPGFX_CMDID_MAPSURFACETOWINDOW, 18); if (!s) { @@ -1050,7 +1036,7 @@ static UINT rdpgfx_recv_frame_acknowledge_pdu(RdpgfxServerContext* context, RDPGFX_FRAME_ACKNOWLEDGE_PDU pdu; UINT error = CHANNEL_RC_OK; - if (Stream_GetRemainingLength(s) < sizeof(RDPGFX_FRAME_ACKNOWLEDGE_PDU)) + if (Stream_GetRemainingLength(s) < 12) { WLog_ERR(TAG, "not enough data!"); return ERROR_INVALID_DATA; @@ -1086,7 +1072,7 @@ static UINT rdpgfx_recv_cache_import_offer_pdu(RdpgfxServerContext* context, RDPGFX_CACHE_ENTRY_METADATA* cacheEntries; UINT error = CHANNEL_RC_OK; - if (Stream_GetRemainingLength(s) < sizeof(UINT16)) + if (Stream_GetRemainingLength(s) < 2) { WLog_ERR(TAG, "not enough data!"); return ERROR_INVALID_DATA; @@ -1102,8 +1088,7 @@ static UINT rdpgfx_recv_cache_import_offer_pdu(RdpgfxServerContext* context, return ERROR_INVALID_DATA; } - if (Stream_GetRemainingLength(s) < - (pdu.cacheEntriesCount * sizeof(RDPGFX_CACHE_ENTRY_METADATA))) + if (Stream_GetRemainingLength(s) < (pdu.cacheEntriesCount * 12)) { WLog_ERR(TAG, "not enough data!"); return ERROR_INVALID_DATA; @@ -1155,7 +1140,7 @@ static UINT rdpgfx_recv_caps_advertise_pdu(RdpgfxServerContext* context, UINT error = CHANNEL_RC_OK; UINT32 capsDataLength; - if (Stream_GetRemainingLength(s) < sizeof(UINT16)) + if (Stream_GetRemainingLength(s) < 2) { WLog_ERR(TAG, "not enough data!"); return ERROR_INVALID_DATA; @@ -1170,8 +1155,7 @@ static UINT rdpgfx_recv_caps_advertise_pdu(RdpgfxServerContext* context, return ERROR_INVALID_DATA; } - if (Stream_GetRemainingLength(s) < - (pdu.capsSetCount * (sizeof(RDPGFX_CAPSET) + sizeof(UINT32)))) + if (Stream_GetRemainingLength(s) < (pdu.capsSetCount * 12)) { WLog_ERR(TAG, "not enough data!"); return ERROR_INVALID_DATA; @@ -1217,7 +1201,7 @@ 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)) + if (Stream_GetRemainingLength(s) < 12) { WLog_ERR(TAG, "not enough data!"); return ERROR_INVALID_DATA; diff --git a/include/freerdp/channels/rdpgfx.h b/include/freerdp/channels/rdpgfx.h index fdc643ba8..972a08208 100644 --- a/include/freerdp/channels/rdpgfx.h +++ b/include/freerdp/channels/rdpgfx.h @@ -143,6 +143,8 @@ typedef struct _RDPGFX_CAPSET_VERSION10 RDPGFX_CAPSET_VERSION10; #define RDPGFX_CODECID_ALPHA 0x000C #define RDPGFX_CODECID_AVC444 0x000E +#define RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE 17 + struct _RDPGFX_WIRE_TO_SURFACE_PDU_1 { UINT16 surfaceId; @@ -157,6 +159,8 @@ typedef struct _RDPGFX_WIRE_TO_SURFACE_PDU_1 RDPGFX_WIRE_TO_SURFACE_PDU_1; #define RDPGFX_CODECID_CAPROGRESSIVE 0x0009 #define RDPGFX_CODECID_CAPROGRESSIVE_V2 0x000D +#define RDPGFX_WIRE_TO_SURFACE_PDU_2_SIZE 13 + struct _RDPGFX_WIRE_TO_SURFACE_PDU_2 { UINT16 surfaceId; @@ -251,6 +255,8 @@ struct _RDPGFX_DELETE_SURFACE_PDU }; typedef struct _RDPGFX_DELETE_SURFACE_PDU RDPGFX_DELETE_SURFACE_PDU; +#define RDPGFX_START_FRAME_PDU_SIZE 8 + struct _RDPGFX_START_FRAME_PDU { UINT32 timestamp; @@ -258,6 +264,8 @@ struct _RDPGFX_START_FRAME_PDU }; typedef struct _RDPGFX_START_FRAME_PDU RDPGFX_START_FRAME_PDU; +#define RDPGFX_END_FRAME_PDU_SIZE 4 + struct _RDPGFX_END_FRAME_PDU { UINT32 frameId; From 5d4e9a2c87bcf121736e5962caa79a919f4bf93c Mon Sep 17 00:00:00 2001 From: "zihao.jiang" Date: Sat, 20 Aug 2016 01:36:37 +0800 Subject: [PATCH 7/8] rdpgfx/server: More minor fix --- channels/rdpgfx/client/rdpgfx_codec.c | 2 +- channels/rdpgfx/server/rdpgfx_main.c | 4 ++-- server/shadow/shadow_rdpgfx.c | 13 ++++++++++++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/channels/rdpgfx/client/rdpgfx_codec.c b/channels/rdpgfx/client/rdpgfx_codec.c index bf28ddd4d..323cda5a5 100644 --- a/channels/rdpgfx/client/rdpgfx_codec.c +++ b/channels/rdpgfx/client/rdpgfx_codec.c @@ -57,7 +57,7 @@ static UINT rdpgfx_read_h264_metablock(RDPGFX_PLUGIN* gfx, wStream* s, Stream_Read_UINT32(s, meta->numRegionRects); /* numRegionRects (4 bytes) */ - if (Stream_GetRemainingLength(s) < (meta->numRegionRects * sizeof(RECTANGLE_16))) + if (Stream_GetRemainingLength(s) < (meta->numRegionRects * 8)) { WLog_ERR(TAG, "not enough data!"); goto error_out; diff --git a/channels/rdpgfx/server/rdpgfx_main.c b/channels/rdpgfx/server/rdpgfx_main.c index 209a666aa..906374b27 100644 --- a/channels/rdpgfx/server/rdpgfx_main.c +++ b/channels/rdpgfx/server/rdpgfx_main.c @@ -427,7 +427,7 @@ static INLINE UINT32 rdpgfx_estimate_h264_avc420( { /* H264 metadata + H264 stream. See rdpgfx_write_h264_avc420 */ return sizeof(UINT32) /* numRegionRects */ - + (sizeof(RECTANGLE_16) + 2) /* regionRects + quantQualityVals */ + + 10 /* regionRects + quantQualityVals */ * havc420->meta.numRegionRects + havc420->length; } @@ -814,7 +814,7 @@ UINT rdpgfx_send_solid_fill_pdu(RdpgfxServerContext* context, RECTANGLE_16* fillRect; wStream* s = rdpgfx_server_single_packet_new( RDPGFX_CMDID_SOLIDFILL, - 8 + sizeof(RECTANGLE_16) * pdu->fillRectCount); + 8 + 8 * pdu->fillRectCount); if (!s) { diff --git a/server/shadow/shadow_rdpgfx.c b/server/shadow/shadow_rdpgfx.c index 51459eca4..a8ad1153d 100644 --- a/server/shadow/shadow_rdpgfx.c +++ b/server/shadow/shadow_rdpgfx.c @@ -42,7 +42,18 @@ static UINT rdpgfx_caps_advertise(RdpgfxServerContext* context, RDPGFX_CAPS_ADVE for (index = 0; index < capsAdvertise->capsSetCount; index++) { pdu.capsSet = &(capsAdvertise->capsSets[index]); - if (pdu.capsSet->version == RDPGFX_CAPVERSION_81) + if (pdu.capsSet->version == RDPGFX_CAPVERSION_10) + { + if (settings) + { + flags = pdu.capsSet->flags; + settings->GfxSmallCache = (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE); + settings->GfxH264 = !(flags & RDPGFX_CAPS_FLAG_AVC_DISABLED); + } + + return context->CapsConfirm(context, &pdu); + } + else if (pdu.capsSet->version == RDPGFX_CAPVERSION_81) { if (settings) { From 92ca9851d2b553ce4d0a09e701514b52bb9ad506 Mon Sep 17 00:00:00 2001 From: "zihao.jiang" Date: Sun, 21 Aug 2016 01:02:13 +0800 Subject: [PATCH 8/8] rdpgfx/server: Fix for windows10 clients 1. Fix order of gfx reset and new-surface. Windows10 client will show black screen with this issue(FreeRDP itself is dramatically immune to this issue) 2. Handle RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU for FPS control --- server/shadow/shadow_client.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/server/shadow/shadow_client.c b/server/shadow/shadow_client.c index ba0a80365..e978d5bbd 100644 --- a/server/shadow/shadow_client.c +++ b/server/shadow/shadow_client.c @@ -606,6 +606,12 @@ static UINT shadow_client_rdpgfx_frame_acknowledge(RdpgfxServerContext* context, frameAcknowledge->frameId); return CHANNEL_RC_OK; } +static UINT shadow_client_rdpgfx_qoe_frame_acknowledge(RdpgfxServerContext* context, RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU* qoeFrameAcknowledge) +{ + shadow_client_common_frame_acknowledge((rdpShadowClient *)context->custom, + qoeFrameAcknowledge->frameId); + return CHANNEL_RC_OK; +} /** * Function description @@ -1172,10 +1178,10 @@ static BOOL shadow_client_send_surface_update(rdpShadowClient* client, SHADOW_GF if (!pStatus->gfxSurfaceCreated) { /* Only init surface when we have h264 supported */ - if (!(ret = shadow_client_rdpgfx_new_surface(client))) + if (!(ret = shadow_client_rdpgfx_reset_graphic(client))) goto out; - if (!(ret = shadow_client_rdpgfx_reset_graphic(client))) + if (!(ret = shadow_client_rdpgfx_new_surface(client))) goto out; pStatus->gfxSurfaceCreated = TRUE; @@ -1534,6 +1540,7 @@ static void* shadow_client_thread(rdpShadowClient* client) } client->rdpgfx->FrameAcknowledge = shadow_client_rdpgfx_frame_acknowledge; + client->rdpgfx->QoeFrameAcknowledge = shadow_client_rdpgfx_qoe_frame_acknowledge; gfxstatus.gfxOpened = TRUE; WLog_INFO(TAG, "Gfx Pipeline Opened");