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>
49 #include <freerdp/utils/event.h>
51 #include "libchannels.h"
53 #define CHANNEL_MAX_COUNT 30
57 PVIRTUALCHANNELENTRY entry; /* the one and only exported function */
58 PCHANNEL_INIT_EVENT_FN init_event_proc;
64 char name[CHANNEL_NAME_LEN + 1];
67 int flags; /* 0 nothing 1 init 2 open */
68 PCHANNEL_OPEN_EVENT_FN open_event_proc;
79 typedef struct rdp_init_handle rdpInitHandle;
80 struct rdp_init_handle
82 rdpChannels* channels;
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
93 * ie, no two threads can access index 0, ...
96 struct lib_data libs_data[CHANNEL_MAX_COUNT];
99 struct channel_data channels_data[CHANNEL_MAX_COUNT];
100 int num_channels_data;
102 rdpInitHandle init_handles[CHANNEL_MAX_COUNT];
103 int num_init_handles;
105 /* control for entry into MyVirtualChannelInit */
107 rdpSettings* settings;
109 /* true once freerdp_chanman_post_connect is called */
112 /* used for locating the channels for a given instance */
115 /* signal for incoming data or event */
116 struct wait_obj* signal;
118 /* used for sync write */
119 freerdp_mutex sync_data_mutex;
120 LIST* sync_data_list;
122 /* used for sync event */
123 freerdp_sem event_sem;
128 * The current channel manager reference passes from VirtualChannelEntry to
129 * VirtualChannelInit for the pInitHandle.
131 static rdpChannels* g_init_channels;
133 /* The list of all channel managers. */
134 typedef struct rdp_channels_list rdpChannelsList;
135 struct rdp_channels_list
137 rdpChannels* channels;
138 rdpChannelsList* next;
141 static rdpChannelsList* g_channels_list;
143 /* To generate unique sequence for all open handles */
144 static int g_open_handle_sequence;
146 /* For locking the global resources */
147 static freerdp_mutex g_mutex_init;
148 static freerdp_mutex g_mutex_list;
150 /* returns the channels for the open handle passed in */
151 static rdpChannels* freerdp_channels_find_by_open_handle(int open_handle, int* pindex)
154 rdpChannels* channels;
155 rdpChannelsList* channels_list;
157 freerdp_mutex_lock(g_mutex_list);
159 for (channels_list = g_channels_list; channels_list; channels_list = channels_list->next)
161 channels = channels_list->channels;
163 for (lindex = 0; lindex < channels->num_channels_data; lindex++)
165 if (channels->channels_data[lindex].open_handle == open_handle)
167 freerdp_mutex_unlock(g_mutex_list);
174 freerdp_mutex_unlock(g_mutex_list);
179 /* returns the channels for the rdp instance passed in */
180 static rdpChannels* freerdp_channels_find_by_instance(freerdp* instance)
182 rdpChannels* channels;
183 rdpChannelsList* channels_list;
185 freerdp_mutex_lock(g_mutex_list);
187 for (channels_list = g_channels_list; channels_list; channels_list = channels_list->next)
189 channels = channels_list->channels;
190 if (channels->instance == instance)
192 freerdp_mutex_unlock(g_mutex_list);
197 freerdp_mutex_unlock(g_mutex_list);
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)
206 struct channel_data* lchannel_data;
208 for (lindex = 0; lindex < channels->num_channels_data; lindex++)
210 lchannel_data = channels->channels_data + lindex;
212 if (strcmp(channel_name, lchannel_data->name) == 0)
217 return lchannel_data;
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)
229 rdpChannel* lrdp_channel;
231 lcount = settings->num_channels;
233 for (lindex = 0; lindex < lcount; lindex++)
235 lrdp_channel = settings->channels + lindex;
237 if (lrdp_channel->channel_id == channel_id)
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)
255 rdpChannel* lrdp_channel;
257 lcount = settings->num_channels;
259 for (lindex = 0; lindex < lcount; lindex++)
261 lrdp_channel = settings->channels + lindex;
263 if (strcmp(channel_name, lrdp_channel->name) == 0)
276 * must be called by same thread that calls freerdp_chanman_load_plugin
277 * according to MS docs
278 * only called from main thread
280 static uint32 FREERDP_CC MyVirtualChannelInit(void** ppInitHandle, PCHANNEL_DEF pChannel,
281 int channelCount, uint32 versionRequested, PCHANNEL_INIT_EVENT_FN pChannelInitEventProc)
284 rdpChannels* channels;
285 struct lib_data* llib;
286 rdpChannel* lrdp_channel;
287 PCHANNEL_DEF lchannel_def;
288 struct channel_data* lchannel_data;
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++;
295 DEBUG_CHANNELS("enter");
297 if (!channels->can_call_init)
299 DEBUG_CHANNELS("error not in entry");
300 return CHANNEL_RC_NOT_IN_VIRTUALCHANNELENTRY;
303 if (ppInitHandle == 0)
305 DEBUG_CHANNELS("error bad pphan");
306 return CHANNEL_RC_BAD_INIT_HANDLE;
309 if (channels->num_channels_data + channelCount >= CHANNEL_MAX_COUNT)
311 DEBUG_CHANNELS("error too many channels");
312 return CHANNEL_RC_TOO_MANY_CHANNELS;
317 DEBUG_CHANNELS("error bad pchan");
318 return CHANNEL_RC_BAD_CHANNEL;
321 if (channels->is_connected)
323 DEBUG_CHANNELS("error already connected");
324 return CHANNEL_RC_ALREADY_CONNECTED;
327 if (versionRequested != VIRTUAL_CHANNEL_VERSION_WIN2000)
329 DEBUG_CHANNELS("warning version");
332 for (index = 0; index < channelCount; index++)
334 lchannel_def = pChannel + index;
335 if (freerdp_channels_find_channel_data_by_name(channels, lchannel_def->name, 0) != 0)
337 DEBUG_CHANNELS("error channel already used");
338 return CHANNEL_RC_BAD_CHANNEL;
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++;
347 for (index = 0; index < channelCount; index++)
349 lchannel_def = pChannel + index;
350 lchannel_data = channels->channels_data + channels->num_channels_data;
352 freerdp_mutex_lock(g_mutex_list);
353 lchannel_data->open_handle = g_open_handle_sequence++;
354 freerdp_mutex_unlock(g_mutex_list);
356 lchannel_data->flags = 1; /* init */
357 strncpy(lchannel_data->name, lchannel_def->name, CHANNEL_NAME_LEN);
358 lchannel_data->options = lchannel_def->options;
360 if (channels->settings->num_channels < 16)
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++;
369 DEBUG_CHANNELS("warning more than 16 channels");
372 channels->num_channels_data++;
375 return CHANNEL_RC_OK;
379 * can be called from any thread
380 * thread safe because no 2 threads can have the same channel name registered
382 static uint32 FREERDP_CC MyVirtualChannelOpen(void* pInitHandle, uint32* pOpenHandle,
383 char* pChannelName, PCHANNEL_OPEN_EVENT_FN pChannelOpenEventProc)
386 rdpChannels* channels;
387 struct channel_data* lchannel_data;
389 DEBUG_CHANNELS("enter");
391 channels = ((rdpInitHandle*) pInitHandle)->channels;
393 if (pOpenHandle == 0)
395 DEBUG_CHANNELS("error bad chanhan");
396 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
399 if (pChannelOpenEventProc == 0)
401 DEBUG_CHANNELS("error bad proc");
402 return CHANNEL_RC_BAD_PROC;
405 if (!channels->is_connected)
407 DEBUG_CHANNELS("error not connected");
408 return CHANNEL_RC_NOT_CONNECTED;
411 lchannel_data = freerdp_channels_find_channel_data_by_name(channels, pChannelName, &index);
413 if (lchannel_data == 0)
415 DEBUG_CHANNELS("error chan name");
416 return CHANNEL_RC_UNKNOWN_CHANNEL_NAME;
419 if (lchannel_data->flags == 2)
421 DEBUG_CHANNELS("error chan already open");
422 return CHANNEL_RC_ALREADY_OPEN;
425 lchannel_data->flags = 2; /* open */
426 lchannel_data->open_event_proc = pChannelOpenEventProc;
427 *pOpenHandle = lchannel_data->open_handle;
429 return CHANNEL_RC_OK;
433 * can be called from any thread
434 * thread safe because no 2 threads can have the same openHandle
436 static uint32 FREERDP_CC MyVirtualChannelClose(uint32 openHandle)
439 rdpChannels* channels;
440 struct channel_data* lchannel_data;
442 DEBUG_CHANNELS("enter");
444 channels = freerdp_channels_find_by_open_handle(openHandle, &index);
446 if ((channels == NULL) || (index < 0) || (index >= CHANNEL_MAX_COUNT))
448 DEBUG_CHANNELS("error bad channels");
449 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
452 lchannel_data = channels->channels_data + index;
454 if (lchannel_data->flags != 2)
456 DEBUG_CHANNELS("error not open");
457 return CHANNEL_RC_NOT_OPEN;
460 lchannel_data->flags = 0;
462 return CHANNEL_RC_OK;
465 /* can be called from any thread */
466 static uint32 FREERDP_CC MyVirtualChannelWrite(uint32 openHandle, void* pData, uint32 dataLength, void* pUserData)
469 rdpChannels* channels;
470 struct sync_data* item;
471 struct channel_data* lchannel_data;
473 channels = freerdp_channels_find_by_open_handle(openHandle, &index);
475 if ((channels == NULL) || (index < 0) || (index >= CHANNEL_MAX_COUNT))
477 DEBUG_CHANNELS("error bad chanhan");
478 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
481 if (!channels->is_connected)
483 DEBUG_CHANNELS("error not connected");
484 return CHANNEL_RC_NOT_CONNECTED;
489 DEBUG_CHANNELS("error bad pData");
490 return CHANNEL_RC_NULL_DATA;
495 DEBUG_CHANNELS("error bad dataLength");
496 return CHANNEL_RC_ZERO_LENGTH;
499 lchannel_data = channels->channels_data + index;
501 if (lchannel_data->flags != 2)
503 DEBUG_CHANNELS("error not open");
504 return CHANNEL_RC_NOT_OPEN;
507 freerdp_mutex_lock(channels->sync_data_mutex); /* lock channels->sync* vars */
509 if (!channels->is_connected)
511 freerdp_mutex_unlock(channels->sync_data_mutex);
512 DEBUG_CHANNELS("error not connected");
513 return CHANNEL_RC_NOT_CONNECTED;
516 item = xnew(struct sync_data);
518 item->data_length = dataLength;
519 item->user_data = pUserData;
521 list_enqueue(channels->sync_data_list, item);
522 freerdp_mutex_unlock(channels->sync_data_mutex);
525 wait_obj_set(channels->signal);
527 return CHANNEL_RC_OK;
530 static uint32 FREERDP_CC MyVirtualChannelEventPush(uint32 openHandle, RDP_EVENT* event)
533 rdpChannels* channels;
534 struct channel_data* lchannel_data;
536 channels = freerdp_channels_find_by_open_handle(openHandle, &index);
538 if ((channels == NULL) || (index < 0) || (index >= CHANNEL_MAX_COUNT))
540 DEBUG_CHANNELS("error bad chanhan");
541 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
544 if (!channels->is_connected)
546 DEBUG_CHANNELS("error not connected");
547 return CHANNEL_RC_NOT_CONNECTED;
552 DEBUG_CHANNELS("error bad event");
553 return CHANNEL_RC_NULL_DATA;
556 lchannel_data = channels->channels_data + index;
558 if (lchannel_data->flags != 2)
560 DEBUG_CHANNELS("error not open");
561 return CHANNEL_RC_NOT_OPEN;
564 freerdp_sem_wait(channels->event_sem); /* lock channels->event */
566 if (!channels->is_connected)
568 freerdp_sem_signal(channels->event_sem);
569 DEBUG_CHANNELS("error not connected");
570 return CHANNEL_RC_NOT_CONNECTED;
573 channels->event = event;
575 wait_obj_set(channels->signal);
577 return CHANNEL_RC_OK;
581 * this is called shortly after the application starts and
582 * before any other function in the file
583 * called only from main thread
585 int freerdp_channels_global_init(void)
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();
596 int freerdp_channels_global_uninit(void)
598 while (g_channels_list)
599 freerdp_channels_free(g_channels_list->channels);
601 freerdp_mutex_free(g_mutex_init);
602 freerdp_mutex_free(g_mutex_list);
607 rdpChannels* freerdp_channels_new(void)
609 rdpChannels* channels;
610 rdpChannelsList* channels_list;
612 channels = xnew(rdpChannels);
614 channels->sync_data_mutex = freerdp_mutex_new();
615 channels->sync_data_list = list_new();
617 channels->event_sem = freerdp_sem_new(1);
618 channels->signal = wait_obj_new();
620 /* Add it to the global list */
621 channels_list = xnew(rdpChannelsList);
622 channels_list->channels = channels;
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);
632 void freerdp_channels_free(rdpChannels* channels)
634 rdpChannelsList* list;
635 rdpChannelsList* prev;
637 freerdp_mutex_free(channels->sync_data_mutex);
638 list_free(channels->sync_data_list);
640 freerdp_sem_free(channels->event_sem);
641 wait_obj_free(channels->signal);
643 /* Remove from global list */
645 freerdp_mutex_lock(g_mutex_list);
647 for (prev = NULL, list = g_channels_list; list; prev = list, list = list->next)
649 if (list->channels == channels)
656 prev->next = list->next;
658 g_channels_list = list->next;
662 freerdp_mutex_unlock(g_mutex_list);
668 * this is called when processing the command line parameters
669 * called only from main thread
671 int freerdp_channels_load_plugin(rdpChannels* channels, rdpSettings* settings, const char* name, void* data)
674 struct lib_data* lib;
675 CHANNEL_ENTRY_POINTS_EX ep;
677 DEBUG_CHANNELS("%s", name);
679 if (channels->num_libs_data + 1 >= CHANNEL_MAX_COUNT)
681 DEBUG_CHANNELS("too many channels");
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);
689 if (lib->entry == NULL)
691 DEBUG_CHANNELS("failed to find export function");
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;
704 /* enable MyVirtualChannelInit */
705 channels->can_call_init = 1;
706 channels->settings = settings;
708 freerdp_mutex_lock(g_mutex_init);
710 g_init_channels = channels;
711 ok = lib->entry((PCHANNEL_ENTRY_POINTS) &ep);
712 g_init_channels = NULL;
714 freerdp_mutex_unlock(g_mutex_init);
716 /* disable MyVirtualChannelInit */
717 channels->settings = 0;
718 channels->can_call_init = 0;
722 DEBUG_CHANNELS("export function call failed");
730 * go through and inform all the libraries that we are initialized
731 * called only from main thread
733 int freerdp_channels_pre_connect(rdpChannels* channels, freerdp* instance)
737 struct lib_data* llib;
738 CHANNEL_DEF lchannel_def;
740 DEBUG_CHANNELS("enter");
741 channels->instance = instance;
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
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)
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.");
767 for (index = 0; index < channels->num_libs_data; index++)
769 llib = channels->libs_data + index;
771 if (llib->init_event_proc != 0)
772 llib->init_event_proc(llib->init_handle, CHANNEL_EVENT_INITIALIZED, 0, 0);
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
783 int freerdp_channels_post_connect(rdpChannels* channels, freerdp* instance)
788 struct lib_data* llib;
790 channels->is_connected = 1;
791 hostname = instance->settings->hostname;
792 hostname_len = strlen(hostname);
794 DEBUG_CHANNELS("hostname [%s] channels->num_libs [%d]", hostname, channels->num_libs_data);
796 for (index = 0; index < channels->num_libs_data; index++)
798 llib = channels->libs_data + index;
800 if (llib->init_event_proc != 0)
801 llib->init_event_proc(llib->init_handle, CHANNEL_EVENT_CONNECTED, hostname, hostname_len);
808 * data comming from the server to the client
809 * called only from main thread
811 int freerdp_channels_data(freerdp* instance, int channel_id, void* data, int data_size, int flags, int total_size)
814 rdpChannels* channels;
815 rdpChannel* lrdp_channel;
816 struct channel_data* lchannel_data;
818 channels = freerdp_channels_find_by_instance(instance);
822 DEBUG_CHANNELS("could not find channel manager");
826 lrdp_channel = freerdp_channels_find_channel_by_id(channels, instance->settings,
828 if (lrdp_channel == 0)
830 DEBUG_CHANNELS("could not find channel id");
834 lchannel_data = freerdp_channels_find_channel_data_by_name(channels, lrdp_channel->name, &index);
836 if (lchannel_data == 0)
838 DEBUG_CHANNELS("could not find channel name");
842 if (lchannel_data->open_event_proc != 0)
844 lchannel_data->open_event_proc(lchannel_data->open_handle,
845 CHANNEL_EVENT_DATA_RECEIVED, data, data_size, total_size, flags);
851 static const char* event_class_to_name_table[] =
853 "rdpdbg", /* RDP_EVENT_CLASS_DEBUG */
854 "cliprdr", /* RDP_EVENT_CLASS_CLIPRDR */
855 "tsmf", /* RDP_EVENT_CLASS_TSMF */
856 "rail", /* RDP_EVENT_CLASS_RAIL */
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()
866 FREERDP_API int freerdp_channels_send_event(rdpChannels* channels, RDP_EVENT* event)
870 struct channel_data* lchannel_data;
872 name = event_class_to_name_table[event->event_class];
876 DEBUG_CHANNELS("unknown event_class %d", event->event_class);
877 freerdp_event_free(event);
881 lchannel_data = freerdp_channels_find_channel_data_by_name(channels, name, &index);
883 if (lchannel_data == NULL)
885 DEBUG_CHANNELS("could not find channel name %s", name);
886 freerdp_event_free(event);
890 if (lchannel_data->open_event_proc != NULL)
892 lchannel_data->open_event_proc(lchannel_data->open_handle,
894 event, sizeof(RDP_EVENT), sizeof(RDP_EVENT), 0);
901 * called only from main thread
903 static void freerdp_channels_process_sync(rdpChannels* channels, freerdp* instance)
905 struct sync_data* item;
906 rdpChannel* lrdp_channel;
907 struct channel_data* lchannel_data;
909 while (channels->sync_data_list->head != NULL)
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);
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);
919 if (lrdp_channel != NULL)
920 instance->SendChannelData(instance, lrdp_channel->channel_id, item->data, item->data_length);
922 if (lchannel_data->open_event_proc != 0)
924 lchannel_data->open_event_proc(lchannel_data->open_handle,
925 CHANNEL_EVENT_WRITE_COMPLETE,
926 item->user_data, sizeof(void *), sizeof(void *), 0);
933 * called only from main thread
935 boolean freerdp_channels_get_fds(rdpChannels* channels, freerdp* instance, void** read_fds,
936 int* read_count, void** write_fds, int* write_count)
938 wait_obj_get_fds(channels->signal, read_fds, read_count);
943 * called only from main thread
945 boolean freerdp_channels_check_fds(rdpChannels* channels, freerdp* instance)
947 if (wait_obj_is_set(channels->signal))
949 wait_obj_clear(channels->signal);
950 freerdp_channels_process_sync(channels, instance);
956 RDP_EVENT* freerdp_channels_pop_event(rdpChannels* channels)
960 if (channels->event == NULL)
963 event = channels->event;
964 channels->event = NULL;
966 freerdp_sem_signal(channels->event_sem); /* release channels->event */
971 void freerdp_channels_close(rdpChannels* channels, freerdp* instance)
974 struct lib_data* llib;
976 DEBUG_CHANNELS("closing");
977 channels->is_connected = 0;
978 freerdp_channels_check_fds(channels, instance);
980 /* tell all libraries we are shutting down */
981 for (index = 0; index < channels->num_libs_data; index++)
983 llib = channels->libs_data + index;
985 if (llib->init_event_proc != 0)
986 llib->init_event_proc(llib->init_handle, CHANNEL_EVENT_TERMINATED, 0, 0);