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