2 * FreeRDP: A Remote Desktop Protocol client.
3 * Virtual Channel Manager
5 * Copyright 2009-2011 Jay Sorg
6 * Copyright 2010-2011 Vic Lee
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 * MS compatible plugin interface
24 * http://msdn.microsoft.com/en-us/library/aa383580.aspx
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.
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>
50 #include "libchannels.h"
52 #define CHANNEL_MAX_COUNT 30
56 PVIRTUALCHANNELENTRY entry; /* the one and only exported function */
57 PCHANNEL_INIT_EVENT_FN init_event_proc;
63 char name[CHANNEL_NAME_LEN + 1];
66 int flags; /* 0 nothing 1 init 2 open */
67 PCHANNEL_OPEN_EVENT_FN open_event_proc;
78 typedef struct rdp_init_handle rdpInitHandle;
79 struct rdp_init_handle
81 rdpChannels* chan_man;
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
92 * ie, no two threads can access index 0, ...
94 struct lib_data libs[CHANNEL_MAX_COUNT];
96 struct channel_data chans[CHANNEL_MAX_COUNT];
98 rdpInitHandle init_handles[CHANNEL_MAX_COUNT];
101 /* control for entry into MyVirtualChannelInit */
103 rdpSettings* settings;
105 /* true once freerdp_chanman_post_connect is called */
108 /* used for locating the chan_man for a given instance */
111 /* signal for incoming data or event */
112 struct wait_obj* signal;
114 /* used for sync write */
115 freerdp_mutex sync_data_mutex;
116 LIST* sync_data_list;
118 /* used for sync event */
119 freerdp_sem event_sem;
124 * The current channel manager reference passes from VirtualChannelEntry to
125 * VirtualChannelInit for the pInitHandle.
127 static rdpChannels* g_init_chan_man;
129 /* The list of all channel managers. */
130 typedef struct rdp_channels_list rdpChannelsList;
131 struct rdp_channels_list
133 rdpChannels* channels;
134 rdpChannelsList* next;
137 static rdpChannelsList* g_channels_list;
139 /* To generate unique sequence for all open handles */
140 static int g_open_handle_sequence;
142 /* For locking the global resources */
143 static freerdp_mutex g_mutex_init;
144 static freerdp_mutex g_mutex_list;
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)
149 rdpChannelsList* list;
150 rdpChannels* chan_man;
153 freerdp_mutex_lock(g_mutex_list);
154 for (list = g_channels_list; list; list = list->next)
156 chan_man = list->channels;
157 for (lindex = 0; lindex < chan_man->num_chans; lindex++)
159 if (chan_man->chans[lindex].open_handle == open_handle)
161 freerdp_mutex_unlock(g_mutex_list);
167 freerdp_mutex_unlock(g_mutex_list);
171 /* returns the chan_man for the rdp instance passed in */
172 static rdpChannels* freerdp_channels_find_by_instance(freerdp* instance)
174 rdpChannelsList* list;
175 rdpChannels* chan_man;
177 freerdp_mutex_lock(g_mutex_list);
178 for (list = g_channels_list; list; list = list->next)
180 chan_man = list->channels;
181 if (chan_man->instance == instance)
183 freerdp_mutex_unlock(g_mutex_list);
187 freerdp_mutex_unlock(g_mutex_list);
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)
196 struct channel_data* lchan_data;
198 for (lindex = 0; lindex < chan_man->num_chans; lindex++)
200 lchan_data = chan_man->chans + lindex;
201 if (strcmp(chan_name, lchan_data->name) == 0)
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)
219 rdpChannel* lrdp_chan;
221 lcount = settings->num_channels;
222 for (lindex = 0; lindex < lcount; lindex++)
224 lrdp_chan = settings->channels + lindex;
225 if (lrdp_chan->channel_id == channel_id)
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)
242 rdpChannel* lrdp_chan;
244 lcount = settings->num_channels;
245 for (lindex = 0; lindex < lcount; lindex++)
247 lrdp_chan = settings->channels + lindex;
248 if (strcmp(chan_name, lrdp_chan->name) == 0)
260 * must be called by same thread that calls freerdp_chanman_load_plugin
261 * according to MS docs
262 * only called from main thread
264 static uint32 FREERDP_CC MyVirtualChannelInit(void** ppInitHandle, PCHANNEL_DEF pChannel,
265 int channelCount, uint32 versionRequested,
266 PCHANNEL_INIT_EVENT_FN pChannelInitEventProc)
268 rdpChannels* chan_man;
270 struct lib_data* llib;
271 struct channel_data* lchan;
272 rdpChannel* lrdp_chan;
273 PCHANNEL_DEF lchan_def;
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++;
280 DEBUG_CHANNELS("enter");
281 if (!chan_man->can_call_init)
283 DEBUG_CHANNELS("error not in entry");
284 return CHANNEL_RC_NOT_IN_VIRTUALCHANNELENTRY;
286 if (ppInitHandle == 0)
288 DEBUG_CHANNELS("error bad pphan");
289 return CHANNEL_RC_BAD_INIT_HANDLE;
291 if (chan_man->num_chans + channelCount >= CHANNEL_MAX_COUNT)
293 DEBUG_CHANNELS("error too many channels");
294 return CHANNEL_RC_TOO_MANY_CHANNELS;
298 DEBUG_CHANNELS("error bad pchan");
299 return CHANNEL_RC_BAD_CHANNEL;
301 if (chan_man->is_connected)
303 DEBUG_CHANNELS("error already connected");
304 return CHANNEL_RC_ALREADY_CONNECTED;
306 if (versionRequested != VIRTUAL_CHANNEL_VERSION_WIN2000)
308 DEBUG_CHANNELS("warning version");
310 for (index = 0; index < channelCount; index++)
312 lchan_def = pChannel + index;
313 if (freerdp_channels_find_channel_data_by_name(chan_man, lchan_def->name, 0) != 0)
315 DEBUG_CHANNELS("error channel already used");
316 return CHANNEL_RC_BAD_CHANNEL;
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++)
325 lchan_def = pChannel + index;
326 lchan = chan_man->chans + chan_man->num_chans;
328 freerdp_mutex_lock(g_mutex_list);
329 lchan->open_handle = g_open_handle_sequence++;
330 freerdp_mutex_unlock(g_mutex_list);
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)
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++;
344 DEBUG_CHANNELS("warning more than 16 channels");
346 chan_man->num_chans++;
348 return CHANNEL_RC_OK;
352 * can be called from any thread
353 * thread safe because no 2 threads can have the same channel name registered
355 static uint32 FREERDP_CC MyVirtualChannelOpen(void* pInitHandle, uint32* pOpenHandle,
356 char* pChannelName, PCHANNEL_OPEN_EVENT_FN pChannelOpenEventProc)
358 rdpChannels* chan_man;
360 struct channel_data* lchan;
362 DEBUG_CHANNELS("enter");
363 chan_man = ((rdpInitHandle*)pInitHandle)->chan_man;
364 if (pOpenHandle == 0)
366 DEBUG_CHANNELS("error bad chanhan");
367 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
369 if (pChannelOpenEventProc == 0)
371 DEBUG_CHANNELS("error bad proc");
372 return CHANNEL_RC_BAD_PROC;
374 if (!chan_man->is_connected)
376 DEBUG_CHANNELS("error not connected");
377 return CHANNEL_RC_NOT_CONNECTED;
379 lchan = freerdp_channels_find_channel_data_by_name(chan_man, pChannelName, &index);
382 DEBUG_CHANNELS("error chan name");
383 return CHANNEL_RC_UNKNOWN_CHANNEL_NAME;
385 if (lchan->flags == 2)
387 DEBUG_CHANNELS("error chan already open");
388 return CHANNEL_RC_ALREADY_OPEN;
391 lchan->flags = 2; /* open */
392 lchan->open_event_proc = pChannelOpenEventProc;
393 *pOpenHandle = lchan->open_handle;
394 return CHANNEL_RC_OK;
398 * can be called from any thread
399 * thread safe because no 2 threads can have the same openHandle
401 static uint32 FREERDP_CC MyVirtualChannelClose(uint32 openHandle)
403 rdpChannels* chan_man;
404 struct channel_data* lchan;
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))
411 DEBUG_CHANNELS("error bad chanhan");
412 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
414 lchan = chan_man->chans + index;
415 if (lchan->flags != 2)
417 DEBUG_CHANNELS("error not open");
418 return CHANNEL_RC_NOT_OPEN;
421 return CHANNEL_RC_OK;
424 /* can be called from any thread */
425 static uint32 FREERDP_CC MyVirtualChannelWrite(uint32 openHandle, void* pData, uint32 dataLength,
428 rdpChannels* chan_man;
429 struct channel_data* lchan;
430 struct sync_data* item;
433 chan_man = freerdp_channels_find_by_open_handle(openHandle, &index);
434 if ((chan_man == NULL) || (index < 0) || (index >= CHANNEL_MAX_COUNT))
436 DEBUG_CHANNELS("error bad chanhan");
437 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
439 if (!chan_man->is_connected)
441 DEBUG_CHANNELS("error not connected");
442 return CHANNEL_RC_NOT_CONNECTED;
446 DEBUG_CHANNELS("error bad pData");
447 return CHANNEL_RC_NULL_DATA;
451 DEBUG_CHANNELS("error bad dataLength");
452 return CHANNEL_RC_ZERO_LENGTH;
454 lchan = chan_man->chans + index;
455 if (lchan->flags != 2)
457 DEBUG_CHANNELS("error not open");
458 return CHANNEL_RC_NOT_OPEN;
460 freerdp_mutex_lock(chan_man->sync_data_mutex); /* lock channels->sync* vars */
461 if (!chan_man->is_connected)
463 freerdp_mutex_unlock(chan_man->sync_data_mutex);
464 DEBUG_CHANNELS("error not connected");
465 return CHANNEL_RC_NOT_CONNECTED;
467 item = xnew(struct sync_data);
469 item->data_length = dataLength;
470 item->user_data = pUserData;
472 list_enqueue(chan_man->sync_data_list, item);
473 freerdp_mutex_unlock(chan_man->sync_data_mutex);
476 wait_obj_set(chan_man->signal);
478 return CHANNEL_RC_OK;
481 static uint32 FREERDP_CC MyVirtualChannelEventPush(uint32 openHandle, RDP_EVENT* event)
483 rdpChannels* chan_man;
484 struct channel_data* lchan;
487 chan_man = freerdp_channels_find_by_open_handle(openHandle, &index);
488 if ((chan_man == NULL) || (index < 0) || (index >= CHANNEL_MAX_COUNT))
490 DEBUG_CHANNELS("error bad chanhan");
491 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
493 if (!chan_man->is_connected)
495 DEBUG_CHANNELS("error not connected");
496 return CHANNEL_RC_NOT_CONNECTED;
500 DEBUG_CHANNELS("error bad event");
501 return CHANNEL_RC_NULL_DATA;
503 lchan = chan_man->chans + index;
504 if (lchan->flags != 2)
506 DEBUG_CHANNELS("error not open");
507 return CHANNEL_RC_NOT_OPEN;
509 freerdp_sem_wait(chan_man->event_sem); /* lock channels->event */
510 if (!chan_man->is_connected)
512 freerdp_sem_signal(chan_man->event_sem);
513 DEBUG_CHANNELS("error not connected");
514 return CHANNEL_RC_NOT_CONNECTED;
516 chan_man->event = event;
518 wait_obj_set(chan_man->signal);
519 return CHANNEL_RC_OK;
523 * this is called shortly after the application starts and
524 * before any other function in the file
525 * called only from main thread
527 int freerdp_channels_global_init(void)
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();
538 int freerdp_channels_global_uninit(void)
540 while (g_channels_list)
541 freerdp_channels_free(g_channels_list->channels);
543 freerdp_mutex_free(g_mutex_init);
544 freerdp_mutex_free(g_mutex_list);
549 rdpChannels* freerdp_channels_new(void)
551 rdpChannels* chan_man;
552 rdpChannelsList* list;
554 chan_man = xnew(rdpChannels);
556 chan_man->sync_data_mutex = freerdp_mutex_new();
557 chan_man->sync_data_list = list_new();
559 chan_man->event_sem = freerdp_sem_new(1);
560 chan_man->signal = wait_obj_new();
562 /* Add it to the global list */
563 list = xnew(rdpChannelsList);
564 list->channels = chan_man;
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);
574 void freerdp_channels_free(rdpChannels * chan_man)
576 rdpChannelsList* list;
577 rdpChannelsList* prev;
579 freerdp_mutex_free(chan_man->sync_data_mutex);
580 list_free(chan_man->sync_data_list);
582 freerdp_sem_free(chan_man->event_sem);
583 wait_obj_free(chan_man->signal);
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)
589 if (list->channels == chan_man)
595 prev->next = list->next;
597 g_channels_list = list->next;
600 freerdp_mutex_unlock(g_mutex_list);
606 * this is called when processing the command line parameters
607 * called only from main thread
609 int freerdp_channels_load_plugin(rdpChannels* chan_man, rdpSettings* settings,
610 const char* name, void* data)
612 struct lib_data* lib;
613 CHANNEL_ENTRY_POINTS_EX ep;
616 DEBUG_CHANNELS("%s", name);
617 if (chan_man->num_libs + 1 >= CHANNEL_MAX_COUNT)
619 DEBUG_CHANNELS("too many channels");
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)
626 DEBUG_CHANNELS("failed to find export function");
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;
638 /* enable MyVirtualChannelInit */
639 chan_man->can_call_init = 1;
640 chan_man->settings = settings;
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);
648 /* disable MyVirtualChannelInit */
649 chan_man->settings = 0;
650 chan_man->can_call_init = 0;
653 DEBUG_CHANNELS("export function call failed");
660 * go through and inform all the libraries that we are initialized
661 * called only from main thread
663 int freerdp_channels_pre_connect(rdpChannels* chan_man, freerdp* instance)
666 struct lib_data* llib;
667 CHANNEL_DEF lchannel_def;
670 DEBUG_CHANNELS("enter");
671 chan_man->instance = instance;
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
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)
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.");
697 for (index = 0; index < chan_man->num_libs; index++)
699 llib = chan_man->libs + index;
700 if (llib->init_event_proc != 0)
702 llib->init_event_proc(llib->init_handle, CHANNEL_EVENT_INITIALIZED,
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
714 int freerdp_channels_post_connect(rdpChannels* chan_man, freerdp* instance)
717 struct lib_data* llib;
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++)
728 llib = chan_man->libs + index;
729 if (llib->init_event_proc != 0)
731 llib->init_event_proc(llib->init_handle, CHANNEL_EVENT_CONNECTED,
732 hostname, hostname_len);
739 * data comming from the server to the client
740 * called only from main thread
742 int freerdp_channels_data(freerdp* instance, int channel_id, void* data, int data_size,
743 int flags, int total_size)
745 rdpChannels* chan_man;
746 rdpChannel* lrdp_chan;
747 struct channel_data* lchan_data;
750 chan_man = freerdp_channels_find_by_instance(instance);
753 DEBUG_CHANNELS("could not find channel manager");
757 lrdp_chan = freerdp_channels_find_channel_by_id(chan_man, instance->settings,
761 DEBUG_CHANNELS("could not find channel id");
764 lchan_data = freerdp_channels_find_channel_data_by_name(chan_man, lrdp_chan->name,
768 DEBUG_CHANNELS("could not find channel name");
771 if (lchan_data->open_event_proc != 0)
773 lchan_data->open_event_proc(lchan_data->open_handle,
774 CHANNEL_EVENT_DATA_RECEIVED,
775 data, data_size, total_size, flags);
780 static const char* event_class_to_name_table[] =
782 "rdpdbg", /* RDP_EVENT_CLASS_DEBUG */
783 "cliprdr", /* RDP_EVENT_CLASS_CLIPRDR */
784 "tsmf", /* RDP_EVENT_CLASS_TSMF */
785 "rail", /* RDP_EVENT_CLASS_RAIL */
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()
795 FREERDP_API int freerdp_channels_send_event(rdpChannels* chan_man, RDP_EVENT* event)
797 struct channel_data* lchan_data;
801 name = event_class_to_name_table[event->event_class];
804 DEBUG_CHANNELS("unknown event_class %d", event->event_class);
808 lchan_data = freerdp_channels_find_channel_data_by_name(chan_man, name, &index);
809 if (lchan_data == NULL)
811 DEBUG_CHANNELS("could not find channel name %s", name);
814 if (lchan_data->open_event_proc != NULL)
816 lchan_data->open_event_proc(lchan_data->open_handle,
818 event, sizeof(RDP_EVENT), sizeof(RDP_EVENT), 0);
824 * called only from main thread
826 static void freerdp_channels_process_sync(rdpChannels* chan_man, freerdp* instance)
828 struct channel_data* lchan_data;
829 rdpChannel* lrdp_chan;
830 struct sync_data* item;
832 while (chan_man->sync_data_list->head != NULL)
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);
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)
843 IFCALL(instance->SendChannelData, instance, lrdp_chan->channel_id, item->data, item->data_length);
845 if (lchan_data->open_event_proc != 0)
847 lchan_data->open_event_proc(lchan_data->open_handle,
848 CHANNEL_EVENT_WRITE_COMPLETE,
849 item->user_data, sizeof(void *), sizeof(void *), 0);
856 * called only from main thread
858 boolean freerdp_channels_get_fds(rdpChannels* chan_man, freerdp* instance, void** read_fds,
859 int* read_count, void** write_fds, int* write_count)
861 wait_obj_get_fds(chan_man->signal, read_fds, read_count);
866 * called only from main thread
868 boolean freerdp_channels_check_fds(rdpChannels * chan_man, freerdp* instance)
870 if (wait_obj_is_set(chan_man->signal))
872 wait_obj_clear(chan_man->signal);
873 freerdp_channels_process_sync(chan_man, instance);
879 RDP_EVENT* freerdp_channels_pop_event(rdpChannels* chan_man)
883 if (chan_man->event == NULL)
886 event = chan_man->event;
887 chan_man->event = NULL;
889 freerdp_sem_signal(chan_man->event_sem); /* release channels->event */
894 void freerdp_channels_close(rdpChannels* chan_man, freerdp* instance)
897 struct lib_data* llib;
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++)
905 llib = chan_man->libs + index;
906 if (llib->init_event_proc != 0)
908 llib->init_event_proc(llib->init_handle, CHANNEL_EVENT_TERMINATED,