#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 | awesome_locking (struct local_pvt *p, struct ast_channel **outchan, struct ast_channel **outowner) |
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 = "88eaa8f5c1bd988bedd71113385e0886" , .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 78 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 156 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 159 of file chan_local.c.
Referenced by local_alloc(), and local_bridgedchannel().
#define LOCAL_LAUNCHED_PBX (1 << 1) |
PBX was launched
Definition at line 157 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 160 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 158 of file chan_local.c.
Referenced by check_bridge(), local_alloc(), and manager_optimize_away().
static void __reg_module | ( | void | ) | [static] |
Definition at line 1322 of file chan_local.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 1322 of file chan_local.c.
static void awesome_locking | ( | struct local_pvt * | p, | |
struct ast_channel ** | outchan, | |||
struct ast_channel ** | outowner | |||
) | [static] |
Definition at line 171 of file chan_local.c.
References ao2_lock, ast_channel_ref, local_pvt::chan, and local_pvt::owner.
Referenced by local_call(), and local_hangup().
00172 { 00173 struct ast_channel *chan = NULL; 00174 struct ast_channel *owner = NULL; 00175 00176 for (;;) { 00177 ao2_lock(p); 00178 if (p->chan) { 00179 chan = p->chan; 00180 ast_channel_ref(chan); 00181 } 00182 if (p->owner) { 00183 owner = p->owner; 00184 ast_channel_ref(owner); 00185 } 00186 ao2_unlock(p); 00187 00188 /* if we don't have both channels, then this is very easy */ 00189 if (!owner || !chan) { 00190 if (owner) { 00191 ast_channel_lock(owner); 00192 } else if(chan) { 00193 ast_channel_lock(chan); 00194 } 00195 ao2_lock(p); 00196 } else { 00197 /* lock both channels first, then get the pvt lock */ 00198 ast_channel_lock(chan); 00199 while (ast_channel_trylock(owner)) { 00200 CHANNEL_DEADLOCK_AVOIDANCE(chan); 00201 } 00202 ao2_lock(p); 00203 } 00204 00205 /* Now that we have all the locks, validate that nothing changed */ 00206 if (p->owner != owner || p->chan != chan) { 00207 if (owner) { 00208 ast_channel_unlock(owner); 00209 owner = ast_channel_unref(owner); 00210 } 00211 if (chan) { 00212 ast_channel_unlock(chan); 00213 chan = ast_channel_unref(chan); 00214 } 00215 ao2_unlock(p); 00216 continue; 00217 } 00218 00219 break; 00220 } 00221 *outowner = p->owner; 00222 *outchan = p->chan; 00223 }
static void check_bridge | ( | struct local_pvt * | p | ) | [static] |
Definition at line 479 of file chan_local.c.
References ast_channel::_bridge, ast_party_caller::ani, ao2_lock, ao2_unlock, ast_app_group_update(), ast_bridged_channel(), ast_channel_masquerade(), ast_channel_ref, ast_channel_trylock, ast_channel_unlock, ast_channel_unref, 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().
00480 { 00481 struct ast_channel_monitor *tmp; 00482 struct ast_channel *chan = NULL; 00483 struct ast_channel *bridged_chan = NULL; 00484 00485 /* Do a few conditional checks early on just to see if this optimization is possible */ 00486 if (ast_test_flag(p, LOCAL_NO_OPTIMIZATION)) { 00487 return; 00488 } 00489 if (ast_test_flag(p, LOCAL_ALREADY_MASQED) || !p->chan || !p->owner) { 00490 return; 00491 } 00492 00493 /* Safely get the channel bridged to p->chan */ 00494 chan = ast_channel_ref(p->chan); 00495 00496 ao2_unlock(p); /* don't call bridged channel with the pvt locked */ 00497 bridged_chan = ast_bridged_channel(chan); 00498 ao2_lock(p); 00499 00500 chan = ast_channel_unref(chan); 00501 00502 /* since we had to unlock p to get the bridged chan, validate our 00503 * data once again and verify the bridged channel is what we expect 00504 * it to be in order to perform this optimization */ 00505 if (ast_test_flag(p, LOCAL_ALREADY_MASQED) || !p->owner || !p->chan || (p->chan->_bridge != bridged_chan)) { 00506 return; 00507 } 00508 00509 /* only do the masquerade if we are being called on the outbound channel, 00510 if it has been bridged to another channel and if there are no pending 00511 frames on the owner channel (because they would be transferred to the 00512 outbound channel during the masquerade) 00513 */ 00514 if (p->chan->_bridge /* Not ast_bridged_channel! Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) { 00515 /* Masquerade bridged channel into owner */ 00516 /* Lock everything we need, one by one, and give up if 00517 we can't get everything. Remember, we'll get another 00518 chance in just a little bit */ 00519 if (!ast_channel_trylock(p->chan->_bridge)) { 00520 if (!ast_check_hangup(p->chan->_bridge)) { 00521 if (!ast_channel_trylock(p->owner)) { 00522 if (!ast_check_hangup(p->owner)) { 00523 if (p->owner->monitor && !p->chan->_bridge->monitor) { 00524 /* If a local channel is being monitored, we don't want a masquerade 00525 * to cause the monitor to go away. Since the masquerade swaps the monitors, 00526 * pre-swapping the monitors before the masquerade will ensure that the monitor 00527 * ends up where it is expected. 00528 */ 00529 tmp = p->owner->monitor; 00530 p->owner->monitor = p->chan->_bridge->monitor; 00531 p->chan->_bridge->monitor = tmp; 00532 } 00533 if (p->chan->audiohooks) { 00534 struct ast_audiohook_list *audiohooks_swapper; 00535 audiohooks_swapper = p->chan->audiohooks; 00536 p->chan->audiohooks = p->owner->audiohooks; 00537 p->owner->audiohooks = audiohooks_swapper; 00538 } 00539 00540 /* If any Caller ID was set, preserve it after masquerade like above. We must check 00541 * to see if Caller ID was set because otherwise we'll mistakingly copy info not 00542 * set from the dialplan and will overwrite the real channel Caller ID. The reason 00543 * for this whole preswapping action is because the Caller ID is set on the channel 00544 * thread (which is the to be masqueraded away local channel) before both local 00545 * channels are optimized away. 00546 */ 00547 if (p->owner->caller.id.name.valid || p->owner->caller.id.number.valid 00548 || p->owner->caller.id.subaddress.valid || p->owner->caller.ani.name.valid 00549 || p->owner->caller.ani.number.valid || p->owner->caller.ani.subaddress.valid) { 00550 struct ast_party_caller tmp; 00551 tmp = p->owner->caller; 00552 p->owner->caller = p->chan->_bridge->caller; 00553 p->chan->_bridge->caller = tmp; 00554 } 00555 if (p->owner->redirecting.from.name.valid || p->owner->redirecting.from.number.valid 00556 || p->owner->redirecting.from.subaddress.valid || p->owner->redirecting.to.name.valid 00557 || p->owner->redirecting.to.number.valid || p->owner->redirecting.to.subaddress.valid) { 00558 struct ast_party_redirecting tmp; 00559 tmp = p->owner->redirecting; 00560 p->owner->redirecting = p->chan->_bridge->redirecting; 00561 p->chan->_bridge->redirecting = tmp; 00562 } 00563 if (p->owner->dialed.number.str || p->owner->dialed.subaddress.valid) { 00564 struct ast_party_dialed tmp; 00565 tmp = p->owner->dialed; 00566 p->owner->dialed = p->chan->_bridge->dialed; 00567 p->chan->_bridge->dialed = tmp; 00568 } 00569 00570 00571 ast_app_group_update(p->chan, p->owner); 00572 ast_channel_masquerade(p->owner, p->chan->_bridge); 00573 ast_set_flag(p, LOCAL_ALREADY_MASQED); 00574 } 00575 ast_channel_unlock(p->owner); 00576 } 00577 } 00578 ast_channel_unlock(p->chan->_bridge); 00579 } 00580 } 00581 }
static int load_module | ( | void | ) | [static] |
Load module into PBX, register channel.
Definition at line 1276 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().
01277 { 01278 if (!(locals = ao2_container_alloc(BUCKET_SIZE, NULL, locals_cmp_cb))) { 01279 return AST_MODULE_LOAD_FAILURE; 01280 } 01281 01282 /* Make sure we can register our channel type */ 01283 if (ast_channel_register(&local_tech)) { 01284 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n"); 01285 ao2_ref(locals, -1); 01286 return AST_MODULE_LOAD_FAILURE; 01287 } 01288 ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 01289 ast_manager_register_xml("LocalOptimizeAway", EVENT_FLAG_SYSTEM|EVENT_FLAG_CALL, manager_optimize_away); 01290 01291 return AST_MODULE_LOAD_SUCCESS; 01292 }
Create a call structure.
Definition at line 1036 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().
01037 { 01038 struct local_pvt *tmp = NULL; 01039 char *c = NULL, *opts = NULL; 01040 01041 if (!(tmp = ao2_alloc(sizeof(*tmp), NULL))) { 01042 return NULL; 01043 } 01044 01045 /* Initialize private structure information */ 01046 ast_copy_string(tmp->exten, data, sizeof(tmp->exten)); 01047 01048 memcpy(&tmp->jb_conf, &g_jb_conf, sizeof(tmp->jb_conf)); 01049 01050 /* Look for options */ 01051 if ((opts = strchr(tmp->exten, '/'))) { 01052 *opts++ = '\0'; 01053 if (strchr(opts, 'n')) 01054 ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION); 01055 if (strchr(opts, 'j')) { 01056 if (ast_test_flag(tmp, LOCAL_NO_OPTIMIZATION)) 01057 ast_set_flag(&tmp->jb_conf, AST_JB_ENABLED); 01058 else { 01059 ast_log(LOG_ERROR, "You must use the 'n' option for chan_local " 01060 "to use the 'j' option to enable the jitterbuffer\n"); 01061 } 01062 } 01063 if (strchr(opts, 'b')) { 01064 ast_set_flag(tmp, LOCAL_BRIDGE); 01065 } 01066 if (strchr(opts, 'm')) { 01067 ast_set_flag(tmp, LOCAL_MOH_PASSTHRU); 01068 } 01069 } 01070 01071 /* Look for a context */ 01072 if ((c = strchr(tmp->exten, '@'))) 01073 *c++ = '\0'; 01074 01075 ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context)); 01076 01077 tmp->reqformat = format; 01078 01079 #if 0 01080 /* We can't do this check here, because we don't know the CallerID yet, and 01081 * the CallerID could potentially affect what step is actually taken (or 01082 * even if that step exists). */ 01083 if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) { 01084 ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context); 01085 tmp = local_pvt_destroy(tmp); 01086 } else { 01087 #endif 01088 /* Add to list */ 01089 ao2_link(locals, tmp); 01090 #if 0 01091 } 01092 #endif 01093 return tmp; /* this is returned with a ref */ 01094 }
static int local_answer | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 449 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.
00450 { 00451 struct local_pvt *p = ast->tech_pvt; 00452 int isoutbound; 00453 int res = -1; 00454 00455 if (!p) 00456 return -1; 00457 00458 ao2_lock(p); 00459 ao2_ref(p, 1); 00460 isoutbound = IS_OUTBOUND(ast, p); 00461 if (isoutbound) { 00462 /* Pass along answer since somebody answered us */ 00463 struct ast_frame answer = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } }; 00464 res = local_queue_frame(p, isoutbound, &answer, ast, 1); 00465 } else { 00466 ast_log(LOG_WARNING, "Huh? Local is being asked to answer?\n"); 00467 } 00468 ao2_unlock(p); 00469 ao2_ref(p, -1); 00470 return res; 00471 }
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 323 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.
00324 { 00325 struct local_pvt *p = bridge->tech_pvt; 00326 struct ast_channel *bridged = bridge; 00327 00328 if (!p) { 00329 ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning <none>\n", 00330 chan->name, bridge->name); 00331 return NULL; 00332 } 00333 00334 ao2_lock(p); 00335 00336 if (ast_test_flag(p, LOCAL_BRIDGE)) { 00337 /* Find the opposite channel */ 00338 bridged = (bridge == p->owner ? p->chan : p->owner); 00339 00340 /* Now see if the opposite channel is bridged to anything */ 00341 if (!bridged) { 00342 bridged = bridge; 00343 } else if (bridged->_bridge) { 00344 bridged = bridged->_bridge; 00345 } 00346 } 00347 00348 ao2_unlock(p); 00349 00350 return bridged; 00351 }
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 805 of file chan_local.c.
References ast_channel::accountcode, accountcode, ao2_lock, ao2_ref, 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_unlock, ast_channel_unref, 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, awesome_locking(), ast_channel::caller, ast_channel::connected, ast_channel::context, context, ast_channel::dialed, ast_var_t::entries, ast_channel::exten, 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, ast_channel::redirecting, S_COR, ast_party_number::str, ast_channel::tech_pvt, ast_party_number::valid, value, and ast_channel::varshead.
00806 { 00807 struct local_pvt *p = ast->tech_pvt; 00808 int pvt_locked = 0; 00809 00810 struct ast_channel *owner = NULL; 00811 struct ast_channel *chan = NULL; 00812 int res; 00813 struct ast_var_t *varptr = NULL, *new; 00814 size_t len, namelen; 00815 char *reduced_dest = ast_strdupa(dest); 00816 char *slash; 00817 const char *exten; 00818 const char *context; 00819 00820 if (!p) { 00821 return -1; 00822 } 00823 00824 /* since we are letting go of channel locks that were locked coming into 00825 * this function, then we need to give the tech pvt a ref */ 00826 ao2_ref(p, 1); 00827 ast_channel_unlock(ast); 00828 00829 awesome_locking(p, &chan, &owner); 00830 pvt_locked = 1; 00831 00832 if (owner != ast) { 00833 res = -1; 00834 goto return_cleanup; 00835 } 00836 00837 if (!owner || !chan) { 00838 res = -1; 00839 goto return_cleanup; 00840 } 00841 00842 /* 00843 * Note that cid_num and cid_name aren't passed in the ast_channel_alloc 00844 * call, so it's done here instead. 00845 * 00846 * All these failure points just return -1. The individual strings will 00847 * be cleared when we destroy the channel. 00848 */ 00849 ast_party_redirecting_copy(&chan->redirecting, &owner->redirecting); 00850 00851 ast_party_dialed_copy(&chan->dialed, &owner->dialed); 00852 00853 ast_connected_line_copy_to_caller(&chan->caller, &owner->connected); 00854 ast_connected_line_copy_from_caller(&chan->connected, &owner->caller); 00855 00856 ast_string_field_set(chan, language, owner->language); 00857 ast_string_field_set(chan, accountcode, owner->accountcode); 00858 ast_string_field_set(chan, musicclass, owner->musicclass); 00859 ast_cdr_update(chan); 00860 00861 ast_channel_cc_params_init(chan, ast_channel_get_cc_config_params(owner)); 00862 00863 /* Make sure we inherit the ANSWERED_ELSEWHERE flag if it's set on the queue/dial call request in the dialplan */ 00864 if (ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) { 00865 ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE); 00866 } 00867 00868 /* copy the channel variables from the incoming channel to the outgoing channel */ 00869 /* Note that due to certain assumptions, they MUST be in the same order */ 00870 AST_LIST_TRAVERSE(&owner->varshead, varptr, entries) { 00871 namelen = strlen(varptr->name); 00872 len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2; 00873 if ((new = ast_calloc(1, len))) { 00874 memcpy(new, varptr, len); 00875 new->value = &(new->name[0]) + namelen + 1; 00876 AST_LIST_INSERT_TAIL(&chan->varshead, new, entries); 00877 } 00878 } 00879 ast_channel_datastore_inherit(owner, chan); 00880 /* If the local channel has /n or /b on the end of it, 00881 * we need to lop that off for our argument to setting 00882 * up the CC_INTERFACES variable 00883 */ 00884 if ((slash = strrchr(reduced_dest, '/'))) { 00885 *slash = '\0'; 00886 } 00887 ast_set_cc_interfaces_chanvar(chan, reduced_dest); 00888 00889 exten = ast_strdupa(chan->exten); 00890 context = ast_strdupa(chan->context); 00891 00892 ao2_unlock(p); 00893 pvt_locked = 0; 00894 00895 ast_channel_unlock(chan); 00896 00897 if (!ast_exists_extension(chan, context, exten, 1, 00898 S_COR(owner->caller.id.number.valid, owner->caller.id.number.str, NULL))) { 00899 ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", exten, context); 00900 res = -1; 00901 chan = ast_channel_unref(chan); /* we already unlocked it, so clear it hear so the cleanup label won't touch it. */ 00902 goto return_cleanup; 00903 } 00904 00905 /* Start switch on sub channel */ 00906 if (!(res = ast_pbx_start(chan))) { 00907 ao2_lock(p); 00908 ast_set_flag(p, LOCAL_LAUNCHED_PBX); 00909 ao2_unlock(p); 00910 } 00911 chan = ast_channel_unref(chan); /* chan is already unlocked, clear it here so the cleanup lable won't touch it. */ 00912 00913 return_cleanup: 00914 if (p) { 00915 if (pvt_locked) { 00916 ao2_unlock(p); 00917 } 00918 ao2_ref(p, -1); 00919 } 00920 if (chan) { 00921 ast_channel_unlock(chan); 00922 chan = ast_channel_unref(chan); 00923 } 00924 00925 /* owner is supposed to be == to ast, if it 00926 * is, don't unlock it because ast must exit locked */ 00927 if (owner) { 00928 if (owner != ast) { 00929 ast_channel_unlock(owner); 00930 ast_channel_lock(ast); 00931 } 00932 owner = ast_channel_unref(owner); 00933 } else { 00934 /* we have to exit with ast locked */ 00935 ast_channel_lock(ast); 00936 } 00937 00938 return res; 00939 }
static int local_devicestate | ( | void * | data | ) | [static] |
Adds devicestate to local channels.
Definition at line 281 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.
00282 { 00283 char *exten = ast_strdupa(data); 00284 char *context = NULL, *opts = NULL; 00285 int res; 00286 struct local_pvt *lp; 00287 struct ao2_iterator it; 00288 00289 if (!(context = strchr(exten, '@'))) { 00290 ast_log(LOG_WARNING, "Someone used Local/%s somewhere without a @context. This is bad.\n", exten); 00291 return AST_DEVICE_INVALID; 00292 } 00293 00294 *context++ = '\0'; 00295 00296 /* Strip options if they exist */ 00297 if ((opts = strchr(context, '/'))) 00298 *opts = '\0'; 00299 00300 ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context); 00301 00302 res = ast_exists_extension(NULL, context, exten, 1, NULL); 00303 if (!res) 00304 return AST_DEVICE_INVALID; 00305 00306 res = AST_DEVICE_NOT_INUSE; 00307 00308 it = ao2_iterator_init(locals, 0); 00309 while ((lp = ao2_iterator_next(&it))) { 00310 if (!strcmp(exten, lp->exten) && !strcmp(context, lp->context) && lp->owner) { 00311 res = AST_DEVICE_INUSE; 00312 ao2_ref(lp, -1); 00313 break; 00314 } 00315 ao2_ref(lp, -1); 00316 } 00317 ao2_iterator_destroy(&it); 00318 00319 return res; 00320 }
static int local_digit_begin | ( | struct ast_channel * | ast, | |
char | digit | |||
) | [static] |
Definition at line 716 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.
00717 { 00718 struct local_pvt *p = ast->tech_pvt; 00719 int res = -1; 00720 struct ast_frame f = { AST_FRAME_DTMF_BEGIN, }; 00721 int isoutbound; 00722 00723 if (!p) 00724 return -1; 00725 00726 ao2_ref(p, 1); /* ref for local_queue_frame */ 00727 ao2_lock(p); 00728 isoutbound = IS_OUTBOUND(ast, p); 00729 f.subclass.integer = digit; 00730 res = local_queue_frame(p, isoutbound, &f, ast, 0); 00731 ao2_unlock(p); 00732 ao2_ref(p, -1); 00733 00734 return res; 00735 }
static int local_digit_end | ( | struct ast_channel * | ast, | |
char | digit, | |||
unsigned int | duration | |||
) | [static] |
Definition at line 737 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.
00738 { 00739 struct local_pvt *p = ast->tech_pvt; 00740 int res = -1; 00741 struct ast_frame f = { AST_FRAME_DTMF_END, }; 00742 int isoutbound; 00743 00744 if (!p) 00745 return -1; 00746 00747 ao2_ref(p, 1); /* ref for local_queue_frame */ 00748 ao2_lock(p); 00749 isoutbound = IS_OUTBOUND(ast, p); 00750 f.subclass.integer = digit; 00751 f.len = duration; 00752 res = local_queue_frame(p, isoutbound, &f, ast, 0); 00753 ao2_unlock(p); 00754 ao2_ref(p, -1); 00755 00756 return res; 00757 }
static int local_fixup | ( | struct ast_channel * | oldchan, | |
struct ast_channel * | newchan | |||
) | [static] |
Definition at line 619 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.
00620 { 00621 struct local_pvt *p = newchan->tech_pvt; 00622 00623 if (!p) 00624 return -1; 00625 00626 ao2_lock(p); 00627 00628 if ((p->owner != oldchan) && (p->chan != oldchan)) { 00629 ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan); 00630 ao2_unlock(p); 00631 return -1; 00632 } 00633 if (p->owner == oldchan) 00634 p->owner = newchan; 00635 else 00636 p->chan = newchan; 00637 00638 /* Do not let a masquerade cause a Local channel to be bridged to itself! */ 00639 if (!ast_check_hangup(newchan) && ((p->owner && p->owner->_bridge == p->chan) || (p->chan && p->chan->_bridge == p->owner))) { 00640 ast_log(LOG_WARNING, "You can not bridge a Local channel to itself!\n"); 00641 ao2_unlock(p); 00642 ast_queue_hangup(newchan); 00643 return -1; 00644 } 00645 00646 ao2_unlock(p); 00647 return 0; 00648 }
static int local_hangup | ( | struct ast_channel * | ast | ) | [static] |
Hangup a call through the local proxy channel.
Definition at line 942 of file chan_local.c.
References ao2_ref, ao2_unlink, ao2_unlock, ast_channel_lock, ast_channel_unlock, ast_channel_unref, 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, awesome_locking(), local_pvt::chan, f, hangup_chan(), 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.
00943 { 00944 struct local_pvt *p = ast->tech_pvt; 00945 int isoutbound; 00946 int hangup_chan = 0; 00947 int res = 0; 00948 struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_HANGUP }, .data.uint32 = ast->hangupcause }; 00949 struct ast_channel *owner = NULL; 00950 struct ast_channel *chan = NULL; 00951 00952 if (!p) { 00953 return -1; 00954 } 00955 00956 /* give the pvt a ref since we are unlocking the channel. */ 00957 ao2_ref(p, 1); 00958 00959 /* the pvt isn't going anywhere, we gave it a ref */ 00960 ast_channel_unlock(ast); 00961 00962 /* lock everything */ 00963 awesome_locking(p, &chan, &owner); 00964 00965 if (ast != chan && ast != owner) { 00966 res = -1; 00967 goto local_hangup_cleanup; 00968 } 00969 00970 isoutbound = IS_OUTBOUND(ast, p); /* just comparing pointer of ast */ 00971 00972 if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) { 00973 ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE); 00974 ast_debug(2, "This local call has the ANSWERED_ELSEWHERE flag set.\n"); 00975 } 00976 00977 if (isoutbound) { 00978 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS"); 00979 if ((status) && (p->owner)) { 00980 p->owner->hangupcause = p->chan->hangupcause; 00981 pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status); 00982 } 00983 00984 ast_clear_flag(p, LOCAL_LAUNCHED_PBX); 00985 ast_module_user_remove(p->u_chan); 00986 p->chan = NULL; 00987 } else { 00988 ast_module_user_remove(p->u_owner); 00989 if (p->chan) { 00990 ast_queue_hangup(p->chan); 00991 } 00992 p->owner = NULL; 00993 } 00994 00995 ast->tech_pvt = NULL; /* this is one of our locked channels, doesn't matter which */ 00996 00997 if (!p->owner && !p->chan) { 00998 ao2_unlock(p); 00999 /* Remove from list */ 01000 ao2_unlink(locals, p); 01001 ao2_ref(p, -1); 01002 p = NULL; 01003 res = 0; 01004 goto local_hangup_cleanup; 01005 } 01006 if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) { 01007 /* Need to actually hangup since there is no PBX */ 01008 hangup_chan = 1; 01009 } else { 01010 local_queue_frame(p, isoutbound, &f, NULL, 0); 01011 } 01012 01013 local_hangup_cleanup: 01014 if (p) { 01015 ao2_unlock(p); 01016 ao2_ref(p, -1); 01017 } 01018 if (chan) { 01019 ast_channel_unlock(chan); 01020 if (hangup_chan) { 01021 ast_hangup(chan); 01022 } 01023 chan = ast_channel_unref(chan); 01024 } 01025 if (owner) { 01026 ast_channel_unlock(owner); 01027 owner = ast_channel_unref(owner); 01028 } 01029 01030 /* leave with the same stupid channel locked that came in */ 01031 ast_channel_lock(ast); 01032 return res; 01033 }
static int local_indicate | ( | struct ast_channel * | ast, | |
int | condition, | |||
const void * | data, | |||
size_t | datalen | |||
) | [static] |
Definition at line 650 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.
00651 { 00652 struct local_pvt *p = ast->tech_pvt; 00653 int res = 0; 00654 struct ast_frame f = { AST_FRAME_CONTROL, }; 00655 int isoutbound; 00656 00657 if (!p) 00658 return -1; 00659 00660 ao2_ref(p, 1); /* ref for local_queue_frame */ 00661 00662 /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */ 00663 if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) { 00664 ast_moh_start(ast, data, NULL); 00665 } else if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_UNHOLD) { 00666 ast_moh_stop(ast); 00667 } else if (condition == AST_CONTROL_CONNECTED_LINE || condition == AST_CONTROL_REDIRECTING) { 00668 struct ast_channel *this_channel; 00669 struct ast_channel *the_other_channel; 00670 /* A connected line update frame may only contain a partial amount of data, such 00671 * as just a source, or just a ton, and not the full amount of information. However, 00672 * the collected information is all stored in the outgoing channel's connectedline 00673 * structure, so when receiving a connected line update on an outgoing local channel, 00674 * we need to transmit the collected connected line information instead of whatever 00675 * happens to be in this control frame. The same applies for redirecting information, which 00676 * is why it is handled here as well.*/ 00677 ao2_lock(p); 00678 isoutbound = IS_OUTBOUND(ast, p); 00679 if (isoutbound) { 00680 this_channel = p->chan; 00681 the_other_channel = p->owner; 00682 } else { 00683 this_channel = p->owner; 00684 the_other_channel = p->chan; 00685 } 00686 if (the_other_channel) { 00687 unsigned char frame_data[1024]; 00688 if (condition == AST_CONTROL_CONNECTED_LINE) { 00689 if (isoutbound) { 00690 ast_connected_line_copy_to_caller(&the_other_channel->caller, &this_channel->connected); 00691 } 00692 f.datalen = ast_connected_line_build_data(frame_data, sizeof(frame_data), &this_channel->connected, NULL); 00693 } else { 00694 f.datalen = ast_redirecting_build_data(frame_data, sizeof(frame_data), &this_channel->redirecting, NULL); 00695 } 00696 f.subclass.integer = condition; 00697 f.data.ptr = frame_data; 00698 res = local_queue_frame(p, isoutbound, &f, ast, 1); 00699 } 00700 ao2_unlock(p); 00701 } else { 00702 /* Queue up a frame representing the indication as a control frame */ 00703 ao2_lock(p); 00704 isoutbound = IS_OUTBOUND(ast, p); 00705 f.subclass.integer = condition; 00706 f.data.ptr = (void*)data; 00707 f.datalen = datalen; 00708 res = local_queue_frame(p, isoutbound, &f, ast, 1); 00709 ao2_unlock(p); 00710 } 00711 00712 ao2_ref(p, -1); 00713 return res; 00714 }
static struct ast_channel* local_new | ( | struct local_pvt * | p, | |
int | state, | |||
const char * | linkedid | |||
) | [static] |
Start new local channel.
Definition at line 1097 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().
01098 { 01099 struct ast_channel *tmp = NULL, *tmp2 = NULL; 01100 int randnum = ast_random() & 0xffff, fmt = 0; 01101 const char *t; 01102 int ama; 01103 01104 /* Allocate two new Asterisk channels */ 01105 /* safe accountcode */ 01106 if (p->owner && p->owner->accountcode) 01107 t = p->owner->accountcode; 01108 else 01109 t = ""; 01110 01111 if (p->owner) 01112 ama = p->owner->amaflags; 01113 else 01114 ama = 0; 01115 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)) 01116 || !(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))) { 01117 if (tmp) { 01118 tmp = ast_channel_release(tmp); 01119 } 01120 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n"); 01121 return NULL; 01122 } 01123 01124 tmp2->tech = tmp->tech = &local_tech; 01125 01126 tmp->nativeformats = p->reqformat; 01127 tmp2->nativeformats = p->reqformat; 01128 01129 /* Determine our read/write format and set it on each channel */ 01130 fmt = ast_best_codec(p->reqformat); 01131 tmp->writeformat = fmt; 01132 tmp2->writeformat = fmt; 01133 tmp->rawwriteformat = fmt; 01134 tmp2->rawwriteformat = fmt; 01135 tmp->readformat = fmt; 01136 tmp2->readformat = fmt; 01137 tmp->rawreadformat = fmt; 01138 tmp2->rawreadformat = fmt; 01139 01140 tmp->tech_pvt = p; 01141 tmp2->tech_pvt = p; 01142 01143 p->owner = tmp; 01144 p->chan = tmp2; 01145 p->u_owner = ast_module_user_add(p->owner); 01146 p->u_chan = ast_module_user_add(p->chan); 01147 01148 ast_copy_string(tmp->context, p->context, sizeof(tmp->context)); 01149 ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context)); 01150 ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten)); 01151 tmp->priority = 1; 01152 tmp2->priority = 1; 01153 01154 ast_jb_configure(tmp, &p->jb_conf); 01155 01156 return tmp; 01157 }
static int local_queryoption | ( | struct ast_channel * | ast, | |
int | option, | |||
void * | data, | |||
int * | datalen | |||
) | [static] |
Definition at line 354 of file chan_local.c.
References ao2_lock, ao2_unlock, ast_bridged_channel(), ast_channel_lock, ast_channel_queryoption(), ast_channel_ref, ast_channel_unlock, ast_channel_unref, AST_OPTION_T38_STATE, local_pvt::chan, IS_OUTBOUND, local_pvt::owner, and ast_channel::tech_pvt.
00355 { 00356 struct local_pvt *p; 00357 struct ast_channel *bridged = NULL; 00358 struct ast_channel *tmp = NULL; 00359 int res = 0; 00360 00361 if (option != AST_OPTION_T38_STATE) { 00362 /* AST_OPTION_T38_STATE is the only supported option at this time */ 00363 return -1; 00364 } 00365 00366 /* for some reason the channel is not locked in channel.c when this function is called */ 00367 if (!(p = ast->tech_pvt)) { 00368 return -1; 00369 } 00370 00371 ao2_lock(p); 00372 if (!(tmp = IS_OUTBOUND(ast, p) ? p->owner : p->chan)) { 00373 ao2_unlock(p); 00374 return -1; 00375 } 00376 ast_channel_ref(tmp); 00377 ao2_unlock(p); 00378 ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */ 00379 00380 ast_channel_lock(tmp); 00381 if (!(bridged = ast_bridged_channel(tmp))) { 00382 res = -1; 00383 ast_channel_unlock(tmp); 00384 goto query_cleanup; 00385 } 00386 ast_channel_ref(bridged); 00387 ast_channel_unlock(tmp); 00388 00389 query_cleanup: 00390 if (bridged) { 00391 res = ast_channel_queryoption(bridged, option, data, datalen, 0); 00392 bridged = ast_channel_unref(bridged); 00393 } 00394 if (tmp) { 00395 tmp = ast_channel_unref(tmp); 00396 } 00397 ast_channel_lock(ast); /* Lock back before we leave */ 00398 00399 return res; 00400 }
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 410 of file chan_local.c.
References ao2_lock, ao2_unlock, ast_channel_lock, ast_channel_ref, ast_channel_unlock, ast_channel_unref, AST_CONTROL_RINGING, AST_FRAME_CONTROL, ast_queue_frame(), ast_setstate(), AST_STATE_RINGING, local_pvt::chan, f, ast_channel::generator, 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().
00412 { 00413 struct ast_channel *other = NULL; 00414 00415 /* Recalculate outbound channel */ 00416 other = isoutbound ? p->owner : p->chan; 00417 00418 if (!other) { 00419 return 0; 00420 } 00421 00422 /* do not queue frame if generator is on both local channels */ 00423 if (us && us->generator && other->generator) { 00424 return 0; 00425 } 00426 00427 /* grab a ref on the channel before unlocking the pvt, 00428 * other can not go away from us now regardless of locking */ 00429 ast_channel_ref(other); 00430 if (us && us_locked) { 00431 ast_channel_unlock(us); 00432 } 00433 ao2_unlock(p); 00434 00435 if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_RINGING) { 00436 ast_setstate(other, AST_STATE_RINGING); 00437 } 00438 ast_queue_frame(other, f); 00439 00440 other = ast_channel_unref(other); 00441 if (us && us_locked) { 00442 ast_channel_lock(us); 00443 } 00444 ao2_lock(p); 00445 00446 return 0; 00447 }
static struct ast_frame * local_read | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 583 of file chan_local.c.
References ast_null_frame.
00584 { 00585 return &ast_null_frame; 00586 }
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 1160 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.
01161 { 01162 struct local_pvt *p = NULL; 01163 struct ast_channel *chan = NULL; 01164 01165 /* Allocate a new private structure and then Asterisk channel */ 01166 if ((p = local_alloc(data, format))) { 01167 if (!(chan = local_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL))) { 01168 ao2_unlink(locals, p); 01169 } 01170 if (chan && ast_channel_cc_params_init(chan, requestor ? ast_channel_get_cc_config_params((struct ast_channel *)requestor) : NULL)) { 01171 chan = ast_channel_release(chan); 01172 ao2_unlink(locals, p); 01173 } 01174 ao2_ref(p, -1); /* kill the ref from the alloc */ 01175 } 01176 01177 return chan; 01178 }
static int local_sendhtml | ( | struct ast_channel * | ast, | |
int | subclass, | |||
const char * | data, | |||
int | datalen | |||
) | [static] |
Definition at line 780 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.
00781 { 00782 struct local_pvt *p = ast->tech_pvt; 00783 int res = -1; 00784 struct ast_frame f = { AST_FRAME_HTML, }; 00785 int isoutbound; 00786 00787 if (!p) 00788 return -1; 00789 00790 ao2_lock(p); 00791 ao2_ref(p, 1); /* ref for local_queue_frame */ 00792 isoutbound = IS_OUTBOUND(ast, p); 00793 f.subclass.integer = subclass; 00794 f.data.ptr = (char *)data; 00795 f.datalen = datalen; 00796 res = local_queue_frame(p, isoutbound, &f, ast, 0); 00797 ao2_unlock(p); 00798 ao2_ref(p, -1); 00799 00800 return res; 00801 }
static int local_sendtext | ( | struct ast_channel * | ast, | |
const char * | text | |||
) | [static] |
Definition at line 759 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.
00760 { 00761 struct local_pvt *p = ast->tech_pvt; 00762 int res = -1; 00763 struct ast_frame f = { AST_FRAME_TEXT, }; 00764 int isoutbound; 00765 00766 if (!p) 00767 return -1; 00768 00769 ao2_lock(p); 00770 ao2_ref(p, 1); /* ref for local_queue_frame */ 00771 isoutbound = IS_OUTBOUND(ast, p); 00772 f.data.ptr = (char *) text; 00773 f.datalen = strlen(text) + 1; 00774 res = local_queue_frame(p, isoutbound, &f, ast, 0); 00775 ao2_unlock(p); 00776 ao2_ref(p, -1); 00777 return res; 00778 }
static int local_setoption | ( | struct ast_channel * | chan, | |
int | option, | |||
void * | data, | |||
int | datalen | |||
) | [static] |
Definition at line 226 of file chan_local.c.
References ao2_lock, ao2_ref, ao2_unlock, AST_CHAN_WRITE_INFO_T_VERSION, ast_channel_lock, ast_channel_ref, ast_channel_unlock, ast_channel_unref, 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, 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.
00227 { 00228 int res = 0; 00229 struct local_pvt *p = NULL; 00230 struct ast_channel *otherchan = NULL; 00231 ast_chan_write_info_t *write_info; 00232 00233 if (option != AST_OPTION_CHANNEL_WRITE) { 00234 return -1; 00235 } 00236 00237 write_info = data; 00238 00239 if (write_info->version != AST_CHAN_WRITE_INFO_T_VERSION) { 00240 ast_log(LOG_ERROR, "The chan_write_info_t type has changed, and this channel hasn't been updated!\n"); 00241 return -1; 00242 } 00243 00244 /* get the tech pvt */ 00245 if (!(p = ast->tech_pvt)) { 00246 return -1; 00247 } 00248 ao2_ref(p, 1); 00249 ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */ 00250 00251 /* get the channel we are supposed to write to */ 00252 ao2_lock(p); 00253 otherchan = (write_info->chan == p->owner) ? p->chan : p->owner; 00254 if (!otherchan || otherchan == write_info->chan) { 00255 res = -1; 00256 otherchan = NULL; 00257 ao2_unlock(p); 00258 goto setoption_cleanup; 00259 } 00260 ast_channel_ref(otherchan); 00261 00262 /* clear the pvt lock before grabbing the channel */ 00263 ao2_unlock(p); 00264 00265 ast_channel_lock(otherchan); 00266 res = write_info->write_fn(otherchan, write_info->function, write_info->data, write_info->value); 00267 ast_channel_unlock(otherchan); 00268 00269 setoption_cleanup: 00270 if (p) { 00271 ao2_ref(p, -1); 00272 } 00273 if (otherchan) { 00274 ast_channel_unref(otherchan); 00275 } 00276 ast_channel_lock(ast); /* Lock back before we leave */ 00277 return res; 00278 }
static int local_write | ( | struct ast_channel * | ast, | |
struct ast_frame * | f | |||
) | [static] |
Definition at line 588 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.
00589 { 00590 struct local_pvt *p = ast->tech_pvt; 00591 int res = -1; 00592 int isoutbound; 00593 00594 if (!p) { 00595 return -1; 00596 } 00597 00598 /* Just queue for delivery to the other side */ 00599 ao2_ref(p, 1); /* ref for local_queue_frame */ 00600 ao2_lock(p); 00601 isoutbound = IS_OUTBOUND(ast, p); 00602 00603 if (isoutbound && f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) { 00604 check_bridge(p); 00605 } 00606 00607 if (!ast_test_flag(p, LOCAL_ALREADY_MASQED)) { 00608 res = local_queue_frame(p, isoutbound, f, ast, 1); 00609 } else { 00610 ast_debug(1, "Not posting to queue since already masked on '%s'\n", ast->name); 00611 res = 0; 00612 } 00613 ao2_unlock(p); 00614 ao2_ref(p, -1); 00615 00616 return res; 00617 }
static int locals_cmp_cb | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 1270 of file chan_local.c.
References CMP_MATCH.
Referenced by load_module().
01271 { 01272 return (obj == arg) ? CMP_MATCH : 0; 01273 }
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 1181 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.
01182 { 01183 struct local_pvt *p = NULL; 01184 struct ao2_iterator it; 01185 01186 switch (cmd) { 01187 case CLI_INIT: 01188 e->command = "local show channels"; 01189 e->usage = 01190 "Usage: local show channels\n" 01191 " Provides summary information on active local proxy channels.\n"; 01192 return NULL; 01193 case CLI_GENERATE: 01194 return NULL; 01195 } 01196 01197 if (a->argc != 3) 01198 return CLI_SHOWUSAGE; 01199 01200 if (ao2_container_count(locals) == 0) { 01201 ast_cli(a->fd, "No local channels in use\n"); 01202 return RESULT_SUCCESS; 01203 } 01204 01205 it = ao2_iterator_init(locals, 0); 01206 while ((p = ao2_iterator_next(&it))) { 01207 ao2_lock(p); 01208 ast_cli(a->fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context); 01209 ao2_unlock(p); 01210 ao2_ref(p, -1); 01211 } 01212 ao2_iterator_destroy(&it); 01213 01214 return CLI_SUCCESS; 01215 }
static int manager_optimize_away | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 1221 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().
01222 { 01223 const char *channel; 01224 struct local_pvt *p, *tmp = NULL; 01225 struct ast_channel *c; 01226 int found = 0; 01227 struct ao2_iterator it; 01228 01229 channel = astman_get_header(m, "Channel"); 01230 01231 if (ast_strlen_zero(channel)) { 01232 astman_send_error(s, m, "'Channel' not specified."); 01233 return 0; 01234 } 01235 01236 c = ast_channel_get_by_name(channel); 01237 if (!c) { 01238 astman_send_error(s, m, "Channel does not exist."); 01239 return 0; 01240 } 01241 01242 p = c->tech_pvt; 01243 ast_channel_unref(c); 01244 c = NULL; 01245 01246 it = ao2_iterator_init(locals, 0); 01247 while ((tmp = ao2_iterator_next(&it))) { 01248 if (tmp == p) { 01249 ao2_lock(tmp); 01250 found = 1; 01251 ast_clear_flag(tmp, LOCAL_NO_OPTIMIZATION); 01252 ao2_unlock(tmp); 01253 ao2_ref(tmp, -1); 01254 break; 01255 } 01256 ao2_ref(tmp, -1); 01257 } 01258 ao2_iterator_destroy(&it); 01259 01260 if (found) { 01261 astman_send_ack(s, m, "Queued channel to be optimized away"); 01262 } else { 01263 astman_send_error(s, m, "Unable to find channel"); 01264 } 01265 01266 return 0; 01267 }
static int unload_module | ( | void | ) | [static] |
Unload the local proxy channel from Asterisk.
Definition at line 1295 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.
01296 { 01297 struct local_pvt *p = NULL; 01298 struct ao2_iterator it; 01299 01300 /* First, take us out of the channel loop */ 01301 ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 01302 ast_manager_unregister("LocalOptimizeAway"); 01303 ast_channel_unregister(&local_tech); 01304 01305 it = ao2_iterator_init(locals, 0); 01306 while ((p = ao2_iterator_next(&it))) { 01307 if (p->owner) { 01308 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); 01309 } 01310 ao2_ref(p, -1); 01311 } 01312 ao2_iterator_destroy(&it); 01313 ao2_ref(locals, -1); 01314 01315 return 0; 01316 }
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 = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DRIVER, } [static] |
Definition at line 1322 of file chan_local.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1322 of file chan_local.c.
const int BUCKET_SIZE = 1 [static] |
Definition at line 83 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 1217 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 113 of file chan_local.c.
Referenced by load_module(), local_new(), and unload_module().
struct ao2_container* locals [static] |
Definition at line 85 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 76 of file chan_local.c.