#include "asterisk.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/signal.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/logger.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/options.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_MOH_PASSTHRU (1 << 5) |
#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 int | locals_show (int fd, int argc, char **argv) |
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 | AST_MODFLAG_BUILDSUM, .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 = "6989f2ec67f8497e38c12890500c525b" , .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_channel_tech | local_tech |
static char | show_locals_usage [] |
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 67 of file chan_local.c.
#define LOCAL_ALREADY_MASQED (1 << 2) |
Already masqueraded
Definition at line 120 of file chan_local.c.
Referenced by check_bridge(), and local_write().
#define LOCAL_CANCEL_QUEUE (1 << 1) |
Cancel queue
Definition at line 119 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 118 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 121 of file chan_local.c.
Referenced by local_call(), and local_hangup().
#define LOCAL_MOH_PASSTHRU (1 << 5) |
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 122 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 246 of file chan_local.c.
References ast_channel::_bridge, ast_channel::_softhangup, ast_app_group_update(), ast_bridged_channel(), ast_channel_masquerade(), 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::lock, ast_channel::monitor, local_pvt::owner, and ast_channel::readq.
Referenced by local_write().
00247 { 00248 struct ast_channel_monitor *tmp; 00249 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))) 00250 return; 00251 00252 /* only do the masquerade if we are being called on the outbound channel, 00253 if it has been bridged to another channel and if there are no pending 00254 frames on the owner channel (because they would be transferred to the 00255 outbound channel during the masquerade) 00256 */ 00257 if (isoutbound && p->chan->_bridge /* Not ast_bridged_channel! Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) { 00258 /* Masquerade bridged channel into owner */ 00259 /* Lock everything we need, one by one, and give up if 00260 we can't get everything. Remember, we'll get another 00261 chance in just a little bit */ 00262 if (!ast_mutex_trylock(&(p->chan->_bridge)->lock)) { 00263 if (!p->chan->_bridge->_softhangup) { 00264 if (!ast_mutex_trylock(&p->owner->lock)) { 00265 if (!p->owner->_softhangup) { 00266 if (p->owner->monitor && !p->chan->_bridge->monitor) { 00267 /* If a local channel is being monitored, we don't want a masquerade 00268 * to cause the monitor to go away. Since the masquerade swaps the monitors, 00269 * pre-swapping the monitors before the masquerade will ensure that the monitor 00270 * ends up where it is expected. 00271 */ 00272 tmp = p->owner->monitor; 00273 p->owner->monitor = p->chan->_bridge->monitor; 00274 p->chan->_bridge->monitor = tmp; 00275 } 00276 if (p->chan->audiohooks) { 00277 struct ast_audiohook_list *audiohooks_swapper; 00278 audiohooks_swapper = p->chan->audiohooks; 00279 p->chan->audiohooks = p->owner->audiohooks; 00280 p->owner->audiohooks = audiohooks_swapper; 00281 } 00282 ast_app_group_update(p->chan, p->owner); 00283 ast_channel_masquerade(p->owner, p->chan->_bridge); 00284 ast_set_flag(p, LOCAL_ALREADY_MASQED); 00285 } 00286 ast_mutex_unlock(&p->owner->lock); 00287 } 00288 ast_mutex_unlock(&(p->chan->_bridge)->lock); 00289 } 00290 } 00291 /* We only allow masquerading in one 'direction'... it's important to preserve the state 00292 (group variables, etc.) that live on p->chan->_bridge (and were put there by the dialplan) 00293 when the local channels go away. 00294 */ 00295 #if 0 00296 } else if (!isoutbound && p->owner && p->owner->_bridge && p->chan && AST_LIST_EMPTY(&p->chan->readq)) { 00297 /* Masquerade bridged channel into chan */ 00298 if (!ast_mutex_trylock(&(p->owner->_bridge)->lock)) { 00299 if (!p->owner->_bridge->_softhangup) { 00300 if (!ast_mutex_trylock(&p->chan->lock)) { 00301 if (!p->chan->_softhangup) { 00302 ast_channel_masquerade(p->chan, p->owner->_bridge); 00303 ast_set_flag(p, LOCAL_ALREADY_MASQED); 00304 } 00305 ast_mutex_unlock(&p->chan->lock); 00306 } 00307 } 00308 ast_mutex_unlock(&(p->owner->_bridge)->lock); 00309 } 00310 #endif 00311 } 00312 }
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(), 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 -1; 00790 } 00791 ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 00792 return 0; 00793 }
static struct local_pvt* local_alloc | ( | const char * | data, | |
int | format | |||
) | [static] |
Create a call structure.
Definition at line 621 of file chan_local.c.
References ast_calloc, ast_copy_string(), ast_exists_extension(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_mutex_init, ast_set_flag, local_pvt::list, LOCAL_MOH_PASSTHRU, LOCAL_NO_OPTIMIZATION, local_pvt_destroy(), and LOG_NOTICE.
Referenced by local_request().
00622 { 00623 struct local_pvt *tmp = NULL; 00624 char *c = NULL, *opts = NULL; 00625 00626 if (!(tmp = ast_calloc(1, sizeof(*tmp)))) 00627 return NULL; 00628 00629 /* Initialize private structure information */ 00630 ast_mutex_init(&tmp->lock); 00631 ast_copy_string(tmp->exten, data, sizeof(tmp->exten)); 00632 00633 /* Look for options */ 00634 if ((opts = strchr(tmp->exten, '/'))) { 00635 *opts++ = '\0'; 00636 if (strchr(opts, 'n')) 00637 ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION); 00638 if (strchr(opts, 'm')) 00639 ast_set_flag(tmp, LOCAL_MOH_PASSTHRU); 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 0 00651 /* We can't do this check here, because we don't know the CallerID yet, and 00652 * the CallerID could potentially affect what step is actually taken (or 00653 * even if that step exists). */ 00654 if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) { 00655 ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context); 00656 tmp = local_pvt_destroy(tmp); 00657 } else { 00658 #endif 00659 /* Add to list */ 00660 AST_LIST_LOCK(&locals); 00661 AST_LIST_INSERT_HEAD(&locals, tmp, list); 00662 AST_LIST_UNLOCK(&locals); 00663 #if 0 00664 } 00665 #endif 00666 00667 return tmp; 00668 }
static int local_answer | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 224 of file chan_local.c.
References answer, 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.
00225 { 00226 struct local_pvt *p = ast->tech_pvt; 00227 int isoutbound; 00228 int res = -1; 00229 00230 if (!p) 00231 return -1; 00232 00233 ast_mutex_lock(&p->lock); 00234 isoutbound = IS_OUTBOUND(ast, p); 00235 if (isoutbound) { 00236 /* Pass along answer since somebody answered us */ 00237 struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER }; 00238 res = local_queue_frame(p, isoutbound, &answer, ast, 1); 00239 } else 00240 ast_log(LOG_WARNING, "Huh? Local is being asked to answer?\n"); 00241 if (!res) 00242 ast_mutex_unlock(&p->lock); 00243 return res; 00244 }
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_exists_extension(), AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_pbx_start(), ast_set_flag, ast_strdup, ast_string_field_set, ast_channel::cdrflags, local_pvt::chan, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_ani2, ast_callerid::cid_dnid, ast_callerid::cid_name, ast_callerid::cid_num, ast_callerid::cid_pres, ast_callerid::cid_rdnis, ast_callerid::cid_tns, ast_callerid::cid_ton, ast_channel::context, ast_var_t::entries, ast_channel::exten, ast_channel::language, language, len(), LOCAL_LAUNCHED_PBX, local_pvt::lock, LOG_NOTICE, ast_channel::musicclass, musicclass, ast_var_t::name, local_pvt::owner, ast_channel::tech_pvt, ast_var_t::value, and ast_channel::varshead.
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 if (!ast_exists_extension(NULL, p->chan->context, p->chan->exten, 1, p->owner->cid.cid_num)) { 00508 ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->chan->exten, p->chan->context); 00509 ast_mutex_unlock(&p->lock); 00510 return -1; 00511 } 00512 00513 /* copy the channel variables from the incoming channel to the outgoing channel */ 00514 /* Note that due to certain assumptions, they MUST be in the same order */ 00515 AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) { 00516 namelen = strlen(varptr->name); 00517 len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2; 00518 if ((new = ast_calloc(1, len))) { 00519 memcpy(new, varptr, len); 00520 new->value = &(new->name[0]) + namelen + 1; 00521 AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries); 00522 } 00523 } 00524 ast_channel_datastore_inherit(p->owner, p->chan); 00525 00526 /* Start switch on sub channel */ 00527 if (!(res = ast_pbx_start(p->chan))) 00528 ast_set_flag(p, LOCAL_LAUNCHED_PBX); 00529 00530 ast_mutex_unlock(&p->lock); 00531 return res; 00532 }
static int local_devicestate | ( | void * | data | ) | [static] |
Adds devicestate to local channels.
Definition at line 128 of file chan_local.c.
References AST_DEVICE_INVALID, AST_DEVICE_UNKNOWN, ast_exists_extension(), ast_log(), ast_strdupa, local_pvt::context, local_pvt::exten, LOG_DEBUG, LOG_WARNING, and option_debug.
00129 { 00130 char *exten = ast_strdupa(data); 00131 char *context = NULL, *opts = NULL; 00132 int res; 00133 00134 if (!(context = strchr(exten, '@'))) { 00135 ast_log(LOG_WARNING, "Someone used Local/%s somewhere without a @context. This is bad.\n", exten); 00136 return AST_DEVICE_INVALID; 00137 } 00138 00139 *context++ = '\0'; 00140 00141 /* Strip options if they exist */ 00142 if ((opts = strchr(context, '/'))) 00143 *opts = '\0'; 00144 00145 if (option_debug > 2) 00146 ast_log(LOG_DEBUG, "Checking if extension %s@%s exists (devicestate)\n", exten, context); 00147 res = ast_exists_extension(NULL, context, exten, 1, NULL); 00148 if (!res) 00149 return AST_DEVICE_INVALID; 00150 else 00151 return AST_DEVICE_UNKNOWN; 00152 }
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 535 of file chan_local.c.
References ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_clear_flag, AST_CONTROL_HANGUP, AST_FRAME_CONTROL, ast_hangup(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_module_user_remove, ast_mutex_lock, ast_mutex_trylock, 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(), ast_channel::tech_pvt, local_pvt::u_chan, and local_pvt::u_owner.
00536 { 00537 struct local_pvt *p = ast->tech_pvt; 00538 int isoutbound; 00539 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP }; 00540 struct ast_channel *ochan = NULL; 00541 int glaredetect = 0, res = 0; 00542 00543 if (!p) 00544 return -1; 00545 00546 while (ast_mutex_trylock(&p->lock)) { 00547 ast_channel_unlock(ast); 00548 usleep(1); 00549 ast_channel_lock(ast); 00550 } 00551 00552 isoutbound = IS_OUTBOUND(ast, p); 00553 if (isoutbound) { 00554 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS"); 00555 if ((status) && (p->owner)) { 00556 /* Deadlock avoidance */ 00557 while (p->owner && ast_channel_trylock(p->owner)) { 00558 ast_mutex_unlock(&p->lock); 00559 if (ast) { 00560 ast_channel_unlock(ast); 00561 } 00562 usleep(1); 00563 if (ast) { 00564 ast_channel_lock(ast); 00565 } 00566 ast_mutex_lock(&p->lock); 00567 } 00568 if (p->owner) { 00569 pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status); 00570 ast_channel_unlock(p->owner); 00571 } 00572 } 00573 p->chan = NULL; 00574 ast_clear_flag(p, LOCAL_LAUNCHED_PBX); 00575 ast_module_user_remove(p->u_chan); 00576 } else { 00577 p->owner = NULL; 00578 ast_module_user_remove(p->u_owner); 00579 while (p->chan && ast_channel_trylock(p->chan)) { 00580 DEADLOCK_AVOIDANCE(&p->lock); 00581 } 00582 if (p->chan) { 00583 ast_queue_hangup(p->chan); 00584 ast_channel_unlock(p->chan); 00585 } 00586 } 00587 00588 ast->tech_pvt = NULL; 00589 00590 if (!p->owner && !p->chan) { 00591 /* Okay, done with the private part now, too. */ 00592 glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT); 00593 /* If we have a queue holding, don't actually destroy p yet, but 00594 let local_queue do it. */ 00595 if (glaredetect) 00596 ast_set_flag(p, LOCAL_CANCEL_QUEUE); 00597 /* Remove from list */ 00598 AST_LIST_LOCK(&locals); 00599 AST_LIST_REMOVE(&locals, p, list); 00600 AST_LIST_UNLOCK(&locals); 00601 ast_mutex_unlock(&p->lock); 00602 /* And destroy */ 00603 if (!glaredetect) { 00604 p = local_pvt_destroy(p); 00605 } 00606 return 0; 00607 } 00608 if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) 00609 /* Need to actually hangup since there is no PBX */ 00610 ochan = p->chan; 00611 else 00612 res = local_queue_frame(p, isoutbound, &f, NULL, 1); 00613 if (!res) 00614 ast_mutex_unlock(&p->lock); 00615 if (ochan) 00616 ast_hangup(ochan); 00617 return 0; 00618 }
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, ast_test_flag, f, IS_OUTBOUND, LOCAL_MOH_PASSTHRU, 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 (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) { 00379 ast_moh_start(ast, data, NULL); 00380 } else if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && 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 671 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_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_tech, LOG_WARNING, ast_channel::nativeformats, local_pvt::owner, ast_channel::priority, ast_channel::rawreadformat, ast_channel::rawwriteformat, ast_channel::readformat, local_pvt::reqformat, t, ast_channel::tech, ast_channel::tech_pvt, local_pvt::u_chan, local_pvt::u_owner, and ast_channel::writeformat.
Referenced by local_request().
00672 { 00673 struct ast_channel *tmp = NULL, *tmp2 = NULL; 00674 int randnum = ast_random() & 0xffff, fmt = 0; 00675 const char *t; 00676 int ama; 00677 00678 /* Allocate two new Asterisk channels */ 00679 /* safe accountcode */ 00680 if (p->owner && p->owner->accountcode) 00681 t = p->owner->accountcode; 00682 else 00683 t = ""; 00684 00685 if (p->owner) 00686 ama = p->owner->amaflags; 00687 else 00688 ama = 0; 00689 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)) 00690 || !(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))) { 00691 if (tmp) 00692 ast_channel_free(tmp); 00693 if (tmp2) 00694 ast_channel_free(tmp2); 00695 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n"); 00696 return NULL; 00697 } 00698 00699 tmp2->tech = tmp->tech = &local_tech; 00700 00701 tmp->nativeformats = p->reqformat; 00702 tmp2->nativeformats = p->reqformat; 00703 00704 /* Determine our read/write format and set it on each channel */ 00705 fmt = ast_best_codec(p->reqformat); 00706 tmp->writeformat = fmt; 00707 tmp2->writeformat = fmt; 00708 tmp->rawwriteformat = fmt; 00709 tmp2->rawwriteformat = fmt; 00710 tmp->readformat = fmt; 00711 tmp2->readformat = fmt; 00712 tmp->rawreadformat = fmt; 00713 tmp2->rawreadformat = fmt; 00714 00715 tmp->tech_pvt = p; 00716 tmp2->tech_pvt = p; 00717 00718 p->owner = tmp; 00719 p->chan = tmp2; 00720 p->u_owner = ast_module_user_add(p->owner); 00721 p->u_chan = ast_module_user_add(p->chan); 00722 00723 ast_copy_string(tmp->context, p->context, sizeof(tmp->context)); 00724 ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context)); 00725 ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten)); 00726 tmp->priority = 1; 00727 tmp2->priority = 1; 00728 00729 return tmp; 00730 }
Definition at line 157 of file chan_local.c.
References ast_mutex_destroy, free, and local_pvt::lock.
Referenced by local_alloc(), local_hangup(), local_queue_frame(), and local_request().
00158 { 00159 ast_mutex_destroy(&pvt->lock); 00160 free(pvt); 00161 return NULL; 00162 }
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 164 of file chan_local.c.
References ast_channel_lock, 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, 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().
00166 { 00167 struct ast_channel *other = NULL; 00168 00169 /* Recalculate outbound channel */ 00170 other = isoutbound ? p->owner : p->chan; 00171 00172 if (!other) { 00173 return 0; 00174 } 00175 00176 /* do not queue frame if generator is on both local channels */ 00177 if (us && us->generator && other->generator) { 00178 return 0; 00179 } 00180 00181 /* Set glare detection */ 00182 ast_set_flag(p, LOCAL_GLARE_DETECT); 00183 00184 /* Ensure that we have both channels locked */ 00185 while (other && ast_channel_trylock(other)) { 00186 ast_mutex_unlock(&p->lock); 00187 if (us && us_locked) { 00188 do { 00189 ast_channel_unlock(us); 00190 usleep(1); 00191 ast_channel_lock(us); 00192 } while (ast_mutex_trylock(&p->lock)); 00193 } else { 00194 usleep(1); 00195 ast_mutex_lock(&p->lock); 00196 } 00197 other = isoutbound ? p->owner : p->chan; 00198 } 00199 00200 /* Since glare detection only occurs within this function, and because 00201 * a pvt flag cannot be set without having the pvt lock, this is the only 00202 * location where we could detect a cancelling of the queue. */ 00203 if (ast_test_flag(p, LOCAL_CANCEL_QUEUE)) { 00204 /* We had a glare on the hangup. Forget all this business, 00205 return and destroy p. */ 00206 ast_mutex_unlock(&p->lock); 00207 p = local_pvt_destroy(p); 00208 if (other) { 00209 ast_channel_unlock(other); 00210 } 00211 return -1; 00212 } 00213 00214 if (other) { 00215 ast_queue_frame(other, f); 00216 ast_channel_unlock(other); 00217 } 00218 00219 ast_clear_flag(p, LOCAL_GLARE_DETECT); 00220 00221 return 0; 00222 }
static struct ast_frame * local_read | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 314 of file chan_local.c.
References ast_null_frame.
00315 { 00316 return &ast_null_frame; 00317 }
static struct ast_channel * local_request | ( | const char * | type, | |
int | format, | |||
void * | data, | |||
int * | cause | |||
) | [static] |
Part of PBX interface.
Definition at line 733 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().
00734 { 00735 struct local_pvt *p = NULL; 00736 struct ast_channel *chan = NULL; 00737 00738 /* Allocate a new private structure and then Asterisk channel */ 00739 if ((p = local_alloc(data, format))) { 00740 if (!(chan = local_new(p, AST_STATE_DOWN))) { 00741 AST_LIST_LOCK(&locals); 00742 AST_LIST_REMOVE(&locals, p, list); 00743 AST_LIST_UNLOCK(&locals); 00744 p = local_pvt_destroy(p); 00745 } 00746 } 00747 00748 return chan; 00749 }
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 319 of file chan_local.c.
References AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_test_flag, check_bridge(), f, IS_OUTBOUND, LOCAL_ALREADY_MASQED, local_queue_frame(), local_pvt::lock, LOG_DEBUG, ast_channel::name, option_debug, and ast_channel::tech_pvt.
00320 { 00321 struct local_pvt *p = ast->tech_pvt; 00322 int res = -1; 00323 int isoutbound; 00324 00325 if (!p) 00326 return -1; 00327 00328 /* Just queue for delivery to the other side */ 00329 ast_mutex_lock(&p->lock); 00330 isoutbound = IS_OUTBOUND(ast, p); 00331 if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) 00332 check_bridge(p, isoutbound); 00333 if (!ast_test_flag(p, LOCAL_ALREADY_MASQED)) 00334 res = local_queue_frame(p, isoutbound, f, ast, 1); 00335 else { 00336 if (option_debug) 00337 ast_log(LOG_DEBUG, "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 int locals_show | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
CLI command "local show channels".
Definition at line 752 of file chan_local.c.
References ast_cli(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, local_pvt::context, local_pvt::exten, local_pvt::list, local_pvt::lock, ast_channel::name, local_pvt::owner, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
00753 { 00754 struct local_pvt *p = NULL; 00755 00756 if (argc != 3) 00757 return RESULT_SHOWUSAGE; 00758 00759 AST_LIST_LOCK(&locals); 00760 if (!AST_LIST_EMPTY(&locals)) { 00761 AST_LIST_TRAVERSE(&locals, p, list) { 00762 ast_mutex_lock(&p->lock); 00763 ast_cli(fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context); 00764 ast_mutex_unlock(&p->lock); 00765 } 00766 } else 00767 ast_cli(fd, "No local channels in use\n"); 00768 AST_LIST_UNLOCK(&locals); 00769 00770 return RESULT_SUCCESS; 00771 }
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 | AST_MODFLAG_BUILDSUM, .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 = "6989f2ec67f8497e38c12890500c525b" , .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:
{ { { "local", "show", "channels", NULL }, locals_show, "List status of local channels", show_locals_usage }, }
Definition at line 777 of file chan_local.c.
Referenced by load_module(), and unload_module().
struct ast_channel_tech local_tech [static] |
Definition at line 84 of file chan_local.c.
Referenced by load_module(), local_new(), and unload_module().
char show_locals_usage[] [static] |
Initial value:
"Usage: local show channels\n" " Provides summary information on active local proxy channels.\n"
Definition at line 773 of file chan_local.c.
const char tdesc[] = "Local Proxy Channel Driver" [static] |
Definition at line 65 of file chan_local.c.