#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"
#include "asterisk/astobj2.h"
Go to the source code of this file.
Data Structures | |
struct | local_pvt |
Defines | |
#define | IS_OUTBOUND(a, b) (a == b->chan ? 1 : 0) |
#define | LOCAL_ALREADY_MASQED (1 << 1) |
#define | LOCAL_LAUNCHED_PBX (1 << 2) |
#define | LOCAL_MOH_PASSTHRU (1 << 4) |
#define | LOCAL_NO_OPTIMIZATION (1 << 3) |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static void | check_bridge (struct local_pvt *p) |
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 int | local_queue_frame (struct local_pvt *p, int isoutbound, struct ast_frame *f, struct ast_channel *us, int us_locked) |
queue a frame on a to either the p->owner or p->chan | |
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_setoption (struct ast_channel *chan, int option, void *data, int datalen) |
static int | local_write (struct ast_channel *ast, struct ast_frame *f) |
static int | locals_cmp_cb (void *obj, void *arg, int flags) |
static int | locals_show (int fd, int argc, char **argv) |
CLI command "local show channels". | |
static int | unload_module (void) |
Unload the local proxy channel from Asterisk. | |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "Local Proxy Channel (Note: used internally by other modules)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, } |
static const struct ast_module_info * | ast_module_info = &__mod_info |
static const int | BUCKET_SIZE = 1 |
static struct ast_cli_entry | cli_local [] |
static struct ast_channel_tech | local_tech |
static struct ao2_container * | locals |
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 68 of file chan_local.c.
#define LOCAL_ALREADY_MASQED (1 << 1) |
Already masqueraded
Definition at line 127 of file chan_local.c.
Referenced by check_bridge(), and local_write().
#define LOCAL_LAUNCHED_PBX (1 << 2) |
PBX was launched
Definition at line 128 of file chan_local.c.
Referenced by local_call(), and local_hangup().
#define LOCAL_MOH_PASSTHRU (1 << 4) |
Pass through music on hold start/stop frames
Definition at line 130 of file chan_local.c.
Referenced by local_alloc(), and local_indicate().
#define LOCAL_NO_OPTIMIZATION (1 << 3) |
Do not optimize using masquerading
Definition at line 129 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 | ) | [static] |
Definition at line 312 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, 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, LOCAL_ALREADY_MASQED, LOCAL_NO_OPTIMIZATION, ast_channel::lock, ast_channel::monitor, local_pvt::owner, and ast_channel::readq.
Referenced by local_write().
00313 { 00314 struct ast_channel_monitor *tmp; 00315 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))) 00316 return; 00317 00318 /* only do the masquerade if we are being called on the outbound channel, 00319 if it has been bridged to another channel and if there are no pending 00320 frames on the owner channel (because they would be transferred to the 00321 outbound channel during the masquerade) 00322 */ 00323 if (p->chan->_bridge /* Not ast_bridged_channel! Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) { 00324 /* Masquerade bridged channel into owner */ 00325 /* Lock everything we need, one by one, and give up if 00326 we can't get everything. Remember, we'll get another 00327 chance in just a little bit */ 00328 if (!ast_mutex_trylock(&(p->chan->_bridge)->lock)) { 00329 if (!p->chan->_bridge->_softhangup) { 00330 if (!ast_mutex_trylock(&p->owner->lock)) { 00331 if (!p->owner->_softhangup) { 00332 if (p->owner->monitor && !p->chan->_bridge->monitor) { 00333 /* If a local channel is being monitored, we don't want a masquerade 00334 * to cause the monitor to go away. Since the masquerade swaps the monitors, 00335 * pre-swapping the monitors before the masquerade will ensure that the monitor 00336 * ends up where it is expected. 00337 */ 00338 tmp = p->owner->monitor; 00339 p->owner->monitor = p->chan->_bridge->monitor; 00340 p->chan->_bridge->monitor = tmp; 00341 } 00342 if (p->chan->audiohooks) { 00343 struct ast_audiohook_list *audiohooks_swapper; 00344 audiohooks_swapper = p->chan->audiohooks; 00345 p->chan->audiohooks = p->owner->audiohooks; 00346 p->owner->audiohooks = audiohooks_swapper; 00347 } 00348 00349 /* If any Caller ID was set, preserve it after masquerade like above. We must check 00350 * to see if Caller ID was set because otherwise we'll mistakingly copy info not 00351 * set from the dialplan and will overwrite the real channel Caller ID. The reason 00352 * for this whole preswapping action is because the Caller ID is set on the channel 00353 * thread (which is the to be masqueraded away local channel) before both local 00354 * channels are optimized away. 00355 */ 00356 if (p->owner->cid.cid_dnid || p->owner->cid.cid_num || 00357 p->owner->cid.cid_name || p->owner->cid.cid_ani || 00358 p->owner->cid.cid_rdnis || p->owner->cid.cid_pres || 00359 p->owner->cid.cid_ani2 || p->owner->cid.cid_ton || 00360 p->owner->cid.cid_tns) { 00361 00362 struct ast_callerid tmpcid; 00363 tmpcid = p->owner->cid; 00364 p->owner->cid = p->chan->_bridge->cid; 00365 p->chan->_bridge->cid = tmpcid; 00366 } 00367 00368 ast_app_group_update(p->chan, p->owner); 00369 ast_channel_masquerade(p->owner, p->chan->_bridge); 00370 ast_set_flag(p, LOCAL_ALREADY_MASQED); 00371 } 00372 ast_mutex_unlock(&p->owner->lock); 00373 } 00374 } 00375 ast_mutex_unlock(&(p->chan->_bridge)->lock); 00376 } 00377 } 00378 }
static int load_module | ( | void | ) | [static] |
Load module into PBX, register channel.
Definition at line 907 of file chan_local.c.
References ao2_container_alloc(), ao2_ref(), ast_channel_register(), ast_cli_register_multiple(), ast_log(), cli_local, local_tech, locals, locals_cmp_cb(), and LOG_ERROR.
00908 { 00909 if (!(locals = ao2_container_alloc(BUCKET_SIZE, NULL, locals_cmp_cb))) { 00910 return -1; 00911 } 00912 00913 /* Make sure we can register our channel type */ 00914 if (ast_channel_register(&local_tech)) { 00915 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n"); 00916 ao2_ref(locals, -1); 00917 return -1; 00918 } 00919 00920 ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 00921 return 0; 00922 }
static struct local_pvt* local_alloc | ( | const char * | data, | |
int | format | |||
) | [static] |
Create a call structure.
Definition at line 739 of file chan_local.c.
References ao2_alloc(), ast_copy_string(), ast_exists_extension(), ast_log(), ast_set_flag, LOCAL_MOH_PASSTHRU, LOCAL_NO_OPTIMIZATION, locals, and LOG_NOTICE.
Referenced by local_request().
00740 { 00741 struct local_pvt *tmp = NULL; 00742 char *c = NULL, *opts = NULL; 00743 00744 if (!(tmp = ao2_alloc(sizeof(*tmp), NULL))) { 00745 return NULL; 00746 } 00747 00748 /* Initialize private structure information */ 00749 ast_copy_string(tmp->exten, data, sizeof(tmp->exten)); 00750 00751 /* Look for options */ 00752 if ((opts = strchr(tmp->exten, '/'))) { 00753 *opts++ = '\0'; 00754 if (strchr(opts, 'n')) 00755 ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION); 00756 if (strchr(opts, 'm')) 00757 ast_set_flag(tmp, LOCAL_MOH_PASSTHRU); 00758 } 00759 00760 /* Look for a context */ 00761 if ((c = strchr(tmp->exten, '@'))) 00762 *c++ = '\0'; 00763 00764 ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context)); 00765 00766 tmp->reqformat = format; 00767 00768 #if 0 00769 /* We can't do this check here, because we don't know the CallerID yet, and 00770 * the CallerID could potentially affect what step is actually taken (or 00771 * even if that step exists). */ 00772 if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) { 00773 ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context); 00774 tmp = local_pvt_destroy(tmp); 00775 } else { 00776 #endif 00777 /* Add to list */ 00778 ao2_link(locals, tmp); 00779 #if 0 00780 } 00781 #endif 00782 return tmp; /* this is returned with a ref */ 00783 }
static int local_answer | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 284 of file chan_local.c.
References answer, ao2_lock(), ao2_ref(), ao2_unlock(), AST_CONTROL_ANSWER, AST_FRAME_CONTROL, ast_log(), IS_OUTBOUND, local_queue_frame(), LOG_WARNING, and ast_channel::tech_pvt.
00285 { 00286 struct local_pvt *p = ast->tech_pvt; 00287 int isoutbound; 00288 int res = -1; 00289 00290 if (!p) 00291 return -1; 00292 00293 ao2_lock(p); 00294 ao2_ref(p, 1); 00295 isoutbound = IS_OUTBOUND(ast, p); 00296 if (isoutbound) { 00297 /* Pass along answer since somebody answered us */ 00298 struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER }; 00299 res = local_queue_frame(p, isoutbound, &answer, ast, 1); 00300 } else { 00301 ast_log(LOG_WARNING, "Huh? Local is being asked to answer?\n"); 00302 } 00303 ao2_unlock(p); 00304 ao2_ref(p, -1); 00305 return res; 00306 }
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 567 of file chan_local.c.
References ast_channel::accountcode, accountcode, ao2_lock(), ao2_unlock(), ast_calloc, ast_cdr_update(), ast_channel_datastore_inherit(), ast_exists_extension(), AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), 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, 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.
00568 { 00569 struct local_pvt *p = ast->tech_pvt; 00570 int res = 0; 00571 struct ast_var_t *varptr = NULL, *new; 00572 size_t len, namelen; 00573 00574 if (!p) 00575 return -1; 00576 00577 ao2_lock(p); 00578 00579 /* 00580 * Note that cid_num and cid_name aren't passed in the ast_channel_alloc 00581 * call, so it's done here instead. 00582 */ 00583 p->chan->cid.cid_dnid = ast_strdup(p->owner->cid.cid_dnid); 00584 p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num); 00585 p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name); 00586 p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis); 00587 p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani); 00588 p->chan->cid.cid_pres = p->owner->cid.cid_pres; 00589 p->chan->cid.cid_ani2 = p->owner->cid.cid_ani2; 00590 p->chan->cid.cid_ton = p->owner->cid.cid_ton; 00591 p->chan->cid.cid_tns = p->owner->cid.cid_tns; 00592 ast_string_field_set(p->chan, language, p->owner->language); 00593 ast_string_field_set(p->chan, accountcode, p->owner->accountcode); 00594 ast_string_field_set(p->chan, musicclass, p->owner->musicclass); 00595 ast_cdr_update(p->chan); 00596 p->chan->cdrflags = p->owner->cdrflags; 00597 00598 /* copy the channel variables from the incoming channel to the outgoing channel */ 00599 /* Note that due to certain assumptions, they MUST be in the same order */ 00600 AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) { 00601 namelen = strlen(varptr->name); 00602 len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2; 00603 if ((new = ast_calloc(1, len))) { 00604 memcpy(new, varptr, len); 00605 new->value = &(new->name[0]) + namelen + 1; 00606 AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries); 00607 } 00608 } 00609 ast_channel_datastore_inherit(p->owner, p->chan); 00610 00611 if (!ast_exists_extension(p->chan, p->chan->context, p->chan->exten, 1, p->owner->cid.cid_num)) { 00612 ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->chan->exten, p->chan->context); 00613 ao2_unlock(p); 00614 return -1; 00615 } 00616 00617 /* Start switch on sub channel */ 00618 if (!(res = ast_pbx_start(p->chan))) 00619 ast_set_flag(p, LOCAL_LAUNCHED_PBX); 00620 00621 ao2_unlock(p); 00622 return res; 00623 }
static int local_devicestate | ( | void * | data | ) | [static] |
Adds devicestate to local channels.
Definition at line 198 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.
00199 { 00200 char *exten = ast_strdupa(data); 00201 char *context = NULL, *opts = NULL; 00202 int res; 00203 00204 if (!(context = strchr(exten, '@'))) { 00205 ast_log(LOG_WARNING, "Someone used Local/%s somewhere without a @context. This is bad.\n", exten); 00206 return AST_DEVICE_INVALID; 00207 } 00208 00209 *context++ = '\0'; 00210 00211 /* Strip options if they exist */ 00212 if ((opts = strchr(context, '/'))) 00213 *opts = '\0'; 00214 00215 if (option_debug > 2) 00216 ast_log(LOG_DEBUG, "Checking if extension %s@%s exists (devicestate)\n", exten, context); 00217 res = ast_exists_extension(NULL, context, exten, 1, NULL); 00218 if (!res) 00219 return AST_DEVICE_INVALID; 00220 else 00221 return AST_DEVICE_UNKNOWN; 00222 }
static int local_digit_begin | ( | struct ast_channel * | ast, | |
char | digit | |||
) | [static] |
Definition at line 476 of file chan_local.c.
References ao2_lock(), ao2_ref(), ao2_unlock(), AST_FRAME_DTMF_BEGIN, f, IS_OUTBOUND, local_queue_frame(), and ast_channel::tech_pvt.
00477 { 00478 struct local_pvt *p = ast->tech_pvt; 00479 int res = -1; 00480 struct ast_frame f = { AST_FRAME_DTMF_BEGIN, }; 00481 int isoutbound; 00482 00483 if (!p) 00484 return -1; 00485 00486 ao2_ref(p, 1); /* ref for local_queue_frame */ 00487 ao2_lock(p); 00488 isoutbound = IS_OUTBOUND(ast, p); 00489 f.subclass = digit; 00490 res = local_queue_frame(p, isoutbound, &f, ast, 0); 00491 ao2_unlock(p); 00492 ao2_ref(p, -1); 00493 00494 return res; 00495 }
static int local_digit_end | ( | struct ast_channel * | ast, | |
char | digit, | |||
unsigned int | duration | |||
) | [static] |
Definition at line 497 of file chan_local.c.
References ao2_lock(), ao2_ref(), ao2_unlock(), AST_FRAME_DTMF_END, f, IS_OUTBOUND, local_queue_frame(), and ast_channel::tech_pvt.
00498 { 00499 struct local_pvt *p = ast->tech_pvt; 00500 int res = -1; 00501 struct ast_frame f = { AST_FRAME_DTMF_END, }; 00502 int isoutbound; 00503 00504 if (!p) 00505 return -1; 00506 00507 ao2_lock(p); 00508 ao2_ref(p, 1); /* ref for local_queue_frame */ 00509 isoutbound = IS_OUTBOUND(ast, p); 00510 f.subclass = digit; 00511 f.len = duration; 00512 res = local_queue_frame(p, isoutbound, &f, ast, 0); 00513 ao2_unlock(p); 00514 ao2_ref(p, -1); 00515 00516 return res; 00517 }
static int local_fixup | ( | struct ast_channel * | oldchan, | |
struct ast_channel * | newchan | |||
) | [static] |
Definition at line 413 of file chan_local.c.
References ast_channel::_bridge, ao2_lock(), ao2_unlock(), ast_check_hangup(), ast_log(), ast_queue_hangup(), local_pvt::chan, LOG_WARNING, local_pvt::owner, and ast_channel::tech_pvt.
00414 { 00415 struct local_pvt *p = newchan->tech_pvt; 00416 00417 if (!p) 00418 return -1; 00419 00420 ao2_lock(p); 00421 00422 if ((p->owner != oldchan) && (p->chan != oldchan)) { 00423 ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan); 00424 ao2_unlock(p); 00425 return -1; 00426 } 00427 if (p->owner == oldchan) 00428 p->owner = newchan; 00429 else 00430 p->chan = newchan; 00431 00432 /* Do not let a masquerade cause a Local channel to be bridged to itself! */ 00433 if (!ast_check_hangup(newchan) && ((p->owner && p->owner->_bridge == p->chan) || (p->chan && p->chan->_bridge == p->owner))) { 00434 ast_log(LOG_WARNING, "You can not bridge a Local channel to itself!\n"); 00435 ao2_unlock(p); 00436 ast_queue_hangup(newchan); 00437 return -1; 00438 } 00439 00440 ao2_unlock(p); 00441 return 0; 00442 }
static int local_hangup | ( | struct ast_channel * | ast | ) | [static] |
Hangup a call through the local proxy channel.
Definition at line 626 of file chan_local.c.
References ao2_lock(), ao2_ref(), ao2_trylock(), ao2_unlink(), ao2_unlock(), ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_clear_flag, AST_CONTROL_HANGUP, AST_FRAME_CONTROL, ast_hangup(), ast_module_user_remove, ast_queue_hangup(), ast_test_flag, local_pvt::chan, f, ast_channel::hangupcause, IS_OUTBOUND, LOCAL_LAUNCHED_PBX, local_queue_frame(), locals, local_pvt::owner, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), ast_channel::tech_pvt, local_pvt::u_chan, and local_pvt::u_owner.
00627 { 00628 struct local_pvt *p = ast->tech_pvt; 00629 int isoutbound; 00630 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP }; 00631 struct ast_channel *ochan = NULL; 00632 00633 if (!p) 00634 return -1; 00635 00636 /* we MUST give the tech_pvt a ref here since we are unlocking the 00637 * channel during deadlock avoidance. */ 00638 ao2_ref(p, 1); 00639 00640 while (ao2_trylock(p)) { 00641 ast_channel_unlock(ast); 00642 sched_yield(); 00643 ast_channel_lock(ast); 00644 } 00645 00646 isoutbound = IS_OUTBOUND(ast, p); 00647 if (isoutbound) { 00648 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS"); 00649 if ((status) && (p->owner)) { 00650 /* Deadlock avoidance */ 00651 while (p->owner && ast_channel_trylock(p->owner)) { 00652 ao2_unlock(p); 00653 if (p->chan) { 00654 ast_channel_unlock(p->chan); 00655 } 00656 sched_yield(); 00657 if (p->chan) { 00658 ast_channel_lock(p->chan); 00659 } 00660 ao2_lock(p); 00661 } 00662 if (p->owner) { 00663 p->owner->hangupcause = p->chan->hangupcause; 00664 pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status); 00665 ast_channel_unlock(p->owner); 00666 } 00667 } 00668 if (!p->chan) { 00669 /* chan was == to ast and was !NULL before deadlock avoidance started, if chan 00670 * is NULL now, then we should bail because that channel 00671 * hungup already. This is possible because we let go of the 00672 * lock given to the ast channel passed to this function during 00673 * deadlock avoidance. */ 00674 ao2_unlock(p); 00675 ao2_ref(p, -1); 00676 return 0; 00677 } 00678 p->chan = NULL; 00679 ast_clear_flag(p, LOCAL_LAUNCHED_PBX); 00680 ast_module_user_remove(p->u_chan); 00681 } else { 00682 ast_module_user_remove(p->u_owner); 00683 while (p->chan && ast_channel_trylock(p->chan)) { 00684 ao2_unlock(p); 00685 if (p->owner) { 00686 ast_channel_unlock(p->owner); 00687 } 00688 sched_yield(); 00689 if (p->owner) { 00690 ast_channel_lock(p->owner); 00691 } 00692 ao2_lock(p); 00693 } 00694 if (p->chan) { 00695 ast_queue_hangup(p->chan); 00696 ast_channel_unlock(p->chan); 00697 } 00698 00699 if (!p->owner) { 00700 /* owner was == to ast and was !NULL before deadlock avoidance started, if 00701 * owner is NULL now, then we should bail because that channel 00702 * hungup already. This is possible because we let go of the 00703 * lock given to the ast channel passed to this function during 00704 * deadlock avoidance. */ 00705 ao2_unlock(p); 00706 ao2_ref(p, -1); 00707 return 0; 00708 } 00709 p->owner = NULL; 00710 } 00711 00712 ast->tech_pvt = NULL; 00713 00714 if (!p->owner && !p->chan) { 00715 ao2_unlock(p); 00716 00717 /* Remove from list */ 00718 ao2_unlink(locals, p); 00719 ao2_ref(p, -1); 00720 return 0; 00721 } 00722 if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) { 00723 /* Need to actually hangup since there is no PBX */ 00724 ochan = p->chan; 00725 } else { 00726 local_queue_frame(p, isoutbound, &f, NULL, 1); 00727 } 00728 00729 ao2_unlock(p); 00730 if (ochan) { 00731 ast_hangup(ochan); 00732 } 00733 00734 ao2_ref(p, -1); 00735 return 0; 00736 }
static int local_indicate | ( | struct ast_channel * | ast, | |
int | condition, | |||
const void * | data, | |||
size_t | datalen | |||
) | [static] |
Definition at line 444 of file chan_local.c.
References ao2_lock(), ao2_ref(), ao2_unlock(), AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, ast_moh_start(), ast_moh_stop(), ast_test_flag, f, IS_OUTBOUND, LOCAL_MOH_PASSTHRU, local_queue_frame(), and ast_channel::tech_pvt.
00445 { 00446 struct local_pvt *p = ast->tech_pvt; 00447 int res = 0; 00448 struct ast_frame f = { AST_FRAME_CONTROL, }; 00449 int isoutbound; 00450 00451 if (!p) 00452 return -1; 00453 00454 ao2_ref(p, 1); /* ref for local_queue_frame */ 00455 00456 /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */ 00457 if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) { 00458 ast_moh_start(ast, data, NULL); 00459 } else if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_UNHOLD) { 00460 ast_moh_stop(ast); 00461 } else { 00462 /* Queue up a frame representing the indication as a control frame */ 00463 ao2_lock(p); 00464 isoutbound = IS_OUTBOUND(ast, p); 00465 f.subclass = condition; 00466 f.data = (void*)data; 00467 f.datalen = datalen; 00468 res = local_queue_frame(p, isoutbound, &f, ast, 1); 00469 ao2_unlock(p); 00470 } 00471 ao2_ref(p, -1); 00472 00473 return res; 00474 }
static struct ast_channel* local_new | ( | struct local_pvt * | p, | |
int | state | |||
) | [static] |
Start new local channel.
Definition at line 786 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().
00787 { 00788 struct ast_channel *tmp = NULL, *tmp2 = NULL; 00789 int randnum = ast_random() & 0xffff, fmt = 0; 00790 const char *t; 00791 int ama; 00792 00793 /* Allocate two new Asterisk channels */ 00794 /* safe accountcode */ 00795 if (p->owner && p->owner->accountcode) 00796 t = p->owner->accountcode; 00797 else 00798 t = ""; 00799 00800 if (p->owner) 00801 ama = p->owner->amaflags; 00802 else 00803 ama = 0; 00804 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)) 00805 || !(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))) { 00806 if (tmp) 00807 ast_channel_free(tmp); 00808 if (tmp2) 00809 ast_channel_free(tmp2); 00810 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n"); 00811 return NULL; 00812 } 00813 00814 tmp2->tech = tmp->tech = &local_tech; 00815 00816 tmp->nativeformats = p->reqformat; 00817 tmp2->nativeformats = p->reqformat; 00818 00819 /* Determine our read/write format and set it on each channel */ 00820 fmt = ast_best_codec(p->reqformat); 00821 tmp->writeformat = fmt; 00822 tmp2->writeformat = fmt; 00823 tmp->rawwriteformat = fmt; 00824 tmp2->rawwriteformat = fmt; 00825 tmp->readformat = fmt; 00826 tmp2->readformat = fmt; 00827 tmp->rawreadformat = fmt; 00828 tmp2->rawreadformat = fmt; 00829 00830 tmp->tech_pvt = p; 00831 tmp2->tech_pvt = p; 00832 00833 p->owner = tmp; 00834 p->chan = tmp2; 00835 p->u_owner = ast_module_user_add(p->owner); 00836 p->u_chan = ast_module_user_add(p->chan); 00837 00838 ast_copy_string(tmp->context, p->context, sizeof(tmp->context)); 00839 ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context)); 00840 ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten)); 00841 tmp->priority = 1; 00842 tmp2->priority = 1; 00843 00844 return tmp; 00845 }
static int local_queue_frame | ( | struct local_pvt * | p, | |
int | isoutbound, | |||
struct ast_frame * | f, | |||
struct ast_channel * | us, | |||
int | us_locked | |||
) | [static] |
queue a frame on a to either the p->owner or p->chan
Definition at line 232 of file chan_local.c.
References ao2_lock(), ao2_trylock(), ao2_unlock(), ast_channel_lock, ast_channel_trylock, ast_channel_unlock, AST_CONTROL_RINGING, AST_FRAME_CONTROL, ast_log(), ast_queue_frame(), ast_setstate(), AST_STATE_RINGING, local_pvt::chan, f, ast_channel::generator, LOG_ERROR, 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().
00234 { 00235 struct ast_channel *other = NULL; 00236 00237 /* Recalculate outbound channel */ 00238 other = isoutbound ? p->owner : p->chan; 00239 00240 if (!other) { 00241 return 0; 00242 } 00243 00244 /* do not queue frame if generator is on both local channels */ 00245 if (us && us->generator && other->generator) { 00246 return 0; 00247 } 00248 00249 /* Ensure that we have both channels locked */ 00250 while (other && ast_channel_trylock(other)) { 00251 int res; 00252 if ((res = ao2_unlock(p))) { 00253 ast_log(LOG_ERROR, "chan_local bug! '&p->lock' was not locked when entering local_queue_frame! (%s)\n", strerror(res)); 00254 return -1; 00255 } 00256 if (us && us_locked) { 00257 do { 00258 if (ast_channel_unlock(us)) { 00259 ast_log(LOG_ERROR, "chan_local bug! Our channel was not locked, yet arguments indicated that it was!!\n"); 00260 ao2_lock(p); 00261 return -1; 00262 } 00263 usleep(1); 00264 ast_channel_lock(us); 00265 } while (ao2_trylock(p)); 00266 } else { 00267 usleep(1); 00268 ao2_lock(p); 00269 } 00270 other = isoutbound ? p->owner : p->chan; 00271 } 00272 00273 if (other) { 00274 if (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_RINGING) { 00275 ast_setstate(other, AST_STATE_RINGING); 00276 } 00277 ast_queue_frame(other, f); 00278 ast_channel_unlock(other); 00279 } 00280 00281 return 0; 00282 }
static struct ast_frame * local_read | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 380 of file chan_local.c.
References ast_null_frame.
00381 { 00382 return &ast_null_frame; 00383 }
static struct ast_channel * local_request | ( | const char * | type, | |
int | format, | |||
void * | data, | |||
int * | cause | |||
) | [static] |
Part of PBX interface.
Definition at line 848 of file chan_local.c.
References ao2_ref(), ao2_unlink(), AST_STATE_DOWN, local_pvt::chan, local_alloc(), local_new(), and locals.
00849 { 00850 struct local_pvt *p = NULL; 00851 struct ast_channel *chan = NULL; 00852 00853 /* Allocate a new private structure and then Asterisk channel */ 00854 if ((p = local_alloc(data, format))) { 00855 if (!(chan = local_new(p, AST_STATE_DOWN))) { 00856 ao2_unlink(locals, p); 00857 } 00858 ao2_ref(p, -1); /* kill the ref from the alloc */ 00859 } 00860 00861 return chan; 00862 }
static int local_sendhtml | ( | struct ast_channel * | ast, | |
int | subclass, | |||
const char * | data, | |||
int | datalen | |||
) | [static] |
Definition at line 540 of file chan_local.c.
References ao2_lock(), ao2_ref(), ao2_unlock(), AST_FRAME_HTML, f, IS_OUTBOUND, local_queue_frame(), and ast_channel::tech_pvt.
00541 { 00542 struct local_pvt *p = ast->tech_pvt; 00543 int res = -1; 00544 struct ast_frame f = { AST_FRAME_HTML, }; 00545 int isoutbound; 00546 00547 if (!p) 00548 return -1; 00549 00550 ao2_lock(p); 00551 ao2_ref(p, 1); /* ref for local_queue_frame */ 00552 00553 isoutbound = IS_OUTBOUND(ast, p); 00554 f.subclass = subclass; 00555 f.data = (char *)data; 00556 f.datalen = datalen; 00557 res = local_queue_frame(p, isoutbound, &f, ast, 0); 00558 00559 ao2_unlock(p); 00560 ao2_ref(p, -1); 00561 00562 return res; 00563 }
static int local_sendtext | ( | struct ast_channel * | ast, | |
const char * | text | |||
) | [static] |
Definition at line 519 of file chan_local.c.
References ao2_lock(), ao2_ref(), ao2_unlock(), AST_FRAME_TEXT, f, IS_OUTBOUND, local_queue_frame(), and ast_channel::tech_pvt.
00520 { 00521 struct local_pvt *p = ast->tech_pvt; 00522 int res = -1; 00523 struct ast_frame f = { AST_FRAME_TEXT, }; 00524 int isoutbound; 00525 00526 if (!p) 00527 return -1; 00528 00529 ao2_lock(p); 00530 ao2_ref(p, 1); /* ref for local_queue_frame */ 00531 isoutbound = IS_OUTBOUND(ast, p); 00532 f.data = (char *) text; 00533 f.datalen = strlen(text) + 1; 00534 res = local_queue_frame(p, isoutbound, &f, ast, 0); 00535 ao2_unlock(p); 00536 ao2_ref(p, -1); 00537 return res; 00538 }
static int local_setoption | ( | struct ast_channel * | chan, | |
int | option, | |||
void * | data, | |||
int | datalen | |||
) | [static] |
Definition at line 132 of file chan_local.c.
References ao2_trylock(), ao2_unlock(), AST_CHAN_WRITE_INFO_T_VERSION, ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_log(), AST_OPTION_CHANNEL_WRITE, ast_chan_write_info_t::chan, local_pvt::chan, ast_chan_write_info_t::data, ast_chan_write_info_t::function, LOG_ERROR, LOG_WARNING, ast_channel::name, local_pvt::owner, ast_channel::tech_pvt, ast_chan_write_info_t::value, ast_chan_write_info_t::version, and ast_chan_write_info_t::write_fn.
00133 { 00134 int res; 00135 struct local_pvt *p; 00136 struct ast_channel *otherchan; 00137 ast_chan_write_info_t *write_info; 00138 00139 if (option != AST_OPTION_CHANNEL_WRITE) { 00140 return -1; 00141 } 00142 00143 write_info = data; 00144 00145 if (write_info->version != AST_CHAN_WRITE_INFO_T_VERSION) { 00146 ast_log(LOG_ERROR, "The chan_write_info_t type has changed, and this channel hasn't been updated!\n"); 00147 return -1; 00148 } 00149 00150 00151 startover: 00152 ast_channel_lock(chan); 00153 00154 p = chan->tech_pvt; 00155 if (!p) { 00156 ast_channel_unlock(chan); 00157 ast_log(LOG_WARNING, "Could not update other side of %s, local_pvt went away.\n", chan->name); 00158 return -1; 00159 } 00160 00161 while (ao2_trylock(p)) { 00162 ast_channel_unlock(chan); 00163 sched_yield(); 00164 ast_channel_lock(chan); 00165 p = chan->tech_pvt; 00166 if (!p) { 00167 ast_channel_unlock(chan); 00168 ast_log(LOG_WARNING, "Could not update other side of %s, local_pvt went away.\n", chan->name); 00169 return -1; 00170 } 00171 } 00172 00173 otherchan = (write_info->chan == p->owner) ? p->chan : p->owner; 00174 00175 if (!otherchan || otherchan == write_info->chan) { 00176 ao2_unlock(p); 00177 ast_channel_unlock(chan); 00178 ast_log(LOG_WARNING, "Could not update other side of %s, other side went away.\n", chan->name); 00179 return 0; 00180 } 00181 00182 if (ast_channel_trylock(otherchan)) { 00183 ao2_unlock(p); 00184 ast_channel_unlock(chan); 00185 goto startover; 00186 } 00187 00188 res = write_info->write_fn(otherchan, write_info->function, write_info->data, write_info->value); 00189 00190 ast_channel_unlock(otherchan); 00191 ao2_unlock(p); 00192 ast_channel_unlock(chan); 00193 00194 return res; 00195 }
static int local_write | ( | struct ast_channel * | ast, | |
struct ast_frame * | f | |||
) | [static] |
Definition at line 385 of file chan_local.c.
References ao2_lock(), ao2_ref(), ao2_unlock(), AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_log(), ast_test_flag, check_bridge(), f, IS_OUTBOUND, LOCAL_ALREADY_MASQED, local_queue_frame(), LOG_DEBUG, ast_channel::name, option_debug, and ast_channel::tech_pvt.
00386 { 00387 struct local_pvt *p = ast->tech_pvt; 00388 int res = -1; 00389 int isoutbound; 00390 00391 if (!p) 00392 return -1; 00393 00394 /* Just queue for delivery to the other side */ 00395 ao2_lock(p); 00396 ao2_ref(p, 1); /* ref for local_queue_frame */ 00397 isoutbound = IS_OUTBOUND(ast, p); 00398 if (isoutbound && f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) 00399 check_bridge(p); 00400 if (!ast_test_flag(p, LOCAL_ALREADY_MASQED)) 00401 res = local_queue_frame(p, isoutbound, f, ast, 1); 00402 else { 00403 if (option_debug) 00404 ast_log(LOG_DEBUG, "Not posting to queue since already masked on '%s'\n", ast->name); 00405 res = 0; 00406 } 00407 ao2_unlock(p); 00408 ao2_ref(p, -1); 00409 00410 return res; 00411 }
static int locals_cmp_cb | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
static int locals_show | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
CLI command "local show channels".
Definition at line 865 of file chan_local.c.
References ao2_container_count(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlock(), ast_cli(), locals, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
00866 { 00867 struct local_pvt *p = NULL; 00868 struct ao2_iterator it; 00869 00870 if (argc != 3) 00871 return RESULT_SHOWUSAGE; 00872 00873 00874 if (ao2_container_count(locals) == 0) { 00875 ast_cli(fd, "No local channels in use\n"); 00876 return RESULT_SUCCESS; 00877 } 00878 00879 it = ao2_iterator_init(locals, 0); 00880 while ((p = ao2_iterator_next(&it))) { 00881 ao2_lock(p); 00882 ast_cli(fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context); 00883 ao2_unlock(p); 00884 ao2_ref(p, -1); 00885 } 00886 ao2_iterator_destroy(&it); 00887 00888 return RESULT_SUCCESS; 00889 }
static int unload_module | ( | void | ) | [static] |
Unload the local proxy channel from Asterisk.
Definition at line 925 of file chan_local.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), ast_channel_unregister(), ast_cli_unregister_multiple(), ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, cli_local, local_tech, locals, and local_pvt::owner.
00926 { 00927 struct local_pvt *p = NULL; 00928 struct ao2_iterator it; 00929 00930 /* First, take us out of the channel loop */ 00931 ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 00932 ast_channel_unregister(&local_tech); 00933 00934 it = ao2_iterator_init(locals, 0); 00935 while ((p = ao2_iterator_next(&it))) { 00936 if (p->owner) { 00937 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); 00938 } 00939 ao2_ref(p, -1); 00940 } 00941 ao2_iterator_destroy(&it); 00942 ao2_ref(locals, -1); 00943 return 0; 00944 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "Local Proxy Channel (Note: used internally by other modules)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, } [static] |
Definition at line 946 of file chan_local.c.
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 946 of file chan_local.c.
const int BUCKET_SIZE = 1 [static] |
Definition at line 73 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 895 of file chan_local.c.
Referenced by load_module(), and unload_module().
struct ast_channel_tech local_tech [static] |
Definition at line 93 of file chan_local.c.
Referenced by load_module(), local_new(), and unload_module().
struct ao2_container* locals [static] |
Definition at line 75 of file chan_local.c.
char show_locals_usage[] [static] |
Initial value:
"Usage: local show channels\n" " Provides summary information on active local proxy channels.\n"
Definition at line 891 of file chan_local.c.
const char tdesc[] = "Local Proxy Channel Driver" [static] |
Definition at line 66 of file chan_local.c.