#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 ast_channel *ast, 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 = "ac1f6a56484a8820659555499174e588" , .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(), local_indicate(), and manager_optimize_away().
static void __reg_module | ( | void | ) | [static] |
Definition at line 1384 of file chan_local.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 1384 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 ast_channel * | ast, | |
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_lock, ast_channel_masquerade(), ast_channel_ref, ast_channel_trylock, ast_channel_unlock, ast_channel_unref, ast_check_hangup(), ast_debug, ast_do_masquerade(), AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, AST_LIST_EMPTY, AST_LIST_FIRST, AST_LIST_REMOVE_HEAD, ast_set_flag, ast_test_flag, ast_channel::audiohooks, ast_channel::caller, local_pvt::chan, ast_channel::dialed, f, ast_party_redirecting::from, ast_party_caller::id, LOCAL_ALREADY_MASQED, LOCAL_NO_OPTIMIZATION, ast_channel::monitor, ast_party_id::name, ast_channel::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 *owner; 00482 struct ast_channel *chan; 00483 struct ast_channel *bridged_chan; 00484 struct ast_frame *f; 00485 00486 /* Do a few conditional checks early on just to see if this optimization is possible */ 00487 if (ast_test_flag(p, LOCAL_NO_OPTIMIZATION | LOCAL_ALREADY_MASQED) 00488 || !p->chan || !p->owner) { 00489 return; 00490 } 00491 00492 /* Safely get the channel bridged to p->chan */ 00493 chan = ast_channel_ref(p->chan); 00494 00495 ao2_unlock(p); /* don't call bridged channel with the pvt locked */ 00496 bridged_chan = ast_bridged_channel(chan); 00497 ao2_lock(p); 00498 00499 chan = ast_channel_unref(chan); 00500 00501 /* since we had to unlock p to get the bridged chan, validate our 00502 * data once again and verify the bridged channel is what we expect 00503 * it to be in order to perform this optimization */ 00504 if (ast_test_flag(p, LOCAL_NO_OPTIMIZATION | LOCAL_ALREADY_MASQED) 00505 || !p->chan || !p->owner 00506 || (p->chan->_bridge != bridged_chan)) { 00507 return; 00508 } 00509 00510 /* only do the masquerade if we are being called on the outbound channel, 00511 if it has been bridged to another channel and if there are no pending 00512 frames on the owner channel (because they would be transferred to the 00513 outbound channel during the masquerade) 00514 */ 00515 if (!p->chan->_bridge /* Not ast_bridged_channel! Only go one step! */ 00516 || !AST_LIST_EMPTY(&p->owner->readq) 00517 || ast != p->chan /* Sanity check (should always be false) */) { 00518 return; 00519 } 00520 00521 /* Masquerade bridged channel into owner */ 00522 /* Lock everything we need, one by one, and give up if 00523 we can't get everything. Remember, we'll get another 00524 chance in just a little bit */ 00525 if (ast_channel_trylock(p->chan->_bridge)) { 00526 return; 00527 } 00528 if (ast_check_hangup(p->chan->_bridge) || ast_channel_trylock(p->owner)) { 00529 ast_channel_unlock(p->chan->_bridge); 00530 return; 00531 } 00532 00533 /* 00534 * At this point we have 4 locks: 00535 * p, p->chan (same as ast), p->chan->_bridge, p->owner 00536 * 00537 * Flush a voice or video frame on the outbound channel to make 00538 * the queue empty faster so we can get optimized out. 00539 */ 00540 f = AST_LIST_FIRST(&p->chan->readq); 00541 if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) { 00542 AST_LIST_REMOVE_HEAD(&p->chan->readq, frame_list); 00543 ast_frfree(f); 00544 f = AST_LIST_FIRST(&p->chan->readq); 00545 } 00546 00547 if (f 00548 || ast_check_hangup(p->owner) 00549 || ast_channel_masquerade(p->owner, p->chan->_bridge)) { 00550 ast_channel_unlock(p->owner); 00551 ast_channel_unlock(p->chan->_bridge); 00552 return; 00553 } 00554 00555 /* Masquerade got setup. */ 00556 ast_debug(4, "Masquerading %s <- %s\n", 00557 p->owner->name, p->chan->_bridge->name); 00558 if (p->owner->monitor && !p->chan->_bridge->monitor) { 00559 struct ast_channel_monitor *tmp; 00560 00561 /* If a local channel is being monitored, we don't want a masquerade 00562 * to cause the monitor to go away. Since the masquerade swaps the monitors, 00563 * pre-swapping the monitors before the masquerade will ensure that the monitor 00564 * ends up where it is expected. 00565 */ 00566 tmp = p->owner->monitor; 00567 p->owner->monitor = p->chan->_bridge->monitor; 00568 p->chan->_bridge->monitor = tmp; 00569 } 00570 if (p->chan->audiohooks) { 00571 struct ast_audiohook_list *audiohooks_swapper; 00572 audiohooks_swapper = p->chan->audiohooks; 00573 p->chan->audiohooks = p->owner->audiohooks; 00574 p->owner->audiohooks = audiohooks_swapper; 00575 } 00576 00577 /* If any Caller ID was set, preserve it after masquerade like above. We must check 00578 * to see if Caller ID was set because otherwise we'll mistakingly copy info not 00579 * set from the dialplan and will overwrite the real channel Caller ID. The reason 00580 * for this whole preswapping action is because the Caller ID is set on the channel 00581 * thread (which is the to be masqueraded away local channel) before both local 00582 * channels are optimized away. 00583 */ 00584 if (p->owner->caller.id.name.valid || p->owner->caller.id.number.valid 00585 || p->owner->caller.id.subaddress.valid || p->owner->caller.ani.name.valid 00586 || p->owner->caller.ani.number.valid || p->owner->caller.ani.subaddress.valid) { 00587 struct ast_party_caller tmp; 00588 00589 tmp = p->owner->caller; 00590 p->owner->caller = p->chan->_bridge->caller; 00591 p->chan->_bridge->caller = tmp; 00592 } 00593 if (p->owner->redirecting.from.name.valid || p->owner->redirecting.from.number.valid 00594 || p->owner->redirecting.from.subaddress.valid || p->owner->redirecting.to.name.valid 00595 || p->owner->redirecting.to.number.valid || p->owner->redirecting.to.subaddress.valid) { 00596 struct ast_party_redirecting tmp; 00597 00598 tmp = p->owner->redirecting; 00599 p->owner->redirecting = p->chan->_bridge->redirecting; 00600 p->chan->_bridge->redirecting = tmp; 00601 } 00602 if (p->owner->dialed.number.str || p->owner->dialed.subaddress.valid) { 00603 struct ast_party_dialed tmp; 00604 00605 tmp = p->owner->dialed; 00606 p->owner->dialed = p->chan->_bridge->dialed; 00607 p->chan->_bridge->dialed = tmp; 00608 } 00609 ast_app_group_update(p->chan, p->owner); 00610 ast_set_flag(p, LOCAL_ALREADY_MASQED); 00611 00612 ast_channel_unlock(p->owner); 00613 ast_channel_unlock(p->chan->_bridge); 00614 00615 /* Do the masquerade now. */ 00616 owner = ast_channel_ref(p->owner); 00617 ao2_unlock(p); 00618 ast_channel_unlock(ast); 00619 ast_do_masquerade(owner); 00620 ast_channel_unref(owner); 00621 ast_channel_lock(ast); 00622 ao2_lock(p); 00623 }
static int load_module | ( | void | ) | [static] |
Load module into PBX, register channel.
Definition at line 1338 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().
01339 { 01340 if (!(locals = ao2_container_alloc(BUCKET_SIZE, NULL, locals_cmp_cb))) { 01341 return AST_MODULE_LOAD_FAILURE; 01342 } 01343 01344 /* Make sure we can register our channel type */ 01345 if (ast_channel_register(&local_tech)) { 01346 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n"); 01347 ao2_ref(locals, -1); 01348 return AST_MODULE_LOAD_FAILURE; 01349 } 01350 ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 01351 ast_manager_register_xml("LocalOptimizeAway", EVENT_FLAG_SYSTEM|EVENT_FLAG_CALL, manager_optimize_away); 01352 01353 return AST_MODULE_LOAD_SUCCESS; 01354 }
Create a call structure.
Definition at line 1089 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().
01090 { 01091 struct local_pvt *tmp = NULL; 01092 char *c = NULL, *opts = NULL; 01093 01094 if (!(tmp = ao2_alloc(sizeof(*tmp), NULL))) { 01095 return NULL; 01096 } 01097 01098 /* Initialize private structure information */ 01099 ast_copy_string(tmp->exten, data, sizeof(tmp->exten)); 01100 01101 memcpy(&tmp->jb_conf, &g_jb_conf, sizeof(tmp->jb_conf)); 01102 01103 /* Look for options */ 01104 if ((opts = strchr(tmp->exten, '/'))) { 01105 *opts++ = '\0'; 01106 if (strchr(opts, 'n')) 01107 ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION); 01108 if (strchr(opts, 'j')) { 01109 if (ast_test_flag(tmp, LOCAL_NO_OPTIMIZATION)) 01110 ast_set_flag(&tmp->jb_conf, AST_JB_ENABLED); 01111 else { 01112 ast_log(LOG_ERROR, "You must use the 'n' option for chan_local " 01113 "to use the 'j' option to enable the jitterbuffer\n"); 01114 } 01115 } 01116 if (strchr(opts, 'b')) { 01117 ast_set_flag(tmp, LOCAL_BRIDGE); 01118 } 01119 if (strchr(opts, 'm')) { 01120 ast_set_flag(tmp, LOCAL_MOH_PASSTHRU); 01121 } 01122 } 01123 01124 /* Look for a context */ 01125 if ((c = strchr(tmp->exten, '@'))) 01126 *c++ = '\0'; 01127 01128 ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context)); 01129 01130 tmp->reqformat = format; 01131 01132 #if 0 01133 /* We can't do this check here, because we don't know the CallerID yet, and 01134 * the CallerID could potentially affect what step is actually taken (or 01135 * even if that step exists). */ 01136 if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) { 01137 ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context); 01138 tmp = local_pvt_destroy(tmp); 01139 } else { 01140 #endif 01141 /* Add to list */ 01142 ao2_link(locals, tmp); 01143 #if 0 01144 } 01145 #endif 01146 return tmp; /* this is returned with a ref */ 01147 }
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 858 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.
00859 { 00860 struct local_pvt *p = ast->tech_pvt; 00861 int pvt_locked = 0; 00862 00863 struct ast_channel *owner = NULL; 00864 struct ast_channel *chan = NULL; 00865 int res; 00866 struct ast_var_t *varptr = NULL, *new; 00867 size_t len, namelen; 00868 char *reduced_dest = ast_strdupa(dest); 00869 char *slash; 00870 const char *exten; 00871 const char *context; 00872 00873 if (!p) { 00874 return -1; 00875 } 00876 00877 /* since we are letting go of channel locks that were locked coming into 00878 * this function, then we need to give the tech pvt a ref */ 00879 ao2_ref(p, 1); 00880 ast_channel_unlock(ast); 00881 00882 awesome_locking(p, &chan, &owner); 00883 pvt_locked = 1; 00884 00885 if (owner != ast) { 00886 res = -1; 00887 goto return_cleanup; 00888 } 00889 00890 if (!owner || !chan) { 00891 res = -1; 00892 goto return_cleanup; 00893 } 00894 00895 /* 00896 * Note that cid_num and cid_name aren't passed in the ast_channel_alloc 00897 * call, so it's done here instead. 00898 * 00899 * All these failure points just return -1. The individual strings will 00900 * be cleared when we destroy the channel. 00901 */ 00902 ast_party_redirecting_copy(&chan->redirecting, &owner->redirecting); 00903 00904 ast_party_dialed_copy(&chan->dialed, &owner->dialed); 00905 00906 ast_connected_line_copy_to_caller(&chan->caller, &owner->connected); 00907 ast_connected_line_copy_from_caller(&chan->connected, &owner->caller); 00908 00909 ast_string_field_set(chan, language, owner->language); 00910 ast_string_field_set(chan, accountcode, owner->accountcode); 00911 ast_string_field_set(chan, musicclass, owner->musicclass); 00912 ast_cdr_update(chan); 00913 00914 ast_channel_cc_params_init(chan, ast_channel_get_cc_config_params(owner)); 00915 00916 /* Make sure we inherit the ANSWERED_ELSEWHERE flag if it's set on the queue/dial call request in the dialplan */ 00917 if (ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) { 00918 ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE); 00919 } 00920 00921 /* copy the channel variables from the incoming channel to the outgoing channel */ 00922 /* Note that due to certain assumptions, they MUST be in the same order */ 00923 AST_LIST_TRAVERSE(&owner->varshead, varptr, entries) { 00924 namelen = strlen(varptr->name); 00925 len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2; 00926 if ((new = ast_calloc(1, len))) { 00927 memcpy(new, varptr, len); 00928 new->value = &(new->name[0]) + namelen + 1; 00929 AST_LIST_INSERT_TAIL(&chan->varshead, new, entries); 00930 } 00931 } 00932 ast_channel_datastore_inherit(owner, chan); 00933 /* If the local channel has /n or /b on the end of it, 00934 * we need to lop that off for our argument to setting 00935 * up the CC_INTERFACES variable 00936 */ 00937 if ((slash = strrchr(reduced_dest, '/'))) { 00938 *slash = '\0'; 00939 } 00940 ast_set_cc_interfaces_chanvar(chan, reduced_dest); 00941 00942 exten = ast_strdupa(chan->exten); 00943 context = ast_strdupa(chan->context); 00944 00945 ao2_unlock(p); 00946 pvt_locked = 0; 00947 00948 ast_channel_unlock(chan); 00949 00950 if (!ast_exists_extension(chan, context, exten, 1, 00951 S_COR(owner->caller.id.number.valid, owner->caller.id.number.str, NULL))) { 00952 ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", exten, context); 00953 res = -1; 00954 chan = ast_channel_unref(chan); /* we already unlocked it, so clear it hear so the cleanup label won't touch it. */ 00955 goto return_cleanup; 00956 } 00957 00958 /* Start switch on sub channel */ 00959 if (!(res = ast_pbx_start(chan))) { 00960 ao2_lock(p); 00961 ast_set_flag(p, LOCAL_LAUNCHED_PBX); 00962 ao2_unlock(p); 00963 } 00964 chan = ast_channel_unref(chan); /* chan is already unlocked, clear it here so the cleanup lable won't touch it. */ 00965 00966 return_cleanup: 00967 if (p) { 00968 if (pvt_locked) { 00969 ao2_unlock(p); 00970 } 00971 ao2_ref(p, -1); 00972 } 00973 if (chan) { 00974 ast_channel_unlock(chan); 00975 chan = ast_channel_unref(chan); 00976 } 00977 00978 /* owner is supposed to be == to ast, if it 00979 * is, don't unlock it because ast must exit locked */ 00980 if (owner) { 00981 if (owner != ast) { 00982 ast_channel_unlock(owner); 00983 ast_channel_lock(ast); 00984 } 00985 owner = ast_channel_unref(owner); 00986 } else { 00987 /* we have to exit with ast locked */ 00988 ast_channel_lock(ast); 00989 } 00990 00991 return res; 00992 }
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 769 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.
00770 { 00771 struct local_pvt *p = ast->tech_pvt; 00772 int res = -1; 00773 struct ast_frame f = { AST_FRAME_DTMF_BEGIN, }; 00774 int isoutbound; 00775 00776 if (!p) 00777 return -1; 00778 00779 ao2_ref(p, 1); /* ref for local_queue_frame */ 00780 ao2_lock(p); 00781 isoutbound = IS_OUTBOUND(ast, p); 00782 f.subclass.integer = digit; 00783 res = local_queue_frame(p, isoutbound, &f, ast, 0); 00784 ao2_unlock(p); 00785 ao2_ref(p, -1); 00786 00787 return res; 00788 }
static int local_digit_end | ( | struct ast_channel * | ast, | |
char | digit, | |||
unsigned int | duration | |||
) | [static] |
Definition at line 790 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.
00791 { 00792 struct local_pvt *p = ast->tech_pvt; 00793 int res = -1; 00794 struct ast_frame f = { AST_FRAME_DTMF_END, }; 00795 int isoutbound; 00796 00797 if (!p) 00798 return -1; 00799 00800 ao2_ref(p, 1); /* ref for local_queue_frame */ 00801 ao2_lock(p); 00802 isoutbound = IS_OUTBOUND(ast, p); 00803 f.subclass.integer = digit; 00804 f.len = duration; 00805 res = local_queue_frame(p, isoutbound, &f, ast, 0); 00806 ao2_unlock(p); 00807 ao2_ref(p, -1); 00808 00809 return res; 00810 }
static int local_fixup | ( | struct ast_channel * | oldchan, | |
struct ast_channel * | newchan | |||
) | [static] |
Definition at line 663 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.
00664 { 00665 struct local_pvt *p = newchan->tech_pvt; 00666 00667 if (!p) 00668 return -1; 00669 00670 ao2_lock(p); 00671 00672 if ((p->owner != oldchan) && (p->chan != oldchan)) { 00673 ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan); 00674 ao2_unlock(p); 00675 return -1; 00676 } 00677 if (p->owner == oldchan) 00678 p->owner = newchan; 00679 else 00680 p->chan = newchan; 00681 00682 /* Do not let a masquerade cause a Local channel to be bridged to itself! */ 00683 if (!ast_check_hangup(newchan) && ((p->owner && p->owner->_bridge == p->chan) || (p->chan && p->chan->_bridge == p->owner))) { 00684 ast_log(LOG_WARNING, "You can not bridge a Local channel to itself!\n"); 00685 ao2_unlock(p); 00686 ast_queue_hangup(newchan); 00687 return -1; 00688 } 00689 00690 ao2_unlock(p); 00691 return 0; 00692 }
static int local_hangup | ( | struct ast_channel * | ast | ) | [static] |
Hangup a call through the local proxy channel.
Definition at line 995 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.
00996 { 00997 struct local_pvt *p = ast->tech_pvt; 00998 int isoutbound; 00999 int hangup_chan = 0; 01000 int res = 0; 01001 struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_HANGUP }, .data.uint32 = ast->hangupcause }; 01002 struct ast_channel *owner = NULL; 01003 struct ast_channel *chan = NULL; 01004 01005 if (!p) { 01006 return -1; 01007 } 01008 01009 /* give the pvt a ref since we are unlocking the channel. */ 01010 ao2_ref(p, 1); 01011 01012 /* the pvt isn't going anywhere, we gave it a ref */ 01013 ast_channel_unlock(ast); 01014 01015 /* lock everything */ 01016 awesome_locking(p, &chan, &owner); 01017 01018 if (ast != chan && ast != owner) { 01019 res = -1; 01020 goto local_hangup_cleanup; 01021 } 01022 01023 isoutbound = IS_OUTBOUND(ast, p); /* just comparing pointer of ast */ 01024 01025 if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) { 01026 ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE); 01027 ast_debug(2, "This local call has the ANSWERED_ELSEWHERE flag set.\n"); 01028 } 01029 01030 if (isoutbound) { 01031 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS"); 01032 if ((status) && (p->owner)) { 01033 p->owner->hangupcause = p->chan->hangupcause; 01034 pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status); 01035 } 01036 01037 ast_clear_flag(p, LOCAL_LAUNCHED_PBX); 01038 ast_module_user_remove(p->u_chan); 01039 p->chan = NULL; 01040 } else { 01041 ast_module_user_remove(p->u_owner); 01042 if (p->chan) { 01043 ast_queue_hangup(p->chan); 01044 } 01045 p->owner = NULL; 01046 } 01047 01048 ast->tech_pvt = NULL; /* this is one of our locked channels, doesn't matter which */ 01049 01050 if (!p->owner && !p->chan) { 01051 ao2_unlock(p); 01052 /* Remove from list */ 01053 ao2_unlink(locals, p); 01054 ao2_ref(p, -1); 01055 p = NULL; 01056 res = 0; 01057 goto local_hangup_cleanup; 01058 } 01059 if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) { 01060 /* Need to actually hangup since there is no PBX */ 01061 hangup_chan = 1; 01062 } else { 01063 local_queue_frame(p, isoutbound, &f, NULL, 0); 01064 } 01065 01066 local_hangup_cleanup: 01067 if (p) { 01068 ao2_unlock(p); 01069 ao2_ref(p, -1); 01070 } 01071 if (chan) { 01072 ast_channel_unlock(chan); 01073 if (hangup_chan) { 01074 ast_hangup(chan); 01075 } 01076 chan = ast_channel_unref(chan); 01077 } 01078 if (owner) { 01079 ast_channel_unlock(owner); 01080 owner = ast_channel_unref(owner); 01081 } 01082 01083 /* leave with the same stupid channel locked that came in */ 01084 ast_channel_lock(ast); 01085 return res; 01086 }
static int local_indicate | ( | struct ast_channel * | ast, | |
int | condition, | |||
const void * | data, | |||
size_t | datalen | |||
) | [static] |
Definition at line 694 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_debug, 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_NO_OPTIMIZATION, local_queue_frame(), local_pvt::owner, ast_channel::redirecting, and ast_channel::tech_pvt.
00695 { 00696 struct local_pvt *p = ast->tech_pvt; 00697 int res = 0; 00698 struct ast_frame f = { AST_FRAME_CONTROL, }; 00699 int isoutbound; 00700 00701 if (!p) 00702 return -1; 00703 00704 ao2_ref(p, 1); /* ref for local_queue_frame */ 00705 00706 /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */ 00707 if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) { 00708 ast_moh_start(ast, data, NULL); 00709 } else if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_UNHOLD) { 00710 ast_moh_stop(ast); 00711 } else if (condition == AST_CONTROL_CONNECTED_LINE || condition == AST_CONTROL_REDIRECTING) { 00712 struct ast_channel *this_channel; 00713 struct ast_channel *the_other_channel; 00714 /* A connected line update frame may only contain a partial amount of data, such 00715 * as just a source, or just a ton, and not the full amount of information. However, 00716 * the collected information is all stored in the outgoing channel's connectedline 00717 * structure, so when receiving a connected line update on an outgoing local channel, 00718 * we need to transmit the collected connected line information instead of whatever 00719 * happens to be in this control frame. The same applies for redirecting information, which 00720 * is why it is handled here as well.*/ 00721 ao2_lock(p); 00722 isoutbound = IS_OUTBOUND(ast, p); 00723 if (isoutbound) { 00724 this_channel = p->chan; 00725 the_other_channel = p->owner; 00726 } else { 00727 this_channel = p->owner; 00728 the_other_channel = p->chan; 00729 } 00730 if (the_other_channel) { 00731 unsigned char frame_data[1024]; 00732 if (condition == AST_CONTROL_CONNECTED_LINE) { 00733 if (isoutbound) { 00734 ast_connected_line_copy_to_caller(&the_other_channel->caller, &this_channel->connected); 00735 } 00736 f.datalen = ast_connected_line_build_data(frame_data, sizeof(frame_data), &this_channel->connected, NULL); 00737 } else { 00738 f.datalen = ast_redirecting_build_data(frame_data, sizeof(frame_data), &this_channel->redirecting, NULL); 00739 } 00740 f.subclass.integer = condition; 00741 f.data.ptr = frame_data; 00742 res = local_queue_frame(p, isoutbound, &f, ast, 1); 00743 } 00744 ao2_unlock(p); 00745 } else { 00746 /* Queue up a frame representing the indication as a control frame */ 00747 ao2_lock(p); 00748 /* 00749 * Block -1 stop tones events if we are to be optimized out. We 00750 * don't need a flurry of these events on a local channel chain 00751 * when initially connected to slow the optimization process. 00752 */ 00753 if (0 <= condition || ast_test_flag(p, LOCAL_NO_OPTIMIZATION)) { 00754 isoutbound = IS_OUTBOUND(ast, p); 00755 f.subclass.integer = condition; 00756 f.data.ptr = (void *) data; 00757 f.datalen = datalen; 00758 res = local_queue_frame(p, isoutbound, &f, ast, 1); 00759 } else { 00760 ast_debug(4, "Blocked indication %d\n", condition); 00761 } 00762 ao2_unlock(p); 00763 } 00764 00765 ao2_ref(p, -1); 00766 return res; 00767 }
static struct ast_channel* local_new | ( | struct local_pvt * | p, | |
int | state, | |||
const char * | linkedid | |||
) | [static] |
Start new local channel.
Definition at line 1150 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, ast_channel::linkedid, 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().
01151 { 01152 struct ast_channel *tmp = NULL, *tmp2 = NULL; 01153 int randnum = ast_random() & 0xffff, fmt = 0; 01154 const char *t; 01155 int ama; 01156 01157 /* Allocate two new Asterisk channels */ 01158 /* safe accountcode */ 01159 if (p->owner && p->owner->accountcode) 01160 t = p->owner->accountcode; 01161 else 01162 t = ""; 01163 01164 if (p->owner) 01165 ama = p->owner->amaflags; 01166 else 01167 ama = 0; 01168 01169 /* Make sure that the ;2 channel gets the same linkedid as ;1. You can't pass linkedid to both 01170 * allocations since if linkedid isn't set, then each channel will generate its own linkedid. */ 01171 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)) 01172 || !(tmp2 = ast_channel_alloc(1, AST_STATE_RING, 0, 0, t, p->exten, p->context, tmp->linkedid, ama, "Local/%s@%s-%04x;2", p->exten, p->context, randnum))) { 01173 if (tmp) { 01174 tmp = ast_channel_release(tmp); 01175 } 01176 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n"); 01177 return NULL; 01178 } 01179 01180 tmp2->tech = tmp->tech = &local_tech; 01181 01182 tmp->nativeformats = p->reqformat; 01183 tmp2->nativeformats = p->reqformat; 01184 01185 /* Determine our read/write format and set it on each channel */ 01186 fmt = ast_best_codec(p->reqformat); 01187 tmp->writeformat = fmt; 01188 tmp2->writeformat = fmt; 01189 tmp->rawwriteformat = fmt; 01190 tmp2->rawwriteformat = fmt; 01191 tmp->readformat = fmt; 01192 tmp2->readformat = fmt; 01193 tmp->rawreadformat = fmt; 01194 tmp2->rawreadformat = fmt; 01195 01196 tmp->tech_pvt = p; 01197 tmp2->tech_pvt = p; 01198 01199 p->owner = tmp; 01200 p->chan = tmp2; 01201 p->u_owner = ast_module_user_add(p->owner); 01202 p->u_chan = ast_module_user_add(p->chan); 01203 01204 ast_copy_string(tmp->context, p->context, sizeof(tmp->context)); 01205 ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context)); 01206 ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten)); 01207 tmp->priority = 1; 01208 tmp2->priority = 1; 01209 01210 ast_jb_configure(tmp, &p->jb_conf); 01211 01212 return tmp; 01213 }
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 625 of file chan_local.c.
References ast_null_frame.
00626 { 00627 return &ast_null_frame; 00628 }
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 1216 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_module_user_remove, AST_STATE_DOWN, local_pvt::chan, ast_channel::linkedid, local_alloc(), local_new(), locals, local_pvt::owner, local_pvt::u_chan, and local_pvt::u_owner.
01217 { 01218 struct local_pvt *p; 01219 struct ast_channel *chan; 01220 01221 /* Allocate a new private structure and then Asterisk channels */ 01222 p = local_alloc(data, format); 01223 if (!p) { 01224 return NULL; 01225 } 01226 chan = local_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL); 01227 if (!chan) { 01228 ao2_unlink(locals, p); 01229 } else if (ast_channel_cc_params_init(chan, requestor ? ast_channel_get_cc_config_params((struct ast_channel *)requestor) : NULL)) { 01230 ao2_unlink(locals, p); 01231 p->owner = ast_channel_release(p->owner); 01232 ast_module_user_remove(p->u_owner); 01233 p->chan = ast_channel_release(p->chan); 01234 ast_module_user_remove(p->u_chan); 01235 chan = NULL; 01236 } 01237 ao2_ref(p, -1); /* kill the ref from the alloc */ 01238 01239 return chan; 01240 }
static int local_sendhtml | ( | struct ast_channel * | ast, | |
int | subclass, | |||
const char * | data, | |||
int | datalen | |||
) | [static] |
Definition at line 833 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.
00834 { 00835 struct local_pvt *p = ast->tech_pvt; 00836 int res = -1; 00837 struct ast_frame f = { AST_FRAME_HTML, }; 00838 int isoutbound; 00839 00840 if (!p) 00841 return -1; 00842 00843 ao2_lock(p); 00844 ao2_ref(p, 1); /* ref for local_queue_frame */ 00845 isoutbound = IS_OUTBOUND(ast, p); 00846 f.subclass.integer = subclass; 00847 f.data.ptr = (char *)data; 00848 f.datalen = datalen; 00849 res = local_queue_frame(p, isoutbound, &f, ast, 0); 00850 ao2_unlock(p); 00851 ao2_ref(p, -1); 00852 00853 return res; 00854 }
static int local_sendtext | ( | struct ast_channel * | ast, | |
const char * | text | |||
) | [static] |
Definition at line 812 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.
00813 { 00814 struct local_pvt *p = ast->tech_pvt; 00815 int res = -1; 00816 struct ast_frame f = { AST_FRAME_TEXT, }; 00817 int isoutbound; 00818 00819 if (!p) 00820 return -1; 00821 00822 ao2_lock(p); 00823 ao2_ref(p, 1); /* ref for local_queue_frame */ 00824 isoutbound = IS_OUTBOUND(ast, p); 00825 f.data.ptr = (char *) text; 00826 f.datalen = strlen(text) + 1; 00827 res = local_queue_frame(p, isoutbound, &f, ast, 0); 00828 ao2_unlock(p); 00829 ao2_ref(p, -1); 00830 return res; 00831 }
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 630 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.
00631 { 00632 struct local_pvt *p = ast->tech_pvt; 00633 int res = -1; 00634 int isoutbound; 00635 00636 if (!p) { 00637 return -1; 00638 } 00639 00640 /* Just queue for delivery to the other side */ 00641 ao2_ref(p, 1); /* ref for local_queue_frame */ 00642 ao2_lock(p); 00643 isoutbound = IS_OUTBOUND(ast, p); 00644 00645 if (isoutbound 00646 && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) { 00647 check_bridge(ast, p); 00648 } 00649 00650 if (!ast_test_flag(p, LOCAL_ALREADY_MASQED)) { 00651 res = local_queue_frame(p, isoutbound, f, ast, 1); 00652 } else { 00653 ast_debug(1, "Not posting to '%s' queue since already masqueraded out\n", 00654 ast->name); 00655 res = 0; 00656 } 00657 ao2_unlock(p); 00658 ao2_ref(p, -1); 00659 00660 return res; 00661 }
static int locals_cmp_cb | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 1332 of file chan_local.c.
References CMP_MATCH.
Referenced by load_module().
01333 { 01334 return (obj == arg) ? CMP_MATCH : 0; 01335 }
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 1243 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.
01244 { 01245 struct local_pvt *p = NULL; 01246 struct ao2_iterator it; 01247 01248 switch (cmd) { 01249 case CLI_INIT: 01250 e->command = "local show channels"; 01251 e->usage = 01252 "Usage: local show channels\n" 01253 " Provides summary information on active local proxy channels.\n"; 01254 return NULL; 01255 case CLI_GENERATE: 01256 return NULL; 01257 } 01258 01259 if (a->argc != 3) 01260 return CLI_SHOWUSAGE; 01261 01262 if (ao2_container_count(locals) == 0) { 01263 ast_cli(a->fd, "No local channels in use\n"); 01264 return RESULT_SUCCESS; 01265 } 01266 01267 it = ao2_iterator_init(locals, 0); 01268 while ((p = ao2_iterator_next(&it))) { 01269 ao2_lock(p); 01270 ast_cli(a->fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context); 01271 ao2_unlock(p); 01272 ao2_ref(p, -1); 01273 } 01274 ao2_iterator_destroy(&it); 01275 01276 return CLI_SUCCESS; 01277 }
static int manager_optimize_away | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 1283 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().
01284 { 01285 const char *channel; 01286 struct local_pvt *p, *tmp = NULL; 01287 struct ast_channel *c; 01288 int found = 0; 01289 struct ao2_iterator it; 01290 01291 channel = astman_get_header(m, "Channel"); 01292 01293 if (ast_strlen_zero(channel)) { 01294 astman_send_error(s, m, "'Channel' not specified."); 01295 return 0; 01296 } 01297 01298 c = ast_channel_get_by_name(channel); 01299 if (!c) { 01300 astman_send_error(s, m, "Channel does not exist."); 01301 return 0; 01302 } 01303 01304 p = c->tech_pvt; 01305 ast_channel_unref(c); 01306 c = NULL; 01307 01308 it = ao2_iterator_init(locals, 0); 01309 while ((tmp = ao2_iterator_next(&it))) { 01310 if (tmp == p) { 01311 ao2_lock(tmp); 01312 found = 1; 01313 ast_clear_flag(tmp, LOCAL_NO_OPTIMIZATION); 01314 ao2_unlock(tmp); 01315 ao2_ref(tmp, -1); 01316 break; 01317 } 01318 ao2_ref(tmp, -1); 01319 } 01320 ao2_iterator_destroy(&it); 01321 01322 if (found) { 01323 astman_send_ack(s, m, "Queued channel to be optimized away"); 01324 } else { 01325 astman_send_error(s, m, "Unable to find channel"); 01326 } 01327 01328 return 0; 01329 }
static int unload_module | ( | void | ) | [static] |
Unload the local proxy channel from Asterisk.
Definition at line 1357 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.
01358 { 01359 struct local_pvt *p = NULL; 01360 struct ao2_iterator it; 01361 01362 /* First, take us out of the channel loop */ 01363 ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 01364 ast_manager_unregister("LocalOptimizeAway"); 01365 ast_channel_unregister(&local_tech); 01366 01367 it = ao2_iterator_init(locals, 0); 01368 while ((p = ao2_iterator_next(&it))) { 01369 if (p->owner) { 01370 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); 01371 } 01372 ao2_ref(p, -1); 01373 } 01374 ao2_iterator_destroy(&it); 01375 ao2_ref(locals, -1); 01376 01377 return 0; 01378 }
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 = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DRIVER, } [static] |
Definition at line 1384 of file chan_local.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1384 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 1279 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.