dynamic channels: mutualize things for listeners and plugins

The same code is copied in all dynamic channels to create a plugin, have a listener,
and manage the channel lifecycle. This patch does a mutualization effort so that channels
only have to code things that are specific to them.
This commit is contained in:
David Fort 2022-06-21 08:09:00 +02:00 committed by akallabeth
parent ffcb25a925
commit 3478051f15
12 changed files with 580 additions and 979 deletions

View File

@ -41,13 +41,10 @@
typedef struct AINPUT_PLUGIN_ AINPUT_PLUGIN;
struct AINPUT_PLUGIN_
{
IWTSPlugin iface;
GENERIC_LISTENER_CALLBACK* listener_callback;
IWTSListener* listener;
GENERIC_DYNVC_PLUGIN base;
AInputClientContext* context;
UINT32 MajorVersion;
UINT32 MinorVersion;
BOOL initialized;
};
/**
@ -101,7 +98,6 @@ static UINT ainput_send_input_event(AInputClientContext* context, UINT64 flags,
time = GetTickCount64();
ainput = (AINPUT_PLUGIN*)context->handle;
WINPR_ASSERT(ainput);
WINPR_ASSERT(ainput->listener_callback);
if (ainput->MajorVersion != AINPUT_VERSION_MAJOR)
{
@ -109,7 +105,7 @@ static UINT ainput_send_input_event(AInputClientContext* context, UINT64 flags,
ainput->MajorVersion, ainput->MinorVersion);
return CHANNEL_RC_UNSUPPORTED_VERSION;
}
callback = ainput->listener_callback->channel_callback;
callback = ainput->base.listener_callback->channel_callback;
WINPR_ASSERT(callback);
{
@ -149,104 +145,30 @@ static UINT ainput_on_close(IWTSVirtualChannelCallback* pChannelCallback)
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT ainput_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
IWTSVirtualChannel* pChannel, BYTE* Data,
BOOL* pbAccept,
IWTSVirtualChannelCallback** ppCallback)
static UINT init_plugin_cb(GENERIC_DYNVC_PLUGIN* base, rdpContext* rcontext, rdpSettings* settings)
{
GENERIC_CHANNEL_CALLBACK* callback;
GENERIC_LISTENER_CALLBACK* listener_callback = (GENERIC_LISTENER_CALLBACK*)pListenerCallback;
WINPR_ASSERT(listener_callback);
WINPR_UNUSED(Data);
WINPR_UNUSED(pbAccept);
callback = (GENERIC_CHANNEL_CALLBACK*)calloc(1, sizeof(GENERIC_CHANNEL_CALLBACK));
if (!callback)
{
WLog_ERR(TAG, "calloc failed!");
AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)base;
AInputClientContext* context = (AInputClientContext*)calloc(1, sizeof(AInputClientContext));
if (!context)
return CHANNEL_RC_NO_MEMORY;
}
callback->iface.OnDataReceived = ainput_on_data_received;
callback->iface.OnClose = ainput_on_close;
callback->plugin = listener_callback->plugin;
callback->channel_mgr = listener_callback->channel_mgr;
callback->channel = pChannel;
listener_callback->channel_callback = callback;
*ppCallback = &callback->iface;
context->handle = (void*)base;
context->AInputSendInputEvent = ainput_send_input_event;
ainput->context = context;
ainput->base.iface.pInterface = context;
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT ainput_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
static void terminate_plugin_cb(GENERIC_DYNVC_PLUGIN* base)
{
UINT status;
AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)pPlugin;
WINPR_ASSERT(ainput);
if (ainput->initialized)
{
WLog_ERR(TAG, "[%s] channel initialized twice, aborting", AINPUT_DVC_CHANNEL_NAME);
return ERROR_INVALID_DATA;
}
ainput->listener_callback =
(GENERIC_LISTENER_CALLBACK*)calloc(1, sizeof(GENERIC_LISTENER_CALLBACK));
if (!ainput->listener_callback)
{
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
ainput->listener_callback->iface.OnNewChannelConnection = ainput_on_new_channel_connection;
ainput->listener_callback->plugin = pPlugin;
ainput->listener_callback->channel_mgr = pChannelMgr;
status = pChannelMgr->CreateListener(pChannelMgr, AINPUT_DVC_CHANNEL_NAME, 0,
&ainput->listener_callback->iface, &ainput->listener);
ainput->listener->pInterface = ainput->iface.pInterface;
ainput->initialized = status == CHANNEL_RC_OK;
return status;
AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)base;
free(ainput->context);
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT ainput_plugin_terminated(IWTSPlugin* pPlugin)
{
AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)pPlugin;
if (ainput && ainput->listener_callback)
{
IWTSVirtualChannelManager* mgr = ainput->listener_callback->channel_mgr;
if (mgr)
IFCALL(mgr->DestroyListener, mgr, ainput->listener);
}
if (ainput)
{
free(ainput->listener_callback);
free(ainput->iface.pInterface);
}
free(ainput);
return CHANNEL_RC_OK;
}
static const IWTSVirtualChannelCallback ainput_functions = { ainput_on_data_received,
NULL, /* Open */
ainput_on_close };
/**
* Function description
@ -255,32 +177,7 @@ static UINT ainput_plugin_terminated(IWTSPlugin* pPlugin)
*/
UINT ainput_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
{
UINT status = CHANNEL_RC_OK;
AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "ainput");
if (!ainput)
{
AInputClientContext* context = (AInputClientContext*)calloc(1, sizeof(AInputClientContext));
ainput = (AINPUT_PLUGIN*)calloc(1, sizeof(AINPUT_PLUGIN));
if (!ainput || !context)
{
free(context);
free(ainput);
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
ainput->iface.Initialize = ainput_plugin_initialize;
ainput->iface.Terminated = ainput_plugin_terminated;
context->handle = (void*)ainput;
context->AInputSendInputEvent = ainput_send_input_event;
ainput->iface.pInterface = (void*)context;
status = pEntryPoints->RegisterPlugin(pEntryPoints, AINPUT_CHANNEL_NAME, &ainput->iface);
}
return status;
return freerdp_generic_DVCPluginEntry(pEntryPoints, TAG, AINPUT_DVC_CHANNEL_NAME,
sizeof(AINPUT_PLUGIN), sizeof(GENERIC_CHANNEL_CALLBACK),
&ainput_functions, init_plugin_cb, terminate_plugin_cb);
}

View File

@ -22,7 +22,8 @@ set(${MODULE_PREFIX}_SRCS
${CMAKE_CURRENT_BINARY_DIR}/tables.c
${CMAKE_CURRENT_SOURCE_DIR}/tables.h
${CMAKE_CURRENT_SOURCE_DIR}/addin.c
${CMAKE_CURRENT_SOURCE_DIR}/addin.h)
${CMAKE_CURRENT_SOURCE_DIR}/addin.h
${CMAKE_CURRENT_SOURCE_DIR}/generic_dynvc.c)
if(CHANNEL_STATIC_CLIENT_ENTRIES)
list(REMOVE_DUPLICATES CHANNEL_STATIC_CLIENT_ENTRIES)

View File

