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