20#include <freerdp/config.h>
21#include <freerdp/log.h>
22#include <freerdp/client/channels.h>
24#define TAG FREERDP_TAG("genericdynvc")
26static char magic[32] =
"**GENERIC_DYNVC_PLUGIN_PRIVATE*";
27static const size_t maxPrivateOffset = 0x100000;
35} GENERIC_DYNVC_PLUGIN_PRIVATE;
48 char* ptr = (
char*)(&plugin[1]);
50 for (
size_t count = 0; count <= maxPrivateOffset; count++, ptr++)
54 if ((*ptr == magic[0]) && (memcmp(ptr, magic,
sizeof(magic)) == 0))
55 return WINPR_PACKED_ALIGN_CAST(GENERIC_DYNVC_PLUGIN_PRIVATE*, ptr);
59 "Failed to find GENERIC_DYNVC_PLUGIN_PRIVATE offset in the first %" PRIuz
60 " bytes after GENERIC_DYNVC_PLUGIN, giving up.",
69 GENERIC_DYNVC_PLUGIN_PRIVATE* priv = getFromGeneric(plugin);
72 return (priv->flags & GENERIC_CHANNEL_ENTRY_OPTION_MULTI_INSTANCE) != 0;
77 GENERIC_DYNVC_PLUGIN_PRIVATE* priv = getFromGeneric(plugin);
80 priv->connected = val;
87 GENERIC_DYNVC_PLUGIN_PRIVATE* priv = getFromGeneric(plugin);
90 return priv->connected;
93static UINT generic_on_close(IWTSVirtualChannelCallback* pChannelCallback)
96 WINPR_ASSERT(callback);
104 WINPR_ASSERT(plugin->channel_callbacks);
106 IFCALLRESULT(CHANNEL_RC_OK, plugin->channel_callbacks->OnClose, pChannelCallback);
107 generic_update_connected_state(plugin, FALSE);
112static UINT generic_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
113 IWTSVirtualChannel* pChannel,
114 WINPR_ATTR_UNUSED BYTE* Data,
115 WINPR_ATTR_UNUSED BOOL* pbAccept,
116 IWTSVirtualChannelCallback** ppCallback)
120 if (!listener_callback || !listener_callback->plugin)
121 return ERROR_INTERNAL_ERROR;
124 WLog_Print(plugin->log, WLOG_TRACE,
"...");
126 if (!generic_connected_allow_multiple(plugin) && generic_get_connected_state(plugin))
128 WLog_Print(plugin->log, WLOG_ERROR,
"Channel already connected, terminating.");
129 return ERROR_DEVICE_ALREADY_ATTACHED;
136 WLog_Print(plugin->log, WLOG_ERROR,
"calloc failed!");
137 return CHANNEL_RC_NO_MEMORY;
141 callback->iface = *plugin->channel_callbacks;
142 callback->iface.OnClose = generic_on_close;
144 callback->plugin = listener_callback->plugin;
145 callback->channel_mgr = listener_callback->channel_mgr;
146 callback->channel = pChannel;
148 listener_callback->channel_callback = callback;
149 listener_callback->channel = pChannel;
151 *ppCallback = &callback->iface;
152 generic_update_connected_state(plugin, TRUE);
153 return CHANNEL_RC_OK;
156static UINT generic_dynvc_plugin_initialize(IWTSPlugin* pPlugin,
157 IWTSVirtualChannelManager* pChannelMgr)
163 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
166 return ERROR_INVALID_PARAMETER;
168 if (plugin->initialized)
170 WLog_ERR(TAG,
"[%s] channel initialized twice, aborting", plugin->dynvc_name);
171 return ERROR_INVALID_DATA;
174 WLog_Print(plugin->log, WLOG_TRACE,
"...");
177 if (!listener_callback)
179 WLog_Print(plugin->log, WLOG_ERROR,
"calloc failed!");
180 return CHANNEL_RC_NO_MEMORY;
183 plugin->listener_callback = listener_callback;
184 listener_callback->iface.OnNewChannelConnection = generic_on_new_channel_connection;
185 listener_callback->plugin = pPlugin;
186 listener_callback->channel_mgr = pChannelMgr;
187 rc = pChannelMgr->CreateListener(pChannelMgr, plugin->dynvc_name, 0, &listener_callback->iface,
190 plugin->listener->pInterface = plugin->iface.pInterface;
191 plugin->initialized = (rc == CHANNEL_RC_OK);
195static UINT generic_plugin_terminated(IWTSPlugin* pPlugin)
198 UINT error = CHANNEL_RC_OK;
201 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
203 WLog_Print(plugin->log, WLOG_TRACE,
"...");
206 plugin->initialized = FALSE;
208 if (plugin->terminatePluginFn)
209 plugin->terminatePluginFn(plugin);
211 if (plugin->listener_callback)
213 IWTSVirtualChannelManager* mgr = plugin->listener_callback->channel_mgr;
215 IFCALL(mgr->DestroyListener, mgr, plugin->listener);
218 free(plugin->listener_callback);
219 free(plugin->dynvc_name);
224static UINT generic_dynvc_plugin_attached(IWTSPlugin* pPlugin)
227 UINT error = CHANNEL_RC_OK;
230 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
232 pluginn->attached = TRUE;
236static UINT generic_dynvc_plugin_detached(IWTSPlugin* pPlugin)
239 UINT error = CHANNEL_RC_OK;
242 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
244 plugin->attached = FALSE;
248UINT freerdp_generic_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints,
const char* logTag,
249 const char* name,
size_t pluginSize,
size_t channelCallbackSize,
250 const IWTSVirtualChannelCallback* channel_callbacks,
251 DYNVC_PLUGIN_INIT_FN initPluginFn,
252 DYNVC_PLUGIN_TERMINATE_FN terminatePluginFn)
254 return freerdp_generic_DVCPluginEntryWithOptions(pEntryPoints, logTag, name, pluginSize,
255 channelCallbackSize, channel_callbacks,
256 initPluginFn, terminatePluginFn, 0);
259UINT freerdp_generic_DVCPluginEntryWithOptions(
260 IDRDYNVC_ENTRY_POINTS* pEntryPoints,
const char* logTag,
const char* name,
size_t pluginSize,
261 size_t channelCallbackSize,
const IWTSVirtualChannelCallback* channel_callbacks,
262 DYNVC_PLUGIN_INIT_FN initPluginFn, DYNVC_PLUGIN_TERMINATE_FN terminatePluginFn, UINT32 flags)
264 UINT error = CHANNEL_RC_INITIALIZATION_ERROR;
266 WINPR_ASSERT(pEntryPoints);
267 WINPR_ASSERT(pEntryPoints->GetPlugin);
268 WINPR_ASSERT(logTag);
275 if (plugin !=
nullptr)
276 return CHANNEL_RC_ALREADY_INITIALIZED;
280 size_t size = pluginSize;
281 if ((size % 32) != 0)
282 size += 32 - size % 32;
283 size +=
sizeof(GENERIC_DYNVC_PLUGIN_PRIVATE);
287 WLog_ERR(TAG,
"calloc failed!");
288 return CHANNEL_RC_NO_MEMORY;
291 BYTE* ptr = &(((BYTE*)plugin)[size -
sizeof(GENERIC_DYNVC_PLUGIN_PRIVATE)]);
292 GENERIC_DYNVC_PLUGIN_PRIVATE* priv =
293 WINPR_PACKED_ALIGN_CAST(GENERIC_DYNVC_PLUGIN_PRIVATE*, ptr);
297 WINPR_STATIC_ASSERT(
sizeof(magic) ==
sizeof(priv->magic));
298 memcpy(priv->magic, magic,
sizeof(priv->magic));
299 priv->pluginSize = pluginSize;
302 plugin->log = WLog_Get(logTag);
303 plugin->attached = TRUE;
304 plugin->channel_callbacks = channel_callbacks;
305 plugin->channelCallbackSize = channelCallbackSize;
306 plugin->iface.Initialize = generic_dynvc_plugin_initialize;
307 plugin->iface.Connected =
nullptr;
308 plugin->iface.Disconnected =
nullptr;
309 plugin->iface.Terminated = generic_plugin_terminated;
310 plugin->iface.Attached = generic_dynvc_plugin_attached;
311 plugin->iface.Detached = generic_dynvc_plugin_detached;
312 plugin->terminatePluginFn = terminatePluginFn;
316 rdpSettings* settings = pEntryPoints->GetRdpSettings(pEntryPoints);
317 rdpContext* context = pEntryPoints->GetRdpContext(pEntryPoints);
319 error = initPluginFn(plugin, context, settings);
320 if (error != CHANNEL_RC_OK)
324 plugin->dynvc_name = _strdup(name);
325 if (!plugin->dynvc_name)
328 error = pEntryPoints->RegisterPlugin(pEntryPoints, name, &plugin->iface);
329 if (error == CHANNEL_RC_OK)
333 generic_plugin_terminated(&plugin->iface);