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