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