diff options
Diffstat (limited to '1.4.23-rc4/channels/chan_local.c')
-rw-r--r-- | 1.4.23-rc4/channels/chan_local.c | 808 |
1 files changed, 0 insertions, 808 deletions
diff --git a/1.4.23-rc4/channels/chan_local.c b/1.4.23-rc4/channels/chan_local.c deleted file mode 100644 index b2e3c72b8..000000000 --- a/1.4.23-rc4/channels/chan_local.c +++ /dev/null @@ -1,808 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2005, Digium, Inc. - * - * Mark Spencer <markster@digium.com> - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! \file - * - * \author Mark Spencer <markster@digium.com> - * - * \brief Local Proxy Channel - * - * \ingroup channel_drivers - */ - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <sys/socket.h> -#include <errno.h> -#include <stdlib.h> -#include <fcntl.h> -#include <netdb.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <sys/signal.h> - -#include "asterisk/lock.h" -#include "asterisk/channel.h" -#include "asterisk/config.h" -#include "asterisk/logger.h" -#include "asterisk/module.h" -#include "asterisk/pbx.h" -#include "asterisk/options.h" -#include "asterisk/lock.h" -#include "asterisk/sched.h" -#include "asterisk/io.h" -#include "asterisk/rtp.h" -#include "asterisk/acl.h" -#include "asterisk/callerid.h" -#include "asterisk/file.h" -#include "asterisk/cli.h" -#include "asterisk/app.h" -#include "asterisk/musiconhold.h" -#include "asterisk/manager.h" -#include "asterisk/stringfields.h" -#include "asterisk/devicestate.h" - -static const char tdesc[] = "Local Proxy Channel Driver"; - -#define IS_OUTBOUND(a,b) (a == b->chan ? 1 : 0) - -static struct ast_channel *local_request(const char *type, int format, void *data, int *cause); -static int local_digit_begin(struct ast_channel *ast, char digit); -static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration); -static int local_call(struct ast_channel *ast, char *dest, int timeout); -static int local_hangup(struct ast_channel *ast); -static int local_answer(struct ast_channel *ast); -static struct ast_frame *local_read(struct ast_channel *ast); -static int local_write(struct ast_channel *ast, struct ast_frame *f); -static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen); -static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); -static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen); -static int local_sendtext(struct ast_channel *ast, const char *text); -static int local_devicestate(void *data); - -/* PBX interface structure for channel registration */ -static const struct ast_channel_tech local_tech = { - .type = "Local", - .description = tdesc, - .capabilities = -1, - .requester = local_request, - .send_digit_begin = local_digit_begin, - .send_digit_end = local_digit_end, - .call = local_call, - .hangup = local_hangup, - .answer = local_answer, - .read = local_read, - .write = local_write, - .write_video = local_write, - .exception = local_read, - .indicate = local_indicate, - .fixup = local_fixup, - .send_html = local_sendhtml, - .send_text = local_sendtext, - .devicestate = local_devicestate, -}; - -struct local_pvt { - ast_mutex_t lock; /* Channel private lock */ - unsigned int flags; /* Private flags */ - char context[AST_MAX_CONTEXT]; /* Context to call */ - char exten[AST_MAX_EXTENSION]; /* Extension to call */ - int reqformat; /* Requested format */ - struct ast_channel *owner; /* Master Channel */ - struct ast_channel *chan; /* Outbound channel */ - struct ast_module_user *u_owner; /*! reference to keep the module loaded while in use */ - struct ast_module_user *u_chan; /*! reference to keep the module loaded while in use */ - AST_LIST_ENTRY(local_pvt) list; /* Next entity */ -}; - -#define LOCAL_GLARE_DETECT (1 << 0) /*!< Detect glare on hangup */ -#define LOCAL_CANCEL_QUEUE (1 << 1) /*!< Cancel queue */ -#define LOCAL_ALREADY_MASQED (1 << 2) /*!< Already masqueraded */ -#define LOCAL_LAUNCHED_PBX (1 << 3) /*!< PBX was launched */ -#define LOCAL_NO_OPTIMIZATION (1 << 4) /*!< Do not optimize using masquerading */ - -static AST_LIST_HEAD_STATIC(locals, local_pvt); - -/*! \brief Adds devicestate to local channels */ -static int local_devicestate(void *data) -{ - char *exten = ast_strdupa(data); - char *context = NULL, *opts = NULL; - int res; - - if (!(context = strchr(exten, '@'))) { - ast_log(LOG_WARNING, "Someone used Local/%s somewhere without a @context. This is bad.\n", exten); - return AST_DEVICE_INVALID; - } - - *context++ = '\0'; - - /* Strip options if they exist */ - if ((opts = strchr(context, '/'))) - *opts = '\0'; - - if (option_debug > 2) - ast_log(LOG_DEBUG, "Checking if extension %s@%s exists (devicestate)\n", exten, context); - res = ast_exists_extension(NULL, context, exten, 1, NULL); - if (!res) - return AST_DEVICE_INVALID; - else - return AST_DEVICE_UNKNOWN; -} - -/*! - * \note Assumes the pvt is no longer in the pvts list - */ -static struct local_pvt *local_pvt_destroy(struct local_pvt *pvt) -{ - ast_mutex_destroy(&pvt->lock); - free(pvt); - return NULL; -} - -static int local_queue_frame(struct local_pvt *p, int isoutbound, struct ast_frame *f, - struct ast_channel *us, int us_locked) -{ - struct ast_channel *other = NULL; - - /* Recalculate outbound channel */ - other = isoutbound ? p->owner : p->chan; - - /* do not queue frame if generator is on both local channels */ - if (us && us->generator && other->generator) - return 0; - - /* Set glare detection */ - ast_set_flag(p, LOCAL_GLARE_DETECT); - if (ast_test_flag(p, LOCAL_CANCEL_QUEUE)) { - /* We had a glare on the hangup. Forget all this business, - return and destroy p. */ - ast_mutex_unlock(&p->lock); - p = local_pvt_destroy(p); - return -1; - } - if (!other) { - ast_clear_flag(p, LOCAL_GLARE_DETECT); - return 0; - } - - /* Ensure that we have both channels locked */ - while (other && ast_channel_trylock(other)) { - ast_mutex_unlock(&p->lock); - if (us && us_locked) { - do { - ast_channel_unlock(us); - usleep(1); - ast_channel_lock(us); - } while (ast_mutex_trylock(&p->lock)); - } else { - usleep(1); - ast_mutex_lock(&p->lock); - } - other = isoutbound ? p->owner : p->chan; - } - - if (other) { - ast_queue_frame(other, f); - ast_channel_unlock(other); - } - - ast_clear_flag(p, LOCAL_GLARE_DETECT); - - return 0; -} - -static int local_answer(struct ast_channel *ast) -{ - struct local_pvt *p = ast->tech_pvt; - int isoutbound; - int res = -1; - - if (!p) - return -1; - - ast_mutex_lock(&p->lock); - isoutbound = IS_OUTBOUND(ast, p); - if (isoutbound) { - /* Pass along answer since somebody answered us */ - struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER }; - res = local_queue_frame(p, isoutbound, &answer, ast, 1); - } else - ast_log(LOG_WARNING, "Huh? Local is being asked to answer?\n"); - if (!res) - ast_mutex_unlock(&p->lock); - return res; -} - -static void check_bridge(struct local_pvt *p, int isoutbound) -{ - struct ast_channel_monitor *tmp; - if (ast_test_flag(p, LOCAL_ALREADY_MASQED) || ast_test_flag(p, LOCAL_NO_OPTIMIZATION) || !p->chan || !p->owner || (p->chan->_bridge != ast_bridged_channel(p->chan))) - return; - - /* only do the masquerade if we are being called on the outbound channel, - if it has been bridged to another channel and if there are no pending - frames on the owner channel (because they would be transferred to the - outbound channel during the masquerade) - */ - if (isoutbound && p->chan->_bridge /* Not ast_bridged_channel! Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) { - /* Masquerade bridged channel into owner */ - /* Lock everything we need, one by one, and give up if - we can't get everything. Remember, we'll get another - chance in just a little bit */ - if (!ast_mutex_trylock(&(p->chan->_bridge)->lock)) { - if (!p->chan->_bridge->_softhangup) { - if (!ast_mutex_trylock(&p->owner->lock)) { - if (!p->owner->_softhangup) { - if (p->owner->monitor && !p->chan->_bridge->monitor) { - /* If a local channel is being monitored, we don't want a masquerade - * to cause the monitor to go away. Since the masquerade swaps the monitors, - * pre-swapping the monitors before the masquerade will ensure that the monitor - * ends up where it is expected. - */ - tmp = p->owner->monitor; - p->owner->monitor = p->chan->_bridge->monitor; - p->chan->_bridge->monitor = tmp; - } - if (p->chan->audiohooks) { - struct ast_audiohook_list *audiohooks_swapper; - audiohooks_swapper = p->chan->audiohooks; - p->chan->audiohooks = p->owner->audiohooks; - p->owner->audiohooks = audiohooks_swapper; - } - ast_channel_masquerade(p->owner, p->chan->_bridge); - ast_set_flag(p, LOCAL_ALREADY_MASQED); - } - ast_mutex_unlock(&p->owner->lock); - } - ast_mutex_unlock(&(p->chan->_bridge)->lock); - } - } - /* We only allow masquerading in one 'direction'... it's important to preserve the state - (group variables, etc.) that live on p->chan->_bridge (and were put there by the dialplan) - when the local channels go away. - */ -#if 0 - } else if (!isoutbound && p->owner && p->owner->_bridge && p->chan && AST_LIST_EMPTY(&p->chan->readq)) { - /* Masquerade bridged channel into chan */ - if (!ast_mutex_trylock(&(p->owner->_bridge)->lock)) { - if (!p->owner->_bridge->_softhangup) { - if (!ast_mutex_trylock(&p->chan->lock)) { - if (!p->chan->_softhangup) { - ast_channel_masquerade(p->chan, p->owner->_bridge); - ast_set_flag(p, LOCAL_ALREADY_MASQED); - } - ast_mutex_unlock(&p->chan->lock); - } - } - ast_mutex_unlock(&(p->owner->_bridge)->lock); - } -#endif - } -} - -static struct ast_frame *local_read(struct ast_channel *ast) -{ - return &ast_null_frame; -} - -static int local_write(struct ast_channel *ast, struct ast_frame *f) -{ - struct local_pvt *p = ast->tech_pvt; - int res = -1; - int isoutbound; - - if (!p) - return -1; - - /* Just queue for delivery to the other side */ - ast_mutex_lock(&p->lock); - isoutbound = IS_OUTBOUND(ast, p); - if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) - check_bridge(p, isoutbound); - if (!ast_test_flag(p, LOCAL_ALREADY_MASQED)) - res = local_queue_frame(p, isoutbound, f, ast, 1); - else { - if (option_debug) - ast_log(LOG_DEBUG, "Not posting to queue since already masked on '%s'\n", ast->name); - res = 0; - } - if (!res) - ast_mutex_unlock(&p->lock); - return res; -} - -static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) -{ - struct local_pvt *p = newchan->tech_pvt; - - if (!p) - return -1; - - ast_mutex_lock(&p->lock); - - if ((p->owner != oldchan) && (p->chan != oldchan)) { - ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan); - ast_mutex_unlock(&p->lock); - return -1; - } - if (p->owner == oldchan) - p->owner = newchan; - else - p->chan = newchan; - ast_mutex_unlock(&p->lock); - return 0; -} - -static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen) -{ - struct local_pvt *p = ast->tech_pvt; - int res = 0; - struct ast_frame f = { AST_FRAME_CONTROL, }; - int isoutbound; - - if (!p) - return -1; - - /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */ - if (condition == AST_CONTROL_HOLD) { - ast_moh_start(ast, data, NULL); - } else if (condition == AST_CONTROL_UNHOLD) { - ast_moh_stop(ast); - } else { - /* Queue up a frame representing the indication as a control frame */ - ast_mutex_lock(&p->lock); - isoutbound = IS_OUTBOUND(ast, p); - f.subclass = condition; - f.data = (void*)data; - f.datalen = datalen; - if (!(res = local_queue_frame(p, isoutbound, &f, ast, 1))) - ast_mutex_unlock(&p->lock); - } - - return res; -} - -static int local_digit_begin(struct ast_channel *ast, char digit) -{ - struct local_pvt *p = ast->tech_pvt; - int res = -1; - struct ast_frame f = { AST_FRAME_DTMF_BEGIN, }; - int isoutbound; - - if (!p) - return -1; - - ast_mutex_lock(&p->lock); - isoutbound = IS_OUTBOUND(ast, p); - f.subclass = digit; - if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) - ast_mutex_unlock(&p->lock); - - return res; -} - -static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration) -{ - struct local_pvt *p = ast->tech_pvt; - int res = -1; - struct ast_frame f = { AST_FRAME_DTMF_END, }; - int isoutbound; - - if (!p) - return -1; - - ast_mutex_lock(&p->lock); - isoutbound = IS_OUTBOUND(ast, p); - f.subclass = digit; - f.len = duration; - if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) - ast_mutex_unlock(&p->lock); - - return res; -} - -static int local_sendtext(struct ast_channel *ast, const char *text) -{ - struct local_pvt *p = ast->tech_pvt; - int res = -1; - struct ast_frame f = { AST_FRAME_TEXT, }; - int isoutbound; - - if (!p) - return -1; - - ast_mutex_lock(&p->lock); - isoutbound = IS_OUTBOUND(ast, p); - f.data = (char *) text; - f.datalen = strlen(text) + 1; - if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) - ast_mutex_unlock(&p->lock); - return res; -} - -static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen) -{ - struct local_pvt *p = ast->tech_pvt; - int res = -1; - struct ast_frame f = { AST_FRAME_HTML, }; - int isoutbound; - - if (!p) - return -1; - - ast_mutex_lock(&p->lock); - isoutbound = IS_OUTBOUND(ast, p); - f.subclass = subclass; - f.data = (char *)data; - f.datalen = datalen; - if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) - ast_mutex_unlock(&p->lock); - return res; -} - -/*! \brief Initiate new call, part of PBX interface - * dest is the dial string */ -static int local_call(struct ast_channel *ast, char *dest, int timeout) -{ - struct local_pvt *p = ast->tech_pvt; - int res; - struct ast_var_t *varptr = NULL, *new; - size_t len, namelen; - - if (!p) - return -1; - - ast_mutex_lock(&p->lock); - - /* - * Note that cid_num and cid_name aren't passed in the ast_channel_alloc - * call, so it's done here instead. - */ - p->chan->cid.cid_dnid = ast_strdup(p->owner->cid.cid_dnid); - p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num); - p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name); - p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis); - p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani); - p->chan->cid.cid_pres = p->owner->cid.cid_pres; - p->chan->cid.cid_ani2 = p->owner->cid.cid_ani2; - p->chan->cid.cid_ton = p->owner->cid.cid_ton; - p->chan->cid.cid_tns = p->owner->cid.cid_tns; - ast_string_field_set(p->chan, language, p->owner->language); - ast_string_field_set(p->chan, accountcode, p->owner->accountcode); - ast_string_field_set(p->chan, musicclass, p->owner->musicclass); - ast_cdr_update(p->chan); - p->chan->cdrflags = p->owner->cdrflags; - - if (!ast_exists_extension(NULL, p->chan->context, p->chan->exten, 1, p->owner->cid.cid_num)) { - ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->chan->exten, p->chan->context); - ast_mutex_unlock(&p->lock); - return -1; - } - - /* copy the channel variables from the incoming channel to the outgoing channel */ - /* Note that due to certain assumptions, they MUST be in the same order */ - AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) { - namelen = strlen(varptr->name); - len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2; - if ((new = ast_calloc(1, len))) { - memcpy(new, varptr, len); - new->value = &(new->name[0]) + namelen + 1; - AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries); - } - } - ast_channel_datastore_inherit(p->owner, p->chan); - - /* Start switch on sub channel */ - if (!(res = ast_pbx_start(p->chan))) - ast_set_flag(p, LOCAL_LAUNCHED_PBX); - - ast_mutex_unlock(&p->lock); - return res; -} - -/*! \brief Hangup a call through the local proxy channel */ -static int local_hangup(struct ast_channel *ast) -{ - struct local_pvt *p = ast->tech_pvt; - int isoutbound; - struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP }; - struct ast_channel *ochan = NULL; - int glaredetect = 0, res = 0; - - if (!p) - return -1; - - while (ast_mutex_trylock(&p->lock)) { - ast_channel_unlock(ast); - usleep(1); - ast_channel_lock(ast); - } - - isoutbound = IS_OUTBOUND(ast, p); - if (isoutbound) { - const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS"); - if ((status) && (p->owner)) { - /* Deadlock avoidance */ - while (p->owner && ast_channel_trylock(p->owner)) { - ast_mutex_unlock(&p->lock); - if (ast) { - ast_channel_unlock(ast); - } - usleep(1); - if (ast) { - ast_channel_lock(ast); - } - ast_mutex_lock(&p->lock); - } - if (p->owner) { - pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status); - ast_channel_unlock(p->owner); - } - } - p->chan = NULL; - ast_clear_flag(p, LOCAL_LAUNCHED_PBX); - ast_module_user_remove(p->u_chan); - } else { - p->owner = NULL; - ast_module_user_remove(p->u_owner); - while (p->chan && ast_channel_trylock(p->chan)) { - DEADLOCK_AVOIDANCE(&p->lock); - } - if (p->chan) { - ast_queue_hangup(p->chan); - ast_channel_unlock(p->chan); - } - } - - ast->tech_pvt = NULL; - - if (!p->owner && !p->chan) { - /* Okay, done with the private part now, too. */ - glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT); - /* If we have a queue holding, don't actually destroy p yet, but - let local_queue do it. */ - if (glaredetect) - ast_set_flag(p, LOCAL_CANCEL_QUEUE); - ast_mutex_unlock(&p->lock); - /* Remove from list */ - AST_LIST_LOCK(&locals); - AST_LIST_REMOVE(&locals, p, list); - AST_LIST_UNLOCK(&locals); - /* Grab / release lock just in case */ - ast_mutex_lock(&p->lock); - ast_mutex_unlock(&p->lock); - /* And destroy */ - if (!glaredetect) { - p = local_pvt_destroy(p); - } - return 0; - } - if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) - /* Need to actually hangup since there is no PBX */ - ochan = p->chan; - else - res = local_queue_frame(p, isoutbound, &f, NULL, 1); - if (!res) - ast_mutex_unlock(&p->lock); - if (ochan) - ast_hangup(ochan); - return 0; -} - -/*! \brief Create a call structure */ -static struct local_pvt *local_alloc(const char *data, int format) -{ - struct local_pvt *tmp = NULL; - char *c = NULL, *opts = NULL; - - if (!(tmp = ast_calloc(1, sizeof(*tmp)))) - return NULL; - - /* Initialize private structure information */ - ast_mutex_init(&tmp->lock); - ast_copy_string(tmp->exten, data, sizeof(tmp->exten)); - - /* Look for options */ - if ((opts = strchr(tmp->exten, '/'))) { - *opts++ = '\0'; - if (strchr(opts, 'n')) - ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION); - } - - /* Look for a context */ - if ((c = strchr(tmp->exten, '@'))) - *c++ = '\0'; - - ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context)); - - tmp->reqformat = format; - -#if 0 - /* We can't do this check here, because we don't know the CallerID yet, and - * the CallerID could potentially affect what step is actually taken (or - * even if that step exists). */ - if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) { - ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context); - tmp = local_pvt_destroy(tmp); - } else { -#endif - /* Add to list */ - AST_LIST_LOCK(&locals); - AST_LIST_INSERT_HEAD(&locals, tmp, list); - AST_LIST_UNLOCK(&locals); -#if 0 - } -#endif - - return tmp; -} - -/*! \brief Start new local channel */ -static struct ast_channel *local_new(struct local_pvt *p, int state) -{ - struct ast_channel *tmp = NULL, *tmp2 = NULL; - int randnum = ast_random() & 0xffff, fmt = 0; - const char *t; - int ama; - - /* Allocate two new Asterisk channels */ - /* safe accountcode */ - if (p->owner && p->owner->accountcode) - t = p->owner->accountcode; - else - t = ""; - - if (p->owner) - ama = p->owner->amaflags; - else - ama = 0; - if (!(tmp = ast_channel_alloc(1, state, 0, 0, t, p->exten, p->context, ama, "Local/%s@%s-%04x,1", p->exten, p->context, randnum)) - || !(tmp2 = ast_channel_alloc(1, AST_STATE_RING, 0, 0, t, p->exten, p->context, ama, "Local/%s@%s-%04x,2", p->exten, p->context, randnum))) { - if (tmp) - ast_channel_free(tmp); - if (tmp2) - ast_channel_free(tmp2); - ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n"); - return NULL; - } - - tmp2->tech = tmp->tech = &local_tech; - - tmp->nativeformats = p->reqformat; - tmp2->nativeformats = p->reqformat; - - /* Determine our read/write format and set it on each channel */ - fmt = ast_best_codec(p->reqformat); - tmp->writeformat = fmt; - tmp2->writeformat = fmt; - tmp->rawwriteformat = fmt; - tmp2->rawwriteformat = fmt; - tmp->readformat = fmt; - tmp2->readformat = fmt; - tmp->rawreadformat = fmt; - tmp2->rawreadformat = fmt; - - tmp->tech_pvt = p; - tmp2->tech_pvt = p; - - p->owner = tmp; - p->chan = tmp2; - p->u_owner = ast_module_user_add(p->owner); - p->u_chan = ast_module_user_add(p->chan); - - ast_copy_string(tmp->context, p->context, sizeof(tmp->context)); - ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context)); - ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten)); - tmp->priority = 1; - tmp2->priority = 1; - - return tmp; -} - -/*! \brief Part of PBX interface */ -static struct ast_channel *local_request(const char *type, int format, void *data, int *cause) -{ - struct local_pvt *p = NULL; - struct ast_channel *chan = NULL; - - /* Allocate a new private structure and then Asterisk channel */ - if ((p = local_alloc(data, format))) { - if (!(chan = local_new(p, AST_STATE_DOWN))) { - AST_LIST_LOCK(&locals); - AST_LIST_REMOVE(&locals, p, list); - AST_LIST_UNLOCK(&locals); - p = local_pvt_destroy(p); - } - } - - return chan; -} - -/*! \brief CLI command "local show channels" */ -static int locals_show(int fd, int argc, char **argv) -{ - struct local_pvt *p = NULL; - - if (argc != 3) - return RESULT_SHOWUSAGE; - - AST_LIST_LOCK(&locals); - if (!AST_LIST_EMPTY(&locals)) { - AST_LIST_TRAVERSE(&locals, p, list) { - ast_mutex_lock(&p->lock); - ast_cli(fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context); - ast_mutex_unlock(&p->lock); - } - } else - ast_cli(fd, "No local channels in use\n"); - AST_LIST_UNLOCK(&locals); - - return RESULT_SUCCESS; -} - -static char show_locals_usage[] = -"Usage: local show channels\n" -" Provides summary information on active local proxy channels.\n"; - -static struct ast_cli_entry cli_local[] = { - { { "local", "show", "channels", NULL }, - locals_show, "List status of local channels", - show_locals_usage }, -}; - -/*! \brief Load module into PBX, register channel */ -static int load_module(void) -{ - /* Make sure we can register our channel type */ - if (ast_channel_register(&local_tech)) { - ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n"); - return -1; - } - ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); - return 0; -} - -/*! \brief Unload the local proxy channel from Asterisk */ -static int unload_module(void) -{ - struct local_pvt *p = NULL; - - /* First, take us out of the channel loop */ - ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); - ast_channel_unregister(&local_tech); - if (!AST_LIST_LOCK(&locals)) { - /* Hangup all interfaces if they have an owner */ - AST_LIST_TRAVERSE(&locals, p, list) { - if (p->owner) - ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); - } - AST_LIST_UNLOCK(&locals); - } else { - ast_log(LOG_WARNING, "Unable to lock the monitor\n"); - return -1; - } - return 0; -} - -AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Local Proxy Channel (Note: used internally by other modules)"); |