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