Fix changelog email address
[freerdp-ubuntu-pcb-backport.git] / libfreerdp-utils / svc_plugin.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol client.
3  * Static Virtual Channel Interface
4  *
5  * Copyright 2009-2011 Jay Sorg
6  * Copyright 2010-2011 Vic Lee
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20
21 #include "config.h"
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <freerdp/constants.h>
26 #include <freerdp/utils/memory.h>
27 #include <freerdp/utils/mutex.h>
28 #include <freerdp/utils/debug.h>
29 #include <freerdp/utils/stream.h>
30 #include <freerdp/utils/list.h>
31 #include <freerdp/utils/thread.h>
32 #include <freerdp/utils/event.h>
33 #include <freerdp/utils/svc_plugin.h>
34
35 /* The list of all plugin instances. */
36 typedef struct rdp_svc_plugin_list rdpSvcPluginList;
37 struct rdp_svc_plugin_list
38 {
39         rdpSvcPlugin* plugin;
40         rdpSvcPluginList* next;
41 };
42
43 static rdpSvcPluginList* g_svc_plugin_list = NULL;
44
45 /* For locking the global resources */
46 static freerdp_mutex g_mutex = NULL;
47
48 /* Queue for receiving packets */
49 struct _svc_data_in_item
50 {
51         STREAM* data_in;
52         RDP_EVENT* event_in;
53 };
54 typedef struct _svc_data_in_item svc_data_in_item;
55
56 static void svc_data_in_item_free(svc_data_in_item* item)
57 {
58         if (item->data_in)
59         {
60                 stream_free(item->data_in);
61                 item->data_in = NULL;
62         }
63         if (item->event_in)
64         {
65                 freerdp_event_free(item->event_in);
66                 item->event_in = NULL;
67         }
68         xfree(item);
69 }
70
71 struct rdp_svc_plugin_private
72 {
73         void* init_handle;
74         uint32 open_handle;
75         STREAM* data_in;
76
77         LIST* data_in_list;
78         freerdp_thread* thread;
79 };
80
81 static rdpSvcPlugin* svc_plugin_find_by_init_handle(void* init_handle)
82 {
83         rdpSvcPluginList * list;
84         rdpSvcPlugin * plugin;
85
86         freerdp_mutex_lock(g_mutex);
87         for (list = g_svc_plugin_list; list; list = list->next)
88         {
89                 plugin = list->plugin;
90                 if (plugin->priv->init_handle == init_handle)
91                 {
92                         freerdp_mutex_unlock(g_mutex);
93                         return plugin;
94                 }
95         }
96         freerdp_mutex_unlock(g_mutex);
97         return NULL;
98 }
99
100 static rdpSvcPlugin* svc_plugin_find_by_open_handle(uint32 open_handle)
101 {
102         rdpSvcPluginList * list;
103         rdpSvcPlugin * plugin;
104
105         freerdp_mutex_lock(g_mutex);
106         for (list = g_svc_plugin_list; list; list = list->next)
107         {
108                 plugin = list->plugin;
109                 if (plugin->priv->open_handle == open_handle)
110                 {
111                         freerdp_mutex_unlock(g_mutex);
112                         return plugin;
113                 }
114         }
115         freerdp_mutex_unlock(g_mutex);
116         return NULL;
117 }
118
119 static void svc_plugin_remove(rdpSvcPlugin* plugin)
120 {
121         rdpSvcPluginList* list;
122         rdpSvcPluginList* prev;
123
124         /* Remove from global list */
125         freerdp_mutex_lock(g_mutex);
126         for (prev = NULL, list = g_svc_plugin_list; list; prev = list, list = list->next)
127         {
128                 if (list->plugin == plugin)
129                         break;
130         }
131         if (list)
132         {
133                 if (prev)
134                         prev->next = list->next;
135                 else
136                         g_svc_plugin_list = list->next;
137                 xfree(list);
138         }
139         freerdp_mutex_unlock(g_mutex);
140 }
141
142 static void svc_plugin_process_received(rdpSvcPlugin* plugin, void* pData, uint32 dataLength,
143         uint32 totalLength, uint32 dataFlags)
144 {
145         STREAM* data_in;
146         svc_data_in_item* item;
147
148         if (dataFlags & CHANNEL_FLAG_FIRST)
149         {
150                 if (plugin->priv->data_in != NULL)
151                         stream_free(plugin->priv->data_in);
152                 plugin->priv->data_in = stream_new(totalLength);
153         }
154
155         data_in = plugin->priv->data_in;
156         stream_check_size(data_in, (int) dataLength);
157         stream_write(data_in, pData, dataLength);
158
159         if (dataFlags & CHANNEL_FLAG_LAST)
160         {
161                 if (stream_get_size(data_in) != stream_get_length(data_in))
162                 {
163                         printf("svc_plugin_process_received: read error\n");
164                 }
165
166                 plugin->priv->data_in = NULL;
167                 stream_set_pos(data_in, 0);
168
169                 item = xnew(svc_data_in_item);
170                 item->data_in = data_in;
171
172                 freerdp_thread_lock(plugin->priv->thread);
173                 list_enqueue(plugin->priv->data_in_list, item);
174                 freerdp_thread_unlock(plugin->priv->thread);
175
176                 freerdp_thread_signal(plugin->priv->thread);
177         }
178 }
179
180 static void svc_plugin_process_event(rdpSvcPlugin* plugin, RDP_EVENT* event_in)
181 {
182         svc_data_in_item* item;
183
184         item = xnew(svc_data_in_item);
185         item->event_in = event_in;
186
187         freerdp_thread_lock(plugin->priv->thread);
188         list_enqueue(plugin->priv->data_in_list, item);
189         freerdp_thread_unlock(plugin->priv->thread);
190
191         freerdp_thread_signal(plugin->priv->thread);
192 }
193
194 static void svc_plugin_open_event(uint32 openHandle, uint32 event, void* pData, uint32 dataLength,
195         uint32 totalLength, uint32 dataFlags)
196 {
197         rdpSvcPlugin* plugin;
198
199         DEBUG_SVC("openHandle %d event %d dataLength %d totalLength %d dataFlags %d",
200                 openHandle, event, dataLength, totalLength, dataFlags);
201
202         plugin = (rdpSvcPlugin*)svc_plugin_find_by_open_handle(openHandle);
203         if (plugin == NULL)
204         {
205                 printf("svc_plugin_open_event: error no match\n");
206                 return;
207         }
208         switch (event)
209         {
210                 case CHANNEL_EVENT_DATA_RECEIVED:
211                         svc_plugin_process_received(plugin, pData, dataLength, totalLength, dataFlags);
212                         break;
213                 case CHANNEL_EVENT_WRITE_COMPLETE:
214                         stream_free((STREAM*)pData);
215                         break;
216                 case CHANNEL_EVENT_USER:
217                         svc_plugin_process_event(plugin, (RDP_EVENT*)pData);
218                         break;
219         }
220 }
221
222 static void svc_plugin_process_data_in(rdpSvcPlugin* plugin)
223 {
224         svc_data_in_item* item;
225
226         while (1)
227         {
228                 /* terminate signal */
229                 if (freerdp_thread_is_stopped(plugin->priv->thread))
230                         break;
231
232                 freerdp_thread_lock(plugin->priv->thread);
233                 item = list_dequeue(plugin->priv->data_in_list);
234                 freerdp_thread_unlock(plugin->priv->thread);
235
236                 if (item != NULL)
237                 {
238                         /* the ownership of the data is passed to the callback */
239                         if (item->data_in)
240                                 IFCALL(plugin->receive_callback, plugin, item->data_in);
241                         if (item->event_in)
242                                 IFCALL(plugin->event_callback, plugin, item->event_in);
243                         xfree(item);
244                 }
245                 else
246                         break;
247         }
248 }
249
250 static void* svc_plugin_thread_func(void* arg)
251 {
252         rdpSvcPlugin* plugin = (rdpSvcPlugin*)arg;
253
254         DEBUG_SVC("in");
255
256         IFCALL(plugin->connect_callback, plugin);
257
258         while (1)
259         {
260                 if (plugin->interval_ms > 0)
261                         freerdp_thread_wait_timeout(plugin->priv->thread, plugin->interval_ms);
262                 else
263                         freerdp_thread_wait(plugin->priv->thread);
264
265                 if (freerdp_thread_is_stopped(plugin->priv->thread))
266                         break;
267
268                 freerdp_thread_reset(plugin->priv->thread);
269                 svc_plugin_process_data_in(plugin);
270
271                 if (plugin->interval_ms > 0)
272                         IFCALL(plugin->interval_callback, plugin);
273         }
274
275         freerdp_thread_quit(plugin->priv->thread);
276
277         DEBUG_SVC("out");
278
279         return 0;
280 }
281
282 static void svc_plugin_process_connected(rdpSvcPlugin* plugin, void* pData, uint32 dataLength)
283 {
284         uint32 error;
285
286         error = plugin->channel_entry_points.pVirtualChannelOpen(plugin->priv->init_handle,
287                 &plugin->priv->open_handle, plugin->channel_def.name, svc_plugin_open_event);
288
289         if (error != CHANNEL_RC_OK)
290         {
291                 printf("svc_plugin_process_connected: open failed\n");
292                 return;
293         }
294
295         plugin->priv->data_in_list = list_new();
296         plugin->priv->thread = freerdp_thread_new();
297
298         freerdp_thread_start(plugin->priv->thread, svc_plugin_thread_func, plugin);
299 }
300
301 static void svc_plugin_process_terminated(rdpSvcPlugin* plugin)
302 {
303         svc_data_in_item* item;
304
305         freerdp_thread_stop(plugin->priv->thread);
306         freerdp_thread_free(plugin->priv->thread);
307
308         plugin->channel_entry_points.pVirtualChannelClose(plugin->priv->open_handle);
309         xfree(plugin->channel_entry_points.pExtendedData);
310
311         svc_plugin_remove(plugin);
312
313         while ((item = list_dequeue(plugin->priv->data_in_list)) != NULL)
314                 svc_data_in_item_free(item);
315         list_free(plugin->priv->data_in_list);
316
317         if (plugin->priv->data_in != NULL)
318         {
319                 stream_free(plugin->priv->data_in);
320                 plugin->priv->data_in = NULL;
321         }
322         xfree(plugin->priv);
323         plugin->priv = NULL;
324
325         IFCALL(plugin->terminate_callback, plugin);
326 }
327
328 static void svc_plugin_init_event(void* pInitHandle, uint32 event, void* pData, uint32 dataLength)
329 {
330         rdpSvcPlugin* plugin;
331
332         DEBUG_SVC("event %d", event);
333
334         plugin = (rdpSvcPlugin*)svc_plugin_find_by_init_handle(pInitHandle);
335         if (plugin == NULL)
336         {
337                 printf("svc_plugin_init_event: error no match\n");
338                 return;
339         }
340         switch (event)
341         {
342                 case CHANNEL_EVENT_CONNECTED:
343                         svc_plugin_process_connected(plugin, pData, dataLength);
344                         break;
345                 case CHANNEL_EVENT_DISCONNECTED:
346                         break;
347                 case CHANNEL_EVENT_TERMINATED:
348                         svc_plugin_process_terminated(plugin);
349                         break;
350         }
351 }
352
353 void svc_plugin_init(rdpSvcPlugin* plugin, CHANNEL_ENTRY_POINTS* pEntryPoints)
354 {
355         rdpSvcPluginList* list;
356
357         /**
358          * The channel manager will guarantee only one thread can call
359          * VirtualChannelInit at a time. So this should be safe.
360          */
361         if (g_mutex == NULL)
362                 g_mutex = freerdp_mutex_new();
363
364         memcpy(&plugin->channel_entry_points, pEntryPoints, pEntryPoints->cbSize);
365
366         plugin->priv = xnew(rdpSvcPluginPrivate);
367
368         /* Add it to the global list */
369         list = xnew(rdpSvcPluginList);
370         list->plugin = plugin;
371
372         freerdp_mutex_lock(g_mutex);
373         list->next = g_svc_plugin_list;
374         g_svc_plugin_list = list;
375         freerdp_mutex_unlock(g_mutex);
376
377         plugin->channel_entry_points.pVirtualChannelInit(&plugin->priv->init_handle,
378                 &plugin->channel_def, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, svc_plugin_init_event);
379 }
380
381 int svc_plugin_send(rdpSvcPlugin* plugin, STREAM* data_out)
382 {
383         uint32 error = 0;
384
385         DEBUG_SVC("length %d", stream_get_length(data_out));
386
387         error = plugin->channel_entry_points.pVirtualChannelWrite(plugin->priv->open_handle,
388                 stream_get_data(data_out), stream_get_length(data_out), data_out);
389         if (error != CHANNEL_RC_OK)
390         {
391                 stream_free(data_out);
392                 printf("svc_plugin_send: VirtualChannelWrite failed %d\n", error);
393         }
394
395         return error;
396 }
397
398 int svc_plugin_send_event(rdpSvcPlugin* plugin, RDP_EVENT* event)
399 {
400         uint32 error = 0;
401
402         DEBUG_SVC("event_type %d", event->event_type);
403
404         error = plugin->channel_entry_points.pVirtualChannelEventPush(plugin->priv->open_handle, event);
405
406         if (error != CHANNEL_RC_OK)
407                 printf("svc_plugin_send_event: VirtualChannelEventPush failed %d\n", error);
408
409         return error;
410 }