|
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 Service |
5a9772 |
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 Service |
5a9772 |
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 Service |
5a9772 |
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 Service |
5a9772 |
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 Service |
5a9772 |
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 Service |
5a9772 |
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 Service |
5a9772 |
static BOOL shadow_client_context_new(freerdp_peer* peer, rdpShadowClient* client)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
const char bind_address[] = "bind-address,";
|
|
Packit |
1fb8d4 |
rdpSettings* settings;
|
|
Packit |
1fb8d4 |
rdpShadowServer* server;
|
|
Packit |
1fb8d4 |
const wObject cb = { NULL, NULL, NULL, shadow_client_free_queued_message, NULL };
|
|
Packit Service |
5a9772 |
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 Service |
5a9772 |
if (server->ipcSocket && (strncmp(bind_address, server->ipcSocket,
|
|
Packit Service |
5a9772 |
strnlen(bind_address, sizeof(bind_address))) != 0))
|
|
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 Service |
5a9772 |
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 Service |
5a9772 |
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 Service |
5a9772 |
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 Service |
5a9772 |
static void shadow_client_context_free(freerdp_peer* peer, rdpShadowClient* client)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
rdpShadowServer* server = client->server;
|
|
Packit Service |
5a9772 |
WINPR_UNUSED(peer);
|
|
Packit Service |
5a9772 |
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 Service |
5a9772 |
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 Service |
5a9772 |
static INLINE void shadow_client_mark_invalid(rdpShadowClient* client, int numRects,
|
|
Packit Service |
5a9772 |
const RECTANGLE_16* rects)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
int index;
|
|
Packit |
1fb8d4 |
RECTANGLE_16 screenRegion;
|
|
Packit Service |
5a9772 |
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 Service |
5a9772 |
region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &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 Service |
5a9772 |
region16_union_rect(&(client->invalidRegion), &(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 Service |
5a9772 |
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 Service |
5a9772 |
if (settings->DesktopWidth != (UINT32)width || 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 Service |
5a9772 |
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 Service |
5a9772 |
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 Service |
5a9772 |
settings->NSCodec = FALSE; /* NSCodec compressor does not support fragmentation yet */
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
WLog_INFO(TAG, "Client from %s is activated (%" PRIu32 "x%" PRIu32 "@%" PRIu32 ")",
|
|
Packit Service |
5a9772 |
peer->hostname, settings->DesktopWidth, settings->DesktopHeight,
|
|
Packit Service |
5a9772 |
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 Service |
5a9772 |
WLog_INFO(TAG, "Client from %s is resized (%" PRIu32 "x%" PRIu32 "@%" PRIu32 ")",
|
|
Packit Service |
5a9772 |
peer->hostname, settings->DesktopWidth, settings->DesktopHeight,
|
|
Packit Service |
5a9772 |
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 Service |
5a9772 |
authStatus = subsystem->Authenticate(subsystem, client, settings->Username,
|
|
Packit Service |
5a9772 |
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 Service |
5a9772 |
static INLINE void shadow_client_convert_rects(rdpShadowClient* client, RECTANGLE_16* dst,
|
|
Packit Service |
5a9772 |
const RECTANGLE_16* src, UINT32 numRects)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (client->server->shareSubRect)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
UINT32 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 Service |
5a9772 |
message.context = (void*)client;
|
|
Packit |
1fb8d4 |
message.Free = NULL;
|
|
Packit |
1fb8d4 |
return MessageQueue_Dispatch(MsgPipe->In, &message);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
static BOOL shadow_client_refresh_rect(rdpContext* context, BYTE count, const RECTANGLE_16* areas)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
rdpShadowClient* client = (rdpShadowClient*)context;
|
|
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 Service |
5a9772 |
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 Service |
5a9772 |
static BOOL shadow_client_suppress_output(rdpContext* context, BYTE allow, const RECTANGLE_16* area)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
rdpShadowClient* client = (rdpShadowClient*)context;
|
|
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, ®ion, area, 1);
|
|
Packit |
1fb8d4 |
shadow_client_mark_invalid(client, 1, ®ion);
|
|
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 Service |
5a9772 |
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 Service |
5a9772 |
return shadow_client_refresh_rect(&client->context, 0, NULL);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
static BOOL shadow_client_logon(freerdp_peer* peer, 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 Service |
5a9772 |
ConvertFromUnicode(CP_UTF8, 0, identity->User, identity->UserLength, &user, 0, NULL,
|
|
Packit Service |
5a9772 |
NULL);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (identity->Domain)
|
|
Packit Service |
5a9772 |
ConvertFromUnicode(CP_UTF8, 0, identity->Domain, identity->DomainLength, &domain, 0,
|
|
Packit Service |
5a9772 |
NULL, NULL);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (identity->Password)
|
|
Packit Service |
5a9772 |
ConvertFromUnicode(CP_UTF8, 0, identity->Password, identity->PasswordLength, &user, 0,
|
|
Packit Service |
5a9772 |
NULL, NULL);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
else
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (identity->User)
|
|
Packit Service |
5a9772 |
user = _strdup((char*)identity->User);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (identity->Domain)
|
|
Packit Service |
5a9772 |
domain = _strdup((char*)identity->Domain);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (identity->Password)
|
|
Packit Service |
5a9772 |
password = _strdup((char*)identity->Password);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
if ((identity->User && !user) || (identity->Domain && !domain) ||
|
|
Packit Service |
5a9772 |
(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 Service |
5a9772 |
static INLINE void shadow_client_common_frame_acknowledge(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 Service |
5a9772 |
static BOOL shadow_client_surface_frame_acknowledge(rdpContext* context, UINT32 frameId)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
rdpShadowClient* client = (rdpShadowClient*)context;
|
|
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 Service |
5a9772 |
static UINT
|
|
Packit Service |
5a9772 |
shadow_client_rdpgfx_frame_acknowledge(RdpgfxServerContext* context,
|
|
Packit Service |
5a9772 |
const 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 Service |
5a9772 |
static BOOL shadow_are_caps_filtered(const rdpSettings* settings, UINT32 caps)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
const UINT32 filter = settings->GfxCapsFilter;
|
|
Packit Service |
5a9772 |
const UINT32 capList[] = {
|
|
Packit Service |
5a9772 |
RDPGFX_CAPVERSION_8, RDPGFX_CAPVERSION_81, RDPGFX_CAPVERSION_10,
|
|
Packit Service |
5a9772 |
RDPGFX_CAPVERSION_101, RDPGFX_CAPVERSION_102, RDPGFX_CAPVERSION_103,
|
|
Packit Service |
5a9772 |
RDPGFX_CAPVERSION_104, RDPGFX_CAPVERSION_105, RDPGFX_CAPVERSION_106
|
|
Packit Service |
5a9772 |
};
|
|
Packit Service |
5a9772 |
UINT32 x;
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
for (x = 0; x < ARRAYSIZE(capList); x++)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
if (caps == capList[x])
|
|
Packit Service |
5a9772 |
return (filter & (1 << x)) != 0;
|
|
Packit Service |
5a9772 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
return TRUE;
|
|
Packit Service |
5a9772 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
static BOOL shadow_client_caps_test_version(RdpgfxServerContext* context, BOOL h264,
|
|
Packit Service |
5a9772 |
const RDPGFX_CAPSET* capsSets, UINT32 capsSetCount,
|
|
Packit Service |
5a9772 |
UINT32 capsVersion, UINT* rc)
|
|
Packit Service |
5a9772 |
{
|
|
Packit Service |
5a9772 |
UINT32 flags = 0;
|
|
Packit Service |
5a9772 |
UINT32 index;
|
|
Packit Service |
5a9772 |
rdpSettings* settings;
|
|
Packit Service |
5a9772 |
settings = context->rdpcontext->settings;
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
if (shadow_are_caps_filtered(settings, capsVersion))
|
|
Packit Service |
5a9772 |
return FALSE;
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
for (index = 0; index < capsSetCount; index++)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
const RDPGFX_CAPSET* currentCaps = &capsSets[index];
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
if (currentCaps->version == capsVersion)
|
|
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 Service |
5a9772 |
|
|
Packit Service |
5a9772 |
if (h264)
|
|
Packit Service |
5a9772 |
settings->GfxAVC444v2 = settings->GfxAVC444 = settings->GfxH264 =
|
|
Packit Service |
5a9772 |
!(flags & RDPGFX_CAPS_FLAG_AVC_DISABLED);
|
|
Packit Service |
5a9772 |
else
|
|
Packit Service |
5a9772 |
{
|
|
Packit Service |
5a9772 |
settings->GfxAVC444v2 = settings->GfxAVC444 = settings->GfxH264 = FALSE;
|
|
Packit Service |
5a9772 |
pdu.capsSet->flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
|
|
Packit Service |
5a9772 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
*rc = context->CapsConfirm(context, &pdu);
|
|
Packit Service |
5a9772 |
return TRUE;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
return FALSE;
|
|
Packit Service |
5a9772 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
/**
|
|
Packit Service |
5a9772 |
* Function description
|
|
Packit Service |
5a9772 |
*
|
|
Packit Service |
5a9772 |
* @return 0 on success, otherwise a Win32 error code
|
|
Packit Service |
5a9772 |
*/
|
|
Packit Service |
5a9772 |
static UINT shadow_client_rdpgfx_caps_advertise(RdpgfxServerContext* context,
|
|
Packit Service |
5a9772 |
const RDPGFX_CAPS_ADVERTISE_PDU* capsAdvertise)
|
|
Packit Service |
5a9772 |
{
|
|
Packit Service |
5a9772 |
UINT16 index;
|
|
Packit Service |
5a9772 |
UINT rc = ERROR_INTERNAL_ERROR;
|
|
Packit Service |
5a9772 |
BOOL h264 = FALSE;
|
|
Packit Service |
5a9772 |
rdpSettings* settings = context->rdpcontext->settings;
|
|
Packit Service |
5a9772 |
UINT32 flags = 0;
|
|
Packit Service |
5a9772 |
rdpShadowClient* client = (rdpShadowClient*)context->custom;
|
|
Packit Service |
5a9772 |
|
|
Packit Service |
5a9772 |
#ifdef WITH_GFX_H264
|
|
Packit Service |
5a9772 |
if (shadow_encoder_prepare(client->encoder, FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444) >= 0)
|
|
Packit Service |
5a9772 |
h264 = TRUE;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#endif
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
/* Request full screen update for new gfx channel */
|
|
Packit Service |
5a9772 |
if (!shadow_client_refresh_rect(&client->context, 0, NULL))
|
|
Packit Service |
5a9772 |
return rc;
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
if (shadow_client_caps_test_version(context, h264, capsAdvertise->capsSets,
|
|
Packit Service |
5a9772 |
capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_106, &rc))
|
|
Packit Service |
5a9772 |
return rc;
|
|
Packit Service |
5a9772 |
|
|
Packit Service |
5a9772 |
if (shadow_client_caps_test_version(context, h264, capsAdvertise->capsSets,
|
|
Packit Service |
5a9772 |
capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_105, &rc))
|
|
Packit Service |
5a9772 |
return rc;
|
|
Packit Service |
5a9772 |
|
|
Packit Service |
5a9772 |
if (shadow_client_caps_test_version(context, h264, capsAdvertise->capsSets,
|
|
Packit Service |
5a9772 |
capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_104, &rc))
|
|
Packit Service |
5a9772 |
return rc;
|
|
Packit Service |
5a9772 |
|
|
Packit Service |
5a9772 |
if (shadow_client_caps_test_version(context, h264, capsAdvertise->capsSets,
|
|
Packit Service |
5a9772 |
capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_103, &rc))
|
|
Packit Service |
5a9772 |
return rc;
|
|
Packit Service |
5a9772 |
|
|
Packit Service |
5a9772 |
if (shadow_client_caps_test_version(context, h264, capsAdvertise->capsSets,
|
|
Packit Service |
5a9772 |
capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_102, &rc))
|
|
Packit Service |
5a9772 |
return rc;
|
|
Packit Service |
5a9772 |
|
|
Packit Service |
5a9772 |
if (shadow_client_caps_test_version(context, h264, capsAdvertise->capsSets,
|
|
Packit Service |
5a9772 |
capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_101, &rc))
|
|
Packit Service |
5a9772 |
return rc;
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
if (shadow_client_caps_test_version(context, h264, capsAdvertise->capsSets,
|
|
Packit Service |
5a9772 |
capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_10, &rc))
|
|
Packit Service |
5a9772 |
return rc;
|
|
Packit Service |
5a9772 |
|
|
Packit Service |
5a9772 |
if (!shadow_are_caps_filtered(settings, RDPGFX_CAPVERSION_81))
|
|
Packit Service |
5a9772 |
{
|
|
Packit Service |
5a9772 |
for (index = 0; index < capsAdvertise->capsSetCount; index++)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
const RDPGFX_CAPSET* currentCaps = &capsAdvertise->capsSets[index];
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
if (currentCaps->version == RDPGFX_CAPVERSION_81)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
RDPGFX_CAPSET caps = *currentCaps;
|
|
Packit Service |
5a9772 |
RDPGFX_CAPS_CONFIRM_PDU pdu;
|
|
Packit Service |
5a9772 |
pdu.capsSet = ∩︀
|
|
Packit Service |
5a9772 |
|
|
Packit Service |
5a9772 |
if (settings)
|
|
Packit Service |
5a9772 |
{
|
|
Packit Service |
5a9772 |
flags = pdu.capsSet->flags;
|
|
Packit Service |
5a9772 |
settings->GfxAVC444v2 = settings->GfxAVC444 = FALSE;
|
|
Packit Service |
5a9772 |
settings->GfxThinClient = (flags & RDPGFX_CAPS_FLAG_THINCLIENT);
|
|
Packit Service |
5a9772 |
settings->GfxSmallCache = (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE);
|
|
Packit |
1fb8d4 |
#ifndef WITH_GFX_H264
|
|
Packit Service |
5a9772 |
settings->GfxH264 = FALSE;
|
|
Packit Service |
5a9772 |
pdu.capsSet->flags &= ~RDPGFX_CAPS_FLAG_AVC420_ENABLED;
|
|
Packit |
1fb8d4 |
#else
|
|
Packit Service |
5a9772 |
if (h264)
|
|
Packit Service |
5a9772 |
settings->GfxH264 = (flags & RDPGFX_CAPS_FLAG_AVC420_ENABLED);
|
|
Packit Service |
5a9772 |
else
|
|
Packit Service |
5a9772 |
settings->GfxH264 = FALSE;
|
|
Packit |
1fb8d4 |
#endif
|
|
Packit Service |
5a9772 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
return context->CapsConfirm(context, &pdu);
|
|
Packit Service |
5a9772 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
if (!shadow_are_caps_filtered(settings, RDPGFX_CAPVERSION_8))
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
for (index = 0; index < capsAdvertise->capsSetCount; index++)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
const RDPGFX_CAPSET* currentCaps = &capsAdvertise->capsSets[index];
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
if (currentCaps->version == RDPGFX_CAPVERSION_8)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
RDPGFX_CAPSET caps = *currentCaps;
|
|
Packit Service |
5a9772 |
RDPGFX_CAPS_CONFIRM_PDU pdu;
|
|
Packit Service |
5a9772 |
pdu.capsSet = ∩︀
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
if (settings)
|
|
Packit Service |
5a9772 |
{
|
|
Packit Service |
5a9772 |
flags = pdu.capsSet->flags;
|
|
Packit Service |
5a9772 |
settings->GfxThinClient = (flags & RDPGFX_CAPS_FLAG_THINCLIENT);
|
|
Packit Service |
5a9772 |
settings->GfxSmallCache = (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE);
|
|
Packit Service |
5a9772 |
}
|
|
Packit Service |
5a9772 |
|
|
Packit Service |
5a9772 |
return context->CapsConfirm(context, &pdu);
|
|
Packit Service |
5a9772 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
return CHANNEL_RC_UNSUPPORTED_VERSION;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
static INLINE UINT32 rdpgfx_estimate_h264_avc420(RDPGFX_AVC420_BITMAP_STREAM* havc420)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
/* H264 metadata + H264 stream. See rdpgfx_write_h264_avc420 */
|
|
Packit |
1fb8d4 |
return sizeof(UINT32) /* numRegionRects */
|
|
Packit Service |
5a9772 |
+ 10 /* regionRects + quantQualityVals */
|
|
Packit Service |
5a9772 |
* havc420->meta.numRegionRects +
|
|
Packit Service |
5a9772 |
havc420->length;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/**
|
|
Packit |
1fb8d4 |
* Function description
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* @return TRUE on success
|
|
Packit |
1fb8d4 |
*/
|
|
Packit Service |
5a9772 |
static BOOL shadow_client_send_surface_gfx(rdpShadowClient* client, const BYTE* pSrcData,
|
|
Packit Service |
5a9772 |
int nSrcStep, int nXSrc, int nYSrc, int nWidth,
|
|
Packit Service |
5a9772 |
int nHeight)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
UINT error = CHANNEL_RC_OK;
|
|
Packit Service |
5a9772 |
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 Service |
5a9772 |
cmdstart.timestamp =
|
|
Packit Service |
5a9772 |
sTime.wHour << 22 | sTime.wMinute << 16 | 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 Service |
5a9772 |
if (avc444_compress(encoder->h264, pSrcData, cmd.format, nSrcStep, nWidth, nHeight, version,
|
|
Packit Service |
5a9772 |
&avc444.LC, &avc444.bitstream[0].data, &avc444.bitstream[0].length,
|
|
Packit Service |
5a9772 |
&avc444.bitstream[1].data, &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 = ®ionRect;
|
|
Packit |
1fb8d4 |
avc444.bitstream[0].meta.quantQualityVals = &quantQualityVal;
|
|
Packit |
1fb8d4 |
avc444.bitstream[1].meta.numRegionRects = 1;
|
|
Packit |
1fb8d4 |
avc444.bitstream[1].meta.regionRects = ®ionRect;
|
|
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 Service |
5a9772 |
IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, &cmd, &cmdstart,
|
|
Packit Service |
5a9772 |
&cmdend);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (error)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
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 Service |
5a9772 |
if (avc420_compress(encoder->h264, pSrcData, cmd.format, nSrcStep, nWidth, nHeight,
|
|
Packit Service |
5a9772 |
&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 = ®ionRect;
|
|
Packit |
1fb8d4 |
avc420.meta.quantQualityVals = &quantQualityVal;
|
|
Packit Service |
5a9772 |
IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, &cmd, &cmdstart,
|
|
Packit Service |
5a9772 |
&cmdend);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (error)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
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 Service |
5a9772 |
static BOOL shadow_client_send_surface_bits(rdpShadowClient* client, BYTE* pSrcData, int nSrcStep,
|
|
Packit Service |
5a9772 |
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 Service |
5a9772 |
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 Service |
5a9772 |
if (!(messages = rfx_encode_messages(
|
|
Packit Service |
5a9772 |
encoder->rfx, &rect, 1, pSrcData, settings->DesktopWidth, settings->DesktopHeight,
|
|
Packit Service |
5a9772 |
nSrcStep, &numMessages, settings->MultifragMaxRequestSize)))
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "rfx_encode_messages failed");
|
|
Packit |
1fb8d4 |
return FALSE;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
cmd.cmdType = CMDTYPE_STREAM_SURFACE_BITS;
|
|
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 Service |
5a9772 |
cmd.cmdType = CMDTYPE_SET_SURFACE_BITS;
|
|
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 Service |
5a9772 |
IFCALLRET(update->SurfaceFrameBits, ret, update->context, &cmd, first, last, 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 Service |
5a9772 |
static BOOL shadow_client_send_bitmap_update(rdpShadowClient* client, BYTE* pSrcData, int nSrcStep,
|
|
Packit Service |
5a9772 |
int nXSrc, int nYSrc, int nWidth, int nHeight)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
BOOL ret = TRUE;
|
|
Packit |
1fb8d4 |
BYTE* data;
|
|
Packit |
1fb8d4 |
BYTE* buffer;
|
|
Packit Service |
5a9772 |
size_t k;
|
|
Packit Service |
5a9772 |
int yIdx, xIdx;
|
|
Packit |
1fb8d4 |
int rows, cols;
|
|
Packit |
1fb8d4 |
UINT32 DstSize;
|
|
Packit |
1fb8d4 |
UINT32 SrcFormat;
|
|
Packit |
1fb8d4 |
BITMAP_DATA* bitmap;
|
|
Packit |
1fb8d4 |
rdpUpdate* update;
|
|
Packit Service |
5a9772 |
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 Service |
5a9772 |
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 Service |
5a9772 |
if ((INT64)(bitmap->destLeft + bitmap->width) > (nXSrc + nWidth))
|
|
Packit Service |
5a9772 |
bitmap->width = (UINT32)(nXSrc + nWidth) - bitmap->destLeft;
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
if ((INT64)(bitmap->destTop + bitmap->height) > (nYSrc + nHeight))
|
|
Packit Service |
5a9772 |
bitmap->height = (UINT32)(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 Service |
5a9772 |
bitmap->height, pSrcData, SrcFormat, nSrcStep,
|
|
Packit Service |
5a9772 |
bitmap->destLeft, bitmap->destTop, NULL, 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 Service |
5a9772 |
buffer =
|
|
Packit Service |
5a9772 |
freerdp_bitmap_compress_planar(encoder->planar, data, SrcFormat, bitmap->width,
|
|
Packit Service |
5a9772 |
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 Service |
5a9772 |
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 Service |
5a9772 |
static BOOL shadow_client_send_surface_update(rdpShadowClient* client, SHADOW_GFX_STATUS* pStatus)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
BOOL ret = TRUE;
|
|
Packit |
1fb8d4 |
int nXSrc, nYSrc;
|
|
Packit |
1fb8d4 |
int nWidth, nHeight;
|
|
Packit Service |
5a9772 |
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 Service |
5a9772 |
// WLog_INFO(TAG, "shadow_client_send_surface_update: x: %d y: %d width: %d height: %d right: %d
|
|
Packit Service |
5a9772 |
// bottom: %d", nXSrc, nYSrc, nWidth, nHeight, nXSrc + nWidth, nYSrc + nHeight);
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
if (settings->SupportGraphicsPipeline && settings->GfxH264 && 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 Service |
5a9772 |
ret = shadow_client_send_surface_gfx(client, pSrcData, nSrcStep, 0, 0, nWidth, nHeight);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
else if (settings->RemoteFxCodec || settings->NSCodec)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
ret = shadow_client_send_surface_bits(client, pSrcData, nSrcStep, nXSrc, nYSrc, nWidth,
|
|
Packit Service |
5a9772 |
nHeight);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
else
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
ret = shadow_client_send_bitmap_update(client, pSrcData, nSrcStep, nXSrc, nYSrc, nWidth,
|
|
Packit Service |
5a9772 |
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 Service |
5a9772 |
static BOOL shadow_client_send_resize(rdpShadowClient* client, SHADOW_GFX_STATUS* pStatus)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
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 Service |
5a9772 |
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 Service |
5a9772 |
static 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 Service |
5a9772 |
SHADOW_GFX_STATUS* pStatus)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
rdpShadowServer* server;
|
|
Packit |
1fb8d4 |
rdpShadowSurface* surface;
|
|
Packit Service |
5a9772 |
WINPR_UNUSED(pStatus);
|
|
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 Service |
5a9772 |
static int shadow_client_subsystem_process_message(rdpShadowClient* client, wMessage* message)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
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 Service |
5a9772 |
{
|
|
Packit Service |
5a9772 |
POINTER_POSITION_UPDATE pointerPosition;
|
|
Packit Service |
5a9772 |
SHADOW_MSG_OUT_POINTER_POSITION_UPDATE* msg =
|
|
Packit Service |
5a9772 |
(SHADOW_MSG_OUT_POINTER_POSITION_UPDATE*)message->wParam;
|
|
Packit Service |
5a9772 |
pointerPosition.xPos = msg->xPos;
|
|
Packit Service |
5a9772 |
pointerPosition.yPos = msg->yPos;
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
if (client->server->shareSubRect)
|
|
Packit Service |
5a9772 |
{
|
|
Packit Service |
5a9772 |
pointerPosition.xPos -= client->server->subRect.left;
|
|
Packit Service |
5a9772 |
pointerPosition.yPos -= client->server->subRect.top;
|
|
Packit Service |
5a9772 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
if (client->activated)
|
|
Packit Service |
5a9772 |
{
|
|
Packit Service |
5a9772 |
if ((msg->xPos != client->pointerX) || (msg->yPos != client->pointerY))
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
IFCALL(update->pointer->PointerPosition, context, &pointerPosition);
|
|
Packit Service |
5a9772 |
client->pointerX = msg->xPos;
|
|
Packit Service |
5a9772 |
client->pointerY = msg->yPos;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
break;
|
|
Packit Service |
5a9772 |
}
|
|
Packit Service |
5a9772 |
|
|
Packit |
1fb8d4 |
case SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID:
|
|
Packit Service |
5a9772 |
{
|
|
Packit Service |
5a9772 |
POINTER_NEW_UPDATE pointerNew;
|
|
Packit Service |
5a9772 |
POINTER_COLOR_UPDATE* pointerColor;
|
|
Packit Service |
5a9772 |
POINTER_CACHED_UPDATE pointerCached;
|
|
Packit Service |
5a9772 |
SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE* msg =
|
|
Packit Service |
5a9772 |
(SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE*)message->wParam;
|
|
Packit Service |
5a9772 |
ZeroMemory(&pointerNew, sizeof(POINTER_NEW_UPDATE));
|
|
Packit Service |
5a9772 |
pointerNew.xorBpp = 24;
|
|
Packit Service |
5a9772 |
pointerColor = &(pointerNew.colorPtrAttr);
|
|
Packit Service |
5a9772 |
pointerColor->cacheIndex = 0;
|
|
Packit Service |
5a9772 |
pointerColor->xPos = msg->xHot;
|
|
Packit Service |
5a9772 |
pointerColor->yPos = msg->yHot;
|
|
Packit Service |
5a9772 |
pointerColor->width = msg->width;
|
|
Packit Service |
5a9772 |
pointerColor->height = msg->height;
|
|
Packit Service |
5a9772 |
pointerColor->lengthAndMask = msg->lengthAndMask;
|
|
Packit Service |
5a9772 |
pointerColor->lengthXorMask = msg->lengthXorMask;
|
|
Packit Service |
5a9772 |
pointerColor->xorMaskData = msg->xorMaskData;
|
|
Packit Service |
5a9772 |
pointerColor->andMaskData = msg->andMaskData;
|
|
Packit Service |
5a9772 |
pointerCached.cacheIndex = pointerColor->cacheIndex;
|
|
Packit Service |
5a9772 |
|
|
Packit Service |
5a9772 |
if (client->activated)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
IFCALL(update->pointer->PointerNew, context, &pointerNew);
|
|
Packit Service |
5a9772 |
IFCALL(update->pointer->PointerCached, context, &pointerCached);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
break;
|
|
Packit Service |
5a9772 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
case SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES_ID:
|
|
Packit Service |
5a9772 |
{
|
|
Packit Service |
5a9772 |
SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES* msg =
|
|
Packit Service |
5a9772 |
(SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES*)message->wParam;
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
if (client->activated && client->rdpsnd && client->rdpsnd->Activated)
|
|
Packit Service |
5a9772 |
{
|
|
Packit Service |
5a9772 |
client->rdpsnd->src_format = msg->audio_format;
|
|
Packit Service |
5a9772 |
IFCALL(client->rdpsnd->SendSamples, client->rdpsnd, msg->buf, msg->nFrames,
|
|
Packit Service |
5a9772 |
msg->wTimestamp);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
break;
|
|
Packit Service |
5a9772 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
case SHADOW_MSG_OUT_AUDIO_OUT_VOLUME_ID:
|
|
Packit Service |
5a9772 |
{
|
|
Packit Service |
5a9772 |
SHADOW_MSG_OUT_AUDIO_OUT_VOLUME* msg =
|
|
Packit Service |
5a9772 |
(SHADOW_MSG_OUT_AUDIO_OUT_VOLUME*)message->wParam;
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
if (client->activated && client->rdpsnd && client->rdpsnd->Activated)
|
|
Packit Service |
5a9772 |
{
|
|
Packit Service |
5a9772 |
IFCALL(client->rdpsnd->SetVolume, client->rdpsnd, msg->left, msg->right);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
break;
|
|
Packit Service |
5a9772 |
}
|
|
Packit Service |
5a9772 |
|
|
Packit |
1fb8d4 |
default:
|
|
Packit Service |
5a9772 |
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 Service |
5a9772 |
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 Service |
5a9772 |
peer->update->RefreshRect = shadow_client_refresh_rect;
|
|
Packit Service |
5a9772 |
peer->update->SuppressOutput = shadow_client_suppress_output;
|
|
Packit Service |
5a9772 |
peer->update->SurfaceFrameAcknowledge = 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 Service |
5a9772 |
if (client->audin &&
|
|
Packit Service |
5a9772 |
!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 Service |
5a9772 |
client->rdpgfx->FrameAcknowledge =
|
|
Packit Service |
5a9772 |
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 Service |
5a9772 |
server = (rdpShadowServer*)listener->info;
|
|
Packit Service |
5a9772 |
peer->ContextExtra = (void*)server;
|
|
Packit |
1fb8d4 |
peer->ContextSize = sizeof(rdpShadowClient);
|
|
Packit Service |
5a9772 |
peer->ContextNew = (psPeerContextNew)shadow_client_context_new;
|
|
Packit Service |
5a9772 |
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 Service |
5a9772 |
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 Service |
5a9772 |
static BOOL shadow_client_dispatch_msg(rdpShadowClient* client, 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 Service |
5a9772 |
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 Service |
5a9772 |
int shadow_client_boardcast_msg(rdpShadowServer* server, void* context, UINT32 type,
|
|
Packit Service |
5a9772 |
SHADOW_MSG_OUT* msg, void* lParam)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
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 |
}
|