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 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] |
Definition at line 878 of file chan_local.c.
00878 : used internally by other modules)");
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 878 of file chan_local.c.
00878 : used internally by other modules)");
| static void check_bridge | ( | struct local_pvt * | p, | |
| int | isoutbound | |||
| ) | [static] |
Definition at line 289 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().
00290 { 00291 struct ast_channel_monitor *tmp; 00292 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))) 00293 return; 00294 00295 /* only do the masquerade if we are being called on the outbound channel, 00296 if it has been bridged to another channel and if there are no pending 00297 frames on the owner channel (because they would be transferred to the 00298 outbound channel during the masquerade) 00299 */ 00300 if (isoutbound && p->chan->_bridge /* Not ast_bridged_channel! Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) { 00301 /* Masquerade bridged channel into owner */ 00302 /* Lock everything we need, one by one, and give up if 00303 we can't get everything. Remember, we'll get another 00304 chance in just a little bit */ 00305 if (!ast_channel_trylock(p->chan->_bridge)) { 00306 if (!ast_check_hangup(p->chan->_bridge)) { 00307 if (!ast_channel_trylock(p->owner)) { 00308 if (!ast_check_hangup(p->owner)) { 00309 if (p->owner->monitor && !p->chan->_bridge->monitor) { 00310 /* If a local channel is being monitored, we don't want a masquerade 00311 * to cause the monitor to go away. Since the masquerade swaps the monitors, 00312 * pre-swapping the monitors before the masquerade will ensure that the monitor 00313 * ends up where it is expected. 00314 */ 00315 tmp = p->owner->monitor; 00316 p->owner->monitor = p->chan->_bridge->monitor; 00317 p->chan->_bridge->monitor = tmp; 00318 } 00319 if (p->chan->audiohooks) { 00320 struct ast_audiohook_list *audiohooks_swapper; 00321 audiohooks_swapper = p->chan->audiohooks; 00322 p->chan->audiohooks = p->owner->audiohooks; 00323 p->owner->audiohooks = audiohooks_swapper; 00324 } 00325 ast_app_group_update(p->chan, p->owner); 00326 ast_channel_masquerade(p->owner, p->chan->_bridge); 00327 ast_set_flag(p, LOCAL_ALREADY_MASQED); 00328 } 00329 ast_channel_unlock(p->owner); 00330 } 00331 ast_channel_unlock(p->chan->_bridge); 00332 } 00333 } 00334 /* We only allow masquerading in one 'direction'... it's important to preserve the state 00335 (group variables, etc.) that live on p->chan->_bridge (and were put there by the dialplan) 00336 when the local channels go away. 00337 */ 00338 #if 0 00339 } else if (!isoutbound && p->owner && p->owner->_bridge && p->chan && AST_LIST_EMPTY(&p->chan->readq)) { 00340 /* Masquerade bridged channel into chan */ 00341 if (!ast_mutex_trylock(&(p->owner->_bridge)->lock)) { 00342 if (!ast_check_hangup(p->owner->_bridge)) { 00343 if (!ast_mutex_trylock(&p->chan->lock)) { 00344 if (!ast_check_hangup(p->chan)) { 00345 ast_channel_masquerade(p->chan, p->owner->_bridge); 00346 ast_set_flag(p, LOCAL_ALREADY_MASQED); 00347 } 00348 ast_mutex_unlock(&p->chan->lock); 00349 } 00350 } 00351 ast_mutex_unlock(&(p->owner->_bridge)->lock); 00352 } 00353 #endif 00354 } 00355 }
| static int load_module | ( | void | ) | [static] |
Load module into PBX, register channel.
Definition at line 845 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.
00846 { 00847 /* Make sure we can register our channel type */ 00848 if (ast_channel_register(&local_tech)) { 00849 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n"); 00850 return AST_MODULE_LOAD_FAILURE; 00851 } 00852 ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 00853 return AST_MODULE_LOAD_SUCCESS; 00854 }
| static struct local_pvt* local_alloc | ( | const char * | data, | |
| int | format | |||
| ) | [static, read] |
Create a call structure.
Definition at line 661 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().
00662 { 00663 struct local_pvt *tmp = NULL; 00664 char *c = NULL, *opts = NULL; 00665 00666 if (!(tmp = ast_calloc(1, sizeof(*tmp)))) 00667 return NULL; 00668 00669 /* Initialize private structure information */ 00670 ast_mutex_init(&tmp->lock); 00671 ast_copy_string(tmp->exten, data, sizeof(tmp->exten)); 00672 00673 memcpy(&tmp->jb_conf, &g_jb_conf, sizeof(tmp->jb_conf)); 00674 00675 /* Look for options */ 00676 if ((opts = strchr(tmp->exten, '/'))) { 00677 *opts++ = '\0'; 00678 if (strchr(opts, 'n')) 00679 ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION); 00680 if (strchr(opts, 'j')) { 00681 if (ast_test_flag(tmp, LOCAL_NO_OPTIMIZATION)) 00682 ast_set_flag(&tmp->jb_conf, AST_JB_ENABLED); 00683 else { 00684 ast_log(LOG_ERROR, "You must use the 'n' option for chan_local " 00685 "to use the 'j' option to enable the jitterbuffer\n"); 00686 } 00687 } 00688 if (strchr(opts, 'b')) { 00689 ast_set_flag(tmp, LOCAL_BRIDGE); 00690 } 00691 if (strchr(opts, 'm')) { 00692 ast_set_flag(tmp, LOCAL_MOH_PASSTHRU); 00693 } 00694 } 00695 00696 /* Look for a context */ 00697 if ((c = strchr(tmp->exten, '@'))) 00698 *c++ = '\0'; 00699 00700 ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context)); 00701 00702 tmp->reqformat = format; 00703 00704 #if 0 00705 /* We can't do this check here, because we don't know the CallerID yet, and 00706 * the CallerID could potentially affect what step is actually taken (or 00707 * even if that step exists). */ 00708 if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) { 00709 ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context); 00710 tmp = local_pvt_destroy(tmp); 00711 } else { 00712 #endif 00713 /* Add to list */ 00714 AST_LIST_LOCK(&locals); 00715 AST_LIST_INSERT_HEAD(&locals, tmp, list); 00716 AST_LIST_UNLOCK(&locals); 00717 #if 0 00718 } 00719 #endif 00720 00721 return tmp; 00722 }
| 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, read] |
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, 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 518 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.
00519 { 00520 struct local_pvt *p = ast->tech_pvt; 00521 int res; 00522 struct ast_var_t *varptr = NULL, *new; 00523 size_t len, namelen; 00524 00525 if (!p) 00526 return -1; 00527 00528 ast_mutex_lock(&p->lock); 00529 00530 /* 00531 * Note that cid_num and cid_name aren't passed in the ast_channel_alloc 00532 * call, so it's done here instead. 00533 */ 00534 p->chan->cid.cid_dnid = ast_strdup(p->owner->cid.cid_dnid); 00535 p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num); 00536 p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name); 00537 p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis); 00538 p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani); 00539 p->chan->cid.cid_pres = p->owner->cid.cid_pres; 00540 p->chan->cid.cid_ani2 = p->owner->cid.cid_ani2; 00541 p->chan->cid.cid_ton = p->owner->cid.cid_ton; 00542 p->chan->cid.cid_tns = p->owner->cid.cid_tns; 00543 ast_string_field_set(p->chan, language, p->owner->language); 00544 ast_string_field_set(p->chan, accountcode, p->owner->accountcode); 00545 ast_string_field_set(p->chan, musicclass, p->owner->musicclass); 00546 ast_cdr_update(p->chan); 00547 p->chan->cdrflags = p->owner->cdrflags; 00548 00549 if (!ast_exists_extension(NULL, p->chan->context, p->chan->exten, 1, p->owner->cid.cid_num)) { 00550 ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->chan->exten, p->chan->context); 00551 ast_mutex_unlock(&p->lock); 00552 return -1; 00553 } 00554 00555 /* copy the channel variables from the incoming channel to the outgoing channel */ 00556 /* Note that due to certain assumptions, they MUST be in the same order */ 00557 AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) { 00558 namelen = strlen(varptr->name); 00559 len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2; 00560 if ((new = ast_calloc(1, len))) { 00561 memcpy(new, varptr, len); 00562 new->value = &(new->name[0]) + namelen + 1; 00563 AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries); 00564 } 00565 } 00566 ast_channel_datastore_inherit(p->owner, p->chan); 00567 00568 /* Start switch on sub channel */ 00569 if (!(res = ast_pbx_start(p->chan))) 00570 ast_set_flag(p, LOCAL_LAUNCHED_PBX); 00571 00572 ast_mutex_unlock(&p->lock); 00573 return res; 00574 }
| 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, 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 438 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.
00439 { 00440 struct local_pvt *p = ast->tech_pvt; 00441 int res = -1; 00442 struct ast_frame f = { AST_FRAME_DTMF_BEGIN, }; 00443 int isoutbound; 00444 00445 if (!p) 00446 return -1; 00447 00448 ast_mutex_lock(&p->lock); 00449 isoutbound = IS_OUTBOUND(ast, p); 00450 f.subclass = digit; 00451 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) 00452 ast_mutex_unlock(&p->lock); 00453 00454 return res; 00455 }
| static int local_digit_end | ( | struct ast_channel * | ast, | |
| char | digit, | |||
| unsigned int | duration | |||
| ) | [static] |
Definition at line 457 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.
00458 { 00459 struct local_pvt *p = ast->tech_pvt; 00460 int res = -1; 00461 struct ast_frame f = { AST_FRAME_DTMF_END, }; 00462 int isoutbound; 00463 00464 if (!p) 00465 return -1; 00466 00467 ast_mutex_lock(&p->lock); 00468 isoutbound = IS_OUTBOUND(ast, p); 00469 f.subclass = digit; 00470 f.len = duration; 00471 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) 00472 ast_mutex_unlock(&p->lock); 00473 00474 return res; 00475 }
| static int local_fixup | ( | struct ast_channel * | oldchan, | |
| struct ast_channel * | newchan | |||
| ) | [static] |
Definition at line 387 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.
00388 { 00389 struct local_pvt *p = newchan->tech_pvt; 00390 00391 if (!p) 00392 return -1; 00393 00394 ast_mutex_lock(&p->lock); 00395 00396 if ((p->owner != oldchan) && (p->chan != oldchan)) { 00397 ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan); 00398 ast_mutex_unlock(&p->lock); 00399 return -1; 00400 } 00401 if (p->owner == oldchan) 00402 p->owner = newchan; 00403 else 00404 p->chan = newchan; 00405 ast_mutex_unlock(&p->lock); 00406 return 0; 00407 }
| static int local_hangup | ( | struct ast_channel * | ast | ) | [static] |
Hangup a call through the local proxy channel.
Definition at line 577 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.
00578 { 00579 struct local_pvt *p = ast->tech_pvt; 00580 int isoutbound; 00581 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP, .data.uint32 = ast->hangupcause }; 00582 struct ast_channel *ochan = NULL; 00583 int glaredetect = 0, res = 0; 00584 00585 if (!p) 00586 return -1; 00587 00588 ast_mutex_lock(&p->lock); 00589 00590 if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) 00591 ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE); 00592 isoutbound = IS_OUTBOUND(ast, p); 00593 if (isoutbound) { 00594 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS"); 00595 if ((status) && (p->owner)) { 00596 /* Deadlock avoidance */ 00597 while (p->owner && ast_channel_trylock(p->owner)) { 00598 ast_mutex_unlock(&p->lock); 00599 if (ast) { 00600 ast_channel_unlock(ast); 00601 } 00602 usleep(1); 00603 if (ast) { 00604 ast_channel_lock(ast); 00605 } 00606 ast_mutex_lock(&p->lock); 00607 } 00608 if (p->owner) { 00609 pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status); 00610 ast_channel_unlock(p->owner); 00611 } 00612 } 00613 p->chan = NULL; 00614 ast_clear_flag(p, LOCAL_LAUNCHED_PBX); 00615 ast_module_user_remove(p->u_chan); 00616 } else { 00617 ast_module_user_remove(p->u_owner); 00618 while (p->chan && ast_channel_trylock(p->chan)) { 00619 DEADLOCK_AVOIDANCE(&p->lock); 00620 } 00621 p->owner = NULL; 00622 if (p->chan) { 00623 ast_queue_hangup(p->chan); 00624 ast_channel_unlock(p->chan); 00625 } 00626 } 00627 00628 ast->tech_pvt = NULL; 00629 00630 if (!p->owner && !p->chan) { 00631 /* Okay, done with the private part now, too. */ 00632 glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT); 00633 /* If we have a queue holding, don't actually destroy p yet, but 00634 let local_queue do it. */ 00635 if (glaredetect) 00636 ast_set_flag(p, LOCAL_CANCEL_QUEUE); 00637 /* Remove from list */ 00638 AST_LIST_LOCK(&locals); 00639 AST_LIST_REMOVE(&locals, p, list); 00640 AST_LIST_UNLOCK(&locals); 00641 ast_mutex_unlock(&p->lock); 00642 /* And destroy */ 00643 if (!glaredetect) { 00644 p = local_pvt_destroy(p); 00645 } 00646 return 0; 00647 } 00648 if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) 00649 /* Need to actually hangup since there is no PBX */ 00650 ochan = p->chan; 00651 else 00652 res = local_queue_frame(p, isoutbound, &f, NULL, 1); 00653 if (!res) 00654 ast_mutex_unlock(&p->lock); 00655 if (ochan) 00656 ast_hangup(ochan); 00657 return 0; 00658 }
| static int local_indicate | ( | struct ast_channel * | ast, | |
| int | condition, | |||
| const void * | data, | |||
| size_t | datalen | |||
| ) | [static] |
Definition at line 409 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.
00410 { 00411 struct local_pvt *p = ast->tech_pvt; 00412 int res = 0; 00413 struct ast_frame f = { AST_FRAME_CONTROL, }; 00414 int isoutbound; 00415 00416 if (!p) 00417 return -1; 00418 00419 /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */ 00420 if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) { 00421 ast_moh_start(ast, data, NULL); 00422 } else if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_UNHOLD) { 00423 ast_moh_stop(ast); 00424 } else { 00425 /* Queue up a frame representing the indication as a control frame */ 00426 ast_mutex_lock(&p->lock); 00427 isoutbound = IS_OUTBOUND(ast, p); 00428 f.subclass = condition; 00429 f.data.ptr = (void*)data; 00430 f.datalen = datalen; 00431 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 1))) 00432 ast_mutex_unlock(&p->lock); 00433 } 00434 00435 return res; 00436 }
| static struct ast_channel* local_new | ( | struct local_pvt * | p, | |
| int | state | |||
| ) | [static, read] |
Start new local channel.
Definition at line 725 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().
00726 { 00727 struct ast_channel *tmp = NULL, *tmp2 = NULL; 00728 int randnum = ast_random() & 0xffff, fmt = 0; 00729 const char *t; 00730 int ama; 00731 00732 /* Allocate two new Asterisk channels */ 00733 /* safe accountcode */ 00734 if (p->owner && p->owner->accountcode) 00735 t = p->owner->accountcode; 00736 else 00737 t = ""; 00738 00739 if (p->owner) 00740 ama = p->owner->amaflags; 00741 else 00742 ama = 0; 00743 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)) 00744 || !(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))) { 00745 if (tmp) 00746 ast_channel_free(tmp); 00747 if (tmp2) 00748 ast_channel_free(tmp2); 00749 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n"); 00750 return NULL; 00751 } 00752 00753 tmp2->tech = tmp->tech = &local_tech; 00754 00755 tmp->nativeformats = p->reqformat; 00756 tmp2->nativeformats = p->reqformat; 00757 00758 /* Determine our read/write format and set it on each channel */ 00759 fmt = ast_best_codec(p->reqformat); 00760 tmp->writeformat = fmt; 00761 tmp2->writeformat = fmt; 00762 tmp->rawwriteformat = fmt; 00763 tmp2->rawwriteformat = fmt; 00764 tmp->readformat = fmt; 00765 tmp2->readformat = fmt; 00766 tmp->rawreadformat = fmt; 00767 tmp2->rawreadformat = fmt; 00768 00769 tmp->tech_pvt = p; 00770 tmp2->tech_pvt = p; 00771 00772 p->owner = tmp; 00773 p->chan = tmp2; 00774 p->u_owner = ast_module_user_add(p->owner); 00775 p->u_chan = ast_module_user_add(p->chan); 00776 00777 ast_copy_string(tmp->context, p->context, sizeof(tmp->context)); 00778 ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context)); 00779 ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten)); 00780 tmp->priority = 1; 00781 tmp2->priority = 1; 00782 00783 ast_jb_configure(tmp, &p->jb_conf); 00784 00785 return tmp; 00786 }
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, ast_frame::frametype, ast_channel::generator, LOCAL_CANCEL_QUEUE, LOCAL_GLARE_DETECT, local_pvt_destroy(), local_pvt::lock, local_pvt::owner, and ast_frame::subclass.
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, read] |
Definition at line 357 of file chan_local.c.
References ast_null_frame.
00358 { 00359 return &ast_null_frame; 00360 }
| static struct ast_channel * local_request | ( | const char * | type, | |
| int | format, | |||
| void * | data, | |||
| int * | cause | |||
| ) | [static, read] |
Part of PBX interface.
Definition at line 789 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().
00790 { 00791 struct local_pvt *p = NULL; 00792 struct ast_channel *chan = NULL; 00793 00794 /* Allocate a new private structure and then Asterisk channel */ 00795 if ((p = local_alloc(data, format))) { 00796 if (!(chan = local_new(p, AST_STATE_DOWN))) { 00797 AST_LIST_LOCK(&locals); 00798 AST_LIST_REMOVE(&locals, p, list); 00799 AST_LIST_UNLOCK(&locals); 00800 p = local_pvt_destroy(p); 00801 } 00802 } 00803 00804 return chan; 00805 }
| static int local_sendhtml | ( | struct ast_channel * | ast, | |
| int | subclass, | |||
| const char * | data, | |||
| int | datalen | |||
| ) | [static] |
Definition at line 496 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.
00497 { 00498 struct local_pvt *p = ast->tech_pvt; 00499 int res = -1; 00500 struct ast_frame f = { AST_FRAME_HTML, }; 00501 int isoutbound; 00502 00503 if (!p) 00504 return -1; 00505 00506 ast_mutex_lock(&p->lock); 00507 isoutbound = IS_OUTBOUND(ast, p); 00508 f.subclass = subclass; 00509 f.data.ptr = (char *)data; 00510 f.datalen = datalen; 00511 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) 00512 ast_mutex_unlock(&p->lock); 00513 return res; 00514 }
| static int local_sendtext | ( | struct ast_channel * | ast, | |
| const char * | text | |||
| ) | [static] |
Definition at line 477 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.
00478 { 00479 struct local_pvt *p = ast->tech_pvt; 00480 int res = -1; 00481 struct ast_frame f = { AST_FRAME_TEXT, }; 00482 int isoutbound; 00483 00484 if (!p) 00485 return -1; 00486 00487 ast_mutex_lock(&p->lock); 00488 isoutbound = IS_OUTBOUND(ast, p); 00489 f.data.ptr = (char *) text; 00490 f.datalen = strlen(text) + 1; 00491 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) 00492 ast_mutex_unlock(&p->lock); 00493 return res; 00494 }
| static int local_write | ( | struct ast_channel * | ast, | |
| struct ast_frame * | f | |||
| ) | [static] |
Definition at line 362 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.
00363 { 00364 struct local_pvt *p = ast->tech_pvt; 00365 int res = -1; 00366 int isoutbound; 00367 00368 if (!p) 00369 return -1; 00370 00371 /* Just queue for delivery to the other side */ 00372 ast_mutex_lock(&p->lock); 00373 isoutbound = IS_OUTBOUND(ast, p); 00374 if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) 00375 check_bridge(p, isoutbound); 00376 if (!ast_test_flag(p, LOCAL_ALREADY_MASQED)) 00377 res = local_queue_frame(p, isoutbound, f, ast, 1); 00378 else { 00379 ast_debug(1, "Not posting to queue since already masked on '%s'\n", ast->name); 00380 res = 0; 00381 } 00382 if (!res) 00383 ast_mutex_unlock(&p->lock); 00384 return res; 00385 }
| 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 808 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.
00809 { 00810 struct local_pvt *p = NULL; 00811 00812 switch (cmd) { 00813 case CLI_INIT: 00814 e->command = "local show channels"; 00815 e->usage = 00816 "Usage: local show channels\n" 00817 " Provides summary information on active local proxy channels.\n"; 00818 return NULL; 00819 case CLI_GENERATE: 00820 return NULL; 00821 } 00822 00823 if (a->argc != 3) 00824 return CLI_SHOWUSAGE; 00825 00826 AST_LIST_LOCK(&locals); 00827 if (!AST_LIST_EMPTY(&locals)) { 00828 AST_LIST_TRAVERSE(&locals, p, list) { 00829 ast_mutex_lock(&p->lock); 00830 ast_cli(a->fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context); 00831 ast_mutex_unlock(&p->lock); 00832 } 00833 } else 00834 ast_cli(a->fd, "No local channels in use\n"); 00835 AST_LIST_UNLOCK(&locals); 00836 00837 return CLI_SUCCESS; 00838 }
| static int unload_module | ( | void | ) | [static] |
Unload the local proxy channel from Asterisk.
Definition at line 857 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.
00858 { 00859 struct local_pvt *p = NULL; 00860 00861 /* First, take us out of the channel loop */ 00862 ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 00863 ast_channel_unregister(&local_tech); 00864 if (!AST_LIST_LOCK(&locals)) { 00865 /* Hangup all interfaces if they have an owner */ 00866 AST_LIST_TRAVERSE(&locals, p, list) { 00867 if (p->owner) 00868 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); 00869 } 00870 AST_LIST_UNLOCK(&locals); 00871 } else { 00872 ast_log(LOG_WARNING, "Unable to lock the monitor\n"); 00873 return -1; 00874 } 00875 return 0; 00876 }
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 878 of file chan_local.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 878 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 840 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 81 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