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