FreeRDP
Loading...
Searching...
No Matches
generic_dynvc.c
1
20#include <freerdp/config.h>
21#include <freerdp/log.h>
22#include <freerdp/client/channels.h>
23
24#define TAG FREERDP_TAG("genericdynvc")
25
26static BOOL generic_update_connected_state(GENERIC_DYNVC_PLUGIN* plugin, BOOL val)
27{
28 if (!plugin || !plugin->dynvc_name)
29 return FALSE;
30 const size_t len = strlen(plugin->dynvc_name);
31 plugin->dynvc_name[len + 1] = (char)val;
32 return TRUE;
33}
34
35WINPR_ATTR_NODISCARD
36static BOOL generic_get_connected_state(GENERIC_DYNVC_PLUGIN* plugin)
37{
38 if (!plugin || !plugin->dynvc_name)
39 return FALSE;
40 const size_t len = strlen(plugin->dynvc_name);
41 return plugin->dynvc_name[len + 1];
42}
43
44static UINT generic_on_close(IWTSVirtualChannelCallback* pChannelCallback)
45{
46 GENERIC_CHANNEL_CALLBACK* callback = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback;
47 WINPR_ASSERT(callback);
48
49 GENERIC_DYNVC_PLUGIN* plugin = (GENERIC_DYNVC_PLUGIN*)callback->plugin;
50 WINPR_ASSERT(plugin);
51
52 /* We're wrapping the originally set callback to update the channel state.
53 * call the originally intended OnClose from the plugin
54 */
55 WINPR_ASSERT(plugin->channel_callbacks);
56 const UINT rc =
57 IFCALLRESULT(CHANNEL_RC_OK, plugin->channel_callbacks->OnClose, pChannelCallback);
58 generic_update_connected_state(plugin, FALSE);
59
60 return rc;
61}
62
63static UINT generic_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
64 IWTSVirtualChannel* pChannel,
65 WINPR_ATTR_UNUSED BYTE* Data,
66 WINPR_ATTR_UNUSED BOOL* pbAccept,
67 IWTSVirtualChannelCallback** ppCallback)
68{
69 GENERIC_LISTENER_CALLBACK* listener_callback = (GENERIC_LISTENER_CALLBACK*)pListenerCallback;
70
71 if (!listener_callback || !listener_callback->plugin)
72 return ERROR_INTERNAL_ERROR;
73
74 GENERIC_DYNVC_PLUGIN* plugin = (GENERIC_DYNVC_PLUGIN*)listener_callback->plugin;
75 WLog_Print(plugin->log, WLOG_TRACE, "...");
76
77 if (generic_get_connected_state(plugin))
78 {
79 WLog_Print(plugin->log, WLOG_ERROR, "Channel already connected, terminating.");
80 return ERROR_DEVICE_ALREADY_ATTACHED;
81 }
82
83 GENERIC_CHANNEL_CALLBACK* callback =
84 (GENERIC_CHANNEL_CALLBACK*)calloc(1, plugin->channelCallbackSize);
85 if (!callback)
86 {
87 WLog_Print(plugin->log, WLOG_ERROR, "calloc failed!");
88 return CHANNEL_RC_NO_MEMORY;
89 }
90
91 /* implant configured channel callbacks */
92 callback->iface = *plugin->channel_callbacks;
93 callback->iface.OnClose = generic_on_close;
94
95 callback->plugin = listener_callback->plugin;
96 callback->channel_mgr = listener_callback->channel_mgr;
97 callback->channel = pChannel;
98
99 listener_callback->channel_callback = callback;
100 listener_callback->channel = pChannel;
101
102 *ppCallback = &callback->iface;
103 generic_update_connected_state(plugin, TRUE);
104 return CHANNEL_RC_OK;
105}
106
107static UINT generic_dynvc_plugin_initialize(IWTSPlugin* pPlugin,
108 IWTSVirtualChannelManager* pChannelMgr)
109{
110 UINT rc = 0;
111 GENERIC_DYNVC_PLUGIN* plugin = (GENERIC_DYNVC_PLUGIN*)pPlugin;
112
113 if (!plugin)
114 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
115
116 if (!pChannelMgr)
117 return ERROR_INVALID_PARAMETER;
118
119 if (plugin->initialized)
120 {
121 WLog_ERR(TAG, "[%s] channel initialized twice, aborting", plugin->dynvc_name);
122 return ERROR_INVALID_DATA;
123 }
124
125 WLog_Print(plugin->log, WLOG_TRACE, "...");
126 GENERIC_LISTENER_CALLBACK* listener_callback =
128 if (!listener_callback)
129 {
130 WLog_Print(plugin->log, WLOG_ERROR, "calloc failed!");
131 return CHANNEL_RC_NO_MEMORY;
132 }
133
134 plugin->listener_callback = listener_callback;
135 listener_callback->iface.OnNewChannelConnection = generic_on_new_channel_connection;
136 listener_callback->plugin = pPlugin;
137 listener_callback->channel_mgr = pChannelMgr;
138 rc = pChannelMgr->CreateListener(pChannelMgr, plugin->dynvc_name, 0, &listener_callback->iface,
139 &plugin->listener);
140
141 plugin->listener->pInterface = plugin->iface.pInterface;
142 plugin->initialized = (rc == CHANNEL_RC_OK);
143 return rc;
144}
145
146static UINT generic_plugin_terminated(IWTSPlugin* pPlugin)
147{
148 GENERIC_DYNVC_PLUGIN* plugin = (GENERIC_DYNVC_PLUGIN*)pPlugin;
149 UINT error = CHANNEL_RC_OK;
150
151 if (!plugin)
152 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
153
154 WLog_Print(plugin->log, WLOG_TRACE, "...");
155
156 /* some channels (namely rdpei), look at initialized to see if they should continue to run */
157 plugin->initialized = FALSE;
158
159 if (plugin->terminatePluginFn)
160 plugin->terminatePluginFn(plugin);
161
162 if (plugin->listener_callback)
163 {
164 IWTSVirtualChannelManager* mgr = plugin->listener_callback->channel_mgr;
165 if (mgr)
166 IFCALL(mgr->DestroyListener, mgr, plugin->listener);
167 }
168
169 free(plugin->listener_callback);
170 free(plugin->dynvc_name);
171 free(plugin);
172 return error;
173}
174
175static UINT generic_dynvc_plugin_attached(IWTSPlugin* pPlugin)
176{
177 GENERIC_DYNVC_PLUGIN* pluginn = (GENERIC_DYNVC_PLUGIN*)pPlugin;
178 UINT error = CHANNEL_RC_OK;
179
180 if (!pluginn)
181 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
182
183 pluginn->attached = TRUE;
184 return error;
185}
186
187static UINT generic_dynvc_plugin_detached(IWTSPlugin* pPlugin)
188{
189 GENERIC_DYNVC_PLUGIN* plugin = (GENERIC_DYNVC_PLUGIN*)pPlugin;
190 UINT error = CHANNEL_RC_OK;
191
192 if (!plugin)
193 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
194
195 plugin->attached = FALSE;
196 return error;
197}
198
199UINT freerdp_generic_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints, const char* logTag,
200 const char* name, size_t pluginSize, size_t channelCallbackSize,
201 const IWTSVirtualChannelCallback* channel_callbacks,
202 DYNVC_PLUGIN_INIT_FN initPluginFn,
203 DYNVC_PLUGIN_TERMINATE_FN terminatePluginFn)
204{
205 GENERIC_DYNVC_PLUGIN* plugin = nullptr;
206 UINT error = CHANNEL_RC_INITIALIZATION_ERROR;
207
208 WINPR_ASSERT(pEntryPoints);
209 WINPR_ASSERT(pEntryPoints->GetPlugin);
210 WINPR_ASSERT(logTag);
211 WINPR_ASSERT(name);
212 WINPR_ASSERT(pluginSize >= sizeof(*plugin));
213 WINPR_ASSERT(channelCallbackSize >= sizeof(GENERIC_CHANNEL_CALLBACK));
214
215 plugin = (GENERIC_DYNVC_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, name);
216 if (plugin != nullptr)
217 return CHANNEL_RC_ALREADY_INITIALIZED;
218
219 plugin = (GENERIC_DYNVC_PLUGIN*)calloc(1, pluginSize);
220 if (!plugin)
221 {
222 WLog_ERR(TAG, "calloc failed!");
223 return CHANNEL_RC_NO_MEMORY;
224 }
225
226 plugin->log = WLog_Get(logTag);
227 plugin->attached = TRUE;
228 plugin->channel_callbacks = channel_callbacks;
229 plugin->channelCallbackSize = channelCallbackSize;
230 plugin->iface.Initialize = generic_dynvc_plugin_initialize;
231 plugin->iface.Connected = nullptr;
232 plugin->iface.Disconnected = nullptr;
233 plugin->iface.Terminated = generic_plugin_terminated;
234 plugin->iface.Attached = generic_dynvc_plugin_attached;
235 plugin->iface.Detached = generic_dynvc_plugin_detached;
236 plugin->terminatePluginFn = terminatePluginFn;
237
238 if (initPluginFn)
239 {
240 rdpSettings* settings = pEntryPoints->GetRdpSettings(pEntryPoints);
241 rdpContext* context = pEntryPoints->GetRdpContext(pEntryPoints);
242
243 error = initPluginFn(plugin, context, settings);
244 if (error != CHANNEL_RC_OK)
245 goto error;
246 }
247
248 /* Since we do not have a private struct append the connected state after the name of the
249 * channel */
250 const size_t len = strlen(name);
251 plugin->dynvc_name = calloc(len + 2, sizeof(char));
252 if (!plugin->dynvc_name)
253 goto error;
254 strncpy(plugin->dynvc_name, name, len);
255
256 error = pEntryPoints->RegisterPlugin(pEntryPoints, name, &plugin->iface);
257 if (error == CHANNEL_RC_OK)
258 return error;
259
260error:
261 generic_plugin_terminated(&plugin->iface);
262 return error;
263}