#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, struct ast_format_cap *cap) |
| 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, const char *dest, int timeout) |
| Initiate new call, part of PBX interface dest is the dial string. | |
| static void | local_destroy (void *obj) |
| static int | local_devicestate (const char *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, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *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 = AST_BUILDOPT_SUM, .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 155 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 158 of file chan_local.c.
Referenced by local_alloc(), and local_bridgedchannel().
| #define LOCAL_LAUNCHED_PBX (1 << 1) |
PBX was launched
Definition at line 156 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 159 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 157 of file chan_local.c.
Referenced by check_bridge(), local_alloc(), local_call(), and manager_optimize_away().
| static void __reg_module | ( | void | ) | [static] |
Definition at line 1359 of file chan_local.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 1359 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 170 of file chan_local.c.
References ao2_lock, ao2_unlock, ast_channel_lock, ast_channel_ref, ast_channel_trylock, ast_channel_unlock, ast_channel_unref, local_pvt::chan, CHANNEL_DEADLOCK_AVOIDANCE, and local_pvt::owner.
Referenced by local_call(), and local_hangup().
00171 { 00172 struct ast_channel *chan = NULL; 00173 struct ast_channel *owner = NULL; 00174 00175 for (;;) { 00176 ao2_lock(p); 00177 if (p->chan) { 00178 chan = p->chan; 00179 ast_channel_ref(chan); 00180 } 00181 if (p->owner) { 00182 owner = p->owner; 00183 ast_channel_ref(owner); 00184 } 00185 ao2_unlock(p); 00186 00187 /* if we don't have both channels, then this is very easy */ 00188 if (!owner || !chan) { 00189 if (owner) { 00190 ast_channel_lock(owner); 00191 } else if(chan) { 00192 ast_channel_lock(chan); 00193 } 00194 ao2_lock(p); 00195 } else { 00196 /* lock both channels first, then get the pvt lock */ 00197 ast_channel_lock(chan); 00198 while (ast_channel_trylock(owner)) { 00199 CHANNEL_DEADLOCK_AVOIDANCE(chan); 00200 } 00201 ao2_lock(p); 00202 } 00203 00204 /* Now that we have all the locks, validate that nothing changed */ 00205 if (p->owner != owner || p->chan != chan) { 00206 if (owner) { 00207 ast_channel_unlock(owner); 00208 owner = ast_channel_unref(owner); 00209 } 00210 if (chan) { 00211 ast_channel_unlock(chan); 00212 chan = ast_channel_unref(chan); 00213 } 00214 ao2_unlock(p); 00215 continue; 00216 } 00217 00218 break; 00219 } 00220 *outowner = p->owner; 00221 *outchan = p->chan; 00222 }
| 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 1305 of file chan_local.c.
References ao2_container_alloc, ao2_ref, ast_channel_register(), ast_cli_register_multiple(), ast_format_cap_add_all(), ast_format_cap_alloc(), ast_format_cap_destroy(), ast_log(), ast_manager_register_xml, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_channel_tech::capabilities, EVENT_FLAG_CALL, EVENT_FLAG_SYSTEM, locals_cmp_cb(), LOG_ERROR, and manager_optimize_away().
01306 { 01307 if (!(local_tech.capabilities = ast_format_cap_alloc())) { 01308 return AST_MODULE_LOAD_FAILURE; 01309 } 01310 ast_format_cap_add_all(local_tech.capabilities); 01311 01312 if (!(locals = ao2_container_alloc(BUCKET_SIZE, NULL, locals_cmp_cb))) { 01313 ast_format_cap_destroy(local_tech.capabilities); 01314 return AST_MODULE_LOAD_FAILURE; 01315 } 01316 01317 /* Make sure we can register our channel type */ 01318 if (ast_channel_register(&local_tech)) { 01319 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n"); 01320 ao2_ref(locals, -1); 01321 ast_format_cap_destroy(local_tech.capabilities); 01322 return AST_MODULE_LOAD_FAILURE; 01323 } 01324 ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 01325 ast_manager_register_xml("LocalOptimizeAway", EVENT_FLAG_SYSTEM|EVENT_FLAG_CALL, manager_optimize_away); 01326 01327 return AST_MODULE_LOAD_SUCCESS; 01328 }
| static struct local_pvt* local_alloc | ( | const char * | data, | |
| struct ast_format_cap * | cap | |||
| ) | [static, read] |
Create a call structure.
Definition at line 1062 of file chan_local.c.
References ao2_alloc, ao2_link, ao2_ref, ast_copy_string(), ast_exists_extension(), ast_format_cap_dup(), AST_JB_ENABLED, ast_log(), ast_set_flag, ast_test_flag, local_pvt::context, local_pvt::exten, local_pvt::jb_conf, LOCAL_BRIDGE, local_destroy(), LOCAL_MOH_PASSTHRU, LOCAL_NO_OPTIMIZATION, LOG_ERROR, LOG_NOTICE, and local_pvt::reqcap.
Referenced by local_request().
01063 { 01064 struct local_pvt *tmp = NULL; 01065 char *c = NULL, *opts = NULL; 01066 01067 if (!(tmp = ao2_alloc(sizeof(*tmp), local_destroy))) { 01068 return NULL; 01069 } 01070 if (!(tmp->reqcap = ast_format_cap_dup(cap))) { 01071 ao2_ref(tmp, -1); 01072 return NULL; 01073 } 01074 01075 /* Initialize private structure information */ 01076 ast_copy_string(tmp->exten, data, sizeof(tmp->exten)); 01077 01078 memcpy(&tmp->jb_conf, &g_jb_conf, sizeof(tmp->jb_conf)); 01079 01080 /* Look for options */ 01081 if ((opts = strchr(tmp->exten, '/'))) { 01082 *opts++ = '\0'; 01083 if (strchr(opts, 'n')) 01084 ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION); 01085 if (strchr(opts, 'j')) { 01086 if (ast_test_flag(tmp, LOCAL_NO_OPTIMIZATION)) 01087 ast_set_flag(&tmp->jb_conf, AST_JB_ENABLED); 01088 else { 01089 ast_log(LOG_ERROR, "You must use the 'n' option for chan_local " 01090 "to use the 'j' option to enable the jitterbuffer\n"); 01091 } 01092 } 01093 if (strchr(opts, 'b')) { 01094 ast_set_flag(tmp, LOCAL_BRIDGE); 01095 } 01096 if (strchr(opts, 'm')) { 01097 ast_set_flag(tmp, LOCAL_MOH_PASSTHRU); 01098 } 01099 } 01100 01101 /* Look for a context */ 01102 if ((c = strchr(tmp->exten, '@'))) 01103 *c++ = '\0'; 01104 01105 ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context)); 01106 #if 0 01107 /* We can't do this check here, because we don't know the CallerID yet, and 01108 * the CallerID could potentially affect what step is actually taken (or 01109 * even if that step exists). */ 01110 if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) { 01111 ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context); 01112 tmp = local_pvt_destroy(tmp); 01113 } else { 01114 #endif 01115 /* Add to list */ 01116 ao2_link(locals, tmp); 01117 #if 0 01118 } 01119 #endif 01120 return tmp; /* this is returned with a ref */ 01121 }
| static int local_answer | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 448 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.
00449 { 00450 struct local_pvt *p = ast->tech_pvt; 00451 int isoutbound; 00452 int res = -1; 00453 00454 if (!p) { 00455 return -1; 00456 } 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, read] |
Return the bridged channel of a Local channel.
Definition at line 322 of file chan_local.c.
References ast_channel::_bridge, ao2_lock, ao2_unlock, ast_channel_name(), ast_debug, ast_test_flag, local_pvt::chan, LOCAL_BRIDGE, local_pvt::owner, and ast_channel::tech_pvt.
00323 { 00324 struct local_pvt *p = bridge->tech_pvt; 00325 struct ast_channel *bridged = bridge; 00326 00327 if (!p) { 00328 ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning <none>\n", 00329 ast_channel_name(chan), ast_channel_name(bridge)); 00330 return NULL; 00331 } 00332 00333 ao2_lock(p); 00334 00335 if (ast_test_flag(p, LOCAL_BRIDGE)) { 00336 /* Find the opposite channel */ 00337 bridged = (bridge == p->owner ? p->chan : p->owner); 00338 00339 /* Now see if the opposite channel is bridged to anything */ 00340 if (!bridged) { 00341 bridged = bridge; 00342 } else if (bridged->_bridge) { 00343 bridged = bridged->_bridge; 00344 } 00345 } 00346 00347 ao2_unlock(p); 00348 00349 return bridged; 00350 }
| static int local_call | ( | struct ast_channel * | ast, | |
| const char * | dest, | |||
| int | timeout | |||
| ) | [static] |
Initiate new call, part of PBX interface dest is the dial string.
Definition at line 812 of file chan_local.c.
References ao2_lock, ao2_ref, ao2_unlock, ast_calloc, ast_cdr_update(), ast_channel_accountcode(), ast_channel_cc_params_init(), ast_channel_datastore_inherit(), ast_channel_get_cc_config_params(), ast_channel_language(), ast_channel_lock, ast_channel_musicclass(), ast_channel_name(), ast_channel_uniqueid(), 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_test_flag, awesome_locking(), ast_channel::caller, local_pvt::chan, ast_channel::connected, local_pvt::context, ast_channel::context, context, ast_channel::dialed, ast_var_t::entries, EVENT_FLAG_CALL, local_pvt::exten, ast_channel::exten, exten, ast_party_caller::id, len(), LOCAL_LAUNCHED_PBX, LOCAL_NO_OPTIMIZATION, LOG_NOTICE, manager_event, 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, and ast_channel::varshead.
00813 { 00814 struct local_pvt *p = ast->tech_pvt; 00815 int pvt_locked = 0; 00816 00817 struct ast_channel *owner = NULL; 00818 struct ast_channel *chan = NULL; 00819 int res; 00820 struct ast_var_t *varptr = NULL, *new; 00821 size_t len, namelen; 00822 char *reduced_dest = ast_strdupa(dest); 00823 char *slash; 00824 const char *exten; 00825 const char *context; 00826 00827 if (!p) { 00828 return -1; 00829 } 00830 00831 /* since we are letting go of channel locks that were locked coming into 00832 * this function, then we need to give the tech pvt a ref */ 00833 ao2_ref(p, 1); 00834 ast_channel_unlock(ast); 00835 00836 awesome_locking(p, &chan, &owner); 00837 pvt_locked = 1; 00838 00839 if (owner != ast) { 00840 res = -1; 00841 goto return_cleanup; 00842 } 00843 00844 if (!owner || !chan) { 00845 res = -1; 00846 goto return_cleanup; 00847 } 00848 00849 /* 00850 * Note that cid_num and cid_name aren't passed in the ast_channel_alloc 00851 * call, so it's done here instead. 00852 * 00853 * All these failure points just return -1. The individual strings will 00854 * be cleared when we destroy the channel. 00855 */ 00856 ast_party_redirecting_copy(&chan->redirecting, &owner->redirecting); 00857 00858 ast_party_dialed_copy(&chan->dialed, &owner->dialed); 00859 00860 ast_connected_line_copy_to_caller(&chan->caller, &owner->connected); 00861 ast_connected_line_copy_from_caller(&chan->connected, &owner->caller); 00862 00863 ast_channel_language_set(chan, ast_channel_language(owner)); 00864 ast_channel_accountcode_set(chan, ast_channel_accountcode(owner)); 00865 ast_channel_musicclass_set(chan, ast_channel_musicclass(owner)); 00866 ast_cdr_update(chan); 00867 00868 ast_channel_cc_params_init(chan, ast_channel_get_cc_config_params(owner)); 00869 00870 /* Make sure we inherit the ANSWERED_ELSEWHERE flag if it's set on the queue/dial call request in the dialplan */ 00871 if (ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) { 00872 ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE); 00873 } 00874 00875 /* copy the channel variables from the incoming channel to the outgoing channel */ 00876 /* Note that due to certain assumptions, they MUST be in the same order */ 00877 AST_LIST_TRAVERSE(&owner->varshead, varptr, entries) { 00878 namelen = strlen(varptr->name); 00879 len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2; 00880 if ((new = ast_calloc(1, len))) { 00881 memcpy(new, varptr, len); 00882 new->value = &(new->name[0]) + namelen + 1; 00883 AST_LIST_INSERT_TAIL(&chan->varshead, new, entries); 00884 } 00885 } 00886 ast_channel_datastore_inherit(owner, chan); 00887 /* If the local channel has /n or /b on the end of it, 00888 * we need to lop that off for our argument to setting 00889 * up the CC_INTERFACES variable 00890 */ 00891 if ((slash = strrchr(reduced_dest, '/'))) { 00892 *slash = '\0'; 00893 } 00894 ast_set_cc_interfaces_chanvar(chan, reduced_dest); 00895 00896 exten = ast_strdupa(chan->exten); 00897 context = ast_strdupa(chan->context); 00898 00899 ao2_unlock(p); 00900 pvt_locked = 0; 00901 00902 ast_channel_unlock(chan); 00903 00904 if (!ast_exists_extension(chan, context, exten, 1, 00905 S_COR(owner->caller.id.number.valid, owner->caller.id.number.str, NULL))) { 00906 ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", exten, context); 00907 res = -1; 00908 chan = ast_channel_unref(chan); /* we already unlocked it, so clear it hear so the cleanup label won't touch it. */ 00909 goto return_cleanup; 00910 } 00911 00912 manager_event(EVENT_FLAG_CALL, "LocalBridge", 00913 "Channel1: %s\r\n" 00914 "Channel2: %s\r\n" 00915 "Uniqueid1: %s\r\n" 00916 "Uniqueid2: %s\r\n" 00917 "Context: %s\r\n" 00918 "Exten: %s\r\n" 00919 "LocalOptimization: %s\r\n", 00920 ast_channel_name(p->owner), ast_channel_name(p->chan), ast_channel_uniqueid(p->owner), ast_channel_uniqueid(p->chan), 00921 p->context, p->exten, 00922 ast_test_flag(p, LOCAL_NO_OPTIMIZATION) ? "Yes" : "No"); 00923 00924 00925 /* Start switch on sub channel */ 00926 if (!(res = ast_pbx_start(chan))) { 00927 ao2_lock(p); 00928 ast_set_flag(p, LOCAL_LAUNCHED_PBX); 00929 ao2_unlock(p); 00930 } 00931 chan = ast_channel_unref(chan); /* chan is already unlocked, clear it here so the cleanup lable won't touch it. */ 00932 00933 return_cleanup: 00934 if (p) { 00935 if (pvt_locked) { 00936 ao2_unlock(p); 00937 } 00938 ao2_ref(p, -1); 00939 } 00940 if (chan) { 00941 ast_channel_unlock(chan); 00942 chan = ast_channel_unref(chan); 00943 } 00944 00945 /* owner is supposed to be == to ast, if it 00946 * is, don't unlock it because ast must exit locked */ 00947 if (owner) { 00948 if (owner != ast) { 00949 ast_channel_unlock(owner); 00950 ast_channel_lock(ast); 00951 } 00952 owner = ast_channel_unref(owner); 00953 } else { 00954 /* we have to exit with ast locked */ 00955 ast_channel_lock(ast); 00956 } 00957 00958 return res; 00959 }
| static void local_destroy | ( | void * | obj | ) | [static] |
Definition at line 1055 of file chan_local.c.
References ast_format_cap_destroy(), and local_pvt::reqcap.
Referenced by local_alloc().
01056 { 01057 struct local_pvt *pvt = obj; 01058 pvt->reqcap = ast_format_cap_destroy(pvt->reqcap); 01059 }
| static int local_devicestate | ( | const char * | data | ) | [static] |
Adds devicestate to local channels.
Definition at line 280 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, LOG_WARNING, and local_pvt::owner.
00281 { 00282 char *exten = ast_strdupa(data); 00283 char *context = NULL, *opts = NULL; 00284 int res; 00285 struct local_pvt *lp; 00286 struct ao2_iterator it; 00287 00288 if (!(context = strchr(exten, '@'))) { 00289 ast_log(LOG_WARNING, "Someone used Local/%s somewhere without a @context. This is bad.\n", exten); 00290 return AST_DEVICE_INVALID; 00291 } 00292 00293 *context++ = '\0'; 00294 00295 /* Strip options if they exist */ 00296 if ((opts = strchr(context, '/'))) 00297 *opts = '\0'; 00298 00299 ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context); 00300 00301 res = ast_exists_extension(NULL, context, exten, 1, NULL); 00302 if (!res) 00303 return AST_DEVICE_INVALID; 00304 00305 res = AST_DEVICE_NOT_INUSE; 00306 00307 it = ao2_iterator_init(locals, 0); 00308 while ((lp = ao2_iterator_next(&it))) { 00309 if (!strcmp(exten, lp->exten) && !strcmp(context, lp->context) && lp->owner) { 00310 res = AST_DEVICE_INUSE; 00311 ao2_ref(lp, -1); 00312 break; 00313 } 00314 ao2_ref(lp, -1); 00315 } 00316 ao2_iterator_destroy(&it); 00317 00318 return res; 00319 }
| static int local_digit_begin | ( | struct ast_channel * | ast, | |
| char | digit | |||
| ) | [static] |
Definition at line 719 of file chan_local.c.
References ao2_lock, ao2_ref, ao2_unlock, AST_FRAME_DTMF_BEGIN, ast_frame_subclass::integer, IS_OUTBOUND, local_queue_frame(), ast_frame::subclass, and ast_channel::tech_pvt.
00720 { 00721 struct local_pvt *p = ast->tech_pvt; 00722 int res = -1; 00723 struct ast_frame f = { AST_FRAME_DTMF_BEGIN, }; 00724 int isoutbound; 00725 00726 if (!p) { 00727 return -1; 00728 } 00729 00730 ao2_ref(p, 1); /* ref for local_queue_frame */ 00731 ao2_lock(p); 00732 isoutbound = IS_OUTBOUND(ast, p); 00733 f.subclass.integer = digit; 00734 res = local_queue_frame(p, isoutbound, &f, ast, 0); 00735 ao2_unlock(p); 00736 ao2_ref(p, -1); 00737 00738 return res; 00739 }
| static int local_digit_end | ( | struct ast_channel * | ast, | |
| char | digit, | |||
| unsigned int | duration | |||
| ) | [static] |
Definition at line 741 of file chan_local.c.
References ao2_lock, ao2_ref, ao2_unlock, AST_FRAME_DTMF_END, ast_frame_subclass::integer, IS_OUTBOUND, ast_frame::len, local_queue_frame(), ast_frame::subclass, and ast_channel::tech_pvt.
00742 { 00743 struct local_pvt *p = ast->tech_pvt; 00744 int res = -1; 00745 struct ast_frame f = { AST_FRAME_DTMF_END, }; 00746 int isoutbound; 00747 00748 if (!p) { 00749 return -1; 00750 } 00751 00752 ao2_ref(p, 1); /* ref for local_queue_frame */ 00753 ao2_lock(p); 00754 isoutbound = IS_OUTBOUND(ast, p); 00755 f.subclass.integer = digit; 00756 f.len = duration; 00757 res = local_queue_frame(p, isoutbound, &f, ast, 0); 00758 ao2_unlock(p); 00759 ao2_ref(p, -1); 00760 00761 return res; 00762 }
| 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 00627 ao2_lock(p); 00628 00629 if ((p->owner != oldchan) && (p->chan != oldchan)) { 00630 ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan); 00631 ao2_unlock(p); 00632 return -1; 00633 } 00634 if (p->owner == oldchan) { 00635 p->owner = newchan; 00636 } else { 00637 p->chan = newchan; 00638 } 00639 00640 /* Do not let a masquerade cause a Local channel to be bridged to itself! */ 00641 if (!ast_check_hangup(newchan) && ((p->owner && p->owner->_bridge == p->chan) || (p->chan && p->chan->_bridge == p->owner))) { 00642 ast_log(LOG_WARNING, "You can not bridge a Local channel to itself!\n"); 00643 ao2_unlock(p); 00644 ast_queue_hangup(newchan); 00645 return -1; 00646 } 00647 00648 ao2_unlock(p); 00649 return 0; 00650 }
| static int local_hangup | ( | struct ast_channel * | ast | ) | [static] |
Hangup a call through the local proxy channel.
Definition at line 962 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, hangup_chan(), ast_channel::hangupcause, IS_OUTBOUND, LOCAL_LAUNCHED_PBX, local_queue_frame(), 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.
00963 { 00964 struct local_pvt *p = ast->tech_pvt; 00965 int isoutbound; 00966 int hangup_chan = 0; 00967 int res = 0; 00968 struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_HANGUP }, .data.uint32 = ast->hangupcause }; 00969 struct ast_channel *owner = NULL; 00970 struct ast_channel *chan = NULL; 00971 00972 if (!p) { 00973 return -1; 00974 } 00975 00976 /* give the pvt a ref since we are unlocking the channel. */ 00977 ao2_ref(p, 1); 00978 00979 /* the pvt isn't going anywhere, we gave it a ref */ 00980 ast_channel_unlock(ast); 00981 00982 /* lock everything */ 00983 awesome_locking(p, &chan, &owner); 00984 00985 if (ast != chan && ast != owner) { 00986 res = -1; 00987 goto local_hangup_cleanup; 00988 } 00989 00990 isoutbound = IS_OUTBOUND(ast, p); /* just comparing pointer of ast */ 00991 00992 if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) { 00993 ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE); 00994 ast_debug(2, "This local call has the ANSWERED_ELSEWHERE flag set.\n"); 00995 } 00996 00997 if (isoutbound) { 00998 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS"); 00999 if ((status) && (p->owner)) { 01000 p->owner->hangupcause = p->chan->hangupcause; 01001 pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status); 01002 } 01003 01004 ast_clear_flag(p, LOCAL_LAUNCHED_PBX); 01005 ast_module_user_remove(p->u_chan); 01006 p->chan = NULL; 01007 } else { 01008 ast_module_user_remove(p->u_owner); 01009 if (p->chan) { 01010 ast_queue_hangup(p->chan); 01011 } 01012 p->owner = NULL; 01013 } 01014 01015 ast->tech_pvt = NULL; /* this is one of our locked channels, doesn't matter which */ 01016 01017 if (!p->owner && !p->chan) { 01018 ao2_unlock(p); 01019 /* Remove from list */ 01020 ao2_unlink(locals, p); 01021 ao2_ref(p, -1); 01022 p = NULL; 01023 res = 0; 01024 goto local_hangup_cleanup; 01025 } 01026 if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) { 01027 /* Need to actually hangup since there is no PBX */ 01028 hangup_chan = 1; 01029 } else { 01030 local_queue_frame(p, isoutbound, &f, NULL, 0); 01031 } 01032 01033 local_hangup_cleanup: 01034 if (p) { 01035 ao2_unlock(p); 01036 ao2_ref(p, -1); 01037 } 01038 if (chan) { 01039 ast_channel_unlock(chan); 01040 if (hangup_chan) { 01041 ast_hangup(chan); 01042 } 01043 chan = ast_channel_unref(chan); 01044 } 01045 if (owner) { 01046 ast_channel_unlock(owner); 01047 owner = ast_channel_unref(owner); 01048 } 01049 01050 /* leave with the same stupid channel locked that came in */ 01051 ast_channel_lock(ast); 01052 return res; 01053 }
| static int local_indicate | ( | struct ast_channel * | ast, | |
| int | condition, | |||
| const void * | data, | |||
| size_t | datalen | |||
| ) | [static] |
Definition at line 652 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, ast_frame::data, ast_frame::datalen, ast_frame_subclass::integer, IS_OUTBOUND, LOCAL_MOH_PASSTHRU, local_queue_frame(), local_pvt::owner, ast_frame::ptr, ast_channel::redirecting, ast_frame::subclass, and ast_channel::tech_pvt.
00653 { 00654 struct local_pvt *p = ast->tech_pvt; 00655 int res = 0; 00656 struct ast_frame f = { AST_FRAME_CONTROL, }; 00657 int isoutbound; 00658 00659 if (!p) { 00660 return -1; 00661 } 00662 00663 ao2_ref(p, 1); /* ref for local_queue_frame */ 00664 00665 /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */ 00666 if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) { 00667 ast_moh_start(ast, data, NULL); 00668 } else if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_UNHOLD) { 00669 ast_moh_stop(ast); 00670 } else if (condition == AST_CONTROL_CONNECTED_LINE || condition == AST_CONTROL_REDIRECTING) { 00671 struct ast_channel *this_channel; 00672 struct ast_channel *the_other_channel; 00673 /* A connected line update frame may only contain a partial amount of data, such 00674 * as just a source, or just a ton, and not the full amount of information. However, 00675 * the collected information is all stored in the outgoing channel's connectedline 00676 * structure, so when receiving a connected line update on an outgoing local channel, 00677 * we need to transmit the collected connected line information instead of whatever 00678 * happens to be in this control frame. The same applies for redirecting information, which 00679 * is why it is handled here as well.*/ 00680 ao2_lock(p); 00681 isoutbound = IS_OUTBOUND(ast, p); 00682 if (isoutbound) { 00683 this_channel = p->chan; 00684 the_other_channel = p->owner; 00685 } else { 00686 this_channel = p->owner; 00687 the_other_channel = p->chan; 00688 } 00689 if (the_other_channel) { 00690 unsigned char frame_data[1024]; 00691 if (condition == AST_CONTROL_CONNECTED_LINE) { 00692 if (isoutbound) { 00693 ast_connected_line_copy_to_caller(&the_other_channel->caller, &this_channel->connected); 00694 } 00695 f.datalen = ast_connected_line_build_data(frame_data, sizeof(frame_data), &this_channel->connected, NULL); 00696 } else { 00697 f.datalen = ast_redirecting_build_data(frame_data, sizeof(frame_data), &this_channel->redirecting, NULL); 00698 } 00699 f.subclass.integer = condition; 00700 f.data.ptr = frame_data; 00701 res = local_queue_frame(p, isoutbound, &f, ast, 1); 00702 } 00703 ao2_unlock(p); 00704 } else { 00705 /* Queue up a frame representing the indication as a control frame */ 00706 ao2_lock(p); 00707 isoutbound = IS_OUTBOUND(ast, p); 00708 f.subclass.integer = condition; 00709 f.data.ptr = (void*)data; 00710 f.datalen = datalen; 00711 res = local_queue_frame(p, isoutbound, &f, ast, 1); 00712 ao2_unlock(p); 00713 } 00714 00715 ao2_ref(p, -1); 00716 return res; 00717 }
| static struct ast_channel* local_new | ( | struct local_pvt * | p, | |
| int | state, | |||
| const char * | linkedid | |||
| ) | [static, read] |
Start new local channel.
Definition at line 1124 of file chan_local.c.
References ast_channel::amaflags, ast_best_codec(), ast_channel_accountcode(), ast_channel_alloc, ast_channel_release(), ast_copy_string(), ast_format_cap_copy(), ast_format_copy(), 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, LOG_WARNING, ast_channel::nativeformats, local_pvt::owner, ast_channel::priority, ast_channel::rawreadformat, ast_channel::rawwriteformat, ast_channel::readformat, local_pvt::reqcap, ast_channel::tech, ast_channel::tech_pvt, local_pvt::u_chan, local_pvt::u_owner, and ast_channel::writeformat.
Referenced by local_request().
01125 { 01126 struct ast_channel *tmp = NULL, *tmp2 = NULL; 01127 int randnum = ast_random() & 0xffff; 01128 struct ast_format fmt; 01129 const char *t; 01130 int ama; 01131 01132 /* Allocate two new Asterisk channels */ 01133 /* safe accountcode */ 01134 if (p->owner && ast_channel_accountcode(p->owner)) 01135 t = ast_channel_accountcode(p->owner); 01136 else 01137 t = ""; 01138 01139 if (p->owner) 01140 ama = p->owner->amaflags; 01141 else 01142 ama = 0; 01143 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)) 01144 || !(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))) { 01145 if (tmp) { 01146 tmp = ast_channel_release(tmp); 01147 } 01148 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n"); 01149 return NULL; 01150 } 01151 01152 tmp2->tech = tmp->tech = &local_tech; 01153 01154 ast_format_cap_copy(tmp->nativeformats, p->reqcap); 01155 ast_format_cap_copy(tmp2->nativeformats, p->reqcap); 01156 01157 /* Determine our read/write format and set it on each channel */ 01158 ast_best_codec(p->reqcap, &fmt); 01159 ast_format_copy(&tmp->writeformat, &fmt); 01160 ast_format_copy(&tmp2->writeformat, &fmt); 01161 ast_format_copy(&tmp->rawwriteformat, &fmt); 01162 ast_format_copy(&tmp2->rawwriteformat, &fmt); 01163 ast_format_copy(&tmp->readformat, &fmt); 01164 ast_format_copy(&tmp2->readformat, &fmt); 01165 ast_format_copy(&tmp->rawreadformat, &fmt); 01166 ast_format_copy(&tmp2->rawreadformat, &fmt); 01167 01168 tmp->tech_pvt = p; 01169 tmp2->tech_pvt = p; 01170 01171 p->owner = tmp; 01172 p->chan = tmp2; 01173 p->u_owner = ast_module_user_add(p->owner); 01174 p->u_chan = ast_module_user_add(p->chan); 01175 01176 ast_copy_string(tmp->context, p->context, sizeof(tmp->context)); 01177 ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context)); 01178 ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten)); 01179 tmp->priority = 1; 01180 tmp2->priority = 1; 01181 01182 ast_jb_configure(tmp, &p->jb_conf); 01183 01184 return tmp; 01185 }
| static int local_queryoption | ( | struct ast_channel * | ast, | |
| int | option, | |||
| void * | data, | |||
| int * | datalen | |||
| ) | [static] |
Definition at line 353 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.
00354 { 00355 struct local_pvt *p; 00356 struct ast_channel *bridged = NULL; 00357 struct ast_channel *tmp = NULL; 00358 int res = 0; 00359 00360 if (option != AST_OPTION_T38_STATE) { 00361 /* AST_OPTION_T38_STATE is the only supported option at this time */ 00362 return -1; 00363 } 00364 00365 /* for some reason the channel is not locked in channel.c when this function is called */ 00366 if (!(p = ast->tech_pvt)) { 00367 return -1; 00368 } 00369 00370 ao2_lock(p); 00371 if (!(tmp = IS_OUTBOUND(ast, p) ? p->owner : p->chan)) { 00372 ao2_unlock(p); 00373 return -1; 00374 } 00375 ast_channel_ref(tmp); 00376 ao2_unlock(p); 00377 ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */ 00378 00379 ast_channel_lock(tmp); 00380 if (!(bridged = ast_bridged_channel(tmp))) { 00381 res = -1; 00382 ast_channel_unlock(tmp); 00383 goto query_cleanup; 00384 } 00385 ast_channel_ref(bridged); 00386 ast_channel_unlock(tmp); 00387 00388 query_cleanup: 00389 if (bridged) { 00390 res = ast_channel_queryoption(bridged, option, data, datalen, 0); 00391 bridged = ast_channel_unref(bridged); 00392 } 00393 if (tmp) { 00394 tmp = ast_channel_unref(tmp); 00395 } 00396 ast_channel_lock(ast); /* Lock back before we leave */ 00397 00398 return res; 00399 }
| 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 409 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, ast_frame::frametype, ast_channel::generator, ast_frame_subclass::integer, local_pvt::owner, and ast_frame::subclass.
Referenced by local_answer(), local_digit_begin(), local_digit_end(), local_hangup(), local_indicate(), local_sendhtml(), local_sendtext(), and local_write().
00411 { 00412 struct ast_channel *other = NULL; 00413 00414 /* Recalculate outbound channel */ 00415 other = isoutbound ? p->owner : p->chan; 00416 00417 if (!other) { 00418 return 0; 00419 } 00420 00421 /* do not queue frame if generator is on both local channels */ 00422 if (us && us->generator && other->generator) { 00423 return 0; 00424 } 00425 00426 /* grab a ref on the channel before unlocking the pvt, 00427 * other can not go away from us now regardless of locking */ 00428 ast_channel_ref(other); 00429 if (us && us_locked) { 00430 ast_channel_unlock(us); 00431 } 00432 ao2_unlock(p); 00433 00434 if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_RINGING) { 00435 ast_setstate(other, AST_STATE_RINGING); 00436 } 00437 ast_queue_frame(other, f); 00438 00439 other = ast_channel_unref(other); 00440 if (us && us_locked) { 00441 ast_channel_lock(us); 00442 } 00443 ao2_lock(p); 00444 00445 return 0; 00446 }
| static struct ast_frame * local_read | ( | struct ast_channel * | ast | ) | [static, read] |
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, | |
| struct ast_format_cap * | cap, | |||
| const struct ast_channel * | requestor, | |||
| const char * | data, | |||
| int * | cause | |||
| ) | [static, read] |
Part of PBX interface.
Definition at line 1188 of file chan_local.c.
References ao2_ref, ao2_unlink, ast_channel_cc_params_init(), ast_channel_get_cc_config_params(), ast_channel_linkedid(), ast_channel_release(), AST_STATE_DOWN, local_alloc(), and local_new().
01189 { 01190 struct local_pvt *p = NULL; 01191 struct ast_channel *chan = NULL; 01192 01193 /* Allocate a new private structure and then Asterisk channel */ 01194 if ((p = local_alloc(data, cap))) { 01195 if (!(chan = local_new(p, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL))) { 01196 ao2_unlink(locals, p); 01197 } 01198 if (chan && ast_channel_cc_params_init(chan, requestor ? ast_channel_get_cc_config_params((struct ast_channel *)requestor) : NULL)) { 01199 chan = ast_channel_release(chan); 01200 ao2_unlink(locals, p); 01201 } 01202 ao2_ref(p, -1); /* kill the ref from the alloc */ 01203 } 01204 01205 return chan; 01206 }
| static int local_sendhtml | ( | struct ast_channel * | ast, | |
| int | subclass, | |||
| const char * | data, | |||
| int | datalen | |||
| ) | [static] |
Definition at line 786 of file chan_local.c.
References ao2_lock, ao2_ref, ao2_unlock, AST_FRAME_HTML, ast_frame::data, ast_frame::datalen, ast_frame_subclass::integer, IS_OUTBOUND, local_queue_frame(), ast_frame::ptr, ast_frame::subclass, and ast_channel::tech_pvt.
00787 { 00788 struct local_pvt *p = ast->tech_pvt; 00789 int res = -1; 00790 struct ast_frame f = { AST_FRAME_HTML, }; 00791 int isoutbound; 00792 00793 if (!p) { 00794 return -1; 00795 } 00796 00797 ao2_lock(p); 00798 ao2_ref(p, 1); /* ref for local_queue_frame */ 00799 isoutbound = IS_OUTBOUND(ast, p); 00800 f.subclass.integer = subclass; 00801 f.data.ptr = (char *)data; 00802 f.datalen = datalen; 00803 res = local_queue_frame(p, isoutbound, &f, ast, 0); 00804 ao2_unlock(p); 00805 ao2_ref(p, -1); 00806 00807 return res; 00808 }
| static int local_sendtext | ( | struct ast_channel * | ast, | |
| const char * | text | |||
| ) | [static] |
Definition at line 764 of file chan_local.c.
References ao2_lock, ao2_ref, ao2_unlock, AST_FRAME_TEXT, ast_frame::data, ast_frame::datalen, IS_OUTBOUND, local_queue_frame(), ast_frame::ptr, and ast_channel::tech_pvt.
00765 { 00766 struct local_pvt *p = ast->tech_pvt; 00767 int res = -1; 00768 struct ast_frame f = { AST_FRAME_TEXT, }; 00769 int isoutbound; 00770 00771 if (!p) { 00772 return -1; 00773 } 00774 00775 ao2_lock(p); 00776 ao2_ref(p, 1); /* ref for local_queue_frame */ 00777 isoutbound = IS_OUTBOUND(ast, p); 00778 f.data.ptr = (char *) text; 00779 f.datalen = strlen(text) + 1; 00780 res = local_queue_frame(p, isoutbound, &f, ast, 0); 00781 ao2_unlock(p); 00782 ao2_ref(p, -1); 00783 return res; 00784 }
| static int local_setoption | ( | struct ast_channel * | chan, | |
| int | option, | |||
| void * | data, | |||
| int | datalen | |||
| ) | [static] |
Definition at line 225 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.
00226 { 00227 int res = 0; 00228 struct local_pvt *p = NULL; 00229 struct ast_channel *otherchan = NULL; 00230 ast_chan_write_info_t *write_info; 00231 00232 if (option != AST_OPTION_CHANNEL_WRITE) { 00233 return -1; 00234 } 00235 00236 write_info = data; 00237 00238 if (write_info->version != AST_CHAN_WRITE_INFO_T_VERSION) { 00239 ast_log(LOG_ERROR, "The chan_write_info_t type has changed, and this channel hasn't been updated!\n"); 00240 return -1; 00241 } 00242 00243 /* get the tech pvt */ 00244 if (!(p = ast->tech_pvt)) { 00245 return -1; 00246 } 00247 ao2_ref(p, 1); 00248 ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */ 00249 00250 /* get the channel we are supposed to write to */ 00251 ao2_lock(p); 00252 otherchan = (write_info->chan == p->owner) ? p->chan : p->owner; 00253 if (!otherchan || otherchan == write_info->chan) { 00254 res = -1; 00255 otherchan = NULL; 00256 ao2_unlock(p); 00257 goto setoption_cleanup; 00258 } 00259 ast_channel_ref(otherchan); 00260 00261 /* clear the pvt lock before grabbing the channel */ 00262 ao2_unlock(p); 00263 00264 ast_channel_lock(otherchan); 00265 res = write_info->write_fn(otherchan, write_info->function, write_info->data, write_info->value); 00266 ast_channel_unlock(otherchan); 00267 00268 setoption_cleanup: 00269 if (p) { 00270 ao2_ref(p, -1); 00271 } 00272 if (otherchan) { 00273 ast_channel_unref(otherchan); 00274 } 00275 ast_channel_lock(ast); /* Lock back before we leave */ 00276 return res; 00277 }
| 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_channel_name(), ast_debug, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_test_flag, check_bridge(), ast_frame::frametype, IS_OUTBOUND, LOCAL_ALREADY_MASQED, local_queue_frame(), 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_channel_name(ast)); 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 1299 of file chan_local.c.
References CMP_MATCH.
Referenced by load_module().
01300 { 01301 return (obj == arg) ? CMP_MATCH : 0; 01302 }
| 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 1209 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_channel_name(), ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, local_pvt::context, local_pvt::exten, ast_cli_args::fd, local_pvt::owner, RESULT_SUCCESS, and ast_cli_entry::usage.
01210 { 01211 struct local_pvt *p = NULL; 01212 struct ao2_iterator it; 01213 01214 switch (cmd) { 01215 case CLI_INIT: 01216 e->command = "local show channels"; 01217 e->usage = 01218 "Usage: local show channels\n" 01219 " Provides summary information on active local proxy channels.\n"; 01220 return NULL; 01221 case CLI_GENERATE: 01222 return NULL; 01223 } 01224 01225 if (a->argc != 3) { 01226 return CLI_SHOWUSAGE; 01227 } 01228 01229 if (ao2_container_count(locals) == 0) { 01230 ast_cli(a->fd, "No local channels in use\n"); 01231 return RESULT_SUCCESS; 01232 } 01233 01234 it = ao2_iterator_init(locals, 0); 01235 while ((p = ao2_iterator_next(&it))) { 01236 ao2_lock(p); 01237 ast_cli(a->fd, "%s -- %s@%s\n", p->owner ? ast_channel_name(p->owner) : "<unowned>", p->exten, p->context); 01238 ao2_unlock(p); 01239 ao2_ref(p, -1); 01240 } 01241 ao2_iterator_destroy(&it); 01242 01243 return CLI_SUCCESS; 01244 }
| static int manager_optimize_away | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 1250 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(), LOCAL_NO_OPTIMIZATION, and ast_channel::tech_pvt.
Referenced by load_module().
01251 { 01252 const char *channel; 01253 struct local_pvt *p, *tmp = NULL; 01254 struct ast_channel *c; 01255 int found = 0; 01256 struct ao2_iterator it; 01257 01258 channel = astman_get_header(m, "Channel"); 01259 01260 if (ast_strlen_zero(channel)) { 01261 astman_send_error(s, m, "'Channel' not specified."); 01262 return 0; 01263 } 01264 01265 c = ast_channel_get_by_name(channel); 01266 if (!c) { 01267 astman_send_error(s, m, "Channel does not exist."); 01268 return 0; 01269 } 01270 01271 p = c->tech_pvt; 01272 ast_channel_unref(c); 01273 c = NULL; 01274 01275 it = ao2_iterator_init(locals, 0); 01276 while ((tmp = ao2_iterator_next(&it))) { 01277 if (tmp == p) { 01278 ao2_lock(tmp); 01279 found = 1; 01280 ast_clear_flag(tmp, LOCAL_NO_OPTIMIZATION); 01281 ao2_unlock(tmp); 01282 ao2_ref(tmp, -1); 01283 break; 01284 } 01285 ao2_ref(tmp, -1); 01286 } 01287 ao2_iterator_destroy(&it); 01288 01289 if (found) { 01290 astman_send_ack(s, m, "Queued channel to be optimized away"); 01291 } else { 01292 astman_send_error(s, m, "Unable to find channel"); 01293 } 01294 01295 return 0; 01296 }
| static int unload_module | ( | void | ) | [static] |
Unload the local proxy channel from Asterisk.
Definition at line 1331 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_format_cap_destroy(), ast_manager_unregister(), ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, ast_channel_tech::capabilities, and local_pvt::owner.
01332 { 01333 struct local_pvt *p = NULL; 01334 struct ao2_iterator it; 01335 01336 /* First, take us out of the channel loop */ 01337 ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 01338 ast_manager_unregister("LocalOptimizeAway"); 01339 ast_channel_unregister(&local_tech); 01340 01341 it = ao2_iterator_init(locals, 0); 01342 while ((p = ao2_iterator_next(&it))) { 01343 if (p->owner) { 01344 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); 01345 } 01346 ao2_ref(p, -1); 01347 } 01348 ao2_iterator_destroy(&it); 01349 ao2_ref(locals, -1); 01350 01351 ast_format_cap_destroy(local_tech.capabilities); 01352 return 0; 01353 }
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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DRIVER, } [static] |
Definition at line 1359 of file chan_local.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1359 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:
{
AST_CLI_DEFINE(locals_show, "List status of local channels"),
}
Definition at line 1246 of file chan_local.c.
struct ast_jb_conf g_jb_conf [static] |
Definition at line 87 of file chan_local.c.
struct ast_channel_tech local_tech [static] |
Definition at line 113 of file chan_local.c.
struct ao2_container* locals [static] |
Definition at line 85 of file chan_local.c.
const char tdesc[] = "Local Proxy Channel Driver" [static] |
Definition at line 76 of file chan_local.c.
1.5.6