Blame channels/rdpgfx/server/rdpgfx_main.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * Graphics Pipeline Extension
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2016 Jiang Zihao <zihao.jiang@yahoo.com>
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *	 http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <assert.h>
Packit 1fb8d4
#include <stdio.h>
Packit 1fb8d4
#include <stdlib.h>
Packit 1fb8d4
#include <string.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
#include <winpr/synch.h>
Packit 1fb8d4
#include <winpr/thread.h>
Packit 1fb8d4
#include <winpr/stream.h>
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/channels/wtsvc.h>
Packit 1fb8d4
#include <freerdp/channels/log.h>
Packit 1fb8d4
Packit 1fb8d4
#include "rdpgfx_common.h"
Packit 1fb8d4
#include "rdpgfx_main.h"
Packit 1fb8d4
Packit 1fb8d4
#define TAG CHANNELS_TAG("rdpgfx.server")
Packit 1fb8d4
#define RDPGFX_RESET_GRAPHICS_PDU_SIZE 340
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 * Calculate packet size from data length.
Packit 1fb8d4
 * It would be data length + header.
Packit 1fb8d4
 *
Packit 1fb8d4
 * @param dataLen estimated data length without header
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return new stream
Packit 1fb8d4
 */
Packit 1fb8d4
static INLINE UINT32 rdpgfx_pdu_length(UINT32 dataLen)
Packit 1fb8d4
{
Packit 1fb8d4
	return RDPGFX_HEADER_SIZE + dataLen;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static INLINE UINT rdpgfx_server_packet_init_header(wStream* s, UINT16 cmdId, UINT32 pduLength)
Packit 1fb8d4
{
Packit 1fb8d4
	RDPGFX_HEADER header;
Packit 1fb8d4
	header.flags = 0;
Packit 1fb8d4
	header.cmdId = cmdId;
Packit 1fb8d4
	header.pduLength = pduLength;
Packit 1fb8d4
	/* Write header. Note that actual length might be changed
Packit 1fb8d4
	 * after the entire packet has been constructed. */
Packit 1fb8d4
	return rdpgfx_write_header(s, &header);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 * Complete the rdpgfx packet header.
Packit 1fb8d4
 *
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param start saved start pos of the packet in the stream
Packit 1fb8d4
 */
Packit Service 5a9772
static INLINE void rdpgfx_server_packet_complete_header(wStream* s, size_t start)
Packit 1fb8d4
{
Packit 1fb8d4
	size_t current = Stream_GetPosition(s);
Packit 1fb8d4
	/* Fill actual length */
Packit 1fb8d4
	Stream_SetPosition(s, start + RDPGFX_HEADER_SIZE - sizeof(UINT32));
Packit 1fb8d4
	Stream_Write_UINT32(s, current - start); /* pduLength (4 bytes) */
Packit 1fb8d4
	Stream_SetPosition(s, current);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 * Send the stream for rdpgfx server packet.
Packit 1fb8d4
 * The packet would be compressed according to [MS-RDPEGFX].
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT rdpgfx_server_packet_send(RdpgfxServerContext* context, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT error;
Packit 1fb8d4
	UINT32 flags = 0;
Packit 1fb8d4
	ULONG written;
Packit 1fb8d4
	BYTE* pSrcData = Stream_Buffer(s);
Packit 1fb8d4
	UINT32 SrcSize = Stream_GetPosition(s);
Packit 1fb8d4
	wStream* fs;
Packit 1fb8d4
	/* Allocate new stream with enough capacity. Additional overhead is
Packit 1fb8d4
	 * descriptor (1 bytes) + segmentCount (2 bytes) + uncompressedSize (4 bytes)
Packit 1fb8d4
	 * + segmentCount * size (4 bytes) */
Packit Service 5a9772
	fs = Stream_New(NULL, SrcSize + 7 + (SrcSize / ZGFX_SEGMENTED_MAXSIZE + 1) * 4);
Packit 1fb8d4
Packit 1fb8d4
	if (!fs)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Stream_New failed!");
Packit 1fb8d4
		error = CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
		goto out;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	if (zgfx_compress_to_stream(context->priv->zgfx, fs, pSrcData, SrcSize, &flags) < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "zgfx_compress_to_stream failed!");
Packit 1fb8d4
		error = ERROR_INTERNAL_ERROR;
Packit 1fb8d4
		goto out;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	if (!WTSVirtualChannelWrite(context->priv->rdpgfx_channel, (PCHAR)Stream_Buffer(fs),
Packit 1fb8d4
	                            Stream_GetPosition(fs), &written))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
Packit 1fb8d4
		error = ERROR_INTERNAL_ERROR;
Packit 1fb8d4
		goto out;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (written < Stream_GetPosition(fs))
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_WARN(TAG, "Unexpected bytes written: %" PRIu32 "/%" PRIuz "", written,
Packit Service 5a9772
		          Stream_GetPosition(fs));
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	error = CHANNEL_RC_OK;
Packit 1fb8d4
out:
Packit 1fb8d4
	Stream_Free(fs, TRUE);
Packit 1fb8d4
	Stream_Free(s, TRUE);
Packit 1fb8d4
	return error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 * Create new stream for single rdpgfx packet. The new stream length
Packit 1fb8d4
 * would be required data length + header. The header will be written
Packit 1fb8d4
 * to the stream before return, but the pduLength field might be
Packit 1fb8d4
 * changed in rdpgfx_server_single_packet_send.
Packit 1fb8d4
 *
Packit 1fb8d4
 * @param cmdId
Packit 1fb8d4
 * @param dataLen estimated data length without header
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return new stream
Packit 1fb8d4
 */
Packit 1fb8d4
static wStream* rdpgfx_server_single_packet_new(UINT16 cmdId, UINT32 dataLen)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT error;
Packit 1fb8d4
	wStream* s;
Packit 1fb8d4
	UINT32 pduLength = rdpgfx_pdu_length(dataLen);
Packit 1fb8d4
	s = Stream_New(NULL, pduLength);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Stream_New failed!");
Packit 1fb8d4
		goto error;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if ((error = rdpgfx_server_packet_init_header(s, cmdId, pduLength)))
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_ERR(TAG, "Failed to init header with error %" PRIu32 "!", error);
Packit 1fb8d4
		goto error;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return s;
Packit 1fb8d4
error:
Packit 1fb8d4
	Stream_Free(s, TRUE);
Packit 1fb8d4
	return NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 * Send the stream for single rdpgfx packet.
Packit 1fb8d4
 * The header will be filled with actual length.
Packit 1fb8d4
 * The packet would be compressed according to [MS-RDPEGFX].
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit Service 5a9772
static INLINE UINT rdpgfx_server_single_packet_send(RdpgfxServerContext* context, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	/* Fill actual length */
Packit 1fb8d4
	rdpgfx_server_packet_complete_header(s, 0);
Packit 1fb8d4
	return rdpgfx_server_packet_send(context, s);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT rdpgfx_send_caps_confirm_pdu(RdpgfxServerContext* context,
Packit Service 5a9772
                                         const RDPGFX_CAPS_CONFIRM_PDU* capsConfirm)
Packit 1fb8d4
{
Packit 1fb8d4
	RDPGFX_CAPSET* capsSet = capsConfirm->capsSet;
Packit Service 5a9772
	wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_CAPSCONFIRM,
Packit Service 5a9772
	                                             RDPGFX_CAPSET_BASE_SIZE + capsSet->length);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
Packit 1fb8d4
		return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Write_UINT32(s, capsSet->version); /* version (4 bytes) */
Packit Service 5a9772
	Stream_Write_UINT32(s, capsSet->length);  /* capsDataLength (4 bytes) */
Packit Service 5a9772
Packit Service 5a9772
	if (capsSet->length >= 4)
Packit Service 5a9772
	{
Packit Service 5a9772
		Stream_Write_UINT32(s, capsSet->flags); /* capsData (4 bytes) */
Packit Service 5a9772
		Stream_Zero(s, capsSet->length - 4);
Packit Service 5a9772
	}
Packit Service 5a9772
	else
Packit Service 5a9772
		Stream_Zero(s, capsSet->length);
Packit Service 5a9772
Packit 1fb8d4
	return rdpgfx_server_single_packet_send(context, s);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT rdpgfx_send_reset_graphics_pdu(RdpgfxServerContext* context,
Packit Service 5a9772
                                           const RDPGFX_RESET_GRAPHICS_PDU* pdu)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 index;
Packit 1fb8d4
	MONITOR_DEF* monitor;
Packit 1fb8d4
	wStream* s;
Packit 1fb8d4
Packit 1fb8d4
	/* Check monitorCount. This ensures total size within 340 bytes) */
Packit 1fb8d4
	if (pdu->monitorCount >= 16)
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_ERR(TAG, "Monitor count MUST be less than or equal to 16: %" PRIu32 "",
Packit 1fb8d4
		         pdu->monitorCount);
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_RESETGRAPHICS,
Packit Service 5a9772
	                                    RDPGFX_RESET_GRAPHICS_PDU_SIZE - RDPGFX_HEADER_SIZE);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
Packit 1fb8d4
		return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	Stream_Write_UINT32(s, pdu->width);        /* width (4 bytes) */
Packit Service 5a9772
	Stream_Write_UINT32(s, pdu->height);       /* height (4 bytes) */
Packit 1fb8d4
	Stream_Write_UINT32(s, pdu->monitorCount); /* monitorCount (4 bytes) */
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < pdu->monitorCount; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		monitor = &(pdu->monitorDefArray[index]);
Packit Service 5a9772
		Stream_Write_UINT32(s, monitor->left);   /* left (4 bytes) */
Packit Service 5a9772
		Stream_Write_UINT32(s, monitor->top);    /* top (4 bytes) */
Packit Service 5a9772
		Stream_Write_UINT32(s, monitor->right);  /* right (4 bytes) */
Packit 1fb8d4
		Stream_Write_UINT32(s, monitor->bottom); /* bottom (4 bytes) */
Packit Service 5a9772
		Stream_Write_UINT32(s, monitor->flags);  /* flags (4 bytes) */
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* pad (total size must be 340 bytes) */
Packit 1fb8d4
	Stream_SetPosition(s, RDPGFX_RESET_GRAPHICS_PDU_SIZE);
Packit 1fb8d4
	return rdpgfx_server_single_packet_send(context, s);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT rdpgfx_send_evict_cache_entry_pdu(RdpgfxServerContext* context,
Packit Service 5a9772
                                              const RDPGFX_EVICT_CACHE_ENTRY_PDU* pdu)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_EVICTCACHEENTRY, 2);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
Packit 1fb8d4
		return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Write_UINT16(s, pdu->cacheSlot); /* cacheSlot (2 bytes) */
Packit 1fb8d4
	return rdpgfx_server_single_packet_send(context, s);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT rdpgfx_send_cache_import_reply_pdu(RdpgfxServerContext* context,
Packit Service 5a9772
                                               const RDPGFX_CACHE_IMPORT_REPLY_PDU* pdu)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT16 index;
Packit Service 5a9772
	wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_CACHEIMPORTREPLY,
Packit Service 5a9772
	                                             2 + 2 * pdu->importedEntriesCount);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
Packit 1fb8d4
		return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* importedEntriesCount (2 bytes) */
Packit 1fb8d4
	Stream_Write_UINT16(s, pdu->importedEntriesCount);
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < pdu->importedEntriesCount; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		Stream_Write_UINT16(s, pdu->cacheSlots[index]); /* cacheSlot (2 bytes) */
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return rdpgfx_server_single_packet_send(context, s);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT rdpgfx_send_create_surface_pdu(RdpgfxServerContext* context,
Packit Service 5a9772
                                           const RDPGFX_CREATE_SURFACE_PDU* pdu)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_CREATESURFACE, 7);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
Packit 1fb8d4
		return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	Stream_Write_UINT16(s, pdu->surfaceId);  /* surfaceId (2 bytes) */
Packit Service 5a9772
	Stream_Write_UINT16(s, pdu->width);      /* width (2 bytes) */
Packit Service 5a9772
	Stream_Write_UINT16(s, pdu->height);     /* height (2 bytes) */
Packit 1fb8d4
	Stream_Write_UINT8(s, pdu->pixelFormat); /* RDPGFX_PIXELFORMAT (1 byte) */
Packit 1fb8d4
	return rdpgfx_server_single_packet_send(context, s);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT rdpgfx_send_delete_surface_pdu(RdpgfxServerContext* context,
Packit Service 5a9772
                                           const RDPGFX_DELETE_SURFACE_PDU* pdu)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_DELETESURFACE, 2);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