@ -0,0 +1,209 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Dynamic channel
*
* Copyright 2022 David Fort <contact@hardening-consulting.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <freerdp/config.h>
#include <freerdp/log.h>
#include <freerdp/client/channels.h>
#define TAG FREERDP_TAG("genericdynvc")
static UINT generic_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
IWTSVirtualChannel* pChannel, BYTE* Data,
BOOL* pbAccept,
IWTSVirtualChannelCallback** ppCallback)
{
GENERIC_CHANNEL_CALLBACK* callback;
GENERIC_DYNVC_PLUGIN* plugin;
GENERIC_LISTENER_CALLBACK* listener_callback = (GENERIC_LISTENER_CALLBACK*)pListenerCallback;
if (!listener_callback || !listener_callback->plugin)
return ERROR_INTERNAL_ERROR;
plugin = (GENERIC_DYNVC_PLUGIN*)listener_callback->plugin;
WLog_Print(plugin->log, WLOG_TRACE, "...");
callback = (GENERIC_CHANNEL_CALLBACK*)calloc(1, plugin->channelCallbackSize);
if (!callback)
{
WLog_Print(plugin->log, WLOG_ERROR, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
/* implant configured channel callbacks */
callback->iface = *plugin->channel_callbacks;
callback->plugin = listener_callback->plugin;
callback->channel_mgr = listener_callback->channel_mgr;
callback->channel = pChannel;
listener_callback->channel_callback = callback;
*ppCallback = (IWTSVirtualChannelCallback*)callback;
return CHANNEL_RC_OK;
}
static UINT generic_dynvc_plugin_initialize(IWTSPlugin* pPlugin,
IWTSVirtualChannelManager* pChannelMgr)
{
UINT rc;
GENERIC_LISTENER_CALLBACK* listener_callback;
GENERIC_DYNVC_PLUGIN* plugin = (GENERIC_DYNVC_PLUGIN*)pPlugin;
if (!plugin)
return CHANNEL_RC_BAD_CHANNEL_HANDLE;
if (!pChannelMgr)
return ERROR_INVALID_PARAMETER;
if (plugin->initialized)
{
WLog_ERR(TAG, "[%s] channel initialized twice, aborting", plugin->dynvc_name);
return ERROR_INVALID_DATA;
}
WLog_Print(plugin->log, WLOG_TRACE, "...");
listener_callback = (GENERIC_LISTENER_CALLBACK*)calloc(1, sizeof(GENERIC_LISTENER_CALLBACK));
if (!listener_callback)
{
WLog_Print(plugin->log, WLOG_ERROR, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
plugin->listener_callback = listener_callback;
listener_callback->iface.OnNewChannelConnection = generic_on_new_channel_connection;
listener_callback->plugin = pPlugin;
listener_callback->channel_mgr = pChannelMgr;
rc = pChannelMgr->CreateListener(pChannelMgr, plugin->dynvc_name, 0, &listener_callback->iface,
&plugin->listener);
plugin->listener->pInterface = plugin->iface.pInterface;
plugin->initialized = (rc == CHANNEL_RC_OK);
return rc;
}
static UINT generic_plugin_terminated(IWTSPlugin* pPlugin)
{
GENERIC_DYNVC_PLUGIN* plugin = (GENERIC_DYNVC_PLUGIN*)pPlugin;
UINT error = CHANNEL_RC_OK;
if (!plugin)
return CHANNEL_RC_BAD_CHANNEL_HANDLE;
WLog_Print(plugin->log, WLOG_TRACE, "...");
if (plugin->terminatePluginFn)
plugin->terminatePluginFn(plugin);
if (plugin->listener_callback)
{
IWTSVirtualChannelManager* mgr = plugin->listener_callback->channel_mgr;
if (mgr)
IFCALL(mgr->DestroyListener, mgr, plugin->listener);
}
free(plugin->listener_callback);
free(plugin->dynvc_name);
free(plugin);
return error;
}
static UINT generic_dynvc_plugin_attached(IWTSPlugin* pPlugin)
{
GENERIC_DYNVC_PLUGIN* pluginn = (GENERIC_DYNVC_PLUGIN*)pPlugin;
UINT error = CHANNEL_RC_OK;
if (!pluginn)
return CHANNEL_RC_BAD_CHANNEL_HANDLE;
pluginn->attached = TRUE;
return error;
}
static UINT generic_dynvc_plugin_detached(IWTSPlugin* pPlugin)
{
GENERIC_DYNVC_PLUGIN* plugin = (GENERIC_DYNVC_PLUGIN*)pPlugin;
UINT error = CHANNEL_RC_OK;
if (!plugin)
return CHANNEL_RC_BAD_CHANNEL_HANDLE;
plugin->attached = FALSE;
return error;
}
UINT freerdp_generic_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints, const char* logTag,
const char* name, size_t pluginSize, size_t channelCallbackSize,
const IWTSVirtualChannelCallback* channel_callbacks,
DYNVC_PLUGIN_INIT_FN initPluginFn,
DYNVC_PLUGIN_TERMINATE_FN terminatePluginFn)
{
GENERIC_DYNVC_PLUGIN* plugin;
UINT error = CHANNEL_RC_INITIALIZATION_ERROR;
WINPR_ASSERT(pEntryPoints);
WINPR_ASSERT(pEntryPoints->GetPlugin);
WINPR_ASSERT(logTag);
WINPR_ASSERT(name);
WINPR_ASSERT(pluginSize >= sizeof(*plugin));
WINPR_ASSERT(channelCallbackSize >= sizeof(GENERIC_CHANNEL_CALLBACK));
plugin = (GENERIC_DYNVC_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, name);
if (plugin != NULL)
return CHANNEL_RC_ALREADY_INITIALIZED;
plugin = (GENERIC_DYNVC_PLUGIN*)calloc(1, pluginSize);
if (!plugin)
{
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
plugin->log = WLog_Get(logTag);
plugin->attached = TRUE;
plugin->channel_callbacks = channel_callbacks;
plugin->channelCallbackSize = channelCallbackSize;
plugin->iface.Initialize = generic_dynvc_plugin_initialize;
plugin->iface.Connected = NULL;
plugin->iface.Disconnected = NULL;
plugin->iface.Terminated = generic_plugin_terminated;
plugin->iface.Attached = generic_dynvc_plugin_attached;
plugin->iface.Detached = generic_dynvc_plugin_detached;
plugin->terminatePluginFn = terminatePluginFn;
if (initPluginFn)
{
rdpSettings* settings = pEntryPoints->GetRdpSettings(pEntryPoints);
rdpContext* context = pEntryPoints->GetRdpContext(pEntryPoints);
error = initPluginFn(plugin, context, settings);
if (error != CHANNEL_RC_OK)
goto error;
}
plugin->dynvc_name = _strdup(name);
if (!plugin->dynvc_name)
goto error;
error = pEntryPoints->RegisterPlugin(pEntryPoints, name, &plugin->iface);
if (error == CHANNEL_RC_OK)
return error;
error:
generic_plugin_terminated(&plugin->iface);
return error;
}

View File

@ -44,15 +44,12 @@
typedef struct
{
IWTSPlugin iface;
IWTSListener* listener;
GENERIC_LISTENER_CALLBACK* listener_callback;
GENERIC_DYNVC_PLUGIN base;
DispClientContext* context;
UINT32 MaxNumMonitors;
UINT32 MaxMonitorAreaFactorA;
UINT32 MaxMonitorAreaFactorB;
BOOL initialized;
} DISP_PLUGIN;
/**
@ -167,7 +164,7 @@ static UINT disp_recv_display_control_caps_pdu(GENERIC_CHANNEL_CALLBACK* callbac
disp = (DISP_PLUGIN*)callback->plugin;
WINPR_ASSERT(disp);
context = (DispClientContext*)disp->iface.pInterface;
context = disp->context;
WINPR_ASSERT(context);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
@ -245,103 +242,6 @@ static UINT disp_on_close(IWTSVirtualChannelCallback* pChannelCallback)
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT disp_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept,
IWTSVirtualChannelCallback** ppCallback)
{
GENERIC_CHANNEL_CALLBACK* callback;
GENERIC_LISTENER_CALLBACK* listener_callback = (GENERIC_LISTENER_CALLBACK*)pListenerCallback;
WINPR_ASSERT(listener_callback);
WINPR_ASSERT(pChannel);
WINPR_ASSERT(pbAccept);
WINPR_ASSERT(ppCallback);
callback = (GENERIC_CHANNEL_CALLBACK*)calloc(1, sizeof(GENERIC_CHANNEL_CALLBACK));
if (!callback)
{
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
callback->iface.OnDataReceived = disp_on_data_received;
callback->iface.OnClose = disp_on_close;
callback->plugin = listener_callback->plugin;
callback->channel_mgr = listener_callback->channel_mgr;
callback->channel = pChannel;
listener_callback->channel_callback = callback;
*ppCallback = (IWTSVirtualChannelCallback*)callback;
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT disp_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
{
UINT status;
DISP_PLUGIN* disp = (DISP_PLUGIN*)pPlugin;
WINPR_ASSERT(disp);
WINPR_ASSERT(pChannelMgr);
if (disp->initialized)
{
WLog_ERR(TAG, "[%s] channel initialized twice, aborting", DISP_DVC_CHANNEL_NAME);
return ERROR_INVALID_DATA;
}
disp->listener_callback =
(GENERIC_LISTENER_CALLBACK*)calloc(1, sizeof(GENERIC_LISTENER_CALLBACK));
if (!disp->listener_callback)
{
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
disp->listener_callback->iface.OnNewChannelConnection = disp_on_new_channel_connection;
disp->listener_callback->plugin = pPlugin;
disp->listener_callback->channel_mgr = pChannelMgr;
status = pChannelMgr->CreateListener(pChannelMgr, DISP_DVC_CHANNEL_NAME, 0,
&disp->listener_callback->iface, &(disp->listener));
disp->listener->pInterface = disp->iface.pInterface;
disp->initialized = status == CHANNEL_RC_OK;
return status;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT disp_plugin_terminated(IWTSPlugin* pPlugin)
{
DISP_PLUGIN* disp = (DISP_PLUGIN*)pPlugin;
WINPR_ASSERT(disp);
if (disp->listener_callback)
{
IWTSVirtualChannelManager* mgr = disp->listener_callback->channel_mgr;
if (mgr)
IFCALL(mgr->DestroyListener, mgr, disp->listener);
free(disp->listener_callback);
}
free(disp->iface.pInterface);
free(pPlugin);
return CHANNEL_RC_OK;
}
/**
* Channel Client Interface
*/
@ -362,11 +262,54 @@ static UINT disp_send_monitor_layout(DispClientContext* context, UINT32 NumMonit
disp = (DISP_PLUGIN*)context->handle;
WINPR_ASSERT(disp);
callback = disp->listener_callback->channel_callback;
callback = disp->base.listener_callback->channel_callback;
return disp_send_display_control_monitor_layout_pdu(callback, NumMonitors, Monitors);
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT disp_plugin_initialize(GENERIC_DYNVC_PLUGIN* base, rdpContext* rcontext,
rdpSettings* settings)
{
DispClientContext* context;
DISP_PLUGIN* disp = (DISP_PLUGIN*)base;
WINPR_ASSERT(disp);
disp->MaxNumMonitors = 16;
disp->MaxMonitorAreaFactorA = 8192;
disp->MaxMonitorAreaFactorB = 8192;
context = (DispClientContext*)calloc(1, sizeof(*disp));
if (!context)
{
WLog_Print(base->log, WLOG_ERROR, "unable to allocate DispClientContext");
return CHANNEL_RC_NO_MEMORY;
}
context->handle = (void*)disp;
context->SendMonitorLayout = disp_send_monitor_layout;
disp->base.iface.pInterface = disp->context = context;
return CHANNEL_RC_OK;
}
static void disp_plugin_terminated(GENERIC_DYNVC_PLUGIN* base)
{
DISP_PLUGIN* disp = (DISP_PLUGIN*)base;
WINPR_ASSERT(disp);
free(disp->context);
}
static const IWTSVirtualChannelCallback disp_callbacks = { disp_on_data_received, NULL, /* Open */
disp_on_close };
/**
* Function description
*
@ -374,50 +317,8 @@ static UINT disp_send_monitor_layout(DispClientContext* context, UINT32 NumMonit
*/
UINT disp_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
{
UINT error = CHANNEL_RC_OK;
DISP_PLUGIN* disp;
DispClientContext* context;
WINPR_ASSERT(pEntryPoints);
disp = (DISP_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, DISP_CHANNEL_NAME);
if (!disp)
{
disp = (DISP_PLUGIN*)calloc(1, sizeof(DISP_PLUGIN));
if (!disp)
{
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
disp->iface.Initialize = disp_plugin_initialize;
disp->iface.Connected = NULL;
disp->iface.Disconnected = NULL;
disp->iface.Terminated = disp_plugin_terminated;
disp->MaxNumMonitors = 16;
disp->MaxMonitorAreaFactorA = 8192;
disp->MaxMonitorAreaFactorB = 8192;
context = (DispClientContext*)calloc(1, sizeof(DispClientContext));
if (!context)
{
WLog_ERR(TAG, "calloc failed!");
free(disp);
return CHANNEL_RC_NO_MEMORY;
}
context->handle = (void*)disp;
context->SendMonitorLayout = disp_send_monitor_layout;
disp->iface.pInterface = (void*)context;
error = pEntryPoints->RegisterPlugin(pEntryPoints, DISP_CHANNEL_NAME, &disp->iface);
}
else
{
WLog_ERR(TAG, "could not get disp Plugin.");
return CHANNEL_RC_BAD_CHANNEL;
}
return error;
return freerdp_generic_DVCPluginEntry(pEntryPoints, TAG, DISP_DVC_CHANNEL_NAME,
sizeof(DISP_PLUGIN), sizeof(GENERIC_CHANNEL_CALLBACK),
&disp_callbacks, disp_plugin_initialize,
disp_plugin_terminated);
}

View File

@ -34,14 +34,9 @@
#define TAG CHANNELS_TAG("echo.client")
typedef struct
{
IWTSPlugin iface;
GENERIC_LISTENER_CALLBACK* listener_callback;
IWTSListener* listener;
BOOL initialized;
GENERIC_DYNVC_PLUGIN baseDynPlugin;
} ECHO_PLUGIN;
/**
@ -66,95 +61,15 @@ static UINT echo_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
*/
static UINT echo_on_close(IWTSVirtualChannelCallback* pChannelCallback)
{
GENERIC_CHANNEL_CALLBACK* callback = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback;
GENERIC_CHANNEL_CALLBACK* callback = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback;
free(callback);
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT echo_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept,
IWTSVirtualChannelCallback** ppCallback)
{
GENERIC_CHANNEL_CALLBACK* callback;
GENERIC_LISTENER_CALLBACK* listener_callback = (GENERIC_LISTENER_CALLBACK*)pListenerCallback;
callback = (GENERIC_CHANNEL_CALLBACK*)calloc(1, sizeof(GENERIC_CHANNEL_CALLBACK));
if (!callback)
{
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
callback->iface.OnDataReceived = echo_on_data_received;
callback->iface.OnClose = echo_on_close;
callback->plugin = listener_callback->plugin;
callback->channel_mgr = listener_callback->channel_mgr;
callback->channel = pChannel;
*ppCallback = (IWTSVirtualChannelCallback*)callback;
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT echo_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
{
UINT status;
ECHO_PLUGIN* echo = (ECHO_PLUGIN*)pPlugin;
if (echo->initialized)
{
WLog_ERR(TAG, "[%s] channel initialized twice, aborting", ECHO_DVC_CHANNEL_NAME);
return ERROR_INVALID_DATA;
}
echo->listener_callback = (GENERIC_LISTENER_CALLBACK*)calloc(1, sizeof(GENERIC_LISTENER_CALLBACK));
if (!echo->listener_callback)
{
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
echo->listener_callback->iface.OnNewChannelConnection = echo_on_new_channel_connection;
echo->listener_callback->plugin = pPlugin;
echo->listener_callback->channel_mgr = pChannelMgr;
status = pChannelMgr->CreateListener(pChannelMgr, ECHO_DVC_CHANNEL_NAME, 0,
&echo->listener_callback->iface, &echo->listener);
echo->initialized = status == CHANNEL_RC_OK;
return status;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT echo_plugin_terminated(IWTSPlugin* pPlugin)
{
ECHO_PLUGIN* echo = (ECHO_PLUGIN*)pPlugin;
if (echo && echo->listener_callback)
{
IWTSVirtualChannelManager* mgr = echo->listener_callback->channel_mgr;
if (mgr)
IFCALL(mgr->DestroyListener, mgr, echo->listener);
}
free(echo);
return CHANNEL_RC_OK;
}
static const IWTSVirtualChannelCallback echo_callbacks = { echo_on_data_received, NULL, /* Open */
echo_on_close };
/**
* Function description
@ -163,28 +78,7 @@ static UINT echo_plugin_terminated(IWTSPlugin* pPlugin)
*/
UINT echo_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
{
UINT status = CHANNEL_RC_OK;
ECHO_PLUGIN* echo;
echo = (ECHO_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "echo");
if (!echo)
{
echo = (ECHO_PLUGIN*)calloc(1, sizeof(ECHO_PLUGIN));
if (!echo)
{
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
echo->iface.Initialize = echo_plugin_initialize;
echo->iface.Connected = NULL;
echo->iface.Disconnected = NULL;
echo->iface.Terminated = echo_plugin_terminated;
status = pEntryPoints->RegisterPlugin(pEntryPoints, "echo", &echo->iface);
}
return status;
return freerdp_generic_DVCPluginEntry(pEntryPoints, TAG, ECHO_DVC_CHANNEL_NAME,
sizeof(ECHO_PLUGIN), sizeof(GENERIC_CHANNEL_CALLBACK),
&echo_callbacks, NULL, NULL);
}

View File

@ -41,13 +41,8 @@
typedef struct
{
IWTSPlugin iface;
IWTSListener* listener;
GENERIC_LISTENER_CALLBACK* listener_callback;
GENERIC_DYNVC_PLUGIN base;
GeometryClientContext* context;
BOOL initialized;
} GEOMETRY_PLUGIN;
static UINT32 mappedGeometryHash(const void* v)
@ -68,7 +63,7 @@ static void freerdp_rgndata_reset(FREERDP_RGNDATA* data)
data->nRectCount = 0;
}
static UINT32 geometry_read_RGNDATA(wStream* s, UINT32 len, FREERDP_RGNDATA* rgndata)
static UINT32 geometry_read_RGNDATA(wLog* logger, wStream* s, UINT32 len, FREERDP_RGNDATA* rgndata)
{
UINT32 dwSize, iType;
INT32 right, bottom;
@ -76,7 +71,7 @@ static UINT32 geometry_read_RGNDATA(wStream* s, UINT32 len, FREERDP_RGNDATA* rgn
if (len < 32)
{
WLog_ERR(TAG, "invalid RGNDATA");
WLog_Print(logger, WLOG_ERROR, "invalid RGNDATA");
return ERROR_INVALID_DATA;
}
@ -84,7 +79,7 @@ static UINT32 geometry_read_RGNDATA(wStream* s, UINT32 len, FREERDP_RGNDATA* rgn
if (dwSize != 32)
{
WLog_ERR(TAG, "invalid RGNDATA dwSize");
WLog_Print(logger, WLOG_ERROR, "invalid RGNDATA dwSize");
return ERROR_INVALID_DATA;
}
@ -92,7 +87,7 @@ static UINT32 geometry_read_RGNDATA(wStream* s, UINT32 len, FREERDP_RGNDATA* rgn
if (iType != RDH_RECTANGLE)
{
WLog_ERR(TAG, "iType %" PRIu32 " for RGNDATA is not supported", iType);
WLog_Print(logger, WLOG_ERROR, "iType %" PRIu32 " for RGNDATA is not supported", iType);
return ERROR_UNSUPPORTED_TYPE;
}
@ -116,7 +111,7 @@ static UINT32 geometry_read_RGNDATA(wStream* s, UINT32 len, FREERDP_RGNDATA* rgn
if (len / (4 * 4) < rgndata->nRectCount)
{
WLog_ERR(TAG, "not enough data for region rectangles");
WLog_Print(logger, WLOG_ERROR, "not enough data for region rectangles");
}
if (rgndata->nRectCount)
@ -126,7 +121,8 @@ static UINT32 geometry_read_RGNDATA(wStream* s, UINT32 len, FREERDP_RGNDATA* rgn
if (!tmp)
{
WLog_ERR(TAG, "unable to allocate memory for %" PRIu32 " RECTs", rgndata->nRectCount);
WLog_Print(logger, WLOG_ERROR, "unable to allocate memory for %" PRIu32 " RECTs",
rgndata->nRectCount);
return CHANNEL_RC_NO_MEMORY;
}
rgndata->rects = tmp;
@ -165,11 +161,13 @@ static UINT geometry_recv_pdu(GENERIC_CHANNEL_CALLBACK* callback, wStream* s)
GEOMETRY_PLUGIN* geometry;
GeometryClientContext* context;
UINT ret = CHANNEL_RC_OK;
UINT32 version, updateType, geometryType;
UINT32 updateType, geometryType;
UINT64 id;
wLog* logger;
geometry = (GEOMETRY_PLUGIN*)callback->plugin;
context = (GeometryClientContext*)geometry->iface.pInterface;
logger = geometry->base.log;
context = (GeometryClientContext*)geometry->base.iface.pInterface;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
return ERROR_INVALID_DATA;
@ -178,11 +176,11 @@ static UINT geometry_recv_pdu(GENERIC_CHANNEL_CALLBACK* callback, wStream* s)
if (length < 73 || !Stream_CheckAndLogRequiredLength(TAG, s, (length - 4)))
{
WLog_ERR(TAG, "invalid packet length");
WLog_Print(logger, WLOG_ERROR, "invalid packet length");
return ERROR_INVALID_DATA;
}
Stream_Read_UINT32(s, version);
Stream_Read_UINT32(s, context->remoteVersion);
Stream_Read_UINT64(s, id);
Stream_Read_UINT32(s, updateType);
Stream_Seek_UINT32(s); /* flags */
@ -193,18 +191,19 @@ static UINT geometry_recv_pdu(GENERIC_CHANNEL_CALLBACK* callback, wStream* s)
{
if (!mappedGeometry)
{
WLog_ERR(TAG, "geometry 0x%" PRIx64 " not found here, ignoring clear command", id);
WLog_Print(logger, WLOG_ERROR,
"geometry 0x%" PRIx64 " not found here, ignoring clear command", id);
return CHANNEL_RC_OK;
}
WLog_DBG(TAG, "clearing geometry 0x%" PRIx64 "", id);
WLog_Print(logger, WLOG_DEBUG, "clearing geometry 0x%" PRIx64 "", id);
if (mappedGeometry->MappedGeometryClear &&
!mappedGeometry->MappedGeometryClear(mappedGeometry))
return ERROR_INTERNAL_ERROR;
if (!HashTable_Remove(context->geometries, &id))
WLog_ERR(TAG, "geometry not removed from geometries");
WLog_Print(logger, WLOG_ERROR, "geometry not removed from geometries");
}
else if (updateType == GEOMETRY_UPDATE)
{
@ -213,7 +212,7 @@ static UINT geometry_recv_pdu(GENERIC_CHANNEL_CALLBACK* callback, wStream* s)
if (!mappedGeometry)
{
newOne = TRUE;
WLog_DBG(TAG, "creating geometry 0x%" PRIx64 "", id);
WLog_Print(logger, WLOG_DEBUG, "creating geometry 0x%" PRIx64 "", id);
mappedGeometry = calloc(1, sizeof(MAPPED_GEOMETRY));
if (!mappedGeometry)
return CHANNEL_RC_NO_MEMORY;
@ -224,14 +223,15 @@ static UINT geometry_recv_pdu(GENERIC_CHANNEL_CALLBACK* callback, wStream* s)
if (!HashTable_Insert(context->geometries, &(mappedGeometry->mappingId),
mappedGeometry))
{
WLog_ERR(TAG, "unable to register geometry 0x%" PRIx64 " in the table", id);
WLog_Print(logger, WLOG_ERROR,
"unable to register geometry 0x%" PRIx64 " in the table", id);
free(mappedGeometry);
return CHANNEL_RC_NO_MEMORY;
}
}
else
{
WLog_DBG(TAG, "updating geometry 0x%" PRIx64 "", id);
WLog_Print(logger, WLOG_DEBUG, "updating geometry 0x%" PRIx64 "", id);
}
Stream_Read_UINT64(s, mappedGeometry->topLevelId);
@ -247,6 +247,9 @@ static UINT geometry_recv_pdu(GENERIC_CHANNEL_CALLBACK* callback, wStream* s)
Stream_Read_INT32(s, mappedGeometry->topLevelBottom);
Stream_Read_UINT32(s, geometryType);
if (geometryType != 0x02)
WLog_Print(logger, WLOG_DEBUG, "geometryType should be set to 0x02 and is 0x%" PRIx32,
geometryType);
Stream_Read_UINT32(s, cbGeometryBuffer);
if (!Stream_CheckAndLogRequiredLength(TAG, s, cbGeometryBuffer))
@ -254,7 +257,7 @@ static UINT geometry_recv_pdu(GENERIC_CHANNEL_CALLBACK* callback, wStream* s)
if (cbGeometryBuffer)
{
ret = geometry_read_RGNDATA(s, cbGeometryBuffer, &mappedGeometry->geometry);
ret = geometry_read_RGNDATA(logger, s, cbGeometryBuffer, &mappedGeometry->geometry);
if (ret != CHANNEL_RC_OK)
return ret;
}
@ -268,7 +271,7 @@ static UINT geometry_recv_pdu(GENERIC_CHANNEL_CALLBACK* callback, wStream* s)
if (context->MappedGeometryAdded &&
!context->MappedGeometryAdded(context, mappedGeometry))
{
WLog_ERR(TAG, "geometry added callback failed");
WLog_Print(logger, WLOG_ERROR, "geometry added callback failed");
ret = ERROR_INTERNAL_ERROR;
}
}
@ -277,14 +280,14 @@ static UINT geometry_recv_pdu(GENERIC_CHANNEL_CALLBACK* callback, wStream* s)
if (mappedGeometry->MappedGeometryUpdate &&
!mappedGeometry->MappedGeometryUpdate(mappedGeometry))
{
WLog_ERR(TAG, "geometry update callback failed");
WLog_Print(logger, WLOG_ERROR, "geometry update callback failed");
ret = ERROR_INTERNAL_ERROR;
}
}
}
else
{
WLog_ERR(TAG, "unknown updateType=%" PRIu32 "", updateType);
WLog_Print(logger, WLOG_ERROR, "unknown updateType=%" PRIu32 "", updateType);
ret = CHANNEL_RC_OK;
}
@ -313,101 +316,6 @@ static UINT geometry_on_close(IWTSVirtualChannelCallback* pChannelCallback)
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT geometry_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
IWTSVirtualChannel* pChannel, BYTE* Data,
BOOL* pbAccept,
IWTSVirtualChannelCallback** ppCallback)
{
GENERIC_CHANNEL_CALLBACK* callback;
GENERIC_LISTENER_CALLBACK* listener_callback = (GENERIC_LISTENER_CALLBACK*)pListenerCallback;
WINPR_UNUSED(Data);
WINPR_UNUSED(pbAccept);
callback = (GENERIC_CHANNEL_CALLBACK*)calloc(1, sizeof(GENERIC_CHANNEL_CALLBACK));
if (!callback)
{
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
callback->iface.OnDataReceived = geometry_on_data_received;
callback->iface.OnClose = geometry_on_close;
callback->plugin = listener_callback->plugin;
callback->channel_mgr = listener_callback->channel_mgr;
callback->channel = pChannel;
listener_callback->channel_callback = callback;
*ppCallback = (IWTSVirtualChannelCallback*)callback;
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT geometry_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
{
UINT status;
GEOMETRY_PLUGIN* geometry = (GEOMETRY_PLUGIN*)pPlugin;
if (geometry->initialized)
{
WLog_ERR(TAG, "[%s] channel initialized twice, aborting", GEOMETRY_DVC_CHANNEL_NAME);
return ERROR_INVALID_DATA;
}
geometry->listener_callback =
(GENERIC_LISTENER_CALLBACK*)calloc(1, sizeof(GENERIC_LISTENER_CALLBACK));
if (!geometry->listener_callback)
{
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
geometry->listener_callback->iface.OnNewChannelConnection = geometry_on_new_channel_connection;
geometry->listener_callback->plugin = pPlugin;
geometry->listener_callback->channel_mgr = pChannelMgr;
status =
pChannelMgr->CreateListener(pChannelMgr, GEOMETRY_DVC_CHANNEL_NAME, 0,
&geometry->listener_callback->iface, &(geometry->listener));
geometry->listener->pInterface = geometry->iface.pInterface;
geometry->initialized = status == CHANNEL_RC_OK;
return status;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT geometry_plugin_terminated(IWTSPlugin* pPlugin)
{
GEOMETRY_PLUGIN* geometry = (GEOMETRY_PLUGIN*)pPlugin;
GeometryClientContext* context = (GeometryClientContext*)geometry->iface.pInterface;
if (geometry && geometry->listener_callback)
{
IWTSVirtualChannelManager* mgr = geometry->listener_callback->channel_mgr;
if (mgr)
IFCALL(mgr->DestroyListener, mgr, geometry->listener);
}
if (context)
HashTable_Free(context->geometries);
free(geometry->listener_callback);
free(geometry->iface.pInterface);
free(pPlugin);
return CHANNEL_RC_OK;
}
static void mappedGeometryUnref_void(void* arg)
{
MAPPED_GEOMETRY* g = (MAPPED_GEOMETRY*)arg;
@ -418,6 +326,59 @@ static void mappedGeometryUnref_void(void* arg)
* Channel Client Interface
*/
static const IWTSVirtualChannelCallback geometry_callbacks = { geometry_on_data_received,
NULL, /* Open */
geometry_on_close };
static UINT init_plugin_cb(GENERIC_DYNVC_PLUGIN* base, rdpContext* rcontext, rdpSettings* settings)
{
GeometryClientContext* context;
GEOMETRY_PLUGIN* geometry = (GEOMETRY_PLUGIN*)base;
WINPR_ASSERT(base);
WINPR_UNUSED(settings);
context = (GeometryClientContext*)calloc(1, sizeof(GeometryClientContext));
if (!context)
{
WLog_Print(base->log, WLOG_ERROR, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
context->geometries = HashTable_New(FALSE);
if (!context->geometries)
{
WLog_Print(base->log, WLOG_ERROR, "unable to allocate geometries");
free(context);
return CHANNEL_RC_NO_MEMORY;
}
HashTable_SetHashFunction(context->geometries, mappedGeometryHash);
{
wObject* obj = HashTable_KeyObject(context->geometries);
obj->fnObjectEquals = mappedGeometryKeyCompare;
}
{
wObject* obj = HashTable_ValueObject(context->geometries);
obj->fnObjectFree = mappedGeometryUnref_void;
}
context->handle = (void*)geometry;
geometry->context = context;
geometry->base.iface.pInterface = (void*)context;
return CHANNEL_RC_OK;
}
static void terminate_plugin_cb(GENERIC_DYNVC_PLUGIN* base)
{
GEOMETRY_PLUGIN* geometry = (GEOMETRY_PLUGIN*)base;
if (geometry->context)
HashTable_Free(geometry->context->geometries);
free(geometry->context);
}
/**
* Function description
*
@ -425,58 +386,7 @@ static void mappedGeometryUnref_void(void* arg)
*/
UINT geometry_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
{
UINT error = CHANNEL_RC_OK;
GEOMETRY_PLUGIN* geometry;
GeometryClientContext* context;
geometry = (GEOMETRY_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "geometry");
if (!geometry)
{
geometry = (GEOMETRY_PLUGIN*)calloc(1, sizeof(GEOMETRY_PLUGIN));
if (!geometry)
{
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
geometry->iface.Initialize = geometry_plugin_initialize;
geometry->iface.Connected = NULL;
geometry->iface.Disconnected = NULL;
geometry->iface.Terminated = geometry_plugin_terminated;
context = (GeometryClientContext*)calloc(1, sizeof(GeometryClientContext));
if (!context)
{
WLog_ERR(TAG, "calloc failed!");
goto error_context;
}
context->geometries = HashTable_New(FALSE);
HashTable_SetHashFunction(context->geometries, mappedGeometryHash);
{
wObject* obj = HashTable_KeyObject(context->geometries);
obj->fnObjectEquals = mappedGeometryKeyCompare;
}
{
wObject* obj = HashTable_ValueObject(context->geometries);
obj->fnObjectFree = mappedGeometryUnref_void;
}
context->handle = (void*)geometry;
geometry->iface.pInterface = (void*)context;
geometry->context = context;
error = pEntryPoints->RegisterPlugin(pEntryPoints, "geometry", &geometry->iface);
}
else
{
WLog_ERR(TAG, "could not get geometry Plugin.");
return CHANNEL_RC_BAD_CHANNEL;
}
return error;
error_context:
free(geometry);
return CHANNEL_RC_NO_MEMORY;
return freerdp_generic_DVCPluginEntry(pEntryPoints, TAG, GEOMETRY_DVC_CHANNEL_NAME,
sizeof(GEOMETRY_PLUGIN), sizeof(GENERIC_CHANNEL_CALLBACK),
&geometry_callbacks, init_plugin_cb, terminate_plugin_cb);
}

View File

@ -66,10 +66,7 @@
typedef struct
{
IWTSPlugin iface;
IWTSListener* listener;
GENERIC_LISTENER_CALLBACK* listener_callback;
GENERIC_DYNVC_PLUGIN base;
RdpeiClientContext* context;
@ -87,7 +84,6 @@ typedef struct
CRITICAL_SECTION lock;
rdpContext* rdpcontext;
BOOL initialized;
HANDLE thread;
HANDLE event;
} RDPEI_PLUGIN;
@ -343,14 +339,14 @@ static UINT rdpei_send_pen_frame(RdpeiClientContext* context, RDPINPUT_PEN_FRAME
if (!context)
return ERROR_INTERNAL_ERROR;
rdpei = (RDPEI_PLUGIN*)context->handle;
if (!rdpei || !rdpei->listener_callback)
if (!rdpei || !rdpei->base.listener_callback)
return ERROR_INTERNAL_ERROR;
if (!rdpei || !rdpei->rdpcontext)
return ERROR_INTERNAL_ERROR;
if (freerdp_settings_get_bool(rdpei->rdpcontext->settings, FreeRDP_SuspendInput))
return CHANNEL_RC_OK;
callback = rdpei->listener_callback->channel_callback;
callback = rdpei->base.listener_callback->channel_callback;
/* Just ignore the event if the channel is not connected */
if (!callback)
return CHANNEL_RC_OK;
@ -444,7 +440,7 @@ static DWORD WINAPI rdpei_periodic_update(LPVOID arg)
goto out;
}
context = (RdpeiClientContext*)rdpei->iface.pInterface;
context = rdpei->context;
if (!context)
{
@ -452,7 +448,7 @@ static DWORD WINAPI rdpei_periodic_update(LPVOID arg)
goto out;
}
while (rdpei->initialized)
while (rdpei->base.initialized)
{
status = WaitForSingleObject(rdpei->event, 20);
@ -794,8 +790,10 @@ static UINT rdpei_recv_pdu(GENERIC_CHANNEL_CALLBACK* callback, wStream* s)
UINT16 eventId;
UINT32 pduLength;
UINT error;
if (!s)
return ERROR_INTERNAL_ERROR;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
return ERROR_INVALID_DATA;
@ -870,142 +868,16 @@ static UINT rdpei_on_close(IWTSVirtualChannelCallback* pChannelCallback)
if (callback)
{
RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)callback->plugin;
if (rdpei && rdpei->listener_callback)
if (rdpei && rdpei->base.listener_callback)
{
if (rdpei->listener_callback->channel_callback == callback)
rdpei->listener_callback->channel_callback = NULL;
if (rdpei->base.listener_callback->channel_callback == callback)
rdpei->base.listener_callback->channel_callback = NULL;
}
}
free(callback);
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rdpei_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
IWTSVirtualChannel* pChannel, BYTE* Data,
BOOL* pbAccept, IWTSVirtualChannelCallback** ppCallback)
{
GENERIC_CHANNEL_CALLBACK* callback;
GENERIC_LISTENER_CALLBACK* listener_callback = (GENERIC_LISTENER_CALLBACK*)pListenerCallback;
if (!listener_callback)
return ERROR_INTERNAL_ERROR;
callback = (GENERIC_CHANNEL_CALLBACK*)calloc(1, sizeof(GENERIC_CHANNEL_CALLBACK));
WINPR_UNUSED(Data);
WINPR_UNUSED(pbAccept);
if (!callback)
{
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
callback->iface.OnDataReceived = rdpei_on_data_received;
callback->iface.OnClose = rdpei_on_close;
callback->plugin = listener_callback->plugin;
callback->channel_mgr = listener_callback->channel_mgr;
callback->channel = pChannel;
listener_callback->channel_callback = callback;
*ppCallback = (IWTSVirtualChannelCallback*)callback;
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rdpei_plugin_terminated(IWTSPlugin* pPlugin)
{
RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)pPlugin;
if (!pPlugin)
return ERROR_INVALID_PARAMETER;
if (rdpei)
{
IWTSVirtualChannelManager* mgr = NULL;
rdpei->initialized = FALSE;
if (rdpei->event)
SetEvent(rdpei->event);
if (rdpei->thread)
{
WaitForSingleObject(rdpei->thread, INFINITE);
CloseHandle(rdpei->thread);
}
if (rdpei->event)
CloseHandle(rdpei->event);
if (rdpei->listener_callback)
mgr = rdpei->listener_callback->channel_mgr;
if (mgr)
IFCALL(mgr->DestroyListener, mgr, rdpei->listener);
}
DeleteCriticalSection(&rdpei->lock);
free(rdpei->listener_callback);
free(rdpei->context);
free(rdpei);
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rdpei_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
{
UINT error;
RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)pPlugin;
if (rdpei->initialized)
{
WLog_ERR(TAG, "[%s] channel initialized twice, aborting", RDPEI_DVC_CHANNEL_NAME);
return ERROR_INVALID_DATA;
}
rdpei->listener_callback =
(GENERIC_LISTENER_CALLBACK*)calloc(1, sizeof(GENERIC_LISTENER_CALLBACK));
if (!rdpei->listener_callback)
{
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
rdpei->listener_callback->iface.OnNewChannelConnection = rdpei_on_new_channel_connection;
rdpei->listener_callback->plugin = pPlugin;
rdpei->listener_callback->channel_mgr = pChannelMgr;
if ((error = pChannelMgr->CreateListener(pChannelMgr, RDPEI_DVC_CHANNEL_NAME, 0,
&rdpei->listener_callback->iface, &(rdpei->listener))))
{
WLog_ERR(TAG, "ChannelMgr->CreateListener failed with error %" PRIu32 "!", error);
goto error_out;
}
rdpei->listener->pInterface = rdpei->iface.pInterface;
InitializeCriticalSection(&rdpei->lock);
rdpei->event = CreateEventA(NULL, TRUE, FALSE, NULL);
if (!rdpei->event)
goto error_out;
rdpei->thread = CreateThread(NULL, 0, rdpei_periodic_update, rdpei, 0, NULL);
if (!rdpei->thread)
goto error_out;
rdpei->initialized = TRUE;
return error;
error_out:
rdpei_plugin_terminated(pPlugin);
return error;
}
/**
* Channel Client Interface
*/
@ -1040,7 +912,7 @@ UINT rdpei_send_frame(RdpeiClientContext* context, RDPINPUT_TOUCH_FRAME* frame)
GENERIC_CHANNEL_CALLBACK* callback;
UINT error;
callback = rdpei->listener_callback->channel_callback;
callback = rdpei->base.listener_callback->channel_callback;
/* Just ignore the event if the channel is not connected */
if (!callback)
@ -1437,6 +1309,91 @@ static UINT rdpei_pen_raw_event(RdpeiClientContext* context, INT32 externalId, U
return error;
}
static UINT init_plugin_cb(GENERIC_DYNVC_PLUGIN* base, rdpContext* rcontext, rdpSettings* settings)
{
RdpeiClientContext* context;
RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)base;
WINPR_ASSERT(base);
WINPR_UNUSED(settings);
rdpei->version = RDPINPUT_PROTOCOL_V300;
rdpei->currentFrameTime = 0;
rdpei->previousFrameTime = 0;
rdpei->maxTouchContacts = MAX_CONTACTS;
rdpei->maxPenContacts = MAX_PEN_CONTACTS;
rdpei->rdpcontext = rcontext;
InitializeCriticalSection(&rdpei->lock);
rdpei->event = CreateEventA(NULL, TRUE, FALSE, NULL);
if (!rdpei->event)
{
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
context = (RdpeiClientContext*)calloc(1, sizeof(*context));
if (!context)
{
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
context->clientFeaturesMask = UINT32_MAX;
context->handle = (void*)rdpei;
context->GetVersion = rdpei_get_version;
context->GetFeatures = rdpei_get_features;
context->AddContact = rdpei_add_contact;
context->TouchBegin = rdpei_touch_begin;
context->TouchUpdate = rdpei_touch_update;
context->TouchEnd = rdpei_touch_end;
context->TouchCancel = rdpei_touch_cancel;
context->TouchRawEvent = rdpei_touch_raw_event;
context->AddPen = rdpei_add_pen;
context->PenBegin = rdpei_pen_begin;
context->PenUpdate = rdpei_pen_update;
context->PenEnd = rdpei_pen_end;
context->PenCancel = rdpei_pen_cancel;
context->PenRawEvent = rdpei_pen_raw_event;
rdpei->context = context;
rdpei->base.iface.pInterface = (void*)context;
rdpei->thread = CreateThread(NULL, 0, rdpei_periodic_update, rdpei, 0, NULL);
if (!rdpei->thread)
{
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
return CHANNEL_RC_OK;
}
static void terminate_plugin_cb(GENERIC_DYNVC_PLUGIN* base)
{
RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)base;
WINPR_ASSERT(rdpei);
if (rdpei->event)
SetEvent(rdpei->event);
if (rdpei->thread)
{
WaitForSingleObject(rdpei->thread, INFINITE);
CloseHandle(rdpei->thread);
}
if (rdpei->event)
CloseHandle(rdpei->event);
DeleteCriticalSection(&rdpei->lock);
free(rdpei->context);
}
static const IWTSVirtualChannelCallback geometry_callbacks = { rdpei_on_data_received,
NULL, /* Open */
rdpei_on_close };
/**
* Function description
*
@ -1444,71 +1401,7 @@ static UINT rdpei_pen_raw_event(RdpeiClientContext* context, INT32 externalId, U
*/
UINT rdpei_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
{
UINT error;
RDPEI_PLUGIN* rdpei = NULL;
RdpeiClientContext* context = NULL;
rdpei = (RDPEI_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "rdpei");
if (!rdpei)
{
rdpei = (RDPEI_PLUGIN*)calloc(1, sizeof(RDPEI_PLUGIN));
if (!rdpei)
{
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
rdpei->iface.Initialize = rdpei_plugin_initialize;
rdpei->iface.Connected = NULL;
rdpei->iface.Disconnected = NULL;
rdpei->iface.Terminated = rdpei_plugin_terminated;
rdpei->version = RDPINPUT_PROTOCOL_V300;
rdpei->currentFrameTime = 0;
rdpei->previousFrameTime = 0;
rdpei->maxTouchContacts = MAX_CONTACTS;
rdpei->maxPenContacts = MAX_PEN_CONTACTS;
rdpei->rdpcontext = pEntryPoints->GetRdpContext(pEntryPoints);
context = (RdpeiClientContext*)calloc(1, sizeof(RdpeiClientContext));
if (!context)
{
WLog_ERR(TAG, "calloc failed!");
error = CHANNEL_RC_NO_MEMORY;
goto error_out;
}
context->clientFeaturesMask = UINT32_MAX;
context->handle = (void*)rdpei;
context->GetVersion = rdpei_get_version;
context->GetFeatures = rdpei_get_features;
context->AddContact = rdpei_add_contact;
context->TouchBegin = rdpei_touch_begin;
context->TouchUpdate = rdpei_touch_update;
context->TouchEnd = rdpei_touch_end;
context->TouchCancel = rdpei_touch_cancel;
context->TouchRawEvent = rdpei_touch_raw_event;
context->AddPen = rdpei_add_pen;
context->PenBegin = rdpei_pen_begin;
context->PenUpdate = rdpei_pen_update;
context->PenEnd = rdpei_pen_end;
context->PenCancel = rdpei_pen_cancel;
context->PenRawEvent = rdpei_pen_raw_event;
rdpei->context = context;
rdpei->iface.pInterface = (void*)context;
if ((error = pEntryPoints->RegisterPlugin(pEntryPoints, "rdpei", &rdpei->iface)))
{
WLog_ERR(TAG, "EntryPoints->RegisterPlugin failed with error %" PRIu32 "!", error);
error = CHANNEL_RC_NO_MEMORY;
goto error_out;
}
}
return CHANNEL_RC_OK;
error_out:
rdpei_plugin_terminated(&rdpei->iface);
return error;
return freerdp_generic_DVCPluginEntry(pEntryPoints, TAG, RDPEI_DVC_CHANNEL_NAME,
sizeof(RDPEI_PLUGIN), sizeof(GENERIC_CHANNEL_CALLBACK),
&geometry_callbacks, init_plugin_cb, terminate_plugin_cb);
}

View File

@ -128,7 +128,7 @@ static UINT rdpgfx_decode_AVC420(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd
UINT error;
wStream* s;
RDPGFX_AVC420_BITMAP_STREAM h264;
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
RdpgfxClientContext* context = gfx->context;
s = Stream_New(cmd->data, cmd->length);
if (!s)
@ -173,7 +173,7 @@ static UINT rdpgfx_decode_AVC444(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd
size_t pos1, pos2;
wStream* s;
RDPGFX_AVC444_BITMAP_STREAM h264 = { 0 };
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
RdpgfxClientContext* context = gfx->context;
s = Stream_New(cmd->data, cmd->length);
if (!s)
@ -259,7 +259,7 @@ fail:
UINT rdpgfx_decode(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
{
UINT error = CHANNEL_RC_OK;
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
RdpgfxClientContext* context = gfx->context;
PROFILER_ENTER(context->SurfaceProfiler)
switch (cmd->codecId)

View File

@ -115,10 +115,10 @@ static UINT rdpgfx_send_caps_advertise_pdu(RdpgfxClientContext* context,
gfx = (RDPGFX_PLUGIN*)context->handle;
if (!gfx || !gfx->listener_callback)
if (!gfx || !gfx->base.listener_callback)
return ERROR_BAD_ARGUMENTS;
callback = gfx->listener_callback->channel_callback;
callback = gfx->base.listener_callback->channel_callback;
header.flags = 0;
header.cmdId = RDPGFX_CMDID_CAPSADVERTISE;
@ -205,7 +205,7 @@ static UINT rdpgfx_send_supported_caps(GENERIC_CHANNEL_CALLBACK* callback)
if (!gfx)
return ERROR_BAD_CONFIGURATION;
context = (RdpgfxClientContext*)gfx->iface.pInterface;
context = gfx->context;
if (!context)
return ERROR_BAD_CONFIGURATION;
@ -365,8 +365,10 @@ static UINT rdpgfx_recv_caps_confirm_pdu(GENERIC_CHANNEL_CALLBACK* callback, wSt
RDPGFX_CAPS_CONFIRM_PDU pdu = { 0 };
WINPR_ASSERT(callback);
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
WINPR_ASSERT(gfx);
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
RdpgfxClientContext* context = gfx->context;
pdu.capsSet = &capsSet;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
@ -404,10 +406,10 @@ static UINT rdpgfx_send_frame_acknowledge_pdu(RdpgfxClientContext* context,
gfx = (RDPGFX_PLUGIN*)context->handle;
if (!gfx || !gfx->listener_callback)
if (!gfx || !gfx->base.listener_callback)
return ERROR_BAD_CONFIGURATION;
callback = gfx->listener_callback->channel_callback;
callback = gfx->base.listener_callback->channel_callback;
if (!callback)
return ERROR_BAD_CONFIGURATION;
@ -460,10 +462,10 @@ static UINT rdpgfx_send_qoe_frame_acknowledge_pdu(RdpgfxClientContext* context,
gfx = (RDPGFX_PLUGIN*)context->handle;
if (!gfx || !gfx->listener_callback)
if (!gfx || !gfx->base.listener_callback)
return ERROR_BAD_CONFIGURATION;
callback = gfx->listener_callback->channel_callback;
callback = gfx->base.listener_callback->channel_callback;
if (!callback)
return ERROR_BAD_CONFIGURATION;
@ -506,8 +508,10 @@ static UINT rdpgfx_recv_reset_graphics_pdu(GENERIC_CHANNEL_CALLBACK* callback, w
WINPR_ASSERT(callback);
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
WINPR_ASSERT(gfx);
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
RdpgfxClientContext* context = gfx->context;
UINT error = CHANNEL_RC_OK;
GraphicsResetEventArgs graphicsReset = { 0 };
@ -592,7 +596,7 @@ static UINT rdpgfx_recv_evict_cache_entry_pdu(GENERIC_CHANNEL_CALLBACK* callback
WINPR_ASSERT(callback);
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
WINPR_ASSERT(gfx);
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
RdpgfxClientContext* context = gfx->context;
UINT error = CHANNEL_RC_OK;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
@ -707,7 +711,7 @@ static UINT rdpgfx_save_persistent_cache(RDPGFX_PLUGIN* gfx)
WINPR_ASSERT(gfx);
WINPR_ASSERT(gfx->rdpcontext);
rdpSettings* settings = gfx->rdpcontext->settings;
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
RdpgfxClientContext* context = gfx->context;
WINPR_ASSERT(context);
WINPR_ASSERT(settings);
@ -774,10 +778,10 @@ static UINT rdpgfx_send_cache_import_offer_pdu(RdpgfxClientContext* context,
gfx = (RDPGFX_PLUGIN*)context->handle;
if (!gfx || !gfx->listener_callback)
if (!gfx || !gfx->base.listener_callback)
return ERROR_BAD_CONFIGURATION;
callback = gfx->listener_callback->channel_callback;
callback = gfx->base.listener_callback->channel_callback;
if (!callback)
return ERROR_BAD_CONFIGURATION;
@ -839,7 +843,7 @@ static UINT rdpgfx_send_cache_offer(RDPGFX_PLUGIN* gfx)
WINPR_ASSERT(gfx);
WINPR_ASSERT(gfx->rdpcontext);
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
RdpgfxClientContext* context = gfx->context;
rdpSettings* settings = gfx->rdpcontext->settings;
if (!settings->BitmapCachePersistEnabled)
@ -923,7 +927,7 @@ static UINT rdpgfx_load_cache_import_reply(RDPGFX_PLUGIN* gfx, RDPGFX_CACHE_IMPO
WINPR_ASSERT(gfx);
WINPR_ASSERT(gfx->rdpcontext);
rdpSettings* settings = gfx->rdpcontext->settings;
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
RdpgfxClientContext* context = gfx->context;
WINPR_ASSERT(settings);
WINPR_ASSERT(reply);
@ -990,7 +994,7 @@ static UINT rdpgfx_recv_cache_import_reply_pdu(GENERIC_CHANNEL_CALLBACK* callbac
WINPR_ASSERT(callback);
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
WINPR_ASSERT(gfx);
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
RdpgfxClientContext* context = gfx->context;
UINT error = CHANNEL_RC_OK;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
@ -1044,7 +1048,7 @@ static UINT rdpgfx_recv_create_surface_pdu(GENERIC_CHANNEL_CALLBACK* callback, w
WINPR_ASSERT(callback);
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
WINPR_ASSERT(gfx);
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
RdpgfxClientContext* context = gfx->context;
UINT error = CHANNEL_RC_OK;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 7))
@ -1082,7 +1086,7 @@ static UINT rdpgfx_recv_delete_surface_pdu(GENERIC_CHANNEL_CALLBACK* callback, w
WINPR_ASSERT(callback);
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
WINPR_ASSERT(gfx);
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
RdpgfxClientContext* context = gfx->context;
UINT error = CHANNEL_RC_OK;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
@ -1114,7 +1118,7 @@ static UINT rdpgfx_recv_start_frame_pdu(GENERIC_CHANNEL_CALLBACK* callback, wStr
WINPR_ASSERT(callback);
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
WINPR_ASSERT(gfx);
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
RdpgfxClientContext* context = gfx->context;
UINT error = CHANNEL_RC_OK;
if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPGFX_START_FRAME_PDU_SIZE))
@ -1151,7 +1155,7 @@ static UINT rdpgfx_recv_end_frame_pdu(GENERIC_CHANNEL_CALLBACK* callback, wStrea
WINPR_ASSERT(callback);
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
WINPR_ASSERT(gfx);
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
RdpgfxClientContext* context = gfx->context;
UINT error = CHANNEL_RC_OK;
if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPGFX_END_FRAME_PDU_SIZE))
@ -1340,7 +1344,7 @@ static UINT rdpgfx_recv_wire_to_surface_2_pdu(GENERIC_CHANNEL_CALLBACK* callback
WINPR_ASSERT(callback);
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
WINPR_ASSERT(gfx);
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
RdpgfxClientContext* context = gfx->context;
UINT error = CHANNEL_RC_OK;
if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPGFX_WIRE_TO_SURFACE_PDU_2_SIZE))
@ -1412,7 +1416,7 @@ static UINT rdpgfx_recv_delete_encoding_context_pdu(GENERIC_CHANNEL_CALLBACK* ca
WINPR_ASSERT(callback);
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
WINPR_ASSERT(gfx);
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
RdpgfxClientContext* context = gfx->context;
UINT error = CHANNEL_RC_OK;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
@ -1450,7 +1454,7 @@ static UINT rdpgfx_recv_solid_fill_pdu(GENERIC_CHANNEL_CALLBACK* callback, wStre
WINPR_ASSERT(callback);
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
WINPR_ASSERT(gfx);
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
RdpgfxClientContext* context = gfx->context;
UINT error;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
@ -1519,7 +1523,7 @@ static UINT rdpgfx_recv_surface_to_surface_pdu(GENERIC_CHANNEL_CALLBACK* callbac
WINPR_ASSERT(callback);
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
WINPR_ASSERT(gfx);
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
RdpgfxClientContext* context = gfx->context;
UINT error;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 14))
@ -1591,8 +1595,9 @@ static UINT rdpgfx_recv_surface_to_cache_pdu(GENERIC_CHANNEL_CALLBACK* callback,
RDPGFX_SURFACE_TO_CACHE_PDU pdu = { 0 };
WINPR_ASSERT(callback);
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
WINPR_ASSERT(gfx);
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
RdpgfxClientContext* context = gfx->context;
UINT error;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
@ -1642,7 +1647,7 @@ static UINT rdpgfx_recv_cache_to_surface_pdu(GENERIC_CHANNEL_CALLBACK* callback,
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
WINPR_ASSERT(gfx);
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
RdpgfxClientContext* context = gfx->context;
UINT error = CHANNEL_RC_OK;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
@ -1704,8 +1709,9 @@ static UINT rdpgfx_recv_map_surface_to_output_pdu(GENERIC_CHANNEL_CALLBACK* call
RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU pdu = { 0 };
WINPR_ASSERT(callback);
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
WINPR_ASSERT(gfx);
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
RdpgfxClientContext* context = gfx->context;
UINT error = CHANNEL_RC_OK;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
@ -1738,8 +1744,9 @@ static UINT rdpgfx_recv_map_surface_to_scaled_output_pdu(GENERIC_CHANNEL_CALLBAC
RDPGFX_MAP_SURFACE_TO_SCALED_OUTPUT_PDU pdu = { 0 };
WINPR_ASSERT(callback);
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
WINPR_ASSERT(gfx);
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
RdpgfxClientContext* context = gfx->context;
UINT error = CHANNEL_RC_OK;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
@ -1779,8 +1786,9 @@ static UINT rdpgfx_recv_map_surface_to_window_pdu(GENERIC_CHANNEL_CALLBACK* call
RDPGFX_MAP_SURFACE_TO_WINDOW_PDU pdu = { 0 };
WINPR_ASSERT(callback);
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
WINPR_ASSERT(gfx);
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
RdpgfxClientContext* context = gfx->context;
UINT error = CHANNEL_RC_OK;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 18))
@ -1814,7 +1822,7 @@ static UINT rdpgfx_recv_map_surface_to_scaled_window_pdu(GENERIC_CHANNEL_CALLBAC
WINPR_ASSERT(callback);
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
WINPR_ASSERT(gfx);
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
RdpgfxClientContext* context = gfx->context;
UINT error = CHANNEL_RC_OK;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 26))
@ -2109,7 +2117,7 @@ static UINT rdpgfx_on_open(IWTSVirtualChannelCallback* pChannelCallback)
WINPR_ASSERT(callback);
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
WINPR_ASSERT(gfx);
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
RdpgfxClientContext* context = gfx->context;
UINT error = CHANNEL_RC_OK;
BOOL do_caps_advertise = TRUE;
gfx->sendFrameAcks = TRUE;
@ -2140,9 +2148,11 @@ static UINT rdpgfx_on_close(IWTSVirtualChannelCallback* pChannelCallback)
GENERIC_CHANNEL_CALLBACK* callback = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback;
WINPR_ASSERT(callback);
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
if (!gfx)
goto fail;
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
RdpgfxClientContext* context = gfx->context;
DEBUG_RDPGFX(gfx->log, "OnClose");
error = rdpgfx_save_persistent_cache(gfx);
@ -2170,102 +2180,14 @@ fail:
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rdpgfx_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
IWTSVirtualChannel* pChannel, BYTE* Data,
BOOL* pbAccept,
IWTSVirtualChannelCallback** ppCallback)
static void terminate_plugin_cb(GENERIC_DYNVC_PLUGIN* base)
{
GENERIC_CHANNEL_CALLBACK* callback;
GENERIC_LISTENER_CALLBACK* listener_callback = (GENERIC_LISTENER_CALLBACK*)pListenerCallback;
WINPR_ASSERT(listener_callback);
WINPR_ASSERT(pChannel);
WINPR_ASSERT(ppCallback);
callback = (GENERIC_CHANNEL_CALLBACK*)calloc(1, sizeof(GENERIC_CHANNEL_CALLBACK));
if (!callback)
{
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
callback->iface.OnDataReceived = rdpgfx_on_data_received;
callback->iface.OnOpen = rdpgfx_on_open;
callback->iface.OnClose = rdpgfx_on_close;
callback->plugin = listener_callback->plugin;
callback->channel_mgr = listener_callback->channel_mgr;
callback->channel = pChannel;
listener_callback->channel_callback = callback;
*ppCallback = &callback->iface;
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rdpgfx_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
{
UINT error;
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)pPlugin;
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)base;
WINPR_ASSERT(gfx);
WINPR_ASSERT(pChannelMgr);
RdpgfxClientContext* context = gfx->context;
if (gfx->initialized)
{
WLog_ERR(TAG, "[%s] channel initialized twice, aborting", RDPGFX_DVC_CHANNEL_NAME);
return ERROR_INVALID_DATA;
}
gfx->listener_callback =
(GENERIC_LISTENER_CALLBACK*)calloc(1, sizeof(GENERIC_LISTENER_CALLBACK));
if (!gfx->listener_callback)
{
WLog_Print(gfx->log, WLOG_ERROR, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
gfx->listener_callback->iface.OnNewChannelConnection = rdpgfx_on_new_channel_connection;
gfx->listener_callback->plugin = pPlugin;
gfx->listener_callback->channel_mgr = pChannelMgr;
WINPR_ASSERT(pChannelMgr->CreateListener);
error = pChannelMgr->CreateListener(pChannelMgr, RDPGFX_DVC_CHANNEL_NAME, 0,
&gfx->listener_callback->iface, &(gfx->listener));
gfx->listener->pInterface = gfx->iface.pInterface;
DEBUG_RDPGFX(gfx->log, "Initialize");
gfx->initialized = error == CHANNEL_RC_OK;
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rdpgfx_plugin_terminated(IWTSPlugin* pPlugin)
{
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)pPlugin;
WINPR_ASSERT(gfx);
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
DEBUG_RDPGFX(gfx->log, "Terminated");
if (gfx && gfx->listener_callback)
{
IWTSVirtualChannelManager* mgr = gfx->listener_callback->channel_mgr;
if (mgr)
IFCALL(mgr->DestroyListener, mgr, gfx->listener);
}
rdpgfx_client_context_free(context);
return CHANNEL_RC_OK;
}
/**
@ -2390,49 +2312,41 @@ static void* rdpgfx_get_cache_slot_data(RdpgfxClientContext* context, UINT16 cac
return pData;
}
RdpgfxClientContext* rdpgfx_client_context_new(rdpContext* rdpcontext)
static UINT init_plugin_cb(GENERIC_DYNVC_PLUGIN* base, rdpContext* rcontext, rdpSettings* settings)
{
RDPGFX_PLUGIN* gfx;
RdpgfxClientContext* context;
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)base;
WINPR_ASSERT(rdpcontext);
WINPR_ASSERT(base);
gfx->rdpcontext = rcontext;
gfx = (RDPGFX_PLUGIN*)calloc(1, sizeof(RDPGFX_PLUGIN));
if (!gfx)
{
WLog_ERR(TAG, "calloc failed!");
return NULL;
}
gfx->log = WLog_Get(TAG);
if (!gfx->log)
{
free(gfx);
WLog_ERR(TAG, "Failed to acquire reference to WLog %s", TAG);
return NULL;
}
gfx->rdpcontext = rdpcontext;
gfx->SurfaceTable = HashTable_New(TRUE);
if (!gfx->SurfaceTable)
{
free(gfx);
WLog_ERR(TAG, "HashTable_New failed!");
return NULL;
WLog_ERR(TAG, "HashTable_New for surfaces failed !");
return CHANNEL_RC_NO_MEMORY;
}
gfx->MaxCacheSlots =
freerdp_settings_get_bool(gfx->rdpcontext->settings, FreeRDP_GfxSmallCache) ? 4096 : 25600;
context = (RdpgfxClientContext*)calloc(1, sizeof(RdpgfxClientContext));
context = (RdpgfxClientContext*)calloc(1, sizeof(RdpgfxClientContext));
if (!context)
{
free(gfx);
WLog_ERR(TAG, "calloc failed!");
return NULL;
WLog_ERR(TAG, "context calloc failed!");
HashTable_Free(gfx->SurfaceTable);
gfx->SurfaceTable = NULL;
return CHANNEL_RC_NO_MEMORY;
}
gfx->zgfx = zgfx_context_new(FALSE);
if (!gfx->zgfx)
{
WLog_ERR(TAG, "zgfx_context_new failed!");
HashTable_Free(gfx->SurfaceTable);
gfx->SurfaceTable = NULL;
free(context);
return CHANNEL_RC_NO_MEMORY;
}
context->handle = (void*)gfx;
@ -2446,18 +2360,9 @@ RdpgfxClientContext* rdpgfx_client_context_new(rdpContext* rdpcontext)
context->CacheImportOffer = rdpgfx_send_cache_import_offer_pdu;
context->QoeFrameAcknowledge = rdpgfx_send_qoe_frame_acknowledge_pdu;
gfx->iface.pInterface = (void*)context;
gfx->zgfx = zgfx_context_new(FALSE);
if (!gfx->zgfx)
{
free(gfx);
free(context);
WLog_ERR(TAG, "zgfx_context_new failed!");
return NULL;
}
return context;
gfx->base.iface.pInterface = (void*)context;
gfx->context = context;
return CHANNEL_RC_OK;
}
void rdpgfx_client_context_free(RdpgfxClientContext* context)
@ -2473,12 +2378,6 @@ void rdpgfx_client_context_free(RdpgfxClientContext* context)
free_surfaces(context, gfx->SurfaceTable);
evict_cache_slots(context, gfx->MaxCacheSlots, gfx->CacheSlots);
if (gfx->listener_callback)
{
free(gfx->listener_callback);
gfx->listener_callback = NULL;
}
if (gfx->zgfx)
{
zgfx_context_free(gfx->zgfx);
@ -2487,9 +2386,11 @@ void rdpgfx_client_context_free(RdpgfxClientContext* context)
HashTable_Free(gfx->SurfaceTable);
free(context);
free(gfx);
}
static const IWTSVirtualChannelCallback rdpgfx_callbacks = { rdpgfx_on_data_received,
rdpgfx_on_open, rdpgfx_on_close };
/**
* Function description
*
@ -2497,36 +2398,7 @@ void rdpgfx_client_context_free(RdpgfxClientContext* context)
*/
UINT rdpgfx_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
{
UINT error = CHANNEL_RC_OK;
RDPGFX_PLUGIN* gfx;
RdpgfxClientContext* context;
WINPR_ASSERT(pEntryPoints);
WINPR_ASSERT(pEntryPoints->GetPlugin);
gfx = (RDPGFX_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "rdpgfx");
if (!gfx)
{
WINPR_ASSERT(pEntryPoints->GetRdpContext);
context = rdpgfx_client_context_new(pEntryPoints->GetRdpContext(pEntryPoints));
if (!context)
{
WLog_ERR(TAG, "rdpgfx_client_context_new failed!");
return CHANNEL_RC_NO_MEMORY;
}
gfx = (RDPGFX_PLUGIN*)context->handle;
gfx->iface.Initialize = rdpgfx_plugin_initialize;
gfx->iface.Connected = NULL;
gfx->iface.Disconnected = NULL;
gfx->iface.Terminated = rdpgfx_plugin_terminated;
WINPR_ASSERT(pEntryPoints->RegisterPlugin);
error = pEntryPoints->RegisterPlugin(pEntryPoints, "rdpgfx", &gfx->iface);
}
return error;
return freerdp_generic_DVCPluginEntry(pEntryPoints, TAG, RDPGFX_DVC_CHANNEL_NAME,
sizeof(RDPGFX_PLUGIN), sizeof(GENERIC_CHANNEL_CALLBACK),
&rdpgfx_callbacks, init_plugin_cb, terminate_plugin_cb);
}

View File

@ -36,10 +36,7 @@
typedef struct
{
IWTSPlugin iface;
IWTSListener* listener;
GENERIC_LISTENER_CALLBACK* listener_callback;
GENERIC_DYNVC_PLUGIN base;
ZGFX_CONTEXT* zgfx;
UINT32 UnacknowledgedFrames;
@ -58,7 +55,7 @@ typedef struct
wLog* log;
RDPGFX_CAPSET ConnectionCaps;
BOOL initialized;
RdpgfxClientContext* context;
} RDPGFX_PLUGIN;
#endif /* FREERDP_CHANNEL_RDPGFX_CLIENT_MAIN_H */

View File

@ -41,6 +41,25 @@ typedef struct
GENERIC_CHANNEL_CALLBACK* channel_callback;
} GENERIC_LISTENER_CALLBACK;
typedef struct GENERIC_DYNVC_PLUGIN GENERIC_DYNVC_PLUGIN;
typedef UINT (*DYNVC_PLUGIN_INIT_FN)(GENERIC_DYNVC_PLUGIN* plugin, rdpContext* context,
rdpSettings* settings);
typedef void (*DYNVC_PLUGIN_TERMINATE_FN)(GENERIC_DYNVC_PLUGIN* plugin);
struct GENERIC_DYNVC_PLUGIN
{
IWTSPlugin iface;
GENERIC_LISTENER_CALLBACK* listener_callback;
IWTSListener* listener;
BOOL attached;
BOOL initialized;
wLog* log;
char* dynvc_name;
size_t channelCallbackSize;
const IWTSVirtualChannelCallback* channel_callbacks;
DYNVC_PLUGIN_TERMINATE_FN terminatePluginFn;
};
#ifdef __cplusplus
extern "C"
{
@ -57,6 +76,13 @@ extern "C"
LPCSTR lpType, DWORD dwFlags);
FREERDP_API void freerdp_channels_addin_list_free(FREERDP_ADDIN** ppAddins);
FREERDP_API BOOL freerdp_initialize_generic_dynvc_plugin(GENERIC_DYNVC_PLUGIN* plugin);
FREERDP_API UINT freerdp_generic_DVCPluginEntry(
IDRDYNVC_ENTRY_POINTS* pEntryPoints, const char* logTag, const char* name,
size_t pluginSize, size_t channelCallbackSize,
const IWTSVirtualChannelCallback* channel_callbacks, DYNVC_PLUGIN_INIT_FN initPluginFn,
DYNVC_PLUGIN_TERMINATE_FN terminatePluginFn);
#ifdef __cplusplus
}
#endif

View File

@ -57,6 +57,7 @@ struct s_geometry_client_context
void* custom;
pcMappedGeometryAdded MappedGeometryAdded;
UINT32 remoteVersion;
};
#ifdef __cplusplus