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")
|
|
|
|
|
2020-01-16 17:23:35 +03:00
|
|
|
static void free_surfaces(RdpgfxClientContext* context, wHashTable* SurfaceTable)
|
|
|
|
{
|
|
|
|
UINT error = 0;
|
|
|
|
ULONG_PTR* pKeys = NULL;
|
|
|
|
int count;
|
|
|
|
int index;
|
|
|
|
|
|
|
|
count = HashTable_GetKeys(SurfaceTable, &pKeys);
|
|
|
|
|
|
|
|
for (index = 0; index < count; index++)
|
|
|
|
{
|
|
|
|
RDPGFX_DELETE_SURFACE_PDU pdu;
|
|
|
|
pdu.surfaceId = ((UINT16)pKeys[index]) - 1;
|
|
|
|
|
|
|
|
if (context)
|
|
|
|
{
|
|
|
|
IFCALLRET(context->DeleteSurface, error, context, &pdu);
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "context->DeleteSurface failed with error %" PRIu32 "", error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(pKeys);
|
|
|
|
}
|
|
|
|
|
2020-03-02 11:54:35 +03:00
|
|
|
static void evict_cache_slots(RdpgfxClientContext* context, UINT16 MaxCacheSlots, void** CacheSlots)
|
2020-01-16 17:23:35 +03:00
|
|
|
{
|
|
|
|
UINT16 index;
|
|
|
|
|
2020-03-02 11:54:35 +03:00
|
|
|
for (index = 0; index < MaxCacheSlots; index++)
|
2020-01-16 17:23:35 +03:00
|
|
|
{
|
|
|
|
if (CacheSlots[index])
|
|
|
|
{
|
|
|
|
RDPGFX_EVICT_CACHE_ENTRY_PDU pdu;
|
2020-03-04 13:00:54 +03:00
|
|
|
pdu.cacheSlot = (UINT16)index + 1;
|
2020-01-16 17:23:35 +03:00
|
|
|
|
|
|
|
if (context && context->EvictCacheEntry)
|
|
|
|
{
|
|
|
|
context->EvictCacheEntry(context, &pdu);
|
|
|
|
}
|
|
|
|
|
|
|
|
CacheSlots[index] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2019-05-05 15:31:18 +03:00
|
|
|
static UINT rdpgfx_send_caps_advertise_pdu(RdpgfxClientContext* context,
|
2019-11-06 17:24:51 +03:00
|
|
|
const RDPGFX_CAPS_ADVERTISE_PDU* pdu)
|
2014-06-03 08:05:43 +04:00
|
|
|
{
|
2019-05-05 15:31:18 +03:00
|
|
|
UINT error = CHANNEL_RC_OK;
|
2014-06-03 08:05:43 +04:00
|
|
|
UINT16 index;
|
|
|
|
RDPGFX_HEADER header;
|
|
|
|
RDPGFX_CAPSET* capsSet;
|
2019-05-05 15:31:18 +03:00
|
|
|
RDPGFX_PLUGIN* gfx;
|
|
|
|
RDPGFX_CHANNEL_CALLBACK* callback;
|
|
|
|
wStream* s;
|
2019-11-06 17:24:51 +03:00
|
|
|
gfx = (RDPGFX_PLUGIN*)context->handle;
|
2020-03-01 14:43:09 +03:00
|
|
|
|
|
|
|
if (!gfx || !gfx->listener_callback)
|
|
|
|
return ERROR_BAD_ARGUMENTS;
|
|
|
|
|
2019-05-05 15:31:18 +03:00
|
|
|
callback = gfx->listener_callback->channel_callback;
|
2020-03-01 14:43:09 +03:00
|
|
|
|
2019-05-05 15:31:18 +03:00
|
|
|
header.flags = 0;
|
|
|
|
header.cmdId = RDPGFX_CMDID_CAPSADVERTISE;
|
|
|
|
header.pduLength = RDPGFX_HEADER_SIZE + 2;
|
|
|
|
|
|
|
|
for (index = 0; index < pdu->capsSetCount; index++)
|
|
|
|
{
|
|
|
|
capsSet = &(pdu->capsSets[index]);
|
|
|
|
header.pduLength += RDPGFX_CAPSET_BASE_SIZE + capsSet->length;
|
|
|
|
}
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
DEBUG_RDPGFX(gfx->log, "SendCapsAdvertisePdu %" PRIu16 "", pdu->capsSetCount);
|
2019-05-05 15:31:18 +03:00
|
|
|
s = Stream_New(NULL, header.pduLength);
|
|
|
|
|
|
|
|
if (!s)
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "Stream_New failed!");
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((error = rdpgfx_write_header(s, &header)))
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
/* RDPGFX_CAPS_ADVERTISE_PDU */
|
|
|
|
Stream_Write_UINT16(s, pdu->capsSetCount); /* capsSetCount (2 bytes) */
|
|
|
|
|
|
|
|
for (index = 0; index < pdu->capsSetCount; index++)
|
|
|
|
{
|
|
|
|
capsSet = &(pdu->capsSets[index]);
|
|
|
|
Stream_Write_UINT32(s, capsSet->version); /* version (4 bytes) */
|
2019-11-06 17:24:51 +03:00
|
|
|
Stream_Write_UINT32(s, capsSet->length); /* capsDataLength (4 bytes) */
|
|
|
|
Stream_Write_UINT32(s, capsSet->flags); /* capsData (4 bytes) */
|
2019-05-05 15:31:18 +03:00
|
|
|
Stream_Zero(s, capsSet->length - 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
Stream_SealLength(s);
|
2019-11-06 17:24:51 +03:00
|
|
|
error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s),
|
|
|
|
NULL);
|
2019-05-05 15:31:18 +03:00
|
|
|
fail:
|
|
|
|
Stream_Free(s, TRUE);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2019-05-08 12:43:22 +03:00
|
|
|
static BOOL rdpgfx_is_capability_filtered(RDPGFX_PLUGIN* gfx, UINT32 caps)
|
|
|
|
{
|
|
|
|
const UINT32 filter = gfx->capsFilter;
|
2019-11-06 17:24:51 +03:00
|
|
|
const UINT32 capList[] = {
|
|
|
|
RDPGFX_CAPVERSION_8, RDPGFX_CAPVERSION_81, RDPGFX_CAPVERSION_10,
|
|
|
|
RDPGFX_CAPVERSION_101, RDPGFX_CAPVERSION_102, RDPGFX_CAPVERSION_103,
|
|
|
|
RDPGFX_CAPVERSION_104, RDPGFX_CAPVERSION_105, RDPGFX_CAPVERSION_106
|
2019-05-08 12:43:22 +03:00
|
|
|
};
|
|
|
|
UINT32 x;
|
|
|
|
|
|
|
|
for (x = 0; x < ARRAYSIZE(capList); x++)
|
|
|
|
{
|
|
|
|
if (caps == capList[x])
|
|
|
|
return (filter & (1 << x)) != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2019-05-05 15:31:18 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
|
|
|
static UINT rdpgfx_send_supported_caps(RDPGFX_CHANNEL_CALLBACK* callback)
|
|
|
|
{
|
|
|
|
RDPGFX_PLUGIN* gfx;
|
|
|
|
RdpgfxClientContext* context;
|
|
|
|
RDPGFX_CAPSET* capsSet;
|
2019-02-27 18:36:15 +03:00
|
|
|
RDPGFX_CAPSET capsSets[RDPGFX_NUMBER_CAPSETS] = { 0 };
|
2014-06-03 08:05:43 +04:00
|
|
|
RDPGFX_CAPS_ADVERTISE_PDU pdu;
|
2019-05-08 12:43:22 +03:00
|
|
|
|
|
|
|
if (!callback)
|
|
|
|
return ERROR_BAD_ARGUMENTS;
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
2019-05-08 12:43:22 +03:00
|
|
|
|
|
|
|
if (!gfx)
|
|
|
|
return ERROR_BAD_CONFIGURATION;
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
2019-05-08 12:43:22 +03:00
|
|
|
|
|
|
|
if (!context)
|
|
|
|
return ERROR_BAD_CONFIGURATION;
|
|
|
|
|
2014-07-03 22:35:03 +04:00
|
|
|
pdu.capsSetCount = 0;
|
2019-11-06 17:24:51 +03:00
|
|
|
pdu.capsSets = (RDPGFX_CAPSET*)capsSets;
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2019-05-08 12:43:22 +03:00
|
|
|
if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_8))
|
|
|
|
{
|
|
|
|
capsSet = &capsSets[pdu.capsSetCount++];
|
|
|
|
capsSet->version = RDPGFX_CAPVERSION_8;
|
|
|
|
capsSet->length = 4;
|
|
|
|
capsSet->flags = 0;
|
2014-06-03 08:05:43 +04:00
|
|
|
|
2019-05-08 12:43:22 +03:00
|
|
|
if (gfx->ThinClient)
|
|
|
|
capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT;
|
2014-06-03 08:05:43 +04:00
|
|
|
|
2019-05-08 12:43:22 +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)
|
|
|
|
capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
|
|
|
|
}
|
2014-06-03 08:05:43 +04:00
|
|
|
|
2019-05-08 12:43:22 +03:00
|
|
|
if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_81))
|
|
|
|
{
|
|
|
|
capsSet = &capsSets[pdu.capsSetCount++];
|
|
|
|
capsSet->version = RDPGFX_CAPVERSION_81;
|
|
|
|
capsSet->length = 4;
|
|
|
|
capsSet->flags = 0;
|
2014-06-03 08:05:43 +04:00
|
|
|
|
2019-05-08 12:43:22 +03:00
|
|
|
if (gfx->ThinClient)
|
|
|
|
capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT;
|
|
|
|
|
|
|
|
if (gfx->SmallCache)
|
|
|
|
capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2017-07-17 10:00:57 +03:00
|
|
|
#ifdef WITH_GFX_H264
|
2019-02-27 18:36:15 +03:00
|
|
|
|
2019-05-08 12:43:22 +03:00
|
|
|
if (gfx->H264)
|
|
|
|
capsSet->flags |= RDPGFX_CAPS_FLAG_AVC420_ENABLED;
|
2019-02-27 18:36:15 +03:00
|
|
|
|
2017-07-17 10:00:57 +03:00
|
|
|
#endif
|
2019-05-08 12:43:22 +03:00
|
|
|
}
|
2016-03-02 17:16:49 +03:00
|
|
|
|
2017-09-11 13:05:03 +03:00
|
|
|
if (!gfx->H264 || gfx->AVC444)
|
|
|
|
{
|
2019-02-27 18:36:15 +03:00
|
|
|
UINT32 caps10Flags = 0;
|
2016-03-02 17:16:49 +03:00
|
|
|
|
2017-09-11 13:05:03 +03:00
|
|
|
if (gfx->SmallCache)
|
2019-02-27 18:36:15 +03:00
|
|
|
caps10Flags |= 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
|
2019-02-27 18:36:15 +03:00
|
|
|
|
2017-09-11 13:05:03 +03:00
|
|
|
if (!gfx->AVC444)
|
2019-02-27 18:36:15 +03:00
|
|
|
caps10Flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
|
|
|
|
|
2017-07-17 10:00:57 +03:00
|
|
|
#else
|
2019-02-27 18:36:15 +03:00
|
|
|
caps10Flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
|
2017-07-17 10:00:57 +03:00
|
|
|
#endif
|
2019-05-08 12:43:22 +03:00
|
|
|
|
|
|
|
if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_10))
|
|
|
|
{
|
|
|
|
capsSet = &capsSets[pdu.capsSetCount++];
|
|
|
|
capsSet->version = RDPGFX_CAPVERSION_10;
|
|
|
|
capsSet->length = 4;
|
|
|
|
capsSet->flags = caps10Flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_101))
|
|
|
|
{
|
|
|
|
capsSet = &capsSets[pdu.capsSetCount++];
|
|
|
|
capsSet->version = RDPGFX_CAPVERSION_101;
|
|
|
|
capsSet->length = 0x10;
|
|
|
|
capsSet->flags = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_102))
|
|
|
|
{
|
|
|
|
capsSet = &capsSets[pdu.capsSetCount++];
|
|
|
|
capsSet->version = RDPGFX_CAPVERSION_102;
|
|
|
|
capsSet->length = 0x4;
|
|
|
|
capsSet->flags = caps10Flags;
|
|
|
|
}
|
2019-02-27 18:36:15 +03:00
|
|
|
|
|
|
|
if (gfx->ThinClient)
|
2019-05-09 13:46:10 +03:00
|
|
|
{
|
|
|
|
if ((caps10Flags & RDPGFX_CAPS_FLAG_AVC_DISABLED) == 0)
|
|
|
|
caps10Flags |= RDPGFX_CAPS_FLAG_AVC_THINCLIENT;
|
|
|
|
}
|
2016-10-16 11:28:06 +03:00
|
|
|
|
2019-05-08 12:43:22 +03:00
|
|
|
if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_103))
|
|
|
|
{
|
|
|
|
capsSet = &capsSets[pdu.capsSetCount++];
|
|
|
|
capsSet->version = RDPGFX_CAPVERSION_103;
|
|
|
|
capsSet->length = 0x4;
|
|
|
|
capsSet->flags = caps10Flags & ~RDPGFX_CAPS_FLAG_SMALL_CACHE;
|
|
|
|
}
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2019-05-08 12:43:22 +03:00
|
|
|
if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_104))
|
|
|
|
{
|
|
|
|
capsSet = &capsSets[pdu.capsSetCount++];
|
|
|
|
capsSet->version = RDPGFX_CAPVERSION_104;
|
|
|
|
capsSet->length = 0x4;
|
|
|
|
capsSet->flags = caps10Flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_105))
|
|
|
|
{
|
|
|
|
capsSet = &capsSets[pdu.capsSetCount++];
|
|
|
|
capsSet->version = RDPGFX_CAPVERSION_105;
|
|
|
|
capsSet->length = 0x4;
|
|
|
|
capsSet->flags = caps10Flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_106))
|
|
|
|
{
|
|
|
|
capsSet = &capsSets[pdu.capsSetCount++];
|
|
|
|
capsSet->version = RDPGFX_CAPVERSION_106;
|
|
|
|
capsSet->length = 0x4;
|
|
|
|
capsSet->flags = caps10Flags;
|
|
|
|
}
|
2014-06-03 08:05:43 +04:00
|
|
|
}
|
|
|
|
|
2019-05-08 12:43:22 +03:00
|
|
|
return IFCALLRESULT(ERROR_BAD_CONFIGURATION, context->CapsAdvertise, context, &pdu);
|
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
|
|
|
|
*/
|
2019-11-06 17:24:51 +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;
|
|
|
|
RDPGFX_CAPS_CONFIRM_PDU pdu;
|
2019-11-06 17:24:51 +03:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
|
|
|
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
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) */
|
2019-11-06 17:24:51 +03:00
|
|
|
Stream_Read_UINT32(s, capsSet.length); /* capsDataLength (4 bytes) */
|
|
|
|
Stream_Read_UINT32(s, capsSet.flags); /* capsData (4 bytes) */
|
2017-05-17 11:27:25 +03:00
|
|
|
gfx->ConnectionCaps = capsSet;
|
2019-11-06 17:24:51 +03:00
|
|
|
DEBUG_RDPGFX(gfx->log, "RecvCapsConfirmPdu: version: 0x%08" PRIX32 " flags: 0x%08" PRIX32 "",
|
|
|
|
capsSet.version, capsSet.flags);
|
2019-05-05 15:31:18 +03:00
|
|
|
|
2019-05-09 13:46:10 +03:00
|
|
|
if (!context)
|
|
|
|
return ERROR_BAD_CONFIGURATION;
|
2019-05-05 15:31:18 +03:00
|
|
|
|
2019-05-09 13:46:10 +03:00
|
|
|
return IFCALLRESULT(CHANNEL_RC_OK, context->CapsConfirm, context, &pdu);
|
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
|
|
|
|
*/
|
2019-05-05 15:31:18 +03:00
|
|
|
static UINT rdpgfx_send_frame_acknowledge_pdu(RdpgfxClientContext* context,
|
2019-11-06 17:24:51 +03:00
|
|
|
const 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;
|
2019-05-07 14:46:24 +03:00
|
|
|
RDPGFX_PLUGIN* gfx;
|
|
|
|
RDPGFX_CHANNEL_CALLBACK* callback;
|
|
|
|
|
|
|
|
if (!context || !pdu)
|
|
|
|
return ERROR_BAD_ARGUMENTS;
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
gfx = (RDPGFX_PLUGIN*)context->handle;
|
2019-05-07 14:46:24 +03:00
|
|
|
|
2020-03-01 14:43:09 +03:00
|
|
|
if (!gfx || !gfx->listener_callback)
|
2019-05-07 14:46:24 +03:00
|
|
|
return ERROR_BAD_CONFIGURATION;
|
|
|
|
|
|
|
|
callback = gfx->listener_callback->channel_callback;
|
|
|
|
|
|
|
|
if (!callback)
|
|
|
|
return ERROR_BAD_CONFIGURATION;
|
|
|
|
|
2014-06-04 03:48:47 +04:00
|
|
|
header.flags = 0;
|
|
|
|
header.cmdId = RDPGFX_CMDID_FRAMEACKNOWLEDGE;
|
|
|
|
header.pduLength = RDPGFX_HEADER_SIZE + 12;
|
2019-11-06 17:24:51 +03:00
|
|
|
DEBUG_RDPGFX(gfx->log, "SendFrameAcknowledgePdu: %" PRIu32 "", pdu->frameId);
|
2017-12-23 12:26:25 +03:00
|
|
|
s = Stream_New(NULL, header.pduLength);
|
2019-02-27 18:36:15 +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-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 */
|
2019-11-06 17:24:51 +03:00
|
|
|
Stream_Write_UINT32(s, pdu->queueDepth); /* queueDepth (4 bytes) */
|
|
|
|
Stream_Write_UINT32(s, pdu->frameId); /* frameId (4 bytes) */
|
|
|
|
Stream_Write_UINT32(s, pdu->totalFramesDecoded); /* totalFramesDecoded (4 bytes) */
|
|
|
|
error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s),
|
|
|
|
NULL);
|
2019-06-06 10:24:27 +03:00
|
|
|
|
|
|
|
if (error == CHANNEL_RC_OK) /* frame successfully acked */
|
|
|
|
gfx->UnacknowledgedFrames--;
|
|
|
|
|
2017-05-17 11:27:25 +03:00
|
|
|
fail:
|
|
|
|
Stream_Free(s, TRUE);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2019-06-05 16:18:00 +03:00
|
|
|
static UINT rdpgfx_send_qoe_frame_acknowledge_pdu(RdpgfxClientContext* context,
|
2019-11-06 17:24:51 +03:00
|
|
|
const RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU* pdu)
|
2017-05-17 11:27:25 +03:00
|
|
|
{
|
|
|
|
UINT error;
|
|
|
|
wStream* s;
|
|
|
|
RDPGFX_HEADER header;
|
2019-06-05 16:18:00 +03:00
|
|
|
RDPGFX_CHANNEL_CALLBACK* callback;
|
|
|
|
RDPGFX_PLUGIN* gfx;
|
2017-05-17 11:27:25 +03:00
|
|
|
header.flags = 0;
|
|
|
|
header.cmdId = RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE;
|
|
|
|
header.pduLength = RDPGFX_HEADER_SIZE + 12;
|
2019-06-05 16:18:00 +03:00
|
|
|
|
|
|
|
if (!context || !pdu)
|
|
|
|
return ERROR_BAD_ARGUMENTS;
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
gfx = (RDPGFX_PLUGIN*)context->handle;
|
2019-06-05 16:18:00 +03:00
|
|
|
|
2020-03-01 14:43:09 +03:00
|
|
|
if (!gfx || !gfx->listener_callback)
|
2019-06-05 16:18:00 +03:00
|
|
|
return ERROR_BAD_CONFIGURATION;
|
|
|
|
|
|
|
|
callback = gfx->listener_callback->channel_callback;
|
|
|
|
|
|
|
|
if (!callback)
|
|
|
|
return ERROR_BAD_CONFIGURATION;
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
DEBUG_RDPGFX(gfx->log, "SendQoeFrameAcknowledgePdu: %" PRIu32 "", pdu->frameId);
|
2017-12-23 12:26:25 +03:00
|
|
|
s = Stream_New(NULL, header.pduLength);
|
2019-02-27 18:36:15 +03:00
|
|
|
|
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);
|
2019-11-06 17:24:51 +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-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
|
|
|
}
|
|
|
|
|
2019-06-05 16:13:49 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
|
|
|
static UINT rdpgfx_send_cache_import_offer_pdu(RdpgfxClientContext* context,
|
2019-11-06 17:24:51 +03:00
|
|
|
const RDPGFX_CACHE_IMPORT_OFFER_PDU* pdu)
|
2019-06-05 16:13:49 +03:00
|
|
|
{
|
|
|
|
UINT16 index;
|
|
|
|
UINT error = CHANNEL_RC_OK;
|
|
|
|
wStream* s;
|
|
|
|
RDPGFX_PLUGIN* gfx;
|
|
|
|
RDPGFX_CHANNEL_CALLBACK* callback;
|
|
|
|
RDPGFX_HEADER header;
|
|
|
|
RDPGFX_CACHE_ENTRY_METADATA* cacheEntries;
|
|
|
|
|
|
|
|
if (!context || !pdu)
|
|
|
|
return ERROR_BAD_ARGUMENTS;
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
gfx = (RDPGFX_PLUGIN*)context->handle;
|
2019-06-05 16:13:49 +03:00
|
|
|
|
2020-03-01 14:43:09 +03:00
|
|
|
if (!gfx || !gfx->listener_callback)
|
2019-06-05 16:13:49 +03:00
|
|
|
return ERROR_BAD_CONFIGURATION;
|
|
|
|
|
|
|
|
callback = gfx->listener_callback->channel_callback;
|
|
|
|
|
|
|
|
if (!callback)
|
|
|
|
return ERROR_BAD_CONFIGURATION;
|
|
|
|
|
|
|
|
header.flags = 0;
|
|
|
|
header.cmdId = RDPGFX_CMDID_CACHEIMPORTOFFER;
|
|
|
|
header.pduLength = RDPGFX_HEADER_SIZE + 2 + pdu->cacheEntriesCount * 12;
|
2019-11-06 17:24:51 +03:00
|
|
|
DEBUG_RDPGFX(gfx->log, "SendCacheImportOfferPdu: cacheEntriesCount: %" PRIu16 "",
|
|
|
|
pdu->cacheEntriesCount);
|
2019-06-05 16:13:49 +03:00
|
|
|
s = Stream_New(NULL, header.pduLength);
|
2019-11-06 17:24:51 +03:00
|
|
|
|
2019-06-05 16:13:49 +03:00
|
|
|
if (!s)
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "Stream_New failed!");
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((error = rdpgfx_write_header(s, &header)))
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
if (pdu->cacheEntriesCount <= 0)
|
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
WLog_ERR(TAG, "Invalid cacheEntriesCount: %" PRIu16 "", pdu->cacheEntriesCount);
|
2019-06-05 16:13:49 +03:00
|
|
|
error = ERROR_INVALID_DATA;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* cacheEntriesCount (2 bytes) */
|
|
|
|
Stream_Write_UINT16(s, pdu->cacheEntriesCount);
|
|
|
|
|
|
|
|
for (index = 0; index < pdu->cacheEntriesCount; index++)
|
|
|
|
{
|
|
|
|
cacheEntries = &(pdu->cacheEntries[index]);
|
2019-11-06 17:24:51 +03:00
|
|
|
Stream_Write_UINT64(s, cacheEntries->cacheKey); /* cacheKey (8 bytes) */
|
2019-06-05 16:13:49 +03:00
|
|
|
Stream_Write_UINT32(s, cacheEntries->bitmapLength); /* bitmapLength (4 bytes) */
|
|
|
|
}
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s),
|
|
|
|
NULL);
|
2019-06-05 16:13:49 +03:00
|
|
|
|
|
|
|
fail:
|
|
|
|
Stream_Free(s, TRUE);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2019-11-06 17:24:51 +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;
|
2019-11-06 17:24:51 +03: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
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
Stream_Read_UINT32(s, pdu.width); /* width (4 bytes) */
|
|
|
|
Stream_Read_UINT32(s, pdu.height); /* height (4 bytes) */
|
2014-06-03 23:32:03 +04:00
|
|
|
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
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
pdu.monitorDefArray = (MONITOR_DEF*)calloc(pdu.monitorCount, sizeof(MONITOR_DEF));
|
2019-02-27 18:36:15 +03:00
|
|
|
|
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]);
|
2019-11-06 17:24:51 +03:00
|
|
|
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) */
|
2014-06-03 23:32:03 +04:00
|
|
|
Stream_Read_UINT32(s, monitor->bottom); /* bottom (4 bytes) */
|
2019-11-06 17:24:51 +03:00
|
|
|
Stream_Read_UINT32(s, monitor->flags); /* flags (4 bytes) */
|
2014-06-03 23:32:03 +04:00
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2019-11-06 17:24:51 +03: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) */
|
2019-11-06 17:24:51 +03:00
|
|
|
DEBUG_RDPGFX(gfx->log,
|
|
|
|
"RecvResetGraphicsPdu: width: %" PRIu32 " height: %" PRIu32 " count: %" PRIu32 "",
|
|
|
|
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]);
|
2019-11-06 17:24:51 +03:00
|
|
|
DEBUG_RDPGFX(gfx->log,
|
|
|
|
"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)
|
2019-11-06 17:24:51 +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) */
|
2019-02-12 12:53:30 +03:00
|
|
|
EventArgsInit(&graphicsReset, "libfreerdp");
|
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
|
|
|
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
|
|
|
|
*/
|
2019-11-06 17:24:51 +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;
|
2019-11-06 17:24:51 +03: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) */
|
2019-11-06 17:24:51 +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)
|
2019-11-06 17:24:51 +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
|
|
|
|
*/
|
2019-11-06 17:24:51 +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;
|
2019-11-06 17:24:51 +03: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
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
pdu.cacheSlots = (UINT16*)calloc(pdu.importedEntriesCount, sizeof(UINT16));
|
2019-02-27 18:36:15 +03:00
|
|
|
|
2014-06-04 03:48:47 +04:00
|
|
|
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) */
|
|
|
|
}
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
DEBUG_RDPGFX(gfx->log, "RecvCacheImportReplyPdu: importedEntriesCount: %" PRIu16 "",
|
|
|
|
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)
|
2019-11-06 17:24:51 +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
|
|
|
|
*/
|
2019-11-06 17:24:51 +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;
|
2019-11-06 17:24:51 +03: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
|
|
|
|
2019-11-06 17:24:51 +03: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) */
|
2014-06-03 23:32:03 +04:00
|
|
|
Stream_Read_UINT8(s, pdu.pixelFormat); /* RDPGFX_PIXELFORMAT (1 byte) */
|
2019-11-06 17:24:51 +03:00
|
|
|
DEBUG_RDPGFX(gfx->log,
|
|
|
|
"RecvCreateSurfacePdu: surfaceId: %" PRIu16 " width: %" PRIu16 " height: %" PRIu16
|
|
|
|
" pixelFormat: 0x%02" PRIX8 "",
|
|
|
|
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)
|
2019-11-06 17:24:51 +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
|
|
|
|
*/
|
2019-11-06 17:24:51 +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;
|
2019-11-06 17:24:51 +03: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) */
|
2019-11-06 17:24:51 +03:00
|
|
|
DEBUG_RDPGFX(gfx->log, "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)
|
2019-11-06 17:24:51 +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
|
|
|
|
*/
|
2019-11-06 17:24:51 +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;
|
2019-11-06 17:24:51 +03: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
|
|
|
|
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) */
|
2019-11-06 17:24:51 +03:00
|
|
|
Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */
|
|
|
|
DEBUG_RDPGFX(gfx->log, "RecvStartFramePdu: frameId: %" PRIu32 " timestamp: 0x%08" PRIX32 "",
|
|
|
|
pdu.frameId, pdu.timestamp);
|
2019-09-02 16:44:52 +03:00
|
|
|
gfx->StartDecodingTime = GetTickCount64();
|
2019-02-27 18:36:15 +03: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->StartFrame, error, context, &pdu);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
2015-06-09 16:22:26 +03:00
|
|
|
if (error)
|
2019-11-06 17:24:51 +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
|
|
|
|
*/
|
2019-11-06 17:24:51 +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;
|
2019-11-06 17:24:51 +03: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
|
|
|
|
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) */
|
2019-11-06 17:24:51 +03:00
|
|
|
DEBUG_RDPGFX(gfx->log, "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)
|
|
|
|
{
|
2019-11-06 17:24:51 +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->TotalDecodedFrames++;
|
2019-06-05 16:18:00 +03:00
|
|
|
|
|
|
|
if (!gfx->sendFrameAcks)
|
|
|
|
return error;
|
|
|
|
|
2014-06-04 03:48:47 +04:00
|
|
|
ack.frameId = pdu.frameId;
|
|
|
|
ack.totalFramesDecoded = gfx->TotalDecodedFrames;
|
|
|
|
|
2019-06-05 16:18:00 +03:00
|
|
|
if (gfx->suspendFrameAcks)
|
2015-07-06 23:28:52 +03:00
|
|
|
{
|
2019-06-05 16:18:00 +03:00
|
|
|
ack.queueDepth = SUSPEND_FRAME_ACKNOWLEDGEMENT;
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2019-06-05 16:18:00 +03:00
|
|
|
if (gfx->TotalDecodedFrames == 1)
|
2019-05-05 15:31:18 +03:00
|
|
|
if ((error = rdpgfx_send_frame_acknowledge_pdu(context, &ack)))
|
2019-11-06 17:24:51 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR,
|
|
|
|
"rdpgfx_send_frame_acknowledge_pdu failed with error %" PRIu32 "",
|
|
|
|
error);
|
2019-06-05 16:18:00 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ack.queueDepth = QUEUE_DEPTH_UNAVAILABLE;
|
|
|
|
|
|
|
|
if ((error = rdpgfx_send_frame_acknowledge_pdu(context, &ack)))
|
2019-11-06 17:24:51 +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
|
|
|
}
|
2014-06-04 03:48:47 +04:00
|
|
|
|
2019-02-27 18:36:15 +03:00
|
|
|
switch (gfx->ConnectionCaps.version)
|
2017-05-17 11:27:25 +03:00
|
|
|
{
|
2019-02-27 18:36:15 +03:00
|
|
|
case RDPGFX_CAPVERSION_10:
|
|
|
|
case RDPGFX_CAPVERSION_102:
|
|
|
|
case RDPGFX_CAPVERSION_103:
|
2019-05-07 11:22:02 +03:00
|
|
|
case RDPGFX_CAPVERSION_104:
|
|
|
|
case RDPGFX_CAPVERSION_105:
|
|
|
|
case RDPGFX_CAPVERSION_106:
|
2019-02-27 18:36:15 +03:00
|
|
|
if (gfx->SendQoeAck)
|
|
|
|
{
|
|
|
|
RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU qoe;
|
2019-09-02 16:44:52 +03:00
|
|
|
UINT64 diff = (GetTickCount64() - gfx->StartDecodingTime);
|
2019-02-27 18:36:15 +03:00
|
|
|
|
|
|
|
if (diff > 65000)
|
|
|
|
diff = 0;
|
|
|
|
|
|
|
|
qoe.frameId = pdu.frameId;
|
|
|
|
qoe.timestamp = gfx->StartDecodingTime;
|
|
|
|
qoe.timeDiffSE = diff;
|
|
|
|
qoe.timeDiffEDR = 1;
|
|
|
|
|
2019-06-05 16:18:00 +03:00
|
|
|
if ((error = rdpgfx_send_qoe_frame_acknowledge_pdu(context, &qoe)))
|
2019-05-05 15:31:18 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR,
|
2019-11-06 17:24:51 +03:00
|
|
|
"rdpgfx_send_qoe_frame_acknowledge_pdu failed with error %" PRIu32
|
|
|
|
"",
|
2019-02-27 18:36:15 +03:00
|
|
|
error);
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
2017-05-17 11:27:25 +03: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
|
|
|
|
*/
|
2019-11-06 17:24:51 +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;
|
2019-11-06 17:24:51 +03: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
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
|
|
|
Stream_Read_UINT16(s, pdu.codecId); /* codecId (2 bytes) */
|
2014-06-04 03:48:47 +04:00
|
|
|
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) */
|
|
|
|
{
|
2019-11-06 17:24:51 +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);
|
2019-06-04 10:28:03 +03:00
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
DEBUG_RDPGFX(gfx->log,
|
|
|
|
"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)))
|
2019-11-06 17:24:51 +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
|
|
|
|
*/
|
2019-11-06 17:24:51 +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;
|
2019-11-06 17:24:51 +03: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
|
|
|
|
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
|
|
|
|
2019-11-06 17:24:51 +03: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) */
|
2014-06-04 03:48:47 +04:00
|
|
|
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);
|
2019-11-06 17:24:51 +03:00
|
|
|
DEBUG_RDPGFX(gfx->log,
|
|
|
|
"RecvWireToSurface2Pdu: surfaceId: %" PRIu16 " codecId: %s (0x%04" PRIX16 ") "
|
|
|
|
"codecContextId: %" PRIu32 " pixelFormat: 0x%02" PRIX8
|
|
|
|
" bitmapDataLength: %" PRIu32 "",
|
|
|
|
pdu.surfaceId, rdpgfx_get_codec_id_string(pdu.codecId), pdu.codecId,
|
|
|
|
pdu.codecContextId, pdu.pixelFormat, pdu.bitmapDataLength);
|
2019-06-04 10:28:03 +03:00
|
|
|
|
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;
|
2019-03-18 17:05:07 +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;
|
|
|
|
}
|
|
|
|
|
2014-06-05 05:35:31 +04:00
|
|
|
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)
|
2019-11-06 17:24:51 +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
|
|
|
|
*/
|
2019-11-06 17:24:51 +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;
|
2019-11-06 17:24:51 +03: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
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
2014-06-04 03:48:47 +04:00
|
|
|
Stream_Read_UINT32(s, pdu.codecContextId); /* codecContextId (4 bytes) */
|
2019-06-04 10:28:03 +03:00
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
DEBUG_RDPGFX(gfx->log,
|
|
|
|
"RecvDeleteEncodingContextPdu: surfaceId: %" PRIu16 " codecContextId: %" PRIu32 "",
|
|
|
|
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)
|
2019-11-06 17:24:51 +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;
|
2019-11-06 17:24:51 +03: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
|
|
|
{
|
2019-11-06 17:24:51 +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
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
pdu.fillRects = (RECTANGLE_16*)calloc(pdu.fillRectCount, sizeof(RECTANGLE_16));
|
2019-02-27 18:36:15 +03:00
|
|
|
|
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)))
|
|
|
|
{
|
2019-11-06 17:24:51 +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
|
|
|
}
|
2019-11-06 17:24:51 +03:00
|
|
|
DEBUG_RDPGFX(gfx->log, "RecvSolidFillPdu: surfaceId: %" PRIu16 " fillRectCount: %" PRIu16 "",
|
|
|
|
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)
|
2019-11-06 17:24:51 +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
|
|
|
|
*/
|
2019-11-06 17:24:51 +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;
|
2019-11-06 17:24:51 +03: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
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
Stream_Read_UINT16(s, pdu.surfaceIdSrc); /* surfaceIdSrc (2 bytes) */
|
2014-06-04 03:48:47 +04:00
|
|
|
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 ) */
|
|
|
|
{
|
2019-11-06 17:24:51 +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
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
pdu.destPts = (RDPGFX_POINT16*)calloc(pdu.destPtsCount, sizeof(RDPGFX_POINT16));
|
2019-02-27 18:36:15 +03:00
|
|
|
|
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)))
|
|
|
|
{
|
2019-11-06 17:24:51 +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
|
|
|
}
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
DEBUG_RDPGFX(gfx->log,
|
|
|
|
"RecvSurfaceToSurfacePdu: surfaceIdSrc: %" PRIu16 " surfaceIdDest: %" PRIu16 " "
|
|
|
|
"left: %" PRIu16 " top: %" PRIu16 " right: %" PRIu16 " bottom: %" PRIu16
|
|
|
|
" destPtsCount: %" PRIu16 "",
|
|
|
|
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)
|
2019-11-06 17:24:51 +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
|
|
|
|
*/
|
2019-11-06 17:24:51 +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;
|
2019-11-06 17:24:51 +03: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) */
|
2019-11-06 17:24:51 +03:00
|
|
|
Stream_Read_UINT64(s, pdu.cacheKey); /* cacheKey (8 bytes) */
|
2014-06-04 03:48:47 +04:00
|
|
|
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 ) */
|
|
|
|
{
|
2019-11-06 17:24:51 +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
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
DEBUG_RDPGFX(gfx->log,
|
|
|
|
"RecvSurfaceToCachePdu: surfaceId: %" PRIu16 " cacheKey: 0x%016" PRIX64
|
|
|
|
" cacheSlot: %" PRIu16 " "
|
|
|
|
"left: %" PRIu16 " top: %" PRIu16 " right: %" PRIu16 " bottom: %" PRIu16 "",
|
|
|
|
pdu.surfaceId, pdu.cacheKey, pdu.cacheSlot, 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)
|
2019-11-06 17:24:51 +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
|
|
|
|
*/
|
2019-11-06 17:24:51 +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;
|
2019-11-06 17:24:51 +03: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
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
Stream_Read_UINT16(s, pdu.cacheSlot); /* cacheSlot (2 bytes) */
|
|
|
|
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
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
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
pdu.destPts = (RDPGFX_POINT16*)calloc(pdu.destPtsCount, sizeof(RDPGFX_POINT16));
|
2019-02-27 18:36:15 +03:00
|
|
|
|
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)))
|
|
|
|
{
|
2019-11-06 17:24:51 +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
|
|
|
}
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
DEBUG_RDPGFX(gfx->log,
|
|
|
|
"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)
|
2019-11-06 17:24:51 +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
|
|
|
|
*/
|
2019-11-06 17:24:51 +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;
|
2019-11-06 17:24:51 +03: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
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
|
|
|
Stream_Read_UINT16(s, pdu.reserved); /* reserved (2 bytes) */
|
2014-06-04 03:48:47 +04:00
|
|
|
Stream_Read_UINT32(s, pdu.outputOriginX); /* outputOriginX (4 bytes) */
|
|
|
|
Stream_Read_UINT32(s, pdu.outputOriginY); /* outputOriginY (4 bytes) */
|
2019-11-06 17:24:51 +03:00
|
|
|
DEBUG_RDPGFX(gfx->log,
|
|
|
|
"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)
|
2019-11-06 17:24:51 +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
|
|
|
}
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
static UINT rdpgfx_recv_map_surface_to_scaled_output_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
|
|
|
|
wStream* s)
|
2019-02-27 18:36:15 +03:00
|
|
|
{
|
|
|
|
RDPGFX_MAP_SURFACE_TO_SCALED_OUTPUT_PDU pdu;
|
2019-11-06 17:24:51 +03:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
|
|
|
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
2019-02-27 18:36:15 +03:00
|
|
|
UINT error = CHANNEL_RC_OK;
|
|
|
|
|
2019-05-05 12:34:57 +03:00
|
|
|
if (Stream_GetRemainingLength(s) < 20)
|
2019-02-27 18:36:15 +03:00
|
|
|
{
|
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "not enough data!");
|
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
|
|
|
Stream_Read_UINT16(s, pdu.reserved); /* reserved (2 bytes) */
|
2019-02-27 18:36:15 +03:00
|
|
|
Stream_Read_UINT32(s, pdu.outputOriginX); /* outputOriginX (4 bytes) */
|
|
|
|
Stream_Read_UINT32(s, pdu.outputOriginY); /* outputOriginY (4 bytes) */
|
2019-11-06 17:24:51 +03:00
|
|
|
Stream_Read_UINT32(s, pdu.targetWidth); /* targetWidth (4 bytes) */
|
|
|
|
Stream_Read_UINT32(s, pdu.targetHeight); /* targetHeight (4 bytes) */
|
|
|
|
DEBUG_RDPGFX(gfx->log,
|
|
|
|
"RecvMapSurfaceToScaledOutputPdu: surfaceId: %" PRIu16 " outputOriginX: %" PRIu32
|
|
|
|
" outputOriginY: %" PRIu32 " targetWidth: %" PRIu32 " targetHeight: %" PRIu32,
|
|
|
|
pdu.surfaceId, pdu.outputOriginX, pdu.outputOriginY, pdu.targetWidth,
|
|
|
|
pdu.targetHeight);
|
2019-02-27 18:36:15 +03:00
|
|
|
|
|
|
|
if (context)
|
|
|
|
{
|
|
|
|
IFCALLRET(context->MapSurfaceToScaledOutput, error, context, &pdu);
|
|
|
|
|
|
|
|
if (error)
|
2019-11-06 17:24:51 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR,
|
|
|
|
"context->MapSurfaceToScaledOutput failed with error %" PRIu32 "", error);
|
2019-02-27 18:36:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2019-11-06 17:24:51 +03:00
|
|
|
static UINT rdpgfx_recv_map_surface_to_window_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s)
|
2014-06-04 03:48:47 +04:00
|
|
|
{
|
|
|
|
RDPGFX_MAP_SURFACE_TO_WINDOW_PDU pdu;
|
2019-11-06 17:24:51 +03: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
|
|
|
|
2019-11-06 17:24:51 +03: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) */
|
2014-06-04 03:48:47 +04:00
|
|
|
Stream_Read_UINT32(s, pdu.mappedHeight); /* mappedHeight (4 bytes) */
|
2019-11-06 17:24:51 +03:00
|
|
|
DEBUG_RDPGFX(gfx->log,
|
|
|
|
"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)
|
2019-11-06 17:24:51 +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
|
|
|
}
|
|
|
|
|
2019-02-27 18:36:15 +03:00
|
|
|
static UINT rdpgfx_recv_map_surface_to_scaled_window_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
|
2019-11-06 17:24:51 +03:00
|
|
|
wStream* s)
|
2019-02-27 18:36:15 +03:00
|
|
|
{
|
|
|
|
RDPGFX_MAP_SURFACE_TO_SCALED_WINDOW_PDU pdu;
|
2019-11-06 17:24:51 +03:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
|
|
|
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
2019-02-27 18:36:15 +03:00
|
|
|
UINT error = CHANNEL_RC_OK;
|
|
|
|
|
2019-05-05 12:34:57 +03:00
|
|
|
if (Stream_GetRemainingLength(s) < 26)
|
2019-02-27 18:36:15 +03:00
|
|
|
{
|
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "not enough data!");
|
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
|
|
|
|
2019-11-06 17:24:51 +03: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) */
|
2019-02-27 18:36:15 +03:00
|
|
|
Stream_Read_UINT32(s, pdu.mappedHeight); /* mappedHeight (4 bytes) */
|
2019-11-06 17:24:51 +03:00
|
|
|
Stream_Read_UINT32(s, pdu.targetWidth); /* targetWidth (4 bytes) */
|
2019-05-05 12:34:57 +03:00
|
|
|
Stream_Read_UINT32(s, pdu.targetHeight); /* targetHeight (4 bytes) */
|
2019-11-06 17:24:51 +03:00
|
|
|
DEBUG_RDPGFX(gfx->log,
|
|
|
|
"RecvMapSurfaceToScaledWindowPdu: surfaceId: %" PRIu16 " windowId: 0x%016" PRIX64
|
|
|
|
" mappedWidth: %" PRIu32 " mappedHeight: %" PRIu32 " targetWidth: %" PRIu32
|
|
|
|
" targetHeight: %" PRIu32 "",
|
|
|
|
pdu.surfaceId, pdu.windowId, pdu.mappedWidth, pdu.mappedHeight, pdu.targetWidth,
|
|
|
|
pdu.targetHeight);
|
2019-02-27 18:36:15 +03:00
|
|
|
|
|
|
|
if (context && context->MapSurfaceToScaledWindow)
|
|
|
|
{
|
|
|
|
IFCALLRET(context->MapSurfaceToScaledWindow, error, context, &pdu);
|
|
|
|
|
|
|
|
if (error)
|
2019-11-06 17:24:51 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR,
|
|
|
|
"context->MapSurfaceToScaledWindow failed with error %" PRIu32 "", error);
|
2019-02-27 18:36:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
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;
|
2019-11-06 17:24:51 +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)))
|
|
|
|
{
|
2019-11-06 17:24:51 +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
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
DEBUG_RDPGFX(
|
|
|
|
gfx->log, "cmdId: %s (0x%04" PRIX16 ") flags: 0x%04" PRIX16 " pduLength: %" PRIu32 "",
|
|
|
|
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)))
|
2019-11-06 17:24:51 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR,
|
|
|
|
"rdpgfx_recv_wire_to_surface_1_pdu failed with error %" PRIu32 "!",
|
2019-02-27 18:36:15 +03:00
|
|
|
error);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
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)))
|
2019-11-06 17:24:51 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR,
|
|
|
|
"rdpgfx_recv_wire_to_surface_2_pdu failed with error %" PRIu32 "!",
|
2019-02-27 18:36:15 +03:00
|
|
|
error);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
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)))
|
2019-02-27 18:36:15 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR,
|
2019-11-06 17:24:51 +03:00
|
|
|
"rdpgfx_recv_delete_encoding_context_pdu failed with error %" PRIu32 "!",
|
2019-02-27 18:36:15 +03:00
|
|
|
error);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
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)))
|
2019-11-06 17:24:51 +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)))
|
2019-11-06 17:24:51 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR,
|
|
|
|
"rdpgfx_recv_surface_to_surface_pdu failed with error %" PRIu32 "!",
|
2019-02-27 18:36:15 +03:00
|
|
|
error);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
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)))
|
2019-11-06 17:24:51 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR,
|
|
|
|
"rdpgfx_recv_surface_to_cache_pdu failed with error %" PRIu32 "!",
|
2019-02-27 18:36:15 +03:00
|
|
|
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)))
|
2019-11-06 17:24:51 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR,
|
|
|
|
"rdpgfx_recv_cache_to_surface_pdu failed with error %" PRIu32 "!",
|
2019-02-27 18:36:15 +03:00
|
|
|
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)))
|
2019-11-06 17:24:51 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR,
|
|
|
|
"rdpgfx_recv_evict_cache_entry_pdu failed with error %" PRIu32 "!",
|
2019-02-27 18:36:15 +03:00
|
|
|
error);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
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)))
|
2019-11-06 17:24:51 +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)))
|
2019-11-06 17:24:51 +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)))
|
2019-11-06 17:24:51 +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)))
|
2019-11-06 17:24:51 +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)))
|
2019-11-06 17:24:51 +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)))
|
2019-02-27 18:36:15 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR,
|
2019-11-06 17:24:51 +03:00
|
|
|
"rdpgfx_recv_map_surface_to_output_pdu failed with error %" PRIu32 "!",
|
2019-02-27 18:36:15 +03:00
|
|
|
error);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
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)))
|
2019-11-06 17:24:51 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR,
|
|
|
|
"rdpgfx_recv_cache_import_reply_pdu failed with error %" PRIu32 "!",
|
2019-02-27 18:36:15 +03:00
|
|
|
error);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
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)))
|
2019-11-06 17:24:51 +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)))
|
2019-02-27 18:36:15 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR,
|
2019-11-06 17:24:51 +03:00
|
|
|
"rdpgfx_recv_map_surface_to_window_pdu failed with error %" PRIu32 "!",
|
2019-02-27 18:36:15 +03:00
|
|
|
error);
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RDPGFX_CMDID_MAPSURFACETOSCALEDWINDOW:
|
|
|
|
if ((error = rdpgfx_recv_map_surface_to_scaled_window_pdu(callback, s)))
|
|
|
|
WLog_Print(gfx->log, WLOG_ERROR,
|
2019-11-06 17:24:51 +03:00
|
|
|
"rdpgfx_recv_map_surface_to_scaled_window_pdu failed with error %" PRIu32
|
|
|
|
"!",
|
2019-02-27 18:36:15 +03:00
|
|
|
error);
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RDPGFX_CMDID_MAPSURFACETOSCALEDOUTPUT:
|
|
|
|
if ((error = rdpgfx_recv_map_surface_to_scaled_output_pdu(callback, s)))
|
|
|
|
WLog_Print(gfx->log, WLOG_ERROR,
|
2019-11-06 17:24:51 +03:00
|
|
|
"rdpgfx_recv_map_surface_to_scaled_output_pdu failed with error %" PRIu32
|
|
|
|
"!",
|
2019-02-27 18:36:15 +03:00
|
|
|
error);
|
2016-08-04 17:28:38 +03:00
|
|
|
|
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
|
|
|
{
|
2020-03-03 20:18:00 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "Error while processing GFX cmdId: %s (0x%04" PRIX16 ")",
|
2019-02-27 18:36:15 +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))
|
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR,
|
|
|
|
"Unexpected gfx pdu end: Actual: %d, Expected: %" PRIu32 "", 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
|
|
|
|
*/
|
2019-11-06 17:24:51 +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;
|
2019-11-06 17:24:51 +03:00
|
|
|
RDPGFX_CHANNEL_CALLBACK* callback = (RDPGFX_CHANNEL_CALLBACK*)pChannelCallback;
|
|
|
|
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),
|
2019-02-27 18:36:15 +03:00
|
|
|
&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);
|
2019-02-27 18:36:15 +03:00
|
|
|
|
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)))
|
|
|
|
{
|
2019-11-06 17:24:51 +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
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
RDPGFX_CHANNEL_CALLBACK* callback = (RDPGFX_CHANNEL_CALLBACK*)pChannelCallback;
|
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
|
|
|
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
2019-05-05 15:31:18 +03:00
|
|
|
UINT error = CHANNEL_RC_OK;
|
|
|
|
BOOL do_caps_advertise = TRUE;
|
|
|
|
gfx->sendFrameAcks = TRUE;
|
|
|
|
|
|
|
|
if (context)
|
|
|
|
{
|
|
|
|
IFCALLRET(context->OnOpen, error, context, &do_caps_advertise, &gfx->sendFrameAcks);
|
|
|
|
|
|
|
|
if (error)
|
2019-11-06 17:24:51 +03:00
|
|
|
WLog_Print(gfx->log, WLOG_ERROR, "context->OnOpen failed with error %" PRIu32 "",
|
|
|
|
error);
|
2019-05-05 15:31:18 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (do_caps_advertise)
|
|
|
|
error = rdpgfx_send_supported_caps(callback);
|
|
|
|
|
|
|
|
return error;
|
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
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
RDPGFX_CHANNEL_CALLBACK* callback = (RDPGFX_CHANNEL_CALLBACK*)pChannelCallback;
|
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
|
|
|
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
2020-01-16 17:23:35 +03:00
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
DEBUG_RDPGFX(gfx->log, "OnClose");
|
2020-01-16 17:23:35 +03:00
|
|
|
free_surfaces(context, gfx->SurfaceTable);
|
2020-03-02 11:54:35 +03:00
|
|
|
evict_cache_slots(context, gfx->MaxCacheSlots, gfx->CacheSlots);
|
2020-01-16 17:23:35 +03:00
|
|
|
|
|
|
|
if (gfx->listener_callback)
|
|
|
|
{
|
|
|
|
free(gfx->listener_callback);
|
|
|
|
gfx->listener_callback = NULL;
|
|
|
|
}
|
|
|
|
|
2013-10-22 06:53:55 +04:00
|
|
|
free(callback);
|
2015-07-08 18:17:56 +03:00
|
|
|
gfx->UnacknowledgedFrames = 0;
|
|
|
|
gfx->TotalDecodedFrames = 0;
|
|
|
|
|
2019-05-05 15:31:18 +03:00
|
|
|
if (context)
|
|
|
|
{
|
|
|
|
IFCALL(context->OnClose, context);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
*/
|
2019-11-06 17:24:51 +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;
|
2019-11-06 17:24:51 +03:00
|
|
|
callback = (RDPGFX_CHANNEL_CALLBACK*)calloc(1, sizeof(RDPGFX_CHANNEL_CALLBACK));
|
2019-02-27 18:36:15 +03:00
|
|
|
|
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;
|
2019-11-06 17:24:51 +03:00
|
|
|
*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
|
|
|
|
*/
|
2019-11-06 17:24:51 +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;
|
2019-11-06 17:24:51 +03:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)pPlugin;
|
|
|
|
gfx->listener_callback = (RDPGFX_LISTENER_CALLBACK*)calloc(1, sizeof(RDPGFX_LISTENER_CALLBACK));
|
2019-02-27 18:36:15 +03:00
|
|
|
|
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,
|
2020-05-12 11:54:07 +03:00
|
|
|
&gfx->listener_callback->iface, &(gfx->listener));
|
2014-06-05 06:06:29 +04:00
|
|
|
gfx->listener->pInterface = gfx->iface.pInterface;
|
2019-06-04 10:28:03 +03:00
|
|
|
DEBUG_RDPGFX(gfx->log, "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
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)pPlugin;
|
|
|
|
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
2019-06-04 10:28:03 +03:00
|
|
|
DEBUG_RDPGFX(gfx->log, "Terminated");
|
2020-05-12 11:54:07 +03:00
|
|
|
if (gfx && gfx->listener_callback)
|
|
|
|
{
|
|
|
|
IWTSVirtualChannelManager* mgr = gfx->listener_callback->channel_mgr;
|
|
|
|
if (mgr)
|
2020-05-12 15:26:45 +03:00
|
|
|
IFCALL(mgr->DestroyListener, mgr, gfx->listener);
|
2020-05-12 11:54:07 +03:00
|
|
|
}
|
2019-10-22 15:58:05 +03:00
|
|
|
rdpgfx_client_context_free(context);
|
2020-01-05 08:54: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
|
|
|
|
*/
|
2019-11-06 17:24:51 +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;
|
2019-11-06 17:24:51 +03:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)context->handle;
|
|
|
|
key = ((ULONG_PTR)surfaceId) + 1;
|
2014-06-12 01:48:04 +04:00
|
|
|
|
|
|
|
if (pData)
|
2019-11-06 17:24:51 +03:00
|
|
|
HashTable_Add(gfx->SurfaceTable, (void*)key, pData);
|
2014-06-12 01:48:04 +04:00
|
|
|
else
|
2019-11-06 17:24:51 +03:00
|
|
|
HashTable_Remove(gfx->SurfaceTable, (void*)key);
|
2014-06-12 01:48:04 +04:00
|
|
|
|
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
|
|
|
|
*/
|
2019-11-06 17:24:51 +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;
|
2019-11-06 17:24:51 +03:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)context->handle;
|
2015-02-11 00:32:07 +03:00
|
|
|
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
|
|
|
|
2019-11-06 17:24:51 +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
|
|
|
}
|
|
|
|
|
2019-11-06 17:24:51 +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;
|
2019-11-06 17:24:51 +03:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)context->handle;
|
|
|
|
key = ((ULONG_PTR)surfaceId) + 1;
|
|
|
|
pData = HashTable_GetItemValue(gfx->SurfaceTable, (void*)key);
|
2014-06-12 01:48:04 +04:00
|
|
|
return pData;
|
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2019-11-06 17:24:51 +03:00
|
|
|
static UINT rdpgfx_set_cache_slot_data(RdpgfxClientContext* context, UINT16 cacheSlot, void* pData)
|
2014-06-13 16:36:09 +04:00
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)context->handle;
|
2014-06-13 16:36:09 +04:00
|
|
|
|
2020-02-27 18:43:01 +03:00
|
|
|
/* Microsoft uses 1-based indexing for the egfx bitmap cache ! */
|
2020-03-02 11:54:35 +03:00
|
|
|
if (cacheSlot == 0 || cacheSlot > gfx->MaxCacheSlots)
|
2017-10-10 18:12:16 +03:00
|
|
|
{
|
2020-03-02 11:54:35 +03:00
|
|
|
WLog_ERR(TAG, "%s: invalid cache slot %" PRIu16 ", must be between 1 and %" PRIu16 "",
|
|
|
|
__FUNCTION__, cacheSlot, gfx->MaxCacheSlots);
|
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
|
|
|
|
2020-02-27 18:43:01 +03:00
|
|
|
gfx->CacheSlots[cacheSlot - 1] = 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;
|
2019-11-06 17:24:51 +03:00
|
|
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)context->handle;
|
2014-06-13 16:36:09 +04:00
|
|
|
|
2020-02-27 18:43:01 +03:00
|
|
|
/* Microsoft uses 1-based indexing for the egfx bitmap cache ! */
|
2020-03-02 11:54:35 +03:00
|
|
|
if (cacheSlot == 0 || cacheSlot > gfx->MaxCacheSlots)
|
2017-10-10 18:12:16 +03:00
|
|
|
{
|
2020-03-02 11:54:35 +03:00
|
|
|
WLog_ERR(TAG, "%s: invalid cache slot %" PRIu16 ", must be between 1 and %" PRIu16 "",
|
|
|
|
__FUNCTION__, cacheSlot, gfx->MaxCacheSlots);
|
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
|
|
|
|
2020-02-27 18:43:01 +03:00
|
|
|
pData = gfx->CacheSlots[cacheSlot - 1];
|
2014-06-13 16:36:09 +04:00
|
|
|
return pData;
|
|
|
|
}
|
|
|
|
|
2016-06-15 14:36:27 +03:00
|
|
|
#ifdef BUILTIN_CHANNELS
|
2019-11-06 17:24:51 +03:00
|
|
|
#define DVCPluginEntry rdpgfx_DVCPluginEntry
|
2016-02-29 17:18:19 +03:00
|
|
|
#else
|
2019-11-06 17:24:51 +03:00
|
|
|
#define DVCPluginEntry FREERDP_API DVCPluginEntry
|
2014-10-27 18:33:51 +03:00
|
|
|
#endif
|
|
|
|
|
2019-10-22 15:58:05 +03:00
|
|
|
RdpgfxClientContext* rdpgfx_client_context_new(rdpSettings* settings)
|
|
|
|
{
|
|
|
|
RDPGFX_PLUGIN* gfx;
|
|
|
|
RdpgfxClientContext* context;
|
|
|
|
|
|
|
|
gfx = (RDPGFX_PLUGIN*)calloc(1, sizeof(RDPGFX_PLUGIN));
|
|
|
|
|
|
|
|
if (!gfx)
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "calloc failed!");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
gfx->log = WLog_Get(TAG);
|
|
|
|
|
|
|
|
if (!gfx->log)
|
|
|
|
{
|
|
|
|
free(gfx);
|
|
|
|
WLog_ERR(TAG, "Failed to acquire reference to WLog %s", TAG);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
gfx->settings = settings;
|
|
|
|
gfx->rdpcontext = ((freerdp*)gfx->settings->instance)->context;
|
|
|
|
gfx->SurfaceTable = HashTable_New(TRUE);
|
|
|
|
|
|
|
|
if (!gfx->SurfaceTable)
|
|
|
|
{
|
|
|
|
free(gfx);
|
|
|
|
WLog_ERR(TAG, "HashTable_New failed!");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
gfx->AVC444 = gfx->settings->GfxAVC444;
|
|
|
|
gfx->SendQoeAck = gfx->settings->GfxSendQoeAck;
|
|
|
|
gfx->capsFilter = gfx->settings->GfxCapsFilter;
|
|
|
|
|
|
|
|
if (gfx->H264)
|
|
|
|
gfx->SmallCache = TRUE;
|
|
|
|
|
2020-03-02 11:54:35 +03:00
|
|
|
gfx->MaxCacheSlots = gfx->SmallCache ? 4096 : 25600;
|
2019-10-22 15:58:05 +03:00
|
|
|
context = (RdpgfxClientContext*)calloc(1, sizeof(RdpgfxClientContext));
|
|
|
|
|
|
|
|
if (!context)
|
|
|
|
{
|
|
|
|
free(gfx);
|
|
|
|
WLog_ERR(TAG, "calloc failed!");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
context->handle = (void*)gfx;
|
|
|
|
context->GetSurfaceIds = rdpgfx_get_surface_ids;
|
|
|
|
context->SetSurfaceData = rdpgfx_set_surface_data;
|
|
|
|
context->GetSurfaceData = rdpgfx_get_surface_data;
|
|
|
|
context->SetCacheSlotData = rdpgfx_set_cache_slot_data;
|
|
|
|
context->GetCacheSlotData = rdpgfx_get_cache_slot_data;
|
|
|
|
context->CapsAdvertise = rdpgfx_send_caps_advertise_pdu;
|
|
|
|
context->FrameAcknowledge = rdpgfx_send_frame_acknowledge_pdu;
|
|
|
|
context->CacheImportOffer = rdpgfx_send_cache_import_offer_pdu;
|
|
|
|
context->QoeFrameAcknowledge = rdpgfx_send_qoe_frame_acknowledge_pdu;
|
|
|
|
|
|
|
|
gfx->iface.pInterface = (void*)context;
|
|
|
|
gfx->zgfx = zgfx_context_new(FALSE);
|
|
|
|
|
|
|
|
if (!gfx->zgfx)
|
|
|
|
{
|
|
|
|
free(gfx);
|
|
|
|
free(context);
|
|
|
|
WLog_ERR(TAG, "zgfx_context_new failed!");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return context;
|
|
|
|
}
|
|
|
|
|
|
|
|
void rdpgfx_client_context_free(RdpgfxClientContext* context)
|
|
|
|
{
|
2020-01-05 08:54:26 +03:00
|
|
|
|
2019-10-22 15:58:05 +03:00
|
|
|
RDPGFX_PLUGIN* gfx;
|
|
|
|
|
|
|
|
if (!context)
|
|
|
|
return;
|
|
|
|
|
|
|
|
gfx = (RDPGFX_PLUGIN*)context->handle;
|
|
|
|
|
2020-01-16 17:23:35 +03:00
|
|
|
free_surfaces(context, gfx->SurfaceTable);
|
2020-03-02 11:54:35 +03:00
|
|
|
evict_cache_slots(context, gfx->MaxCacheSlots, gfx->CacheSlots);
|
2020-01-05 08:54:26 +03:00
|
|
|
|
2019-10-22 15:58:05 +03:00
|
|
|
if (gfx->listener_callback)
|
|
|
|
{
|
|
|
|
free(gfx->listener_callback);
|
|
|
|
gfx->listener_callback = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gfx->zgfx)
|
|
|
|
{
|
|
|
|
zgfx_context_free(gfx->zgfx);
|
|
|
|
gfx->zgfx = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
HashTable_Free(gfx->SurfaceTable);
|
|
|
|
free(context);
|
|
|
|
free(gfx);
|
|
|
|
}
|
|
|
|
|
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;
|
2019-11-06 17:24:51 +03: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
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
context =
|
|
|
|
rdpgfx_client_context_new((rdpSettings*)pEntryPoints->GetRdpSettings(pEntryPoints));
|
2014-06-03 08:05:43 +04:00
|
|
|
|
2019-10-22 15:58:05 +03:00
|
|
|
if (!context)
|
2015-06-09 16:22:26 +03:00
|
|
|
{
|
2019-10-22 15:58:05 +03:00
|
|
|
WLog_ERR(TAG, "rdpgfx_client_context_new failed!");
|
2015-06-09 16:22:26 +03:00
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
2013-10-22 06:53:55 +04:00
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
gfx = (RDPGFX_PLUGIN*)context->handle;
|
2019-02-27 18:36:15 +03:00
|
|
|
|
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;
|
2014-07-29 00:47:42 +04:00
|
|
|
|
2019-11-06 17:24:51 +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
|
|
|
}
|