#include "asterisk.h"
#include <fcntl.h>
#include <sys/signal.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/module.h"
#include "asterisk/pbx.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"
Go to the source code of this file.
Data Structures | |
struct | local_pvt |
struct | locals |
Defines | |
#define | IS_OUTBOUND(a, b) (a == b->chan ? 1 : 0) |
#define | LOCAL_ALREADY_MASQED (1 << 2) |
#define | LOCAL_BRIDGE (1 << 5) |
#define | LOCAL_CANCEL_QUEUE (1 << 1) |
#define | LOCAL_GLARE_DETECT (1 << 0) |
#define | LOCAL_LAUNCHED_PBX (1 << 3) |
#define | LOCAL_MOH_PASSTHRU (1 << 6) |
#define | LOCAL_NO_OPTIMIZATION (1 << 4) |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static void | check_bridge (struct local_pvt *p) |
static int | load_module (void) |
Load module into PBX, register channel. | |
static struct local_pvt * | local_alloc (const char *data, int format) |
Create a call structure. | |
static int | local_answer (struct ast_channel *ast) |
static struct ast_channel * | local_bridgedchannel (struct ast_channel *chan, struct ast_channel *bridge) |
Return the bridged channel of a Local channel. | |
static int | local_call (struct ast_channel *ast, char *dest, int timeout) |
Initiate new call, part of PBX interface dest is the dial string. | |
static int | local_devicestate (void *data) |
Adds devicestate to local channels. | |
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_fixup (struct ast_channel *oldchan, struct ast_channel *newchan) |
static int | local_hangup (struct ast_channel *ast) |
Hangup a call through the local proxy channel. | |
static int | local_indicate (struct ast_channel *ast, int condition, const void *data, size_t datalen) |
static struct ast_channel * | local_new (struct local_pvt *p, int state) |
Start new local channel. | |
static struct local_pvt * | local_pvt_destroy (struct local_pvt *pvt) |
static int | local_queue_frame (struct local_pvt *p, int isoutbound, struct ast_frame *f, struct ast_channel *us, int us_locked) |
static struct ast_frame * | local_read (struct ast_channel *ast) |
static struct ast_channel * | local_request (const char *type, int format, void *data, int *cause) |
Part of PBX interface. | |
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_write (struct ast_channel *ast, struct ast_frame *f) |
static char * | locals_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
CLI command "local show channels". | |
static int | unload_module (void) |
Unload the local proxy channel from Asterisk. | |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Local Proxy Channel (Note: used internally by other modules)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, } |
static struct ast_module_info * | ast_module_info = &__mod_info |
static struct ast_cli_entry | cli_local [] |
static struct ast_jb_conf | g_jb_conf |
static struct ast_channel_tech | local_tech |
static const char | tdesc [] = "Local Proxy Channel Driver" |
Definition in file chan_local.c.
#define IS_OUTBOUND | ( | a, | |||
b | ) | (a == b->chan ? 1 : 0) |
Definition at line 55 of file chan_local.c.
Referenced by local_answer(), local_digit_begin(), local_digit_end(), local_hangup(), local_indicate(), local_sendhtml(), local_sendtext(), and local_write().
#define LOCAL_ALREADY_MASQED (1 << 2) |
Already masqueraded
Definition at line 119 of file chan_local.c.
Referenced by check_bridge(), and local_write().
#define LOCAL_BRIDGE (1 << 5) |
Report back the "true" channel as being bridged to
Definition at line 122 of file chan_local.c.
Referenced by local_alloc(), and local_bridgedchannel().
#define LOCAL_CANCEL_QUEUE (1 << 1) |
Cancel queue
Definition at line 118 of file chan_local.c.
Referenced by local_hangup(), and local_queue_frame().
#define LOCAL_GLARE_DETECT (1 << 0) |
Detect glare on hangup
Definition at line 117 of file chan_local.c.
Referenced by local_hangup(), and local_queue_frame().
#define LOCAL_LAUNCHED_PBX (1 << 3) |
PBX was launched
Definition at line 120 of file chan_local.c.
Referenced by local_call(), and local_hangup().
#define LOCAL_MOH_PASSTHRU (1 << 6) |
Pass through music on hold start/stop frames
Definition at line 123 of file chan_local.c.
Referenced by local_alloc(), and local_indicate().
#define LOCAL_NO_OPTIMIZATION (1 << 4) |
Do not optimize using masquerading
Definition at line 121 of file chan_local.c.
Referenced by check_bridge(), and local_alloc().
static void __reg_module | ( | void | ) | [static] |
static void __unreg_module | ( | void | ) | [static] |
static void check_bridge | ( | struct local_pvt * | p | ) | [static] |
Definition at line 293 of file chan_local.c.
References ast_channel::_bridge, ast_app_group_update(), ast_bridged_channel(), ast_channel_masquerade(), ast_channel_trylock, ast_channel_unlock, ast_check_hangup(), AST_LIST_EMPTY, ast_set_flag, ast_test_flag, ast_channel::audiohooks, local_pvt::chan, LOCAL_ALREADY_MASQED, LOCAL_NO_OPTIMIZATION, ast_channel::monitor, local_pvt::owner, and ast_channel::readq.
Referenced by local_write().
00294 { 00295 struct ast_channel_monitor *tmp; 00296 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))) 00297 return; 00298 00299 /* only do the masquerade if we are being called on the outbound channel, 00300 if it has been bridged to another channel and if there are no pending 00301 frames on the owner channel (because they would be transferred to the 00302 outbound channel during the masquerade) 00303 */ 00304 if (p->chan->_bridge /* Not ast_bridged_channel! Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) { 00305 /* Masquerade bridged channel into owner */ 00306 /* Lock everything we need, one by one, and give up if 00307 we can't get everything. Remember, we'll get another 00308 chance in just a little bit */ 00309 if (!ast_channel_trylock(p->chan->_bridge)) { 00310 if (!ast_check_hangup(p->chan->_bridge)) { 00311 if (!ast_channel_trylock(p->owner)) { 00312 if (!ast_check_hangup(p->owner)) { 00313 if (p->owner->monitor && !p->chan->_bridge->monitor) { 00314 /* If a local channel is being monitored, we don't want a masquerade 00315 * to cause the monitor to go away. Since the masquerade swaps the monitors, 00316 * pre-swapping the monitors before the masquerade will ensure that the monitor 00317 * ends up where it is expected. 00318 */ 00319 tmp = p->owner->monitor; 00320 p->owner->monitor = p->chan->_bridge->monitor; 00321 p->chan->_bridge->monitor = tmp; 00322 } 00323 if (p->chan->audiohooks) { 00324 struct ast_audiohook_list *audiohooks_swapper; 00325 audiohooks_swapper = p->chan->audiohooks; 00326 p->chan->audiohooks = p->owner->audiohooks; 00327 p->owner->audiohooks = audiohooks_swapper; 00328 } 00329 ast_app_group_update(p->chan, p->owner); 00330 ast_channel_masquerade(p->owner, p->chan->_bridge); 00331 ast_set_flag(p, LOCAL_ALREADY_MASQED); 00332 } 00333 ast_channel_unlock(p->owner); 00334 } 00335 ast_channel_unlock(p->chan->_bridge); 00336 } 00337 } 00338 } 00339 }
static int load_module | ( | void | ) | [static] |
Load module into PBX, register channel.
Definition at line 838 of file chan_local.c.
References ast_channel_register(), ast_cli_register_multiple(), ast_log(), AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, cli_local, local_tech, and LOG_ERROR.
00839 { 00840 /* Make sure we can register our channel type */ 00841 if (ast_channel_register(&local_tech)) { 00842 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n"); 00843 return AST_MODULE_LOAD_FAILURE; 00844 } 00845 ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 00846 return AST_MODULE_LOAD_SUCCESS; 00847 }
static struct local_pvt* local_alloc | ( | const char * | data, | |
int | format | |||
) | [static] |
Create a call structure.
Definition at line 654 of file chan_local.c.
References ast_calloc, ast_copy_string(), ast_exists_extension(), AST_JB_ENABLED, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_mutex_init(), ast_set_flag, ast_test_flag, g_jb_conf, local_pvt::list, LOCAL_BRIDGE, LOCAL_MOH_PASSTHRU, LOCAL_NO_OPTIMIZATION, local_pvt_destroy(), LOG_ERROR, and LOG_NOTICE.
Referenced by local_request().
00655 { 00656 struct local_pvt *tmp = NULL; 00657 char *c = NULL, *opts = NULL; 00658 00659 if (!(tmp = ast_calloc(1, sizeof(*tmp)))) 00660 return NULL; 00661 00662 /* Initialize private structure information */ 00663 ast_mutex_init(&tmp->lock); 00664 ast_copy_string(tmp->exten, data, sizeof(tmp->exten)); 00665 00666 memcpy(&tmp->jb_conf, &g_jb_conf, sizeof(tmp->jb_conf)); 00667 00668 /* Look for options */ 00669 if ((opts = strchr(tmp->exten, '/'))) { 00670 *opts++ = '\0'; 00671 if (strchr(opts, 'n')) 00672 ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION); 00673 if (strchr(opts, 'j')) { 00674 if (ast_test_flag(tmp, LOCAL_NO_OPTIMIZATION)) 00675 ast_set_flag(&tmp->jb_conf, AST_JB_ENABLED); 00676 else { 00677 ast_log(LOG_ERROR, "You must use the 'n' option for chan_local " 00678 "to use the 'j' option to enable the jitterbuffer\n"); 00679 } 00680 } 00681 if (strchr(opts, 'b')) { 00682 ast_set_flag(tmp, LOCAL_BRIDGE); 00683 } 00684 if (strchr(opts, 'm')) { 00685 ast_set_flag(tmp, LOCAL_MOH_PASSTHRU); 00686 } 00687 } 00688 00689 /* Look for a context */ 00690 if ((c = strchr(tmp->exten, '@'))) 00691 *c++ = '\0'; 00692 00693 ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context)); 00694 00695 tmp->reqformat = format; 00696 00697 #if 0 00698 /* We can't do this check here, because we don't know the CallerID yet, and 00699 * the CallerID could potentially affect what step is actually taken (or 00700 * even if that step exists). */ 00701 if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) { 00702 ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context); 00703 tmp = local_pvt_destroy(tmp); 00704 } else { 00705 #endif 00706 /* Add to list */ 00707 AST_LIST_LOCK(&locals); 00708 AST_LIST_INSERT_HEAD(&locals, tmp, list); 00709 AST_LIST_UNLOCK(&locals); 00710 #if 0 00711 } 00712 #endif 00713 00714 return tmp; 00715 }
static int local_answer | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 267 of file chan_local.c.
References AST_CONTROL_ANSWER, AST_FRAME_CONTROL, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), IS_OUTBOUND, local_queue_frame(), local_pvt::lock, LOG_WARNING, and ast_channel::tech_pvt.
00268 { 00269 struct local_pvt *p = ast->tech_pvt; 00270 int isoutbound; 00271 int res = -1; 00272 00273 if (!p) 00274 return -1; 00275 00276 ast_mutex_lock(&p->lock); 00277 isoutbound = IS_OUTBOUND(ast, p); 00278 if (isoutbound) { 00279 /* Pass along answer since somebody answered us */ 00280 struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER }; 00281 res = local_queue_frame(p, isoutbound, &answer, ast, 1); 00282 } else 00283 ast_log(LOG_WARNING, "Huh? Local is being asked to answer?\n"); 00284 if (!res) 00285 ast_mutex_unlock(&p->lock); 00286 return res; 00287 }
static struct ast_channel * local_bridgedchannel | ( | struct ast_channel * | chan, | |
struct ast_channel * | bridge | |||
) | [static] |
Return the bridged channel of a Local channel.
Definition at line 176 of file chan_local.c.
References ast_channel::_bridge, ast_debug, ast_mutex_lock(), ast_mutex_unlock(), ast_test_flag, local_pvt::chan, LOCAL_BRIDGE, local_pvt::lock, ast_channel::name, local_pvt::owner, and ast_channel::tech_pvt.
00177 { 00178 struct local_pvt *p = bridge->tech_pvt; 00179 struct ast_channel *bridged = bridge; 00180 00181 if (!p) { 00182 ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning <none>\n", 00183 chan->name, bridge->name); 00184 return NULL; 00185 } 00186 00187 ast_mutex_lock(&p->lock); 00188 00189 if (ast_test_flag(p, LOCAL_BRIDGE)) { 00190 /* Find the opposite channel */ 00191 bridged = (bridge == p->owner ? p->chan : p->owner); 00192 00193 /* Now see if the opposite channel is bridged to anything */ 00194 if (!bridged) { 00195 bridged = bridge; 00196 } else if (bridged->_bridge) { 00197 bridged = bridged->_bridge; 00198 } 00199 } 00200 00201 ast_mutex_unlock(&p->lock); 00202 00203 return bridged; 00204 }
static int local_call | ( | struct ast_channel * | ast, | |
char * | dest, | |||
int | timeout | |||
) | [static] |
Initiate new call, part of PBX interface dest is the dial string.
Definition at line 502 of file chan_local.c.
References ast_channel::accountcode, accountcode, ast_calloc, ast_cdr_update(), ast_channel_datastore_inherit(), ast_exists_extension(), AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_pbx_start(), ast_set_flag, ast_strdup, ast_string_field_set, ast_channel::cdrflags, local_pvt::chan, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_ani2, ast_callerid::cid_dnid, ast_callerid::cid_name, ast_callerid::cid_num, ast_callerid::cid_pres, ast_callerid::cid_rdnis, ast_callerid::cid_tns, ast_callerid::cid_ton, ast_channel::context, ast_var_t::entries, ast_channel::exten, ast_channel::language, language, len(), LOCAL_LAUNCHED_PBX, local_pvt::lock, LOG_NOTICE, ast_channel::musicclass, musicclass, ast_var_t::name, local_pvt::owner, ast_channel::tech_pvt, ast_var_t::value, and ast_channel::varshead.
00503 { 00504 struct local_pvt *p = ast->tech_pvt; 00505 int res; 00506 struct ast_var_t *varptr = NULL, *new; 00507 size_t len, namelen; 00508 00509 if (!p) 00510 return -1; 00511 00512 ast_mutex_lock(&p->lock); 00513 00514 /* 00515 * Note that cid_num and cid_name aren't passed in the ast_channel_alloc 00516 * call, so it's done here instead. 00517 */ 00518 p->chan->cid.cid_dnid = ast_strdup(p->owner->cid.cid_dnid); 00519 p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num); 00520 p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name); 00521 p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis); 00522 p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani); 00523 p->chan->cid.cid_pres = p->owner->cid.cid_pres; 00524 p->chan->cid.cid_ani2 = p->owner->cid.cid_ani2; 00525 p->chan->cid.cid_ton = p->owner->cid.cid_ton; 00526 p->chan->cid.cid_tns = p->owner->cid.cid_tns; 00527 ast_string_field_set(p->chan, language, p->owner->language); 00528 ast_string_field_set(p->chan, accountcode, p->owner->accountcode); 00529 ast_string_field_set(p->chan, musicclass, p->owner->musicclass); 00530 ast_cdr_update(p->chan); 00531 p->chan->cdrflags = p->owner->cdrflags; 00532 00533 if (!ast_exists_extension(NULL, p->chan->context, p->chan->exten, 1, p->owner->cid.cid_num)) { 00534 ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->chan->exten, p->chan->context); 00535 ast_mutex_unlock(&p->lock); 00536 return -1; 00537 } 00538 00539 /* copy the channel variables from the incoming channel to the outgoing channel */ 00540 /* Note that due to certain assumptions, they MUST be in the same order */ 00541 AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) { 00542 namelen = strlen(varptr->name); 00543 len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2; 00544 if ((new = ast_calloc(1, len))) { 00545 memcpy(new, varptr, len); 00546 new->value = &(new->name[0]) + namelen + 1; 00547 AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries); 00548 } 00549 } 00550 ast_channel_datastore_inherit(p->owner, p->chan); 00551 00552 /* Start switch on sub channel */ 00553 if (!(res = ast_pbx_start(p->chan))) 00554 ast_set_flag(p, LOCAL_LAUNCHED_PBX); 00555 00556 ast_mutex_unlock(&p->lock); 00557 return res; 00558 }
static int local_devicestate | ( | void * | data | ) | [static] |
Adds devicestate to local channels.
Definition at line 128 of file chan_local.c.
References ast_debug, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, ast_exists_extension(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_strdupa, local_pvt::context, local_pvt::exten, local_pvt::list, LOG_WARNING, and local_pvt::owner.
00129 { 00130 char *exten = ast_strdupa(data); 00131 char *context = NULL, *opts = NULL; 00132 int res; 00133 struct local_pvt *lp; 00134 00135 if (!(context = strchr(exten, '@'))) { 00136 ast_log(LOG_WARNING, "Someone used Local/%s somewhere without a @context. This is bad.\n", exten); 00137 return AST_DEVICE_INVALID; 00138 } 00139 00140 *context++ = '\0'; 00141 00142 /* Strip options if they exist */ 00143 if ((opts = strchr(context, '/'))) 00144 *opts = '\0'; 00145 00146 ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context); 00147 00148 res = ast_exists_extension(NULL, context, exten, 1, NULL); 00149 if (!res) 00150 return AST_DEVICE_INVALID; 00151 00152 res = AST_DEVICE_NOT_INUSE; 00153 AST_LIST_LOCK(&locals); 00154 AST_LIST_TRAVERSE(&locals, lp, list) { 00155 if (!strcmp(exten, lp->exten) && !strcmp(context, lp->context) && lp->owner) { 00156 res = AST_DEVICE_INUSE; 00157 break; 00158 } 00159 } 00160 AST_LIST_UNLOCK(&locals); 00161 00162 return res; 00163 }
static int local_digit_begin | ( | struct ast_channel * | ast, | |
char | digit | |||
) | [static] |
Definition at line 422 of file chan_local.c.
References AST_FRAME_DTMF_BEGIN, ast_mutex_lock(), ast_mutex_unlock(), f, IS_OUTBOUND, local_queue_frame(), local_pvt::lock, and ast_channel::tech_pvt.
00423 { 00424 struct local_pvt *p = ast->tech_pvt; 00425 int res = -1; 00426 struct ast_frame f = { AST_FRAME_DTMF_BEGIN, }; 00427 int isoutbound; 00428 00429 if (!p) 00430 return -1; 00431 00432 ast_mutex_lock(&p->lock); 00433 isoutbound = IS_OUTBOUND(ast, p); 00434 f.subclass = digit; 00435 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) 00436 ast_mutex_unlock(&p->lock); 00437 00438 return res; 00439 }
static int local_digit_end | ( | struct ast_channel * | ast, | |
char | digit, | |||
unsigned int | duration | |||
) | [static] |
Definition at line 441 of file chan_local.c.
References AST_FRAME_DTMF_END, ast_mutex_lock(), ast_mutex_unlock(), f, IS_OUTBOUND, local_queue_frame(), local_pvt::lock, and ast_channel::tech_pvt.
00442 { 00443 struct local_pvt *p = ast->tech_pvt; 00444 int res = -1; 00445 struct ast_frame f = { AST_FRAME_DTMF_END, }; 00446 int isoutbound; 00447 00448 if (!p) 00449 return -1; 00450 00451 ast_mutex_lock(&p->lock); 00452 isoutbound = IS_OUTBOUND(ast, p); 00453 f.subclass = digit; 00454 f.len = duration; 00455 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) 00456 ast_mutex_unlock(&p->lock); 00457 00458 return res; 00459 }
static int local_fixup | ( | struct ast_channel * | oldchan, | |
struct ast_channel * | newchan | |||
) | [static] |
Definition at line 371 of file chan_local.c.
References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), local_pvt::chan, local_pvt::lock, LOG_WARNING, local_pvt::owner, and ast_channel::tech_pvt.
00372 { 00373 struct local_pvt *p = newchan->tech_pvt; 00374 00375 if (!p) 00376 return -1; 00377 00378 ast_mutex_lock(&p->lock); 00379 00380 if ((p->owner != oldchan) && (p->chan != oldchan)) { 00381 ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan); 00382 ast_mutex_unlock(&p->lock); 00383 return -1; 00384 } 00385 if (p->owner == oldchan) 00386 p->owner = newchan; 00387 else 00388 p->chan = newchan; 00389 ast_mutex_unlock(&p->lock); 00390 return 0; 00391 }
static int local_hangup | ( | struct ast_channel * | ast | ) | [static] |
Hangup a call through the local proxy channel.
Definition at line 561 of file chan_local.c.
References ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_clear_flag, AST_CONTROL_HANGUP, AST_FLAG_ANSWERED_ELSEWHERE, AST_FRAME_CONTROL, ast_hangup(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_module_user_remove, ast_mutex_lock(), ast_mutex_unlock(), ast_queue_hangup(), ast_set_flag, ast_test_flag, local_pvt::chan, f, ast_channel::hangupcause, IS_OUTBOUND, local_pvt::list, LOCAL_CANCEL_QUEUE, LOCAL_GLARE_DETECT, LOCAL_LAUNCHED_PBX, local_pvt_destroy(), local_queue_frame(), local_pvt::lock, local_pvt::owner, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), status, ast_channel::tech_pvt, local_pvt::u_chan, and local_pvt::u_owner.
00562 { 00563 struct local_pvt *p = ast->tech_pvt; 00564 int isoutbound; 00565 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP, .data.uint32 = ast->hangupcause }; 00566 struct ast_channel *ochan = NULL; 00567 int glaredetect = 0, res = 0; 00568 00569 if (!p) 00570 return -1; 00571 00572 ast_mutex_lock(&p->lock); 00573 00574 if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) 00575 ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE); 00576 isoutbound = IS_OUTBOUND(ast, p); 00577 if (isoutbound) { 00578 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS"); 00579 if ((status) && (p->owner)) { 00580 /* Deadlock avoidance */ 00581 while (p->owner && ast_channel_trylock(p->owner)) { 00582 ast_mutex_unlock(&p->lock); 00583 if (p->chan) { 00584 ast_channel_unlock(p->chan); 00585 } 00586 usleep(1); 00587 if (p->chan) { 00588 ast_channel_lock(p->chan); 00589 } 00590 ast_mutex_lock(&p->lock); 00591 } 00592 if (p->owner) { 00593 pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status); 00594 ast_channel_unlock(p->owner); 00595 } 00596 } 00597 p->chan = NULL; 00598 ast_clear_flag(p, LOCAL_LAUNCHED_PBX); 00599 ast_module_user_remove(p->u_chan); 00600 } else { 00601 ast_module_user_remove(p->u_owner); 00602 while (p->chan && ast_channel_trylock(p->chan)) { 00603 ast_mutex_unlock(&p->lock); 00604 if (p->owner) { 00605 ast_channel_unlock(p->owner); 00606 } 00607 usleep(1); 00608 if (p->owner) { 00609 ast_channel_lock(p->owner); 00610 } 00611 ast_mutex_lock(&p->lock); 00612 } 00613 00614 p->owner = NULL; 00615 if (p->chan) { 00616 ast_queue_hangup(p->chan); 00617 ast_channel_unlock(p->chan); 00618 } 00619 } 00620 00621 ast->tech_pvt = NULL; 00622 00623 if (!p->owner && !p->chan) { 00624 /* Okay, done with the private part now, too. */ 00625 glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT); 00626 /* If we have a queue holding, don't actually destroy p yet, but 00627 let local_queue do it. */ 00628 if (glaredetect) 00629 ast_set_flag(p, LOCAL_CANCEL_QUEUE); 00630 /* Remove from list */ 00631 AST_LIST_LOCK(&locals); 00632 AST_LIST_REMOVE(&locals, p, list); 00633 AST_LIST_UNLOCK(&locals); 00634 ast_mutex_unlock(&p->lock); 00635 /* And destroy */ 00636 if (!glaredetect) { 00637 p = local_pvt_destroy(p); 00638 } 00639 return 0; 00640 } 00641 if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) 00642 /* Need to actually hangup since there is no PBX */ 00643 ochan = p->chan; 00644 else 00645 res = local_queue_frame(p, isoutbound, &f, NULL, 1); 00646 if (!res) 00647 ast_mutex_unlock(&p->lock); 00648 if (ochan) 00649 ast_hangup(ochan); 00650 return 0; 00651 }
static int local_indicate | ( | struct ast_channel * | ast, | |
int | condition, | |||
const void * | data, | |||
size_t | datalen | |||
) | [static] |
Definition at line 393 of file chan_local.c.
References AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, ast_moh_start(), ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_test_flag, f, IS_OUTBOUND, LOCAL_MOH_PASSTHRU, local_queue_frame(), local_pvt::lock, and ast_channel::tech_pvt.
00394 { 00395 struct local_pvt *p = ast->tech_pvt; 00396 int res = 0; 00397 struct ast_frame f = { AST_FRAME_CONTROL, }; 00398 int isoutbound; 00399 00400 if (!p) 00401 return -1; 00402 00403 /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */ 00404 if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) { 00405 ast_moh_start(ast, data, NULL); 00406 } else if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_UNHOLD) { 00407 ast_moh_stop(ast); 00408 } else { 00409 /* Queue up a frame representing the indication as a control frame */ 00410 ast_mutex_lock(&p->lock); 00411 isoutbound = IS_OUTBOUND(ast, p); 00412 f.subclass = condition; 00413 f.data.ptr = (void*)data; 00414 f.datalen = datalen; 00415 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 1))) 00416 ast_mutex_unlock(&p->lock); 00417 } 00418 00419 return res; 00420 }
static struct ast_channel* local_new | ( | struct local_pvt * | p, | |
int | state | |||
) | [static] |
Start new local channel.
Definition at line 718 of file chan_local.c.
References ast_channel::accountcode, ast_channel::amaflags, ast_best_codec(), ast_channel_alloc, ast_channel_free(), ast_copy_string(), ast_jb_configure(), ast_log(), ast_module_user_add, ast_random(), AST_STATE_RING, local_pvt::chan, ast_channel::context, local_pvt::context, ast_channel::exten, local_pvt::exten, local_pvt::jb_conf, local_tech, LOG_WARNING, ast_channel::nativeformats, local_pvt::owner, ast_channel::priority, ast_channel::rawreadformat, ast_channel::rawwriteformat, ast_channel::readformat, local_pvt::reqformat, ast_channel::tech, ast_channel::tech_pvt, local_pvt::u_chan, local_pvt::u_owner, and ast_channel::writeformat.
Referenced by local_request().
00719 { 00720 struct ast_channel *tmp = NULL, *tmp2 = NULL; 00721 int randnum = ast_random() & 0xffff, fmt = 0; 00722 const char *t; 00723 int ama; 00724 00725 /* Allocate two new Asterisk channels */ 00726 /* safe accountcode */ 00727 if (p->owner && p->owner->accountcode) 00728 t = p->owner->accountcode; 00729 else 00730 t = ""; 00731 00732 if (p->owner) 00733 ama = p->owner->amaflags; 00734 else 00735 ama = 0; 00736 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)) 00737 || !(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))) { 00738 if (tmp) 00739 ast_channel_free(tmp); 00740 if (tmp2) 00741 ast_channel_free(tmp2); 00742 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n"); 00743 return NULL; 00744 } 00745 00746 tmp2->tech = tmp->tech = &local_tech; 00747 00748 tmp->nativeformats = p->reqformat; 00749 tmp2->nativeformats = p->reqformat; 00750 00751 /* Determine our read/write format and set it on each channel */ 00752 fmt = ast_best_codec(p->reqformat); 00753 tmp->writeformat = fmt; 00754 tmp2->writeformat = fmt; 00755 tmp->rawwriteformat = fmt; 00756 tmp2->rawwriteformat = fmt; 00757 tmp->readformat = fmt; 00758 tmp2->readformat = fmt; 00759 tmp->rawreadformat = fmt; 00760 tmp2->rawreadformat = fmt; 00761 00762 tmp->tech_pvt = p; 00763 tmp2->tech_pvt = p; 00764 00765 p->owner = tmp; 00766 p->chan = tmp2; 00767 p->u_owner = ast_module_user_add(p->owner); 00768 p->u_chan = ast_module_user_add(p->chan); 00769 00770 ast_copy_string(tmp->context, p->context, sizeof(tmp->context)); 00771 ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context)); 00772 ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten)); 00773 tmp->priority = 1; 00774 tmp2->priority = 1; 00775 00776 ast_jb_configure(tmp, &p->jb_conf); 00777 00778 return tmp; 00779 }
Definition at line 168 of file chan_local.c.
References ast_free, ast_mutex_destroy(), and local_pvt::lock.
Referenced by local_alloc(), local_hangup(), local_queue_frame(), and local_request().
00169 { 00170 ast_mutex_destroy(&pvt->lock); 00171 ast_free(pvt); 00172 return NULL; 00173 }
static int local_queue_frame | ( | struct local_pvt * | p, | |
int | isoutbound, | |||
struct ast_frame * | f, | |||
struct ast_channel * | us, | |||
int | us_locked | |||
) | [static] |
Definition at line 206 of file chan_local.c.
References ast_channel_trylock, ast_channel_unlock, ast_clear_flag, AST_CONTROL_RINGING, AST_FRAME_CONTROL, ast_mutex_lock(), ast_mutex_trylock(), ast_mutex_unlock(), ast_queue_frame(), ast_set_flag, ast_setstate(), AST_STATE_RINGING, ast_test_flag, local_pvt::chan, CHANNEL_DEADLOCK_AVOIDANCE, f, ast_channel::generator, LOCAL_CANCEL_QUEUE, LOCAL_GLARE_DETECT, local_pvt_destroy(), local_pvt::lock, and local_pvt::owner.
Referenced by local_answer(), local_digit_begin(), local_digit_end(), local_hangup(), local_indicate(), local_sendhtml(), local_sendtext(), and local_write().
00208 { 00209 struct ast_channel *other = NULL; 00210 00211 /* Recalculate outbound channel */ 00212 other = isoutbound ? p->owner : p->chan; 00213 00214 if (!other) { 00215 return 0; 00216 } 00217 00218 /* do not queue frame if generator is on both local channels */ 00219 if (us && us->generator && other->generator) { 00220 return 0; 00221 } 00222 00223 /* Set glare detection */ 00224 ast_set_flag(p, LOCAL_GLARE_DETECT); 00225 00226 /* Ensure that we have both channels locked */ 00227 while (other && ast_channel_trylock(other)) { 00228 ast_mutex_unlock(&p->lock); 00229 if (us && us_locked) { 00230 do { 00231 CHANNEL_DEADLOCK_AVOIDANCE(us); 00232 } while (ast_mutex_trylock(&p->lock)); 00233 } else { 00234 usleep(1); 00235 ast_mutex_lock(&p->lock); 00236 } 00237 other = isoutbound ? p->owner : p->chan; 00238 } 00239 00240 /* Since glare detection only occurs within this function, and because 00241 * a pvt flag cannot be set without having the pvt lock, this is the only 00242 * location where we could detect a cancelling of the queue. */ 00243 if (ast_test_flag(p, LOCAL_CANCEL_QUEUE)) { 00244 /* We had a glare on the hangup. Forget all this business, 00245 return and destroy p. */ 00246 ast_mutex_unlock(&p->lock); 00247 p = local_pvt_destroy(p); 00248 if (other) { 00249 ast_channel_unlock(other); 00250 } 00251 return -1; 00252 } 00253 00254 if (other) { 00255 if (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_RINGING) { 00256 ast_setstate(other, AST_STATE_RINGING); 00257 } 00258 ast_queue_frame(other, f); 00259 ast_channel_unlock(other); 00260 } 00261 00262 ast_clear_flag(p, LOCAL_GLARE_DETECT); 00263 00264 return 0; 00265 }
static struct ast_frame * local_read | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 341 of file chan_local.c.
References ast_null_frame.
00342 { 00343 return &ast_null_frame; 00344 }
static struct ast_channel * local_request | ( | const char * | type, | |
int | format, | |||
void * | data, | |||
int * | cause | |||
) | [static] |
Part of PBX interface.
Definition at line 782 of file chan_local.c.
References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, AST_STATE_DOWN, local_pvt::chan, local_pvt::list, local_alloc(), local_new(), and local_pvt_destroy().
00783 { 00784 struct local_pvt *p = NULL; 00785 struct ast_channel *chan = NULL; 00786 00787 /* Allocate a new private structure and then Asterisk channel */ 00788 if ((p = local_alloc(data, format))) { 00789 if (!(chan = local_new(p, AST_STATE_DOWN))) { 00790 AST_LIST_LOCK(&locals); 00791 AST_LIST_REMOVE(&locals, p, list); 00792 AST_LIST_UNLOCK(&locals); 00793 p = local_pvt_destroy(p); 00794 } 00795 } 00796 00797 return chan; 00798 }
static int local_sendhtml | ( | struct ast_channel * | ast, | |
int | subclass, | |||
const char * | data, | |||
int | datalen | |||
) | [static] |
Definition at line 480 of file chan_local.c.
References AST_FRAME_HTML, ast_mutex_lock(), ast_mutex_unlock(), f, IS_OUTBOUND, local_queue_frame(), local_pvt::lock, and ast_channel::tech_pvt.
00481 { 00482 struct local_pvt *p = ast->tech_pvt; 00483 int res = -1; 00484 struct ast_frame f = { AST_FRAME_HTML, }; 00485 int isoutbound; 00486 00487 if (!p) 00488 return -1; 00489 00490 ast_mutex_lock(&p->lock); 00491 isoutbound = IS_OUTBOUND(ast, p); 00492 f.subclass = subclass; 00493 f.data.ptr = (char *)data; 00494 f.datalen = datalen; 00495 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) 00496 ast_mutex_unlock(&p->lock); 00497 return res; 00498 }
static int local_sendtext | ( | struct ast_channel * | ast, | |
const char * | text | |||
) | [static] |
Definition at line 461 of file chan_local.c.
References AST_FRAME_TEXT, ast_mutex_lock(), ast_mutex_unlock(), f, IS_OUTBOUND, local_queue_frame(), local_pvt::lock, and ast_channel::tech_pvt.
00462 { 00463 struct local_pvt *p = ast->tech_pvt; 00464 int res = -1; 00465 struct ast_frame f = { AST_FRAME_TEXT, }; 00466 int isoutbound; 00467 00468 if (!p) 00469 return -1; 00470 00471 ast_mutex_lock(&p->lock); 00472 isoutbound = IS_OUTBOUND(ast, p); 00473 f.data.ptr = (char *) text; 00474 f.datalen = strlen(text) + 1; 00475 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) 00476 ast_mutex_unlock(&p->lock); 00477 return res; 00478 }
static int local_write | ( | struct ast_channel * | ast, | |
struct ast_frame * | f | |||
) | [static] |
Definition at line 346 of file chan_local.c.
References ast_debug, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_mutex_lock(), ast_mutex_unlock(), ast_test_flag, check_bridge(), f, IS_OUTBOUND, LOCAL_ALREADY_MASQED, local_queue_frame(), local_pvt::lock, ast_channel::name, and ast_channel::tech_pvt.
00347 { 00348 struct local_pvt *p = ast->tech_pvt; 00349 int res = -1; 00350 int isoutbound; 00351 00352 if (!p) 00353 return -1; 00354 00355 /* Just queue for delivery to the other side */ 00356 ast_mutex_lock(&p->lock); 00357 isoutbound = IS_OUTBOUND(ast, p); 00358 if (isoutbound && f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) 00359 check_bridge(p); 00360 if (!ast_test_flag(p, LOCAL_ALREADY_MASQED)) 00361 res = local_queue_frame(p, isoutbound, f, ast, 1); 00362 else { 00363 ast_debug(1, "Not posting to queue since already masked on '%s'\n", ast->name); 00364 res = 0; 00365 } 00366 if (!res) 00367 ast_mutex_unlock(&p->lock); 00368 return res; 00369 }
static char* locals_show | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
CLI command "local show channels".
Definition at line 801 of file chan_local.c.
References ast_cli_args::argc, ast_cli(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, local_pvt::context, local_pvt::exten, ast_cli_args::fd, local_pvt::list, local_pvt::lock, ast_channel::name, local_pvt::owner, and ast_cli_entry::usage.
00802 { 00803 struct local_pvt *p = NULL; 00804 00805 switch (cmd) { 00806 case CLI_INIT: 00807 e->command = "local show channels"; 00808 e->usage = 00809 "Usage: local show channels\n" 00810 " Provides summary information on active local proxy channels.\n"; 00811 return NULL; 00812 case CLI_GENERATE: 00813 return NULL; 00814 } 00815 00816 if (a->argc != 3) 00817 return CLI_SHOWUSAGE; 00818 00819 AST_LIST_LOCK(&locals); 00820 if (!AST_LIST_EMPTY(&locals)) { 00821 AST_LIST_TRAVERSE(&locals, p, list) { 00822 ast_mutex_lock(&p->lock); 00823 ast_cli(a->fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context); 00824 ast_mutex_unlock(&p->lock); 00825 } 00826 } else 00827 ast_cli(a->fd, "No local channels in use\n"); 00828 AST_LIST_UNLOCK(&locals); 00829 00830 return CLI_SUCCESS; 00831 }
static int unload_module | ( | void | ) | [static] |
Unload the local proxy channel from Asterisk.
Definition at line 850 of file chan_local.c.
References ast_channel_unregister(), ast_cli_unregister_multiple(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, cli_local, local_pvt::list, local_tech, locals, LOG_WARNING, and local_pvt::owner.
00851 { 00852 struct local_pvt *p = NULL; 00853 00854 /* First, take us out of the channel loop */ 00855 ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 00856 ast_channel_unregister(&local_tech); 00857 if (!AST_LIST_LOCK(&locals)) { 00858 /* Hangup all interfaces if they have an owner */ 00859 AST_LIST_TRAVERSE(&locals, p, list) { 00860 if (p->owner) 00861 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); 00862 } 00863 AST_LIST_UNLOCK(&locals); 00864 } else { 00865 ast_log(LOG_WARNING, "Unable to lock the monitor\n"); 00866 return -1; 00867 } 00868 return 0; 00869 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Local Proxy Channel (Note: used internally by other modules)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, } [static] |
Definition at line 871 of file chan_local.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 871 of file chan_local.c.
struct ast_cli_entry cli_local[] [static] |
Initial value:
{ { .handler = locals_show , .summary = "List status of local channels" ,__VA_ARGS__ }, }
Definition at line 833 of file chan_local.c.
Referenced by load_module(), and unload_module().
struct ast_jb_conf g_jb_conf [static] |
struct ast_channel_tech local_tech [static] |
Definition at line 81 of file chan_local.c.
Referenced by load_module(), local_new(), and unload_module().
const char tdesc[] = "Local Proxy Channel Driver" [static] |
Definition at line 53 of file chan_local.c.