void freerdp_channels_free(rdpChannels * chan_man) { rdpChannelsList* list; rdpChannelsList* prev; freerdp_mutex_free(chan_man->sync_data_mutex); list_free(chan_man->sync_data_list); freerdp_sem_free(chan_man->event_sem); wait_obj_free(chan_man->signal); /* Remove from global list */ freerdp_mutex_lock(g_mutex_list); for (prev = NULL, list = g_channels_list; list; prev = list, list = list->next) { if (list->channels == chan_man) break; } if (list) { if (prev) prev->next = list->next; else g_channels_list = list->next; xfree(list); } freerdp_mutex_unlock(g_mutex_list); xfree(chan_man); }
/** * called only from main thread */ static void freerdp_channels_process_sync(rdpChannels* chan_man, freerdp* instance) { rdpChannel* lrdp_chan; struct sync_data* item; struct channel_data* lchan_data; while (chan_man->sync_data_list->head != NULL) { freerdp_mutex_lock(chan_man->sync_data_mutex); item = (struct sync_data*)list_dequeue(chan_man->sync_data_list); freerdp_mutex_unlock(chan_man->sync_data_mutex); lchan_data = chan_man->chans + item->index; lrdp_chan = freerdp_channels_find_channel_by_name(chan_man, instance->settings, lchan_data->name, &item->index); if (lrdp_chan != NULL) instance->SendChannelData(instance, lrdp_chan->channel_id, item->data, item->data_length); if (lchan_data->open_event_proc != 0) { lchan_data->open_event_proc(lchan_data->open_handle, CHANNEL_EVENT_WRITE_COMPLETE, item->user_data, sizeof(void *), sizeof(void *), 0); } xfree(item); } }
void svc_plugin_init(rdpSvcPlugin* plugin, CHANNEL_ENTRY_POINTS* pEntryPoints) { rdpSvcPluginList* list; /** * The channel manager will guarantee only one thread can call * VirtualChannelInit at a time. So this should be safe. */ if (g_mutex == NULL) g_mutex = freerdp_mutex_new(); memcpy(&plugin->channel_entry_points, pEntryPoints, pEntryPoints->cbSize); plugin->priv = xnew(rdpSvcPluginPrivate); /* Add it to the global list */ list = xnew(rdpSvcPluginList); list->plugin = plugin; freerdp_mutex_lock(g_mutex); list->next = g_svc_plugin_list; g_svc_plugin_list = list; freerdp_mutex_unlock(g_mutex); plugin->channel_entry_points.pVirtualChannelInit(&plugin->priv->init_handle, &plugin->channel_def, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, svc_plugin_init_event); }
boolean WTSVirtualChannelRead( /* __in */ void* hChannelHandle, /* __in */ uint32 TimeOut, /* __out */ uint8* Buffer, /* __in */ uint32 BufferSize, /* __out */ uint32* pBytesRead) { wts_data_item* item; rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle; item = (wts_data_item*) list_peek(channel->receive_queue); if (item == NULL) { wait_obj_clear(channel->receive_event); *pBytesRead = 0; return true; } *pBytesRead = item->length; if (item->length > BufferSize) return false; /* remove the first element (same as what we just peek) */ freerdp_mutex_lock(channel->mutex); list_dequeue(channel->receive_queue); if (list_size(channel->receive_queue) == 0) wait_obj_clear(channel->receive_event); freerdp_mutex_unlock(channel->mutex); memcpy(Buffer, item->buffer, item->length); wts_data_item_free(item) ; return true; }
void test_mutex(void) { freerdp_mutex mutex; mutex = freerdp_mutex_new(); freerdp_mutex_lock(mutex); freerdp_mutex_unlock(mutex); freerdp_mutex_free(mutex); }
/* can be called from any thread */ static uint32 FREERDP_CC MyVirtualChannelWrite(uint32 openHandle, void* pData, uint32 dataLength, void* pUserData) { rdpChannels* chan_man; struct channel_data* lchan; struct sync_data* item; int index; chan_man = freerdp_channels_find_by_open_handle(openHandle, &index); if ((chan_man == NULL) || (index < 0) || (index >= CHANNEL_MAX_COUNT)) { DEBUG_CHANNELS("error bad chanhan"); return CHANNEL_RC_BAD_CHANNEL_HANDLE; } if (!chan_man->is_connected) { DEBUG_CHANNELS("error not connected"); return CHANNEL_RC_NOT_CONNECTED; } if (pData == 0) { DEBUG_CHANNELS("error bad pData"); return CHANNEL_RC_NULL_DATA; } if (dataLength == 0) { DEBUG_CHANNELS("error bad dataLength"); return CHANNEL_RC_ZERO_LENGTH; } lchan = chan_man->chans + index; if (lchan->flags != 2) { DEBUG_CHANNELS("error not open"); return CHANNEL_RC_NOT_OPEN; } freerdp_mutex_lock(chan_man->sync_data_mutex); /* lock channels->sync* vars */ if (!chan_man->is_connected) { freerdp_mutex_unlock(chan_man->sync_data_mutex); DEBUG_CHANNELS("error not connected"); return CHANNEL_RC_NOT_CONNECTED; } item = xnew(struct sync_data); item->data = pData; item->data_length = dataLength; item->user_data = pUserData; item->index = index; list_enqueue(chan_man->sync_data_list, item); freerdp_mutex_unlock(chan_man->sync_data_mutex); /* set the event */ wait_obj_set(chan_man->signal); return CHANNEL_RC_OK; }
static void wts_queue_send_item(rdpPeerChannel* channel, wts_data_item* item) { WTSVirtualChannelManager* vcm; vcm = channel->vcm; item->channel_id = channel->channel_id; freerdp_mutex_lock(vcm->mutex); list_enqueue(vcm->send_queue, item); freerdp_mutex_unlock(vcm->mutex); wait_obj_set(vcm->send_event); }
boolean WTSVirtualChannelClose( /* __in */ void* hChannelHandle) { STREAM* s; wts_data_item* item; WTSVirtualChannelManager* vcm; rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle; if (channel) { vcm = channel->vcm; if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_SVC) { if (channel->index < channel->client->settings->num_channels) channel->client->settings->channels[channel->index].handle = NULL; } else { freerdp_mutex_lock(vcm->mutex); list_remove(vcm->dvc_channel_list, channel); freerdp_mutex_unlock(vcm->mutex); if (channel->dvc_open_state == DVC_OPEN_STATE_SUCCEEDED) { s = stream_new(8); wts_write_drdynvc_header(s, CLOSE_REQUEST_PDU, channel->channel_id); WTSVirtualChannelWrite(vcm->drdynvc_channel, stream_get_head(s), stream_get_length(s), NULL); stream_free(s); } } if (channel->receive_data) stream_free(channel->receive_data); if (channel->receive_event) wait_obj_free(channel->receive_event); if (channel->receive_queue) { while ((item = (wts_data_item*) list_dequeue(channel->receive_queue)) != NULL) { wts_data_item_free(item); } list_free(channel->receive_queue); } if (channel->mutex) freerdp_mutex_free(channel->mutex); xfree(channel); } return true; }
/** * this is called when processing the command line parameters * called only from main thread */ int freerdp_channels_load_plugin(rdpChannels* chan_man, rdpSettings* settings, const char* name, void* data) { struct lib_data* lib; CHANNEL_ENTRY_POINTS_EX ep; int ok; DEBUG_CHANNELS("%s", name); if (chan_man->num_libs + 1 >= CHANNEL_MAX_COUNT) { DEBUG_CHANNELS("too many channels"); return 1; } lib = chan_man->libs + chan_man->num_libs; lib->entry = (PVIRTUALCHANNELENTRY)freerdp_load_plugin(name, CHANNEL_EXPORT_FUNC_NAME); if (lib->entry == NULL) { DEBUG_CHANNELS("failed to find export function"); return 1; } ep.cbSize = sizeof(ep); ep.protocolVersion = VIRTUAL_CHANNEL_VERSION_WIN2000; ep.pVirtualChannelInit = MyVirtualChannelInit; ep.pVirtualChannelOpen = MyVirtualChannelOpen; ep.pVirtualChannelClose = MyVirtualChannelClose; ep.pVirtualChannelWrite = MyVirtualChannelWrite; ep.pExtendedData = data; ep.pVirtualChannelEventPush = MyVirtualChannelEventPush; /* enable MyVirtualChannelInit */ chan_man->can_call_init = 1; chan_man->settings = settings; freerdp_mutex_lock(g_mutex_init); g_init_chan_man = chan_man; ok = lib->entry((PCHANNEL_ENTRY_POINTS)&ep); g_init_chan_man = NULL; freerdp_mutex_unlock(g_mutex_init); /* disable MyVirtualChannelInit */ chan_man->settings = 0; chan_man->can_call_init = 0; if (!ok) { DEBUG_CHANNELS("export function call failed"); return 1; } return 0; }
static void wts_queue_receive_data(rdpPeerChannel* channel, const uint8* buffer, uint32 length) { wts_data_item* item; item = xnew(wts_data_item); item->length = length; item->buffer = xmalloc(length); memcpy(item->buffer, buffer, length); freerdp_mutex_lock(channel->mutex); list_enqueue(channel->receive_queue, item); freerdp_mutex_unlock(channel->mutex); wait_obj_set(channel->receive_event); }
static void scard_irp_request(DEVICE* device, IRP* irp) { COMPLETIONIDINFO* CompletionIdInfo; SCARD_DEVICE* scard = (SCARD_DEVICE*)device; /* Begin TS Client defect workaround. */ CompletionIdInfo= xnew(COMPLETIONIDINFO); CompletionIdInfo->ID = irp->CompletionId;/* "duplicate" member is set * to false by "xnew()" */ freerdp_mutex_lock(scard->CompletionIdsMutex); scard_mark_duplicate_id(scard, irp->CompletionId); list_enqueue(scard->CompletionIds, CompletionIdInfo); freerdp_mutex_unlock(scard->CompletionIdsMutex); irp->Complete = scard_irp_complete; /* Overwrite the previous * assignment made in * "irp_new()". */ /* End TS Client defect workaround. */ if (irp->MajorFunction == IRP_MJ_DEVICE_CONTROL && scard_async_op(irp)) { /* * certain potentially long running operations * get their own thread * TODO: revise this mechanism.. maybe worker pool */ struct scard_irp_thread_args *args = xmalloc(sizeof(struct scard_irp_thread_args)); args->thread = freerdp_thread_new(); args->scard = scard; args->irp = irp; freerdp_thread_start(args->thread, scard_process_irp_thread_func, args); return; } freerdp_thread_lock(scard->thread); list_enqueue(scard->irp_list, irp); freerdp_thread_unlock(scard->thread); freerdp_thread_signal(scard->thread); }
/** * go through and inform all the libraries that we are initialized * called only from main thread */ int freerdp_channels_pre_connect(rdpChannels* chan_man, freerdp* instance) { int index; struct lib_data* llib; CHANNEL_DEF lchannel_def; void* dummy; DEBUG_CHANNELS("enter"); chan_man->instance = instance; /** * If rdpsnd is registered but not rdpdr, it's necessary to register a fake * rdpdr channel to make sound work. This is a workaround for Window 7 and * Windows 2008 */ if (freerdp_channels_find_channel_data_by_name(chan_man, "rdpsnd", 0) != 0 && freerdp_channels_find_channel_data_by_name(chan_man, "rdpdr", 0) == 0) { lchannel_def.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP; strcpy(lchannel_def.name, "rdpdr"); chan_man->can_call_init = 1; chan_man->settings = instance->settings; freerdp_mutex_lock(g_mutex_init); g_init_chan_man = chan_man; MyVirtualChannelInit(&dummy, &lchannel_def, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, 0); g_init_chan_man = NULL; freerdp_mutex_unlock(g_mutex_init); chan_man->can_call_init = 0; chan_man->settings = 0; DEBUG_CHANNELS("registered fake rdpdr for rdpsnd."); } for (index = 0; index < chan_man->num_libs; index++) { llib = chan_man->libs + index; if (llib->init_event_proc != 0) { llib->init_event_proc(llib->init_handle, CHANNEL_EVENT_INITIALIZED, 0, 0); } } return 0; }
/* returns the chan_man for the rdp instance passed in */ static rdpChannels* freerdp_channels_find_by_instance(freerdp* instance) { rdpChannelsList* list; rdpChannels* chan_man; freerdp_mutex_lock(g_mutex_list); for (list = g_channels_list; list; list = list->next) { chan_man = list->channels; if (chan_man->instance == instance) { freerdp_mutex_unlock(g_mutex_list); return chan_man; } } freerdp_mutex_unlock(g_mutex_list); return NULL; }
/* returns the chan_man for the rdp instance passed in */ static rdpChanMan* freerdp_chanman_find_by_rdp_inst(freerdp* instance) { rdpChanManList* list; rdpChanMan* chan_man; freerdp_mutex_lock(g_mutex_list); for (list = g_chan_man_list; list; list = list->next) { chan_man = list->chan_man; if (chan_man->instance == instance) { freerdp_mutex_unlock(g_mutex_list); return chan_man; } } freerdp_mutex_unlock(g_mutex_list); return NULL; }
static rdpSvcPlugin* svc_plugin_find_by_open_handle(uint32 open_handle) { rdpSvcPluginList * list; rdpSvcPlugin * plugin; freerdp_mutex_lock(g_mutex); for (list = g_svc_plugin_list; list; list = list->next) { plugin = list->plugin; if (plugin->priv->open_handle == open_handle) { freerdp_mutex_unlock(g_mutex); return plugin; } } freerdp_mutex_unlock(g_mutex); return NULL; }
boolean WTSVirtualChannelWrite( /* __in */ void* hChannelHandle, /* __in */ uint8* Buffer, /* __in */ uint32 Length, /* __out */ uint32* pBytesWritten) { uint32 written = 0; wts_data_item* item; boolean result = false; rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle; WTSVirtualChannelManager* vcm ; if (channel == NULL) return false; vcm = channel->vcm ; if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_SVC) { item = xnew(wts_data_item); item->channel_id = channel->channel_id; item->buffer = xmalloc(Length); item->length = Length; memcpy(item->buffer, Buffer, Length); freerdp_mutex_lock(vcm->mutex); list_enqueue(vcm->send_queue, item); freerdp_mutex_unlock(vcm->mutex); wait_obj_set(vcm->send_event); written = Length; result = true; } else { /* TODO: Send to DVC channel */ } if (pBytesWritten != NULL) *pBytesWritten = written; return result; }
static void scard_irp_complete(IRP* irp) { /* This function is (mostly) a copy of the statically-declared "irp_complete()" * function except that this function adds extra operations for the * smart card's handling of duplicate "CompletionID"s. This function needs * to be in this file so that "scard_irp_request()" can reference it. */ int pos; boolean duplicate; SCARD_DEVICE* scard = (SCARD_DEVICE*)irp->device; DEBUG_SVC("DeviceId %d FileId %d CompletionId %d", irp->device->id, irp->FileId, irp->CompletionId); pos = stream_get_pos(irp->output); stream_set_pos(irp->output, 12); stream_write_uint32(irp->output, irp->IoStatus); stream_set_pos(irp->output, pos); /* Begin TS Client defect workaround. */ freerdp_mutex_lock(scard->CompletionIdsMutex); /* Remove from the list the item identified by the CompletionID. * The function returns whether or not it was a duplicate CompletionID. */ duplicate = scard_check_for_duplicate_id(scard, irp->CompletionId); freerdp_mutex_unlock(scard->CompletionIdsMutex); if (false == duplicate) { svc_plugin_send(irp->devman->plugin, irp->output); irp->output = NULL; } /* End TS Client defect workaround. */ /* irp_free(irp); The "irp_free()" function is statically-declared * and so is not available to be called * here. Instead, call it indirectly by calling * the IRP's "Discard()" function, * which has already been assigned * to point to "irp_free()" in "irp_new()". */ irp->Discard(irp); }
rdpChanMan* freerdp_chanman_new(void) { rdpChanMan* chan_man; rdpChanManList* list; chan_man = xnew(rdpChanMan); chan_man->sync_data_sem = freerdp_sem_new(1); chan_man->event_sem = freerdp_sem_new(1); chan_man->signal = wait_obj_new(); /* Add it to the global list */ list = xnew(rdpChanManList); list->chan_man = chan_man; freerdp_mutex_lock(g_mutex_list); list->next = g_chan_man_list; g_chan_man_list = list; freerdp_mutex_unlock(g_mutex_list); return chan_man; }
static void svc_plugin_remove(rdpSvcPlugin* plugin) { rdpSvcPluginList* list; rdpSvcPluginList* prev; /* Remove from global list */ freerdp_mutex_lock(g_mutex); for (prev = NULL, list = g_svc_plugin_list; list; prev = list, list = list->next) { if (list->plugin == plugin) break; } if (list) { if (prev) prev->next = list->next; else g_svc_plugin_list = list->next; xfree(list); } freerdp_mutex_unlock(g_mutex); }
boolean WTSVirtualChannelManagerCheckFileDescriptor(WTSVirtualChannelManager* vcm) { boolean result = true; wts_data_item* item; wait_obj_clear(vcm->send_event); freerdp_mutex_lock(vcm->mutex); while ((item = (wts_data_item*) list_dequeue(vcm->send_queue)) != NULL) { if (vcm->client->SendChannelData(vcm->client, item->channel_id, item->buffer, item->length) == false) { result = false; } wts_data_item_free(item); if (result == false) break; } freerdp_mutex_unlock(vcm->mutex); return result; }
boolean WTSVirtualChannelManagerCheckFileDescriptor(WTSVirtualChannelManager* vcm) { boolean result = true; wts_data_item* item; rdpPeerChannel* channel; uint32 dynvc_caps; if (vcm->drdynvc_state == DRDYNVC_STATE_NONE && vcm->client->activated) { /* Initialize drdynvc channel once and only once. */ vcm->drdynvc_state = DRDYNVC_STATE_INITIALIZED; channel = WTSVirtualChannelOpenEx(vcm, "drdynvc", 0); if (channel) { vcm->drdynvc_channel = channel; dynvc_caps = 0x00010050; /* DYNVC_CAPS_VERSION1 (4 bytes) */ WTSVirtualChannelWrite(channel, (uint8*) &dynvc_caps, sizeof(dynvc_caps), NULL); } } wait_obj_clear(vcm->send_event); freerdp_mutex_lock(vcm->mutex); while ((item = (wts_data_item*) list_dequeue(vcm->send_queue)) != NULL) { if (vcm->client->SendChannelData(vcm->client, item->channel_id, item->buffer, item->length) == false) { result = false; } wts_data_item_free(item); if (result == false) break; } freerdp_mutex_unlock(vcm->mutex); return result; }
static void WTSProcessChannelData(rdpPeerChannel* channel, int channelId, uint8* data, int size, int flags, int total_size) { wts_data_item* item; if (flags & CHANNEL_FLAG_FIRST) { stream_set_pos(channel->receive_data, 0); } stream_check_size(channel->receive_data, size); stream_write(channel->receive_data, data, size); if (flags & CHANNEL_FLAG_LAST) { if (stream_get_length(channel->receive_data) != total_size) { printf("WTSProcessChannelData: read error\n"); } if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_DVC) { /* TODO: Receive DVC channel data */ } else { item = xnew(wts_data_item); item->length = stream_get_length(channel->receive_data); item->buffer = xmalloc(item->length); memcpy(item->buffer, stream_get_head(channel->receive_data), item->length); freerdp_mutex_lock(channel->mutex); list_enqueue(channel->receive_queue, item); freerdp_mutex_unlock(channel->mutex); wait_obj_set(channel->receive_event); } stream_set_pos(channel->receive_data, 0); } }
/* returns the chan_man for the open handle passed in */ static rdpChannels* freerdp_channels_find_by_open_handle(int open_handle, int* pindex) { rdpChannelsList* list; rdpChannels* chan_man; int lindex; freerdp_mutex_lock(g_mutex_list); for (list = g_channels_list; list; list = list->next) { chan_man = list->channels; for (lindex = 0; lindex < chan_man->num_chans; lindex++) { if (chan_man->chans[lindex].open_handle == open_handle) { freerdp_mutex_unlock(g_mutex_list); *pindex = lindex; return chan_man; } } } freerdp_mutex_unlock(g_mutex_list); return NULL; }
/** * must be called by same thread that calls freerdp_chanman_load_plugin * according to MS docs * only called from main thread */ static uint32 FREERDP_CC MyVirtualChannelInit(void** ppInitHandle, PCHANNEL_DEF pChannel, int channelCount, uint32 versionRequested, PCHANNEL_INIT_EVENT_FN pChannelInitEventProc) { rdpChannels* chan_man; int index; struct lib_data* llib; struct channel_data* lchan; rdpChannel* lrdp_chan; PCHANNEL_DEF lchan_def; chan_man = g_init_chan_man; chan_man->init_handles[chan_man->num_init_handles].chan_man = chan_man; *ppInitHandle = &chan_man->init_handles[chan_man->num_init_handles]; chan_man->num_init_handles++; DEBUG_CHANNELS("enter"); if (!chan_man->can_call_init) { DEBUG_CHANNELS("error not in entry"); return CHANNEL_RC_NOT_IN_VIRTUALCHANNELENTRY; } if (ppInitHandle == 0) { DEBUG_CHANNELS("error bad pphan"); return CHANNEL_RC_BAD_INIT_HANDLE; } if (chan_man->num_chans + channelCount >= CHANNEL_MAX_COUNT) { DEBUG_CHANNELS("error too many channels"); return CHANNEL_RC_TOO_MANY_CHANNELS; } if (pChannel == 0) { DEBUG_CHANNELS("error bad pchan"); return CHANNEL_RC_BAD_CHANNEL; } if (chan_man->is_connected) { DEBUG_CHANNELS("error already connected"); return CHANNEL_RC_ALREADY_CONNECTED; } if (versionRequested != VIRTUAL_CHANNEL_VERSION_WIN2000) { DEBUG_CHANNELS("warning version"); } for (index = 0; index < channelCount; index++) { lchan_def = pChannel + index; if (freerdp_channels_find_channel_data_by_name(chan_man, lchan_def->name, 0) != 0) { DEBUG_CHANNELS("error channel already used"); return CHANNEL_RC_BAD_CHANNEL; } } llib = chan_man->libs + chan_man->num_libs; llib->init_event_proc = pChannelInitEventProc; llib->init_handle = *ppInitHandle; chan_man->num_libs++; for (index = 0; index < channelCount; index++) { lchan_def = pChannel + index; lchan = chan_man->chans + chan_man->num_chans; freerdp_mutex_lock(g_mutex_list); lchan->open_handle = g_open_handle_sequence++; freerdp_mutex_unlock(g_mutex_list); lchan->flags = 1; /* init */ strncpy(lchan->name, lchan_def->name, CHANNEL_NAME_LEN); lchan->options = lchan_def->options; if (chan_man->settings->num_channels < 16) { lrdp_chan = chan_man->settings->channels + chan_man->settings->num_channels; strncpy(lrdp_chan->name, lchan_def->name, 7); lrdp_chan->options = lchan_def->options; chan_man->settings->num_channels++; } else { DEBUG_CHANNELS("warning more than 16 channels"); } chan_man->num_chans++; } return CHANNEL_RC_OK; }
void* WTSVirtualChannelOpenEx( /* __in */ WTSVirtualChannelManager* vcm, /* __in */ const char* pVirtualName, /* __in */ uint32 flags) { int i; int len; rdpPeerChannel* channel; freerdp_peer* client = vcm->client; STREAM* s; if ((flags & WTS_CHANNEL_OPTION_DYNAMIC) != 0) { if (vcm->drdynvc_channel == NULL || vcm->drdynvc_state != DRDYNVC_STATE_READY) { DEBUG_DVC("Dynamic virtual channel not ready."); return NULL; } channel = xnew(rdpPeerChannel); channel->vcm = vcm; channel->client = client; channel->channel_type = RDP_PEER_CHANNEL_TYPE_DVC; channel->receive_data = stream_new(client->settings->vc_chunk_size); channel->receive_event = wait_obj_new(); channel->receive_queue = list_new(); channel->mutex = freerdp_mutex_new(); freerdp_mutex_lock(vcm->mutex); channel->channel_id = vcm->dvc_channel_id_seq++; list_enqueue(vcm->dvc_channel_list, channel); freerdp_mutex_unlock(vcm->mutex); s = stream_new(64); wts_write_drdynvc_create_request(s, channel->channel_id, pVirtualName); WTSVirtualChannelWrite(vcm->drdynvc_channel, stream_get_head(s), stream_get_length(s), NULL); stream_free(s); DEBUG_DVC("ChannelId %d.%s (total %d)", channel->channel_id, pVirtualName, list_size(vcm->dvc_channel_list)); } else { len = strlen(pVirtualName); if (len > 8) return NULL; for (i = 0; i < client->settings->num_channels; i++) { if (client->settings->channels[i].joined && strncmp(client->settings->channels[i].name, pVirtualName, len) == 0) { break; } } if (i >= client->settings->num_channels) return NULL; channel = (rdpPeerChannel*) client->settings->channels[i].handle; if (channel == NULL) { channel = xnew(rdpPeerChannel); channel->vcm = vcm; channel->client = client; channel->channel_id = client->settings->channels[i].channel_id; channel->index = i; channel->channel_type = RDP_PEER_CHANNEL_TYPE_SVC; channel->receive_data = stream_new(client->settings->vc_chunk_size); channel->receive_event = wait_obj_new(); channel->receive_queue = list_new(); channel->mutex = freerdp_mutex_new(); client->settings->channels[i].handle = channel; } } return channel; }