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