#include "asterisk.h"
#include <fcntl.h>
#include <sys/signal.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/sched.h"
#include "asterisk/io.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 |
the local pvt structure for all channels More... | |
Defines | |
#define | IS_OUTBOUND(a, b) (a == b->chan ? 1 : 0) |
#define | LOCAL_ALREADY_MASQED (1 << 0) |
#define | LOCAL_BRIDGE (1 << 3) |
#define | LOCAL_LAUNCHED_PBX (1 << 1) |
#define | LOCAL_MOH_PASSTHRU (1 << 4) |
#define | LOCAL_NO_OPTIMIZATION (1 << 2) |
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, format_t format) |
Create a call structure. | |
static int | local_answer (struct ast_channel *ast) |
static struct ast_channel * | local_bridgedchannel (struct ast_channel *chan, struct ast_channel *bridge) |
Return the bridged channel of a Local channel. | |
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, const char *linkedid) |
Start new local channel. | |
static int | local_queryoption (struct ast_channel *ast, int option, void *data, int *datalen) |
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, format_t format, const struct ast_channel *requestor, 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 char * | locals_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
CLI command "local show channels". | |
static int | manager_optimize_away (struct mansession *s, const struct message *m) |
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_LOAD_ORDER , .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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DRIVER, } |
static 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_jb_conf | g_jb_conf |
static struct ast_channel_tech | local_tech |
static struct ao2_container * | locals |
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 74 of file chan_local.c.
Referenced by local_answer(), local_digit_begin(), local_digit_end(), local_hangup(), local_indicate(), local_queryoption(), local_sendhtml(), local_sendtext(), and local_write().
#define LOCAL_ALREADY_MASQED (1 << 0) |
Already masqueraded
Definition at line 152 of file chan_local.c.
Referenced by check_bridge(), and local_write().
#define LOCAL_BRIDGE (1 << 3) |
Report back the "true" channel as being bridged to
Definition at line 155 of file chan_local.c.
Referenced by local_alloc(), and local_bridgedchannel().
#define LOCAL_LAUNCHED_PBX (1 << 1) |
PBX was launched
Definition at line 153 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 156 of file chan_local.c.
Referenced by local_alloc(), and local_indicate().
#define LOCAL_NO_OPTIMIZATION (1 << 2) |
Do not optimize using masquerading
Definition at line 154 of file chan_local.c.
Referenced by check_bridge(), local_alloc(), and manager_optimize_away().
static void __reg_module | ( | void | ) | [static] |
Definition at line 1245 of file chan_local.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 1245 of file chan_local.c.
static void check_bridge | ( | struct local_pvt * | p | ) | [static] |
Definition at line 434 of file chan_local.c.
References ast_channel::_bridge, ast_party_caller::ani, ast_app_group_update(), ast_bridged_channel(), ast_channel_masquerade(), ast_channel_trylock, ast_channel_unlock, ast_check_hangup(), AST_LIST_EMPTY, ast_set_flag, ast_test_flag, ast_channel::audiohooks, ast_channel::caller, local_pvt::chan, ast_channel::dialed, ast_party_redirecting::from, ast_party_caller::id, LOCAL_ALREADY_MASQED, LOCAL_NO_OPTIMIZATION, ast_channel::monitor, ast_party_id::name, ast_party_dialed::number, ast_party_id::number, local_pvt::owner, ast_channel::readq, ast_channel::redirecting, ast_party_dialed::str, ast_party_dialed::subaddress, ast_party_id::subaddress, ast_party_redirecting::to, ast_party_subaddress::valid, ast_party_number::valid, and ast_party_name::valid.
Referenced by local_write().
00435 { 00436 struct ast_channel_monitor *tmp; 00437 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))) 00438 return; 00439 00440 /* only do the masquerade if we are being called on the outbound channel, 00441 if it has been bridged to another channel and if there are no pending 00442 frames on the owner channel (because they would be transferred to the 00443 outbound channel during the masquerade) 00444 */ 00445 if (p->chan->_bridge /* Not ast_bridged_channel! Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) { 00446 /* Masquerade bridged channel into owner */ 00447 /* Lock everything we need, one by one, and give up if 00448 we can't get everything. Remember, we'll get another 00449 chance in just a little bit */ 00450 if (!ast_channel_trylock(p->chan->_bridge)) { 00451 if (!ast_check_hangup(p->chan->_bridge)) { 00452 if (!ast_channel_trylock(p->owner)) { 00453 if (!ast_check_hangup(p->owner)) { 00454 if (p->owner->monitor && !p->chan->_bridge->monitor) { 00455 /* If a local channel is being monitored, we don't want a masquerade 00456 * to cause the monitor to go away. Since the masquerade swaps the monitors, 00457 * pre-swapping the monitors before the masquerade will ensure that the monitor 00458 * ends up where it is expected. 00459 */ 00460 tmp = p->owner->monitor; 00461 p->owner->monitor = p->chan->_bridge->monitor; 00462 p->chan->_bridge->monitor = tmp; 00463 } 00464 if (p->chan->audiohooks) { 00465 struct ast_audiohook_list *audiohooks_swapper; 00466 audiohooks_swapper = p->chan->audiohooks; 00467 p->chan->audiohooks = p->owner->audiohooks; 00468 p->owner->audiohooks = audiohooks_swapper; 00469 } 00470 00471 /* If any Caller ID was set, preserve it after masquerade like above. We must check 00472 * to see if Caller ID was set because otherwise we'll mistakingly copy info not 00473 * set from the dialplan and will overwrite the real channel Caller ID. The reason 00474 * for this whole preswapping action is because the Caller ID is set on the channel 00475 * thread (which is the to be masqueraded away local channel) before both local 00476 * channels are optimized away. 00477 */ 00478 if (p->owner->caller.id.name.valid || p->owner->caller.id.number.valid 00479 || p->owner->caller.id.subaddress.valid || p->owner->caller.ani.name.valid 00480 || p->owner->caller.ani.number.valid || p->owner->caller.ani.subaddress.valid) { 00481 struct ast_party_caller tmp; 00482 tmp = p->owner->caller; 00483 p->owner->caller = p->chan->_bridge->caller; 00484 p->chan->_bridge->caller = tmp; 00485 } 00486 if (p->owner->redirecting.from.name.valid || p->owner->redirecting.from.number.valid 00487 || p->owner->redirecting.from.subaddress.valid || p->owner->redirecting.to.name.valid 00488 || p->owner->redirecting.to.number.valid || p->owner->redirecting.to.subaddress.valid) { 00489 struct ast_party_redirecting tmp; 00490 tmp = p->owner->redirecting; 00491 p->owner->redirecting = p->chan->_bridge->redirecting; 00492 p->chan->_bridge->redirecting = tmp; 00493 } 00494 if (p->owner->dialed.number.str || p->owner->dialed.subaddress.valid) { 00495 struct ast_party_dialed tmp; 00496 tmp = p->owner->dialed; 00497 p->owner->dialed = p->chan->_bridge->dialed; 00498 p->chan->_bridge->dialed = tmp; 00499 } 00500 00501 00502 ast_app_group_update(p->chan, p->owner); 00503 ast_channel_masquerade(p->owner, p->chan->_bridge); 00504 ast_set_flag(p, LOCAL_ALREADY_MASQED); 00505 } 00506 ast_channel_unlock(p->owner); 00507 } 00508 ast_channel_unlock(p->chan->_bridge); 00509 } 00510 } 00511 } 00512 }
static int load_module | ( | void | ) | [static] |
Load module into PBX, register channel.
Definition at line 1199 of file chan_local.c.
References ao2_container_alloc, ao2_ref, ast_channel_register(), ast_cli_register_multiple(), ast_log(), ast_manager_register_xml, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, cli_local, EVENT_FLAG_CALL, EVENT_FLAG_SYSTEM, local_tech, locals, locals_cmp_cb(), LOG_ERROR, and manager_optimize_away().
01200 { 01201 if (!(locals = ao2_container_alloc(BUCKET_SIZE, NULL, locals_cmp_cb))) { 01202 return AST_MODULE_LOAD_FAILURE; 01203 } 01204 01205 /* Make sure we can register our channel type */ 01206 if (ast_channel_register(&local_tech)) { 01207 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n"); 01208 ao2_ref(locals, -1); 01209 return AST_MODULE_LOAD_FAILURE; 01210 } 01211 ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 01212 ast_manager_register_xml("LocalOptimizeAway", EVENT_FLAG_SYSTEM|EVENT_FLAG_CALL, manager_optimize_away); 01213 01214 return AST_MODULE_LOAD_SUCCESS; 01215 }
Create a call structure.
Definition at line 959 of file chan_local.c.
References ao2_alloc, ao2_link, ast_copy_string(), ast_exists_extension(), AST_JB_ENABLED, ast_log(), ast_set_flag, ast_test_flag, g_jb_conf, LOCAL_BRIDGE, LOCAL_MOH_PASSTHRU, LOCAL_NO_OPTIMIZATION, locals, LOG_ERROR, and LOG_NOTICE.
Referenced by local_request().
00960 { 00961 struct local_pvt *tmp = NULL; 00962 char *c = NULL, *opts = NULL; 00963 00964 if (!(tmp = ao2_alloc(sizeof(*tmp), NULL))) { 00965 return NULL; 00966 } 00967 00968 /* Initialize private structure information */ 00969 ast_copy_string(tmp->exten, data, sizeof(tmp->exten)); 00970 00971 memcpy(&tmp->jb_conf, &g_jb_conf, sizeof(tmp->jb_conf)); 00972 00973 /* Look for options */ 00974 if ((opts = strchr(tmp->exten, '/'))) { 00975 *opts++ = '\0'; 00976 if (strchr(opts, 'n')) 00977 ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION); 00978 if (strchr(opts, 'j')) { 00979 if (ast_test_flag(tmp, LOCAL_NO_OPTIMIZATION)) 00980 ast_set_flag(&tmp->jb_conf, AST_JB_ENABLED); 00981 else { 00982 ast_log(LOG_ERROR, "You must use the 'n' option for chan_local " 00983 "to use the 'j' option to enable the jitterbuffer\n"); 00984 } 00985 } 00986 if (strchr(opts, 'b')) { 00987 ast_set_flag(tmp, LOCAL_BRIDGE); 00988 } 00989 if (strchr(opts, 'm')) { 00990 ast_set_flag(tmp, LOCAL_MOH_PASSTHRU); 00991 } 00992 } 00993 00994 /* Look for a context */ 00995 if ((c = strchr(tmp->exten, '@'))) 00996 *c++ = '\0'; 00997 00998 ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context)); 00999 01000 tmp->reqformat = format; 01001 01002 #if 0 01003 /* We can't do this check here, because we don't know the CallerID yet, and 01004 * the CallerID could potentially affect what step is actually taken (or 01005 * even if that step exists). */ 01006 if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) { 01007 ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context); 01008 tmp = local_pvt_destroy(tmp); 01009 } else { 01010 #endif 01011 /* Add to list */ 01012 ao2_link(locals, tmp); 01013 #if 0 01014 } 01015 #endif 01016 return tmp; /* this is returned with a ref */ 01017 }
static int local_answer | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 406 of file chan_local.c.
References 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.
00407 { 00408 struct local_pvt *p = ast->tech_pvt; 00409 int isoutbound; 00410 int res = -1; 00411 00412 if (!p) 00413 return -1; 00414 00415 ao2_lock(p); 00416 ao2_ref(p, 1); 00417 isoutbound = IS_OUTBOUND(ast, p); 00418 if (isoutbound) { 00419 /* Pass along answer since somebody answered us */ 00420 struct ast_frame answer = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } }; 00421 res = local_queue_frame(p, isoutbound, &answer, ast, 1); 00422 } else { 00423 ast_log(LOG_WARNING, "Huh? Local is being asked to answer?\n"); 00424 } 00425 ao2_unlock(p); 00426 ao2_ref(p, -1); 00427 return res; 00428 }
static struct ast_channel * local_bridgedchannel | ( | struct ast_channel * | chan, | |
struct ast_channel * | bridge | |||
) | [static] |
Return the bridged channel of a Local channel.
Definition at line 266 of file chan_local.c.
References ast_channel::_bridge, ao2_lock, ao2_unlock, ast_debug, ast_test_flag, ast_channel::bridge, local_pvt::chan, LOCAL_BRIDGE, ast_channel::name, local_pvt::owner, and ast_channel::tech_pvt.
00267 { 00268 struct local_pvt *p = bridge->tech_pvt; 00269 struct ast_channel *bridged = bridge; 00270 00271 if (!p) { 00272 ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning <none>\n", 00273 chan->name, bridge->name); 00274 return NULL; 00275 } 00276 00277 ao2_lock(p); 00278 00279 if (ast_test_flag(p, LOCAL_BRIDGE)) { 00280 /* Find the opposite channel */ 00281 bridged = (bridge == p->owner ? p->chan : p->owner); 00282 00283 /* Now see if the opposite channel is bridged to anything */ 00284 if (!bridged) { 00285 bridged = bridge; 00286 } else if (bridged->_bridge) { 00287 bridged = bridged->_bridge; 00288 } 00289 } 00290 00291 ao2_unlock(p); 00292 00293 return bridged; 00294 }
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 732 of file chan_local.c.
References ast_channel::accountcode, accountcode, ao2_lock, ao2_ref, ao2_trylock, ao2_unlock, ast_calloc, ast_cdr_update(), ast_channel_cc_params_init(), ast_channel_datastore_inherit(), ast_channel_get_cc_config_params(), ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_connected_line_copy_from_caller(), ast_connected_line_copy_to_caller(), ast_exists_extension(), AST_FLAG_ANSWERED_ELSEWHERE, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), ast_party_dialed_copy(), ast_party_redirecting_copy(), ast_pbx_start(), ast_set_cc_interfaces_chanvar(), ast_set_flag, ast_strdupa, ast_string_field_set, ast_test_flag, ast_channel::caller, local_pvt::chan, ast_channel::connected, ast_channel::context, ast_channel::dialed, ast_var_t::entries, ast_channel::exten, ast_party_caller::id, ast_channel::language, language, len(), LOCAL_LAUNCHED_PBX, LOG_NOTICE, ast_channel::musicclass, musicclass, ast_var_t::name, ast_party_id::number, local_pvt::owner, ast_channel::redirecting, S_COR, ast_party_number::str, ast_channel::tech_pvt, ast_party_number::valid, value, and ast_channel::varshead.
00733 { 00734 struct local_pvt *p = ast->tech_pvt; 00735 int res; 00736 struct ast_var_t *varptr = NULL, *new; 00737 size_t len, namelen; 00738 char *reduced_dest = ast_strdupa(dest); 00739 char *slash; 00740 00741 if (!p || p->owner != ast) { 00742 return -1; 00743 } 00744 00745 /* since we are letting go of channel locks that were locked coming into 00746 * this function, then we need to give the tech pvt a ref */ 00747 ao2_ref(p, 1); 00748 00749 while (ao2_trylock(p)) { 00750 ast_channel_unlock(ast); 00751 sched_yield(); 00752 ast_channel_lock(ast); 00753 } 00754 while ((p->chan && p->owner) && ast_channel_trylock(p->chan)) { 00755 ao2_unlock(p); 00756 if (p->owner) { 00757 ast_channel_unlock(p->owner); 00758 } 00759 sched_yield(); 00760 if (p->owner) { 00761 ast_channel_lock(p->owner); 00762 } 00763 ao2_lock(p); 00764 } 00765 00766 if (!p->owner || !p->chan) { 00767 /* someone went away during the locking madness. 00768 * time to bail. */ 00769 if (p->chan) { 00770 ast_channel_unlock(p->chan); 00771 } 00772 ao2_unlock(p); 00773 ao2_ref(p,-1); 00774 return -1; 00775 } 00776 00777 /* 00778 * Note that cid_num and cid_name aren't passed in the ast_channel_alloc 00779 * call, so it's done here instead. 00780 * 00781 * All these failure points just return -1. The individual strings will 00782 * be cleared when we destroy the channel. 00783 */ 00784 ast_party_redirecting_copy(&p->chan->redirecting, &p->owner->redirecting); 00785 00786 ast_party_dialed_copy(&p->chan->dialed, &p->owner->dialed); 00787 00788 ast_connected_line_copy_to_caller(&p->chan->caller, &p->owner->connected); 00789 ast_connected_line_copy_from_caller(&p->chan->connected, &p->owner->caller); 00790 00791 ast_string_field_set(p->chan, language, p->owner->language); 00792 ast_string_field_set(p->chan, accountcode, p->owner->accountcode); 00793 ast_string_field_set(p->chan, musicclass, p->owner->musicclass); 00794 ast_cdr_update(p->chan); 00795 00796 ast_channel_cc_params_init(p->chan, ast_channel_get_cc_config_params(p->owner)); 00797 00798 /* Make sure we inherit the ANSWERED_ELSEWHERE flag if it's set on the queue/dial call request in the dialplan */ 00799 if (ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) { 00800 ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE); 00801 } 00802 00803 /* copy the channel variables from the incoming channel to the outgoing channel */ 00804 /* Note that due to certain assumptions, they MUST be in the same order */ 00805 AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) { 00806 namelen = strlen(varptr->name); 00807 len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2; 00808 if ((new = ast_calloc(1, len))) { 00809 memcpy(new, varptr, len); 00810 new->value = &(new->name[0]) + namelen + 1; 00811 AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries); 00812 } 00813 } 00814 ast_channel_datastore_inherit(p->owner, p->chan); 00815 /* If the local channel has /n or /b on the end of it, 00816 * we need to lop that off for our argument to setting 00817 * up the CC_INTERFACES variable 00818 */ 00819 if ((slash = strrchr(reduced_dest, '/'))) { 00820 *slash = '\0'; 00821 } 00822 ast_set_cc_interfaces_chanvar(p->chan, reduced_dest); 00823 00824 if (!ast_exists_extension(p->chan, p->chan->context, p->chan->exten, 1, 00825 S_COR(p->owner->caller.id.number.valid, p->owner->caller.id.number.str, NULL))) { 00826 ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->chan->exten, p->chan->context); 00827 ao2_unlock(p); 00828 ast_channel_unlock(p->chan); 00829 ao2_ref(p, -1); 00830 return -1; 00831 } 00832 00833 /* Start switch on sub channel */ 00834 if (!(res = ast_pbx_start(p->chan))) 00835 ast_set_flag(p, LOCAL_LAUNCHED_PBX); 00836 00837 ao2_unlock(p); 00838 ast_channel_unlock(p->chan); 00839 ao2_ref(p, -1); 00840 return res; 00841 }
static int local_devicestate | ( | void * | data | ) | [static] |
Adds devicestate to local channels.
Definition at line 224 of file chan_local.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_debug, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, ast_exists_extension(), ast_log(), ast_strdupa, local_pvt::context, context, local_pvt::exten, exten, locals, LOG_WARNING, and local_pvt::owner.
00225 { 00226 char *exten = ast_strdupa(data); 00227 char *context = NULL, *opts = NULL; 00228 int res; 00229 struct local_pvt *lp; 00230 struct ao2_iterator it; 00231 00232 if (!(context = strchr(exten, '@'))) { 00233 ast_log(LOG_WARNING, "Someone used Local/%s somewhere without a @context. This is bad.\n", exten); 00234 return AST_DEVICE_INVALID; 00235 } 00236 00237 *context++ = '\0'; 00238 00239 /* Strip options if they exist */ 00240 if ((opts = strchr(context, '/'))) 00241 *opts = '\0'; 00242 00243 ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context); 00244 00245 res = ast_exists_extension(NULL, context, exten, 1, NULL); 00246 if (!res) 00247 return AST_DEVICE_INVALID; 00248 00249 res = AST_DEVICE_NOT_INUSE; 00250 00251 it = ao2_iterator_init(locals, 0); 00252 while ((lp = ao2_iterator_next(&it))) { 00253 if (!strcmp(exten, lp->exten) && !strcmp(context, lp->context) && lp->owner) { 00254 res = AST_DEVICE_INUSE; 00255 ao2_ref(lp, -1); 00256 break; 00257 } 00258 ao2_ref(lp, -1); 00259 } 00260 ao2_iterator_destroy(&it); 00261 00262 return res; 00263 }
static int local_digit_begin | ( | struct ast_channel * | ast, | |
char | digit | |||
) | [static] |
Definition at line 643 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.
00644 { 00645 struct local_pvt *p = ast->tech_pvt; 00646 int res = -1; 00647 struct ast_frame f = { AST_FRAME_DTMF_BEGIN, }; 00648 int isoutbound; 00649 00650 if (!p) 00651 return -1; 00652 00653 ao2_ref(p, 1); /* ref for local_queue_frame */ 00654 ao2_lock(p); 00655 isoutbound = IS_OUTBOUND(ast, p); 00656 f.subclass.integer = digit; 00657 res = local_queue_frame(p, isoutbound, &f, ast, 0); 00658 ao2_unlock(p); 00659 ao2_ref(p, -1); 00660 00661 return res; 00662 }
static int local_digit_end | ( | struct ast_channel * | ast, | |
char | digit, | |||
unsigned int | duration | |||
) | [static] |
Definition at line 664 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.
00665 { 00666 struct local_pvt *p = ast->tech_pvt; 00667 int res = -1; 00668 struct ast_frame f = { AST_FRAME_DTMF_END, }; 00669 int isoutbound; 00670 00671 if (!p) 00672 return -1; 00673 00674 ao2_ref(p, 1); /* ref for local_queue_frame */ 00675 ao2_lock(p); 00676 isoutbound = IS_OUTBOUND(ast, p); 00677 f.subclass.integer = digit; 00678 f.len = duration; 00679 res = local_queue_frame(p, isoutbound, &f, ast, 0); 00680 ao2_unlock(p); 00681 ao2_ref(p, -1); 00682 00683 return res; 00684 }
static int local_fixup | ( | struct ast_channel * | oldchan, | |
struct ast_channel * | newchan | |||
) | [static] |
Definition at line 546 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.
00547 { 00548 struct local_pvt *p = newchan->tech_pvt; 00549 00550 if (!p) 00551 return -1; 00552 00553 ao2_lock(p); 00554 00555 if ((p->owner != oldchan) && (p->chan != oldchan)) { 00556 ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan); 00557 ao2_unlock(p); 00558 return -1; 00559 } 00560 if (p->owner == oldchan) 00561 p->owner = newchan; 00562 else 00563 p->chan = newchan; 00564 00565 /* Do not let a masquerade cause a Local channel to be bridged to itself! */ 00566 if (!ast_check_hangup(newchan) && (p->owner->_bridge == p->chan || p->chan->_bridge == p->owner)) { 00567 ast_log(LOG_WARNING, "You can not bridge a Local channel to itself!\n"); 00568 ao2_unlock(p); 00569 ast_queue_hangup(newchan); 00570 return -1; 00571 } 00572 00573 ao2_unlock(p); 00574 return 0; 00575 }
static int local_hangup | ( | struct ast_channel * | ast | ) | [static] |
Hangup a call through the local proxy channel.
Definition at line 844 of file chan_local.c.
References ao2_lock, ao2_ref, ao2_unlink, ao2_unlock, ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_clear_flag, AST_CONTROL_HANGUP, ast_debug, AST_FLAG_ANSWERED_ELSEWHERE, AST_FRAME_CONTROL, ast_hangup(), ast_module_user_remove, ast_queue_hangup(), ast_set_flag, 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(), status, ast_channel::tech_pvt, local_pvt::u_chan, and local_pvt::u_owner.
00845 { 00846 struct local_pvt *p = ast->tech_pvt; 00847 int isoutbound; 00848 struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_HANGUP }, .data.uint32 = ast->hangupcause }; 00849 struct ast_channel *ochan = NULL; 00850 00851 if (!p) 00852 return -1; 00853 00854 /* we MUST give the tech_pvt a ref here since we are unlocking the 00855 * channel during deadlock avoidance. */ 00856 ao2_ref(p, 1); 00857 00858 ao2_lock(p); 00859 00860 isoutbound = IS_OUTBOUND(ast, p); 00861 00862 if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) { 00863 ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE); 00864 ast_debug(2, "This local call has the ANSWERED_ELSEWHERE flag set.\n"); 00865 } 00866 00867 if (isoutbound) { 00868 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS"); 00869 if ((status) && (p->owner)) { 00870 /* Deadlock avoidance */ 00871 while (p->owner && ast_channel_trylock(p->owner)) { 00872 ao2_unlock(p); 00873 if (p->chan) { 00874 ast_channel_unlock(p->chan); 00875 } 00876 sched_yield(); 00877 if (p->chan) { 00878 ast_channel_lock(p->chan); 00879 } 00880 ao2_lock(p); 00881 } 00882 if (p->owner) { 00883 p->owner->hangupcause = p->chan->hangupcause; 00884 pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status); 00885 ast_channel_unlock(p->owner); 00886 } 00887 } 00888 if (!p->chan) { 00889 /* chan was == to ast and was !NULL before deadlock avoidance started, if chan 00890 * is NULL now, then we should bail because that channel 00891 * hungup already. This is possible because we let go of the 00892 * lock given to the ast channel passed to this function during 00893 * deadlock avoidance. */ 00894 ao2_unlock(p); 00895 ao2_ref(p, -1); 00896 return 0; 00897 } 00898 p->chan = NULL; 00899 ast_clear_flag(p, LOCAL_LAUNCHED_PBX); 00900 ast_module_user_remove(p->u_chan); 00901 } else { 00902 ast_module_user_remove(p->u_owner); 00903 while (p->chan && ast_channel_trylock(p->chan)) { 00904 ao2_unlock(p); 00905 if (p->owner) { 00906 ast_channel_unlock(p->owner); 00907 } 00908 sched_yield(); 00909 if (p->owner) { 00910 ast_channel_lock(p->owner); 00911 } 00912 ao2_lock(p); 00913 } 00914 if (p->chan) { 00915 ast_queue_hangup(p->chan); 00916 ast_channel_unlock(p->chan); 00917 } 00918 00919 if (!p->owner) { 00920 /* owner was == to ast and was !NULL before deadlock avoidance started, if 00921 * owner is NULL now, then we should bail because that channel 00922 * hungup already. This is possible because we let go of the 00923 * lock given to the ast channel passed to this function during 00924 * deadlock avoidance. */ 00925 ao2_unlock(p); 00926 ao2_ref(p, -1); 00927 return 0; 00928 } 00929 p->owner = NULL; 00930 } 00931 00932 ast->tech_pvt = NULL; 00933 00934 if (!p->owner && !p->chan) { 00935 ao2_unlock(p); 00936 00937 /* Remove from list */ 00938 ao2_unlink(locals, p); 00939 ao2_ref(p, -1); 00940 return 0; 00941 } 00942 if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) { 00943 /* Need to actually hangup since there is no PBX */ 00944 ochan = p->chan; 00945 } else { 00946 local_queue_frame(p, isoutbound, &f, NULL, 1); 00947 } 00948 00949 ao2_unlock(p); 00950 if (ochan) { 00951 ast_hangup(ochan); 00952 } 00953 00954 ao2_ref(p, -1); 00955 return 0; 00956 }
static int local_indicate | ( | struct ast_channel * | ast, | |
int | condition, | |||
const void * | data, | |||
size_t | datalen | |||
) | [static] |
Definition at line 577 of file chan_local.c.
References ao2_lock, ao2_ref, ao2_unlock, ast_connected_line_build_data(), ast_connected_line_copy_to_caller(), AST_CONTROL_CONNECTED_LINE, AST_CONTROL_HOLD, AST_CONTROL_REDIRECTING, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, ast_moh_start(), ast_moh_stop(), ast_redirecting_build_data(), ast_test_flag, ast_channel::caller, local_pvt::chan, ast_channel::connected, f, IS_OUTBOUND, LOCAL_MOH_PASSTHRU, local_queue_frame(), local_pvt::owner, ast_channel::redirecting, and ast_channel::tech_pvt.
00578 { 00579 struct local_pvt *p = ast->tech_pvt; 00580 int res = 0; 00581 struct ast_frame f = { AST_FRAME_CONTROL, }; 00582 int isoutbound; 00583 00584 if (!p) 00585 return -1; 00586 00587 ao2_ref(p, 1); /* ref for local_queue_frame */ 00588 00589 /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */ 00590 if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) { 00591 ast_moh_start(ast, data, NULL); 00592 } else if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_UNHOLD) { 00593 ast_moh_stop(ast); 00594 } else if (condition == AST_CONTROL_CONNECTED_LINE || condition == AST_CONTROL_REDIRECTING) { 00595 struct ast_channel *this_channel; 00596 struct ast_channel *the_other_channel; 00597 /* A connected line update frame may only contain a partial amount of data, such 00598 * as just a source, or just a ton, and not the full amount of information. However, 00599 * the collected information is all stored in the outgoing channel's connectedline 00600 * structure, so when receiving a connected line update on an outgoing local channel, 00601 * we need to transmit the collected connected line information instead of whatever 00602 * happens to be in this control frame. The same applies for redirecting information, which 00603 * is why it is handled here as well.*/ 00604 ao2_lock(p); 00605 isoutbound = IS_OUTBOUND(ast, p); 00606 if (isoutbound) { 00607 this_channel = p->chan; 00608 the_other_channel = p->owner; 00609 } else { 00610 this_channel = p->owner; 00611 the_other_channel = p->chan; 00612 } 00613 if (the_other_channel) { 00614 unsigned char frame_data[1024]; 00615 if (condition == AST_CONTROL_CONNECTED_LINE) { 00616 if (isoutbound) { 00617 ast_connected_line_copy_to_caller(&the_other_channel->caller, &this_channel->connected); 00618 } 00619 f.datalen = ast_connected_line_build_data(frame_data, sizeof(frame_data), &this_channel->connected, NULL); 00620 } else { 00621 f.datalen = ast_redirecting_build_data(frame_data, sizeof(frame_data), &this_channel->redirecting, NULL); 00622 } 00623 f.subclass.integer = condition; 00624 f.data.ptr = frame_data; 00625 res = local_queue_frame(p, isoutbound, &f, ast, 1); 00626 } 00627 ao2_unlock(p); 00628 } else { 00629 /* Queue up a frame representing the indication as a control frame */ 00630 ao2_lock(p); 00631 isoutbound = IS_OUTBOUND(ast, p); 00632 f.subclass.integer = condition; 00633 f.data.ptr = (void*)data; 00634 f.datalen = datalen; 00635 res = local_queue_frame(p, isoutbound, &f, ast, 1); 00636 ao2_unlock(p); 00637 } 00638 00639 ao2_ref(p, -1); 00640 return res; 00641 }
static struct ast_channel* local_new | ( | struct local_pvt * | p, | |
int | state, | |||
const char * | linkedid | |||
) | [static] |
Start new local channel.
Definition at line 1020 of file chan_local.c.
References ast_channel::accountcode, ast_channel::amaflags, ast_best_codec(), ast_channel_alloc, ast_channel_release(), ast_copy_string(), ast_jb_configure(), 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_pvt::jb_conf, 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, ast_channel::tech, ast_channel::tech_pvt, local_pvt::u_chan, local_pvt::u_owner, and ast_channel::writeformat.
Referenced by local_request().
01021 { 01022 struct ast_channel *tmp = NULL, *tmp2 = NULL; 01023 int randnum = ast_random() & 0xffff, fmt = 0; 01024 const char *t; 01025 int ama; 01026 01027 /* Allocate two new Asterisk channels */ 01028 /* safe accountcode */ 01029 if (p->owner && p->owner->accountcode) 01030 t = p->owner->accountcode; 01031 else 01032 t = ""; 01033 01034 if (p->owner) 01035 ama = p->owner->amaflags; 01036 else 01037 ama = 0; 01038 if (!(tmp = ast_channel_alloc(1, state, 0, 0, t, p->exten, p->context, linkedid, ama, "Local/%s@%s-%04x;1", p->exten, p->context, randnum)) 01039 || !(tmp2 = ast_channel_alloc(1, AST_STATE_RING, 0, 0, t, p->exten, p->context, linkedid, ama, "Local/%s@%s-%04x;2", p->exten, p->context, randnum))) { 01040 if (tmp) { 01041 tmp = ast_channel_release(tmp); 01042 } 01043 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n"); 01044 return NULL; 01045 } 01046 01047 tmp2->tech = tmp->tech = &local_tech; 01048 01049 tmp->nativeformats = p->reqformat; 01050 tmp2->nativeformats = p->reqformat; 01051 01052 /* Determine our read/write format and set it on each channel */ 01053 fmt = ast_best_codec(p->reqformat); 01054 tmp->writeformat = fmt; 01055 tmp2->writeformat = fmt; 01056 tmp->rawwriteformat = fmt; 01057 tmp2->rawwriteformat = fmt; 01058 tmp->readformat = fmt; 01059 tmp2->readformat = fmt; 01060 tmp->rawreadformat = fmt; 01061 tmp2->rawreadformat = fmt; 01062 01063 tmp->tech_pvt = p; 01064 tmp2->tech_pvt = p; 01065 01066 p->owner = tmp; 01067 p->chan = tmp2; 01068 p->u_owner = ast_module_user_add(p->owner); 01069 p->u_chan = ast_module_user_add(p->chan); 01070 01071 ast_copy_string(tmp->context, p->context, sizeof(tmp->context)); 01072 ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context)); 01073 ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten)); 01074 tmp->priority = 1; 01075 tmp2->priority = 1; 01076 01077 ast_jb_configure(tmp, &p->jb_conf); 01078 01079 return tmp; 01080 }
static int local_queryoption | ( | struct ast_channel * | ast, | |
int | option, | |||
void * | data, | |||
int * | datalen | |||
) | [static] |
Definition at line 296 of file chan_local.c.
References ao2_lock, ao2_unlock, ast_bridged_channel(), ast_channel_queryoption(), ast_channel_trylock, ast_channel_unlock, AST_OPTION_T38_STATE, local_pvt::chan, IS_OUTBOUND, local_pvt::owner, and ast_channel::tech_pvt.
00297 { 00298 struct local_pvt *p = ast->tech_pvt; 00299 struct ast_channel *chan, *bridged; 00300 int res; 00301 00302 if (!p) { 00303 return -1; 00304 } 00305 00306 if (option != AST_OPTION_T38_STATE) { 00307 /* AST_OPTION_T38_STATE is the only supported option at this time */ 00308 return -1; 00309 } 00310 00311 ao2_lock(p); 00312 chan = IS_OUTBOUND(ast, p) ? p->owner : p->chan; 00313 00314 try_again: 00315 if (!chan) { 00316 ao2_unlock(p); 00317 return -1; 00318 } 00319 00320 if (ast_channel_trylock(chan)) { 00321 ao2_unlock(p); 00322 sched_yield(); 00323 ao2_lock(p); 00324 chan = IS_OUTBOUND(ast, p) ? p->owner : p->chan; 00325 goto try_again; 00326 } 00327 00328 bridged = ast_bridged_channel(chan); 00329 if (!bridged) { 00330 /* can't query channel unless we are bridged */ 00331 ao2_unlock(p); 00332 ast_channel_unlock(chan); 00333 return -1; 00334 } 00335 00336 if (ast_channel_trylock(bridged)) { 00337 ast_channel_unlock(chan); 00338 ao2_unlock(p); 00339 sched_yield(); 00340 ao2_lock(p); 00341 chan = IS_OUTBOUND(ast, p) ? p->owner : p->chan; 00342 goto try_again; 00343 } 00344 00345 res = ast_channel_queryoption(bridged, option, data, datalen, 0); 00346 ao2_unlock(p); 00347 ast_channel_unlock(chan); 00348 ast_channel_unlock(bridged); 00349 return res; 00350 }
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 360 of file chan_local.c.
References ao2_lock, ao2_trylock, ao2_unlock, 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, CHANNEL_DEADLOCK_AVOIDANCE, 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().
00362 { 00363 struct ast_channel *other = NULL; 00364 00365 /* Recalculate outbound channel */ 00366 other = isoutbound ? p->owner : p->chan; 00367 00368 if (!other) { 00369 return 0; 00370 } 00371 00372 /* do not queue frame if generator is on both local channels */ 00373 if (us && us->generator && other->generator) { 00374 return 0; 00375 } 00376 00377 /* Ensure that we have both channels locked */ 00378 while (other && ast_channel_trylock(other)) { 00379 int res; 00380 if ((res = ao2_unlock(p))) { 00381 ast_log(LOG_ERROR, "chan_local bug! '&p->lock' was not locked when entering local_queue_frame! (%s)\n", strerror(res)); 00382 return -1; 00383 } 00384 if (us && us_locked) { 00385 do { 00386 CHANNEL_DEADLOCK_AVOIDANCE(us); 00387 } while (ao2_trylock(p)); 00388 } else { 00389 usleep(1); 00390 ao2_lock(p); 00391 } 00392 other = isoutbound ? p->owner : p->chan; 00393 } 00394 00395 if (other) { 00396 if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_RINGING) { 00397 ast_setstate(other, AST_STATE_RINGING); 00398 } 00399 ast_queue_frame(other, f); 00400 ast_channel_unlock(other); 00401 } 00402 00403 return 0; 00404 }
static struct ast_frame * local_read | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 514 of file chan_local.c.
References ast_null_frame.
00515 { 00516 return &ast_null_frame; 00517 }
static struct ast_channel * local_request | ( | const char * | type, | |
format_t | format, | |||
const struct ast_channel * | requestor, | |||
void * | data, | |||
int * | cause | |||
) | [static] |
Part of PBX interface.
Definition at line 1083 of file chan_local.c.
References ao2_ref, ao2_unlink, ast_channel_cc_params_init(), ast_channel_get_cc_config_params(), ast_channel_release(), AST_STATE_DOWN, ast_channel::linkedid, local_alloc(), local_new(), and locals.
01084 { 01085 struct local_pvt *p = NULL; 01086 struct ast_channel *chan = NULL; 01087 01088 /* Allocate a new private structure and then Asterisk channel */ 01089 if ((p = local_alloc(data, format))) { 01090 if (!(chan = local_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL))) { 01091 ao2_unlink(locals, p); 01092 } 01093 if (chan && ast_channel_cc_params_init(chan, requestor ? ast_channel_get_cc_config_params((struct ast_channel *)requestor) : NULL)) { 01094 chan = ast_channel_release(chan); 01095 ao2_unlink(locals, p); 01096 } 01097 ao2_ref(p, -1); /* kill the ref from the alloc */ 01098 } 01099 01100 return chan; 01101 }
static int local_sendhtml | ( | struct ast_channel * | ast, | |
int | subclass, | |||
const char * | data, | |||
int | datalen | |||
) | [static] |
Definition at line 707 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.
00708 { 00709 struct local_pvt *p = ast->tech_pvt; 00710 int res = -1; 00711 struct ast_frame f = { AST_FRAME_HTML, }; 00712 int isoutbound; 00713 00714 if (!p) 00715 return -1; 00716 00717 ao2_lock(p); 00718 ao2_ref(p, 1); /* ref for local_queue_frame */ 00719 isoutbound = IS_OUTBOUND(ast, p); 00720 f.subclass.integer = subclass; 00721 f.data.ptr = (char *)data; 00722 f.datalen = datalen; 00723 res = local_queue_frame(p, isoutbound, &f, ast, 0); 00724 ao2_unlock(p); 00725 ao2_ref(p, -1); 00726 00727 return res; 00728 }
static int local_sendtext | ( | struct ast_channel * | ast, | |
const char * | text | |||
) | [static] |
Definition at line 686 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.
00687 { 00688 struct local_pvt *p = ast->tech_pvt; 00689 int res = -1; 00690 struct ast_frame f = { AST_FRAME_TEXT, }; 00691 int isoutbound; 00692 00693 if (!p) 00694 return -1; 00695 00696 ao2_lock(p); 00697 ao2_ref(p, 1); /* ref for local_queue_frame */ 00698 isoutbound = IS_OUTBOUND(ast, p); 00699 f.data.ptr = (char *) text; 00700 f.datalen = strlen(text) + 1; 00701 res = local_queue_frame(p, isoutbound, &f, ast, 0); 00702 ao2_unlock(p); 00703 ao2_ref(p, -1); 00704 return res; 00705 }
static int local_setoption | ( | struct ast_channel * | chan, | |
int | option, | |||
void * | data, | |||
int | datalen | |||
) | [static] |
Definition at line 158 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, local_pvt::chan, ast_chan_write_info_t::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.
00159 { 00160 int res; 00161 struct local_pvt *p; 00162 struct ast_channel *otherchan; 00163 ast_chan_write_info_t *write_info; 00164 00165 if (option != AST_OPTION_CHANNEL_WRITE) { 00166 return -1; 00167 } 00168 00169 write_info = data; 00170 00171 if (write_info->version != AST_CHAN_WRITE_INFO_T_VERSION) { 00172 ast_log(LOG_ERROR, "The chan_write_info_t type has changed, and this channel hasn't been updated!\n"); 00173 return -1; 00174 } 00175 00176 00177 startover: 00178 ast_channel_lock(chan); 00179 00180 p = chan->tech_pvt; 00181 if (!p) { 00182 ast_channel_unlock(chan); 00183 ast_log(LOG_WARNING, "Could not update other side of %s, local_pvt went away.\n", chan->name); 00184 return -1; 00185 } 00186 00187 while (ao2_trylock(p)) { 00188 ast_channel_unlock(chan); 00189 sched_yield(); 00190 ast_channel_lock(chan); 00191 p = chan->tech_pvt; 00192 if (!p) { 00193 ast_channel_unlock(chan); 00194 ast_log(LOG_WARNING, "Could not update other side of %s, local_pvt went away.\n", chan->name); 00195 return -1; 00196 } 00197 } 00198 00199 otherchan = (write_info->chan == p->owner) ? p->chan : p->owner; 00200 00201 if (!otherchan || otherchan == write_info->chan) { 00202 ao2_unlock(p); 00203 ast_channel_unlock(chan); 00204 ast_log(LOG_WARNING, "Could not update other side of %s, other side went away.\n", chan->name); 00205 return 0; 00206 } 00207 00208 if (ast_channel_trylock(otherchan)) { 00209 ao2_unlock(p); 00210 ast_channel_unlock(chan); 00211 goto startover; 00212 } 00213 00214 res = write_info->write_fn(otherchan, write_info->function, write_info->data, write_info->value); 00215 00216 ast_channel_unlock(otherchan); 00217 ao2_unlock(p); 00218 ast_channel_unlock(chan); 00219 00220 return res; 00221 }
static int local_write | ( | struct ast_channel * | ast, | |
struct ast_frame * | f | |||
) | [static] |
Definition at line 519 of file chan_local.c.
References ao2_lock, ao2_ref, ao2_unlock, ast_debug, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_test_flag, check_bridge(), f, IS_OUTBOUND, LOCAL_ALREADY_MASQED, local_queue_frame(), ast_channel::name, and ast_channel::tech_pvt.
00520 { 00521 struct local_pvt *p = ast->tech_pvt; 00522 int res = -1; 00523 int isoutbound; 00524 00525 if (!p) 00526 return -1; 00527 00528 /* Just queue for delivery to the other side */ 00529 ao2_lock(p); 00530 ao2_ref(p, 1); /* ref for local_queue_frame */ 00531 isoutbound = IS_OUTBOUND(ast, p); 00532 if (isoutbound && f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) 00533 check_bridge(p); 00534 if (!ast_test_flag(p, LOCAL_ALREADY_MASQED)) 00535 res = local_queue_frame(p, isoutbound, f, ast, 1); 00536 else { 00537 ast_debug(1, "Not posting to queue since already masked on '%s'\n", ast->name); 00538 res = 0; 00539 } 00540 ao2_unlock(p); 00541 ao2_ref(p, -1); 00542 00543 return res; 00544 }
static int locals_cmp_cb | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 1193 of file chan_local.c.
References CMP_MATCH.
Referenced by load_module().
01194 { 01195 return (obj == arg) ? CMP_MATCH : 0; 01196 }
static char* locals_show | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
CLI command "local show channels".
Definition at line 1104 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_args::argc, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, locals, RESULT_SUCCESS, and ast_cli_entry::usage.
01105 { 01106 struct local_pvt *p = NULL; 01107 struct ao2_iterator it; 01108 01109 switch (cmd) { 01110 case CLI_INIT: 01111 e->command = "local show channels"; 01112 e->usage = 01113 "Usage: local show channels\n" 01114 " Provides summary information on active local proxy channels.\n"; 01115 return NULL; 01116 case CLI_GENERATE: 01117 return NULL; 01118 } 01119 01120 if (a->argc != 3) 01121 return CLI_SHOWUSAGE; 01122 01123 if (ao2_container_count(locals) == 0) { 01124 ast_cli(a->fd, "No local channels in use\n"); 01125 return RESULT_SUCCESS; 01126 } 01127 01128 it = ao2_iterator_init(locals, 0); 01129 while ((p = ao2_iterator_next(&it))) { 01130 ao2_lock(p); 01131 ast_cli(a->fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context); 01132 ao2_unlock(p); 01133 ao2_ref(p, -1); 01134 } 01135 ao2_iterator_destroy(&it); 01136 01137 return CLI_SUCCESS; 01138 }
static int manager_optimize_away | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 1144 of file chan_local.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_channel_get_by_name(), ast_channel_unref, ast_clear_flag, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), ao2_iterator::c, LOCAL_NO_OPTIMIZATION, and locals.
Referenced by load_module().
01145 { 01146 const char *channel; 01147 struct local_pvt *p, *tmp = NULL; 01148 struct ast_channel *c; 01149 int found = 0; 01150 struct ao2_iterator it; 01151 01152 channel = astman_get_header(m, "Channel"); 01153 01154 if (ast_strlen_zero(channel)) { 01155 astman_send_error(s, m, "'Channel' not specified."); 01156 return 0; 01157 } 01158 01159 c = ast_channel_get_by_name(channel); 01160 if (!c) { 01161 astman_send_error(s, m, "Channel does not exist."); 01162 return 0; 01163 } 01164 01165 p = c->tech_pvt; 01166 ast_channel_unref(c); 01167 c = NULL; 01168 01169 it = ao2_iterator_init(locals, 0); 01170 while ((tmp = ao2_iterator_next(&it))) { 01171 if (tmp == p) { 01172 ao2_lock(tmp); 01173 found = 1; 01174 ast_clear_flag(tmp, LOCAL_NO_OPTIMIZATION); 01175 ao2_unlock(tmp); 01176 ao2_ref(tmp, -1); 01177 break; 01178 } 01179 ao2_ref(tmp, -1); 01180 } 01181 ao2_iterator_destroy(&it); 01182 01183 if (found) { 01184 astman_send_ack(s, m, "Queued channel to be optimized away"); 01185 } else { 01186 astman_send_error(s, m, "Unable to find channel"); 01187 } 01188 01189 return 0; 01190 }
static int unload_module | ( | void | ) | [static] |
Unload the local proxy channel from Asterisk.
Definition at line 1218 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_manager_unregister(), ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, cli_local, local_tech, locals, and local_pvt::owner.
01219 { 01220 struct local_pvt *p = NULL; 01221 struct ao2_iterator it; 01222 01223 /* First, take us out of the channel loop */ 01224 ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 01225 ast_manager_unregister("LocalOptimizeAway"); 01226 ast_channel_unregister(&local_tech); 01227 01228 it = ao2_iterator_init(locals, 0); 01229 while ((p = ao2_iterator_next(&it))) { 01230 if (p->owner) { 01231 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); 01232 } 01233 ao2_ref(p, -1); 01234 } 01235 ao2_iterator_destroy(&it); 01236 ao2_ref(locals, -1); 01237 01238 return 0; 01239 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DRIVER, } [static] |
Definition at line 1245 of file chan_local.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1245 of file chan_local.c.
const int BUCKET_SIZE = 1 [static] |
Definition at line 79 of file chan_local.c.
struct ast_cli_entry cli_local[] [static] |
Initial value:
{ { .handler = locals_show , .summary = "List status of local channels" ,__VA_ARGS__ }, }
Definition at line 1140 of file chan_local.c.
Referenced by load_module(), and unload_module().
struct ast_jb_conf g_jb_conf [static] |
struct ast_channel_tech local_tech [static] |
Definition at line 109 of file chan_local.c.
Referenced by load_module(), local_new(), and unload_module().
struct ao2_container* locals [static] |
Definition at line 81 of file chan_local.c.
Referenced by load_module(), local_alloc(), local_devicestate(), local_hangup(), local_request(), locals_show(), manager_optimize_away(), and unload_module().
const char tdesc[] = "Local Proxy Channel Driver" [static] |
Definition at line 72 of file chan_local.c.