Blame server/shadow/shadow_client.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 * Copyright 2017 Armin Novak <armin.novak@thincast.com>
Packit 1fb8d4
 * Copyright 2017 Thincast Technologies GmbH
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
#include <winpr/file.h>
Packit 1fb8d4
#include <winpr/path.h>
Packit 1fb8d4
#include <winpr/synch.h>
Packit 1fb8d4
#include <winpr/thread.h>
Packit 1fb8d4
#include <winpr/sysinfo.h>
Packit 1fb8d4
#include <winpr/interlocked.h>
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/log.h>
Packit 1fb8d4
Packit 1fb8d4
#include "shadow.h"
Packit 1fb8d4
Packit 1fb8d4
#define TAG CLIENT_TAG("shadow")
Packit 1fb8d4
Packit 1fb8d4
struct _SHADOW_GFX_STATUS
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL gfxOpened;
Packit 1fb8d4
	BOOL gfxSurfaceCreated;
Packit 1fb8d4
};
Packit 1fb8d4
typedef struct _SHADOW_GFX_STATUS SHADOW_GFX_STATUS;
Packit 1fb8d4
Packit 1fb8d4
static INLINE BOOL shadow_client_rdpgfx_new_surface(rdpShadowClient* client)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT error = CHANNEL_RC_OK;
Packit 1fb8d4
	RDPGFX_CREATE_SURFACE_PDU createSurface;
Packit 1fb8d4
	RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU surfaceToOutput;
Packit 1fb8d4
	RdpgfxServerContext* context = client->rdpgfx;
Packit 1fb8d4
	rdpSettings* settings = ((rdpContext*) client)->settings;
Packit 1fb8d4
	createSurface.width = settings->DesktopWidth;
Packit 1fb8d4
	createSurface.height = settings->DesktopHeight;
Packit 1fb8d4
	createSurface.pixelFormat = GFX_PIXEL_FORMAT_XRGB_8888;
Packit 1fb8d4
	createSurface.surfaceId = 0;
Packit 1fb8d4
	surfaceToOutput.outputOriginX = 0;
Packit 1fb8d4
	surfaceToOutput.outputOriginY = 0;
Packit 1fb8d4
	surfaceToOutput.surfaceId = 0;
Packit 1fb8d4
	surfaceToOutput.reserved = 0;
Packit 1fb8d4
	IFCALLRET(context->CreateSurface, error, context, &createSurface);
Packit 1fb8d4
Packit 1fb8d4
	if (error)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "CreateSurface failed with error %"PRIu32"", error);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	IFCALLRET(context->MapSurfaceToOutput, error, context, &surfaceToOutput);
Packit 1fb8d4
Packit 1fb8d4
	if (error)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "MapSurfaceToOutput failed with error %"PRIu32"", error);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static INLINE BOOL shadow_client_rdpgfx_release_surface(rdpShadowClient* client)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT error = CHANNEL_RC_OK;
Packit 1fb8d4
	RDPGFX_DELETE_SURFACE_PDU pdu;
Packit 1fb8d4
	RdpgfxServerContext* context = client->rdpgfx;
Packit 1fb8d4
	pdu.surfaceId = 0;
Packit 1fb8d4
	IFCALLRET(context->DeleteSurface, error, context, &pdu);
Packit 1fb8d4
Packit 1fb8d4
	if (error)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "DeleteSurface failed with error %"PRIu32"", error);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static INLINE BOOL shadow_client_rdpgfx_reset_graphic(rdpShadowClient* client)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT error = CHANNEL_RC_OK;
Packit 1fb8d4
	RDPGFX_RESET_GRAPHICS_PDU pdu;
Packit 1fb8d4
	RdpgfxServerContext* context = client->rdpgfx;
Packit 1fb8d4
	rdpSettings* settings = ((rdpContext*) client)->settings;
Packit 1fb8d4
	pdu.width = settings->DesktopWidth;
Packit 1fb8d4
	pdu.height = settings->DesktopHeight;
Packit 1fb8d4
	pdu.monitorCount = client->subsystem->numMonitors;
Packit 1fb8d4
	pdu.monitorDefArray = client->subsystem->monitors;
Packit 1fb8d4
	IFCALLRET(context->ResetGraphics, error, context, &pdu);
Packit 1fb8d4
Packit 1fb8d4
	if (error)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "ResetGraphics failed with error %"PRIu32"", error);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static INLINE void shadow_client_free_queued_message(void* obj)
