/** * Send a plugin-defined event to the plugin. * called only from main thread * @param chan_man the channel manager instance * @param event an event object created by freerdp_event_new() */ FREERDP_API int freerdp_chanman_send_event(rdpChanMan* chan_man, RDP_EVENT* event) { struct chan_data* lchan_data; int index; const char* name; name = event_class_to_name_table[event->event_class]; if (name == NULL) { DEBUG_CHANMAN("unknown event_class %d", event->event_class); return 1; } lchan_data = freerdp_chanman_find_chan_data_by_name(chan_man, name, &index); if (lchan_data == NULL) { DEBUG_CHANMAN("could not find channel name %s", name); return 1; } if (lchan_data->open_event_proc != NULL) { lchan_data->open_event_proc(lchan_data->open_handle, CHANNEL_EVENT_USER, event, sizeof(RDP_EVENT), sizeof(RDP_EVENT), 0); } return 0; }
/* can be called from any thread thread safe because no 2 threads can have the same openHandle */ static uint32 VCHAN_CC MyVirtualChannelClose(uint32 openHandle) { rdpChanMan * chan_man; struct chan_data * lchan; int index; chan_man = freerdp_chanman_find_by_open_handle(openHandle, &index); if ((chan_man == NULL) || (index < 0) || (index >= CHANNEL_MAX_COUNT)) { DEBUG_CHANMAN("MyVirtualChannelClose: error bad chanhan\n"); return CHANNEL_RC_BAD_CHANNEL_HANDLE; } if (!chan_man->is_connected) { DEBUG_CHANMAN("MyVirtualChannelClose: error not connected\n"); return CHANNEL_RC_NOT_CONNECTED; } lchan = chan_man->chans + index; if (lchan->flags != 2) { DEBUG_CHANMAN("MyVirtualChannelClose: error not open\n"); return CHANNEL_RC_NOT_OPEN; } lchan->flags = 0; return CHANNEL_RC_OK; }
/** * this is called when processing the command line parameters * called only from main thread */ int freerdp_chanman_load_plugin(rdpChanMan* chan_man, rdpSettings* settings, const char* name, void* data) { struct lib_data* lib; CHANNEL_ENTRY_POINTS_EX ep; int ok; DEBUG_CHANMAN("%s", name); if (chan_man->num_libs + 1 >= CHANNEL_MAX_COUNT) { DEBUG_CHANMAN("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_CHANMAN("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_CHANMAN("export function call failed"); return 1; } return 0; }
rdpChanMan * freerdp_chanman_new(void) { rdpChanMan * chan_man; rdpChanManList * list; chan_man = (rdpChanMan *) malloc(sizeof(rdpChanMan)); memset(chan_man, 0, sizeof(rdpChanMan)); SEMAPHORE_INIT(chan_man->sem, 0, 1); /* start at 1 */ SEMAPHORE_INIT(chan_man->sem_event, 0, 1); /* start at 1 */ #ifdef _WIN32 chan_man->chan_event = CreateEvent(NULL, TRUE, FALSE, NULL); #else chan_man->pipe_fd[0] = -1; chan_man->pipe_fd[1] = -1; if (pipe(chan_man->pipe_fd) < 0) { DEBUG_CHANMAN("freerdp_chanman_init: pipe failed"); } #endif /* Add it to the global list */ list = (rdpChanManList *) malloc(sizeof(rdpChanManList)); list->chan_man = chan_man; MUTEX_LOCK(g_mutex_list); list->next = g_chan_man_list; g_chan_man_list = list; MUTEX_UNLOCK(g_mutex_list); return chan_man; }
/** * go through and inform all the libraries that we are initialized * called only from main thread */ int freerdp_chanman_pre_connect(rdpChanMan* chan_man, freerdp* instance) { int index; struct lib_data* llib; CHANNEL_DEF lchannel_def; void* dummy; DEBUG_CHANMAN("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_chanman_find_chan_data_by_name(chan_man, "rdpsnd", 0) != 0 && freerdp_chanman_find_chan_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_CHANMAN("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; }
static uint32 VCHAN_CC MyVirtualChannelEventPush(uint32 openHandle, RD_EVENT * event) { rdpChanMan * chan_man; struct chan_data * lchan; int index; chan_man = freerdp_chanman_find_by_open_handle(openHandle, &index); if ((chan_man == NULL) || (index < 0) || (index >= CHANNEL_MAX_COUNT)) { DEBUG_CHANMAN("MyVirtualChannelEventPush: error bad chanhan"); return CHANNEL_RC_BAD_CHANNEL_HANDLE; } if (!chan_man->is_connected) { DEBUG_CHANMAN("MyVirtualChannelEventPush: error not connected"); return CHANNEL_RC_NOT_CONNECTED; } if (event == NULL) { DEBUG_CHANMAN("MyVirtualChannelEventPush: error bad event"); return CHANNEL_RC_NULL_DATA; } lchan = chan_man->chans + index; if (lchan->flags != 2) { DEBUG_CHANMAN("MyVirtualChannelEventPush: error not open"); return CHANNEL_RC_NOT_OPEN; } SEMAPHORE_WAIT(chan_man->sem_event); /* lock chan_man->event */ if (!chan_man->is_connected) { SEMAPHORE_POST(chan_man->sem_event); DEBUG_CHANMAN("MyVirtualChannelEventPush: error not connected"); return CHANNEL_RC_NOT_CONNECTED; } chan_man->event = event; /* set the event */ freerdp_chanman_set_ev(chan_man); return CHANNEL_RC_OK; }
static uint32 FREERDP_CC MyVirtualChannelEventPush(uint32 openHandle, RDP_EVENT* event) { rdpChanMan* chan_man; struct chan_data* lchan; int index; chan_man = freerdp_chanman_find_by_open_handle(openHandle, &index); if ((chan_man == NULL) || (index < 0) || (index >= CHANNEL_MAX_COUNT)) { DEBUG_CHANMAN("error bad chanhan"); return CHANNEL_RC_BAD_CHANNEL_HANDLE; } if (!chan_man->is_connected) { DEBUG_CHANMAN("error not connected"); return CHANNEL_RC_NOT_CONNECTED; } if (event == NULL) { DEBUG_CHANMAN("error bad event"); return CHANNEL_RC_NULL_DATA; } lchan = chan_man->chans + index; if (lchan->flags != 2) { DEBUG_CHANMAN("error not open"); return CHANNEL_RC_NOT_OPEN; } freerdp_sem_wait(chan_man->event_sem); /* lock chan_man->event */ if (!chan_man->is_connected) { freerdp_sem_signal(chan_man->event_sem); DEBUG_CHANMAN("error not connected"); return CHANNEL_RC_NOT_CONNECTED; } chan_man->event = event; /* set the event */ wait_obj_set(chan_man->signal); return CHANNEL_RC_OK; }
/** * can be called from any thread * thread safe because no 2 threads can have the same openHandle */ static uint32 FREERDP_CC MyVirtualChannelClose(uint32 openHandle) { rdpChanMan* chan_man; struct chan_data* lchan; int index; DEBUG_CHANMAN("enter"); chan_man = freerdp_chanman_find_by_open_handle(openHandle, &index); if ((chan_man == NULL) || (index < 0) || (index >= CHANNEL_MAX_COUNT)) { DEBUG_CHANMAN("error bad chanhan"); return CHANNEL_RC_BAD_CHANNEL_HANDLE; } lchan = chan_man->chans + index; if (lchan->flags != 2) { DEBUG_CHANMAN("error not open"); return CHANNEL_RC_NOT_OPEN; } lchan->flags = 0; return CHANNEL_RC_OK; }
/* data comming from the server to the client called only from main thread */ int freerdp_chanman_data(rdpInst * inst, int chan_id, char * data, int data_size, int flags, int total_size) { rdpChanMan * chan_man; struct rdp_chan * lrdp_chan; struct chan_data * lchan_data; int index; chan_man = freerdp_chanman_find_by_rdp_inst(inst); if (chan_man == 0) { DEBUG_CHANMAN("freerdp_chanman_data: could not find channel manager"); return 1; } lrdp_chan = freerdp_chanman_find_rdp_chan_by_id(chan_man, inst->settings, chan_id, &index); if (lrdp_chan == 0) { DEBUG_CHANMAN("freerdp_chanman_data: could not find channel id"); return 1; } lchan_data = freerdp_chanman_find_chan_data_by_name(chan_man, lrdp_chan->name, &index); if (lchan_data == 0) { DEBUG_CHANMAN("freerdp_chanman_data: could not find channel name"); return 1; } if (lchan_data->open_event_proc != 0) { lchan_data->open_event_proc(lchan_data->open_handle, CHANNEL_EVENT_DATA_RECEIVED, data, data_size, total_size, flags); } return 0; }
/* can be called from any thread */ static uint32 FREERDP_CC MyVirtualChannelWrite(uint32 openHandle, void* pData, uint32 dataLength, void* pUserData) { rdpChanMan* chan_man; struct chan_data* lchan; struct sync_data* item; int index; chan_man = freerdp_chanman_find_by_open_handle(openHandle, &index); if ((chan_man == NULL) || (index < 0) || (index >= CHANNEL_MAX_COUNT)) { DEBUG_CHANMAN("error bad chanhan"); return CHANNEL_RC_BAD_CHANNEL_HANDLE; } if (!chan_man->is_connected) { DEBUG_CHANMAN("error not connected"); return CHANNEL_RC_NOT_CONNECTED; } if (pData == 0) { DEBUG_CHANMAN("error bad pData"); return CHANNEL_RC_NULL_DATA; } if (dataLength == 0) { DEBUG_CHANMAN("error bad dataLength"); return CHANNEL_RC_ZERO_LENGTH; } lchan = chan_man->chans + index; if (lchan->flags != 2) { DEBUG_CHANMAN("error not open"); return CHANNEL_RC_NOT_OPEN; } freerdp_mutex_lock(chan_man->sync_data_mutex); /* lock chan_man->sync* vars */ if (!chan_man->is_connected) { freerdp_mutex_unlock(chan_man->sync_data_mutex); DEBUG_CHANMAN("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 freerdp_chanman_clear_ev(rdpChanMan * chan_man) { #ifdef _WIN32 ResetEvent(chan_man->chan_event); #else int len; while (freerdp_chanman_is_ev_set(chan_man)) { len = read(chan_man->pipe_fd[0], &len, 4); if (len != 4) { DEBUG_CHANMAN("freerdp_chanman_clear_ev: error"); } } #endif }
static void freerdp_chanman_set_ev(rdpChanMan * chan_man) { #ifdef _WIN32 SetEvent(chan_man->chan_event); #else int len; if (freerdp_chanman_is_ev_set(chan_man)) { return; } len = write(chan_man->pipe_fd[1], "sig", 4); if (len != 4) { DEBUG_CHANMAN("freerdp_chanman_set_ev: error\n"); } #endif }
void freerdp_chanman_close(rdpChanMan* chan_man, freerdp* instance) { int index; struct lib_data* llib; DEBUG_CHANMAN("closing"); chan_man->is_connected = 0; freerdp_chanman_check_fds(chan_man, instance); /* tell all libraries we are shutting down */ 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_TERMINATED, 0, 0); } } }
/** * Send a plugin-defined event to the plugin. * called only from main thread * @param chan_man the channel manager instance * @param name the static virtual channel name, such as 'cliprdr' * @param event an event object created by freerdp_event_new() */ FREERDP_API int freerdp_chanman_send_event(rdpChanMan* chan_man, const char* name, FRDP_EVENT* event) { struct chan_data* lchan_data; int index; lchan_data = freerdp_chanman_find_chan_data_by_name(chan_man, name, &index); if (lchan_data == NULL) { DEBUG_CHANMAN("could not find channel name %s", name); return 1; } if (lchan_data->open_event_proc != NULL) { lchan_data->open_event_proc(lchan_data->open_handle, CHANNEL_EVENT_USER, event, sizeof(FRDP_EVENT), sizeof(FRDP_EVENT), 0); } return 0; }
/* can be called from any thread */ static uint32 VCHAN_CC MyVirtualChannelWrite(uint32 openHandle, void * pData, uint32 dataLength, void * pUserData) { rdpChanMan * chan_man; struct chan_data * lchan; int index; chan_man = freerdp_chanman_find_by_open_handle(openHandle, &index); if ((chan_man == NULL) || (index < 0) || (index >= CHANNEL_MAX_COUNT)) { DEBUG_CHANMAN("MyVirtualChannelWrite: error bad chanhan"); return CHANNEL_RC_BAD_CHANNEL_HANDLE; } if (!chan_man->is_connected) { DEBUG_CHANMAN("MyVirtualChannelWrite: error not connected"); return CHANNEL_RC_NOT_CONNECTED; } if (pData == 0) { DEBUG_CHANMAN("MyVirtualChannelWrite: error bad pData"); return CHANNEL_RC_NULL_DATA; } if (dataLength == 0) { DEBUG_CHANMAN("MyVirtualChannelWrite: error bad dataLength"); return CHANNEL_RC_ZERO_LENGTH; } lchan = chan_man->chans + index; if (lchan->flags != 2) { DEBUG_CHANMAN("MyVirtualChannelWrite: error not open"); return CHANNEL_RC_NOT_OPEN; } SEMAPHORE_WAIT(chan_man->sem); /* lock chan_man->sync* vars */ if (!chan_man->is_connected) { SEMAPHORE_POST(chan_man->sem); DEBUG_CHANMAN("MyVirtualChannelWrite: error not connected"); return CHANNEL_RC_NOT_CONNECTED; } chan_man->sync_data = pData; chan_man->sync_data_length = dataLength; chan_man->sync_user_data = pUserData; chan_man->sync_index = index; /* set the event */ freerdp_chanman_set_ev(chan_man); return CHANNEL_RC_OK; }
/** * go through and inform all the libraries that we are connected * this will tell the libraries that its ok to call MyVirtualChannelOpen * called only from main thread */ int freerdp_chanman_post_connect(rdpChanMan* chan_man, freerdp* instance) { int index; struct lib_data* llib; char* hostname; int hostname_len; chan_man->is_connected = 1; hostname = instance->settings->hostname; hostname_len = strlen(hostname); DEBUG_CHANMAN("hostname [%s] chan_man->num_libs [%d]", hostname, chan_man->num_libs); 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_CONNECTED, hostname, hostname_len); } } return 0; }
/* go through and inform all the libraries that we are connected this will tell the libraries that its ok to call MyVirtualChannelOpen called only from main thread */ int freerdp_chanman_post_connect(rdpChanMan * chan_man, rdpInst * inst) { int index; int server_name_len; struct lib_data * llib; char * server_name; chan_man->is_connected = 1; server_name = inst->settings->server; server_name_len = strlen(server_name); DEBUG_CHANMAN("freerdp_chanman_post_connect: server name [%s] chan_man->num_libs [%d]", server_name, chan_man->num_libs); 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_CONNECTED, server_name, server_name_len); } } return 0; }
/* can be called from any thread thread safe because no 2 threads can have the same channel name registered */ static uint32 VCHAN_CC MyVirtualChannelOpen(void * pInitHandle, uint32 * pOpenHandle, char * pChannelName, PCHANNEL_OPEN_EVENT_FN pChannelOpenEventProc) { rdpChanMan * chan_man; int index; struct chan_data * lchan; DEBUG_CHANMAN("MyVirtualChannelOpen:"); chan_man = ((rdpInitHandle *) pInitHandle)->chan_man; if (pOpenHandle == 0) { DEBUG_CHANMAN("MyVirtualChannelOpen: error bad chanhan"); return CHANNEL_RC_BAD_CHANNEL_HANDLE; } if (pChannelOpenEventProc == 0) { DEBUG_CHANMAN("MyVirtualChannelOpen: error bad proc"); return CHANNEL_RC_BAD_PROC; } if (!chan_man->is_connected) { DEBUG_CHANMAN("MyVirtualChannelOpen: error not connected"); return CHANNEL_RC_NOT_CONNECTED; } lchan = freerdp_chanman_find_chan_data_by_name(chan_man, pChannelName, &index); if (lchan == 0) { DEBUG_CHANMAN("MyVirtualChannelOpen: error chan name"); return CHANNEL_RC_UNKNOWN_CHANNEL_NAME; } if (lchan->flags == 2) { DEBUG_CHANMAN("MyVirtualChannelOpen: error chan already open\n"); return CHANNEL_RC_ALREADY_OPEN; } lchan->flags = 2; /* open */ lchan->open_event_proc = pChannelOpenEventProc; *pOpenHandle = lchan->open_handle; return CHANNEL_RC_OK; }
/* this is called when processing the command line parameters called only from main thread */ int freerdp_chanman_load_plugin(rdpChanMan * chan_man, rdpSet * settings, const char * filename, void * data) { struct lib_data * lib; CHANNEL_ENTRY_POINTS_EX ep; int ok; CHR path[255]; DEBUG_CHANMAN("input filename %s", filename); if (chan_man->num_libs + 1 >= CHANNEL_MAX_COUNT) { DEBUG_CHANMAN("freerdp_chanman_load_plugin: too many channels"); return 1; } lib = chan_man->libs + chan_man->num_libs; if (strchr(filename, PATH_SEPARATOR) == NULL) { #ifdef _WIN32 swprintf(path, sizeof(path), L"./%S." PLUGIN_EXT, filename); #else snprintf(path, sizeof(path), PLUGIN_PATH "/%s." PLUGIN_EXT, filename); #endif } else { #ifdef _WIN32 swprintf(path, sizeof(path), L"%S", filename); #else strncpy(path, filename, sizeof(path)); #endif } DEBUG_CHANMAN("freerdp_chanman_load_plugin %s: %s", filename, path); lib->han = DLOPEN(path); if (lib->han == 0) { DEBUG_CHANMAN("freerdp_chanman_load_plugin: failed to load library"); return 1; } lib->entry = (PVIRTUALCHANNELENTRY) DLSYM(lib->han, CHANNEL_EXPORT_FUNC_NAME); if (lib->entry == 0) { DEBUG_CHANMAN("freerdp_chanman_load_plugin: failed to find export function"); DLCLOSE(lib->han); 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; MUTEX_LOCK(g_mutex_init); g_init_chan_man = chan_man; ok = lib->entry((PCHANNEL_ENTRY_POINTS)&ep); g_init_chan_man = NULL; MUTEX_UNLOCK(g_mutex_init); /* disable MyVirtualChannelInit */ chan_man->settings = 0; chan_man->can_call_init = 0; if (!ok) { DEBUG_CHANMAN("freerdp_chanman_load_plugin: export function call failed"); DLCLOSE(lib->han); return 1; } return 0; }
/** * 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) { rdpChanMan* chan_man; int index; struct lib_data* llib; struct chan_data* lchan; rdpChan* 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_CHANMAN("enter"); if (!chan_man->can_call_init) { DEBUG_CHANMAN("error not in entry"); return CHANNEL_RC_NOT_IN_VIRTUALCHANNELENTRY; } if (ppInitHandle == 0) { DEBUG_CHANMAN("error bad pphan"); return CHANNEL_RC_BAD_INIT_HANDLE; } if (chan_man->num_chans + channelCount >= CHANNEL_MAX_COUNT) { DEBUG_CHANMAN("error too many channels"); return CHANNEL_RC_TOO_MANY_CHANNELS; } if (pChannel == 0) { DEBUG_CHANMAN("error bad pchan"); return CHANNEL_RC_BAD_CHANNEL; } if (chan_man->is_connected) { DEBUG_CHANMAN("error already connected"); return CHANNEL_RC_ALREADY_CONNECTED; } if (versionRequested != VIRTUAL_CHANNEL_VERSION_WIN2000) { DEBUG_CHANMAN("warning version"); } for (index = 0; index < channelCount; index++) { lchan_def = pChannel + index; if (freerdp_chanman_find_chan_data_by_name(chan_man, lchan_def->name, 0) != 0) { DEBUG_CHANMAN("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_CHANMAN("warning more than 16 channels"); } chan_man->num_chans++; } return CHANNEL_RC_OK; }