#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 = "361d7bb937402d51e4658efb5b4d76e4" , .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 248 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().
00249 { 00250 struct ast_channel_monitor *tmp; 00251 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))) 00252 return; 00253 00254 /* only do the masquerade if we are being called on the outbound channel, 00255 if it has been bridged to another channel and if there are no pending 00256 frames on the owner channel (because they would be transferred to the 00257 outbound channel during the masquerade) 00258 */ 00259 if (isoutbound && p->chan->_bridge /* Not ast_bridged_channel! Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) { 00260 /* Masquerade bridged channel into owner */ 00261 /* Lock everything we need, one by one, and give up if 00262 we can't get everything. Remember, we'll get another 00263 chance in just a little bit */ 00264 if (!ast_mutex_trylock(&(p->chan->_bridge)->lock)) { 00265 if (!p->chan->_bridge->_softhangup) { 00266 if (!ast_mutex_trylock(&p->owner->lock)) { 00267 if (!p->owner->_softhangup) { 00268 if (p->owner->monitor && !p->chan->_bridge->monitor) { 00269 /* If a local channel is being monitored, we don't want a masquerade 00270 * to cause the monitor to go away. Since the masquerade swaps the monitors, 00271 * pre-swapping the monitors before the masquerade will ensure that the monitor 00272 * ends up where it is expected. 00273 */ 00274 tmp = p->owner->monitor; 00275 p->owner->monitor = p->chan->_bridge->monitor; 00276 p->chan->_bridge->monitor = tmp; 00277 } 00278 if (p->chan->audiohooks) { 00279 struct ast_audiohook_list *audiohooks_swapper; 00280 audiohooks_swapper = p->chan->audiohooks; 00281 p->chan->audiohooks = p->owner->audiohooks; 00282 p->owner->audiohooks = audiohooks_swapper; 00283 } 00284 ast_app_group_update(p->chan, p->owner); 00285 ast_channel_masquerade(p->owner, p->chan->_bridge); 00286 ast_set_flag(p, LOCAL_ALREADY_MASQED); 00287 } 00288 ast_mutex_unlock(&p->owner->lock); 00289 } 00290 ast_mutex_unlock(&(p->chan->_bridge)->lock); 00291 } 00292 } 00293 /* We only allow masquerading in one 'direction'... it's important to preserve the state 00294 (group variables, etc.) that live on p->chan->_bridge (and were put there by the dialplan) 00295 when the local channels go away. 00296 */ 00297 #if 0 00298 } else if (!isoutbound && p->owner && p->owner->_bridge && p->chan && AST_LIST_EMPTY(&p->chan->readq)) { 00299 /* Masquerade bridged channel into chan */ 00300 if (!ast_mutex_trylock(&(p->owner->_bridge)->lock)) { 00301 if (!p->owner->_bridge->_softhangup) { 00302 if (!ast_mutex_trylock(&p->chan->lock)) { 00303 if (!p->chan->_softhangup) { 00304 ast_channel_masquerade(p->chan, p->owner->_bridge); 00305 ast_set_flag(p, LOCAL_ALREADY_MASQED); 00306 } 00307 ast_mutex_unlock(&p->chan->lock); 00308 } 00309 } 00310 ast_mutex_unlock(&(p->owner->_bridge)->lock); 00311 } 00312 #endif 00313 } 00314 }
static int load_module | ( | void | ) | [static] |
Load module into PBX, register channel.
Definition at line 786 of file chan_local.c.
References ast_channel_register(), ast_cli_register_multiple(), ast_log(), cli_local, local_tech, and LOG_ERROR.
00787 { 00788 /* Make sure we can register our channel type */ 00789 if (ast_channel_register(&local_tech)) { 00790 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n"); 00791 return -1; 00792 } 00793 ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 00794 return 0; 00795 }
static struct local_pvt* local_alloc | ( | const char * | data, | |
int | format | |||
) | [static] |
Create a call structure.
Definition at line 623 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().
00624 { 00625 struct local_pvt *tmp = NULL; 00626 char *c = NULL, *opts = NULL; 00627 00628 if (!(tmp = ast_calloc(1, sizeof(*tmp)))) 00629 return NULL; 00630 00631 /* Initialize private structure information */ 00632 ast_mutex_init(&tmp->lock); 00633 ast_copy_string(tmp->exten, data, sizeof(tmp->exten)); 00634 00635 /* Look for options */ 00636 if ((opts = strchr(tmp->exten, '/'))) { 00637 *opts++ = '\0'; 00638 if (strchr(opts, 'n')) 00639 ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION); 00640 if (strchr(opts, 'm')) 00641 ast_set_flag(tmp, LOCAL_MOH_PASSTHRU); 00642 } 00643 00644 /* Look for a context */ 00645 if ((c = strchr(tmp->exten, '@'))) 00646 *c++ = '\0'; 00647 00648 ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context)); 00649 00650 tmp->reqformat = format; 00651 00652 #if 0 00653 /* We can't do this check here, because we don't know the CallerID yet, and 00654 * the CallerID could potentially affect what step is actually taken (or 00655 * even if that step exists). */ 00656 if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) { 00657 ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context); 00658 tmp = local_pvt_destroy(tmp); 00659 } else { 00660 #endif 00661 /* Add to list */ 00662 AST_LIST_LOCK(&locals); 00663 AST_LIST_INSERT_HEAD(&locals, tmp, list); 00664 AST_LIST_UNLOCK(&locals); 00665 #if 0 00666 } 00667 #endif 00668 00669 return tmp; 00670 }
static int local_answer | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 226 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.
00227 { 00228 struct local_pvt *p = ast->tech_pvt; 00229 int isoutbound; 00230 int res = -1; 00231 00232 if (!p) 00233 return -1; 00234 00235 ast_mutex_lock(&p->lock); 00236 isoutbound = IS_OUTBOUND(ast, p); 00237 if (isoutbound) { 00238 /* Pass along answer since somebody answered us */ 00239 struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER }; 00240 res = local_queue_frame(p, isoutbound, &answer, ast, 1); 00241 } else 00242 ast_log(LOG_WARNING, "Huh? Local is being asked to answer?\n"); 00243 if (!res) 00244 ast_mutex_unlock(&p->lock); 00245 return res; 00246 }
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 478 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.
00479 { 00480 struct local_pvt *p = ast->tech_pvt; 00481 int res; 00482 struct ast_var_t *varptr = NULL, *new; 00483 size_t len, namelen; 00484 00485 if (!p) 00486 return -1; 00487 00488 ast_mutex_lock(&p->lock); 00489 00490 /* 00491 * Note that cid_num and cid_name aren't passed in the ast_channel_alloc 00492 * call, so it's done here instead. 00493 */ 00494 p->chan->cid.cid_dnid = ast_strdup(p->owner->cid.cid_dnid); 00495 p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num); 00496 p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name); 00497 p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis); 00498 p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani); 00499 p->chan->cid.cid_pres = p->owner->cid.cid_pres; 00500 p->chan->cid.cid_ani2 = p->owner->cid.cid_ani2; 00501 p->chan->cid.cid_ton = p->owner->cid.cid_ton; 00502 p->chan->cid.cid_tns = p->owner->cid.cid_tns; 00503 ast_string_field_set(p->chan, language, p->owner->language); 00504 ast_string_field_set(p->chan, accountcode, p->owner->accountcode); 00505 ast_string_field_set(p->chan, musicclass, p->owner->musicclass); 00506 ast_cdr_update(p->chan); 00507 p->chan->cdrflags = p->owner->cdrflags; 00508 00509 if (!ast_exists_extension(NULL, p->chan->context, p->chan->exten, 1, p->owner->cid.cid_num)) { 00510 ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->chan->exten, p->chan->context); 00511 ast_mutex_unlock(&p->lock); 00512 return -1; 00513 } 00514 00515 /* copy the channel variables from the incoming channel to the outgoing channel */ 00516 /* Note that due to certain assumptions, they MUST be in the same order */ 00517 AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) { 00518 namelen = strlen(varptr->name); 00519 len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2; 00520 if ((new = ast_calloc(1, len))) { 00521 memcpy(new, varptr, len); 00522 new->value = &(new->name[0]) + namelen + 1; 00523 AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries); 00524 } 00525 } 00526 ast_channel_datastore_inherit(p->owner, p->chan); 00527 00528 /* Start switch on sub channel */ 00529 if (!(res = ast_pbx_start(p->chan))) 00530 ast_set_flag(p, LOCAL_LAUNCHED_PBX); 00531 00532 ast_mutex_unlock(&p->lock); 00533 return res; 00534 }
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 398 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.
00399 { 00400 struct local_pvt *p = ast->tech_pvt; 00401 int res = -1; 00402 struct ast_frame f = { AST_FRAME_DTMF_BEGIN, }; 00403 int isoutbound; 00404 00405 if (!p) 00406 return -1; 00407 00408 ast_mutex_lock(&p->lock); 00409 isoutbound = IS_OUTBOUND(ast, p); 00410 f.subclass = digit; 00411 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) 00412 ast_mutex_unlock(&p->lock); 00413 00414 return res; 00415 }
static int local_digit_end | ( | struct ast_channel * | ast, | |
char | digit, | |||
unsigned int | duration | |||
) | [static] |
Definition at line 417 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.
00418 { 00419 struct local_pvt *p = ast->tech_pvt; 00420 int res = -1; 00421 struct ast_frame f = { AST_FRAME_DTMF_END, }; 00422 int isoutbound; 00423 00424 if (!p) 00425 return -1; 00426 00427 ast_mutex_lock(&p->lock); 00428 isoutbound = IS_OUTBOUND(ast, p); 00429 f.subclass = digit; 00430 f.len = duration; 00431 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) 00432 ast_mutex_unlock(&p->lock); 00433 00434 return res; 00435 }
static int local_fixup | ( | struct ast_channel * | oldchan, | |
struct ast_channel * | newchan | |||
) | [static] |
Definition at line 347 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.
00348 { 00349 struct local_pvt *p = newchan->tech_pvt; 00350 00351 if (!p) 00352 return -1; 00353 00354 ast_mutex_lock(&p->lock); 00355 00356 if ((p->owner != oldchan) && (p->chan != oldchan)) { 00357 ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan); 00358 ast_mutex_unlock(&p->lock); 00359 return -1; 00360 } 00361 if (p->owner == oldchan) 00362 p->owner = newchan; 00363 else 00364 p->chan = newchan; 00365 ast_mutex_unlock(&p->lock); 00366 return 0; 00367 }
static int local_hangup | ( | struct ast_channel * | ast | ) | [static] |
Hangup a call through the local proxy channel.
Definition at line 537 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.
00538 { 00539 struct local_pvt *p = ast->tech_pvt; 00540 int isoutbound; 00541 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP }; 00542 struct ast_channel *ochan = NULL; 00543 int glaredetect = 0, res = 0; 00544 00545 if (!p) 00546 return -1; 00547 00548 while (ast_mutex_trylock(&p->lock)) { 00549 ast_channel_unlock(ast); 00550 usleep(1); 00551 ast_channel_lock(ast); 00552 } 00553 00554 isoutbound = IS_OUTBOUND(ast, p); 00555 if (isoutbound) { 00556 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS"); 00557 if ((status) && (p->owner)) { 00558 /* Deadlock avoidance */ 00559 while (p->owner && ast_channel_trylock(p->owner)) { 00560 ast_mutex_unlock(&p->lock); 00561 if (ast) { 00562 ast_channel_unlock(ast); 00563 } 00564 usleep(1); 00565 if (ast) { 00566 ast_channel_lock(ast); 00567 } 00568 ast_mutex_lock(&p->lock); 00569 } 00570 if (p->owner) { 00571 pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status); 00572 ast_channel_unlock(p->owner); 00573 } 00574 } 00575 p->chan = NULL; 00576 ast_clear_flag(p, LOCAL_LAUNCHED_PBX); 00577 ast_module_user_remove(p->u_chan); 00578 } else { 00579 ast_module_user_remove(p->u_owner); 00580 while (p->chan && ast_channel_trylock(p->chan)) { 00581 DEADLOCK_AVOIDANCE(&p->lock); 00582 } 00583 p->owner = NULL; 00584 if (p->chan) { 00585 ast_queue_hangup(p->chan); 00586 ast_channel_unlock(p->chan); 00587 } 00588 } 00589 00590 ast->tech_pvt = NULL; 00591 00592 if (!p->owner && !p->chan) { 00593 /* Okay, done with the private part now, too. */ 00594 glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT); 00595 /* If we have a queue holding, don't actually destroy p yet, but 00596 let local_queue do it. */ 00597 if (glaredetect) 00598 ast_set_flag(p, LOCAL_CANCEL_QUEUE); 00599 /* Remove from list */ 00600 AST_LIST_LOCK(&locals); 00601 AST_LIST_REMOVE(&locals, p, list); 00602 AST_LIST_UNLOCK(&locals); 00603 ast_mutex_unlock(&p->lock); 00604 /* And destroy */ 00605 if (!glaredetect) { 00606 p = local_pvt_destroy(p); 00607 } 00608 return 0; 00609 } 00610 if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) 00611 /* Need to actually hangup since there is no PBX */ 00612 ochan = p->chan; 00613 else 00614 res = local_queue_frame(p, isoutbound, &f, NULL, 1); 00615 if (!res) 00616 ast_mutex_unlock(&p->lock); 00617 if (ochan) 00618 ast_hangup(ochan); 00619 return 0; 00620 }
static int local_indicate | ( | struct ast_channel * | ast, | |
int | condition, | |||
const void * | data, | |||
size_t | datalen | |||
) | [static] |
Definition at line 369 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.
00370 { 00371 struct local_pvt *p = ast->tech_pvt; 00372 int res = 0; 00373 struct ast_frame f = { AST_FRAME_CONTROL, }; 00374 int isoutbound; 00375 00376 if (!p) 00377 return -1; 00378 00379 /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */ 00380 if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) { 00381 ast_moh_start(ast, data, NULL); 00382 } else if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_UNHOLD) { 00383 ast_moh_stop(ast); 00384 } else { 00385 /* Queue up a frame representing the indication as a control frame */ 00386 ast_mutex_lock(&p->lock); 00387 isoutbound = IS_OUTBOUND(ast, p); 00388 f.subclass = condition; 00389 f.data = (void*)data; 00390 f.datalen = datalen; 00391 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 1))) 00392 ast_mutex_unlock(&p->lock); 00393 } 00394 00395 return res; 00396 }
static struct ast_channel* local_new | ( | struct local_pvt * | p, | |
int | state | |||
) | [static] |
Start new local channel.
Definition at line 673 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().
00674 { 00675 struct ast_channel *tmp = NULL, *tmp2 = NULL; 00676 int randnum = ast_random() & 0xffff, fmt = 0; 00677 const char *t; 00678 int ama; 00679 00680 /* Allocate two new Asterisk channels */ 00681 /* safe accountcode */ 00682 if (p->owner && p->owner->accountcode) 00683 t = p->owner->accountcode; 00684 else 00685 t = ""; 00686 00687 if (p->owner) 00688 ama = p->owner->amaflags; 00689 else 00690 ama = 0; 00691 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)) 00692 || !(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))) { 00693 if (tmp) 00694 ast_channel_free(tmp); 00695 if (tmp2) 00696 ast_channel_free(tmp2); 00697 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n"); 00698 return NULL; 00699 } 00700 00701 tmp2->tech = tmp->tech = &local_tech; 00702 00703 tmp->nativeformats = p->reqformat; 00704 tmp2->nativeformats = p->reqformat; 00705 00706 /* Determine our read/write format and set it on each channel */ 00707 fmt = ast_best_codec(p->reqformat); 00708 tmp->writeformat = fmt; 00709 tmp2->writeformat = fmt; 00710 tmp->rawwriteformat = fmt; 00711 tmp2->rawwriteformat = fmt; 00712 tmp->readformat = fmt; 00713 tmp2->readformat = fmt; 00714 tmp->rawreadformat = fmt; 00715 tmp2->rawreadformat = fmt; 00716 00717 tmp->tech_pvt = p; 00718 tmp2->tech_pvt = p; 00719 00720 p->owner = tmp; 00721 p->chan = tmp2; 00722 p->u_owner = ast_module_user_add(p->owner); 00723 p->u_chan = ast_module_user_add(p->chan); 00724 00725 ast_copy_string(tmp->context, p->context, sizeof(tmp->context)); 00726 ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context)); 00727 ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten)); 00728 tmp->priority = 1; 00729 tmp2->priority = 1; 00730 00731 return tmp; 00732 }
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::_bridge, ast_channel::appl, 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_strlen_zero(), ast_test_flag, local_pvt::chan, f, ast_channel::generator, LOCAL_CANCEL_QUEUE, LOCAL_GLARE_DETECT, local_pvt_destroy(), local_pvt::lock, local_pvt::owner, and ast_channel::pbx.
Referenced by local_answer(), local_digit_begin(), local_digit_end(), local_hangup(), local_indicate(), local_sendhtml(), local_sendtext(), and local_write().
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 if (other->pbx || other->_bridge || !ast_strlen_zero(other->appl)) { 00216 ast_queue_frame(other, f); 00217 } /* else the frame won't go anywhere */ 00218 ast_channel_unlock(other); 00219 } 00220 00221 ast_clear_flag(p, LOCAL_GLARE_DETECT); 00222 00223 return 0; 00224 }
static struct ast_frame * local_read | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 316 of file chan_local.c.
References ast_null_frame.
00317 { 00318 return &ast_null_frame; 00319 }
static struct ast_channel * local_request | ( | const char * | type, | |
int | format, | |||
void * | data, | |||
int * | cause | |||
) | [static] |
Part of PBX interface.
Definition at line 735 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().
00736 { 00737 struct local_pvt *p = NULL; 00738 struct ast_channel *chan = NULL; 00739 00740 /* Allocate a new private structure and then Asterisk channel */ 00741 if ((p = local_alloc(data, format))) { 00742 if (!(chan = local_new(p, AST_STATE_DOWN))) { 00743 AST_LIST_LOCK(&locals); 00744 AST_LIST_REMOVE(&locals, p, list); 00745 AST_LIST_UNLOCK(&locals); 00746 p = local_pvt_destroy(p); 00747 } 00748 } 00749 00750 return chan; 00751 }
static int local_sendhtml | ( | struct ast_channel * | ast, | |
int | subclass, | |||
const char * | data, | |||
int | datalen | |||
) | [static] |
Definition at line 456 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.
00457 { 00458 struct local_pvt *p = ast->tech_pvt; 00459 int res = -1; 00460 struct ast_frame f = { AST_FRAME_HTML, }; 00461 int isoutbound; 00462 00463 if (!p) 00464 return -1; 00465 00466 ast_mutex_lock(&p->lock); 00467 isoutbound = IS_OUTBOUND(ast, p); 00468 f.subclass = subclass; 00469 f.data = (char *)data; 00470 f.datalen = datalen; 00471 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) 00472 ast_mutex_unlock(&p->lock); 00473 return res; 00474 }
static int local_sendtext | ( | struct ast_channel * | ast, | |
const char * | text | |||
) | [static] |
Definition at line 437 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.
00438 { 00439 struct local_pvt *p = ast->tech_pvt; 00440 int res = -1; 00441 struct ast_frame f = { AST_FRAME_TEXT, }; 00442 int isoutbound; 00443 00444 if (!p) 00445 return -1; 00446 00447 ast_mutex_lock(&p->lock); 00448 isoutbound = IS_OUTBOUND(ast, p); 00449 f.data = (char *) text; 00450 f.datalen = strlen(text) + 1; 00451 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) 00452 ast_mutex_unlock(&p->lock); 00453 return res; 00454 }
static int local_write | ( | struct ast_channel * | ast, | |
struct ast_frame * | f | |||
) | [static] |
Definition at line 321 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.
00322 { 00323 struct local_pvt *p = ast->tech_pvt; 00324 int res = -1; 00325 int isoutbound; 00326 00327 if (!p) 00328 return -1; 00329 00330 /* Just queue for delivery to the other side */ 00331 ast_mutex_lock(&p->lock); 00332 isoutbound = IS_OUTBOUND(ast, p); 00333 if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) 00334 check_bridge(p, isoutbound); 00335 if (!ast_test_flag(p, LOCAL_ALREADY_MASQED)) 00336 res = local_queue_frame(p, isoutbound, f, ast, 1); 00337 else { 00338 if (option_debug) 00339 ast_log(LOG_DEBUG, "Not posting to queue since already masked on '%s'\n", ast->name); 00340 res = 0; 00341 } 00342 if (!res) 00343 ast_mutex_unlock(&p->lock); 00344 return res; 00345 }
static int locals_show | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
CLI command "local show channels".
Definition at line 754 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.
00755 { 00756 struct local_pvt *p = NULL; 00757 00758 if (argc != 3) 00759 return RESULT_SHOWUSAGE; 00760 00761 AST_LIST_LOCK(&locals); 00762 if (!AST_LIST_EMPTY(&locals)) { 00763 AST_LIST_TRAVERSE(&locals, p, list) { 00764 ast_mutex_lock(&p->lock); 00765 ast_cli(fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context); 00766 ast_mutex_unlock(&p->lock); 00767 } 00768 } else 00769 ast_cli(fd, "No local channels in use\n"); 00770 AST_LIST_UNLOCK(&locals); 00771 00772 return RESULT_SUCCESS; 00773 }
static int unload_module | ( | void | ) | [static] |
Unload the local proxy channel from Asterisk.
Definition at line 798 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.
00799 { 00800 struct local_pvt *p = NULL; 00801 00802 /* First, take us out of the channel loop */ 00803 ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 00804 ast_channel_unregister(&local_tech); 00805 if (!AST_LIST_LOCK(&locals)) { 00806 /* Hangup all interfaces if they have an owner */ 00807 AST_LIST_TRAVERSE(&locals, p, list) { 00808 if (p->owner) 00809 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); 00810 } 00811 AST_LIST_UNLOCK(&locals); 00812 } else { 00813 ast_log(LOG_WARNING, "Unable to lock the monitor\n"); 00814 return -1; 00815 } 00816 return 0; 00817 }
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 = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, } [static] |
Definition at line 819 of file chan_local.c.
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 819 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 779 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 775 of file chan_local.c.
const char tdesc[] = "Local Proxy Channel Driver" [static] |
Definition at line 65 of file chan_local.c.