Packit 1fb8d4
		return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
Packit 1fb8d4
	return rdpgfx_server_single_packet_send(context, s);
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static INLINE void rdpgfx_write_start_frame_pdu(wStream* s, const RDPGFX_START_FRAME_PDU* pdu)
Packit 1fb8d4
{
Packit 1fb8d4
	Stream_Write_UINT32(s, pdu->timestamp); /* timestamp (4 bytes) */
Packit Service 5a9772
	Stream_Write_UINT32(s, pdu->frameId);   /* frameId (4 bytes) */
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static INLINE void rdpgfx_write_end_frame_pdu(wStream* s, const RDPGFX_END_FRAME_PDU* pdu)
Packit 1fb8d4
{
Packit 1fb8d4
	Stream_Write_UINT32(s, pdu->frameId); /* frameId (4 bytes) */
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT rdpgfx_send_start_frame_pdu(RdpgfxServerContext* context,
Packit Service 5a9772
                                        const RDPGFX_START_FRAME_PDU* pdu)
Packit 1fb8d4
{
Packit Service 5a9772
	wStream* s =
Packit Service 5a9772
	    rdpgfx_server_single_packet_new(RDPGFX_CMDID_STARTFRAME, RDPGFX_START_FRAME_PDU_SIZE);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
Packit 1fb8d4
		return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	rdpgfx_write_start_frame_pdu(s, pdu);
Packit 1fb8d4
	return rdpgfx_server_single_packet_send(context, s);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit Service 5a9772
static UINT rdpgfx_send_end_frame_pdu(RdpgfxServerContext* context, const RDPGFX_END_FRAME_PDU* pdu)
Packit 1fb8d4
{
Packit Service 5a9772
	wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_ENDFRAME, RDPGFX_END_FRAME_PDU_SIZE);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
Packit 1fb8d4
		return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	rdpgfx_write_end_frame_pdu(s, pdu);
Packit 1fb8d4
	return rdpgfx_server_single_packet_send(context, s);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 * Estimate RFX_AVC420_BITMAP_STREAM structure size in stream
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return estimated size
Packit 1fb8d4
 */
Packit Service 5a9772
static INLINE UINT32 rdpgfx_estimate_h264_avc420(const RDPGFX_AVC420_BITMAP_STREAM* havc420)
Packit 1fb8d4
{
Packit 1fb8d4
	/* H264 metadata + H264 stream. See rdpgfx_write_h264_avc420 */
Packit 1fb8d4
	return sizeof(UINT32) /* numRegionRects */
Packit Service 5a9772
	       + 10           /* regionRects + quantQualityVals */
Packit Service 5a9772
	             * havc420->meta.numRegionRects +
Packit Service 5a9772
	       havc420->length;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 * Estimate surface command packet size in stream without header
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return estimated size
Packit 1fb8d4
 */
Packit Service 5a9772
static INLINE UINT32 rdpgfx_estimate_surface_command(const RDPGFX_SURFACE_COMMAND* cmd)
Packit 1fb8d4
{
Packit 1fb8d4
	RDPGFX_AVC420_BITMAP_STREAM* havc420 = NULL;
Packit 1fb8d4
	RDPGFX_AVC444_BITMAP_STREAM* havc444 = NULL;
Packit 1fb8d4
	UINT32 h264Size = 0;
Packit 1fb8d4
Packit 1fb8d4
	/* Estimate stream size according to codec. */
Packit 1fb8d4
	switch (cmd->codecId)
Packit 1fb8d4
	{
Packit 1fb8d4
		case RDPGFX_CODECID_CAPROGRESSIVE:
Packit 1fb8d4
		case RDPGFX_CODECID_CAPROGRESSIVE_V2:
Packit 1fb8d4
			return RDPGFX_WIRE_TO_SURFACE_PDU_2_SIZE + cmd->length;
Packit 1fb8d4
Packit 1fb8d4
		case RDPGFX_CODECID_AVC420:
Packit 1fb8d4
			havc420 = (RDPGFX_AVC420_BITMAP_STREAM*)cmd->extra;
Packit 1fb8d4
			h264Size = rdpgfx_estimate_h264_avc420(havc420);
Packit 1fb8d4
			return RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE + h264Size;
Packit 1fb8d4
Packit 1fb8d4
		case RDPGFX_CODECID_AVC444:
Packit 1fb8d4
			havc444 = (RDPGFX_AVC444_BITMAP_STREAM*)cmd->extra;
Packit 1fb8d4
			h264Size = sizeof(UINT32); /* cbAvc420EncodedBitstream1 */
Packit 1fb8d4
			/* avc420EncodedBitstream1 */
Packit 1fb8d4
			havc420 = &(havc444->bitstream[0]);
Packit 1fb8d4
			h264Size += rdpgfx_estimate_h264_avc420(havc420);
Packit 1fb8d4
Packit 1fb8d4
			/* avc420EncodedBitstream2 */
Packit 1fb8d4
			if (havc444->LC == 0)
Packit 1fb8d4
			{
Packit 1fb8d4
				havc420 = &(havc444->bitstream[1]);
Packit 1fb8d4
				h264Size += rdpgfx_estimate_h264_avc420(havc420);
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			return RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE + h264Size;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			return RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE + cmd->length;
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 * Resolve RDPGFX_CMDID_WIRETOSURFACE_1 or RDPGFX_CMDID_WIRETOSURFACE_2
Packit 1fb8d4
 * according to codecId
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit Service 5a9772
static INLINE UINT16 rdpgfx_surface_command_cmdid(const RDPGFX_SURFACE_COMMAND* cmd)
Packit 1fb8d4
{
Packit 1fb8d4
	if (cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE ||
Packit 1fb8d4
	    cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE_V2)
Packit 1fb8d4
	{
Packit 1fb8d4
		return RDPGFX_CMDID_WIRETOSURFACE_2;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return RDPGFX_CMDID_WIRETOSURFACE_1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit Service 5a9772
static UINT rdpgfx_write_h264_metablock(wStream* s, const RDPGFX_H264_METABLOCK* meta)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 index;
Packit 1fb8d4
	RECTANGLE_16* regionRect;
Packit 1fb8d4
	RDPGFX_H264_QUANT_QUALITY* quantQualityVal;
Packit 1fb8d4
	UINT error = CHANNEL_RC_OK;
Packit 1fb8d4
Packit 1fb8d4
	if (!Stream_EnsureRemainingCapacity(s, 4 + meta->numRegionRects * 10))
Packit 1fb8d4
		return ERROR_OUTOFMEMORY;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Write_UINT32(s, meta->numRegionRects); /* numRegionRects (4 bytes) */
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < meta->numRegionRects; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		regionRect = &(meta->regionRects[index]);
Packit 1fb8d4
Packit 1fb8d4
		if ((error = rdpgfx_write_rect16(s, regionRect)))
Packit 1fb8d4
		{
Packit Service 5a9772
			WLog_ERR(TAG, "rdpgfx_write_rect16 failed with error %" PRIu32 "!", error);
Packit 1fb8d4
			return error;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < meta->numRegionRects; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		quantQualityVal = &(meta->quantQualityVals[index]);
Packit Service 5a9772
		Stream_Write_UINT8(s, quantQualityVal->qp | (quantQualityVal->r << 6) |
Packit Service 5a9772
		                          (quantQualityVal->p << 7)); /* qpVal (1 byte) */
Packit 1fb8d4
		/* qualityVal (1 byte) */
Packit 1fb8d4
		Stream_Write_UINT8(s, quantQualityVal->qualityVal);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 * Write RFX_AVC420_BITMAP_STREAM structure to stream
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit Service 5a9772
static INLINE UINT rdpgfx_write_h264_avc420(wStream* s, RDPGFX_AVC420_BITMAP_STREAM* havc420)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT error = CHANNEL_RC_OK;
Packit 1fb8d4
Packit 1fb8d4
	if ((error = rdpgfx_write_h264_metablock(s, &(havc420->meta))))
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_ERR(TAG, "rdpgfx_write_h264_metablock failed with error %" PRIu32 "!", error);
Packit 1fb8d4
		return error;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!Stream_EnsureRemainingCapacity(s, havc420->length))
Packit 1fb8d4
		return ERROR_OUTOFMEMORY;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Write(s, havc420->data, havc420->length);
Packit 1fb8d4
	return error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 * Write RDPGFX_CMDID_WIRETOSURFACE_1 or RDPGFX_CMDID_WIRETOSURFACE_2
Packit 1fb8d4
 * to the stream according to RDPGFX_SURFACE_COMMAND message
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit Service 5a9772
static UINT rdpgfx_write_surface_command(wStream* s, const RDPGFX_SURFACE_COMMAND* cmd)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT error = CHANNEL_RC_OK;
Packit 1fb8d4
	RDPGFX_AVC420_BITMAP_STREAM* havc420 = NULL;
Packit 1fb8d4
	RDPGFX_AVC444_BITMAP_STREAM* havc444 = NULL;
Packit 1fb8d4
	UINT32 bitmapDataStart = 0;
Packit 1fb8d4
	UINT32 bitmapDataLength = 0;
Packit 1fb8d4
	UINT8 pixelFormat = 0;
Packit 1fb8d4
Packit 1fb8d4
	switch (cmd->format)
Packit 1fb8d4
	{
Packit 1fb8d4
		case PIXEL_FORMAT_BGRX32:
Packit 1fb8d4
			pixelFormat = GFX_PIXEL_FORMAT_XRGB_8888;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case PIXEL_FORMAT_BGRA32:
Packit 1fb8d4
			pixelFormat = GFX_PIXEL_FORMAT_ARGB_8888;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			WLog_ERR(TAG, "Format %s not supported!", FreeRDPGetColorFormatName(cmd->format));
Packit 1fb8d4
			return ERROR_INVALID_DATA;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE ||
Packit 1fb8d4
	    cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE_V2)
Packit 1fb8d4
	{
Packit 1fb8d4
		/* Write RDPGFX_CMDID_WIRETOSURFACE_2 format for CAPROGRESSIVE */
Packit 1fb8d4
		Stream_Write_UINT16(s, cmd->surfaceId); /* surfaceId (2 bytes) */
Packit Service 5a9772
		Stream_Write_UINT16(s, cmd->codecId);   /* codecId (2 bytes) */
Packit 1fb8d4
		Stream_Write_UINT32(s, cmd->contextId); /* codecContextId (4 bytes) */
Packit Service 5a9772
		Stream_Write_UINT8(s, pixelFormat);     /* pixelFormat (1 byte) */
Packit Service 5a9772
		Stream_Write_UINT32(s, cmd->length);    /* bitmapDataLength (4 bytes) */
Packit 1fb8d4
		Stream_Write(s, cmd->data, cmd->length);
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		/* Write RDPGFX_CMDID_WIRETOSURFACE_1 format for others */
Packit 1fb8d4
		Stream_Write_UINT16(s, cmd->surfaceId); /* surfaceId (2 bytes) */
Packit Service 5a9772
		Stream_Write_UINT16(s, cmd->codecId);   /* codecId (2 bytes) */
Packit Service 5a9772
		Stream_Write_UINT8(s, pixelFormat);     /* pixelFormat (1 byte) */
Packit Service 5a9772
		Stream_Write_UINT16(s, cmd->left);      /* left (2 bytes) */
Packit Service 5a9772
		Stream_Write_UINT16(s, cmd->top);       /* top (2 bytes) */
Packit Service 5a9772
		Stream_Write_UINT16(s, cmd->right);     /* right (2 bytes) */
Packit Service 5a9772
		Stream_Write_UINT16(s, cmd->bottom);    /* bottom (2 bytes) */
Packit Service 5a9772
		Stream_Write_UINT32(s, cmd->length);    /* bitmapDataLength (4 bytes) */
Packit 1fb8d4
		bitmapDataStart = Stream_GetPosition(s);
Packit 1fb8d4
Packit 1fb8d4
		if (cmd->codecId == RDPGFX_CODECID_AVC420)
Packit 1fb8d4
		{
Packit 1fb8d4
			havc420 = (RDPGFX_AVC420_BITMAP_STREAM*)cmd->extra;
Packit 1fb8d4
			error = rdpgfx_write_h264_avc420(s, havc420);
Packit 1fb8d4
Packit 1fb8d4
			if (error != CHANNEL_RC_OK)
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "rdpgfx_write_h264_avc420 failed!");
Packit 1fb8d4
				return error;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit Service 5a9772
		else if ((cmd->codecId == RDPGFX_CODECID_AVC444) ||
Packit Service 5a9772
		         (cmd->codecId == RDPGFX_CODECID_AVC444v2))
Packit 1fb8d4
		{
Packit 1fb8d4
			havc444 = (RDPGFX_AVC444_BITMAP_STREAM*)cmd->extra;
Packit Service 5a9772
			havc420 = &(havc444->bitstream[0]); /* avc420EncodedBitstreamInfo (4 bytes) */
Packit 1fb8d4
			Stream_Write_UINT32(s, havc444->cbAvc420EncodedBitstream1 | (havc444->LC << 30UL));
Packit 1fb8d4
			/* avc420EncodedBitstream1 */
Packit 1fb8d4
			error = rdpgfx_write_h264_avc420(s, havc420);
Packit 1fb8d4
Packit 1fb8d4
			if (error != CHANNEL_RC_OK)
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "rdpgfx_write_h264_avc420 failed!");
Packit 1fb8d4
				return error;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			/* avc420EncodedBitstream2 */
Packit 1fb8d4
			if (havc444->LC == 0)
Packit 1fb8d4
			{
Packit 1fb8d4
				havc420 = &(havc444->bitstream[1]);
Packit 1fb8d4
				error = rdpgfx_write_h264_avc420(s, havc420);
Packit 1fb8d4
Packit 1fb8d4
				if (error != CHANNEL_RC_OK)
Packit 1fb8d4
				{
Packit 1fb8d4
					WLog_ERR(TAG, "rdpgfx_write_h264_avc420 failed!");
Packit 1fb8d4
					return error;
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			Stream_Write(s, cmd->data, cmd->length);
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		/* Fill actual bitmap data length */
Packit 1fb8d4
		bitmapDataLength = Stream_GetPosition(s) - bitmapDataStart;
Packit 1fb8d4
		Stream_SetPosition(s, bitmapDataStart - sizeof(UINT32));
Packit 1fb8d4
		Stream_Write_UINT32(s, bitmapDataLength); /* bitmapDataLength (4 bytes) */
Packit 1fb8d4
		Stream_Seek(s, bitmapDataLength);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 * Send RDPGFX_CMDID_WIRETOSURFACE_1 or RDPGFX_CMDID_WIRETOSURFACE_2
Packit 1fb8d4
 * message according to codecId
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT rdpgfx_send_surface_command(RdpgfxServerContext* context,
Packit Service 5a9772
                                        const RDPGFX_SURFACE_COMMAND* cmd)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT error = CHANNEL_RC_OK;
Packit 1fb8d4
	wStream* s;
Packit Service 5a9772
	s = rdpgfx_server_single_packet_new(rdpgfx_surface_command_cmdid(cmd),
Packit Service 5a9772
	                                    rdpgfx_estimate_surface_command(cmd));
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
Packit 1fb8d4
		return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	error = rdpgfx_write_surface_command(s, cmd);
Packit 1fb8d4
Packit 1fb8d4
	if (error != CHANNEL_RC_OK)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "rdpgfx_write_surface_command failed!");
Packit 1fb8d4
		goto error;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return rdpgfx_server_single_packet_send(context, s);
Packit 1fb8d4
error:
Packit 1fb8d4
	Stream_Free(s, TRUE);
Packit 1fb8d4
	return error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 * Send RDPGFX_CMDID_WIRETOSURFACE_1 or RDPGFX_CMDID_WIRETOSURFACE_2
Packit 1fb8d4
 * message according to codecId.
Packit 1fb8d4
 * Prepend/append start/end frame message in same packet if exists.
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT rdpgfx_send_surface_frame_command(RdpgfxServerContext* context,
Packit Service 5a9772
                                              const RDPGFX_SURFACE_COMMAND* cmd,
Packit Service 5a9772
                                              const RDPGFX_START_FRAME_PDU* startFrame,
Packit Service 5a9772
                                              const RDPGFX_END_FRAME_PDU* endFrame)
Packit 1fb8d4
Packit 1fb8d4
{
Packit 1fb8d4
	UINT error = CHANNEL_RC_OK;
Packit 1fb8d4
	wStream* s;
Packit 1fb8d4
	UINT32 position = 0;
Packit 1fb8d4
	UINT32 size = rdpgfx_pdu_length(rdpgfx_estimate_surface_command(cmd));
Packit 1fb8d4
Packit 1fb8d4
	if (startFrame)
Packit 1fb8d4
	{
Packit 1fb8d4
		size += rdpgfx_pdu_length(RDPGFX_START_FRAME_PDU_SIZE);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (endFrame)
Packit 1fb8d4
	{
Packit 1fb8d4
		size += rdpgfx_pdu_length(RDPGFX_END_FRAME_PDU_SIZE);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	s = Stream_New(NULL, size);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Stream_New failed!");
Packit 1fb8d4
		return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* Write start frame if exists */
Packit 1fb8d4
	if (startFrame)
Packit 1fb8d4
	{
Packit 1fb8d4
		position = Stream_GetPosition(s);
Packit Service 5a9772
		error = rdpgfx_server_packet_init_header(s, RDPGFX_CMDID_STARTFRAME, 0);
Packit 1fb8d4
Packit 1fb8d4
		if (error != CHANNEL_RC_OK)
Packit 1fb8d4
		{
Packit Service 5a9772
			WLog_ERR(TAG, "Failed to init header with error %" PRIu32 "!", error);
Packit 1fb8d4
			goto error;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		rdpgfx_write_start_frame_pdu(s, startFrame);
Packit 1fb8d4
		rdpgfx_server_packet_complete_header(s, position);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* Write RDPGFX_CMDID_WIRETOSURFACE_1 or RDPGFX_CMDID_WIRETOSURFACE_2 */
Packit 1fb8d4
	position = Stream_GetPosition(s);
Packit Service 5a9772
	error = rdpgfx_server_packet_init_header(s, rdpgfx_surface_command_cmdid(cmd),
Packit Service 5a9772
	                                         0); // Actual length will be filled later
Packit 1fb8d4
Packit 1fb8d4
	if (error != CHANNEL_RC_OK)
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_ERR(TAG, "Failed to init header with error %" PRIu32 "!", error);
Packit 1fb8d4
		goto error;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	error = rdpgfx_write_surface_command(s, cmd);
Packit 1fb8d4
Packit 1fb8d4
	if (error != CHANNEL_RC_OK)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "rdpgfx_write_surface_command failed!");
Packit 1fb8d4
		goto error;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	rdpgfx_server_packet_complete_header(s, position);
Packit 1fb8d4
Packit 1fb8d4
	/* Write end frame if exists */
Packit 1fb8d4
	if (endFrame)
Packit 1fb8d4
	{
Packit 1fb8d4
		position = Stream_GetPosition(s);
Packit Service 5a9772
		error = rdpgfx_server_packet_init_header(s, RDPGFX_CMDID_ENDFRAME, 0);
Packit 1fb8d4
Packit 1fb8d4
		if (error != CHANNEL_RC_OK)
Packit 1fb8d4
		{
Packit Service 5a9772
			WLog_ERR(TAG, "Failed to init header with error %" PRIu32 "!", error);
Packit 1fb8d4
			goto error;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		rdpgfx_write_end_frame_pdu(s, endFrame);
Packit 1fb8d4
		rdpgfx_server_packet_complete_header(s, position);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return rdpgfx_server_packet_send(context, s);
Packit 1fb8d4
error:
Packit 1fb8d4
	Stream_Free(s, TRUE);
Packit 1fb8d4
	return error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit Service 5a9772
static UINT rdpgfx_send_delete_encoding_context_pdu(RdpgfxServerContext* context,
Packit Service 5a9772
                                                    const RDPGFX_DELETE_ENCODING_CONTEXT_PDU* pdu)
Packit 1fb8d4
{
Packit Service 5a9772
	wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_DELETEENCODINGCONTEXT, 6);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
Packit 1fb8d4
		return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	Stream_Write_UINT16(s, pdu->surfaceId);      /* surfaceId (2 bytes) */
Packit 1fb8d4
	Stream_Write_UINT32(s, pdu->codecContextId); /* codecContextId (4 bytes) */
Packit 1fb8d4
	return rdpgfx_server_single_packet_send(context, s);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT rdpgfx_send_solid_fill_pdu(RdpgfxServerContext* context,
Packit Service 5a9772
                                       const RDPGFX_SOLID_FILL_PDU* pdu)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT error = CHANNEL_RC_OK;
Packit 1fb8d4
	UINT16 index;
Packit 1fb8d4
	RECTANGLE_16* fillRect;
Packit Service 5a9772
	wStream* s =
Packit Service 5a9772
	    rdpgfx_server_single_packet_new(RDPGFX_CMDID_SOLIDFILL, 8 + 8 * pdu->fillRectCount);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
Packit 1fb8d4
		return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
Packit 1fb8d4
Packit 1fb8d4
	/* fillPixel (4 bytes) */
Packit 1fb8d4
	if ((error = rdpgfx_write_color32(s, &(pdu->fillPixel))))
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_ERR(TAG, "rdpgfx_write_color32 failed with error %" PRIu32 "!", error);
Packit 1fb8d4
		goto error;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Write_UINT16(s, pdu->fillRectCount); /* fillRectCount (2 bytes) */
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < pdu->fillRectCount; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		fillRect = &(pdu->fillRects[index]);
Packit 1fb8d4
Packit 1fb8d4
		if ((error = rdpgfx_write_rect16(s, fillRect)))
Packit 1fb8d4
		{
Packit Service 5a9772
			WLog_ERR(TAG, "rdpgfx_write_rect16 failed with error %" PRIu32 "!", error);
Packit 1fb8d4
			goto error;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return rdpgfx_server_single_packet_send(context, s);
Packit 1fb8d4
error:
Packit 1fb8d4
	Stream_Free(s, TRUE);
Packit 1fb8d4
	return error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT rdpgfx_send_surface_to_surface_pdu(RdpgfxServerContext* context,
Packit Service 5a9772
                                               const RDPGFX_SURFACE_TO_SURFACE_PDU* pdu)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT error = CHANNEL_RC_OK;
Packit 1fb8d4
	UINT16 index;
Packit 1fb8d4
	RDPGFX_POINT16* destPt;
Packit Service 5a9772
	wStream* s =
Packit Service 5a9772
	    rdpgfx_server_single_packet_new(RDPGFX_CMDID_SURFACETOSURFACE, 14 + 4 * pdu->destPtsCount);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
Packit 1fb8d4
		return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	Stream_Write_UINT16(s, pdu->surfaceIdSrc);  /* surfaceIdSrc (2 bytes) */
Packit 1fb8d4
	Stream_Write_UINT16(s, pdu->surfaceIdDest); /* surfaceIdDest (2 bytes) */
Packit 1fb8d4
Packit 1fb8d4
	/* rectSrc (8 bytes ) */
Packit 1fb8d4
	if ((error = rdpgfx_write_rect16(s, &(pdu->rectSrc))))
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_ERR(TAG, "rdpgfx_write_rect16 failed with error %" PRIu32 "!", error);
Packit 1fb8d4
		goto error;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Write_UINT16(s, pdu->destPtsCount); /* destPtsCount (2 bytes) */
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < pdu->destPtsCount; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		destPt = &(pdu->destPts[index]);
Packit 1fb8d4
Packit 1fb8d4
		if ((error = rdpgfx_write_point16(s, destPt)))
Packit 1fb8d4
		{
Packit Service 5a9772
			WLog_ERR(TAG, "rdpgfx_write_point16 failed with error %" PRIu32 "!", error);
Packit 1fb8d4
			goto error;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return rdpgfx_server_single_packet_send(context, s);
Packit 1fb8d4
error:
Packit 1fb8d4
	Stream_Free(s, TRUE);
Packit 1fb8d4
	return error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT rdpgfx_send_surface_to_cache_pdu(RdpgfxServerContext* context,
Packit Service 5a9772
                                             const RDPGFX_SURFACE_TO_CACHE_PDU* pdu)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT error = CHANNEL_RC_OK;
Packit Service 5a9772
	wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_SURFACETOCACHE, 20);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
Packit 1fb8d4
		return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
Packit Service 5a9772
	Stream_Write_UINT64(s, pdu->cacheKey);  /* cacheKey (8 bytes) */
Packit 1fb8d4
	Stream_Write_UINT16(s, pdu->cacheSlot); /* cacheSlot (2 bytes) */
Packit 1fb8d4
Packit 1fb8d4
	/* rectSrc (8 bytes ) */
Packit 1fb8d4
	if ((error = rdpgfx_write_rect16(s, &(pdu->rectSrc))))
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_ERR(TAG, "rdpgfx_write_rect16 failed with error %" PRIu32 "!", error);
Packit 1fb8d4
		goto error;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return rdpgfx_server_single_packet_send(context, s);
Packit 1fb8d4
error:
Packit 1fb8d4
	Stream_Free(s, TRUE);
Packit 1fb8d4
	return error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT rdpgfx_send_cache_to_surface_pdu(RdpgfxServerContext* context,
Packit Service 5a9772
                                             const RDPGFX_CACHE_TO_SURFACE_PDU* pdu)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT error = CHANNEL_RC_OK;
Packit 1fb8d4
	UINT16 index;
Packit 1fb8d4
	RDPGFX_POINT16* destPt;
Packit Service 5a9772
	wStream* s =
Packit Service 5a9772
	    rdpgfx_server_single_packet_new(RDPGFX_CMDID_CACHETOSURFACE, 6 + 4 * pdu->destPtsCount);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
Packit 1fb8d4
		return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	Stream_Write_UINT16(s, pdu->cacheSlot);    /* cacheSlot (2 bytes) */
Packit Service 5a9772
	Stream_Write_UINT16(s, pdu->surfaceId);    /* surfaceId (2 bytes) */
Packit 1fb8d4
	Stream_Write_UINT16(s, pdu->destPtsCount); /* destPtsCount (2 bytes) */
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < pdu->destPtsCount; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		destPt = &(pdu->destPts[index]);
Packit 1fb8d4
Packit 1fb8d4
		if ((error = rdpgfx_write_point16(s, destPt)))
Packit 1fb8d4
		{
Packit Service 5a9772
			WLog_ERR(TAG, "rdpgfx_write_point16 failed with error %" PRIu32 "", error);
Packit 1fb8d4
			goto error;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return rdpgfx_server_single_packet_send(context, s);
Packit 1fb8d4
error:
Packit 1fb8d4
	Stream_Free(s, TRUE);
Packit 1fb8d4
	return error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT rdpgfx_send_map_surface_to_output_pdu(RdpgfxServerContext* context,
Packit Service 5a9772
                                                  const RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU* pdu)
Packit 1fb8d4
{
Packit Service 5a9772
	wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_MAPSURFACETOOUTPUT, 12);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
Packit 1fb8d4
		return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	Stream_Write_UINT16(s, pdu->surfaceId);     /* surfaceId (2 bytes) */
Packit Service 5a9772
	Stream_Write_UINT16(s, 0);                  /* reserved (2 bytes). Must be 0 */
Packit 1fb8d4
	Stream_Write_UINT32(s, pdu->outputOriginX); /* outputOriginX (4 bytes) */
Packit 1fb8d4
	Stream_Write_UINT32(s, pdu->outputOriginY); /* outputOriginY (4 bytes) */
Packit 1fb8d4
	return rdpgfx_server_single_packet_send(context, s);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT rdpgfx_send_map_surface_to_window_pdu(RdpgfxServerContext* context,
Packit Service 5a9772
                                                  const RDPGFX_MAP_SURFACE_TO_WINDOW_PDU* pdu)
Packit 1fb8d4
{
Packit Service 5a9772
	wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_MAPSURFACETOWINDOW, 18);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
Packit 1fb8d4
		return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	Stream_Write_UINT16(s, pdu->surfaceId);    /* surfaceId (2 bytes) */
Packit Service 5a9772
	Stream_Write_UINT64(s, pdu->windowId);     /* windowId (8 bytes) */
Packit Service 5a9772
	Stream_Write_UINT32(s, pdu->mappedWidth);  /* mappedWidth (4 bytes) */
Packit Service 5a9772
	Stream_Write_UINT32(s, pdu->mappedHeight); /* mappedHeight (4 bytes) */
Packit Service 5a9772
	return rdpgfx_server_single_packet_send(context, s);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static UINT
Packit Service 5a9772
rdpgfx_send_map_surface_to_scaled_window_pdu(RdpgfxServerContext* context,
Packit Service 5a9772
                                             const RDPGFX_MAP_SURFACE_TO_SCALED_WINDOW_PDU* pdu)
Packit Service 5a9772
{
Packit Service 5a9772
	wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_MAPSURFACETOSCALEDWINDOW, 26);
Packit Service 5a9772
Packit Service 5a9772
	if (!s)
Packit Service 5a9772
	{
Packit Service 5a9772
		WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
Packit Service 5a9772
		return CHANNEL_RC_NO_MEMORY;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	Stream_Write_UINT16(s, pdu->surfaceId);    /* surfaceId (2 bytes) */
Packit Service 5a9772
	Stream_Write_UINT64(s, pdu->windowId);     /* windowId (8 bytes) */
Packit Service 5a9772
	Stream_Write_UINT32(s, pdu->mappedWidth);  /* mappedWidth (4 bytes) */
Packit 1fb8d4
	Stream_Write_UINT32(s, pdu->mappedHeight); /* mappedHeight (4 bytes) */
Packit Service 5a9772
	Stream_Write_UINT32(s, pdu->targetWidth);  /* targetWidth (4 bytes) */
Packit Service 5a9772
	Stream_Write_UINT32(s, pdu->targetHeight); /* targetHeight  (4 bytes) */
Packit 1fb8d4
	return rdpgfx_server_single_packet_send(context, s);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit Service 5a9772
static UINT rdpgfx_recv_frame_acknowledge_pdu(RdpgfxServerContext* context, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	RDPGFX_FRAME_ACKNOWLEDGE_PDU pdu;
Packit 1fb8d4
	UINT error = CHANNEL_RC_OK;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 12)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "not enough data!");
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	Stream_Read_UINT32(s, pdu.queueDepth);         /* queueDepth (4 bytes) */
Packit Service 5a9772
	Stream_Read_UINT32(s, pdu.frameId);            /* frameId (4 bytes) */
Packit Service 5a9772
	Stream_Read_UINT32(s, pdu.totalFramesDecoded); /* totalFramesDecoded (4 bytes) */
Packit 1fb8d4
Packit 1fb8d4
	if (context)
Packit 1fb8d4
	{
Packit 1fb8d4
		IFCALLRET(context->FrameAcknowledge, error, context, &pdu);
Packit 1fb8d4
Packit 1fb8d4
		if (error)
Packit Service 5a9772
			WLog_ERR(TAG, "context->FrameAcknowledge failed with error %" PRIu32 "", error);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit Service 5a9772
static UINT rdpgfx_recv_cache_import_offer_pdu(RdpgfxServerContext* context, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT16 index;
Packit Service 5a9772
	RDPGFX_CACHE_IMPORT_OFFER_PDU pdu = { 0 };
Packit 1fb8d4
	RDPGFX_CACHE_ENTRY_METADATA* cacheEntries;
Packit 1fb8d4
	UINT error = CHANNEL_RC_OK;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 2)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "not enough data!");
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* cacheEntriesCount (2 bytes) */
Packit 1fb8d4
	Stream_Read_UINT16(s, pdu.cacheEntriesCount);
Packit 1fb8d4
Packit Service 5a9772
	/* 2.2.2.16 RDPGFX_CACHE_IMPORT_OFFER_PDU */
Packit Service 5a9772
	if (pdu.cacheEntriesCount >= 5462)
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_ERR(TAG, "Invalid cacheEntriesCount: %" PRIu16 "", pdu.cacheEntriesCount);
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < (pdu.cacheEntriesCount * 12))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "not enough data!");
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	if (pdu.cacheEntriesCount > 0)
Packit 1fb8d4
	{
Packit Service 5a9772
		pdu.cacheEntries = (RDPGFX_CACHE_ENTRY_METADATA*)calloc(
Packit Service 5a9772
		    pdu.cacheEntriesCount, sizeof(RDPGFX_CACHE_ENTRY_METADATA));
Packit Service 5a9772
Packit Service 5a9772
		if (!pdu.cacheEntries)
Packit Service 5a9772
		{
Packit Service 5a9772
			WLog_ERR(TAG, "calloc failed!");
Packit Service 5a9772
			return CHANNEL_RC_NO_MEMORY;
Packit Service 5a9772
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < pdu.cacheEntriesCount; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		cacheEntries = &(pdu.cacheEntries[index]);
Packit Service 5a9772
		Stream_Read_UINT64(s, cacheEntries->cacheKey);     /* cacheKey (8 bytes) */
Packit Service 5a9772
		Stream_Read_UINT32(s, cacheEntries->bitmapLength); /* bitmapLength (4 bytes) */
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (context)
Packit 1fb8d4
	{
Packit 1fb8d4
		IFCALLRET(context->CacheImportOffer, error, context, &pdu);
Packit 1fb8d4
Packit 1fb8d4
		if (error)
Packit Service 5a9772
			WLog_ERR(TAG, "context->CacheImportOffer failed with error %" PRIu32 "", error);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	free(pdu.cacheEntries);
Packit 1fb8d4
	return error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit Service 5a9772
static UINT rdpgfx_recv_caps_advertise_pdu(RdpgfxServerContext* context, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT16 index;
Packit Service 5a9772
	RDPGFX_CAPSET* capsSets = NULL;
Packit Service 5a9772
	RDPGFX_CAPS_ADVERTISE_PDU pdu = { 0 };
Packit Service 5a9772
	UINT error = ERROR_INVALID_DATA;
Packit Service 5a9772
Packit Service 5a9772
	if (!context)
Packit Service 5a9772
		return ERROR_BAD_ARGUMENTS;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 2)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "not enough data!");
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT16(s, pdu.capsSetCount); /* capsSetCount (2 bytes) */
Packit Service 5a9772
	if (pdu.capsSetCount > 0)
Packit 1fb8d4
	{
Packit Service 5a9772
		capsSets = calloc(pdu.capsSetCount, (RDPGFX_CAPSET_BASE_SIZE + 4));
Packit Service 5a9772
		if (!capsSets)
Packit Service 5a9772
			return ERROR_OUTOFMEMORY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	pdu.capsSets = capsSets;
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < pdu.capsSetCount; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		RDPGFX_CAPSET* capsSet = &(pdu.capsSets[index]);
Packit Service 5a9772
Packit Service 5a9772
		if (Stream_GetRemainingLength(s) < 8)
Packit Service 5a9772
			goto fail;
Packit Service 5a9772
Packit 1fb8d4
		Stream_Read_UINT32(s, capsSet->version); /* version (4 bytes) */
Packit Service 5a9772
		Stream_Read_UINT32(s, capsSet->length);  /* capsDataLength (4 bytes) */
Packit 1fb8d4
Packit Service 5a9772
		if (capsSet->length >= 4)
Packit 1fb8d4
		{
Packit Service 5a9772
			if (Stream_GetRemainingLength(s) < 4)
Packit Service 5a9772
				goto fail;
Packit Service 5a9772
Packit Service 5a9772
			Stream_Peek_UINT32(s, capsSet->flags); /* capsData (4 bytes) */
Packit 1fb8d4
		}
Packit 1fb8d4
Packit Service 5a9772
		if (!Stream_SafeSeek(s, capsSet->length))
Packit Service 5a9772
			goto fail;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	error = ERROR_BAD_CONFIGURATION;
Packit Service 5a9772
	IFCALLRET(context->CapsAdvertise, error, context, &pdu);
Packit 1fb8d4
Packit Service 5a9772
	if (error)
Packit Service 5a9772
		WLog_ERR(TAG, "context->CapsAdvertise failed with error %" PRIu32 "", error);
Packit 1fb8d4
Packit Service 5a9772
fail:
Packit 1fb8d4
	free(capsSets);
Packit 1fb8d4
	return error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit Service 5a9772
static UINT rdpgfx_recv_qoe_frame_acknowledge_pdu(RdpgfxServerContext* context, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU pdu;
Packit 1fb8d4
	UINT error = CHANNEL_RC_OK;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 12)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "not enough data!");
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	Stream_Read_UINT32(s, pdu.frameId);     /* frameId (4 bytes) */
Packit Service 5a9772
	Stream_Read_UINT32(s, pdu.timestamp);   /* timestamp (4 bytes) */
Packit Service 5a9772
	Stream_Read_UINT16(s, pdu.timeDiffSE);  /* timeDiffSE (2 bytes) */
Packit 1fb8d4
	Stream_Read_UINT16(s, pdu.timeDiffEDR); /* timeDiffEDR (2 bytes) */
Packit 1fb8d4
Packit 1fb8d4
	if (context)
Packit 1fb8d4
	{
Packit 1fb8d4
		IFCALLRET(context->QoeFrameAcknowledge, error, context, &pdu);
Packit 1fb8d4
Packit 1fb8d4
		if (error)
Packit Service 5a9772
			WLog_ERR(TAG, "context->QoeFrameAcknowledge failed with error %" PRIu32 "", error);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static UINT
Packit Service 5a9772
rdpgfx_send_map_surface_to_scaled_output_pdu(RdpgfxServerContext* context,
Packit Service 5a9772
                                             const RDPGFX_MAP_SURFACE_TO_SCALED_OUTPUT_PDU* pdu)
Packit Service 5a9772
{
Packit Service 5a9772
	wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_MAPSURFACETOSCALEDOUTPUT, 20);
Packit Service 5a9772
Packit Service 5a9772
	if (!s)
Packit Service 5a9772
	{
Packit Service 5a9772
		WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
Packit Service 5a9772
		return CHANNEL_RC_NO_MEMORY;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	Stream_Write_UINT16(s, pdu->surfaceId);     /* surfaceId (2 bytes) */
Packit Service 5a9772
	Stream_Write_UINT16(s, 0);                  /* reserved (2 bytes). Must be 0 */
Packit Service 5a9772
	Stream_Write_UINT32(s, pdu->outputOriginX); /* outputOriginX (4 bytes) */
Packit Service 5a9772
	Stream_Write_UINT32(s, pdu->outputOriginY); /* outputOriginY (4 bytes) */
Packit Service 5a9772
	Stream_Write_UINT32(s, pdu->targetWidth);   /* targetWidth (4 bytes) */
Packit Service 5a9772
	Stream_Write_UINT32(s, pdu->targetHeight);  /* targetHeight (4 bytes) */
Packit Service 5a9772
	return rdpgfx_server_single_packet_send(context, s);
Packit Service 5a9772
}
Packit Service 5a9772
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT rdpgfx_server_receive_pdu(RdpgfxServerContext* context, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	size_t beg, end;
Packit 1fb8d4
	RDPGFX_HEADER header;
Packit 1fb8d4
	UINT error = CHANNEL_RC_OK;
Packit 1fb8d4
	beg = Stream_GetPosition(s);
Packit 1fb8d4
Packit 1fb8d4
	if ((error = rdpgfx_read_header(s, &header)))
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_ERR(TAG, "rdpgfx_read_header failed with error %" PRIu32 "!", error);
Packit 1fb8d4
		return error;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
#ifdef WITH_DEBUG_RDPGFX
Packit Service 5a9772
	WLog_DBG(TAG, "cmdId: %s (0x%04" PRIX16 ") flags: 0x%04" PRIX16 " pduLength: %" PRIu32 "",
Packit Service 5a9772
	         rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId, header.flags, header.pduLength);
Packit Service 5a9772
#endif
Packit 1fb8d4
Packit 1fb8d4
	switch (header.cmdId)
Packit 1fb8d4
	{
Packit 1fb8d4
		case RDPGFX_CMDID_FRAMEACKNOWLEDGE:
Packit 1fb8d4
			if ((error = rdpgfx_recv_frame_acknowledge_pdu(context, s)))
Packit Service 5a9772
				WLog_ERR(TAG,
Packit Service 5a9772
				         "rdpgfx_recv_frame_acknowledge_pdu "
Packit Service 5a9772
				         "failed with error %" PRIu32 "!",
Packit Service 5a9772
				         error);
Packit 1fb8d4
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RDPGFX_CMDID_CACHEIMPORTOFFER:
Packit 1fb8d4
			if ((error = rdpgfx_recv_cache_import_offer_pdu(context, s)))
Packit Service 5a9772
				WLog_ERR(TAG,
Packit Service 5a9772
				         "rdpgfx_recv_cache_import_offer_pdu "
Packit Service 5a9772
				         "failed with error %" PRIu32 "!",
Packit Service 5a9772
				         error);
Packit 1fb8d4
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RDPGFX_CMDID_CAPSADVERTISE:
Packit 1fb8d4
			if ((error = rdpgfx_recv_caps_advertise_pdu(context, s)))
Packit Service 5a9772
				WLog_ERR(TAG,
Packit Service 5a9772
				         "rdpgfx_recv_caps_advertise_pdu "
Packit Service 5a9772
				         "failed with error %" PRIu32 "!",
Packit Service 5a9772
				         error);
Packit 1fb8d4
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE:
Packit 1fb8d4
			if ((error = rdpgfx_recv_qoe_frame_acknowledge_pdu(context, s)))
Packit Service 5a9772
				WLog_ERR(TAG,
Packit Service 5a9772
				         "rdpgfx_recv_qoe_frame_acknowledge_pdu "
Packit Service 5a9772
				         "failed with error %" PRIu32 "!",
Packit Service 5a9772
				         error);
Packit 1fb8d4
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			error = CHANNEL_RC_BAD_PROC;
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (error)
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_ERR(TAG, "Error while parsing GFX cmdId: %s (0x%04" PRIX16 ")",
Packit 1fb8d4
		         rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId);
Packit 1fb8d4
		return error;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	end = Stream_GetPosition(s);
Packit 1fb8d4
Packit 1fb8d4
	if (end != (beg + header.pduLength))
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_ERR(TAG, "Unexpected gfx pdu end: Actual: %d, Expected: %" PRIu32 "", end,
Packit Service 5a9772
		         (beg + header.pduLength));
Packit 1fb8d4
		Stream_SetPosition(s, (beg + header.pduLength));
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static DWORD WINAPI rdpgfx_server_thread_func(LPVOID arg)
Packit 1fb8d4
{
Packit Service 5a9772
	RdpgfxServerContext* context = (RdpgfxServerContext*)arg;
Packit 1fb8d4
	RdpgfxServerPrivate* priv = context->priv;
Packit 1fb8d4
	DWORD status;
Packit 1fb8d4
	DWORD nCount;
Packit 1fb8d4
	void* buffer;
Packit 1fb8d4
	HANDLE events[8];
Packit 1fb8d4
	UINT error = CHANNEL_RC_OK;
Packit 1fb8d4
	buffer = NULL;
Packit 1fb8d4
	nCount = 0;
Packit 1fb8d4
	events[nCount++] = priv->stopEvent;
Packit 1fb8d4
	events[nCount++] = priv->channelEvent;
Packit 1fb8d4
Packit 1fb8d4
	/* Main virtual channel loop. RDPGFX do not need version negotiation */
Packit 1fb8d4
	while (TRUE)
Packit 1fb8d4
	{
Packit 1fb8d4
		status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
Packit 1fb8d4
Packit 1fb8d4
		if (status == WAIT_FAILED)
Packit 1fb8d4
		{
Packit 1fb8d4
			error = GetLastError();
Packit Service 5a9772
			WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error);
Packit 1fb8d4
			break;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		/* Stop Event */
Packit 1fb8d4
		if (status == WAIT_OBJECT_0)
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		if ((error = rdpgfx_server_handle_messages(context)))
Packit 1fb8d4
		{
Packit Service 5a9772
			WLog_ERR(TAG, "rdpgfx_server_handle_messages failed with error %" PRIu32 "", error);
Packit 1fb8d4
			break;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (error && context->rdpcontext)
Packit Service 5a9772
		setChannelError(context->rdpcontext, error, "rdpgfx_server_thread_func reported an error");
Packit 1fb8d4
Packit 1fb8d4
	ExitThread(error);
Packit 1fb8d4
	return error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL rdpgfx_server_open(RdpgfxServerContext* context)
Packit 1fb8d4
{
Packit Service 5a9772
	RdpgfxServerPrivate* priv = (RdpgfxServerPrivate*)context->priv;
Packit 1fb8d4
	void* buffer = NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (!priv->isOpened)
Packit 1fb8d4
	{
Packit 1fb8d4
		PULONG pSessionId = NULL;
Packit 1fb8d4
		DWORD BytesReturned = 0;
Packit 1fb8d4
		priv->SessionId = WTS_CURRENT_SESSION;
Packit 1fb8d4
Packit Service 5a9772
		if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId,
Packit Service 5a9772
		                                (LPSTR*)&pSessionId, &BytesReturned) == FALSE)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "WTSQuerySessionInformationA failed!");
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit Service 5a9772
		priv->SessionId = (DWORD)*pSessionId;
Packit 1fb8d4
		WTSFreeMemory(pSessionId);
Packit Service 5a9772
		priv->rdpgfx_channel = WTSVirtualChannelOpenEx(priv->SessionId, RDPGFX_DVC_CHANNEL_NAME,
Packit Service 5a9772
		                                               WTS_CHANNEL_OPTION_DYNAMIC);
Packit 1fb8d4
Packit 1fb8d4
		if (!priv->rdpgfx_channel)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "WTSVirtualChannelOpenEx failed!");
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		/* Query for channel event handle */
Packit Service 5a9772
		if (!WTSVirtualChannelQuery(priv->rdpgfx_channel, WTSVirtualEventHandle, &buffer,
Packit Service 5a9772
		                            &BytesReturned) ||
Packit Service 5a9772
		    (BytesReturned != sizeof(HANDLE)))
Packit 1fb8d4
		{
Packit Service 5a9772
			WLog_ERR(TAG,
Packit Service 5a9772
			         "WTSVirtualChannelQuery failed "
Packit Service 5a9772
			         "or invalid returned size(%" PRIu32 ")",
Packit 1fb8d4
			         BytesReturned);
Packit 1fb8d4
Packit 1fb8d4
			if (buffer)
Packit 1fb8d4
				WTSFreeMemory(buffer);
Packit 1fb8d4
Packit 1fb8d4
			goto out_close;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		CopyMemory(&priv->channelEvent, buffer, sizeof(HANDLE));
Packit 1fb8d4
		WTSFreeMemory(buffer);
Packit 1fb8d4
Packit 1fb8d4
		if (!(priv->zgfx = zgfx_context_new(TRUE)))
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "Create zgfx context failed!");
Packit 1fb8d4
			goto out_close;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (priv->ownThread)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (!(priv->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "CreateEvent failed!");
Packit 1fb8d4
				goto out_zgfx;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit Service 5a9772
			if (!(priv->thread =
Packit Service 5a9772
			          CreateThread(NULL, 0, rdpgfx_server_thread_func, (void*)context, 0, NULL)))
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "CreateThread failed!");
Packit 1fb8d4
				goto out_stopEvent;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		priv->isOpened = TRUE;
Packit 1fb8d4
		priv->isReady = FALSE;
Packit 1fb8d4
		return TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	WLog_ERR(TAG, "RDPGFX channel is already opened!");
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
out_stopEvent:
Packit 1fb8d4
	CloseHandle(priv->stopEvent);
Packit 1fb8d4
	priv->stopEvent = NULL;
Packit 1fb8d4
out_zgfx:
Packit 1fb8d4
	zgfx_context_free(priv->zgfx);
Packit 1fb8d4
	priv->zgfx = NULL;
Packit 1fb8d4
out_close:
Packit 1fb8d4
	WTSVirtualChannelClose(priv->rdpgfx_channel);
Packit 1fb8d4
	priv->rdpgfx_channel = NULL;
Packit 1fb8d4
	priv->channelEvent = NULL;
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL rdpgfx_server_close(RdpgfxServerContext* context)
Packit 1fb8d4
{
Packit Service 5a9772
	RdpgfxServerPrivate* priv = (RdpgfxServerPrivate*)context->priv;
Packit 1fb8d4
Packit 1fb8d4
	if (priv->ownThread && priv->thread)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetEvent(priv->stopEvent);
Packit 1fb8d4
Packit 1fb8d4
		if (WaitForSingleObject(priv->thread, INFINITE) == WAIT_FAILED)
Packit 1fb8d4
		{
Packit Service 5a9772
			WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", GetLastError());
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		CloseHandle(priv->thread);
Packit 1fb8d4
		CloseHandle(priv->stopEvent);
Packit 1fb8d4
		priv->thread = NULL;
Packit 1fb8d4
		priv->stopEvent = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	zgfx_context_free(priv->zgfx);
Packit 1fb8d4
	priv->zgfx = NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (priv->rdpgfx_channel)
Packit 1fb8d4
	{
Packit 1fb8d4
		WTSVirtualChannelClose(priv->rdpgfx_channel);
Packit 1fb8d4
		priv->rdpgfx_channel = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	priv->channelEvent = NULL;
Packit 1fb8d4
	priv->isOpened = FALSE;
Packit 1fb8d4
	priv->isReady = FALSE;
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
RdpgfxServerContext* rdpgfx_server_context_new(HANDLE vcm)
Packit 1fb8d4
{
Packit 1fb8d4
	RdpgfxServerContext* context;
Packit 1fb8d4
	RdpgfxServerPrivate* priv;
Packit 1fb8d4
	context = (RdpgfxServerContext*)calloc(1, sizeof(RdpgfxServerContext));
Packit 1fb8d4
Packit 1fb8d4
	if (!context)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "calloc failed!");
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	context->vcm = vcm;
Packit 1fb8d4
	context->Open = rdpgfx_server_open;
Packit 1fb8d4
	context->Close = rdpgfx_server_close;
Packit 1fb8d4
	context->ResetGraphics = rdpgfx_send_reset_graphics_pdu;
Packit 1fb8d4
	context->StartFrame = rdpgfx_send_start_frame_pdu;
Packit 1fb8d4
	context->EndFrame = rdpgfx_send_end_frame_pdu;
Packit 1fb8d4
	context->SurfaceCommand = rdpgfx_send_surface_command;
Packit 1fb8d4
	context->SurfaceFrameCommand = rdpgfx_send_surface_frame_command;
Packit 1fb8d4
	context->DeleteEncodingContext = rdpgfx_send_delete_encoding_context_pdu;
Packit 1fb8d4
	context->CreateSurface = rdpgfx_send_create_surface_pdu;
Packit 1fb8d4
	context->DeleteSurface = rdpgfx_send_delete_surface_pdu;
Packit 1fb8d4
	context->SolidFill = rdpgfx_send_solid_fill_pdu;
Packit 1fb8d4
	context->SurfaceToSurface = rdpgfx_send_surface_to_surface_pdu;
Packit 1fb8d4
	context->SurfaceToCache = rdpgfx_send_surface_to_cache_pdu;
Packit 1fb8d4
	context->CacheToSurface = rdpgfx_send_cache_to_surface_pdu;
Packit 1fb8d4
	context->CacheImportOffer = NULL;
Packit 1fb8d4
	context->CacheImportReply = rdpgfx_send_cache_import_reply_pdu;
Packit 1fb8d4
	context->EvictCacheEntry = rdpgfx_send_evict_cache_entry_pdu;
Packit 1fb8d4
	context->MapSurfaceToOutput = rdpgfx_send_map_surface_to_output_pdu;
Packit 1fb8d4
	context->MapSurfaceToWindow = rdpgfx_send_map_surface_to_window_pdu;
Packit Service 5a9772
	context->MapSurfaceToScaledOutput = rdpgfx_send_map_surface_to_scaled_output_pdu;
Packit Service 5a9772
	context->MapSurfaceToScaledWindow = rdpgfx_send_map_surface_to_scaled_window_pdu;
Packit 1fb8d4
	context->CapsAdvertise = NULL;
Packit 1fb8d4
	context->CapsConfirm = rdpgfx_send_caps_confirm_pdu;
Packit 1fb8d4
	context->FrameAcknowledge = NULL;
Packit 1fb8d4
	context->QoeFrameAcknowledge = NULL;
Packit Service 5a9772
	context->priv = priv = (RdpgfxServerPrivate*)calloc(1, sizeof(RdpgfxServerPrivate));
Packit 1fb8d4
Packit 1fb8d4
	if (!priv)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "calloc failed!");
Packit 1fb8d4
		goto out_free;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* Create shared input stream */
Packit 1fb8d4
	priv->input_stream = Stream_New(NULL, 4);
Packit 1fb8d4
Packit 1fb8d4
	if (!priv->input_stream)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Stream_New failed!");
Packit 1fb8d4
		goto out_free_priv;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	priv->isOpened = FALSE;
Packit 1fb8d4
	priv->isReady = FALSE;
Packit 1fb8d4
	priv->ownThread = TRUE;
Packit Service 5a9772
	return (RdpgfxServerContext*)context;
Packit 1fb8d4
out_free_priv:
Packit 1fb8d4
	free(context->priv);
Packit 1fb8d4
out_free:
Packit 1fb8d4
	free(context);
Packit 1fb8d4
	return NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void rdpgfx_server_context_free(RdpgfxServerContext* context)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpgfx_server_close(context);
Packit 1fb8d4
Packit 1fb8d4
	if (context->priv)
Packit 1fb8d4
		Stream_Free(context->priv->input_stream, TRUE);
Packit 1fb8d4
Packit 1fb8d4
	free(context->priv);
Packit 1fb8d4
	free(context);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
HANDLE rdpgfx_server_get_event_handle(RdpgfxServerContext* context)
Packit 1fb8d4
{
Packit 1fb8d4
	return context->priv->channelEvent;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/*
Packit 1fb8d4
 * Handle rpdgfx messages - server side
Packit 1fb8d4
 *
Packit 1fb8d4
 * @param Server side context
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success
Packit 1fb8d4
 *         ERROR_NO_DATA if no data could be read this time
Packit 1fb8d4
 *         otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
UINT rdpgfx_server_handle_messages(RdpgfxServerContext* context)
Packit 1fb8d4
{
Packit 1fb8d4
	DWORD BytesReturned;
Packit 1fb8d4
	void* buffer;
Packit 1fb8d4
	UINT ret = CHANNEL_RC_OK;
Packit 1fb8d4
	RdpgfxServerPrivate* priv = context->priv;
Packit 1fb8d4
	wStream* s = priv->input_stream;
Packit 1fb8d4
Packit 1fb8d4
	/* Check whether the dynamic channel is ready */
Packit 1fb8d4
	if (!priv->isReady)
Packit 1fb8d4
	{
Packit Service 5a9772
		if (WTSVirtualChannelQuery(priv->rdpgfx_channel, WTSVirtualChannelReady, &buffer,
Packit Service 5a9772
		                           &BytesReturned) == FALSE)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (GetLastError() == ERROR_NO_DATA)
Packit 1fb8d4
				return ERROR_NO_DATA;
Packit 1fb8d4
Packit 1fb8d4
			WLog_ERR(TAG, "WTSVirtualChannelQuery failed");
Packit 1fb8d4
			return ERROR_INTERNAL_ERROR;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit Service 5a9772
		priv->isReady = *((BOOL*)buffer);
Packit 1fb8d4
		WTSFreeMemory(buffer);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* Consume channel event only after the gfx dynamic channel is ready */
Packit 1fb8d4
	if (priv->isReady)
Packit 1fb8d4
	{
Packit 1fb8d4
		Stream_SetPosition(s, 0);
Packit 1fb8d4
Packit Service 5a9772
		if (!WTSVirtualChannelRead(priv->rdpgfx_channel, 0, NULL, 0, &BytesReturned))
Packit 1fb8d4
		{
Packit 1fb8d4
			if (GetLastError() == ERROR_NO_DATA)
Packit 1fb8d4
				return ERROR_NO_DATA;
Packit 1fb8d4
Packit 1fb8d4
			WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
Packit 1fb8d4
			return ERROR_INTERNAL_ERROR;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (BytesReturned < 1)
Packit 1fb8d4
			return CHANNEL_RC_OK;
Packit 1fb8d4
Packit 1fb8d4
		if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
Packit 1fb8d4
			return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit Service 5a9772
		if (WTSVirtualChannelRead(priv->rdpgfx_channel, 0, (PCHAR)Stream_Buffer(s),
Packit 1fb8d4
		                          Stream_Capacity(s), &BytesReturned) == FALSE)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
Packit 1fb8d4
			return ERROR_INTERNAL_ERROR;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		Stream_SetLength(s, BytesReturned);
Packit 1fb8d4
		Stream_SetPosition(s, 0);
Packit 1fb8d4
Packit 1fb8d4
		while (Stream_GetPosition(s) < Stream_Length(s))
Packit 1fb8d4
		{
Packit 1fb8d4
			if ((ret = rdpgfx_server_receive_pdu(context, s)))
Packit 1fb8d4
			{
Packit Service 5a9772
				WLog_ERR(TAG,
Packit Service 5a9772
				         "rdpgfx_server_receive_pdu "
Packit Service 5a9772
				         "failed with error %" PRIu32 "!",
Packit Service 5a9772
				         ret);
Packit 1fb8d4
				return ret;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return ret;
Packit 1fb8d4
}