Fix changelog email address
[freerdp-ubuntu-pcb-backport.git] / libfreerdp-channels / libchannels.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol client.
3  * Virtual Channel Manager
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 /**
22  * MS compatible plugin interface
23  * reference:
24  * http://msdn.microsoft.com/en-us/library/aa383580.aspx
25  *
26  * Notes on threads:
27  * Many virtual channel plugins are built using threads.
28  * Non main threads may call MyVirtualChannelOpen,
29  * MyVirtualChannelClose, or MyVirtualChannelWrite.
30  * Since the plugin's VirtualChannelEntry function is called
31  * from the main thread, MyVirtualChannelInit has to be called
32  * from the main thread.
33  */
34
35 #include "config.h"
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <freerdp/freerdp.h>
40 #include <freerdp/constants.h>
41 #include <freerdp/channels/channels.h>
42 #include <freerdp/svc.h>
43 #include <freerdp/utils/memory.h>
44 #include <freerdp/utils/list.h>
45 #include <freerdp/utils/semaphore.h>
46 #include <freerdp/utils/mutex.h>
47 #include <freerdp/utils/wait_obj.h>
48 #include <freerdp/utils/load_plugin.h>
49 #include <freerdp/utils/event.h>
50
51 #include "libchannels.h"
52
53 #define CHANNEL_MAX_COUNT 30
54
55 struct lib_data
56 {
57         PVIRTUALCHANNELENTRY entry; /* the one and only exported function */
58         PCHANNEL_INIT_EVENT_FN init_event_proc;
59         void* init_handle;
60 };
61
62 struct channel_data
63 {
64         char name[CHANNEL_NAME_LEN + 1];
65         int open_handle;
66         int options;
67         int flags; /* 0 nothing 1 init 2 open */
68         PCHANNEL_OPEN_EVENT_FN open_event_proc;
69 };
70
71 struct sync_data
72 {
73         void* data;
74         uint32 data_length;
75         void* user_data;
76         int index;
77 };
78
79 typedef struct rdp_init_handle rdpInitHandle;
80 struct rdp_init_handle
81 {
82         rdpChannels* channels;
83 };
84
85 struct rdp_channels
86 {
87         /**
88          * Only the main thread alters these arrays, before any
89          * library thread is allowed in(post_connect is called)
90          * so no need to use mutex locking
91          * After post_connect, each library thread can only access it's
92          * own array items
93          * ie, no two threads can access index 0, ...
94          */
95
96         struct lib_data libs_data[CHANNEL_MAX_COUNT];
97         int num_libs_data;
98
99         struct channel_data channels_data[CHANNEL_MAX_COUNT];
100         int num_channels_data;
101
102         rdpInitHandle init_handles[CHANNEL_MAX_COUNT];
103         int num_init_handles;
104
105         /* control for entry into MyVirtualChannelInit */
106         int can_call_init;
107         rdpSettings* settings;
108
109         /* true once freerdp_chanman_post_connect is called */
110         int is_connected;
111
112         /* used for locating the channels for a given instance */
113         freerdp* instance;
114
115         /* signal for incoming data or event */
116         struct wait_obj* signal;
117
118         /* used for sync write */
119         freerdp_mutex sync_data_mutex;
120         LIST* sync_data_list;
121
122         /* used for sync event */
123         freerdp_sem event_sem;
124         RDP_EVENT* event;
125 };
126
127 /**
128  * The current channel manager reference passes from VirtualChannelEntry to
129  * VirtualChannelInit for the pInitHandle.
130  */
131 static rdpChannels* g_init_channels;
132
133 /* The list of all channel managers. */
134 typedef struct rdp_channels_list rdpChannelsList;
135 struct rdp_channels_list
136 {
137         rdpChannels* channels;
138         rdpChannelsList* next;
139 };
140
141 static rdpChannelsList* g_channels_list;
142
143 /* To generate unique sequence for all open handles */
144 static int g_open_handle_sequence;
145
146 /* For locking the global resources */
147 static freerdp_mutex g_mutex_init;
148 static freerdp_mutex g_mutex_list;
149
150 /* returns the channels for the open handle passed in */
151 static rdpChannels* freerdp_channels_find_by_open_handle(int open_handle, int* pindex)
152 {
153         int lindex;
154         rdpChannels* channels;
155         rdpChannelsList* channels_list;
156
157         freerdp_mutex_lock(g_mutex_list);
158
159         for (channels_list = g_channels_list; channels_list; channels_list = channels_list->next)
160         {
161                 channels = channels_list->channels;
162
163                 for (lindex = 0; lindex < channels->num_channels_data; lindex++)
164                 {
165                         if (channels->channels_data[lindex].open_handle == open_handle)
166                         {
167                                 freerdp_mutex_unlock(g_mutex_list);
168                                 *pindex = lindex;
169                                 return channels;
170                         }
171                 }
172         }
173
174         freerdp_mutex_unlock(g_mutex_list);
175
176         return NULL;
177 }
178
179 /* returns the channels for the rdp instance passed in */
180 static rdpChannels* freerdp_channels_find_by_instance(freerdp* instance)
181 {
182         rdpChannels* channels;
183         rdpChannelsList* channels_list;
184
185         freerdp_mutex_lock(g_mutex_list);
186
187         for (channels_list = g_channels_list; channels_list; channels_list = channels_list->next)
188         {
189                 channels = channels_list->channels;
190                 if (channels->instance == instance)
191                 {
192                         freerdp_mutex_unlock(g_mutex_list);
193                         return channels;
194                 }
195         }
196
197         freerdp_mutex_unlock(g_mutex_list);
198
199         return NULL;
200 }
201
202 /* returns struct channel_data for the channel name passed in */
203 static struct channel_data* freerdp_channels_find_channel_data_by_name(rdpChannels* channels, const char* channel_name, int* pindex)
204 {
205         int lindex;
206         struct channel_data* lchannel_data;
207
208         for (lindex = 0; lindex < channels->num_channels_data; lindex++)
209         {
210                 lchannel_data = channels->channels_data + lindex;
211
212                 if (strcmp(channel_name, lchannel_data->name) == 0)
213                 {
214                         if (pindex != 0)
215                                 *pindex = lindex;
216
217                         return lchannel_data;
218                 }
219         }
220
221         return NULL;
222 }
223
224 /* returns rdpChannel for the channel id passed in */
225 static rdpChannel* freerdp_channels_find_channel_by_id(rdpChannels* channels, rdpSettings* settings, int channel_id, int* pindex)
226 {
227         int lindex;
228         int lcount;
229         rdpChannel* lrdp_channel;
230
231         lcount = settings->num_channels;
232
233         for (lindex = 0; lindex < lcount; lindex++)
234         {
235                 lrdp_channel = settings->channels + lindex;
236
237                 if (lrdp_channel->channel_id == channel_id)
238                 {
239                         if (pindex != 0)
240                                 *pindex = lindex;
241
242                         return lrdp_channel;
243                 }
244         }
245
246         return NULL;
247 }
248
249 /* returns rdpChannel for the channel name passed in */
250 static rdpChannel* freerdp_channels_find_channel_by_name(rdpChannels* channels,
251                 rdpSettings* settings, const char* channel_name, int* pindex)
252 {
253         int lindex;
254         int lcount;
255         rdpChannel* lrdp_channel;
256
257         lcount = settings->num_channels;
258
259         for (lindex = 0; lindex < lcount; lindex++)
260         {
261                 lrdp_channel = settings->channels + lindex;
262
263                 if (strcmp(channel_name, lrdp_channel->name) == 0)
264                 {
265                         if (pindex != 0)
266                                 *pindex = lindex;
267
268                         return lrdp_channel;
269                 }
270         }
271
272         return NULL;
273 }
274
275 /**
276  * must be called by same thread that calls freerdp_chanman_load_plugin
277  * according to MS docs
278  * only called from main thread
279  */
280 static uint32 FREERDP_CC MyVirtualChannelInit(void** ppInitHandle, PCHANNEL_DEF pChannel,
281         int channelCount, uint32 versionRequested, PCHANNEL_INIT_EVENT_FN pChannelInitEventProc)
282 {
283         int index;
284         rdpChannels* channels;
285         struct lib_data* llib;
286         rdpChannel* lrdp_channel;
287         PCHANNEL_DEF lchannel_def;
288         struct channel_data* lchannel_data;
289
290         channels = g_init_channels;
291         channels->init_handles[channels->num_init_handles].channels = channels;
292         *ppInitHandle = &channels->init_handles[channels->num_init_handles];
293         channels->num_init_handles++;
294
295         DEBUG_CHANNELS("enter");
296
297         if (!channels->can_call_init)
298         {
299                 DEBUG_CHANNELS("error not in entry");
300                 return CHANNEL_RC_NOT_IN_VIRTUALCHANNELENTRY;
301         }
302
303         if (ppInitHandle == 0)
304         {
305                 DEBUG_CHANNELS("error bad pphan");
306                 return CHANNEL_RC_BAD_INIT_HANDLE;
307         }
308
309         if (channels->num_channels_data + channelCount >= CHANNEL_MAX_COUNT)
310         {
311                 DEBUG_CHANNELS("error too many channels");
312                 return CHANNEL_RC_TOO_MANY_CHANNELS;
313         }
314
315         if (pChannel == 0)
316         {
317                 DEBUG_CHANNELS("error bad pchan");
318                 return CHANNEL_RC_BAD_CHANNEL;
319         }
320
321         if (channels->is_connected)
322         {
323                 DEBUG_CHANNELS("error already connected");
324                 return CHANNEL_RC_ALREADY_CONNECTED;
325         }
326
327         if (versionRequested != VIRTUAL_CHANNEL_VERSION_WIN2000)
328         {
329                 DEBUG_CHANNELS("warning version");
330         }
331
332         for (index = 0; index < channelCount; index++)
333         {
334                 lchannel_def = pChannel + index;
335                 if (freerdp_channels_find_channel_data_by_name(channels, lchannel_def->name, 0) != 0)
336                 {
337                         DEBUG_CHANNELS("error channel already used");
338                         return CHANNEL_RC_BAD_CHANNEL;
339                 }
340         }
341
342         llib = channels->libs_data + channels->num_libs_data;
343         llib->init_event_proc = pChannelInitEventProc;
344         llib->init_handle = *ppInitHandle;
345         channels->num_libs_data++;
346
347         for (index = 0; index < channelCount; index++)
348         {
349                 lchannel_def = pChannel + index;
350                 lchannel_data = channels->channels_data + channels->num_channels_data;
351
352                 freerdp_mutex_lock(g_mutex_list);
353                 lchannel_data->open_handle = g_open_handle_sequence++;
354                 freerdp_mutex_unlock(g_mutex_list);
355
356                 lchannel_data->flags = 1; /* init */
357                 strncpy(lchannel_data->name, lchannel_def->name, CHANNEL_NAME_LEN);
358                 lchannel_data->options = lchannel_def->options;
359
360                 if (channels->settings->num_channels < 16)
361                 {
362                         lrdp_channel = channels->settings->channels + channels->settings->num_channels;
363                         strncpy(lrdp_channel->name, lchannel_def->name, 7);
364                         lrdp_channel->options = lchannel_def->options;
365                         channels->settings->num_channels++;
366                 }
367                 else
368                 {
369                         DEBUG_CHANNELS("warning more than 16 channels");
370                 }
371
372                 channels->num_channels_data++;
373         }
374
375         return CHANNEL_RC_OK;
376 }
377
378 /**
379  * can be called from any thread
380  * thread safe because no 2 threads can have the same channel name registered
381  */
382 static uint32 FREERDP_CC MyVirtualChannelOpen(void* pInitHandle, uint32* pOpenHandle,
383         char* pChannelName, PCHANNEL_OPEN_EVENT_FN pChannelOpenEventProc)
384 {
385         int index;
386         rdpChannels* channels;
387         struct channel_data* lchannel_data;
388
389         DEBUG_CHANNELS("enter");
390
391         channels = ((rdpInitHandle*) pInitHandle)->channels;
392
393         if (pOpenHandle == 0)
394         {
395                 DEBUG_CHANNELS("error bad chanhan");
396                 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
397         }
398
399         if (pChannelOpenEventProc == 0)
400         {
401                 DEBUG_CHANNELS("error bad proc");
402                 return CHANNEL_RC_BAD_PROC;
403         }
404
405         if (!channels->is_connected)
406         {
407                 DEBUG_CHANNELS("error not connected");
408                 return CHANNEL_RC_NOT_CONNECTED;
409         }
410
411         lchannel_data = freerdp_channels_find_channel_data_by_name(channels, pChannelName, &index);
412
413         if (lchannel_data == 0)
414         {
415                 DEBUG_CHANNELS("error chan name");
416                 return CHANNEL_RC_UNKNOWN_CHANNEL_NAME;
417         }
418
419         if (lchannel_data->flags == 2)
420         {
421                 DEBUG_CHANNELS("error chan already open");
422                 return CHANNEL_RC_ALREADY_OPEN;
423         }
424
425         lchannel_data->flags = 2; /* open */
426         lchannel_data->open_event_proc = pChannelOpenEventProc;
427         *pOpenHandle = lchannel_data->open_handle;
428
429         return CHANNEL_RC_OK;
430 }
431
432 /**
433  * can be called from any thread
434  * thread safe because no 2 threads can have the same openHandle
435  */
436 static uint32 FREERDP_CC MyVirtualChannelClose(uint32 openHandle)
437 {
438         int index;
439         rdpChannels* channels;
440         struct channel_data* lchannel_data;
441
442         DEBUG_CHANNELS("enter");
443
444         channels = freerdp_channels_find_by_open_handle(openHandle, &index);
445
446         if ((channels == NULL) || (index < 0) || (index >= CHANNEL_MAX_COUNT))
447         {
448                 DEBUG_CHANNELS("error bad channels");
449                 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
450         }
451
452         lchannel_data = channels->channels_data + index;
453
454         if (lchannel_data->flags != 2)
455         {
456                 DEBUG_CHANNELS("error not open");
457                 return CHANNEL_RC_NOT_OPEN;
458         }
459
460         lchannel_data->flags = 0;
461
462         return CHANNEL_RC_OK;
463 }
464
465 /* can be called from any thread */
466 static uint32 FREERDP_CC MyVirtualChannelWrite(uint32 openHandle, void* pData, uint32 dataLength, void* pUserData)
467 {
468         int index;
469         rdpChannels* channels;
470         struct sync_data* item;
471         struct channel_data* lchannel_data;
472
473         channels = freerdp_channels_find_by_open_handle(openHandle, &index);
474
475         if ((channels == NULL) || (index < 0) || (index >= CHANNEL_MAX_COUNT))
476         {
477                 DEBUG_CHANNELS("error bad chanhan");
478                 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
479         }
480
481         if (!channels->is_connected)
482         {
483                 DEBUG_CHANNELS("error not connected");
484                 return CHANNEL_RC_NOT_CONNECTED;
485         }
486
487         if (pData == 0)
488         {
489                 DEBUG_CHANNELS("error bad pData");
490                 return CHANNEL_RC_NULL_DATA;
491         }
492
493         if (dataLength == 0)
494         {
495                 DEBUG_CHANNELS("error bad dataLength");
496                 return CHANNEL_RC_ZERO_LENGTH;
497         }
498
499         lchannel_data = channels->channels_data + index;
500
501         if (lchannel_data->flags != 2)
502         {
503                 DEBUG_CHANNELS("error not open");
504                 return CHANNEL_RC_NOT_OPEN;
505         }
506
507         freerdp_mutex_lock(channels->sync_data_mutex); /* lock channels->sync* vars */
508
509         if (!channels->is_connected)
510         {
511                 freerdp_mutex_unlock(channels->sync_data_mutex);
512                 DEBUG_CHANNELS("error not connected");
513                 return CHANNEL_RC_NOT_CONNECTED;
514         }
515
516         item = xnew(struct sync_data);
517         item->data = pData;
518         item->data_length = dataLength;
519         item->user_data = pUserData;
520         item->index = index;
521         list_enqueue(channels->sync_data_list, item);
522         freerdp_mutex_unlock(channels->sync_data_mutex);
523
524         /* set the event */
525         wait_obj_set(channels->signal);
526
527         return CHANNEL_RC_OK;
528 }
529
530 static uint32 FREERDP_CC MyVirtualChannelEventPush(uint32 openHandle, RDP_EVENT* event)
531 {
532         int index;
533         rdpChannels* channels;
534         struct channel_data* lchannel_data;
535
536         channels = freerdp_channels_find_by_open_handle(openHandle, &index);
537
538         if ((channels == NULL) || (index < 0) || (index >= CHANNEL_MAX_COUNT))
539         {
540                 DEBUG_CHANNELS("error bad chanhan");
541                 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
542         }
543
544         if (!channels->is_connected)
545         {
546                 DEBUG_CHANNELS("error not connected");
547                 return CHANNEL_RC_NOT_CONNECTED;
548         }
549
550         if (event == NULL)
551         {
552                 DEBUG_CHANNELS("error bad event");
553                 return CHANNEL_RC_NULL_DATA;
554         }
555
556         lchannel_data = channels->channels_data + index;
557
558         if (lchannel_data->flags != 2)
559         {
560                 DEBUG_CHANNELS("error not open");
561                 return CHANNEL_RC_NOT_OPEN;
562         }
563
564         freerdp_sem_wait(channels->event_sem); /* lock channels->event */
565
566         if (!channels->is_connected)
567         {
568                 freerdp_sem_signal(channels->event_sem);
569                 DEBUG_CHANNELS("error not connected");
570                 return CHANNEL_RC_NOT_CONNECTED;
571         }
572
573         channels->event = event;
574         /* set the event */
575         wait_obj_set(channels->signal);
576
577         return CHANNEL_RC_OK;
578 }
579
580 /**
581  * this is called shortly after the application starts and
582  * before any other function in the file
583  * called only from main thread
584  */
585 int freerdp_channels_global_init(void)
586 {
587         g_init_channels = NULL;
588         g_channels_list = NULL;
589         g_open_handle_sequence = 1;
590         g_mutex_init = freerdp_mutex_new();
591         g_mutex_list = freerdp_mutex_new();
592
593         return 0;
594 }
595
596 int freerdp_channels_global_uninit(void)
597 {
598         while (g_channels_list)
599                 freerdp_channels_free(g_channels_list->channels);
600
601         freerdp_mutex_free(g_mutex_init);
602         freerdp_mutex_free(g_mutex_list);
603
604         return 0;
605 }
606
607 rdpChannels* freerdp_channels_new(void)
608 {
609         rdpChannels* channels;
610         rdpChannelsList* channels_list;
611
612         channels = xnew(rdpChannels);
613
614         channels->sync_data_mutex = freerdp_mutex_new();
615         channels->sync_data_list = list_new();
616
617         channels->event_sem = freerdp_sem_new(1);
618         channels->signal = wait_obj_new();
619
620         /* Add it to the global list */
621         channels_list = xnew(rdpChannelsList);
622         channels_list->channels = channels;
623
624         freerdp_mutex_lock(g_mutex_list);
625         channels_list->next = g_channels_list;
626         g_channels_list = channels_list;
627         freerdp_mutex_unlock(g_mutex_list);
628
629         return channels;
630 }
631
632 void freerdp_channels_free(rdpChannels* channels)
633 {
634         rdpChannelsList* list;
635         rdpChannelsList* prev;
636
637         freerdp_mutex_free(channels->sync_data_mutex);
638         list_free(channels->sync_data_list);
639
640         freerdp_sem_free(channels->event_sem);
641         wait_obj_free(channels->signal);
642
643         /* Remove from global list */
644
645         freerdp_mutex_lock(g_mutex_list);
646
647         for (prev = NULL, list = g_channels_list; list; prev = list, list = list->next)
648         {
649                 if (list->channels == channels)
650                         break;
651         }
652
653         if (list)
654         {
655                 if (prev)
656                         prev->next = list->next;
657                 else
658                         g_channels_list = list->next;
659                 xfree(list);
660         }
661
662         freerdp_mutex_unlock(g_mutex_list);
663
664         xfree(channels);
665 }
666
667 /**
668  * this is called when processing the command line parameters
669  * called only from main thread
670  */
671 int freerdp_channels_load_plugin(rdpChannels* channels, rdpSettings* settings, const char* name, void* data)
672 {
673         int ok;
674         struct lib_data* lib;
675         CHANNEL_ENTRY_POINTS_EX ep;
676
677         DEBUG_CHANNELS("%s", name);
678
679         if (channels->num_libs_data + 1 >= CHANNEL_MAX_COUNT)
680         {
681                 DEBUG_CHANNELS("too many channels");
682                 return 1;
683         }
684
685         lib = channels->libs_data + channels->num_libs_data;
686         lib->entry = (PVIRTUALCHANNELENTRY) freerdp_load_plugin(name, CHANNEL_EXPORT_FUNC_NAME);
687         //lib->entry = (PVIRTUALCHANNELENTRY) freerdp_load_channel_plugin(settings, name, CHANNEL_EXPORT_FUNC_NAME);
688
689         if (lib->entry == NULL)
690         {
691                 DEBUG_CHANNELS("failed to find export function");
692                 return 1;
693         }
694
695         ep.cbSize = sizeof(ep);
696         ep.protocolVersion = VIRTUAL_CHANNEL_VERSION_WIN2000;
697         ep.pVirtualChannelInit = MyVirtualChannelInit;
698         ep.pVirtualChannelOpen = MyVirtualChannelOpen;
699         ep.pVirtualChannelClose = MyVirtualChannelClose;
700         ep.pVirtualChannelWrite = MyVirtualChannelWrite;
701         ep.pExtendedData = data;
702         ep.pVirtualChannelEventPush = MyVirtualChannelEventPush;
703
704         /* enable MyVirtualChannelInit */
705         channels->can_call_init = 1;
706         channels->settings = settings;
707
708         freerdp_mutex_lock(g_mutex_init);
709
710         g_init_channels = channels;
711         ok = lib->entry((PCHANNEL_ENTRY_POINTS) &ep);
712         g_init_channels = NULL;
713
714         freerdp_mutex_unlock(g_mutex_init);
715
716         /* disable MyVirtualChannelInit */
717         channels->settings = 0;
718         channels->can_call_init = 0;
719
720         if (!ok)
721         {
722                 DEBUG_CHANNELS("export function call failed");
723                 return 1;
724         }
725
726         return 0;
727 }
728
729 /**
730  * go through and inform all the libraries that we are initialized
731  * called only from main thread
732  */
733 int freerdp_channels_pre_connect(rdpChannels* channels, freerdp* instance)
734 {
735         int index;
736         void* dummy;
737         struct lib_data* llib;
738         CHANNEL_DEF lchannel_def;
739
740         DEBUG_CHANNELS("enter");
741         channels->instance = instance;
742
743         /**
744          * If rdpsnd is registered but not rdpdr, it's necessary to register a fake
745          * rdpdr channel to make sound work. This is a workaround for Window 7 and
746          * Windows 2008
747          */
748         if (freerdp_channels_find_channel_data_by_name(channels, "rdpsnd", 0) != 0 &&
749                 freerdp_channels_find_channel_data_by_name(channels, "rdpdr", 0) == 0)
750         {
751                 lchannel_def.options = CHANNEL_OPTION_INITIALIZED |
752                         CHANNEL_OPTION_ENCRYPT_RDP;
753                 strcpy(lchannel_def.name, "rdpdr");
754                 channels->can_call_init = 1;
755                 channels->settings = instance->settings;
756                 freerdp_mutex_lock(g_mutex_init);
757                 g_init_channels = channels;
758                 MyVirtualChannelInit(&dummy, &lchannel_def, 1,
759                         VIRTUAL_CHANNEL_VERSION_WIN2000, 0);
760                 g_init_channels = NULL;
761                 freerdp_mutex_unlock(g_mutex_init);
762                 channels->can_call_init = 0;
763                 channels->settings = 0;
764                 DEBUG_CHANNELS("registered fake rdpdr for rdpsnd.");
765         }
766
767         for (index = 0; index < channels->num_libs_data; index++)
768         {
769                 llib = channels->libs_data + index;
770
771                 if (llib->init_event_proc != 0)
772                         llib->init_event_proc(llib->init_handle, CHANNEL_EVENT_INITIALIZED, 0, 0);
773         }
774
775         return 0;
776 }
777
778 /**
779  * go through and inform all the libraries that we are connected
780  * this will tell the libraries that its ok to call MyVirtualChannelOpen
781  * called only from main thread
782  */
783 int freerdp_channels_post_connect(rdpChannels* channels, freerdp* instance)
784 {
785         int index;
786         char* hostname;
787         int hostname_len;
788         struct lib_data* llib;
789
790         channels->is_connected = 1;
791         hostname = instance->settings->hostname;
792         hostname_len = strlen(hostname);
793
794         DEBUG_CHANNELS("hostname [%s] channels->num_libs [%d]", hostname, channels->num_libs_data);
795
796         for (index = 0; index < channels->num_libs_data; index++)
797         {
798                 llib = channels->libs_data + index;
799
800                 if (llib->init_event_proc != 0)
801                         llib->init_event_proc(llib->init_handle, CHANNEL_EVENT_CONNECTED, hostname, hostname_len);
802         }
803
804         return 0;
805 }
806
807 /**
808  * data comming from the server to the client
809  * called only from main thread
810  */
811 int freerdp_channels_data(freerdp* instance, int channel_id, void* data, int data_size, int flags, int total_size)
812 {
813         int index;
814         rdpChannels* channels;
815         rdpChannel* lrdp_channel;
816         struct channel_data* lchannel_data;
817
818         channels = freerdp_channels_find_by_instance(instance);
819
820         if (channels == 0)
821         {
822                 DEBUG_CHANNELS("could not find channel manager");
823                 return 1;
824         }
825
826         lrdp_channel = freerdp_channels_find_channel_by_id(channels, instance->settings,
827                 channel_id, &index);
828         if (lrdp_channel == 0)
829         {
830                 DEBUG_CHANNELS("could not find channel id");
831                 return 1;
832         }
833
834         lchannel_data = freerdp_channels_find_channel_data_by_name(channels, lrdp_channel->name, &index);
835
836         if (lchannel_data == 0)
837         {
838                 DEBUG_CHANNELS("could not find channel name");
839                 return 1;
840         }
841
842         if (lchannel_data->open_event_proc != 0)
843         {
844                 lchannel_data->open_event_proc(lchannel_data->open_handle,
845                         CHANNEL_EVENT_DATA_RECEIVED, data, data_size, total_size, flags);
846         }
847
848         return 0;
849 }
850
851 static const char* event_class_to_name_table[] =
852 {
853         "rdpdbg",   /* RDP_EVENT_CLASS_DEBUG */
854         "cliprdr",  /* RDP_EVENT_CLASS_CLIPRDR */
855         "tsmf",     /* RDP_EVENT_CLASS_TSMF */
856         "rail",     /* RDP_EVENT_CLASS_RAIL */
857         NULL
858 };
859
860 /**
861  * Send a plugin-defined event to the plugin.
862  * called only from main thread
863  * @param channels the channel manager instance
864  * @param event an event object created by freerdp_event_new()
865  */
866 FREERDP_API int freerdp_channels_send_event(rdpChannels* channels, RDP_EVENT* event)
867 {
868         int index;
869         const char* name;
870         struct channel_data* lchannel_data;
871
872         name = event_class_to_name_table[event->event_class];
873
874         if (name == NULL)
875         {
876                 DEBUG_CHANNELS("unknown event_class %d", event->event_class);
877                 freerdp_event_free(event);
878                 return 1;
879         }
880
881         lchannel_data = freerdp_channels_find_channel_data_by_name(channels, name, &index);
882
883         if (lchannel_data == NULL)
884         {
885                 DEBUG_CHANNELS("could not find channel name %s", name);
886                 freerdp_event_free(event);
887                 return 1;
888         }
889
890         if (lchannel_data->open_event_proc != NULL)
891         {
892                 lchannel_data->open_event_proc(lchannel_data->open_handle,
893                         CHANNEL_EVENT_USER,
894                         event, sizeof(RDP_EVENT), sizeof(RDP_EVENT), 0);
895         }
896
897         return 0;
898 }
899
900 /**
901  * called only from main thread
902  */
903 static void freerdp_channels_process_sync(rdpChannels* channels, freerdp* instance)
904 {
905         struct sync_data* item;
906         rdpChannel* lrdp_channel;
907         struct channel_data* lchannel_data;
908
909         while (channels->sync_data_list->head != NULL)
910         {
911                 freerdp_mutex_lock(channels->sync_data_mutex);
912                 item = (struct sync_data*)list_dequeue(channels->sync_data_list);
913                 freerdp_mutex_unlock(channels->sync_data_mutex);
914
915                 lchannel_data = channels->channels_data + item->index;
916                 lrdp_channel = freerdp_channels_find_channel_by_name(channels, instance->settings,
917                         lchannel_data->name, &item->index);
918
919                 if (lrdp_channel != NULL)
920                         instance->SendChannelData(instance, lrdp_channel->channel_id, item->data, item->data_length);
921
922                 if (lchannel_data->open_event_proc != 0)
923                 {
924                         lchannel_data->open_event_proc(lchannel_data->open_handle,
925                                 CHANNEL_EVENT_WRITE_COMPLETE,
926                                 item->user_data, sizeof(void *), sizeof(void *), 0);
927                 }
928                 xfree(item);
929         }
930 }
931
932 /**
933  * called only from main thread
934  */
935 boolean freerdp_channels_get_fds(rdpChannels* channels, freerdp* instance, void** read_fds,
936         int* read_count, void** write_fds, int* write_count)
937 {
938         wait_obj_get_fds(channels->signal, read_fds, read_count);
939         return true;
940 }
941
942 /**
943  * called only from main thread
944  */
945 boolean freerdp_channels_check_fds(rdpChannels* channels, freerdp* instance)
946 {
947         if (wait_obj_is_set(channels->signal))
948         {
949                 wait_obj_clear(channels->signal);
950                 freerdp_channels_process_sync(channels, instance);
951         }
952
953         return true;
954 }
955
956 RDP_EVENT* freerdp_channels_pop_event(rdpChannels* channels)
957 {
958         RDP_EVENT* event;
959
960         if (channels->event == NULL)
961                 return NULL;
962
963         event = channels->event;
964         channels->event = NULL;
965
966         freerdp_sem_signal(channels->event_sem); /* release channels->event */
967
968         return event;
969 }
970
971 void freerdp_channels_close(rdpChannels* channels, freerdp* instance)
972 {
973         int index;
974         struct lib_data* llib;
975
976         DEBUG_CHANNELS("closing");
977         channels->is_connected = 0;
978         freerdp_channels_check_fds(channels, instance);
979
980         /* tell all libraries we are shutting down */
981         for (index = 0; index < channels->num_libs_data; index++)
982         {
983                 llib = channels->libs_data + index;
984
985                 if (llib->init_event_proc != 0)
986                         llib->init_event_proc(llib->init_handle, CHANNEL_EVENT_TERMINATED, 0, 0);
987         }
988 }