/**
* 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;
-
- s = Stream_New(NULL, header.pduLength);
-
- if(!s)
- {
- WLog_ERR(TAG, "Stream_New failed!");
- return NULL;
- }
+ header.pduLength = pduLength;
- /* 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 rdpgfx_write_header(s, &header);
+}
- return s;
+/**
+ * Function description
+ * 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 packet. The packet would be compressed
- * according to [MS-RDPEGFX].
+ * 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
*/
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!");
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);
/**
* 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
*
* @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(
+ 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;
}
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);
}
/**
{
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;
}
}
/* 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);
}
/**
*/
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);
}
/**
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;
}
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);
}
/**
*/
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;
}
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);
}
/**
*/
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) */
}
/**
*/
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);
}
/**
*/
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 UINT rdpgfx_write_h264_metablock(RdpgfxServerContext* context, wStream* s,
- RDPGFX_H264_METABLOCK* meta)
+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;
+}
+
+/**
+ * Function description
+ *
+ * @return 0 on success, otherwise a Win32 error code
+ */
+static UINT rdpgfx_write_h264_metablock(wStream* s, RDPGFX_H264_METABLOCK* meta)
{
UINT32 index;
RECTANGLE_16* regionRect;
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) */
}
*
* @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;
/**
* 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) */
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) */
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)
{
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
Stream_SetPosition(s, bitmapDataStart - sizeof(UINT32));
Stream_Write_UINT32(s, bitmapDataLength); /* bitmapDataLength (4 bytes) */
Stream_Seek(s, bitmapDataLength);
+ }
+
+ 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;
+ }
- return rdpgfx_server_packet_send(context, s);
+ 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;
}
/**
*/
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);
}
/**
*/
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;
}
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) */
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;
}
/**
*/
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;
}
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) */
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;
}
/**
*/
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;
}
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;
}
/**
*/
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;
}
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;
}
/**
*/
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;
}
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);
}
/**
*/
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;
}
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);
}
/**
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) */
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)
{
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) */
}
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) */
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);
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)
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;
#include <freerdp/log.h>
-#include "libfreerdp/core/server.h"
#include "shadow.h"
#define TAG CLIENT_TAG("shadow")
};
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;
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;
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)
}
}
-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;
/**
* 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;
if (server->shareSubRect)
{
- rectangles_intersection(&viewport, &(server->subRect), &viewport);
+ rectangles_intersection(&viewport, &(server->subRect), &viewport);
}
width = viewport.right - viewport.left;
{
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)
}
/* 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)
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);
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;
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);
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;
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;
settings->DesktopWidth, settings->DesktopHeight, nSrcStep, &numMessages,
settings->MultifragMaxRequestSize)))
{
- return 0;
+ WLog_ERR(TAG, "rfx_encode_messages failed");
+ return FALSE;
}
cmd.codecID = settings->RemoteFxCodecId;
{
rfx_message_free(encoder->rfx, &messages[i++]);
}
+ WLog_ERR(TAG, "rfx_write_message failed");
+ ret = FALSE;
break;
}
rfx_message_free(encoder->rfx, &messages[i]);
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);
}
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);
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;
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;
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)
if (!fragBitmapData)
{
- free(bitmapData);
- return -1;
+ WLog_ERR(TAG, "Failed to allocate memory for fragBitmapData");
+ ret = FALSE;
+ goto out;
}
bitmapUpdate.rectangles = fragBitmapData;
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;
}
}
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;
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);
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;
/**
* 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;
/* 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));
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));
+ return TRUE;
}
-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;
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)
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);
}
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))
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 &&
{
if (!client->rdpgfx->Open(client->rdpgfx))
{
- WLog_ERR(TAG, "Failed to open GraphicsPipeline");
+ WLog_WARN(TAG, "Failed to open GraphicsPipeline");
settings->SupportGraphicsPipeline = FALSE;
}
{
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);
}
out:
peer->Disconnect(peer);
-
+
freerdp_peer_context_free(peer);
freerdp_peer_free(peer);
ExitThread(0);