Packit 1fb8d4
{
Packit 1fb8d4
	wMessage* message = (wMessage*)obj;
Packit 1fb8d4
Packit 1fb8d4
	if (message->Free)
Packit 1fb8d4
	{
Packit 1fb8d4
		message->Free(message);
Packit 1fb8d4
		message->Free = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL shadow_client_context_new(freerdp_peer* peer,
Packit 1fb8d4
                                      rdpShadowClient* client)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpSettings* settings;
Packit 1fb8d4
	rdpShadowServer* server;
Packit 1fb8d4
	const wObject cb = { NULL, NULL, NULL, shadow_client_free_queued_message, NULL };
Packit 1fb8d4
	server = (rdpShadowServer*) peer->ContextExtra;
Packit 1fb8d4
	client->server = server;
Packit 1fb8d4
	client->subsystem = server->subsystem;
Packit 1fb8d4
	settings = peer->settings;
Packit 1fb8d4
	settings->ColorDepth = 32;
Packit 1fb8d4
	settings->NSCodec = TRUE;
Packit 1fb8d4
	settings->RemoteFxCodec = TRUE;
Packit 1fb8d4
	settings->BitmapCacheV3Enabled = TRUE;
Packit 1fb8d4
	settings->FrameMarkerCommandEnabled = TRUE;
Packit 1fb8d4
	settings->SurfaceFrameMarkerEnabled = TRUE;
Packit 1fb8d4
	settings->SupportGraphicsPipeline = TRUE;
Packit 1fb8d4
	settings->GfxH264 = FALSE;
Packit 1fb8d4
	settings->DrawAllowSkipAlpha = TRUE;
Packit 1fb8d4
	settings->DrawAllowColorSubsampling = TRUE;
Packit 1fb8d4
	settings->DrawAllowDynamicColorFidelity = TRUE;
Packit 1fb8d4
	settings->CompressionLevel = PACKET_COMPR_TYPE_RDP6;
Packit 1fb8d4
Packit 1fb8d4
	if (!(settings->CertificateFile = _strdup(server->CertificateFile)))
Packit 1fb8d4
		goto fail_cert_file;
Packit 1fb8d4
Packit 1fb8d4
	if (!(settings->PrivateKeyFile = _strdup(server->PrivateKeyFile)))
Packit 1fb8d4
		goto fail_privkey_file;
Packit 1fb8d4
Packit 1fb8d4
	if (!(settings->RdpKeyFile = _strdup(settings->PrivateKeyFile)))
Packit 1fb8d4
		goto fail_rdpkey_file;
Packit 1fb8d4
Packit 1fb8d4
	if (server->ipcSocket)
Packit 1fb8d4
	{
Packit 1fb8d4
		settings->LyncRdpMode = TRUE;
Packit 1fb8d4
		settings->CompressionEnabled = FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	client->inLobby = TRUE;
Packit 1fb8d4
	client->mayView = server->mayView;
Packit 1fb8d4
	client->mayInteract = server->mayInteract;
Packit 1fb8d4
Packit 1fb8d4
	if (!InitializeCriticalSectionAndSpinCount(&(client->lock), 4000))
Packit 1fb8d4
		goto fail_client_lock;
Packit 1fb8d4
Packit 1fb8d4
	region16_init(&(client->invalidRegion));
Packit 1fb8d4
	client->vcm = WTSOpenServerA((LPSTR) peer->context);
Packit 1fb8d4
Packit 1fb8d4
	if (!client->vcm || client->vcm == INVALID_HANDLE_VALUE)
Packit 1fb8d4
		goto fail_open_server;
Packit 1fb8d4
Packit 1fb8d4
	if (!(client->MsgQueue = MessageQueue_New(&cb)))
Packit 1fb8d4
		goto fail_message_queue;
Packit 1fb8d4
Packit 1fb8d4
	if (!(client->encoder = shadow_encoder_new(client)))
Packit 1fb8d4
		goto fail_encoder_new;
Packit 1fb8d4
Packit 1fb8d4
	if (ArrayList_Add(server->clients, (void*) client) >= 0)
Packit 1fb8d4
		return TRUE;
Packit 1fb8d4
Packit 1fb8d4
	shadow_encoder_free(client->encoder);
Packit 1fb8d4
	client->encoder = NULL;
Packit 1fb8d4
fail_encoder_new:
Packit 1fb8d4
	MessageQueue_Free(client->MsgQueue);
Packit 1fb8d4
	client->MsgQueue = NULL;
Packit 1fb8d4
fail_message_queue:
Packit 1fb8d4
	WTSCloseServer((HANDLE) client->vcm);
Packit 1fb8d4
	client->vcm = NULL;
Packit 1fb8d4
fail_open_server:
Packit 1fb8d4
	DeleteCriticalSection(&(client->lock));
Packit 1fb8d4
fail_client_lock:
Packit 1fb8d4
	free(settings->RdpKeyFile);
Packit 1fb8d4
	settings->RdpKeyFile = NULL;
Packit 1fb8d4
fail_rdpkey_file:
Packit 1fb8d4
	free(settings->PrivateKeyFile);
Packit 1fb8d4
	settings->PrivateKeyFile = NULL;
Packit 1fb8d4
fail_privkey_file:
Packit 1fb8d4
	free(settings->CertificateFile);
Packit 1fb8d4
	settings->CertificateFile = NULL;
Packit 1fb8d4
fail_cert_file:
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void shadow_client_context_free(freerdp_peer* peer,
Packit 1fb8d4
                                       rdpShadowClient* client)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpShadowServer* server = client->server;
Packit 1fb8d4
	ArrayList_Remove(server->clients, (void*) client);
Packit 1fb8d4
Packit 1fb8d4
	if (client->encoder)
Packit 1fb8d4
	{
Packit 1fb8d4
		shadow_encoder_free(client->encoder);
Packit 1fb8d4
		client->encoder = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* Clear queued messages and free resource */
Packit 1fb8d4
	MessageQueue_Clear(client->MsgQueue);
Packit 1fb8d4
	MessageQueue_Free(client->MsgQueue);
Packit 1fb8d4
	WTSCloseServer((HANDLE) client->vcm);
Packit 1fb8d4
	client->vcm = NULL;
Packit 1fb8d4
	region16_uninit(&(client->invalidRegion));
Packit 1fb8d4
	DeleteCriticalSection(&(client->lock));
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void shadow_client_message_free(wMessage* message)
Packit 1fb8d4
{
Packit 1fb8d4
	switch (message->id)
Packit 1fb8d4
	{
Packit 1fb8d4
		case SHADOW_MSG_IN_REFRESH_REQUEST_ID:
Packit 1fb8d4
			/* Refresh request do not have message to free */
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			WLog_ERR(TAG, "Unknown message id: %"PRIu32"", message->id);
Packit 1fb8d4
			free(message->wParam);
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static INLINE void shadow_client_mark_invalid(rdpShadowClient* client,
Packit 1fb8d4
        int numRects, const RECTANGLE_16* rects)
Packit 1fb8d4
{
Packit 1fb8d4
	int index;
Packit 1fb8d4
	RECTANGLE_16 screenRegion;
Packit 1fb8d4
	rdpSettings* settings = ((rdpContext*) client)->settings;
Packit 1fb8d4
	EnterCriticalSection(&(client->lock));
Packit 1fb8d4
Packit 1fb8d4
	/* Mark client invalid region. No rectangle means full screen */
Packit 1fb8d4
	if (numRects > 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		for (index = 0; index < numRects; index++)
Packit 1fb8d4
		{
Packit 1fb8d4
			region16_union_rect(&(client->invalidRegion), &(client->invalidRegion),
Packit 1fb8d4
			                    &rects[index]);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		screenRegion.left = 0;
Packit 1fb8d4
		screenRegion.top = 0;
Packit 1fb8d4
		screenRegion.right = settings->DesktopWidth;
Packit 1fb8d4
		screenRegion.bottom = settings->DesktopHeight;
Packit 1fb8d4
		region16_union_rect(&(client->invalidRegion),
Packit 1fb8d4
		                    &(client->invalidRegion), &screenRegion);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	LeaveCriticalSection(&(client->lock));
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 * Recalculate client desktop size and update to rdpSettings
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return TRUE if width/height changed.
Packit 1fb8d4
 */
Packit 1fb8d4
static INLINE BOOL shadow_client_recalc_desktop_size(rdpShadowClient* client)
Packit 1fb8d4
{
Packit 1fb8d4
	int width, height;
Packit 1fb8d4
	rdpShadowServer* server = client->server;
Packit 1fb8d4
	rdpSettings* settings = client->context.settings;
Packit 1fb8d4
	RECTANGLE_16 viewport = {0, 0, server->surface->width, server->surface->height};
Packit 1fb8d4
Packit 1fb8d4
	if (server->shareSubRect)
Packit 1fb8d4
	{
Packit 1fb8d4
		rectangles_intersection(&viewport, &(server->subRect), &viewport);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	width = viewport.right - viewport.left;
Packit 1fb8d4
	height = viewport.bottom - viewport.top;
Packit 1fb8d4
Packit 1fb8d4
	if (settings->DesktopWidth != (UINT32)width
Packit 1fb8d4
	    || settings->DesktopHeight != (UINT32)height)
Packit 1fb8d4
	{
Packit 1fb8d4
		settings->DesktopWidth = width;
Packit 1fb8d4
		settings->DesktopHeight = height;
Packit 1fb8d4
		return TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL shadow_client_capabilities(freerdp_peer* peer)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpShadowSubsystem* subsystem;
Packit 1fb8d4
	rdpShadowClient* client;
Packit 1fb8d4
	BOOL ret = TRUE;
Packit 1fb8d4
	client = (rdpShadowClient*) peer->context;
Packit 1fb8d4
	subsystem = client->server->subsystem;
Packit 1fb8d4
	IFCALLRET(subsystem->ClientCapabilities, ret, subsystem, client);
Packit 1fb8d4
Packit 1fb8d4
	if (!ret)
Packit 1fb8d4
		WLog_WARN(TAG, "subsystem->ClientCapabilities failed");
Packit 1fb8d4
Packit 1fb8d4
	/* Recalculate desktop size regardless whether previous call fail
Packit 1fb8d4
	 * or not. Make sure we send correct width/height to client */
Packit 1fb8d4
	(void)shadow_client_recalc_desktop_size(client);
Packit 1fb8d4
	return ret;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL shadow_client_post_connect(freerdp_peer* peer)
Packit 1fb8d4
{
Packit 1fb8d4
	int authStatus;
Packit 1fb8d4
	rdpSettings* settings;
Packit 1fb8d4
	rdpShadowClient* client;
Packit 1fb8d4
	rdpShadowServer* server;
Packit 1fb8d4
	rdpShadowSubsystem* subsystem;
Packit 1fb8d4
	client = (rdpShadowClient*) peer->context;
Packit 1fb8d4
	settings = peer->settings;
Packit 1fb8d4
	server = client->server;
Packit 1fb8d4
	subsystem = server->subsystem;
Packit 1fb8d4
Packit 1fb8d4
	if (settings->ColorDepth == 24)
Packit 1fb8d4
		settings->ColorDepth = 16; /* disable 24bpp */
Packit 1fb8d4
Packit 1fb8d4
	if (settings->MultifragMaxRequestSize < 0x3F0000)
Packit 1fb8d4
		settings->NSCodec =
Packit 1fb8d4
		    FALSE; /* NSCodec compressor does not support fragmentation yet */
Packit 1fb8d4
Packit 1fb8d4
	WLog_INFO(TAG, "Client from %s is activated (%"PRIu32"x%"PRIu32"@%"PRIu32")",
Packit 1fb8d4
	          peer->hostname, settings->DesktopWidth,
Packit 1fb8d4
	          settings->DesktopHeight, settings->ColorDepth);
Packit 1fb8d4
Packit 1fb8d4
	/* Resize client if necessary */
Packit 1fb8d4
	if (shadow_client_recalc_desktop_size(client))
Packit 1fb8d4
	{
Packit 1fb8d4
		peer->update->DesktopResize(peer->update->context);
Packit 1fb8d4
		WLog_INFO(TAG, "Client from %s is resized (%"PRIu32"x%"PRIu32"@%"PRIu32")",
Packit 1fb8d4
		          peer->hostname, settings->DesktopWidth,
Packit 1fb8d4
		          settings->DesktopHeight, settings->ColorDepth);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (shadow_client_channels_post_connect(client) != CHANNEL_RC_OK)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	shadow_client_mark_invalid(client, 0, NULL);
Packit 1fb8d4
	authStatus = -1;
Packit 1fb8d4
Packit 1fb8d4
	if (settings->Username && settings->Password)
Packit 1fb8d4
		settings->AutoLogonEnabled = TRUE;
Packit 1fb8d4
Packit 1fb8d4
	if (server->authentication && !settings->NlaSecurity)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (subsystem->Authenticate)
Packit 1fb8d4
		{
Packit 1fb8d4
			authStatus = subsystem->Authenticate(subsystem, client,
Packit 1fb8d4
			                                     settings->Username, settings->Domain, settings->Password);
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (authStatus < 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "client authentication failure: %d", authStatus);
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (subsystem->ClientConnect)
Packit 1fb8d4
	{
Packit 1fb8d4
		return subsystem->ClientConnect(subsystem, client);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/* Convert rects in sub rect coordinate to client/surface coordinate */
Packit 1fb8d4
static INLINE void shadow_client_convert_rects(rdpShadowClient* client,
Packit 1fb8d4
        RECTANGLE_16* dst, const RECTANGLE_16* src, UINT32 numRects)
Packit 1fb8d4
{
Packit 1fb8d4
	if (client->server->shareSubRect)
Packit 1fb8d4
	{
Packit 1fb8d4
		int i = 0;
Packit 1fb8d4
		UINT16 offsetX = client->server->subRect.left;
Packit 1fb8d4
		UINT16 offsetY = client->server->subRect.top;
Packit 1fb8d4
Packit 1fb8d4
		for (i = 0; i < numRects; i++)
Packit 1fb8d4
		{
Packit 1fb8d4
			dst[i].left = src[i].left + offsetX;
Packit 1fb8d4
			dst[i].right = src[i].right + offsetX;
Packit 1fb8d4
			dst[i].top = src[i].top + offsetY;
Packit 1fb8d4
			dst[i].bottom = src[i].bottom + offsetY;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		if (src != dst)
Packit 1fb8d4
		{
Packit 1fb8d4
			CopyMemory(dst, src, numRects * sizeof(RECTANGLE_16));
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL shadow_client_refresh_request(rdpShadowClient* client)
Packit 1fb8d4
{
Packit 1fb8d4
	wMessage message = { 0 };
Packit 1fb8d4
	wMessagePipe* MsgPipe = client->subsystem->MsgPipe;
Packit 1fb8d4
	message.id = SHADOW_MSG_IN_REFRESH_REQUEST_ID;
Packit 1fb8d4
	message.wParam = NULL;
Packit 1fb8d4
	message.lParam = NULL;
Packit 1fb8d4
	message.context = (void*) client;
Packit 1fb8d4
	message.Free = NULL;
Packit 1fb8d4
	return MessageQueue_Dispatch(MsgPipe->In, &message);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL shadow_client_refresh_rect(rdpShadowClient* client, BYTE count,
Packit 1fb8d4
                                       RECTANGLE_16* areas)
Packit 1fb8d4
{
Packit 1fb8d4
	RECTANGLE_16* rects;
Packit 1fb8d4
Packit 1fb8d4
	/* It is invalid if we have area count but no actual area */
Packit 1fb8d4
	if (count && !areas)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (count)
Packit 1fb8d4
	{
Packit 1fb8d4
		rects = (RECTANGLE_16*) calloc(count, sizeof(RECTANGLE_16));
Packit 1fb8d4
Packit 1fb8d4
		if (!rects)
Packit 1fb8d4
		{
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		shadow_client_convert_rects(client, rects, areas, count);
Packit 1fb8d4
		shadow_client_mark_invalid(client, count, rects);
Packit 1fb8d4
		free(rects);
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		shadow_client_mark_invalid(client, 0, NULL);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return shadow_client_refresh_request(client);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL shadow_client_suppress_output(rdpShadowClient* client, BYTE allow,
Packit 1fb8d4
        RECTANGLE_16* area)
Packit 1fb8d4
{
Packit 1fb8d4
	RECTANGLE_16 region;
Packit 1fb8d4
	client->suppressOutput = allow ? FALSE : TRUE;
Packit 1fb8d4
Packit 1fb8d4
	if (allow)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (area)
Packit 1fb8d4
		{
Packit 1fb8d4
			shadow_client_convert_rects(client, &region, area, 1);
Packit 1fb8d4
			shadow_client_mark_invalid(client, 1, &region);
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			shadow_client_mark_invalid(client, 0, NULL);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return shadow_client_refresh_request(client);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL shadow_client_activate(freerdp_peer* peer)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpSettings* settings = peer->settings;
Packit 1fb8d4
	rdpShadowClient* client = (rdpShadowClient*) peer->context;
Packit 1fb8d4
Packit 1fb8d4
	if (settings->ClientDir && (strcmp(settings->ClientDir, "librdp") == 0))
Packit 1fb8d4
	{
Packit 1fb8d4
		/* Hack for Mac/iOS/Android Microsoft RDP clients */
Packit 1fb8d4
		settings->RemoteFxCodec = FALSE;
Packit 1fb8d4
		settings->NSCodec = FALSE;
Packit 1fb8d4
		settings->NSCodecAllowSubsampling = FALSE;
Packit 1fb8d4
		settings->SurfaceFrameMarkerEnabled = FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	client->activated = TRUE;
Packit 1fb8d4
	client->inLobby = client->mayView ? FALSE : TRUE;
Packit 1fb8d4
Packit 1fb8d4
	if (shadow_encoder_reset(client->encoder) < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Failed to reset encoder");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* Update full screen in next update */
Packit 1fb8d4
	return shadow_client_refresh_rect(client, 0, NULL);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL shadow_client_logon(freerdp_peer* peer,
Packit 1fb8d4
                                SEC_WINNT_AUTH_IDENTITY* identity,
Packit 1fb8d4
                                BOOL automatic)
Packit 1fb8d4
{
Packit 1fb8d4
	char* user = NULL;
Packit 1fb8d4
	char* domain = NULL;
Packit 1fb8d4
	char* password = NULL;
Packit 1fb8d4
	rdpSettings* settings = peer->settings;
Packit 1fb8d4
Packit 1fb8d4
	if (identity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (identity->User)
Packit 1fb8d4
			ConvertFromUnicode(CP_UTF8, 0, identity->User, identity->UserLength, &user, 0,
Packit 1fb8d4
			                   NULL, NULL);
Packit 1fb8d4
Packit 1fb8d4
		if (identity->Domain)
Packit 1fb8d4
			ConvertFromUnicode(CP_UTF8, 0, identity->Domain, identity->DomainLength,
Packit 1fb8d4
			                   &domain, 0, NULL, NULL);
Packit 1fb8d4
Packit 1fb8d4
		if (identity->Password)
Packit 1fb8d4
			ConvertFromUnicode(CP_UTF8, 0, identity->Password, identity->PasswordLength,
Packit 1fb8d4
			                   &user, 0, NULL, NULL);
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		if (identity->User)
Packit 1fb8d4
			user = _strdup((char*) identity->User);
Packit 1fb8d4
Packit 1fb8d4
		if (identity->Domain)
Packit 1fb8d4
			domain = _strdup((char*) identity->Domain);
Packit 1fb8d4
Packit 1fb8d4
		if (identity->Password)
Packit 1fb8d4
			password = _strdup((char*) identity->Password);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if ((identity->User && !user) || (identity->Domain && !domain)
Packit 1fb8d4
	    || (identity->Password && !password))
Packit 1fb8d4
	{
Packit 1fb8d4
		free(user);
Packit 1fb8d4
		free(domain);
Packit 1fb8d4
		free(password);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (user)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(settings->Username);
Packit 1fb8d4
		settings->Username = user;
Packit 1fb8d4
		user = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (domain)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(settings->Domain);
Packit 1fb8d4
		settings->Domain = domain;
Packit 1fb8d4
		domain = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (password)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(settings->Password);
Packit 1fb8d4
		settings->Password = password;
Packit 1fb8d4
		password = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	free(user);
Packit 1fb8d4
	free(domain);
Packit 1fb8d4
	free(password);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static INLINE void shadow_client_common_frame_acknowledge(
Packit 1fb8d4
    rdpShadowClient* client, UINT32 frameId)
Packit 1fb8d4
{
Packit 1fb8d4
	/*
Packit 1fb8d4
	 * Record the last client acknowledged frame id to
Packit 1fb8d4
	 * calculate how much frames are in progress.
Packit 1fb8d4
	 * Some rdp clients (win7 mstsc) skips frame ACK if it is
Packit 1fb8d4
	 * inactive, we should not expect ACK for each frame.
Packit 1fb8d4
	 * So it is OK to calculate inflight frame count according to
Packit 1fb8d4
	 * a latest acknowledged frame id.
Packit 1fb8d4
	 */
Packit 1fb8d4
	client->encoder->lastAckframeId = frameId;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL shadow_client_surface_frame_acknowledge(rdpShadowClient* client,
Packit 1fb8d4
        UINT32 frameId)
Packit 1fb8d4
{
Packit 1fb8d4
	shadow_client_common_frame_acknowledge(client, frameId);
Packit 1fb8d4
	/*
Packit 1fb8d4
	 * Reset queueDepth for legacy none RDPGFX acknowledge
Packit 1fb8d4
	 */
Packit 1fb8d4
	client->encoder->queueDepth = QUEUE_DEPTH_UNAVAILABLE;
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static UINT shadow_client_rdpgfx_frame_acknowledge(RdpgfxServerContext* context,
Packit 1fb8d4
        RDPGFX_FRAME_ACKNOWLEDGE_PDU* frameAcknowledge)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpShadowClient* client = (rdpShadowClient*)context->custom;
Packit 1fb8d4
	shadow_client_common_frame_acknowledge(client, frameAcknowledge->frameId);
Packit 1fb8d4
	client->encoder->queueDepth = frameAcknowledge->queueDepth;
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT shadow_client_rdpgfx_caps_advertise(RdpgfxServerContext* context,
Packit 1fb8d4
        RDPGFX_CAPS_ADVERTISE_PDU* capsAdvertise)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT16 index;
Packit 1fb8d4
	rdpSettings* settings = context->rdpcontext->settings;
Packit 1fb8d4
	UINT32 flags = 0;
Packit 1fb8d4
	/* Request full screen update for new gfx channel */
Packit 1fb8d4
	shadow_client_refresh_rect((rdpShadowClient*)context->custom, 0, NULL);
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < capsAdvertise->capsSetCount; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		const RDPGFX_CAPSET* currentCaps = &capsAdvertise->capsSets[index];
Packit 1fb8d4
Packit 1fb8d4
		if (currentCaps->version == RDPGFX_CAPVERSION_103)
Packit 1fb8d4
		{
Packit 1fb8d4
			RDPGFX_CAPSET caps = *currentCaps;
Packit 1fb8d4
			RDPGFX_CAPS_CONFIRM_PDU pdu;
Packit 1fb8d4
			pdu.capsSet = ∩︀
Packit 1fb8d4
Packit 1fb8d4
			if (settings)
Packit 1fb8d4
			{
Packit 1fb8d4
				flags = pdu.capsSet->flags;
Packit 1fb8d4
				settings->GfxSmallCache = (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE);
Packit 1fb8d4
#ifndef WITH_GFX_H264
Packit 1fb8d4
				settings->GfxAVC444v2 = settings->GfxAVC444 = settings->GfxH264 = FALSE;
Packit 1fb8d4
				pdu.capsSet->flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
Packit 1fb8d4
#else
Packit 1fb8d4
				settings->GfxAVC444v2 = settings->GfxAVC444 = settings->GfxH264 = !(flags &
Packit 1fb8d4
				                        RDPGFX_CAPS_FLAG_AVC_DISABLED);
Packit 1fb8d4
#endif
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			return context->CapsConfirm(context, &pdu);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < capsAdvertise->capsSetCount; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		const RDPGFX_CAPSET* currentCaps = &capsAdvertise->capsSets[index];
Packit 1fb8d4
Packit 1fb8d4
		if (currentCaps->version == RDPGFX_CAPVERSION_102)
Packit 1fb8d4
		{
Packit 1fb8d4
			RDPGFX_CAPSET caps = *currentCaps;
Packit 1fb8d4
			RDPGFX_CAPS_CONFIRM_PDU pdu;
Packit 1fb8d4
			pdu.capsSet = ∩︀
Packit 1fb8d4
Packit 1fb8d4
			if (settings)
Packit 1fb8d4
			{
Packit 1fb8d4
				flags = pdu.capsSet->flags;
Packit 1fb8d4
				settings->GfxSmallCache = (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE);
Packit 1fb8d4
#ifndef WITH_GFX_H264
Packit 1fb8d4
				settings->GfxAVC444v2 = settings->GfxAVC444 = settings->GfxH264 = FALSE;
Packit 1fb8d4
				pdu.capsSet->flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
Packit 1fb8d4
#else
Packit 1fb8d4
				settings->GfxAVC444v2 = settings->GfxAVC444 = settings->GfxH264 = !(flags &
Packit 1fb8d4
				                        RDPGFX_CAPS_FLAG_AVC_DISABLED);
Packit 1fb8d4
#endif
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			return context->CapsConfirm(context, &pdu);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < capsAdvertise->capsSetCount; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		const RDPGFX_CAPSET* currentCaps = &capsAdvertise->capsSets[index];
Packit 1fb8d4
Packit 1fb8d4
		if (currentCaps->version == RDPGFX_CAPVERSION_10)
Packit 1fb8d4
		{
Packit 1fb8d4
			RDPGFX_CAPSET caps = *currentCaps;
Packit 1fb8d4
			RDPGFX_CAPS_CONFIRM_PDU pdu;
Packit 1fb8d4
			pdu.capsSet = ∩︀
Packit 1fb8d4
Packit 1fb8d4
			if (settings)
Packit 1fb8d4
			{
Packit 1fb8d4
				flags = pdu.capsSet->flags;
Packit 1fb8d4
				settings->GfxSmallCache = (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE);
Packit 1fb8d4
#ifndef WITH_GFX_H264
Packit 1fb8d4
				settings->GfxAVC444v2 = settings->GfxAVC444 = settings->GfxH264 = FALSE;
Packit 1fb8d4
				pdu.capsSet->flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
Packit 1fb8d4
#else
Packit 1fb8d4
				settings->GfxAVC444 = settings->GfxH264 = !(flags & RDPGFX_CAPS_FLAG_AVC_DISABLED);
Packit 1fb8d4
#endif
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			return context->CapsConfirm(context, &pdu);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < capsAdvertise->capsSetCount; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		const RDPGFX_CAPSET* currentCaps = &capsAdvertise->capsSets[index];
Packit 1fb8d4
Packit 1fb8d4
		if (currentCaps->version == RDPGFX_CAPVERSION_81)
Packit 1fb8d4
		{
Packit 1fb8d4
			RDPGFX_CAPSET caps = *currentCaps;
Packit 1fb8d4
			RDPGFX_CAPS_CONFIRM_PDU pdu;
Packit 1fb8d4
			pdu.capsSet = ∩︀
Packit 1fb8d4
Packit 1fb8d4
			if (settings)
Packit 1fb8d4
			{
Packit 1fb8d4
				flags = pdu.capsSet->flags;
Packit 1fb8d4
				settings->GfxAVC444v2 = settings->GfxAVC444 = FALSE;
Packit 1fb8d4
				settings->GfxThinClient = (flags & RDPGFX_CAPS_FLAG_THINCLIENT);
Packit 1fb8d4
				settings->GfxSmallCache = (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE);
Packit 1fb8d4
#ifndef WITH_GFX_H264
Packit 1fb8d4
				settings->GfxH264 = FALSE;
Packit 1fb8d4
				pdu.capsSet->flags &= ~RDPGFX_CAPS_FLAG_AVC420_ENABLED;
Packit 1fb8d4
#else
Packit 1fb8d4
				settings->GfxH264 = (flags & RDPGFX_CAPS_FLAG_AVC420_ENABLED);
Packit 1fb8d4
#endif
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			return context->CapsConfirm(context, &pdu);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < capsAdvertise->capsSetCount; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		const RDPGFX_CAPSET* currentCaps = &capsAdvertise->capsSets[index];
Packit 1fb8d4
Packit 1fb8d4
		if (currentCaps->version == RDPGFX_CAPVERSION_8)
Packit 1fb8d4
		{
Packit 1fb8d4
			RDPGFX_CAPSET caps = *currentCaps;
Packit 1fb8d4
			RDPGFX_CAPS_CONFIRM_PDU pdu;
Packit 1fb8d4
			pdu.capsSet = ∩︀
Packit 1fb8d4
Packit 1fb8d4
			if (settings)
Packit 1fb8d4
			{
Packit 1fb8d4
				flags = pdu.capsSet->flags;
Packit 1fb8d4
				settings->GfxThinClient = (flags & RDPGFX_CAPS_FLAG_THINCLIENT);
Packit 1fb8d4
				settings->GfxSmallCache = (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE);
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			return context->CapsConfirm(context, &pdu);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return CHANNEL_RC_UNSUPPORTED_VERSION;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static INLINE UINT32 rdpgfx_estimate_h264_avc420(
Packit 1fb8d4
    RDPGFX_AVC420_BITMAP_STREAM* havc420)
Packit 1fb8d4
{
Packit 1fb8d4
	/* H264 metadata + H264 stream. See rdpgfx_write_h264_avc420 */
Packit 1fb8d4
	return sizeof(UINT32) /* numRegionRects */
Packit 1fb8d4
	       + 10 /* regionRects + quantQualityVals */
Packit 1fb8d4
	       * havc420->meta.numRegionRects
Packit 1fb8d4
	       + havc420->length;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return TRUE on success
Packit 1fb8d4
 */
Packit 1fb8d4
static BOOL shadow_client_send_surface_gfx(rdpShadowClient* client,
Packit 1fb8d4
        const BYTE* pSrcData, int nSrcStep, int nXSrc, int nYSrc, int nWidth, int nHeight)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT error = CHANNEL_RC_OK;
Packit 1fb8d4
	rdpContext* context = (rdpContext*) client;
Packit 1fb8d4
	rdpSettings* settings;
Packit 1fb8d4
	rdpShadowEncoder* encoder;
Packit 1fb8d4
	RDPGFX_SURFACE_COMMAND cmd;
Packit 1fb8d4
	RDPGFX_START_FRAME_PDU cmdstart;
Packit 1fb8d4
	RDPGFX_END_FRAME_PDU cmdend;
Packit 1fb8d4
	SYSTEMTIME sTime;
Packit 1fb8d4
Packit 1fb8d4
	if (!context || !pSrcData)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	settings = context->settings;
Packit 1fb8d4
	encoder = client->encoder;
Packit 1fb8d4
Packit 1fb8d4
	if (!settings || !encoder)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	cmdstart.frameId = shadow_encoder_create_frame_id(encoder);
Packit 1fb8d4
	GetSystemTime(&sTime);
Packit 1fb8d4
	cmdstart.timestamp = sTime.wHour << 22 | sTime.wMinute << 16 |
Packit 1fb8d4
	                     sTime.wSecond << 10 | sTime.wMilliseconds;
Packit 1fb8d4
	cmdend.frameId = cmdstart.frameId;
Packit 1fb8d4
	cmd.surfaceId = 0;
Packit 1fb8d4
	cmd.codecId = 0;
Packit 1fb8d4
	cmd.contextId = 0;
Packit 1fb8d4
	cmd.format = PIXEL_FORMAT_BGRX32;
Packit 1fb8d4
	cmd.left = nXSrc;
Packit 1fb8d4
	cmd.top = nYSrc;
Packit 1fb8d4
	cmd.right = cmd.left + nWidth;
Packit 1fb8d4
	cmd.bottom = cmd.top + nHeight;
Packit 1fb8d4
	cmd.width = nWidth;
Packit 1fb8d4
	cmd.height = nHeight;
Packit 1fb8d4
	cmd.length = 0;
Packit 1fb8d4
	cmd.data = NULL;
Packit 1fb8d4
	cmd.extra = NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (settings->GfxAVC444 || settings->GfxAVC444v2)
Packit 1fb8d4
	{
Packit 1fb8d4
		RDPGFX_AVC444_BITMAP_STREAM avc444;
Packit 1fb8d4
		RECTANGLE_16 regionRect;
Packit 1fb8d4
		RDPGFX_H264_QUANT_QUALITY quantQualityVal;
Packit 1fb8d4
		BYTE version = settings->GfxAVC444v2 ? 2 : 1;
Packit 1fb8d4
Packit 1fb8d4
		if (shadow_encoder_prepare(encoder, FREERDP_CODEC_AVC444) < 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_AVC444");
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (avc444_compress(encoder->h264, pSrcData, cmd.format, nSrcStep,
Packit 1fb8d4
		                    nWidth, nHeight, version, &avc444.LC, &avc444.bitstream[0].data,
Packit 1fb8d4
		                    &avc444.bitstream[0].length, &avc444.bitstream[1].data,
Packit 1fb8d4
		                    &avc444.bitstream[1].length) < 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "avc420_compress failed for avc444");
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		regionRect.left = cmd.left;
Packit 1fb8d4
		regionRect.top = cmd.top;
Packit 1fb8d4
		regionRect.right = cmd.right;
Packit 1fb8d4
		regionRect.bottom = cmd.bottom;
Packit 1fb8d4
		quantQualityVal.qp = encoder->h264->QP;
Packit 1fb8d4
		quantQualityVal.r = 0;
Packit 1fb8d4
		quantQualityVal.p = 0;
Packit 1fb8d4
		quantQualityVal.qualityVal = 100 - quantQualityVal.qp;
Packit 1fb8d4
		avc444.bitstream[0].meta.numRegionRects = 1;
Packit 1fb8d4
		avc444.bitstream[0].meta.regionRects = &regionRect;
Packit 1fb8d4
		avc444.bitstream[0].meta.quantQualityVals = &quantQualityVal;
Packit 1fb8d4
		avc444.bitstream[1].meta.numRegionRects = 1;
Packit 1fb8d4
		avc444.bitstream[1].meta.regionRects = &regionRect;
Packit 1fb8d4
		avc444.bitstream[1].meta.quantQualityVals = &quantQualityVal;
Packit 1fb8d4
		avc444.cbAvc420EncodedBitstream1 = rdpgfx_estimate_h264_avc420(&avc444.bitstream[0]);
Packit 1fb8d4
		cmd.codecId = settings->GfxAVC444v2 ? RDPGFX_CODECID_AVC444v2 : RDPGFX_CODECID_AVC444;
Packit 1fb8d4
		cmd.extra = (void*)&avc444;
Packit 1fb8d4
		IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, &cmd,
Packit 1fb8d4
		          &cmdstart, &cmdend);
Packit 1fb8d4
Packit 1fb8d4
		if (error)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "SurfaceFrameCommand failed with error %"PRIu32"", error);
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (settings->GfxH264)
Packit 1fb8d4
	{
Packit 1fb8d4
		RDPGFX_AVC420_BITMAP_STREAM avc420;
Packit 1fb8d4
		RECTANGLE_16 regionRect;
Packit 1fb8d4
		RDPGFX_H264_QUANT_QUALITY quantQualityVal;
Packit 1fb8d4
Packit 1fb8d4
		if (shadow_encoder_prepare(encoder, FREERDP_CODEC_AVC420) < 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_AVC420");
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (avc420_compress(encoder->h264, pSrcData, cmd.format, nSrcStep,
Packit 1fb8d4
		                    nWidth, nHeight, &avc420.data, &avc420.length) < 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "avc420_compress failed");
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		cmd.codecId = RDPGFX_CODECID_AVC420;
Packit 1fb8d4
		cmd.extra = (void*)&avc420;
Packit 1fb8d4
		regionRect.left = cmd.left;
Packit 1fb8d4
		regionRect.top = cmd.top;
Packit 1fb8d4
		regionRect.right = cmd.right;
Packit 1fb8d4
		regionRect.bottom = cmd.bottom;
Packit 1fb8d4
		quantQualityVal.qp = encoder->h264->QP;
Packit 1fb8d4
		quantQualityVal.r = 0;
Packit 1fb8d4
		quantQualityVal.p = 0;
Packit 1fb8d4
		quantQualityVal.qualityVal = 100 - quantQualityVal.qp;
Packit 1fb8d4
		avc420.meta.numRegionRects = 1;
Packit 1fb8d4
		avc420.meta.regionRects = &regionRect;
Packit 1fb8d4
		avc420.meta.quantQualityVals = &quantQualityVal;
Packit 1fb8d4
		IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, &cmd,
Packit 1fb8d4
		          &cmdstart, &cmdend);
Packit 1fb8d4
Packit 1fb8d4
		if (error)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "SurfaceFrameCommand failed with error %"PRIu32"", error);
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return TRUE on success
Packit 1fb8d4
 */
Packit 1fb8d4
static BOOL shadow_client_send_surface_bits(rdpShadowClient* client,
Packit 1fb8d4
        BYTE* pSrcData, int nSrcStep, int nXSrc, int nYSrc, int nWidth, int nHeight)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL ret = TRUE;
Packit 1fb8d4
	int i;
Packit 1fb8d4
	BOOL first;
Packit 1fb8d4
	BOOL last;
Packit 1fb8d4
	wStream* s;
Packit 1fb8d4
	int numMessages;
Packit 1fb8d4
	UINT32 frameId = 0;
Packit 1fb8d4
	rdpUpdate* update;
Packit 1fb8d4
	rdpContext* context = (rdpContext*) client;
Packit 1fb8d4
	rdpSettings* settings;
Packit 1fb8d4
	rdpShadowEncoder* encoder;
Packit 1fb8d4
	SURFACE_BITS_COMMAND cmd = { 0 };
Packit 1fb8d4
Packit 1fb8d4
	if (!context || !pSrcData)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	update = context->update;
Packit 1fb8d4
	settings = context->settings;
Packit 1fb8d4
	encoder = client->encoder;
Packit 1fb8d4
Packit 1fb8d4
	if (!update || !settings || !encoder)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (encoder->frameAck)
Packit 1fb8d4
		frameId = shadow_encoder_create_frame_id(encoder);
Packit 1fb8d4
Packit 1fb8d4
	if (settings->RemoteFxCodec)
Packit 1fb8d4
	{
Packit 1fb8d4
		RFX_RECT rect;
Packit 1fb8d4
		RFX_MESSAGE* messages;
Packit 1fb8d4
		RFX_RECT* messageRects = NULL;
Packit 1fb8d4
Packit 1fb8d4
		if (shadow_encoder_prepare(encoder, FREERDP_CODEC_REMOTEFX) < 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_REMOTEFX");
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		s = encoder->bs;
Packit 1fb8d4
		rect.x = nXSrc;
Packit 1fb8d4
		rect.y = nYSrc;
Packit 1fb8d4
		rect.width = nWidth;
Packit 1fb8d4
		rect.height = nHeight;
Packit 1fb8d4
Packit 1fb8d4
		if (!(messages = rfx_encode_messages(encoder->rfx, &rect, 1, pSrcData,
Packit 1fb8d4
		                                     settings->DesktopWidth, settings->DesktopHeight, nSrcStep, &numMessages,
Packit 1fb8d4
		                                     settings->MultifragMaxRequestSize)))
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "rfx_encode_messages failed");
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		cmd.bmp.codecID = settings->RemoteFxCodecId;
Packit 1fb8d4
		cmd.destLeft = 0;
Packit 1fb8d4
		cmd.destTop = 0;
Packit 1fb8d4
		cmd.destRight = settings->DesktopWidth;
Packit 1fb8d4
		cmd.destBottom = settings->DesktopHeight;
Packit 1fb8d4
		cmd.bmp.bpp = 32;
Packit 1fb8d4
		cmd.bmp.flags = 0;
Packit 1fb8d4
		cmd.bmp.width = settings->DesktopWidth;
Packit 1fb8d4
		cmd.bmp.height = settings->DesktopHeight;
Packit 1fb8d4
		cmd.skipCompression = TRUE;
Packit 1fb8d4
Packit 1fb8d4
		if (numMessages > 0)
Packit 1fb8d4
			messageRects = messages[0].rects;
Packit 1fb8d4
Packit 1fb8d4
		for (i = 0; i < numMessages; i++)
Packit 1fb8d4
		{
Packit 1fb8d4
			Stream_SetPosition(s, 0);
Packit 1fb8d4
Packit 1fb8d4
			if (!rfx_write_message(encoder->rfx, s, &messages[i]))
Packit 1fb8d4
			{
Packit 1fb8d4
				while (i < numMessages)
Packit 1fb8d4
				{
Packit 1fb8d4
					rfx_message_free(encoder->rfx, &messages[i++]);
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				WLog_ERR(TAG, "rfx_write_message failed");
Packit 1fb8d4
				ret = FALSE;
Packit 1fb8d4
				break;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			rfx_message_free(encoder->rfx, &messages[i]);
Packit 1fb8d4
			cmd.bmp.bitmapDataLength = Stream_GetPosition(s);
Packit 1fb8d4
			cmd.bmp.bitmapData = Stream_Buffer(s);
Packit 1fb8d4
			first = (i == 0) ? TRUE : FALSE;
Packit 1fb8d4
			last = ((i + 1) == numMessages) ? TRUE : FALSE;
Packit 1fb8d4
Packit 1fb8d4
			if (!encoder->frameAck)
Packit 1fb8d4
				IFCALLRET(update->SurfaceBits, ret, update->context, &cmd);
Packit 1fb8d4
			else
Packit 1fb8d4
				IFCALLRET(update->SurfaceFrameBits, ret, update->context, &cmd, first, last,
Packit 1fb8d4
				          frameId);
Packit 1fb8d4
Packit 1fb8d4
			if (!ret)
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "Send surface bits(RemoteFxCodec) failed");
Packit 1fb8d4
				break;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		free(messageRects);
Packit 1fb8d4
		free(messages);
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (settings->NSCodec)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (shadow_encoder_prepare(encoder, FREERDP_CODEC_NSCODEC) < 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_NSCODEC");
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		s = encoder->bs;
Packit 1fb8d4
		Stream_SetPosition(s, 0);
Packit 1fb8d4
		pSrcData = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 4)];
Packit 1fb8d4
		nsc_compose_message(encoder->nsc, s, pSrcData, nWidth, nHeight, nSrcStep);
Packit 1fb8d4
		cmd.bmp.bpp = 32;
Packit 1fb8d4
		cmd.bmp.codecID = settings->NSCodecId;
Packit 1fb8d4
		cmd.destLeft = nXSrc;
Packit 1fb8d4
		cmd.destTop = nYSrc;
Packit 1fb8d4
		cmd.destRight = cmd.destLeft + nWidth;
Packit 1fb8d4
		cmd.destBottom = cmd.destTop + nHeight;
Packit 1fb8d4
		cmd.bmp.width = nWidth;
Packit 1fb8d4
		cmd.bmp.height = nHeight;
Packit 1fb8d4
		cmd.bmp.bitmapDataLength = Stream_GetPosition(s);
Packit 1fb8d4
		cmd.bmp.bitmapData = Stream_Buffer(s);
Packit 1fb8d4
		first = TRUE;
Packit 1fb8d4
		last = TRUE;
Packit 1fb8d4
Packit 1fb8d4
		if (!encoder->frameAck)
Packit 1fb8d4
			IFCALLRET(update->SurfaceBits, ret, update->context, &cmd);
Packit 1fb8d4
		else
Packit 1fb8d4
			IFCALLRET(update->SurfaceFrameBits, ret, update->context, &cmd, first, last,
Packit 1fb8d4
			          frameId);
Packit 1fb8d4
Packit 1fb8d4
		if (!ret)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "Send surface bits(NSCodec) failed");
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return ret;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return TRUE on success
Packit 1fb8d4
 */
Packit 1fb8d4
static BOOL shadow_client_send_bitmap_update(rdpShadowClient* client,
Packit 1fb8d4
        BYTE* pSrcData, int nSrcStep, int nXSrc, int nYSrc, int nWidth, int nHeight)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL ret = TRUE;
Packit 1fb8d4
	BYTE* data;
Packit 1fb8d4
	BYTE* buffer;
Packit 1fb8d4
	int yIdx, xIdx, k;
Packit 1fb8d4
	int rows, cols;
Packit 1fb8d4
	UINT32 DstSize;
Packit 1fb8d4
	UINT32 SrcFormat;
Packit 1fb8d4
	BITMAP_DATA* bitmap;
Packit 1fb8d4
	rdpUpdate* update;
Packit 1fb8d4
	rdpContext* context = (rdpContext*) client;
Packit 1fb8d4
	rdpSettings* settings;
Packit 1fb8d4
	UINT32 maxUpdateSize;
Packit 1fb8d4
	UINT32 totalBitmapSize;
Packit 1fb8d4
	UINT32 updateSizeEstimate;
Packit 1fb8d4
	BITMAP_DATA* bitmapData;
Packit 1fb8d4
	BITMAP_UPDATE bitmapUpdate;
Packit 1fb8d4
	rdpShadowEncoder* encoder;
Packit 1fb8d4
Packit 1fb8d4
	if (!context || !pSrcData)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	update = context->update;
Packit 1fb8d4
	settings = context->settings;
Packit 1fb8d4
	encoder = client->encoder;
Packit 1fb8d4
Packit 1fb8d4
	if (!update || !settings || !encoder)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	maxUpdateSize = settings->MultifragMaxRequestSize;
Packit 1fb8d4
Packit 1fb8d4
	if (settings->ColorDepth < 32)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (shadow_encoder_prepare(encoder, FREERDP_CODEC_INTERLEAVED) < 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_INTERLEAVED");
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		if (shadow_encoder_prepare(encoder, FREERDP_CODEC_PLANAR) < 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_PLANAR");
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	SrcFormat = PIXEL_FORMAT_BGRX32;
Packit 1fb8d4
Packit 1fb8d4
	if ((nXSrc % 4) != 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		nWidth += (nXSrc % 4);
Packit 1fb8d4
		nXSrc -= (nXSrc % 4);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if ((nYSrc % 4) != 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		nHeight += (nYSrc % 4);
Packit 1fb8d4
		nYSrc -= (nYSrc % 4);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	rows = (nHeight / 64) + ((nHeight % 64) ? 1 : 0);
Packit 1fb8d4
	cols = (nWidth / 64) + ((nWidth % 64) ? 1 : 0);
Packit 1fb8d4
	k = 0;
Packit 1fb8d4
	totalBitmapSize = 0;
Packit 1fb8d4
	bitmapUpdate.count = bitmapUpdate.number = rows * cols;
Packit 1fb8d4
Packit 1fb8d4
	if (!(bitmapData = (BITMAP_DATA*) calloc(bitmapUpdate.number, sizeof(BITMAP_DATA))))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	bitmapUpdate.rectangles = bitmapData;
Packit 1fb8d4
Packit 1fb8d4
	if ((nWidth % 4) != 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		nWidth += (4 - (nWidth % 4));
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if ((nHeight % 4) != 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		nHeight += (4 - (nHeight % 4));
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	for (yIdx = 0; yIdx < rows; yIdx++)
Packit 1fb8d4
	{
Packit 1fb8d4
		for (xIdx = 0; xIdx < cols; xIdx++)
Packit 1fb8d4
		{
Packit 1fb8d4
			bitmap = &bitmapData[k];
Packit 1fb8d4
			bitmap->width = 64;
Packit 1fb8d4
			bitmap->height = 64;
Packit 1fb8d4
			bitmap->destLeft = nXSrc + (xIdx * 64);
Packit 1fb8d4
			bitmap->destTop = nYSrc + (yIdx * 64);
Packit 1fb8d4
Packit 1fb8d4
			if ((bitmap->destLeft + bitmap->width) > (nXSrc + nWidth))
Packit 1fb8d4
				bitmap->width = (nXSrc + nWidth) - bitmap->destLeft;
Packit 1fb8d4
Packit 1fb8d4
			if ((bitmap->destTop + bitmap->height) > (nYSrc + nHeight))
Packit 1fb8d4
				bitmap->height = (nYSrc + nHeight) - bitmap->destTop;
Packit 1fb8d4
Packit 1fb8d4
			bitmap->destRight = bitmap->destLeft + bitmap->width - 1;
Packit 1fb8d4
			bitmap->destBottom = bitmap->destTop + bitmap->height - 1;
Packit 1fb8d4
			bitmap->compressed = TRUE;
Packit 1fb8d4
Packit 1fb8d4
			if ((bitmap->width < 4) || (bitmap->height < 4))
Packit 1fb8d4
				continue;
Packit 1fb8d4
Packit 1fb8d4
			if (settings->ColorDepth < 32)
Packit 1fb8d4
			{
Packit 1fb8d4
				int bitsPerPixel = settings->ColorDepth;
Packit 1fb8d4
				int bytesPerPixel = (bitsPerPixel + 7) / 8;
Packit 1fb8d4
				DstSize = 64 * 64 * 4;
Packit 1fb8d4
				buffer = encoder->grid[k];
Packit 1fb8d4
				interleaved_compress(encoder->interleaved, buffer, &DstSize, bitmap->width,
Packit 1fb8d4
				                     bitmap->height,
Packit 1fb8d4
				                     pSrcData, SrcFormat, nSrcStep, bitmap->destLeft, bitmap->destTop, NULL,
Packit 1fb8d4
				                     bitsPerPixel);
Packit 1fb8d4
				bitmap->bitmapDataStream = buffer;
Packit 1fb8d4
				bitmap->bitmapLength = DstSize;
Packit 1fb8d4
				bitmap->bitsPerPixel = bitsPerPixel;
Packit 1fb8d4
				bitmap->cbScanWidth = bitmap->width * bytesPerPixel;
Packit 1fb8d4
				bitmap->cbUncompressedSize = bitmap->width * bitmap->height * bytesPerPixel;
Packit 1fb8d4
			}
Packit 1fb8d4
			else
Packit 1fb8d4
			{
Packit 1fb8d4
				UINT32 dstSize;
Packit 1fb8d4
				buffer = encoder->grid[k];
Packit 1fb8d4
				data = &pSrcData[(bitmap->destTop * nSrcStep) + (bitmap->destLeft * 4)];
Packit 1fb8d4
				buffer = freerdp_bitmap_compress_planar(encoder->planar, data, SrcFormat,
Packit 1fb8d4
				                                        bitmap->width, bitmap->height, nSrcStep, buffer, &dstSize);
Packit 1fb8d4
				bitmap->bitmapDataStream = buffer;
Packit 1fb8d4
				bitmap->bitmapLength = dstSize;
Packit 1fb8d4
				bitmap->bitsPerPixel = 32;
Packit 1fb8d4
				bitmap->cbScanWidth = bitmap->width * 4;
Packit 1fb8d4
				bitmap->cbUncompressedSize = bitmap->width * bitmap->height * 4;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			bitmap->cbCompFirstRowSize = 0;
Packit 1fb8d4
			bitmap->cbCompMainBodySize = bitmap->bitmapLength;
Packit 1fb8d4
			totalBitmapSize += bitmap->bitmapLength;
Packit 1fb8d4
			k++;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	bitmapUpdate.count = bitmapUpdate.number = k;
Packit 1fb8d4
	updateSizeEstimate = totalBitmapSize + (k * bitmapUpdate.count) + 16;
Packit 1fb8d4
Packit 1fb8d4
	if (updateSizeEstimate > maxUpdateSize)
Packit 1fb8d4
	{
Packit 1fb8d4
		UINT32 i, j;
Packit 1fb8d4
		UINT32 updateSize;
Packit 1fb8d4
		UINT32 newUpdateSize;
Packit 1fb8d4
		BITMAP_DATA* fragBitmapData = NULL;
Packit 1fb8d4
Packit 1fb8d4
		if (k > 0)
Packit 1fb8d4
			fragBitmapData = (BITMAP_DATA*) calloc(k, sizeof(BITMAP_DATA));
Packit 1fb8d4
Packit 1fb8d4
		if (!fragBitmapData)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "Failed to allocate memory for fragBitmapData");
Packit 1fb8d4
			ret = FALSE;
Packit 1fb8d4
			goto out;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		bitmapUpdate.rectangles = fragBitmapData;
Packit 1fb8d4
		i = j = 0;
Packit 1fb8d4
		updateSize = 1024;
Packit 1fb8d4
Packit 1fb8d4
		while (i < k)
Packit 1fb8d4
		{
Packit 1fb8d4
			newUpdateSize = updateSize + (bitmapData[i].bitmapLength + 16);
Packit 1fb8d4
Packit 1fb8d4
			if (newUpdateSize < maxUpdateSize)
Packit 1fb8d4
			{
Packit 1fb8d4
				CopyMemory(&fragBitmapData[j++], &bitmapData[i++], sizeof(BITMAP_DATA));
Packit 1fb8d4
				updateSize = newUpdateSize;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if ((newUpdateSize >= maxUpdateSize) || (i + 1) >= k)
Packit 1fb8d4
			{
Packit 1fb8d4
				bitmapUpdate.count = bitmapUpdate.number = j;
Packit 1fb8d4
				IFCALLRET(update->BitmapUpdate, ret, context, &bitmapUpdate);
Packit 1fb8d4
Packit 1fb8d4
				if (!ret)
Packit 1fb8d4
				{
Packit 1fb8d4
					WLog_ERR(TAG, "BitmapUpdate failed");
Packit 1fb8d4
					break;
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				updateSize = 1024;
Packit 1fb8d4
				j = 0;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		free(fragBitmapData);
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		IFCALLRET(update->BitmapUpdate, ret, context, &bitmapUpdate);
Packit 1fb8d4
Packit 1fb8d4
		if (!ret)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "BitmapUpdate failed");
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
out:
Packit 1fb8d4
	free(bitmapData);
Packit 1fb8d4
	return ret;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return TRUE on success (or nothing need to be updated)
Packit 1fb8d4
 */
Packit 1fb8d4
static BOOL shadow_client_send_surface_update(rdpShadowClient* client,
Packit 1fb8d4
        SHADOW_GFX_STATUS* pStatus)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL ret = TRUE;
Packit 1fb8d4
	int nXSrc, nYSrc;
Packit 1fb8d4
	int nWidth, nHeight;
Packit 1fb8d4
	rdpContext* context = (rdpContext*) client;
Packit 1fb8d4
	rdpSettings* settings;
Packit 1fb8d4
	rdpShadowServer* server;
Packit 1fb8d4
	rdpShadowSurface* surface;
Packit 1fb8d4
	REGION16 invalidRegion;
Packit 1fb8d4
	RECTANGLE_16 surfaceRect;
Packit 1fb8d4
	const RECTANGLE_16* extents;
Packit 1fb8d4
	BYTE* pSrcData;
Packit 1fb8d4
	int nSrcStep;
Packit 1fb8d4
	UINT32 index;
Packit 1fb8d4
	UINT32 numRects = 0;
Packit 1fb8d4
	const RECTANGLE_16* rects;
Packit 1fb8d4
Packit 1fb8d4
	if (!context || !pStatus)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	settings = context->settings;
Packit 1fb8d4
	server = client->server;
Packit 1fb8d4
Packit 1fb8d4
	if (!settings || !server)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	surface = client->inLobby ? server->lobby : server->surface;
Packit 1fb8d4
Packit 1fb8d4
	if (!surface)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	EnterCriticalSection(&(client->lock));
Packit 1fb8d4
	region16_init(&invalidRegion);
Packit 1fb8d4
	region16_copy(&invalidRegion, &(client->invalidRegion));
Packit 1fb8d4
	region16_clear(&(client->invalidRegion));
Packit 1fb8d4
	LeaveCriticalSection(&(client->lock));
Packit 1fb8d4
	rects = region16_rects(&(surface->invalidRegion), &numRects);
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < numRects; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		region16_union_rect(&invalidRegion, &invalidRegion, &rects[index]);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	surfaceRect.left = 0;
Packit 1fb8d4
	surfaceRect.top = 0;
Packit 1fb8d4
	surfaceRect.right = surface->width;
Packit 1fb8d4
	surfaceRect.bottom = surface->height;
Packit 1fb8d4
	region16_intersect_rect(&invalidRegion, &invalidRegion, &surfaceRect);
Packit 1fb8d4
Packit 1fb8d4
	if (server->shareSubRect)
Packit 1fb8d4
	{
Packit 1fb8d4
		region16_intersect_rect(&invalidRegion, &invalidRegion, &(server->subRect));
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (region16_is_empty(&invalidRegion))
Packit 1fb8d4
	{
Packit 1fb8d4
		/* No image region need to be updated. Success */
Packit 1fb8d4
		goto out;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	extents = region16_extents(&invalidRegion);
Packit 1fb8d4
	nXSrc = extents->left;
Packit 1fb8d4
	nYSrc = extents->top;
Packit 1fb8d4
	nWidth = extents->right - extents->left;
Packit 1fb8d4
	nHeight = extents->bottom - extents->top;
Packit 1fb8d4
	pSrcData = surface->data;
Packit 1fb8d4
	nSrcStep = surface->scanline;
Packit 1fb8d4
Packit 1fb8d4
	/* Move to new pSrcData / nXSrc / nYSrc according to sub rect */
Packit 1fb8d4
	if (server->shareSubRect)
Packit 1fb8d4
	{
Packit 1fb8d4
		int subX, subY;
Packit 1fb8d4
		subX = server->subRect.left;
Packit 1fb8d4
		subY = server->subRect.top;
Packit 1fb8d4
		nXSrc -= subX;
Packit 1fb8d4
		nYSrc -= subY;
Packit 1fb8d4
		pSrcData = &pSrcData[(subY * nSrcStep) + (subX * 4)];
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	//WLog_INFO(TAG, "shadow_client_send_surface_update: x: %d y: %d width: %d height: %d right: %d bottom: %d",
Packit 1fb8d4
	//	nXSrc, nYSrc, nWidth, nHeight, nXSrc + nWidth, nYSrc + nHeight);
Packit 1fb8d4
Packit 1fb8d4
	if (settings->SupportGraphicsPipeline &&
Packit 1fb8d4
	    settings->GfxH264 &&
Packit 1fb8d4
	    pStatus->gfxOpened)
Packit 1fb8d4
	{
Packit 1fb8d4
		/* GFX/h264 always full screen encoded */
Packit 1fb8d4
		nWidth = settings->DesktopWidth;
Packit 1fb8d4
		nHeight = settings->DesktopHeight;
Packit 1fb8d4
Packit 1fb8d4
		/* Create primary surface if have not */
Packit 1fb8d4
		if (!pStatus->gfxSurfaceCreated)
Packit 1fb8d4
		{
Packit 1fb8d4
			/* Only init surface when we have h264 supported */
Packit 1fb8d4
			if (!(ret = shadow_client_rdpgfx_reset_graphic(client)))
Packit 1fb8d4
				goto out;
Packit 1fb8d4
Packit 1fb8d4
			if (!(ret = shadow_client_rdpgfx_new_surface(client)))
Packit 1fb8d4
				goto out;
Packit 1fb8d4
Packit 1fb8d4
			pStatus->gfxSurfaceCreated = TRUE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		ret = shadow_client_send_surface_gfx(client, pSrcData, nSrcStep, 0, 0, nWidth,
Packit 1fb8d4
		                                     nHeight);
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (settings->RemoteFxCodec || settings->NSCodec)
Packit 1fb8d4
	{
Packit 1fb8d4
		ret = shadow_client_send_surface_bits(client, pSrcData, nSrcStep, nXSrc, nYSrc,
Packit 1fb8d4
		                                      nWidth, nHeight);
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		ret = shadow_client_send_bitmap_update(client, pSrcData, nSrcStep, nXSrc, nYSrc,
Packit 1fb8d4
		                                       nWidth, nHeight);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
out:
Packit 1fb8d4
	region16_uninit(&invalidRegion);
Packit 1fb8d4
	return ret;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 * Notify client for resize. The new desktop width/height
Packit 1fb8d4
 * should have already been updated in rdpSettings.
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return TRUE on success
Packit 1fb8d4
 */
Packit 1fb8d4
static BOOL shadow_client_send_resize(rdpShadowClient* client,
Packit 1fb8d4
                                      SHADOW_GFX_STATUS* pStatus)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpContext* context = (rdpContext*) client;
Packit 1fb8d4
	rdpSettings* settings;
Packit 1fb8d4
	freerdp_peer* peer;
Packit 1fb8d4
Packit 1fb8d4
	if (!context || !pStatus)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	peer = context->peer;
Packit 1fb8d4
	settings = context->settings;
Packit 1fb8d4
Packit 1fb8d4
	if (!peer || !settings)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/**
Packit 1fb8d4
	 * Unset client activated flag to avoid sending update message during
Packit 1fb8d4
	 * resize. DesktopResize will reactive the client and
Packit 1fb8d4
	 * shadow_client_activate would be invoked later.
Packit 1fb8d4
	 */
Packit 1fb8d4
	client->activated = FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* Close Gfx surfaces */
Packit 1fb8d4
	if (pStatus->gfxSurfaceCreated)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!shadow_client_rdpgfx_release_surface(client))
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		pStatus->gfxSurfaceCreated = FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* Send Resize */
Packit 1fb8d4
	if (!peer->update->DesktopResize(peer->update->context))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "DesktopResize failed");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* Clear my invalidRegion. shadow_client_activate refreshes fullscreen */
Packit 1fb8d4
	EnterCriticalSection(&(client->lock));
Packit 1fb8d4
	region16_clear(&(client->invalidRegion));
Packit 1fb8d4
	LeaveCriticalSection(&(client->lock));
Packit 1fb8d4
	WLog_INFO(TAG, "Client from %s is resized (%"PRIu32"x%"PRIu32"@%"PRIu32")",
Packit 1fb8d4
	          peer->hostname, settings->DesktopWidth, settings->DesktopHeight,
Packit 1fb8d4
	          settings->ColorDepth);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 * Mark invalid region for client
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return TRUE on success
Packit 1fb8d4
 */
Packit 1fb8d4
BOOL shadow_client_surface_update(rdpShadowClient* client, REGION16* region)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 numRects = 0;
Packit 1fb8d4
	const RECTANGLE_16* rects;
Packit 1fb8d4
	rects = region16_rects(region, &numRects);
Packit 1fb8d4
	shadow_client_mark_invalid(client, numRects, rects);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 * Only union invalid region from server surface
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return TRUE on success
Packit 1fb8d4
 */
Packit 1fb8d4
static INLINE BOOL shadow_client_no_surface_update(rdpShadowClient* client,
Packit 1fb8d4
        SHADOW_GFX_STATUS* pStatus)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpShadowServer* server;
Packit 1fb8d4
	rdpShadowSurface* surface;
Packit 1fb8d4
	server = client->server;
Packit 1fb8d4
	surface = client->inLobby ? server->lobby : server->surface;
Packit 1fb8d4
	return shadow_client_surface_update(client, &(surface->invalidRegion));
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int shadow_client_subsystem_process_message(rdpShadowClient* client,
Packit 1fb8d4
        wMessage* message)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpContext* context = (rdpContext*) client;
Packit 1fb8d4
	rdpUpdate* update = context->update;
Packit 1fb8d4
Packit 1fb8d4
	/* FIXME: the pointer updates appear to be broken when used with bulk compression and mstsc */
Packit 1fb8d4
Packit 1fb8d4
	switch (message->id)
Packit 1fb8d4
	{
Packit 1fb8d4
		case SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID:
Packit 1fb8d4
			{
Packit 1fb8d4
				POINTER_POSITION_UPDATE pointerPosition;
Packit 1fb8d4
				SHADOW_MSG_OUT_POINTER_POSITION_UPDATE* msg =
Packit 1fb8d4
				    (SHADOW_MSG_OUT_POINTER_POSITION_UPDATE*) message->wParam;
Packit 1fb8d4
				pointerPosition.xPos = msg->xPos;
Packit 1fb8d4
				pointerPosition.yPos = msg->yPos;
Packit 1fb8d4
Packit 1fb8d4
				if (client->server->shareSubRect)
Packit 1fb8d4
				{
Packit 1fb8d4
					pointerPosition.xPos -= client->server->subRect.left;
Packit 1fb8d4
					pointerPosition.yPos -= client->server->subRect.top;
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				if (client->activated)
Packit 1fb8d4
				{
Packit 1fb8d4
					if ((msg->xPos != client->pointerX) || (msg->yPos != client->pointerY))
Packit 1fb8d4
					{
Packit 1fb8d4
						IFCALL(update->pointer->PointerPosition, context, &pointerPosition);
Packit 1fb8d4
						client->pointerX = msg->xPos;
Packit 1fb8d4
						client->pointerY = msg->yPos;
Packit 1fb8d4
					}
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				break;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
		case SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID:
Packit 1fb8d4
			{
Packit 1fb8d4
				POINTER_NEW_UPDATE pointerNew;
Packit 1fb8d4
				POINTER_COLOR_UPDATE* pointerColor;
Packit 1fb8d4
				POINTER_CACHED_UPDATE pointerCached;
Packit 1fb8d4
				SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE* msg =
Packit 1fb8d4
				    (SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE*) message->wParam;
Packit 1fb8d4
				ZeroMemory(&pointerNew, sizeof(POINTER_NEW_UPDATE));
Packit 1fb8d4
				pointerNew.xorBpp = 24;
Packit 1fb8d4
				pointerColor = &(pointerNew.colorPtrAttr);
Packit 1fb8d4
				pointerColor->cacheIndex = 0;
Packit 1fb8d4
				pointerColor->xPos = msg->xHot;
Packit 1fb8d4
				pointerColor->yPos = msg->yHot;
Packit 1fb8d4
				pointerColor->width = msg->width;
Packit 1fb8d4
				pointerColor->height = msg->height;
Packit 1fb8d4
				pointerColor->lengthAndMask = msg->lengthAndMask;
Packit 1fb8d4
				pointerColor->lengthXorMask = msg->lengthXorMask;
Packit 1fb8d4
				pointerColor->xorMaskData = msg->xorMaskData;
Packit 1fb8d4
				pointerColor->andMaskData = msg->andMaskData;
Packit 1fb8d4
				pointerCached.cacheIndex = pointerColor->cacheIndex;
Packit 1fb8d4
Packit 1fb8d4
				if (client->activated)
Packit 1fb8d4
				{
Packit 1fb8d4
					IFCALL(update->pointer->PointerNew, context, &pointerNew);
Packit 1fb8d4
					IFCALL(update->pointer->PointerCached, context, &pointerCached);
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				break;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
		case SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES_ID:
Packit 1fb8d4
			{
Packit 1fb8d4
				SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES* msg = (SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES*)
Packit 1fb8d4
				                                        message->wParam;
Packit 1fb8d4
Packit 1fb8d4
				if (client->activated && client->rdpsnd && client->rdpsnd->Activated)
Packit 1fb8d4
				{
Packit 1fb8d4
					client->rdpsnd->src_format = msg->audio_format;
Packit 1fb8d4
					IFCALL(client->rdpsnd->SendSamples, client->rdpsnd, msg->buf, msg->nFrames,
Packit 1fb8d4
					       msg->wTimestamp);
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				break;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
		case SHADOW_MSG_OUT_AUDIO_OUT_VOLUME_ID:
Packit 1fb8d4
			{
Packit 1fb8d4
				SHADOW_MSG_OUT_AUDIO_OUT_VOLUME* msg = (SHADOW_MSG_OUT_AUDIO_OUT_VOLUME*)
Packit 1fb8d4
				                                       message->wParam;
Packit 1fb8d4
Packit 1fb8d4
				if (client->activated && client->rdpsnd && client->rdpsnd->Activated)
Packit 1fb8d4
				{
Packit 1fb8d4
					IFCALL(client->rdpsnd->SetVolume, client->rdpsnd, msg->left, msg->right);
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				break;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			WLog_ERR(TAG, "Unknown message id: %"PRIu32"", message->id);
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	shadow_client_free_queued_message(message);
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static DWORD WINAPI shadow_client_thread(LPVOID arg)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpShadowClient* client = (rdpShadowClient*)arg;
Packit 1fb8d4
	DWORD status;
Packit 1fb8d4
	DWORD nCount;
Packit 1fb8d4
	wMessage message;
Packit 1fb8d4
	wMessage pointerPositionMsg;
Packit 1fb8d4
	wMessage pointerAlphaMsg;
Packit 1fb8d4
	wMessage audioVolumeMsg;
Packit 1fb8d4
	HANDLE events[32];
Packit 1fb8d4
	HANDLE ChannelEvent;
Packit 1fb8d4
	void* UpdateSubscriber;
Packit 1fb8d4
	HANDLE UpdateEvent;
Packit 1fb8d4
	freerdp_peer* peer;
Packit 1fb8d4
	rdpContext* context;
Packit 1fb8d4
	rdpSettings* settings;
Packit 1fb8d4
	rdpShadowServer* server;
Packit 1fb8d4
	rdpShadowSubsystem* subsystem;
Packit 1fb8d4
	wMessageQueue* MsgQueue = client->MsgQueue;
Packit 1fb8d4
	/* This should only be visited in client thread */
Packit 1fb8d4
	SHADOW_GFX_STATUS gfxstatus;
Packit 1fb8d4
	gfxstatus.gfxOpened = FALSE;
Packit 1fb8d4
	gfxstatus.gfxSurfaceCreated = FALSE;
Packit 1fb8d4
	server = client->server;
Packit 1fb8d4
	subsystem = server->subsystem;
Packit 1fb8d4
	context = (rdpContext*) client;
Packit 1fb8d4
	peer = context->peer;
Packit 1fb8d4
	settings = peer->settings;
Packit 1fb8d4
	peer->Capabilities = shadow_client_capabilities;
Packit 1fb8d4
	peer->PostConnect = shadow_client_post_connect;
Packit 1fb8d4
	peer->Activate = shadow_client_activate;
Packit 1fb8d4
	peer->Logon = shadow_client_logon;
Packit 1fb8d4
	shadow_input_register_callbacks(peer->input);
Packit 1fb8d4
	peer->Initialize(peer);
Packit 1fb8d4
	peer->update->RefreshRect = (pRefreshRect)shadow_client_refresh_rect;
Packit 1fb8d4
	peer->update->SuppressOutput = (pSuppressOutput)shadow_client_suppress_output;
Packit 1fb8d4
	peer->update->SurfaceFrameAcknowledge = (pSurfaceFrameAcknowledge)
Packit 1fb8d4
	                                        shadow_client_surface_frame_acknowledge;
Packit 1fb8d4
Packit 1fb8d4
	if ((!client->vcm) || (!subsystem->updateEvent))
Packit 1fb8d4
		goto out;
Packit 1fb8d4
Packit 1fb8d4
	UpdateSubscriber = shadow_multiclient_get_subscriber(subsystem->updateEvent);
Packit 1fb8d4
Packit 1fb8d4
	if (!UpdateSubscriber)
Packit 1fb8d4
		goto out;
Packit 1fb8d4
Packit 1fb8d4
	UpdateEvent = shadow_multiclient_getevent(UpdateSubscriber);
Packit 1fb8d4
	ChannelEvent = WTSVirtualChannelManagerGetEventHandle(client->vcm);
Packit 1fb8d4
Packit 1fb8d4
	while (1)
Packit 1fb8d4
	{
Packit 1fb8d4
		nCount = 0;
Packit 1fb8d4
		events[nCount++] = UpdateEvent;
Packit 1fb8d4
		{
Packit 1fb8d4
			DWORD tmp = peer->GetEventHandles(peer, &events[nCount], 64 - nCount);
Packit 1fb8d4
Packit 1fb8d4
			if (tmp == 0)
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "Failed to get FreeRDP transport event handles");
Packit 1fb8d4
				goto fail;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			nCount += tmp;
Packit 1fb8d4
		}
Packit 1fb8d4
		events[nCount++] = ChannelEvent;
Packit 1fb8d4
		events[nCount++] = MessageQueue_Event(MsgQueue);
Packit 1fb8d4
		status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
Packit 1fb8d4
Packit 1fb8d4
		if (status == WAIT_FAILED)
Packit 1fb8d4
			goto fail;
Packit 1fb8d4
Packit 1fb8d4
		if (WaitForSingleObject(UpdateEvent, 0) == WAIT_OBJECT_0)
Packit 1fb8d4
		{
Packit 1fb8d4
			/* The UpdateEvent means to start sending current frame. It is
Packit 1fb8d4
			 * triggered from subsystem implementation and it should ensure
Packit 1fb8d4
			 * that the screen and primary surface meta data (width, height,
Packit 1fb8d4
			 * scanline, invalid region, etc) is not changed until it is reset
Packit 1fb8d4
			 * (at shadow_multiclient_consume). As best practice, subsystem
Packit 1fb8d4
			 * implementation should invoke shadow_subsystem_frame_update which
Packit 1fb8d4
			 * triggers the event and then wait for completion */
Packit 1fb8d4
			if (client->activated && !client->suppressOutput)
Packit 1fb8d4
			{
Packit 1fb8d4
				/* Send screen update or resize to this client */
Packit 1fb8d4
Packit 1fb8d4
				/* Check resize */
Packit 1fb8d4
				if (shadow_client_recalc_desktop_size(client))
Packit 1fb8d4
				{
Packit 1fb8d4
					/* Screen size changed, do resize */
Packit 1fb8d4
					if (!shadow_client_send_resize(client, &gfxstatus))
Packit 1fb8d4
					{
Packit 1fb8d4
						WLog_ERR(TAG, "Failed to send resize message");
Packit 1fb8d4
						break;
Packit 1fb8d4
					}
Packit 1fb8d4
				}
Packit 1fb8d4
				else
Packit 1fb8d4
				{
Packit 1fb8d4
					/* Send frame */
Packit 1fb8d4
					if (!shadow_client_send_surface_update(client, &gfxstatus))
Packit 1fb8d4
					{
Packit 1fb8d4
						WLog_ERR(TAG, "Failed to send surface update");
Packit 1fb8d4
						break;
Packit 1fb8d4
					}
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
			else
Packit 1fb8d4
			{
Packit 1fb8d4
				/* Our client don't receive graphic updates. Just save the invalid region */
Packit 1fb8d4
				if (!shadow_client_no_surface_update(client, &gfxstatus))
Packit 1fb8d4
				{
Packit 1fb8d4
					WLog_ERR(TAG, "Failed to handle surface update");
Packit 1fb8d4
					break;
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			/*
Packit 1fb8d4
			 * The return value of shadow_multiclient_consume is whether or not
Packit 1fb8d4
			 * the subscriber really consumes the event. It's not cared currently.
Packit 1fb8d4
			 */
Packit 1fb8d4
			(void)shadow_multiclient_consume(UpdateSubscriber);
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (!peer->CheckFileDescriptor(peer))
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
Packit 1fb8d4
			goto fail;
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			if (WTSVirtualChannelManagerIsChannelJoined(client->vcm, "drdynvc"))
Packit 1fb8d4
			{
Packit 1fb8d4
				switch (WTSVirtualChannelManagerGetDrdynvcState(client->vcm))
Packit 1fb8d4
				{
Packit 1fb8d4
					/* Dynamic channel status may have been changed after processing */
Packit 1fb8d4
					case DRDYNVC_STATE_NONE:
Packit 1fb8d4
Packit 1fb8d4
						/* Call this routine to Initialize drdynvc channel */
Packit 1fb8d4
						if (!WTSVirtualChannelManagerCheckFileDescriptor(client->vcm))
Packit 1fb8d4
						{
Packit 1fb8d4
							WLog_ERR(TAG, "Failed to initialize drdynvc channel");
Packit 1fb8d4
							goto fail;
Packit 1fb8d4
						}
Packit 1fb8d4
Packit 1fb8d4
						break;
Packit 1fb8d4
Packit 1fb8d4
					case DRDYNVC_STATE_READY:
Packit 1fb8d4
						if (client->audin && !IFCALLRESULT(TRUE, client->audin->IsOpen, client->audin))
Packit 1fb8d4
						{
Packit 1fb8d4
							if (!IFCALLRESULT(FALSE, client->audin->Open, client->audin))
Packit 1fb8d4
							{
Packit 1fb8d4
								WLog_ERR(TAG, "Failed to initialize audin channel");
Packit 1fb8d4
								goto fail;
Packit 1fb8d4
							}
Packit 1fb8d4
						}
Packit 1fb8d4
Packit 1fb8d4
						/* Init RDPGFX dynamic channel */
Packit 1fb8d4
						if (settings->SupportGraphicsPipeline && client->rdpgfx &&
Packit 1fb8d4
						    !gfxstatus.gfxOpened)
Packit 1fb8d4
						{
Packit 1fb8d4
							client->rdpgfx->FrameAcknowledge = shadow_client_rdpgfx_frame_acknowledge;
Packit 1fb8d4
							client->rdpgfx->CapsAdvertise = shadow_client_rdpgfx_caps_advertise;
Packit 1fb8d4
Packit 1fb8d4
							if (!client->rdpgfx->Open(client->rdpgfx))
Packit 1fb8d4
							{
Packit 1fb8d4
								WLog_WARN(TAG, "Failed to open GraphicsPipeline");
Packit 1fb8d4
								settings->SupportGraphicsPipeline = FALSE;
Packit 1fb8d4
							}
Packit 1fb8d4
Packit 1fb8d4
							gfxstatus.gfxOpened = TRUE;
Packit 1fb8d4
							WLog_INFO(TAG, "Gfx Pipeline Opened");
Packit 1fb8d4
						}
Packit 1fb8d4
Packit 1fb8d4
						break;
Packit 1fb8d4
Packit 1fb8d4
					default:
Packit 1fb8d4
						break;
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (WaitForSingleObject(ChannelEvent, 0) == WAIT_OBJECT_0)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (!WTSVirtualChannelManagerCheckFileDescriptor(client->vcm))
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "WTSVirtualChannelManagerCheckFileDescriptor failure");
Packit 1fb8d4
				goto fail;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (WaitForSingleObject(MessageQueue_Event(MsgQueue), 0) == WAIT_OBJECT_0)
Packit 1fb8d4
		{
Packit 1fb8d4
			/* Drain messages. Pointer update could be accumulated. */
Packit 1fb8d4
			pointerPositionMsg.id = 0;
Packit 1fb8d4
			pointerPositionMsg.Free = NULL;
Packit 1fb8d4
			pointerAlphaMsg.id = 0;
Packit 1fb8d4
			pointerAlphaMsg.Free = NULL;
Packit 1fb8d4
			audioVolumeMsg.id = 0;
Packit 1fb8d4
			audioVolumeMsg.Free = NULL;
Packit 1fb8d4
Packit 1fb8d4
			while (MessageQueue_Peek(MsgQueue, &message, TRUE))
Packit 1fb8d4
			{
Packit 1fb8d4
				if (message.id == WMQ_QUIT)
Packit 1fb8d4
				{
Packit 1fb8d4
					break;
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				switch (message.id)
Packit 1fb8d4
				{
Packit 1fb8d4
					case SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID:
Packit 1fb8d4
						/* Abandon previous message */
Packit 1fb8d4
						shadow_client_free_queued_message(&pointerPositionMsg);
Packit 1fb8d4
						CopyMemory(&pointerPositionMsg, &message, sizeof(wMessage));
Packit 1fb8d4
						break;
Packit 1fb8d4
Packit 1fb8d4
					case SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID:
Packit 1fb8d4
						/* Abandon previous message */
Packit 1fb8d4
						shadow_client_free_queued_message(&pointerAlphaMsg);
Packit 1fb8d4
						CopyMemory(&pointerAlphaMsg, &message, sizeof(wMessage));
Packit 1fb8d4
						break;
Packit 1fb8d4
Packit 1fb8d4
					case SHADOW_MSG_OUT_AUDIO_OUT_VOLUME_ID:
Packit 1fb8d4
						/* Abandon previous message */
Packit 1fb8d4
						shadow_client_free_queued_message(&audioVolumeMsg);
Packit 1fb8d4
						CopyMemory(&audioVolumeMsg, &message, sizeof(wMessage));
Packit 1fb8d4
						break;
Packit 1fb8d4
Packit 1fb8d4
					default:
Packit 1fb8d4
						shadow_client_subsystem_process_message(client, &message);
Packit 1fb8d4
						break;
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if (message.id == WMQ_QUIT)
Packit 1fb8d4
			{
Packit 1fb8d4
				/* Release stored message */
Packit 1fb8d4
				shadow_client_free_queued_message(&pointerPositionMsg);
Packit 1fb8d4
				shadow_client_free_queued_message(&pointerAlphaMsg);
Packit 1fb8d4
				shadow_client_free_queued_message(&audioVolumeMsg);
Packit 1fb8d4
				goto fail;
Packit 1fb8d4
			}
Packit 1fb8d4
			else
Packit 1fb8d4
			{
Packit 1fb8d4
				/* Process accumulated messages if needed */
Packit 1fb8d4
				if (pointerPositionMsg.id)
Packit 1fb8d4
				{
Packit 1fb8d4
					shadow_client_subsystem_process_message(client, &pointerPositionMsg);
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				if (pointerAlphaMsg.id)
Packit 1fb8d4
				{
Packit 1fb8d4
					shadow_client_subsystem_process_message(client, &pointerAlphaMsg);
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				if (audioVolumeMsg.id)
Packit 1fb8d4
				{
Packit 1fb8d4
					shadow_client_subsystem_process_message(client, &audioVolumeMsg);
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
fail:
Packit 1fb8d4
Packit 1fb8d4
	/* Free channels early because we establish channels in post connect */
Packit 1fb8d4
	if (client->audin && !IFCALLRESULT(TRUE, client->audin->IsOpen, client->audin))
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!IFCALLRESULT(FALSE, client->audin->Close, client->audin))
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_WARN(TAG, "AUDIN shutdown failure!");
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (gfxstatus.gfxOpened)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (gfxstatus.gfxSurfaceCreated)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (!shadow_client_rdpgfx_release_surface(client))
Packit 1fb8d4
				WLog_WARN(TAG, "GFX release surface failure!");
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		(void)client->rdpgfx->Close(client->rdpgfx);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	shadow_client_channels_free(client);
Packit 1fb8d4
Packit 1fb8d4
	if (UpdateSubscriber)
Packit 1fb8d4
	{
Packit 1fb8d4
		shadow_multiclient_release_subscriber(UpdateSubscriber);
Packit 1fb8d4
		UpdateSubscriber = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (peer->connected && subsystem->ClientDisconnect)
Packit 1fb8d4
	{
Packit 1fb8d4
		subsystem->ClientDisconnect(subsystem, client);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
out:
Packit 1fb8d4
	peer->Disconnect(peer);
Packit 1fb8d4
	freerdp_peer_context_free(peer);
Packit 1fb8d4
	freerdp_peer_free(peer);
Packit 1fb8d4
	ExitThread(0);
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL shadow_client_accepted(freerdp_listener* listener, freerdp_peer* peer)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpShadowClient* client;
Packit 1fb8d4
	rdpShadowServer* server;
Packit 1fb8d4
Packit 1fb8d4
	if (!listener || !peer)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	server = (rdpShadowServer*) listener->info;
Packit 1fb8d4
	peer->ContextExtra = (void*) server;
Packit 1fb8d4
	peer->ContextSize = sizeof(rdpShadowClient);
Packit 1fb8d4
	peer->ContextNew = (psPeerContextNew) shadow_client_context_new;
Packit 1fb8d4
	peer->ContextFree = (psPeerContextFree) shadow_client_context_free;
Packit 1fb8d4
	peer->settings = freerdp_settings_clone(server->settings);
Packit 1fb8d4
Packit 1fb8d4
	if (!freerdp_peer_context_new(peer))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	client = (rdpShadowClient*) peer->context;
Packit 1fb8d4
Packit 1fb8d4
	if (!(client->thread = CreateThread(NULL, 0, shadow_client_thread, client, 0, NULL)))
Packit 1fb8d4
	{
Packit 1fb8d4
		freerdp_peer_context_free(peer);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		/* Close the thread handle to make it detached. */
Packit 1fb8d4
		CloseHandle(client->thread);
Packit 1fb8d4
		client->thread = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void shadow_msg_out_addref(wMessage* message)
Packit 1fb8d4
{
Packit 1fb8d4
	SHADOW_MSG_OUT* msg = (SHADOW_MSG_OUT*)message->wParam;
Packit 1fb8d4
	InterlockedIncrement(&(msg->refCount));
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void shadow_msg_out_release(wMessage* message)
Packit 1fb8d4
{
Packit 1fb8d4
	SHADOW_MSG_OUT* msg = (SHADOW_MSG_OUT*)message->wParam;
Packit 1fb8d4
Packit 1fb8d4
	if (InterlockedDecrement(&(msg->refCount)) <= 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (msg->Free)
Packit 1fb8d4
			msg->Free(message->id, msg);
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL shadow_client_dispatch_msg(rdpShadowClient* client,
Packit 1fb8d4
                                       wMessage* message)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!client || !message)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* Add reference when it is posted */
Packit 1fb8d4
	shadow_msg_out_addref(message);
Packit 1fb8d4
Packit 1fb8d4
	if (MessageQueue_Dispatch(client->MsgQueue, message))
Packit 1fb8d4
		return TRUE;
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		/* Release the reference since post failed */
Packit 1fb8d4
		shadow_msg_out_release(message);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL shadow_client_post_msg(rdpShadowClient* client, void* context, UINT32 type,
Packit 1fb8d4
                            SHADOW_MSG_OUT* msg, void* lParam)
Packit 1fb8d4
{
Packit 1fb8d4
	wMessage message = {0};
Packit 1fb8d4
	message.context = context;
Packit 1fb8d4
	message.id = type;
Packit 1fb8d4
	message.wParam = (void*)msg;
Packit 1fb8d4
	message.lParam = lParam;
Packit 1fb8d4
	message.Free = shadow_msg_out_release;
Packit 1fb8d4
	return shadow_client_dispatch_msg(client, &message);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int shadow_client_boardcast_msg(rdpShadowServer* server, void* context,
Packit 1fb8d4
                                UINT32 type, SHADOW_MSG_OUT* msg, void* lParam)
Packit 1fb8d4
{
Packit 1fb8d4
	wMessage message = {0};
Packit 1fb8d4
	rdpShadowClient* client = NULL;
Packit 1fb8d4
	int count = 0;
Packit 1fb8d4
	int index = 0;
Packit 1fb8d4
	message.context = context;
Packit 1fb8d4
	message.id = type;
Packit 1fb8d4
	message.wParam = (void*)msg;
Packit 1fb8d4
	message.lParam = lParam;
Packit 1fb8d4
	message.Free = shadow_msg_out_release;
Packit 1fb8d4
	/* First add reference as we reference it in this function.
Packit 1fb8d4
	 * Therefore it would not be free'ed during post. */
Packit 1fb8d4
	shadow_msg_out_addref(&message);
Packit 1fb8d4
	ArrayList_Lock(server->clients);
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < ArrayList_Count(server->clients); index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		client = (rdpShadowClient*)ArrayList_GetItem(server->clients, index);
Packit 1fb8d4
Packit 1fb8d4
		if (shadow_client_dispatch_msg(client, &message))
Packit 1fb8d4
		{
Packit 1fb8d4
			count++;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	ArrayList_Unlock(server->clients);
Packit 1fb8d4
	/* Release the reference for this function */
Packit 1fb8d4
	shadow_msg_out_release(&message);
Packit 1fb8d4
	return count;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int shadow_client_boardcast_quit(rdpShadowServer* server, int nExitCode)
Packit 1fb8d4
{
Packit 1fb8d4
	wMessageQueue* queue = NULL;
Packit 1fb8d4
	int count = 0;
Packit 1fb8d4
	int index = 0;
Packit 1fb8d4
	ArrayList_Lock(server->clients);
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < ArrayList_Count(server->clients); index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		queue = ((rdpShadowClient*)ArrayList_GetItem(server->clients, index))->MsgQueue;
Packit 1fb8d4
Packit 1fb8d4
		if (MessageQueue_PostQuit(queue, nExitCode))
Packit 1fb8d4
		{
Packit 1fb8d4
			count++;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	ArrayList_Unlock(server->clients);
Packit 1fb8d4
	return count;
Packit 1fb8d4
}