2013-10-22 06:53:55 +04:00
|
|
|
/**
|
|
|
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
|
|
|
* Graphics Pipeline Extension
|
|
|
|
*
|
2014-06-04 04:51:28 +04:00
|
|
|
* Copyright 2013-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
2015-06-09 16:22:26 +03:00
|
|
|
* Copyright 2015 Thincast Technologies GmbH
|
|
|
|
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
2016-04-05 18:07:45 +03:00
|
|
|
* Copyright 2016 Thincast Technologies GmbH
|
|
|
|
* Copyright 2016 Armin Novak <armin.novak@thincast.com>
|
2013-10-22 06:53:55 +04:00
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#include <winpr/crt.h>
|
2013-10-22 07:33:25 +04:00
|
|
|
#include <winpr/wlog.h>
|
2014-06-03 21:38:10 +04:00
|
|
|
#include <winpr/print.h>
|
2013-10-22 06:53:55 +04:00
|
|
|
#include <winpr/synch.h>
|
|
|
|
#include <winpr/thread.h>
|
|
|
|
#include <winpr/stream.h>
|
|
|
|
#include <winpr/sysinfo.h>
|
|
|
|
#include <winpr/cmdline.h>
|
|
|
|
#include <winpr/collections.h>
|
|
|
|
|
|
|
|
#include <freerdp/addin.h>
|
2014-08-11 11:12:01 +04:00
|
|
|
#include <freerdp/channels/log.h>
|
2013-10-22 06:53:55 +04:00
|
|
|
|
|
|
|
#include "rdpgfx_common.h"
|
2014-06-04 04:51:28 +04:00
|
|
|
#include "rdpgfx_codec.h"
|
2013-10-22 06:53:55 +04:00
|
|
|
|
|
|
|
#include "rdpgfx_main.h"
|
|
|
|
|
2015-06-26 20:59:41 +03:00
|
|
|
#define TAG CHANNELS_TAG("rdpgfx.client")
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2015-09-03 13:00:22 +03:00
|
|
|
static UINT rdpgfx_send_caps_advertise_pdu(RDPGFX_CHANNEL_CALLBACK* callback)
|
2014-06-03 08:05:43 +04:00
|
|
|
{
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2014-06-03 08:05:43 +04:00
|
|
|
wStream* s;
|
|
|
|
UINT16 index;
|
|
|
|
RDPGFX_PLUGIN* gfx;
|
|
|
|
RDPGFX_HEADER header;
|
|
|
|
RDPGFX_CAPSET* capsSet;
|
2016-10-16 11:28:06 +03:00
|
|
|
RDPGFX_CAPSET capsSets[RDPGFX_NUMBER_CAPSETS];
|
2014-06-03 08:05:43 +04:00
|
|
|
RDPGFX_CAPS_ADVERTISE_PDU pdu;
|
|
|
|
gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
|
|
|
header.flags = 0;
|
2014-06-04 03:48:47 +04:00
|
|
|
header.cmdId = RDPGFX_CMDID_CAPSADVERTISE;
|
2014-07-03 22:35:03 +04:00
|
|
|
pdu.capsSetCount = 0;
|
2014-06-04 03:48:47 +04:00
|
|
|
pdu.capsSets = (RDPGFX_CAPSET*) capsSets;
|
2014-07-03 22:35:03 +04:00
|
|
|
capsSet = &capsSets[pdu.capsSetCount++];
|
2014-06-04 03:48:47 +04:00
|
|
|
capsSet->version = RDPGFX_CAPVERSION_8;
|
|
|
|
capsSet->flags = 0;
|
|
|
|
|
|
|
|
if (gfx->ThinClient)
|
|
|
|
capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT;
|
2014-06-03 08:05:43 +04:00
|
|
|
|
2017-10-10 18:12:16 +03:00
|
|
|
/* in CAPVERSION_8 the spec says that we should not have both
|
|
|
|
* thinclient and smallcache (and thinclient implies a small cache)
|
|
|
|
*/
|
|
|
|
if (gfx->SmallCache && !gfx->ThinClient)
|
2014-06-04 03:48:47 +04:00
|
|
|
capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
|
2014-06-03 08:05:43 +04:00
|
|
|
|
2014-07-03 22:35:03 +04:00
|
|
|
capsSet = &capsSets[pdu.capsSetCount++];
|
2014-06-04 03:48:47 +04:00
|
|
|
capsSet->version = RDPGFX_CAPVERSION_81;
|
|
|
|
capsSet->flags = 0;
|
2014-06-03 08:05:43 +04:00
|
|
|
|
2014-06-04 03:48:47 +04:00
|
|
|
if (gfx->ThinClient)
|
|
|
|
capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT;
|
2014-06-03 08:05:43 +04:00
|
|
|
|
2014-06-04 03:48:47 +04:00
|
|
|
if (gfx->SmallCache)
|
|
|
|
capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
|
|
|
|
|
2017-07-17 10:00:57 +03:00
|
|
|
#ifdef WITH_GFX_H264
|
2014-06-04 03:48:47 +04:00
|
|
|
if (gfx->H264)
|
2016-03-14 10:57:00 +03:00
|
|
|
capsSet->flags |= RDPGFX_CAPS_FLAG_AVC420_ENABLED;
|
2017-07-17 10:00:57 +03:00
|
|
|
#endif
|
2016-03-02 17:16:49 +03:00
|
|
|
|
2017-09-11 13:05:03 +03:00
|
|
|
if (!gfx->H264 || gfx->AVC444)
|
|
|
|
{
|
|
|
|
capsSet = &capsSets[pdu.capsSetCount++];
|
|
|
|
capsSet->version = RDPGFX_CAPVERSION_10;
|
|
|
|
capsSet->flags = 0;
|
2016-03-02 17:16:49 +03:00
|
|
|
|
2017-09-11 13:05:03 +03:00
|
|
|
if (gfx->SmallCache)
|
|
|
|
capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
|
2016-03-02 17:16:49 +03:00
|
|
|
|
2017-07-17 10:00:57 +03:00
|
|
|
#ifdef WITH_GFX_H264
|
2017-09-11 13:05:03 +03:00
|
|
|
if (!gfx->AVC444)
|
|
|
|
capsSet->flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
|
2017-07-17 10:00:57 +03:00
|
|
|
#else
|
2017-09-11 13:05:03 +03:00
|
|
|
capsSet->flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
|
2017-07-17 10:00:57 +03:00
|
|
|
#endif
|
2016-10-16 11:28:06 +03:00
|
|
|
|
2017-09-11 13:05:03 +03:00
|
|
|
capsSets[pdu.capsSetCount] = *capsSet;
|
|
|
|
capsSets[pdu.capsSetCount++].version = RDPGFX_CAPVERSION_102;
|
|
|
|
capsSets[pdu.capsSetCount] = *capsSet;
|
|
|
|
capsSets[pdu.capsSetCount++].version = RDPGFX_CAPVERSION_103;
|
|
|
|
}
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2017-10-10 18:12:16 +03:00
|
|
|
header.pduLength = RDPGFX_HEADER_SIZE + 2 + (pdu.capsSetCount * RDPGFX_CAPSET_SIZE);
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_DEBUG, "SendCapsAdvertisePdu %"PRIu16"", pdu.capsSetCount);
|
2014-06-03 08:05:43 +04:00
|
|
|
s = Stream_New(NULL, header.pduLength);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (!s)
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "Stream_New failed!");
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
2014-06-03 08:05:43 +04:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if ((error = rdpgfx_write_header(s, &header)))
|
2017-05-17 11:27:25 +03:00
|
|
|
goto fail;
|
2014-06-03 08:05:43 +04:00
|
|
|
|
|
|
|
/* RDPGFX_CAPS_ADVERTISE_PDU */
|
|
|
|
Stream_Write_UINT16(s, pdu.capsSetCount); /* capsSetCount (2 bytes) */
|
|
|
|
|
|
|
|
for (index = 0; index < pdu.capsSetCount; index++)
|
|
|
|
{
|
2014-06-04 03:48:47 +04:00
|
|
|
capsSet = &(pdu.capsSets[index]);
|
2014-06-03 08:05:43 +04:00
|
|
|
Stream_Write_UINT32(s, capsSet->version); /* version (4 bytes) */
|
2014-06-04 03:48:47 +04:00
|
|
|
Stream_Write_UINT32(s, 4); /* capsDataLength (4 bytes) */
|
|
|
|
Stream_Write_UINT32(s, capsSet->flags); /* capsData (4 bytes) */
|
2014-06-03 08:05:43 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
Stream_SealLength(s);
|
2016-08-04 17:28:38 +03:00
|
|
|
error = callback->channel->Write(callback->channel, (UINT32) Stream_Length(s),
|
|
|
|
Stream_Buffer(s), NULL);
|
2017-05-17 11:27:25 +03:00
|
|
|
fail:
|
2014-06-03 08:05:43 +04:00
|
|
|
Stream_Free(s, TRUE);
|
2015-06-09 16:22:26 +03:00
|
|
|
return error;
|
2014-06-03 08:05:43 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2016-08-04 17:28:38 +03:00
|
|
|
static UINT rdpgfx_recv_caps_confirm_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
|
|
|
|
wStream* s)
|
2014-06-03 23:32:03 +04:00
|
|
|
{
|
|
|
|
RDPGFX_CAPSET capsSet;
|
2014-06-04 03:48:47 +04:00
|
|
|
UINT32 capsDataLength;
|
2014-06-03 23:32:03 +04:00
|
|
|
RDPGFX_CAPS_CONFIRM_PDU pdu;
|
2017-05-15 18:24:47 +03:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
|
|
|
|
2014-06-03 23:32:03 +04:00
|
|
|
pdu.capsSet = &capsSet;
|
|
|
|
|
2014-07-01 19:33:35 +04:00
|
|
|
if (Stream_GetRemainingLength(s) < 12)
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2016-05-11 20:42:54 +03:00
|
|
|
WLog_ERR(TAG, "not enough data!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
2014-07-01 19:33:35 +04:00
|
|
|
|
2014-06-03 23:32:03 +04:00
|
|
|
Stream_Read_UINT32(s, capsSet.version); /* version (4 bytes) */
|
2014-06-04 03:48:47 +04:00
|
|
|
Stream_Read_UINT32(s, capsDataLength); /* capsDataLength (4 bytes) */
|
|
|
|
Stream_Read_UINT32(s, capsSet.flags); /* capsData (4 bytes) */
|
2017-05-17 11:27:25 +03:00
|
|
|
|
|
|
|
gfx->ConnectionCaps = capsSet;
|
|
|
|
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_DEBUG, "RecvCapsConfirmPdu: version: 0x%08"PRIX32" flags: 0x%08"PRIX32"",
|
2016-08-04 17:28:38 +03:00
|
|
|
capsSet.version, capsSet.flags);
|
2015-06-09 16:22:26 +03:00
|
|
|
return CHANNEL_RC_OK;
|
2014-06-03 23:32:03 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2016-08-04 17:28:38 +03:00
|
|
|
static UINT rdpgfx_send_frame_acknowledge_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
|
|
|
|
RDPGFX_FRAME_ACKNOWLEDGE_PDU* pdu)
|
2014-06-04 03:48:47 +04:00
|
|
|
{
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2014-06-04 03:48:47 +04:00
|
|
|
wStream* s;
|
|
|
|
RDPGFX_HEADER header;
|
2017-05-15 18:24:47 +03:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
|
|
|
|
2014-06-04 03:48:47 +04:00
|
|
|
header.flags = 0;
|
|
|
|
header.cmdId = RDPGFX_CMDID_FRAMEACKNOWLEDGE;
|
|
|
|
header.pduLength = RDPGFX_HEADER_SIZE + 12;
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_DEBUG, "SendFrameAcknowledgePdu: %"PRIu32"", pdu->frameId);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2017-12-23 12:26:25 +03:00
|
|
|
s = Stream_New(NULL, header.pduLength);
|
2015-06-09 16:22:26 +03:00
|
|
|
if (!s)
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "Stream_New failed!");
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if ((error = rdpgfx_write_header(s, &header)))
|
2017-05-17 11:27:25 +03:00
|
|
|
goto fail;
|
2014-06-04 03:48:47 +04:00
|
|
|
|
|
|
|
/* RDPGFX_FRAME_ACKNOWLEDGE_PDU */
|
|
|
|
Stream_Write_UINT32(s, pdu->queueDepth); /* queueDepth (4 bytes) */
|
|
|
|
Stream_Write_UINT32(s, pdu->frameId); /* frameId (4 bytes) */
|
2016-08-04 17:28:38 +03:00
|
|
|
Stream_Write_UINT32(s,
|
|
|
|
pdu->totalFramesDecoded); /* totalFramesDecoded (4 bytes) */
|
|
|
|
error = callback->channel->Write(callback->channel, (UINT32) Stream_Length(s),
|
|
|
|
Stream_Buffer(s), NULL);
|
2017-05-17 11:27:25 +03:00
|
|
|
fail:
|
|
|
|
Stream_Free(s, TRUE);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT rdpgfx_send_qoe_frame_acknowledge_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
|
|
|
|
const RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU* pdu)
|
|
|
|
{
|
|
|
|
UINT error;
|
|
|
|
wStream* s;
|
|
|
|
RDPGFX_HEADER header;
|
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
|
|
|
|
|
|
|
header.flags = 0;
|
|
|
|
header.cmdId = RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE;
|
|
|
|
header.pduLength = RDPGFX_HEADER_SIZE + 12;
|
|
|
|
WLog_Print(gfx->log, WLOG_DEBUG, "SendQoeFrameAcknowledgePdu: %"PRIu32"", pdu->frameId);
|
|
|
|
|
2017-12-23 12:26:25 +03:00
|
|
|
s = Stream_New(NULL, header.pduLength);
|
2017-05-17 11:27:25 +03:00
|
|
|
if (!s)
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "Stream_New failed!");
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((error = rdpgfx_write_header(s, &header)))
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
/* RDPGFX_FRAME_ACKNOWLEDGE_PDU */
|
|
|
|
Stream_Write_UINT32(s, pdu->frameId);
|
|
|
|
Stream_Write_UINT32(s, pdu->timestamp);
|
|
|
|
Stream_Write_UINT16(s, pdu->timeDiffSE);
|
|
|
|
Stream_Write_UINT16(s, pdu->timeDiffEDR);
|
|
|
|
|
|
|
|
error = callback->channel->Write(callback->channel, (UINT32) Stream_Length(s),
|
|
|
|
Stream_Buffer(s), NULL);
|
|
|
|
fail:
|
2014-06-04 03:48:47 +04:00
|
|
|
Stream_Free(s, TRUE);
|
2015-06-09 16:22:26 +03:00
|
|
|
return error;
|
2014-06-04 03:48:47 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2016-08-04 17:28:38 +03:00
|
|
|
static UINT rdpgfx_recv_reset_graphics_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
|
|
|
|
wStream* s)
|
2014-06-03 23:32:03 +04:00
|
|
|
{
|
2014-06-05 05:35:31 +04:00
|
|
|
int pad;
|
2014-06-03 23:32:03 +04:00
|
|
|
UINT32 index;
|
|
|
|
MONITOR_DEF* monitor;
|
|
|
|
RDPGFX_RESET_GRAPHICS_PDU pdu;
|
2014-06-04 23:18:02 +04:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
|
|
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error = CHANNEL_RC_OK;
|
Fix for #4330
Since ec027bf dynamic resolution is broken when used with egfx. Before that commit
we were tracking a server sent resize by setting a DesktopResize callback. This callback
is called when the desktop is resized by the server. Anyway the problem was that when this
callback is called, the activation sequence is not always completed, which were leading to
some freeze with 2012r2 servers (sending packets before the sequence is finished).
So with the faulty commit, we are tracking server resizes by subscribing to the Actived
event, that is called at the end of a reactivation sequence, so we're sure to not send packets
when not fully activated.
Anyway the issue that shows on (#4330) is that when you use egfx, no reactivation sequence happens,
the server only sends a ResetGraphics message with the new size, and so we miss the resized event.
This fix introduces a new GraphicsReset event, makes the display channel subscribe to that event,
and react accordingly.
2017-12-23 15:50:54 +03:00
|
|
|
GraphicsResetEventArgs graphicsReset;
|
2014-06-03 23:32:03 +04:00
|
|
|
|
2014-07-01 19:33:35 +04:00
|
|
|
if (Stream_GetRemainingLength(s) < 12)
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "not enough data!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
2014-07-01 19:33:35 +04:00
|
|
|
|
2014-06-03 23:32:03 +04:00
|
|
|
Stream_Read_UINT32(s, pdu.width); /* width (4 bytes) */
|
|
|
|
Stream_Read_UINT32(s, pdu.height); /* height (4 bytes) */
|
|
|
|
Stream_Read_UINT32(s, pdu.monitorCount); /* monitorCount (4 bytes) */
|
|
|
|
|
2014-07-01 19:33:35 +04:00
|
|
|
if (Stream_GetRemainingLength(s) < (pdu.monitorCount * 20))
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "not enough data!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
2014-07-01 19:33:35 +04:00
|
|
|
|
2017-12-23 12:26:25 +03:00
|
|
|
pdu.monitorDefArray = (MONITOR_DEF*) calloc(pdu.monitorCount, sizeof(MONITOR_DEF));
|
2014-06-03 23:32:03 +04:00
|
|
|
if (!pdu.monitorDefArray)
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "calloc failed!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
2014-06-03 23:32:03 +04:00
|
|
|
|
|
|
|
for (index = 0; index < pdu.monitorCount; index++)
|
|
|
|
{
|
|
|
|
monitor = &(pdu.monitorDefArray[index]);
|
|
|
|
Stream_Read_UINT32(s, monitor->left); /* left (4 bytes) */
|
|
|
|
Stream_Read_UINT32(s, monitor->top); /* top (4 bytes) */
|
|
|
|
Stream_Read_UINT32(s, monitor->right); /* right (4 bytes) */
|
|
|
|
Stream_Read_UINT32(s, monitor->bottom); /* bottom (4 bytes) */
|
|
|
|
Stream_Read_UINT32(s, monitor->flags); /* flags (4 bytes) */
|
|
|
|
}
|
|
|
|
|
2014-06-05 05:35:31 +04:00
|
|
|
pad = 340 - (RDPGFX_HEADER_SIZE + 12 + (pdu.monitorCount * 20));
|
2014-07-01 19:33:35 +04:00
|
|
|
|
2014-08-12 02:48:42 +04:00
|
|
|
if (Stream_GetRemainingLength(s) < (size_t) pad)
|
2014-11-17 01:30:31 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "Stream_GetRemainingLength failed!");
|
2014-11-17 01:30:31 +03:00
|
|
|
free(pdu.monitorDefArray);
|
2015-06-09 16:22:26 +03:00
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
2014-11-17 01:30:31 +03:00
|
|
|
}
|
2014-07-01 19:33:35 +04:00
|
|
|
|
2014-06-05 05:35:31 +04:00
|
|
|
Stream_Seek(s, pad); /* pad (total size is 340 bytes) */
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_DEBUG, "RecvResetGraphicsPdu: width: %"PRIu32" height: %"PRIu32" count: %"PRIu32"",
|
2016-08-04 17:28:38 +03:00
|
|
|
pdu.width, pdu.height, pdu.monitorCount);
|
2017-04-10 18:16:57 +03:00
|
|
|
|
2017-02-16 16:46:20 +03:00
|
|
|
for (index = 0; index < pdu.monitorCount; index++)
|
|
|
|
{
|
|
|
|
monitor = &(pdu.monitorDefArray[index]);
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_DEBUG,
|
2017-04-10 18:16:57 +03:00
|
|
|
"RecvResetGraphicsPdu: monitor left:%"PRIi32" top:%"PRIi32" right:%"PRIi32" left:%"PRIi32" flags:0x%"PRIx32"",
|
|
|
|
monitor->left, monitor->top, monitor->right, monitor->bottom, monitor->flags);
|
2017-02-16 16:46:20 +03:00
|
|
|
}
|
2014-06-03 23:32:03 +04:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (context)
|
2014-06-04 23:18:02 +04:00
|
|
|
{
|
2015-06-09 16:22:26 +03:00
|
|
|
IFCALLRET(context->ResetGraphics, error, context, &pdu);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (error)
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "context->ResetGraphics failed with error %"PRIu32"", error);
|
2014-06-04 23:18:02 +04:00
|
|
|
}
|
|
|
|
|
Fix for #4330
Since ec027bf dynamic resolution is broken when used with egfx. Before that commit
we were tracking a server sent resize by setting a DesktopResize callback. This callback
is called when the desktop is resized by the server. Anyway the problem was that when this
callback is called, the activation sequence is not always completed, which were leading to
some freeze with 2012r2 servers (sending packets before the sequence is finished).
So with the faulty commit, we are tracking server resizes by subscribing to the Actived
event, that is called at the end of a reactivation sequence, so we're sure to not send packets
when not fully activated.
Anyway the issue that shows on (#4330) is that when you use egfx, no reactivation sequence happens,
the server only sends a ResetGraphics message with the new size, and so we miss the resized event.
This fix introduces a new GraphicsReset event, makes the display channel subscribe to that event,
and react accordingly.
2017-12-23 15:50:54 +03:00
|
|
|
/* some listeners may be interested (namely the display channel) */
|
|
|
|
EventArgsInit(&graphicsReset, "xfreerdp");
|
|
|
|
graphicsReset.width = pdu.width;
|
|
|
|
graphicsReset.height = pdu.height;
|
|
|
|
PubSub_OnGraphicsReset(gfx->rdpcontext->pubSub, gfx->rdpcontext, &graphicsReset);
|
|
|
|
|
2014-06-20 21:52:13 +04:00
|
|
|
free(pdu.monitorDefArray);
|
2015-06-09 16:22:26 +03:00
|
|
|
return error;
|
2014-06-03 23:32:03 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2016-08-04 17:28:38 +03:00
|
|
|
static UINT rdpgfx_recv_evict_cache_entry_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
|
|
|
|
wStream* s)
|
2014-06-04 03:48:47 +04:00
|
|
|
{
|
|
|
|
RDPGFX_EVICT_CACHE_ENTRY_PDU pdu;
|
2014-06-04 23:18:02 +04:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
|
|
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error = CHANNEL_RC_OK;
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2014-07-01 19:33:35 +04:00
|
|
|
if (Stream_GetRemainingLength(s) < 2)
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "not enough data!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
2014-07-01 19:33:35 +04:00
|
|
|
|
2014-06-04 03:48:47 +04:00
|
|
|
Stream_Read_UINT16(s, pdu.cacheSlot); /* cacheSlot (2 bytes) */
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_DEBUG, "RecvEvictCacheEntryPdu: cacheSlot: %"PRIu16"", pdu.cacheSlot);
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (context)
|
2014-06-04 23:18:02 +04:00
|
|
|
{
|
2015-06-09 16:22:26 +03:00
|
|
|
IFCALLRET(context->EvictCacheEntry, error, context, &pdu);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (error)
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "context->EvictCacheEntry failed with error %"PRIu32"", error);
|
2014-06-04 23:18:02 +04:00
|
|
|
}
|
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
return error;
|
2014-06-04 03:48:47 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2016-10-17 10:05:54 +03:00
|
|
|
static UINT rdpgfx_recv_cache_import_reply_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
|
|
|
|
wStream* s)
|
2014-06-04 03:48:47 +04:00
|
|
|
{
|
|
|
|
UINT16 index;
|
|
|
|
RDPGFX_CACHE_IMPORT_REPLY_PDU pdu;
|
2014-06-04 23:18:02 +04:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
|
|
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error = CHANNEL_RC_OK;
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2014-07-01 19:33:35 +04:00
|
|
|
if (Stream_GetRemainingLength(s) < 2)
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "not enough data!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
2014-07-01 19:33:35 +04:00
|
|
|
|
2014-06-04 03:48:47 +04:00
|
|
|
Stream_Read_UINT16(s, pdu.importedEntriesCount); /* cacheSlot (2 bytes) */
|
|
|
|
|
2016-08-04 17:28:38 +03:00
|
|
|
if (Stream_GetRemainingLength(s) < (size_t)(pdu.importedEntriesCount * 2))
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "not enough data!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
2014-07-01 19:33:35 +04:00
|
|
|
|
2014-06-04 03:48:47 +04:00
|
|
|
pdu.cacheSlots = (UINT16*) calloc(pdu.importedEntriesCount, sizeof(UINT16));
|
|
|
|
if (!pdu.cacheSlots)
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "calloc failed!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
2014-06-04 03:48:47 +04:00
|
|
|
|
|
|
|
for (index = 0; index < pdu.importedEntriesCount; index++)
|
|
|
|
{
|
|
|
|
Stream_Read_UINT16(s, pdu.cacheSlots[index]); /* cacheSlot (2 bytes) */
|
|
|
|
}
|
|
|
|
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_DEBUG, "RecvCacheImportReplyPdu: importedEntriesCount: %"PRIu16"",
|
2016-08-04 17:28:38 +03:00
|
|
|
pdu.importedEntriesCount);
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (context)
|
2014-06-04 23:18:02 +04:00
|
|
|
{
|
2015-06-09 16:22:26 +03:00
|
|
|
IFCALLRET(context->CacheImportReply, error, context, &pdu);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (error)
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "context->CacheImportReply failed with error %"PRIu32"", error);
|
2014-06-04 23:18:02 +04:00
|
|
|
}
|
|
|
|
|
2014-07-01 19:33:35 +04:00
|
|
|
free(pdu.cacheSlots);
|
2015-06-09 16:22:26 +03:00
|
|
|
return error;
|
2014-06-04 03:48:47 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2016-08-04 17:28:38 +03:00
|
|
|
static UINT rdpgfx_recv_create_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
|
|
|
|
wStream* s)
|
2014-06-03 23:32:03 +04:00
|
|
|
{
|
|
|
|
RDPGFX_CREATE_SURFACE_PDU pdu;
|
2014-06-04 23:18:02 +04:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
|
|
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error = CHANNEL_RC_OK;
|
2014-06-03 23:32:03 +04:00
|
|
|
|
2014-07-01 19:33:35 +04:00
|
|
|
if (Stream_GetRemainingLength(s) < 7)
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "not enough data!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
2014-07-01 19:33:35 +04:00
|
|
|
|
2014-06-03 23:32:03 +04:00
|
|
|
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
|
|
|
Stream_Read_UINT16(s, pdu.width); /* width (2 bytes) */
|
|
|
|
Stream_Read_UINT16(s, pdu.height); /* height (2 bytes) */
|
|
|
|
Stream_Read_UINT8(s, pdu.pixelFormat); /* RDPGFX_PIXELFORMAT (1 byte) */
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_DEBUG,
|
2016-12-14 00:47:08 +03:00
|
|
|
"RecvCreateSurfacePdu: surfaceId: %"PRIu16" width: %"PRIu16" height: %"PRIu16" pixelFormat: 0x%02"PRIX8"",
|
2016-08-04 17:28:38 +03:00
|
|
|
pdu.surfaceId, pdu.width, pdu.height, pdu.pixelFormat);
|
2014-06-03 23:32:03 +04:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (context)
|
2014-06-04 23:18:02 +04:00
|
|
|
{
|
2015-06-09 16:22:26 +03:00
|
|
|
IFCALLRET(context->CreateSurface, error, context, &pdu);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (error)
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "context->CreateSurface failed with error %"PRIu32"", error);
|
2014-06-04 23:18:02 +04:00
|
|
|
}
|
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
return error;
|
2014-06-03 23:32:03 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2016-10-17 10:05:54 +03:00
|
|
|
static UINT rdpgfx_recv_delete_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
|
|
|
|
wStream* s)
|
2014-06-04 03:48:47 +04:00
|
|
|
{
|
|
|
|
RDPGFX_DELETE_SURFACE_PDU pdu;
|
2014-06-04 23:18:02 +04:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
|
|
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error = CHANNEL_RC_OK;
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2014-07-01 19:33:35 +04:00
|
|
|
if (Stream_GetRemainingLength(s) < 2)
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "not enough data!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
2014-07-01 19:33:35 +04:00
|
|
|
|
2014-06-04 03:48:47 +04:00
|
|
|
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_DEBUG, "RecvDeleteSurfacePdu: surfaceId: %"PRIu16"", pdu.surfaceId);
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (context)
|
2014-06-04 23:18:02 +04:00
|
|
|
{
|
2015-06-09 16:22:26 +03:00
|
|
|
IFCALLRET(context->DeleteSurface, error, context, &pdu);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (error)
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "context->DeleteSurface failed with error %"PRIu32"", error);
|
2014-06-04 23:18:02 +04:00
|
|
|
}
|
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
return error;
|
2014-06-04 03:48:47 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2016-08-04 17:28:38 +03:00
|
|
|
static UINT rdpgfx_recv_start_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
|
|
|
|
wStream* s)
|
2014-06-03 23:32:03 +04:00
|
|
|
{
|
|
|
|
RDPGFX_START_FRAME_PDU pdu;
|
2014-06-04 03:48:47 +04:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
2014-06-04 23:18:02 +04:00
|
|
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error = CHANNEL_RC_OK;
|
2014-06-03 23:32:03 +04:00
|
|
|
|
2016-08-16 09:49:56 +03:00
|
|
|
if (Stream_GetRemainingLength(s) < RDPGFX_START_FRAME_PDU_SIZE)
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "not enough data!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
2014-07-01 19:33:35 +04:00
|
|
|
|
2014-06-03 23:32:03 +04:00
|
|
|
Stream_Read_UINT32(s, pdu.timestamp); /* timestamp (4 bytes) */
|
|
|
|
Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_DEBUG, "RecvStartFramePdu: frameId: %"PRIu32" timestamp: 0x%08"PRIX32"",
|
2016-08-04 17:28:38 +03:00
|
|
|
pdu.frameId, pdu.timestamp);
|
2014-06-03 23:32:03 +04:00
|
|
|
|
2017-05-17 11:27:25 +03:00
|
|
|
gfx->StartDecodingTime = GetTickCountPrecise();
|
2015-06-09 16:22:26 +03:00
|
|
|
if (context)
|
2014-06-04 23:18:02 +04:00
|
|
|
{
|
2015-06-09 16:22:26 +03:00
|
|
|
IFCALLRET(context->StartFrame, error, context, &pdu);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (error)
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "context->StartFrame failed with error %"PRIu32"", error);
|
2014-06-04 23:18:02 +04:00
|
|
|
}
|
|
|
|
|
2014-06-04 03:48:47 +04:00
|
|
|
gfx->UnacknowledgedFrames++;
|
2015-06-09 16:22:26 +03:00
|
|
|
return error;
|
2014-06-03 23:32:03 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2016-08-04 17:28:38 +03:00
|
|
|
static UINT rdpgfx_recv_end_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
|
|
|
|
wStream* s)
|
2014-06-03 23:32:03 +04:00
|
|
|
{
|
|
|
|
RDPGFX_END_FRAME_PDU pdu;
|
2014-06-04 03:48:47 +04:00
|
|
|
RDPGFX_FRAME_ACKNOWLEDGE_PDU ack;
|
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
2014-06-04 23:18:02 +04:00
|
|
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error = CHANNEL_RC_OK;
|
2014-06-03 23:32:03 +04:00
|
|
|
|
2016-08-16 09:49:56 +03:00
|
|
|
if (Stream_GetRemainingLength(s) < RDPGFX_END_FRAME_PDU_SIZE)
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "not enough data!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
2014-07-01 19:33:35 +04:00
|
|
|
|
2014-06-03 23:32:03 +04:00
|
|
|
Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_DEBUG, "RecvEndFramePdu: frameId: %"PRIu32"", pdu.frameId);
|
2014-06-03 23:32:03 +04:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (context)
|
2014-06-04 23:18:02 +04:00
|
|
|
{
|
2015-06-09 16:22:26 +03:00
|
|
|
IFCALLRET(context->EndFrame, error, context, &pdu);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (error)
|
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "context->EndFrame failed with error %"PRIu32"", error);
|
2015-06-09 16:22:26 +03:00
|
|
|
return error;
|
|
|
|
}
|
2014-06-04 23:18:02 +04:00
|
|
|
}
|
|
|
|
|
2014-06-04 03:48:47 +04:00
|
|
|
gfx->UnacknowledgedFrames--;
|
|
|
|
gfx->TotalDecodedFrames++;
|
|
|
|
ack.frameId = pdu.frameId;
|
|
|
|
ack.totalFramesDecoded = gfx->TotalDecodedFrames;
|
|
|
|
|
2015-07-06 23:28:52 +03:00
|
|
|
if (gfx->suspendFrameAcks)
|
|
|
|
{
|
|
|
|
ack.queueDepth = SUSPEND_FRAME_ACKNOWLEDGEMENT;
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2015-07-08 21:16:29 +03:00
|
|
|
if (gfx->TotalDecodedFrames == 1)
|
2016-08-04 17:28:38 +03:00
|
|
|
if ((error = rdpgfx_send_frame_acknowledge_pdu(callback, &ack)))
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_send_frame_acknowledge_pdu failed with error %"PRIu32"", error);
|
2015-07-06 23:28:52 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ack.queueDepth = QUEUE_DEPTH_UNAVAILABLE;
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2015-08-25 10:07:04 +03:00
|
|
|
if ((error = rdpgfx_send_frame_acknowledge_pdu(callback, &ack)))
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_DEBUG, "rdpgfx_send_frame_acknowledge_pdu failed with error %"PRIu32"", error);
|
2015-07-06 23:28:52 +03:00
|
|
|
}
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2017-05-17 11:27:25 +03:00
|
|
|
switch(gfx->ConnectionCaps.version)
|
|
|
|
{
|
|
|
|
case RDPGFX_CAPVERSION_10:
|
|
|
|
case RDPGFX_CAPVERSION_102:
|
|
|
|
case RDPGFX_CAPVERSION_103:
|
2017-05-18 15:05:41 +03:00
|
|
|
if (gfx->SendQoeAck)
|
2017-05-17 11:27:25 +03:00
|
|
|
{
|
|
|
|
RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU qoe;
|
|
|
|
UINT32 diff = (GetTickCountPrecise() - gfx->StartDecodingTime);
|
|
|
|
|
|
|
|
if (diff > 65000)
|
|
|
|
diff = 0;
|
|
|
|
|
|
|
|
qoe.frameId = pdu.frameId;
|
|
|
|
qoe.timestamp = gfx->StartDecodingTime;
|
|
|
|
qoe.timeDiffSE = diff;
|
|
|
|
qoe.timeDiffEDR = 1;
|
|
|
|
if ((error = rdpgfx_send_qoe_frame_acknowledge_pdu(callback, &qoe)))
|
|
|
|
WLog_Print(gfx->log, WLOG_DEBUG, "rdpgfx_send_frame_acknowledge_pdu failed with error %"PRIu32"", error);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
return error;
|
2014-06-04 03:48:47 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2016-08-04 17:28:38 +03:00
|
|
|
static UINT rdpgfx_recv_wire_to_surface_1_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
|
|
|
|
wStream* s)
|
2014-06-04 03:48:47 +04:00
|
|
|
{
|
2014-06-04 04:51:28 +04:00
|
|
|
RDPGFX_SURFACE_COMMAND cmd;
|
2014-06-04 03:48:47 +04:00
|
|
|
RDPGFX_WIRE_TO_SURFACE_PDU_1 pdu;
|
2014-06-04 04:51:28 +04:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2016-08-16 09:49:56 +03:00
|
|
|
if (Stream_GetRemainingLength(s) < RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE)
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "not enough data!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
2014-07-01 19:33:35 +04:00
|
|
|
|
2014-06-04 03:48:47 +04:00
|
|
|
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
|
|
|
Stream_Read_UINT16(s, pdu.codecId); /* codecId (2 bytes) */
|
|
|
|
Stream_Read_UINT8(s, pdu.pixelFormat); /* pixelFormat (1 byte) */
|
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if ((error = rdpgfx_read_rect16(s, &(pdu.destRect)))) /* destRect (8 bytes) */
|
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_read_rect16 failed with error %"PRIu32"", error);
|
2015-06-09 16:22:26 +03:00
|
|
|
return error;
|
|
|
|
}
|
2014-06-04 03:48:47 +04:00
|
|
|
|
|
|
|
Stream_Read_UINT32(s, pdu.bitmapDataLength); /* bitmapDataLength (4 bytes) */
|
|
|
|
|
2014-06-13 05:02:25 +04:00
|
|
|
if (pdu.bitmapDataLength > Stream_GetRemainingLength(s))
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "not enough data!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
2014-06-13 05:02:25 +04:00
|
|
|
|
2014-06-04 03:48:47 +04:00
|
|
|
pdu.bitmapData = Stream_Pointer(s);
|
2014-06-05 05:35:31 +04:00
|
|
|
Stream_Seek(s, pdu.bitmapDataLength);
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_DEBUG,
|
2017-01-17 18:00:24 +03:00
|
|
|
"RecvWireToSurface1Pdu: surfaceId: %"PRIu16" codecId: %s (0x%04"PRIX16") pixelFormat: 0x%02"PRIX8" "
|
|
|
|
"destRect: left: %"PRIu16" top: %"PRIu16" right: %"PRIu16" bottom: %"PRIu16" bitmapDataLength: %"PRIu32"",
|
|
|
|
pdu.surfaceId, rdpgfx_get_codec_id_string(pdu.codecId),
|
|
|
|
pdu.codecId, pdu.pixelFormat,
|
|
|
|
pdu.destRect.left, pdu.destRect.top,
|
|
|
|
pdu.destRect.right, pdu.destRect.bottom,
|
|
|
|
pdu.bitmapDataLength);
|
2014-06-04 04:51:28 +04:00
|
|
|
cmd.surfaceId = pdu.surfaceId;
|
|
|
|
cmd.codecId = pdu.codecId;
|
2014-06-05 05:35:31 +04:00
|
|
|
cmd.contextId = 0;
|
2016-08-04 17:28:38 +03:00
|
|
|
|
|
|
|
switch (pdu.pixelFormat)
|
|
|
|
{
|
|
|
|
case GFX_PIXEL_FORMAT_XRGB_8888:
|
|
|
|
cmd.format = PIXEL_FORMAT_BGRX32;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GFX_PIXEL_FORMAT_ARGB_8888:
|
|
|
|
cmd.format = PIXEL_FORMAT_BGRA32;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return ERROR_INVALID_DATA;
|
2016-04-05 18:07:45 +03:00
|
|
|
}
|
|
|
|
|
2014-06-05 05:35:31 +04:00
|
|
|
cmd.left = pdu.destRect.left;
|
|
|
|
cmd.top = pdu.destRect.top;
|
|
|
|
cmd.right = pdu.destRect.right;
|
|
|
|
cmd.bottom = pdu.destRect.bottom;
|
2014-06-13 05:02:25 +04:00
|
|
|
cmd.width = cmd.right - cmd.left;
|
|
|
|
cmd.height = cmd.bottom - cmd.top;
|
2014-06-05 05:35:31 +04:00
|
|
|
cmd.length = pdu.bitmapDataLength;
|
|
|
|
cmd.data = pdu.bitmapData;
|
2016-12-14 00:47:08 +03:00
|
|
|
cmd.extra = NULL;
|
2014-06-04 04:51:28 +04:00
|
|
|
|
2015-09-03 13:00:22 +03:00
|
|
|
if ((error = rdpgfx_decode(gfx, &cmd)))
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_decode failed with error %"PRIu32"!", error);
|
2014-06-04 23:18:02 +04:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
return error;
|
2014-06-04 03:48:47 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2016-08-04 17:28:38 +03:00
|
|
|
static UINT rdpgfx_recv_wire_to_surface_2_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
|
|
|
|
wStream* s)
|
2014-06-04 03:48:47 +04:00
|
|
|
{
|
2014-06-04 04:51:28 +04:00
|
|
|
RDPGFX_SURFACE_COMMAND cmd;
|
2014-06-04 03:48:47 +04:00
|
|
|
RDPGFX_WIRE_TO_SURFACE_PDU_2 pdu;
|
2014-06-04 04:51:28 +04:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
2014-06-04 23:18:02 +04:00
|
|
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error = CHANNEL_RC_OK;
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2016-08-16 09:49:56 +03:00
|
|
|
if (Stream_GetRemainingLength(s) < RDPGFX_WIRE_TO_SURFACE_PDU_2_SIZE)
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "not enough data!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
2014-07-01 19:33:35 +04:00
|
|
|
|
2014-06-04 03:48:47 +04:00
|
|
|
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
|
|
|
Stream_Read_UINT16(s, pdu.codecId); /* codecId (2 bytes) */
|
|
|
|
Stream_Read_UINT32(s, pdu.codecContextId); /* codecContextId (4 bytes) */
|
|
|
|
Stream_Read_UINT8(s, pdu.pixelFormat); /* pixelFormat (1 byte) */
|
|
|
|
Stream_Read_UINT32(s, pdu.bitmapDataLength); /* bitmapDataLength (4 bytes) */
|
|
|
|
pdu.bitmapData = Stream_Pointer(s);
|
2014-06-05 05:35:31 +04:00
|
|
|
Stream_Seek(s, pdu.bitmapDataLength);
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_DEBUG, "RecvWireToSurface2Pdu: surfaceId: %"PRIu16" codecId: %s (0x%04"PRIX16") "
|
2016-12-14 00:47:08 +03:00
|
|
|
"codecContextId: %"PRIu32" pixelFormat: 0x%02"PRIX8" bitmapDataLength: %"PRIu32"",
|
|
|
|
pdu.surfaceId, rdpgfx_get_codec_id_string(pdu.codecId), pdu.codecId,
|
2016-08-04 17:28:38 +03:00
|
|
|
pdu.codecContextId, pdu.pixelFormat, pdu.bitmapDataLength);
|
2014-06-04 04:51:28 +04:00
|
|
|
cmd.surfaceId = pdu.surfaceId;
|
|
|
|
cmd.codecId = pdu.codecId;
|
2014-06-05 05:35:31 +04:00
|
|
|
cmd.contextId = pdu.codecContextId;
|
|
|
|
cmd.format = pdu.pixelFormat;
|
|
|
|
cmd.left = 0;
|
|
|
|
cmd.top = 0;
|
|
|
|
cmd.right = 0;
|
|
|
|
cmd.bottom = 0;
|
|
|
|
cmd.width = 0;
|
|
|
|
cmd.height = 0;
|
|
|
|
cmd.length = pdu.bitmapDataLength;
|
|
|
|
cmd.data = pdu.bitmapData;
|
2016-12-14 00:47:08 +03:00
|
|
|
cmd.extra = NULL;
|
2014-06-04 04:51:28 +04:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (context)
|
2014-06-04 23:18:02 +04:00
|
|
|
{
|
2015-06-09 16:22:26 +03:00
|
|
|
IFCALLRET(context->SurfaceCommand, error, context, &cmd);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (error)
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "context->SurfaceCommand failed with error %"PRIu32"", error);
|
2014-06-04 23:18:02 +04:00
|
|
|
}
|
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
return error;
|
2014-06-04 03:48:47 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2016-08-04 17:28:38 +03:00
|
|
|
static UINT rdpgfx_recv_delete_encoding_context_pdu(RDPGFX_CHANNEL_CALLBACK*
|
|
|
|
callback, wStream* s)
|
2014-06-04 03:48:47 +04:00
|
|
|
{
|
|
|
|
RDPGFX_DELETE_ENCODING_CONTEXT_PDU pdu;
|
2014-06-04 23:18:02 +04:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
|
|
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error = CHANNEL_RC_OK;
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2014-07-01 19:33:35 +04:00
|
|
|
if (Stream_GetRemainingLength(s) < 6)
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "not enough data!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
2014-07-01 19:33:35 +04:00
|
|
|
|
2014-06-04 03:48:47 +04:00
|
|
|
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
|
|
|
Stream_Read_UINT32(s, pdu.codecContextId); /* codecContextId (4 bytes) */
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_DEBUG, "RecvDeleteEncodingContextPdu: surfaceId: %"PRIu16" codecContextId: %"PRIu32"",
|
2016-08-04 17:28:38 +03:00
|
|
|
pdu.surfaceId, pdu.codecContextId);
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (context)
|
2014-06-04 23:18:02 +04:00
|
|
|
{
|
2015-06-09 16:22:26 +03:00
|
|
|
IFCALLRET(context->DeleteEncodingContext, error, context, &pdu);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (error)
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "context->DeleteEncodingContext failed with error %"PRIu32"", error);
|
2014-06-04 23:18:02 +04:00
|
|
|
}
|
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
return error;
|
2014-06-04 03:48:47 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2016-10-17 10:05:54 +03:00
|
|
|
static UINT rdpgfx_recv_solid_fill_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s)
|
2014-06-04 03:48:47 +04:00
|
|
|
{
|
|
|
|
UINT16 index;
|
2016-03-02 16:39:36 +03:00
|
|
|
RECTANGLE_16* fillRect;
|
2014-06-04 03:48:47 +04:00
|
|
|
RDPGFX_SOLID_FILL_PDU pdu;
|
2014-06-04 23:18:02 +04:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
|
|
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2014-07-01 19:33:35 +04:00
|
|
|
if (Stream_GetRemainingLength(s) < 8)
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "not enough data!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2014-07-01 19:33:35 +04:00
|
|
|
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2017-12-23 12:26:25 +03:00
|
|
|
if ((error = rdpgfx_read_color32(s, &(pdu.fillPixel)))) /* fillPixel (4 bytes) */
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_read_color32 failed with error %"PRIu32"!", error);
|
2015-06-09 16:22:26 +03:00
|
|
|
return error;
|
|
|
|
}
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2014-06-04 03:48:47 +04:00
|
|
|
Stream_Read_UINT16(s, pdu.fillRectCount); /* fillRectCount (2 bytes) */
|
|
|
|
|
2016-08-04 17:28:38 +03:00
|
|
|
if (Stream_GetRemainingLength(s) < (size_t)(pdu.fillRectCount * 8))
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "not enough data!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
2014-07-01 19:33:35 +04:00
|
|
|
|
2016-03-02 16:39:36 +03:00
|
|
|
pdu.fillRects = (RECTANGLE_16*) calloc(pdu.fillRectCount, sizeof(RECTANGLE_16));
|
2014-06-04 03:48:47 +04:00
|
|
|
if (!pdu.fillRects)
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "calloc failed!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
2014-06-04 03:48:47 +04:00
|
|
|
|
|
|
|
for (index = 0; index < pdu.fillRectCount; index++)
|
|
|
|
{
|
|
|
|
fillRect = &(pdu.fillRects[index]);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if ((error = rdpgfx_read_rect16(s, fillRect)))
|
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_read_rect16 failed with error %"PRIu32"!", error);
|
2015-06-09 16:22:26 +03:00
|
|
|
free(pdu.fillRects);
|
|
|
|
return error;
|
|
|
|
}
|
2014-06-04 03:48:47 +04:00
|
|
|
}
|
|
|
|
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_DEBUG, "RecvSolidFillPdu: surfaceId: %"PRIu16" fillRectCount: %"PRIu16"",
|
2016-08-04 17:28:38 +03:00
|
|
|
pdu.surfaceId, pdu.fillRectCount);
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (context)
|
2014-06-04 23:18:02 +04:00
|
|
|
{
|
2015-06-09 16:22:26 +03:00
|
|
|
IFCALLRET(context->SolidFill, error, context, &pdu);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (error)
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "context->SolidFill failed with error %"PRIu32"", error);
|
2014-06-04 23:18:02 +04:00
|
|
|
}
|
2016-03-02 17:16:49 +03:00
|
|
|
|
2014-08-08 17:19:49 +04:00
|
|
|
free(pdu.fillRects);
|
2015-06-09 16:22:26 +03:00
|
|
|
return error;
|
2014-06-04 03:48:47 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2016-08-04 17:28:38 +03:00
|
|
|
static UINT rdpgfx_recv_surface_to_surface_pdu(RDPGFX_CHANNEL_CALLBACK*
|
|
|
|
callback, wStream* s)
|
2014-06-04 03:48:47 +04:00
|
|
|
{
|
|
|
|
UINT16 index;
|
|
|
|
RDPGFX_POINT16* destPt;
|
|
|
|
RDPGFX_SURFACE_TO_SURFACE_PDU pdu;
|
2014-06-04 23:18:02 +04:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
|
|
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2014-07-01 19:33:35 +04:00
|
|
|
if (Stream_GetRemainingLength(s) < 14)
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "not enough data!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
2014-07-01 19:33:35 +04:00
|
|
|
|
2014-06-04 03:48:47 +04:00
|
|
|
Stream_Read_UINT16(s, pdu.surfaceIdSrc); /* surfaceIdSrc (2 bytes) */
|
|
|
|
Stream_Read_UINT16(s, pdu.surfaceIdDest); /* surfaceIdDest (2 bytes) */
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if ((error = rdpgfx_read_rect16(s, &(pdu.rectSrc)))) /* rectSrc (8 bytes ) */
|
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_read_rect16 failed with error %"PRIu32"!", error);
|
2015-06-09 16:22:26 +03:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2014-06-04 03:48:47 +04:00
|
|
|
Stream_Read_UINT16(s, pdu.destPtsCount); /* destPtsCount (2 bytes) */
|
|
|
|
|
2016-08-04 17:28:38 +03:00
|
|
|
if (Stream_GetRemainingLength(s) < (size_t)(pdu.destPtsCount * 4))
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "not enough data!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
2014-07-01 19:33:35 +04:00
|
|
|
|
2017-12-23 12:26:25 +03:00
|
|
|
pdu.destPts = (RDPGFX_POINT16*) calloc(pdu.destPtsCount, sizeof(RDPGFX_POINT16));
|
2014-06-04 03:48:47 +04:00
|
|
|
if (!pdu.destPts)
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "calloc failed!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
2014-06-04 03:48:47 +04:00
|
|
|
|
|
|
|
for (index = 0; index < pdu.destPtsCount; index++)
|
|
|
|
{
|
|
|
|
destPt = &(pdu.destPts[index]);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if ((error = rdpgfx_read_point16(s, destPt)))
|
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_read_point16 failed with error %"PRIu32"!", error);
|
2015-06-09 16:22:26 +03:00
|
|
|
free(pdu.destPts);
|
|
|
|
return error;
|
|
|
|
}
|
2014-06-04 03:48:47 +04:00
|
|
|
}
|
|
|
|
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_DEBUG, "RecvSurfaceToSurfacePdu: surfaceIdSrc: %"PRIu16" surfaceIdDest: %"PRIu16" "
|
2016-12-14 00:47:08 +03:00
|
|
|
"left: %"PRIu16" top: %"PRIu16" right: %"PRIu16" bottom: %"PRIu16" destPtsCount: %"PRIu16"",
|
2016-08-04 17:28:38 +03:00
|
|
|
pdu.surfaceIdSrc, pdu.surfaceIdDest,
|
|
|
|
pdu.rectSrc.left, pdu.rectSrc.top, pdu.rectSrc.right, pdu.rectSrc.bottom,
|
|
|
|
pdu.destPtsCount);
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (context)
|
2014-06-04 23:18:02 +04:00
|
|
|
{
|
2015-06-09 16:22:26 +03:00
|
|
|
IFCALLRET(context->SurfaceToSurface, error, context, &pdu);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (error)
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "context->SurfaceToSurface failed with error %"PRIu32"", error);
|
2014-06-04 23:18:02 +04:00
|
|
|
}
|
|
|
|
|
2014-08-08 17:19:49 +04:00
|
|
|
free(pdu.destPts);
|
2015-06-09 16:22:26 +03:00
|
|
|
return error;
|
2014-06-04 03:48:47 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2016-08-04 17:28:38 +03:00
|
|
|
static UINT rdpgfx_recv_surface_to_cache_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
|
|
|
|
wStream* s)
|
2014-06-04 03:48:47 +04:00
|
|
|
{
|
|
|
|
RDPGFX_SURFACE_TO_CACHE_PDU pdu;
|
2014-06-04 23:18:02 +04:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
|
|
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2014-07-01 19:33:35 +04:00
|
|
|
if (Stream_GetRemainingLength(s) < 20)
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "not enough data!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
2014-07-01 19:33:35 +04:00
|
|
|
|
2014-06-04 03:48:47 +04:00
|
|
|
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
|
|
|
Stream_Read_UINT64(s, pdu.cacheKey); /* cacheKey (8 bytes) */
|
|
|
|
Stream_Read_UINT16(s, pdu.cacheSlot); /* cacheSlot (2 bytes) */
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if ((error = rdpgfx_read_rect16(s, &(pdu.rectSrc)))) /* rectSrc (8 bytes ) */
|
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_read_rect16 failed with error %"PRIu32"!", error);
|
2015-06-09 16:22:26 +03:00
|
|
|
return error;
|
|
|
|
}
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_DEBUG,
|
2016-12-14 00:47:08 +03:00
|
|
|
"RecvSurfaceToCachePdu: surfaceId: %"PRIu16" cacheKey: 0x%016"PRIX64" cacheSlot: %"PRIu16" "
|
|
|
|
"left: %"PRIu16" top: %"PRIu16" right: %"PRIu16" bottom: %"PRIu16"",
|
|
|
|
pdu.surfaceId, pdu.cacheKey, pdu.cacheSlot,
|
2016-08-04 17:28:38 +03:00
|
|
|
pdu.rectSrc.left, pdu.rectSrc.top,
|
|
|
|
pdu.rectSrc.right, pdu.rectSrc.bottom);
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (context)
|
2014-06-04 23:18:02 +04:00
|
|
|
{
|
2015-06-09 16:22:26 +03:00
|
|
|
IFCALLRET(context->SurfaceToCache, error, context, &pdu);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (error)
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "context->SurfaceToCache failed with error %"PRIu32"", error);
|
2014-06-04 23:18:02 +04:00
|
|
|
}
|
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
return error;
|
2014-06-04 03:48:47 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2016-10-17 10:05:54 +03:00
|
|
|
static UINT rdpgfx_recv_cache_to_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
|
|
|
|
wStream* s)
|
2014-06-04 03:48:47 +04:00
|
|
|
{
|
|
|
|
UINT16 index;
|
|
|
|
RDPGFX_POINT16* destPt;
|
|
|
|
RDPGFX_CACHE_TO_SURFACE_PDU pdu;
|
2014-06-04 23:18:02 +04:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
|
|
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error = CHANNEL_RC_OK;
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2014-07-01 19:33:35 +04:00
|
|
|
if (Stream_GetRemainingLength(s) < 6)
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "not enough data!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
2014-07-01 19:33:35 +04:00
|
|
|
|
2014-06-04 03:48:47 +04:00
|
|
|
Stream_Read_UINT16(s, pdu.cacheSlot); /* cacheSlot (2 bytes) */
|
|
|
|
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
|
|
|
Stream_Read_UINT16(s, pdu.destPtsCount); /* destPtsCount (2 bytes) */
|
|
|
|
|
2016-08-04 17:28:38 +03:00
|
|
|
if (Stream_GetRemainingLength(s) < (size_t)(pdu.destPtsCount * 4))
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "not enough data!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
2014-07-01 19:33:35 +04:00
|
|
|
|
2017-10-10 18:12:16 +03:00
|
|
|
pdu.destPts = (RDPGFX_POINT16*) calloc(pdu.destPtsCount, sizeof(RDPGFX_POINT16));
|
2014-06-04 03:48:47 +04:00
|
|
|
if (!pdu.destPts)
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "calloc failed!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
2014-06-04 03:48:47 +04:00
|
|
|
|
|
|
|
for (index = 0; index < pdu.destPtsCount; index++)
|
|
|
|
{
|
|
|
|
destPt = &(pdu.destPts[index]);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if ((error = rdpgfx_read_point16(s, destPt)))
|
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_read_point16 failed with error %"PRIu32"", error);
|
2015-06-09 16:22:26 +03:00
|
|
|
free(pdu.destPts);
|
|
|
|
return error;
|
|
|
|
}
|
2014-06-04 03:48:47 +04:00
|
|
|
}
|
|
|
|
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_DEBUG,
|
2016-12-14 00:47:08 +03:00
|
|
|
"RdpGfxRecvCacheToSurfacePdu: cacheSlot: %"PRIu16" surfaceId: %"PRIu16" destPtsCount: %"PRIu16"",
|
|
|
|
pdu.cacheSlot, pdu.surfaceId, pdu.destPtsCount);
|
2014-06-04 23:18:02 +04:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (context)
|
2014-06-04 23:18:02 +04:00
|
|
|
{
|
2015-06-09 16:22:26 +03:00
|
|
|
IFCALLRET(context->CacheToSurface, error, context, &pdu);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (error)
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "context->CacheToSurface failed with error %"PRIu32"", error);
|
2014-06-04 23:18:02 +04:00
|
|
|
}
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2014-06-20 21:52:13 +04:00
|
|
|
free(pdu.destPts);
|
2015-06-09 16:22:26 +03:00
|
|
|
return error;
|
2014-06-04 03:48:47 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2016-08-04 17:28:38 +03:00
|
|
|
static UINT rdpgfx_recv_map_surface_to_output_pdu(RDPGFX_CHANNEL_CALLBACK*
|
|
|
|
callback, wStream* s)
|
2014-06-04 03:48:47 +04:00
|
|
|
{
|
|
|
|
RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU pdu;
|
2014-06-04 23:18:02 +04:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
|
|
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error = CHANNEL_RC_OK;
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2014-07-01 19:33:35 +04:00
|
|
|
if (Stream_GetRemainingLength(s) < 12)
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "not enough data!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
2014-07-01 19:33:35 +04:00
|
|
|
|
2014-06-04 03:48:47 +04:00
|
|
|
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
|
|
|
Stream_Read_UINT16(s, pdu.reserved); /* reserved (2 bytes) */
|
|
|
|
Stream_Read_UINT32(s, pdu.outputOriginX); /* outputOriginX (4 bytes) */
|
|
|
|
Stream_Read_UINT32(s, pdu.outputOriginY); /* outputOriginY (4 bytes) */
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_DEBUG,
|
2016-12-14 00:47:08 +03:00
|
|
|
"RecvMapSurfaceToOutputPdu: surfaceId: %"PRIu16" outputOriginX: %"PRIu32" outputOriginY: %"PRIu32"",
|
|
|
|
pdu.surfaceId, pdu.outputOriginX, pdu.outputOriginY);
|
2014-06-04 23:18:02 +04:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (context)
|
2014-06-04 23:18:02 +04:00
|
|
|
{
|
2015-06-09 16:22:26 +03:00
|
|
|
IFCALLRET(context->MapSurfaceToOutput, error, context, &pdu);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (error)
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "context->MapSurfaceToOutput failed with error %"PRIu32"", error);
|
2014-06-04 23:18:02 +04:00
|
|
|
}
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
return error;
|
2014-06-04 03:48:47 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2016-10-17 10:05:54 +03:00
|
|
|
static UINT rdpgfx_recv_map_surface_to_window_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
|
2016-08-04 17:28:38 +03:00
|
|
|
wStream* s)
|
2014-06-04 03:48:47 +04:00
|
|
|
{
|
|
|
|
RDPGFX_MAP_SURFACE_TO_WINDOW_PDU pdu;
|
2014-06-04 23:18:02 +04:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
|
|
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error = CHANNEL_RC_OK;
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2014-07-01 19:33:35 +04:00
|
|
|
if (Stream_GetRemainingLength(s) < 18)
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "not enough data!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
2014-07-01 19:33:35 +04:00
|
|
|
|
2014-06-04 03:48:47 +04:00
|
|
|
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
|
|
|
Stream_Read_UINT64(s, pdu.windowId); /* windowId (8 bytes) */
|
|
|
|
Stream_Read_UINT32(s, pdu.mappedWidth); /* mappedWidth (4 bytes) */
|
|
|
|
Stream_Read_UINT32(s, pdu.mappedHeight); /* mappedHeight (4 bytes) */
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_DEBUG,
|
2016-12-14 00:47:08 +03:00
|
|
|
"RecvMapSurfaceToWindowPdu: surfaceId: %"PRIu16" windowId: 0x%016"PRIX64" mappedWidth: %"PRIu32" mappedHeight: %"PRIu32"",
|
|
|
|
pdu.surfaceId, pdu.windowId, pdu.mappedWidth, pdu.mappedHeight);
|
2014-06-04 23:18:02 +04:00
|
|
|
|
|
|
|
if (context && context->MapSurfaceToWindow)
|
|
|
|
{
|
2015-06-09 16:22:26 +03:00
|
|
|
IFCALLRET(context->MapSurfaceToWindow, error, context, &pdu);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (error)
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "context->MapSurfaceToWindow failed with error %"PRIu32"", error);
|
2014-06-04 23:18:02 +04:00
|
|
|
}
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
return error;
|
2014-06-03 23:32:03 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2015-09-03 13:00:22 +03:00
|
|
|
static UINT rdpgfx_recv_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s)
|
2013-10-22 06:53:55 +04:00
|
|
|
{
|
2017-12-11 12:25:21 +03:00
|
|
|
size_t beg, end;
|
2014-06-03 21:38:10 +04:00
|
|
|
RDPGFX_HEADER header;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2017-05-15 18:24:47 +03:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
|
|
|
|
2014-06-05 05:35:31 +04:00
|
|
|
beg = Stream_GetPosition(s);
|
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if ((error = rdpgfx_read_header(s, &header)))
|
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_read_header failed with error %"PRIu32"!", error);
|
2015-06-09 16:22:26 +03:00
|
|
|
return error;
|
|
|
|
}
|
2014-06-03 21:38:10 +04:00
|
|
|
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_DEBUG, "cmdId: %s (0x%04"PRIX16") flags: 0x%04"PRIX16" pduLength: %"PRIu32"",
|
2016-08-04 17:28:38 +03:00
|
|
|
rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId, header.flags,
|
|
|
|
header.pduLength);
|
2014-06-03 23:32:03 +04:00
|
|
|
|
|
|
|
switch (header.cmdId)
|
|
|
|
{
|
|
|
|
case RDPGFX_CMDID_WIRETOSURFACE_1:
|
2015-06-09 16:22:26 +03:00
|
|
|
if ((error = rdpgfx_recv_wire_to_surface_1_pdu(callback, s)))
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_wire_to_surface_1_pdu failed with error %"PRIu32"!",
|
2016-08-04 17:28:38 +03:00
|
|
|
error);
|
|
|
|
|
2014-06-03 23:32:03 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RDPGFX_CMDID_WIRETOSURFACE_2:
|
2015-06-09 16:22:26 +03:00
|
|
|
if ((error = rdpgfx_recv_wire_to_surface_2_pdu(callback, s)))
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_wire_to_surface_2_pdu failed with error %"PRIu32"!",
|
2016-08-04 17:28:38 +03:00
|
|
|
error);
|
|
|
|
|
2014-06-03 23:32:03 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RDPGFX_CMDID_DELETEENCODINGCONTEXT:
|
2015-06-09 16:22:26 +03:00
|
|
|
if ((error = rdpgfx_recv_delete_encoding_context_pdu(callback, s)))
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_delete_encoding_context_pdu failed with error %"PRIu32"!",
|
2016-08-04 17:28:38 +03:00
|
|
|
error);
|
|
|
|
|
2014-06-03 23:32:03 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RDPGFX_CMDID_SOLIDFILL:
|
2015-06-09 16:22:26 +03:00
|
|
|
if ((error = rdpgfx_recv_solid_fill_pdu(callback, s)))
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_solid_fill_pdu failed with error %"PRIu32"!", error);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2014-06-03 23:32:03 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RDPGFX_CMDID_SURFACETOSURFACE:
|
2015-06-09 16:22:26 +03:00
|
|
|
if ((error = rdpgfx_recv_surface_to_surface_pdu(callback, s)))
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_surface_to_surface_pdu failed with error %"PRIu32"!",
|
2016-08-04 17:28:38 +03:00
|
|
|
error);
|
|
|
|
|
2014-06-03 23:32:03 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RDPGFX_CMDID_SURFACETOCACHE:
|
2015-06-09 16:22:26 +03:00
|
|
|
if ((error = rdpgfx_recv_surface_to_cache_pdu(callback, s)))
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_surface_to_cache_pdu failed with error %"PRIu32"!", error);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2014-06-03 23:32:03 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RDPGFX_CMDID_CACHETOSURFACE:
|
2015-06-09 16:22:26 +03:00
|
|
|
if ((error = rdpgfx_recv_cache_to_surface_pdu(callback, s)))
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_cache_to_surface_pdu failed with error %"PRIu32"!", error);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2014-06-03 23:32:03 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RDPGFX_CMDID_EVICTCACHEENTRY:
|
2015-06-09 16:22:26 +03:00
|
|
|
if ((error = rdpgfx_recv_evict_cache_entry_pdu(callback, s)))
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_evict_cache_entry_pdu failed with error %"PRIu32"!",
|
2016-08-04 17:28:38 +03:00
|
|
|
error);
|
|
|
|
|
2014-06-03 23:32:03 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RDPGFX_CMDID_CREATESURFACE:
|
2015-06-09 16:22:26 +03:00
|
|
|
if ((error = rdpgfx_recv_create_surface_pdu(callback, s)))
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_create_surface_pdu failed with error %"PRIu32"!", error);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2014-06-03 23:32:03 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RDPGFX_CMDID_DELETESURFACE:
|
2015-06-09 16:22:26 +03:00
|
|
|
if ((error = rdpgfx_recv_delete_surface_pdu(callback, s)))
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_delete_surface_pdu failed with error %"PRIu32"!", error);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2014-06-03 23:32:03 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RDPGFX_CMDID_STARTFRAME:
|
2015-06-09 16:22:26 +03:00
|
|
|
if ((error = rdpgfx_recv_start_frame_pdu(callback, s)))
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_start_frame_pdu failed with error %"PRIu32"!", error);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2014-06-03 23:32:03 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RDPGFX_CMDID_ENDFRAME:
|
2015-06-09 16:22:26 +03:00
|
|
|
if ((error = rdpgfx_recv_end_frame_pdu(callback, s)))
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_end_frame_pdu failed with error %"PRIu32"!", error);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2014-06-03 23:32:03 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RDPGFX_CMDID_RESETGRAPHICS:
|
2015-06-09 16:22:26 +03:00
|
|
|
if ((error = rdpgfx_recv_reset_graphics_pdu(callback, s)))
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_reset_graphics_pdu failed with error %"PRIu32"!", error);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2014-06-03 23:32:03 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RDPGFX_CMDID_MAPSURFACETOOUTPUT:
|
2015-06-09 16:22:26 +03:00
|
|
|
if ((error = rdpgfx_recv_map_surface_to_output_pdu(callback, s)))
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_map_surface_to_output_pdu failed with error %"PRIu32"!",
|
2016-08-04 17:28:38 +03:00
|
|
|
error);
|
|
|
|
|
2014-06-03 23:32:03 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RDPGFX_CMDID_CACHEIMPORTREPLY:
|
2015-06-09 16:22:26 +03:00
|
|
|
if ((error = rdpgfx_recv_cache_import_reply_pdu(callback, s)))
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_cache_import_reply_pdu failed with error %"PRIu32"!",
|
2016-08-04 17:28:38 +03:00
|
|
|
error);
|
|
|
|
|
2014-06-03 23:32:03 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RDPGFX_CMDID_CAPSCONFIRM:
|
2015-06-09 16:22:26 +03:00
|
|
|
if ((error = rdpgfx_recv_caps_confirm_pdu(callback, s)))
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_caps_confirm_pdu failed with error %"PRIu32"!", error);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2014-06-03 23:32:03 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RDPGFX_CMDID_MAPSURFACETOWINDOW:
|
2015-06-09 16:22:26 +03:00
|
|
|
if ((error = rdpgfx_recv_map_surface_to_window_pdu(callback, s)))
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_map_surface_to_window_pdu failed with error %"PRIu32"!",
|
2016-08-04 17:28:38 +03:00
|
|
|
error);
|
|
|
|
|
2014-06-03 23:32:03 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2015-06-09 16:22:26 +03:00
|
|
|
error = CHANNEL_RC_BAD_PROC;
|
2014-06-03 23:32:03 +04:00
|
|
|
break;
|
|
|
|
}
|
2014-06-03 21:38:10 +04:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (error)
|
2014-07-01 19:33:35 +04:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "Error while parsing GFX cmdId: %s (0x%04"PRIX16")",
|
2016-08-04 17:28:38 +03:00
|
|
|
rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId);
|
2015-06-09 16:22:26 +03:00
|
|
|
return error;
|
2014-07-01 19:33:35 +04:00
|
|
|
}
|
|
|
|
|
2014-06-05 05:35:31 +04:00
|
|
|
end = Stream_GetPosition(s);
|
|
|
|
|
|
|
|
if (end != (beg + header.pduLength))
|
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "Unexpected gfx pdu end: Actual: %d, Expected: %"PRIu32"",
|
2016-08-04 17:28:38 +03:00
|
|
|
end, (beg + header.pduLength));
|
2014-06-05 05:35:31 +04:00
|
|
|
Stream_SetPosition(s, (beg + header.pduLength));
|
|
|
|
}
|
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
return error;
|
2013-10-22 06:53:55 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2016-08-04 17:28:38 +03:00
|
|
|
static UINT rdpgfx_on_data_received(IWTSVirtualChannelCallback*
|
|
|
|
pChannelCallback, wStream* data)
|
2013-10-22 06:53:55 +04:00
|
|
|
{
|
|
|
|
wStream* s;
|
|
|
|
int status = 0;
|
2014-06-03 22:29:55 +04:00
|
|
|
UINT32 DstSize = 0;
|
|
|
|
BYTE* pDstData = NULL;
|
2013-10-22 06:53:55 +04:00
|
|
|
RDPGFX_CHANNEL_CALLBACK* callback = (RDPGFX_CHANNEL_CALLBACK*) pChannelCallback;
|
2014-06-05 06:06:29 +04:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error = CHANNEL_RC_OK;
|
2017-12-23 12:26:25 +03:00
|
|
|
status = zgfx_decompress(gfx->zgfx, Stream_Pointer(data), Stream_GetRemainingLength(data),
|
|
|
|
&pDstData, &DstSize, 0);
|
2014-06-03 22:29:55 +04:00
|
|
|
|
|
|
|
if (status < 0)
|
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "zgfx_decompress failure! status: %d", status);
|
2015-06-09 16:22:26 +03:00
|
|
|
return ERROR_INTERNAL_ERROR;
|
2014-06-03 22:29:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
s = Stream_New(pDstData, DstSize);
|
2015-06-09 16:22:26 +03:00
|
|
|
if (!s)
|
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "calloc failed!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
2013-10-22 06:53:55 +04:00
|
|
|
|
2016-12-14 00:47:08 +03:00
|
|
|
while (Stream_GetPosition(s) < Stream_Length(s))
|
2014-06-05 05:35:31 +04:00
|
|
|
{
|
2015-06-09 16:22:26 +03:00
|
|
|
if ((error = rdpgfx_recv_pdu(callback, s)))
|
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_pdu failed with error %"PRIu32"!", error);
|
2014-07-01 19:33:35 +04:00
|
|
|
break;
|
2015-06-09 16:22:26 +03:00
|
|
|
}
|
2014-06-05 05:35:31 +04:00
|
|
|
}
|
2013-10-22 06:53:55 +04:00
|
|
|
|
2014-06-03 22:29:55 +04:00
|
|
|
Stream_Free(s, TRUE);
|
2015-06-09 16:22:26 +03:00
|
|
|
return error;
|
2013-10-22 06:53:55 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
|
|
|
static UINT rdpgfx_on_open(IWTSVirtualChannelCallback* pChannelCallback)
|
2014-06-03 17:49:00 +04:00
|
|
|
{
|
|
|
|
RDPGFX_CHANNEL_CALLBACK* callback = (RDPGFX_CHANNEL_CALLBACK*) pChannelCallback;
|
2015-06-26 20:59:41 +03:00
|
|
|
WLog_DBG(TAG, "OnOpen");
|
2015-06-09 16:22:26 +03:00
|
|
|
return rdpgfx_send_caps_advertise_pdu(callback);
|
2014-06-03 17:49:00 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
|
|
|
static UINT rdpgfx_on_close(IWTSVirtualChannelCallback* pChannelCallback)
|
2013-10-22 06:53:55 +04:00
|
|
|
{
|
2015-07-08 18:17:56 +03:00
|
|
|
int count;
|
|
|
|
int index;
|
|
|
|
ULONG_PTR* pKeys = NULL;
|
2013-10-22 06:53:55 +04:00
|
|
|
RDPGFX_CHANNEL_CALLBACK* callback = (RDPGFX_CHANNEL_CALLBACK*) pChannelCallback;
|
2014-06-05 06:06:29 +04:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
2015-07-08 18:17:56 +03:00
|
|
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
2017-12-23 12:26:25 +03:00
|
|
|
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_DEBUG, "OnClose");
|
2013-10-22 06:53:55 +04:00
|
|
|
free(callback);
|
2015-07-08 18:17:56 +03:00
|
|
|
gfx->UnacknowledgedFrames = 0;
|
|
|
|
gfx->TotalDecodedFrames = 0;
|
|
|
|
|
|
|
|
if (gfx->zgfx)
|
|
|
|
{
|
|
|
|
zgfx_context_free(gfx->zgfx);
|
|
|
|
gfx->zgfx = zgfx_context_new(FALSE);
|
|
|
|
|
|
|
|
if (!gfx->zgfx)
|
2015-08-25 10:07:04 +03:00
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
2015-07-08 18:17:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
count = HashTable_GetKeys(gfx->SurfaceTable, &pKeys);
|
|
|
|
|
|
|
|
for (index = 0; index < count; index++)
|
|
|
|
{
|
|
|
|
RDPGFX_DELETE_SURFACE_PDU pdu;
|
|
|
|
pdu.surfaceId = ((UINT16) pKeys[index]) - 1;
|
|
|
|
|
|
|
|
if (context && context->DeleteSurface)
|
|
|
|
{
|
|
|
|
context->DeleteSurface(context, &pdu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(pKeys);
|
|
|
|
|
|
|
|
for (index = 0; index < gfx->MaxCacheSlot; index++)
|
|
|
|
{
|
|
|
|
if (gfx->CacheSlots[index])
|
|
|
|
{
|
|
|
|
RDPGFX_EVICT_CACHE_ENTRY_PDU pdu;
|
|
|
|
pdu.cacheSlot = (UINT16) index;
|
|
|
|
|
|
|
|
if (context && context->EvictCacheEntry)
|
|
|
|
{
|
|
|
|
context->EvictCacheEntry(context, &pdu);
|
|
|
|
}
|
|
|
|
|
|
|
|
gfx->CacheSlots[index] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
return CHANNEL_RC_OK;
|
2013-10-22 06:53:55 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2016-08-04 17:28:38 +03:00
|
|
|
static UINT rdpgfx_on_new_channel_connection(IWTSListenerCallback*
|
|
|
|
pListenerCallback,
|
|
|
|
IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept,
|
|
|
|
IWTSVirtualChannelCallback** ppCallback)
|
2013-10-22 06:53:55 +04:00
|
|
|
{
|
|
|
|
RDPGFX_CHANNEL_CALLBACK* callback;
|
2017-12-23 12:26:25 +03:00
|
|
|
RDPGFX_LISTENER_CALLBACK* listener_callback = (RDPGFX_LISTENER_CALLBACK*)pListenerCallback;
|
2013-10-22 06:53:55 +04:00
|
|
|
|
2017-12-23 12:26:25 +03:00
|
|
|
callback = (RDPGFX_CHANNEL_CALLBACK*) calloc(1, sizeof(RDPGFX_CHANNEL_CALLBACK));
|
2014-06-05 06:06:29 +04:00
|
|
|
if (!callback)
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "calloc failed!");
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
2014-06-05 06:06:29 +04:00
|
|
|
|
2013-10-22 06:53:55 +04:00
|
|
|
callback->iface.OnDataReceived = rdpgfx_on_data_received;
|
2014-06-03 17:49:00 +04:00
|
|
|
callback->iface.OnOpen = rdpgfx_on_open;
|
2013-10-22 06:53:55 +04:00
|
|
|
callback->iface.OnClose = rdpgfx_on_close;
|
|
|
|
callback->plugin = listener_callback->plugin;
|
|
|
|
callback->channel_mgr = listener_callback->channel_mgr;
|
|
|
|
callback->channel = pChannel;
|
|
|
|
listener_callback->channel_callback = callback;
|
|
|
|
*ppCallback = (IWTSVirtualChannelCallback*) callback;
|
2015-06-09 16:22:26 +03:00
|
|
|
return CHANNEL_RC_OK;
|
2013-10-22 06:53:55 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2016-08-04 17:28:38 +03:00
|
|
|
static UINT rdpgfx_plugin_initialize(IWTSPlugin* pPlugin,
|
|
|
|
IWTSVirtualChannelManager* pChannelMgr)
|
2013-10-22 06:53:55 +04:00
|
|
|
{
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2014-06-05 06:06:29 +04:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) pPlugin;
|
2014-06-03 08:05:43 +04:00
|
|
|
|
2017-12-23 12:26:25 +03:00
|
|
|
gfx->listener_callback = (RDPGFX_LISTENER_CALLBACK*) calloc(1, sizeof(RDPGFX_LISTENER_CALLBACK));
|
2014-06-05 06:06:29 +04:00
|
|
|
if (!gfx->listener_callback)
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "calloc failed!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
2013-10-22 06:53:55 +04:00
|
|
|
|
2017-12-23 12:26:25 +03:00
|
|
|
gfx->listener_callback->iface.OnNewChannelConnection = rdpgfx_on_new_channel_connection;
|
2014-06-05 06:06:29 +04:00
|
|
|
gfx->listener_callback->plugin = pPlugin;
|
|
|
|
gfx->listener_callback->channel_mgr = pChannelMgr;
|
2015-06-09 16:22:26 +03:00
|
|
|
error = pChannelMgr->CreateListener(pChannelMgr, RDPGFX_DVC_CHANNEL_NAME, 0,
|
2016-08-04 17:28:38 +03:00
|
|
|
(IWTSListenerCallback*) gfx->listener_callback, &(gfx->listener));
|
2014-06-05 06:06:29 +04:00
|
|
|
gfx->listener->pInterface = gfx->iface.pInterface;
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_DEBUG, "Initialize");
|
2015-06-09 16:22:26 +03:00
|
|
|
return error;
|
2013-10-22 06:53:55 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
|
|
|
static UINT rdpgfx_plugin_terminated(IWTSPlugin* pPlugin)
|
2013-10-22 06:53:55 +04:00
|
|
|
{
|
2014-06-20 21:52:13 +04:00
|
|
|
int count;
|
|
|
|
int index;
|
|
|
|
ULONG_PTR* pKeys = NULL;
|
2014-06-05 06:06:29 +04:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) pPlugin;
|
2014-06-20 21:52:13 +04:00
|
|
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error = CHANNEL_RC_OK;
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_DEBUG, "Terminated");
|
2014-06-03 22:29:55 +04:00
|
|
|
|
2014-06-05 06:06:29 +04:00
|
|
|
if (gfx->listener_callback)
|
2015-02-06 01:01:56 +03:00
|
|
|
{
|
2014-06-05 06:06:29 +04:00
|
|
|
free(gfx->listener_callback);
|
2015-02-06 01:01:56 +03:00
|
|
|
gfx->listener_callback = NULL;
|
|
|
|
}
|
2013-10-22 06:53:55 +04:00
|
|
|
|
2015-02-06 01:01:56 +03:00
|
|
|
if (gfx->zgfx)
|
|
|
|
{
|
|
|
|
zgfx_context_free(gfx->zgfx);
|
|
|
|
gfx->zgfx = NULL;
|
|
|
|
}
|
2013-10-22 06:53:55 +04:00
|
|
|
|
2014-06-20 21:52:13 +04:00
|
|
|
count = HashTable_GetKeys(gfx->SurfaceTable, &pKeys);
|
|
|
|
|
|
|
|
for (index = 0; index < count; index++)
|
|
|
|
{
|
|
|
|
RDPGFX_DELETE_SURFACE_PDU pdu;
|
|
|
|
pdu.surfaceId = ((UINT16) pKeys[index]) - 1;
|
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (context)
|
2014-06-20 21:52:13 +04:00
|
|
|
{
|
2015-06-09 16:22:26 +03:00
|
|
|
IFCALLRET(context->DeleteSurface, error, context, &pdu);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (error)
|
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "context->DeleteSurface failed with error %"PRIu32"", error);
|
2015-06-09 16:22:26 +03:00
|
|
|
free(pKeys);
|
|
|
|
free(context);
|
|
|
|
free(gfx);
|
|
|
|
return error;
|
|
|
|
}
|
2014-06-20 21:52:13 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(pKeys);
|
2014-06-12 01:48:04 +04:00
|
|
|
HashTable_Free(gfx->SurfaceTable);
|
|
|
|
|
2014-06-20 21:52:13 +04:00
|
|
|
for (index = 0; index < gfx->MaxCacheSlot; index++)
|
|
|
|
{
|
|
|
|
if (gfx->CacheSlots[index])
|
|
|
|
{
|
|
|
|
RDPGFX_EVICT_CACHE_ENTRY_PDU pdu;
|
|
|
|
pdu.cacheSlot = (UINT16) index;
|
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (context)
|
2014-06-20 21:52:13 +04:00
|
|
|
{
|
2015-06-09 16:22:26 +03:00
|
|
|
IFCALLRET(context->EvictCacheEntry, error, context, &pdu);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (error)
|
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "context->EvictCacheEntry failed with error %"PRIu32"", error);
|
2015-06-09 16:22:26 +03:00
|
|
|
free(context);
|
|
|
|
free(gfx);
|
|
|
|
return error;
|
|
|
|
}
|
2014-06-20 21:52:13 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
gfx->CacheSlots[index] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-27 23:20:29 +03:00
|
|
|
free(context);
|
2014-06-05 06:06:29 +04:00
|
|
|
free(gfx);
|
2015-06-09 16:22:26 +03:00
|
|
|
return CHANNEL_RC_OK;
|
2013-10-22 06:53:55 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2016-08-04 17:28:38 +03:00
|
|
|
static UINT rdpgfx_set_surface_data(RdpgfxClientContext* context,
|
|
|
|
UINT16 surfaceId, void* pData)
|
2014-06-12 01:48:04 +04:00
|
|
|
{
|
|
|
|
ULONG_PTR key;
|
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) context->handle;
|
|
|
|
key = ((ULONG_PTR) surfaceId) + 1;
|
|
|
|
|
|
|
|
if (pData)
|
|
|
|
HashTable_Add(gfx->SurfaceTable, (void*) key, pData);
|
|
|
|
else
|
|
|
|
HashTable_Remove(gfx->SurfaceTable, (void*) key);
|
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
return CHANNEL_RC_OK;
|
2014-06-12 01:48:04 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2016-08-04 17:28:38 +03:00
|
|
|
static UINT rdpgfx_get_surface_ids(RdpgfxClientContext* context,
|
|
|
|
UINT16** ppSurfaceIds, UINT16* count_out)
|
2015-02-11 00:32:07 +03:00
|
|
|
{
|
|
|
|
int count;
|
|
|
|
int index;
|
|
|
|
UINT16* pSurfaceIds;
|
|
|
|
ULONG_PTR* pKeys = NULL;
|
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) context->handle;
|
|
|
|
count = HashTable_GetKeys(gfx->SurfaceTable, &pKeys);
|
|
|
|
|
|
|
|
if (count < 1)
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
|
|
|
*count_out = 0;
|
|
|
|
return CHANNEL_RC_OK;
|
|
|
|
}
|
2015-02-11 00:32:07 +03:00
|
|
|
|
2017-05-30 11:46:43 +03:00
|
|
|
pSurfaceIds = (UINT16*) calloc(count, sizeof(UINT16));
|
2015-02-11 00:32:07 +03:00
|
|
|
|
|
|
|
if (!pSurfaceIds)
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2017-05-15 18:24:47 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "calloc failed!");
|
2018-02-09 12:23:48 +03:00
|
|
|
free(pKeys);
|
2015-06-09 16:22:26 +03:00
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
2015-02-11 00:32:07 +03:00
|
|
|
|
|
|
|
for (index = 0; index < count; index++)
|
|
|
|
{
|
|
|
|
pSurfaceIds[index] = pKeys[index] - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(pKeys);
|
|
|
|
*ppSurfaceIds = pSurfaceIds;
|
2015-06-09 16:22:26 +03:00
|
|
|
*count_out = (UINT16)count;
|
|
|
|
return CHANNEL_RC_OK;
|
2015-02-11 00:32:07 +03:00
|
|
|
}
|
|
|
|
|
2016-08-04 17:28:38 +03:00
|
|
|
static void* rdpgfx_get_surface_data(RdpgfxClientContext* context,
|
|
|
|
UINT16 surfaceId)
|
2014-06-12 01:48:04 +04:00
|
|
|
{
|
|
|
|
ULONG_PTR key;
|
|
|
|
void* pData = NULL;
|
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) context->handle;
|
|
|
|
key = ((ULONG_PTR) surfaceId) + 1;
|
|
|
|
pData = HashTable_GetItemValue(gfx->SurfaceTable, (void*) key);
|
|
|
|
return pData;
|
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2016-08-04 17:28:38 +03:00
|
|
|
static UINT rdpgfx_set_cache_slot_data(RdpgfxClientContext* context,
|
|
|
|
UINT16 cacheSlot, void* pData)
|
2014-06-13 16:36:09 +04:00
|
|
|
{
|
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) context->handle;
|
|
|
|
|
|
|
|
if (cacheSlot >= gfx->MaxCacheSlot)
|
2017-10-10 18:12:16 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "%s: invalid cache slot %"PRIu16" maxAllowed=%"PRIu16"", __FUNCTION__,
|
|
|
|
cacheSlot, gfx->MaxCacheSlot);
|
2015-06-09 16:22:26 +03:00
|
|
|
return ERROR_INVALID_INDEX;
|
2017-10-10 18:12:16 +03:00
|
|
|
}
|
2014-06-13 16:36:09 +04:00
|
|
|
|
|
|
|
gfx->CacheSlots[cacheSlot] = pData;
|
2015-06-09 16:22:26 +03:00
|
|
|
return CHANNEL_RC_OK;
|
2014-06-13 16:36:09 +04:00
|
|
|
}
|
|
|
|
|
2016-10-17 10:05:54 +03:00
|
|
|
static void* rdpgfx_get_cache_slot_data(RdpgfxClientContext* context, UINT16 cacheSlot)
|
2014-06-13 16:36:09 +04:00
|
|
|
{
|
|
|
|
void* pData = NULL;
|
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) context->handle;
|
|
|
|
|
|
|
|
if (cacheSlot >= gfx->MaxCacheSlot)
|
2017-10-10 18:12:16 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "%s: invalid cache slot %"PRIu16" maxAllowed=%"PRIu16"", __FUNCTION__,
|
|
|
|
cacheSlot, gfx->MaxCacheSlot);
|
2014-06-13 16:36:09 +04:00
|
|
|
return NULL;
|
2017-10-10 18:12:16 +03:00
|
|
|
}
|
2014-06-13 16:36:09 +04:00
|
|
|
|
|
|
|
pData = gfx->CacheSlots[cacheSlot];
|
|
|
|
return pData;
|
|
|
|
}
|
|
|
|
|
2016-06-15 14:36:27 +03:00
|
|
|
#ifdef BUILTIN_CHANNELS
|
2014-10-27 18:33:51 +03:00
|
|
|
#define DVCPluginEntry rdpgfx_DVCPluginEntry
|
2016-02-29 17:18:19 +03:00
|
|
|
#else
|
|
|
|
#define DVCPluginEntry FREERDP_API DVCPluginEntry
|
2014-10-27 18:33:51 +03:00
|
|
|
#endif
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
|
|
|
UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
2013-10-22 06:53:55 +04:00
|
|
|
{
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error = CHANNEL_RC_OK;
|
2014-06-05 06:06:29 +04:00
|
|
|
RDPGFX_PLUGIN* gfx;
|
2013-10-22 06:53:55 +04:00
|
|
|
RdpgfxClientContext* context;
|
2014-06-05 06:06:29 +04:00
|
|
|
gfx = (RDPGFX_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "rdpgfx");
|
2013-10-22 06:53:55 +04:00
|
|
|
|
2014-06-05 06:06:29 +04:00
|
|
|
if (!gfx)
|
2013-10-22 06:53:55 +04:00
|
|
|
{
|
2014-06-05 06:06:29 +04:00
|
|
|
gfx = (RDPGFX_PLUGIN*) calloc(1, sizeof(RDPGFX_PLUGIN));
|
2014-06-03 08:05:43 +04:00
|
|
|
|
2014-06-05 06:06:29 +04:00
|
|
|
if (!gfx)
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "calloc failed!");
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
2013-10-22 06:53:55 +04:00
|
|
|
|
2017-05-15 18:24:47 +03:00
|
|
|
gfx->log = WLog_Get(TAG);
|
|
|
|
if (!gfx->log)
|
|
|
|
{
|
|
|
|
free(gfx);
|
2017-08-03 09:38:05 +03:00
|
|
|
WLog_ERR(TAG, "Failed to acquire reference to WLog %s", TAG);
|
2017-05-15 18:24:47 +03:00
|
|
|
return ERROR_INTERNAL_ERROR;
|
|
|
|
}
|
|
|
|
|
2014-07-03 22:35:03 +04:00
|
|
|
gfx->settings = (rdpSettings*) pEntryPoints->GetRdpSettings(pEntryPoints);
|
2014-06-05 06:06:29 +04:00
|
|
|
gfx->iface.Initialize = rdpgfx_plugin_initialize;
|
|
|
|
gfx->iface.Connected = NULL;
|
|
|
|
gfx->iface.Disconnected = NULL;
|
|
|
|
gfx->iface.Terminated = rdpgfx_plugin_terminated;
|
Fix for #4330
Since ec027bf dynamic resolution is broken when used with egfx. Before that commit
we were tracking a server sent resize by setting a DesktopResize callback. This callback
is called when the desktop is resized by the server. Anyway the problem was that when this
callback is called, the activation sequence is not always completed, which were leading to
some freeze with 2012r2 servers (sending packets before the sequence is finished).
So with the faulty commit, we are tracking server resizes by subscribing to the Actived
event, that is called at the end of a reactivation sequence, so we're sure to not send packets
when not fully activated.
Anyway the issue that shows on (#4330) is that when you use egfx, no reactivation sequence happens,
the server only sends a ResetGraphics message with the new size, and so we miss the resized event.
This fix introduces a new GraphicsReset event, makes the display channel subscribe to that event,
and react accordingly.
2017-12-23 15:50:54 +03:00
|
|
|
gfx->rdpcontext = ((freerdp *)gfx->settings->instance)->context;
|
2015-06-26 20:59:41 +03:00
|
|
|
|
Fix for #4330
Since ec027bf dynamic resolution is broken when used with egfx. Before that commit
we were tracking a server sent resize by setting a DesktopResize callback. This callback
is called when the desktop is resized by the server. Anyway the problem was that when this
callback is called, the activation sequence is not always completed, which were leading to
some freeze with 2012r2 servers (sending packets before the sequence is finished).
So with the faulty commit, we are tracking server resizes by subscribing to the Actived
event, that is called at the end of a reactivation sequence, so we're sure to not send packets
when not fully activated.
Anyway the issue that shows on (#4330) is that when you use egfx, no reactivation sequence happens,
the server only sends a ResetGraphics message with the new size, and so we miss the resized event.
This fix introduces a new GraphicsReset event, makes the display channel subscribe to that event,
and react accordingly.
2017-12-23 15:50:54 +03:00
|
|
|
gfx->SurfaceTable = HashTable_New(TRUE);
|
2014-06-12 01:48:04 +04:00
|
|
|
if (!gfx->SurfaceTable)
|
2014-11-17 01:30:31 +03:00
|
|
|
{
|
2016-08-04 17:28:38 +03:00
|
|
|
free(gfx);
|
2015-06-09 16:22:26 +03:00
|
|
|
WLog_ERR(TAG, "HashTable_New failed!");
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
2014-11-17 01:30:31 +03:00
|
|
|
}
|
2014-06-12 01:48:04 +04:00
|
|
|
|
2014-07-03 22:35:03 +04:00
|
|
|
gfx->ThinClient = gfx->settings->GfxThinClient;
|
|
|
|
gfx->SmallCache = gfx->settings->GfxSmallCache;
|
|
|
|
gfx->Progressive = gfx->settings->GfxProgressive;
|
|
|
|
gfx->ProgressiveV2 = gfx->settings->GfxProgressiveV2;
|
|
|
|
gfx->H264 = gfx->settings->GfxH264;
|
2016-03-24 18:25:22 +03:00
|
|
|
gfx->AVC444 = gfx->settings->GfxAVC444;
|
2017-05-18 15:05:41 +03:00
|
|
|
gfx->SendQoeAck = gfx->settings->GfxSendQoeAck;
|
2014-07-03 22:35:03 +04:00
|
|
|
|
|
|
|
if (gfx->H264)
|
|
|
|
gfx->SmallCache = TRUE;
|
|
|
|
|
2017-10-10 18:12:16 +03:00
|
|
|
gfx->MaxCacheSlot = gfx->SmallCache ? 4096 : 25600;
|
2014-06-03 08:05:43 +04:00
|
|
|
|
Fix for #4330
Since ec027bf dynamic resolution is broken when used with egfx. Before that commit
we were tracking a server sent resize by setting a DesktopResize callback. This callback
is called when the desktop is resized by the server. Anyway the problem was that when this
callback is called, the activation sequence is not always completed, which were leading to
some freeze with 2012r2 servers (sending packets before the sequence is finished).
So with the faulty commit, we are tracking server resizes by subscribing to the Actived
event, that is called at the end of a reactivation sequence, so we're sure to not send packets
when not fully activated.
Anyway the issue that shows on (#4330) is that when you use egfx, no reactivation sequence happens,
the server only sends a ResetGraphics message with the new size, and so we miss the resized event.
This fix introduces a new GraphicsReset event, makes the display channel subscribe to that event,
and react accordingly.
2017-12-23 15:50:54 +03:00
|
|
|
context = (RdpgfxClientContext *)calloc(1, sizeof(RdpgfxClientContext));
|
2014-06-03 08:05:43 +04:00
|
|
|
if (!context)
|
2014-11-17 01:30:31 +03:00
|
|
|
{
|
2014-12-27 23:20:29 +03:00
|
|
|
free(gfx);
|
2015-06-09 16:22:26 +03:00
|
|
|
WLog_ERR(TAG, "calloc failed!");
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
2014-11-17 01:30:31 +03:00
|
|
|
}
|
2013-10-22 06:53:55 +04:00
|
|
|
|
2014-06-05 06:06:29 +04:00
|
|
|
context->handle = (void*) gfx;
|
2015-02-11 00:32:07 +03:00
|
|
|
context->GetSurfaceIds = rdpgfx_get_surface_ids;
|
2014-06-12 01:48:04 +04:00
|
|
|
context->SetSurfaceData = rdpgfx_set_surface_data;
|
|
|
|
context->GetSurfaceData = rdpgfx_get_surface_data;
|
2014-06-13 16:36:09 +04:00
|
|
|
context->SetCacheSlotData = rdpgfx_set_cache_slot_data;
|
|
|
|
context->GetCacheSlotData = rdpgfx_get_cache_slot_data;
|
2014-06-05 06:06:29 +04:00
|
|
|
gfx->iface.pInterface = (void*) context;
|
|
|
|
gfx->zgfx = zgfx_context_new(FALSE);
|
2014-06-03 22:29:55 +04:00
|
|
|
|
2014-07-29 00:47:42 +04:00
|
|
|
if (!gfx->zgfx)
|
2014-11-17 01:30:31 +03:00
|
|
|
{
|
2015-02-07 01:35:14 +03:00
|
|
|
free(gfx);
|
|
|
|
free(context);
|
2015-06-09 16:22:26 +03:00
|
|
|
WLog_ERR(TAG, "zgfx_context_new failed!");
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
2014-11-17 01:30:31 +03:00
|
|
|
}
|
2014-07-29 00:47:42 +04:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
error = pEntryPoints->RegisterPlugin(pEntryPoints, "rdpgfx", (IWTSPlugin*) gfx);
|
2013-10-22 06:53:55 +04:00
|
|
|
}
|
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
return error;
|
2013-10-22 06:53:55 +04:00
|
|
|
}
|