FreeRDP
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 
26 static UINT generic_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
27  IWTSVirtualChannel* pChannel, BYTE* Data,
28  BOOL* pbAccept,
29  IWTSVirtualChannelCallback** ppCallback)
30 {
31  GENERIC_CHANNEL_CALLBACK* callback = NULL;
32  GENERIC_DYNVC_PLUGIN* plugin = NULL;
33  GENERIC_LISTENER_CALLBACK* listener_callback = (GENERIC_LISTENER_CALLBACK*)pListenerCallback;
34 
35  if (!listener_callback || !listener_callback->plugin)
36  return ERROR_INTERNAL_ERROR;
37 
38  plugin = (GENERIC_DYNVC_PLUGIN*)listener_callback->plugin;
39  WLog_Print(plugin->log, WLOG_TRACE, "...");
40 
41  callback = (GENERIC_CHANNEL_CALLBACK*)calloc(1, plugin->channelCallbackSize);
42  if (!callback)
43  {
44  WLog_Print(plugin->log, WLOG_ERROR, "calloc failed!");
45  return CHANNEL_RC_NO_MEMORY;
46  }
47 
48  /* implant configured channel callbacks */
49  callback->iface = *plugin->channel_callbacks;
50 
51  callback->plugin = listener_callback->plugin;
52  callback->channel_mgr = listener_callback->channel_mgr;
53  callback->channel = pChannel;
54 
55  listener_callback->channel_callback = callback;
56  listener_callback->channel = pChannel;
57 
58  *ppCallback = (IWTSVirtualChannelCallback*)callback;
59  return CHANNEL_RC_OK;
60 }
61 
62 static UINT generic_dynvc_plugin_initialize(IWTSPlugin* pPlugin,
63  IWTSVirtualChannelManager* pChannelMgr)
64 {
65  UINT rc = 0;
66  GENERIC_LISTENER_CALLBACK* listener_callback = NULL;
67  GENERIC_DYNVC_PLUGIN* plugin = (GENERIC_DYNVC_PLUGIN*)pPlugin;
68 
69  if (!plugin)
70  return CHANNEL_RC_BAD_CHANNEL_HANDLE;
71 
72  if (!pChannelMgr)
73  return ERROR_INVALID_PARAMETER;
74 
75  if (plugin->initialized)
76  {
77  WLog_ERR(TAG, "[%s] channel initialized twice, aborting", plugin->dynvc_name);
78  return ERROR_INVALID_DATA;
79  }
80 
81  WLog_Print(plugin->log, WLOG_TRACE, "...");
82  listener_callback = (GENERIC_LISTENER_CALLBACK*)calloc(1, sizeof(GENERIC_LISTENER_CALLBACK));
83  if (!listener_callback)
84  {
85  WLog_Print(plugin->log, WLOG_ERROR, "calloc failed!");
86  return CHANNEL_RC_NO_MEMORY;
87  }
88 
89  plugin->listener_callback = listener_callback;
90  listener_callback->iface.OnNewChannelConnection = generic_on_new_channel_connection;
91  listener_callback->plugin = pPlugin;
92  listener_callback->channel_mgr = pChannelMgr;
93  rc = pChannelMgr->CreateListener(pChannelMgr, plugin->dynvc_name, 0, &listener_callback->iface,
94  &plugin->listener);
95 
96  plugin->listener->pInterface = plugin->iface.pInterface;
97  plugin->initialized = (rc == CHANNEL_RC_OK);
98  return rc;
99 }
100 
101 static UINT generic_plugin_terminated(IWTSPlugin* pPlugin)
102 {
103  GENERIC_DYNVC_PLUGIN* plugin = (GENERIC_DYNVC_PLUGIN*)pPlugin;
104  UINT error = CHANNEL_RC_OK;
105 
106  if (!plugin)
107  return CHANNEL_RC_BAD_CHANNEL_HANDLE;
108 
109  WLog_Print(plugin->log, WLOG_TRACE, "...");
110 
111  /* some channels (namely rdpei), look at initialized to see if they should continue to run */
112  plugin->initialized = FALSE;
113 
114  if (plugin->terminatePluginFn)
115  plugin->terminatePluginFn(plugin);
116 
117  if (plugin->listener_callback)
118  {
119  IWTSVirtualChannelManager* mgr = plugin->listener_callback->channel_mgr;
120  if (mgr)
121  IFCALL(mgr->DestroyListener, mgr, plugin->listener);
122  }
123 
124  free(plugin->listener_callback);
125  free(plugin->dynvc_name);
126  free(plugin);
127  return error;
128 }
129 
130 static UINT generic_dynvc_plugin_attached(IWTSPlugin* pPlugin)
131 {
132  GENERIC_DYNVC_PLUGIN* pluginn = (GENERIC_DYNVC_PLUGIN*)pPlugin;
133  UINT error = CHANNEL_RC_OK;
134 
135  if (!pluginn)
136  return CHANNEL_RC_BAD_CHANNEL_HANDLE;
137 
138  pluginn->attached = TRUE;
139  return error;
140 }
141 
142 static UINT generic_dynvc_plugin_detached(IWTSPlugin* pPlugin)
143 {
144  GENERIC_DYNVC_PLUGIN* plugin = (GENERIC_DYNVC_PLUGIN*)pPlugin;
145  UINT error = CHANNEL_RC_OK;
146 
147  if (!plugin)
148  return CHANNEL_RC_BAD_CHANNEL_HANDLE;
149 
150  plugin->attached = FALSE;
151  return error;
152 }
153 
154 UINT freerdp_generic_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints, const char* logTag,
155  const char* name, size_t pluginSize, size_t channelCallbackSize,
156  const IWTSVirtualChannelCallback* channel_callbacks,
157  DYNVC_PLUGIN_INIT_FN initPluginFn,
158  DYNVC_PLUGIN_TERMINATE_FN terminatePluginFn)
159 {
160  GENERIC_DYNVC_PLUGIN* plugin = NULL;
161  UINT error = CHANNEL_RC_INITIALIZATION_ERROR;
162 
163  WINPR_ASSERT(pEntryPoints);
164  WINPR_ASSERT(pEntryPoints->GetPlugin);
165  WINPR_ASSERT(logTag);
166  WINPR_ASSERT(name);
167  WINPR_ASSERT(pluginSize >= sizeof(*plugin));
168  WINPR_ASSERT(channelCallbackSize >= sizeof(GENERIC_CHANNEL_CALLBACK));
169 
170  plugin = (GENERIC_DYNVC_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, name);
171  if (plugin != NULL)
172  return CHANNEL_RC_ALREADY_INITIALIZED;
173 
174  plugin = (GENERIC_DYNVC_PLUGIN*)calloc(1, pluginSize);
175  if (!plugin)
176  {
177  WLog_ERR(TAG, "calloc failed!");
178  return CHANNEL_RC_NO_MEMORY;
179  }
180 
181  plugin->log = WLog_Get(logTag);
182  plugin->attached = TRUE;
183  plugin->channel_callbacks = channel_callbacks;
184  plugin->channelCallbackSize = channelCallbackSize;
185  plugin->iface.Initialize = generic_dynvc_plugin_initialize;
186  plugin->iface.Connected = NULL;
187  plugin->iface.Disconnected = NULL;
188  plugin->iface.Terminated = generic_plugin_terminated;
189  plugin->iface.Attached = generic_dynvc_plugin_attached;
190  plugin->iface.Detached = generic_dynvc_plugin_detached;
191  plugin->terminatePluginFn = terminatePluginFn;
192 
193  if (initPluginFn)
194  {
195  rdpSettings* settings = pEntryPoints->GetRdpSettings(pEntryPoints);
196  rdpContext* context = pEntryPoints->GetRdpContext(pEntryPoints);
197 
198  error = initPluginFn(plugin, context, settings);
199  if (error != CHANNEL_RC_OK)
200  goto error;
201  }
202 
203  plugin->dynvc_name = _strdup(name);
204  if (!plugin->dynvc_name)
205  goto error;
206 
207  error = pEntryPoints->RegisterPlugin(pEntryPoints, name, &plugin->iface);
208  if (error == CHANNEL_RC_OK)
209  return error;
210 
211 error:
212  generic_plugin_terminated(&plugin->iface);
213  return error;
214 }