Local Proxy Channel. More...
#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 | |
AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER,"Local Proxy Channel (Note: used internally by other modules)",.load=load_module,.unload=unload_module,.load_pri=AST_MODPRI_CHANNEL_DRIVER,) | |
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 void | local_pvt_destructor (void *vdoomed) |
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 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 unsigned int | name_sequence = 0 |
static const char | tdesc [] = "Local Proxy Channel Driver" |
Local Proxy Channel.
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(), local_devicestate(), 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().
AST_MODULE_INFO | ( | ASTERISK_GPL_KEY | , | |
AST_MODFLAG_LOAD_ORDER | , | |||
"Local Proxy Channel (Note: used internally by other modules)" | , | |||
. | load = load_module , |
|||
. | unload = unload_module , |
|||
. | load_pri = AST_MODPRI_CHANNEL_DRIVER | |||
) |
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, 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().
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 486 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_frame::frametype, 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::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().
00487 { 00488 struct ast_channel *owner; 00489 struct ast_channel *chan; 00490 struct ast_channel *bridged_chan; 00491 struct ast_frame *f; 00492 00493 /* Do a few conditional checks early on just to see if this optimization is possible */ 00494 if (ast_test_flag(p, LOCAL_NO_OPTIMIZATION | LOCAL_ALREADY_MASQED) 00495 || !p->chan || !p->owner) { 00496 return; 00497 } 00498 00499 /* Safely get the channel bridged to p->chan */ 00500 chan = ast_channel_ref(p->chan); 00501 00502 ao2_unlock(p); /* don't call bridged channel with the pvt locked */ 00503 bridged_chan = ast_bridged_channel(chan); 00504 ao2_lock(p); 00505 00506 chan = ast_channel_unref(chan); 00507 00508 /* since we had to unlock p to get the bridged chan, validate our 00509 * data once again and verify the bridged channel is what we expect 00510 * it to be in order to perform this optimization */ 00511 if (ast_test_flag(p, LOCAL_NO_OPTIMIZATION | LOCAL_ALREADY_MASQED) 00512 || !p->chan || !p->owner 00513 || (p->chan->_bridge != bridged_chan)) { 00514 return; 00515 } 00516 00517 /* only do the masquerade if we are being called on the outbound channel, 00518 if it has been bridged to another channel and if there are no pending 00519 frames on the owner channel (because they would be transferred to the 00520 outbound channel during the masquerade) 00521 */ 00522 if (!p->chan->_bridge /* Not ast_bridged_channel! Only go one step! */ 00523 || !AST_LIST_EMPTY(&p->owner->readq) 00524 || ast != p->chan /* Sanity check (should always be false) */) { 00525 return; 00526 } 00527 00528 /* Masquerade bridged channel into owner */ 00529 /* Lock everything we need, one by one, and give up if 00530 we can't get everything. Remember, we'll get another 00531 chance in just a little bit */ 00532 if (ast_channel_trylock(p->chan->_bridge)) { 00533 return; 00534 } 00535 if (ast_check_hangup(p->chan->_bridge) || ast_channel_trylock(p->owner)) { 00536 ast_channel_unlock(p->chan->_bridge); 00537 return; 00538 } 00539 00540 /* 00541 * At this point we have 4 locks: 00542 * p, p->chan (same as ast), p->chan->_bridge, p->owner 00543 * 00544 * Flush a voice or video frame on the outbound channel to make 00545 * the queue empty faster so we can get optimized out. 00546 */ 00547 f = AST_LIST_FIRST(&p->chan->readq); 00548 if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) { 00549 AST_LIST_REMOVE_HEAD(&p->chan->readq, frame_list); 00550 ast_frfree(f); 00551 f = AST_LIST_FIRST(&p->chan->readq); 00552 } 00553 00554 if (f 00555 || ast_check_hangup(p->owner) 00556 || ast_channel_masquerade(p->owner, p->chan->_bridge)) { 00557 ast_channel_unlock(p->owner); 00558 ast_channel_unlock(p->chan->_bridge); 00559 return; 00560 } 00561 00562 /* Masquerade got setup. */ 00563 ast_debug(4, "Masquerading %s <- %s\n", 00564 p->owner->name, p->chan->_bridge->name); 00565 if (p->owner->monitor && !p->chan->_bridge->monitor) { 00566 struct ast_channel_monitor *tmp; 00567 00568 /* If a local channel is being monitored, we don't want a masquerade 00569 * to cause the monitor to go away. Since the masquerade swaps the monitors, 00570 * pre-swapping the monitors before the masquerade will ensure that the monitor 00571 * ends up where it is expected. 00572 */ 00573 tmp = p->owner->monitor; 00574 p->owner->monitor = p->chan->_bridge->monitor; 00575 p->chan->_bridge->monitor = tmp; 00576 } 00577 if (p->chan->audiohooks) { 00578 struct ast_audiohook_list *audiohooks_swapper; 00579 00580 audiohooks_swapper = p->chan->audiohooks; 00581 p->chan->audiohooks = p->owner->audiohooks; 00582 p->owner->audiohooks = audiohooks_swapper; 00583 } 00584 00585 /* If any Caller ID was set, preserve it after masquerade like above. We must check 00586 * to see if Caller ID was set because otherwise we'll mistakingly copy info not 00587 * set from the dialplan and will overwrite the real channel Caller ID. The reason 00588 * for this whole preswapping action is because the Caller ID is set on the channel 00589 * thread (which is the to be masqueraded away local channel) before both local 00590 * channels are optimized away. 00591 */ 00592 if (p->owner->caller.id.name.valid || p->owner->caller.id.number.valid 00593 || p->owner->caller.id.subaddress.valid || p->owner->caller.ani.name.valid 00594 || p->owner->caller.ani.number.valid || p->owner->caller.ani.subaddress.valid) { 00595 struct ast_party_caller tmp; 00596 00597 tmp = p->owner->caller; 00598 p->owner->caller = p->chan->_bridge->caller; 00599 p->chan->_bridge->caller = tmp; 00600 } 00601 if (p->owner->redirecting.from.name.valid || p->owner->redirecting.from.number.valid 00602 || p->owner->redirecting.from.subaddress.valid || p->owner->redirecting.to.name.valid 00603 || p->owner->redirecting.to.number.valid || p->owner->redirecting.to.subaddress.valid) { 00604 struct ast_party_redirecting tmp; 00605 00606 tmp = p->owner->redirecting; 00607 p->owner->redirecting = p->chan->_bridge->redirecting; 00608 p->chan->_bridge->redirecting = tmp; 00609 } 00610 if (p->owner->dialed.number.str || p->owner->dialed.subaddress.valid) { 00611 struct ast_party_dialed tmp; 00612 00613 tmp = p->owner->dialed; 00614 p->owner->dialed = p->chan->_bridge->dialed; 00615 p->chan->_bridge->dialed = tmp; 00616 } 00617 ast_app_group_update(p->chan, p->owner); 00618 ast_set_flag(p, LOCAL_ALREADY_MASQED); 00619 00620 ast_channel_unlock(p->owner); 00621 ast_channel_unlock(p->chan->_bridge); 00622 00623 /* Do the masquerade now. */ 00624 owner = ast_channel_ref(p->owner); 00625 ao2_unlock(p); 00626 ast_channel_unlock(ast); 00627 ast_do_masquerade(owner); 00628 ast_channel_unref(owner); 00629 ast_channel_lock(ast); 00630 ao2_lock(p); 00631 }
static int load_module | ( | void | ) | [static] |
Load module into PBX, register channel.
Definition at line 1370 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, EVENT_FLAG_CALL, EVENT_FLAG_SYSTEM, locals_cmp_cb(), LOG_ERROR, and manager_optimize_away().
01371 { 01372 if (!(locals = ao2_container_alloc(BUCKET_SIZE, NULL, locals_cmp_cb))) { 01373 return AST_MODULE_LOAD_FAILURE; 01374 } 01375 01376 /* Make sure we can register our channel type */ 01377 if (ast_channel_register(&local_tech)) { 01378 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n"); 01379 ao2_ref(locals, -1); 01380 return AST_MODULE_LOAD_FAILURE; 01381 } 01382 ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 01383 ast_manager_register_xml("LocalOptimizeAway", EVENT_FLAG_SYSTEM|EVENT_FLAG_CALL, manager_optimize_away); 01384 01385 return AST_MODULE_LOAD_SUCCESS; 01386 }
Create a call structure.
Definition at line 1119 of file chan_local.c.
References ao2_alloc, ao2_link, ast_copy_string(), ast_exists_extension(), AST_JB_ENABLED, ast_log(), ast_module_ref(), ast_set_flag, ast_test_flag, local_pvt::context, local_pvt::exten, local_pvt::jb_conf, LOCAL_BRIDGE, LOCAL_MOH_PASSTHRU, LOCAL_NO_OPTIMIZATION, local_pvt_destructor(), LOG_ERROR, LOG_NOTICE, and local_pvt::reqformat.
Referenced by local_request().
01120 { 01121 struct local_pvt *tmp = NULL; 01122 char *c = NULL, *opts = NULL; 01123 01124 if (!(tmp = ao2_alloc(sizeof(*tmp), local_pvt_destructor))) { 01125 return NULL; 01126 } 01127 01128 ast_module_ref(ast_module_info->self); 01129 01130 /* Initialize private structure information */ 01131 ast_copy_string(tmp->exten, data, sizeof(tmp->exten)); 01132 01133 memcpy(&tmp->jb_conf, &g_jb_conf, sizeof(tmp->jb_conf)); 01134 01135 /* Look for options */ 01136 if ((opts = strchr(tmp->exten, '/'))) { 01137 *opts++ = '\0'; 01138 if (strchr(opts, 'n')) 01139 ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION); 01140 if (strchr(opts, 'j')) { 01141 if (ast_test_flag(tmp, LOCAL_NO_OPTIMIZATION)) 01142 ast_set_flag(&tmp->jb_conf, AST_JB_ENABLED); 01143 else { 01144 ast_log(LOG_ERROR, "You must use the 'n' option for chan_local " 01145 "to use the 'j' option to enable the jitterbuffer\n"); 01146 } 01147 } 01148 if (strchr(opts, 'b')) { 01149 ast_set_flag(tmp, LOCAL_BRIDGE); 01150 } 01151 if (strchr(opts, 'm')) { 01152 ast_set_flag(tmp, LOCAL_MOH_PASSTHRU); 01153 } 01154 } 01155 01156 /* Look for a context */ 01157 if ((c = strchr(tmp->exten, '@'))) 01158 *c++ = '\0'; 01159 01160 ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context)); 01161 01162 tmp->reqformat = format; 01163 01164 #if 0 01165 /* We can't do this check here, because we don't know the CallerID yet, and 01166 * the CallerID could potentially affect what step is actually taken (or 01167 * even if that step exists). */ 01168 if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) { 01169 ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context); 01170 tmp = local_pvt_destroy(tmp); 01171 } else { 01172 #endif 01173 /* Add to list */ 01174 ao2_link(locals, tmp); 01175 #if 0 01176 } 01177 #endif 01178 return tmp; /* this is returned with a ref */ 01179 }
static int local_answer | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 456 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.
00457 { 00458 struct local_pvt *p = ast->tech_pvt; 00459 int isoutbound; 00460 int res = -1; 00461 00462 if (!p) 00463 return -1; 00464 00465 ao2_lock(p); 00466 ao2_ref(p, 1); 00467 isoutbound = IS_OUTBOUND(ast, p); 00468 if (isoutbound) { 00469 /* Pass along answer since somebody answered us */ 00470 struct ast_frame answer = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } }; 00471 res = local_queue_frame(p, isoutbound, &answer, ast, 1); 00472 } else { 00473 ast_log(LOG_WARNING, "Huh? Local is being asked to answer?\n"); 00474 } 00475 ao2_unlock(p); 00476 ao2_ref(p, -1); 00477 return res; 00478 }
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 330 of file chan_local.c.
References ast_channel::_bridge, ao2_lock, ao2_unlock, ast_debug, ast_test_flag, local_pvt::chan, LOCAL_BRIDGE, local_pvt::owner, and ast_channel::tech_pvt.
00331 { 00332 struct local_pvt *p = bridge->tech_pvt; 00333 struct ast_channel *bridged = bridge; 00334 00335 if (!p) { 00336 ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning <none>\n", 00337 chan->name, bridge->name); 00338 return NULL; 00339 } 00340 00341 ao2_lock(p); 00342 00343 if (ast_test_flag(p, LOCAL_BRIDGE)) { 00344 /* Find the opposite channel */ 00345 bridged = (bridge == p->owner ? p->chan : p->owner); 00346 00347 /* Now see if the opposite channel is bridged to anything */ 00348 if (!bridged) { 00349 bridged = bridge; 00350 } else if (bridged->_bridge) { 00351 bridged = bridged->_bridge; 00352 } 00353 } 00354 00355 ao2_unlock(p); 00356 00357 return bridged; 00358 }
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 875 of file chan_local.c.
References 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_channel::exten, exten, ast_party_caller::id, language, len(), LOCAL_LAUNCHED_PBX, LOG_NOTICE, 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, and ast_channel::varshead.
00876 { 00877 struct local_pvt *p = ast->tech_pvt; 00878 int pvt_locked = 0; 00879 00880 struct ast_channel *owner = NULL; 00881 struct ast_channel *chan = NULL; 00882 int res; 00883 struct ast_var_t *varptr = NULL, *new; 00884 size_t len, namelen; 00885 char *reduced_dest = ast_strdupa(dest); 00886 char *slash; 00887 const char *exten; 00888 const char *context; 00889 00890 if (!p) { 00891 return -1; 00892 } 00893 00894 /* since we are letting go of channel locks that were locked coming into 00895 * this function, then we need to give the tech pvt a ref */ 00896 ao2_ref(p, 1); 00897 ast_channel_unlock(ast); 00898 00899 awesome_locking(p, &chan, &owner); 00900 pvt_locked = 1; 00901 00902 if (owner != ast) { 00903 res = -1; 00904 goto return_cleanup; 00905 } 00906 00907 if (!owner || !chan) { 00908 res = -1; 00909 goto return_cleanup; 00910 } 00911 00912 /* 00913 * Note that cid_num and cid_name aren't passed in the ast_channel_alloc 00914 * call, so it's done here instead. 00915 * 00916 * All these failure points just return -1. The individual strings will 00917 * be cleared when we destroy the channel. 00918 */ 00919 ast_party_redirecting_copy(&chan->redirecting, &owner->redirecting); 00920 00921 ast_party_dialed_copy(&chan->dialed, &owner->dialed); 00922 00923 ast_connected_line_copy_to_caller(&chan->caller, &owner->connected); 00924 ast_connected_line_copy_from_caller(&chan->connected, &owner->caller); 00925 00926 ast_string_field_set(chan, language, owner->language); 00927 ast_string_field_set(chan, accountcode, owner->accountcode); 00928 ast_string_field_set(chan, musicclass, owner->musicclass); 00929 ast_cdr_update(chan); 00930 00931 ast_channel_cc_params_init(chan, ast_channel_get_cc_config_params(owner)); 00932 00933 /* Make sure we inherit the ANSWERED_ELSEWHERE flag if it's set on the queue/dial call request in the dialplan */ 00934 if (ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) { 00935 ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE); 00936 } 00937 00938 /* copy the channel variables from the incoming channel to the outgoing channel */ 00939 /* Note that due to certain assumptions, they MUST be in the same order */ 00940 AST_LIST_TRAVERSE(&owner->varshead, varptr, entries) { 00941 namelen = strlen(varptr->name); 00942 len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2; 00943 if ((new = ast_calloc(1, len))) { 00944 memcpy(new, varptr, len); 00945 new->value = &(new->name[0]) + namelen + 1; 00946 AST_LIST_INSERT_TAIL(&chan->varshead, new, entries); 00947 } 00948 } 00949 ast_channel_datastore_inherit(owner, chan); 00950 /* If the local channel has /n or /b on the end of it, 00951 * we need to lop that off for our argument to setting 00952 * up the CC_INTERFACES variable 00953 */ 00954 if ((slash = strrchr(reduced_dest, '/'))) { 00955 *slash = '\0'; 00956 } 00957 ast_set_cc_interfaces_chanvar(chan, reduced_dest); 00958 00959 exten = ast_strdupa(chan->exten); 00960 context = ast_strdupa(chan->context); 00961 00962 ao2_unlock(p); 00963 pvt_locked = 0; 00964 00965 ast_channel_unlock(chan); 00966 00967 if (!ast_exists_extension(chan, context, exten, 1, 00968 S_COR(owner->caller.id.number.valid, owner->caller.id.number.str, NULL))) { 00969 ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", exten, context); 00970 res = -1; 00971 chan = ast_channel_unref(chan); /* we already unlocked it, so clear it hear so the cleanup label won't touch it. */ 00972 goto return_cleanup; 00973 } 00974 00975 /* Start switch on sub channel */ 00976 if (!(res = ast_pbx_start(chan))) { 00977 ao2_lock(p); 00978 ast_set_flag(p, LOCAL_LAUNCHED_PBX); 00979 ao2_unlock(p); 00980 } 00981 chan = ast_channel_unref(chan); /* chan is already unlocked, clear it here so the cleanup lable won't touch it. */ 00982 00983 return_cleanup: 00984 if (p) { 00985 if (pvt_locked) { 00986 ao2_unlock(p); 00987 } 00988 ao2_ref(p, -1); 00989 } 00990 if (chan) { 00991 ast_channel_unlock(chan); 00992 chan = ast_channel_unref(chan); 00993 } 00994 00995 /* owner is supposed to be == to ast, if it 00996 * is, don't unlock it because ast must exit locked */ 00997 if (owner) { 00998 if (owner != ast) { 00999 ast_channel_unlock(owner); 01000 ast_channel_lock(ast); 01001 } 01002 owner = ast_channel_unref(owner); 01003 } else { 01004 /* we have to exit with ast locked */ 01005 ast_channel_lock(ast); 01006 } 01007 01008 return res; 01009 }
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_lock, ao2_ref, ao2_unlock, ast_debug, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, ast_exists_extension(), ast_log(), ast_strdupa, ast_test_flag, local_pvt::context, context, local_pvt::exten, exten, LOCAL_LAUNCHED_PBX, 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 for (; (lp = ao2_iterator_next(&it)); ao2_ref(lp, -1)) { 00310 int is_inuse; 00311 00312 ao2_lock(lp); 00313 is_inuse = !strcmp(exten, lp->exten) 00314 && !strcmp(context, lp->context) 00315 && lp->owner 00316 && ast_test_flag(lp, LOCAL_LAUNCHED_PBX); 00317 ao2_unlock(lp); 00318 if (is_inuse) { 00319 res = AST_DEVICE_INUSE; 00320 ao2_ref(lp, -1); 00321 break; 00322 } 00323 } 00324 ao2_iterator_destroy(&it); 00325 00326 return res; 00327 }
static int local_digit_begin | ( | struct ast_channel * | ast, | |
char | digit | |||
) | [static] |
Definition at line 786 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.
00787 { 00788 struct local_pvt *p = ast->tech_pvt; 00789 int res = -1; 00790 struct ast_frame f = { AST_FRAME_DTMF_BEGIN, }; 00791 int isoutbound; 00792 00793 if (!p) 00794 return -1; 00795 00796 ao2_ref(p, 1); /* ref for local_queue_frame */ 00797 ao2_lock(p); 00798 isoutbound = IS_OUTBOUND(ast, p); 00799 f.subclass.integer = digit; 00800 res = local_queue_frame(p, isoutbound, &f, ast, 0); 00801 ao2_unlock(p); 00802 ao2_ref(p, -1); 00803 00804 return res; 00805 }
static int local_digit_end | ( | struct ast_channel * | ast, | |
char | digit, | |||
unsigned int | duration | |||
) | [static] |
Definition at line 807 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.
00808 { 00809 struct local_pvt *p = ast->tech_pvt; 00810 int res = -1; 00811 struct ast_frame f = { AST_FRAME_DTMF_END, }; 00812 int isoutbound; 00813 00814 if (!p) 00815 return -1; 00816 00817 ao2_ref(p, 1); /* ref for local_queue_frame */ 00818 ao2_lock(p); 00819 isoutbound = IS_OUTBOUND(ast, p); 00820 f.subclass.integer = digit; 00821 f.len = duration; 00822 res = local_queue_frame(p, isoutbound, &f, ast, 0); 00823 ao2_unlock(p); 00824 ao2_ref(p, -1); 00825 00826 return res; 00827 }
static int local_fixup | ( | struct ast_channel * | oldchan, | |
struct ast_channel * | newchan | |||
) | [static] |
Definition at line 671 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.
00672 { 00673 struct local_pvt *p = newchan->tech_pvt; 00674 00675 if (!p) 00676 return -1; 00677 00678 ao2_lock(p); 00679 00680 if ((p->owner != oldchan) && (p->chan != oldchan)) { 00681 ast_log(LOG_WARNING, "Old channel %p wasn't %p or %p\n", oldchan, p->owner, p->chan); 00682 ao2_unlock(p); 00683 return -1; 00684 } 00685 if (p->owner == oldchan) 00686 p->owner = newchan; 00687 else 00688 p->chan = newchan; 00689 00690 /* Do not let a masquerade cause a Local channel to be bridged to itself! */ 00691 if (!ast_check_hangup(newchan) && ((p->owner && p->owner->_bridge == p->chan) || (p->chan && p->chan->_bridge == p->owner))) { 00692 ast_log(LOG_WARNING, "You can not bridge a Local channel to itself!\n"); 00693 ao2_unlock(p); 00694 ast_queue_hangup(newchan); 00695 return -1; 00696 } 00697 00698 ao2_unlock(p); 00699 return 0; 00700 }
static int local_hangup | ( | struct ast_channel * | ast | ) | [static] |
Hangup a call through the local proxy channel.
Definition at line 1012 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_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, and ast_channel::tech_pvt.
01013 { 01014 struct local_pvt *p = ast->tech_pvt; 01015 int isoutbound; 01016 int hangup_chan = 0; 01017 int res = 0; 01018 struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_HANGUP }, .data.uint32 = ast->hangupcause }; 01019 struct ast_channel *owner = NULL; 01020 struct ast_channel *chan = NULL; 01021 01022 if (!p) { 01023 return -1; 01024 } 01025 01026 /* give the pvt a ref since we are unlocking the channel. */ 01027 ao2_ref(p, 1); 01028 01029 /* the pvt isn't going anywhere, we gave it a ref */ 01030 ast_channel_unlock(ast); 01031 01032 /* lock everything */ 01033 awesome_locking(p, &chan, &owner); 01034 01035 if (ast != chan && ast != owner) { 01036 res = -1; 01037 goto local_hangup_cleanup; 01038 } 01039 01040 isoutbound = IS_OUTBOUND(ast, p); /* just comparing pointer of ast */ 01041 01042 if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) { 01043 ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE); 01044 ast_debug(2, "This local call has the ANSWERED_ELSEWHERE flag set.\n"); 01045 } 01046 01047 if (isoutbound) { 01048 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS"); 01049 01050 if (status && p->owner) { 01051 p->owner->hangupcause = p->chan->hangupcause; 01052 pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status); 01053 } 01054 01055 ast_clear_flag(p, LOCAL_LAUNCHED_PBX); 01056 p->chan = NULL; 01057 } else { 01058 if (p->chan) { 01059 ast_queue_hangup(p->chan); 01060 } 01061 p->owner = NULL; 01062 } 01063 01064 ast->tech_pvt = NULL; /* this is one of our locked channels, doesn't matter which */ 01065 01066 if (!p->owner && !p->chan) { 01067 ao2_unlock(p); 01068 01069 /* Remove from list */ 01070 ao2_unlink(locals, p); 01071 ao2_ref(p, -1); 01072 p = NULL; 01073 res = 0; 01074 goto local_hangup_cleanup; 01075 } 01076 if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) { 01077 /* Need to actually hangup since there is no PBX */ 01078 hangup_chan = 1; 01079 } else { 01080 local_queue_frame(p, isoutbound, &f, NULL, 0); 01081 } 01082 01083 local_hangup_cleanup: 01084 if (p) { 01085 ao2_unlock(p); 01086 ao2_ref(p, -1); 01087 } 01088 if (owner) { 01089 ast_channel_unlock(owner); 01090 owner = ast_channel_unref(owner); 01091 } 01092 if (chan) { 01093 ast_channel_unlock(chan); 01094 if (hangup_chan) { 01095 ast_hangup(chan); 01096 } 01097 chan = ast_channel_unref(chan); 01098 } 01099 01100 /* leave with the same stupid channel locked that came in */ 01101 ast_channel_lock(ast); 01102 return res; 01103 }
static int local_indicate | ( | struct ast_channel * | ast, | |
int | condition, | |||
const void * | data, | |||
size_t | datalen | |||
) | [static] |
Definition at line 702 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_T38_PARAMETERS, AST_CONTROL_UNHOLD, ast_debug, AST_FRAME_CONTROL, ast_moh_start(), ast_moh_stop(), ast_redirecting_build_data(), AST_T38_REQUEST_PARMS, 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_NO_OPTIMIZATION, local_queue_frame(), local_pvt::owner, ast_frame::ptr, ast_channel::redirecting, ast_control_t38_parameters::request_response, ast_frame::subclass, and ast_channel::tech_pvt.
00703 { 00704 struct local_pvt *p = ast->tech_pvt; 00705 int res = 0; 00706 struct ast_frame f = { AST_FRAME_CONTROL, }; 00707 int isoutbound; 00708 00709 if (!p) 00710 return -1; 00711 00712 ao2_ref(p, 1); /* ref for local_queue_frame */ 00713 00714 /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */ 00715 if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) { 00716 ast_moh_start(ast, data, NULL); 00717 } else if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_UNHOLD) { 00718 ast_moh_stop(ast); 00719 } else if (condition == AST_CONTROL_CONNECTED_LINE || condition == AST_CONTROL_REDIRECTING) { 00720 struct ast_channel *this_channel; 00721 struct ast_channel *the_other_channel; 00722 /* A connected line update frame may only contain a partial amount of data, such 00723 * as just a source, or just a ton, and not the full amount of information. However, 00724 * the collected information is all stored in the outgoing channel's connectedline 00725 * structure, so when receiving a connected line update on an outgoing local channel, 00726 * we need to transmit the collected connected line information instead of whatever 00727 * happens to be in this control frame. The same applies for redirecting information, which 00728 * is why it is handled here as well.*/ 00729 ao2_lock(p); 00730 isoutbound = IS_OUTBOUND(ast, p); 00731 if (isoutbound) { 00732 this_channel = p->chan; 00733 the_other_channel = p->owner; 00734 } else { 00735 this_channel = p->owner; 00736 the_other_channel = p->chan; 00737 } 00738 if (the_other_channel) { 00739 unsigned char frame_data[1024]; 00740 if (condition == AST_CONTROL_CONNECTED_LINE) { 00741 if (isoutbound) { 00742 ast_connected_line_copy_to_caller(&the_other_channel->caller, &this_channel->connected); 00743 } 00744 f.datalen = ast_connected_line_build_data(frame_data, sizeof(frame_data), &this_channel->connected, NULL); 00745 } else { 00746 f.datalen = ast_redirecting_build_data(frame_data, sizeof(frame_data), &this_channel->redirecting, NULL); 00747 } 00748 f.subclass.integer = condition; 00749 f.data.ptr = frame_data; 00750 res = local_queue_frame(p, isoutbound, &f, ast, 1); 00751 } 00752 ao2_unlock(p); 00753 } else { 00754 /* Queue up a frame representing the indication as a control frame */ 00755 ao2_lock(p); 00756 /* 00757 * Block -1 stop tones events if we are to be optimized out. We 00758 * don't need a flurry of these events on a local channel chain 00759 * when initially connected to slow the optimization process. 00760 */ 00761 if (0 <= condition || ast_test_flag(p, LOCAL_NO_OPTIMIZATION)) { 00762 isoutbound = IS_OUTBOUND(ast, p); 00763 f.subclass.integer = condition; 00764 f.data.ptr = (void *) data; 00765 f.datalen = datalen; 00766 res = local_queue_frame(p, isoutbound, &f, ast, 1); 00767 00768 if (!res && (condition == AST_CONTROL_T38_PARAMETERS) && 00769 (datalen == sizeof(struct ast_control_t38_parameters))) { 00770 const struct ast_control_t38_parameters *parameters = data; 00771 00772 if (parameters->request_response == AST_T38_REQUEST_PARMS) { 00773 res = AST_T38_REQUEST_PARMS; 00774 } 00775 } 00776 } else { 00777 ast_debug(4, "Blocked indication %d\n", condition); 00778 } 00779 ao2_unlock(p); 00780 } 00781 00782 ao2_ref(p, -1); 00783 return res; 00784 }
static struct ast_channel* local_new | ( | struct local_pvt * | p, | |
int | state, | |||
const char * | linkedid | |||
) | [static, read] |
Start new local channel.
Definition at line 1182 of file chan_local.c.
References ast_channel::amaflags, ast_atomic_fetchadd_int(), ast_best_codec(), ast_channel_alloc, ast_channel_release(), ast_copy_string(), AST_FLAG_DISABLE_DEVSTATE_CACHE, ast_jb_configure(), ast_log(), AST_STATE_RING, local_pvt::chan, ast_channel::context, local_pvt::context, ast_channel::exten, local_pvt::exten, ast_channel::flags, 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::reqformat, ast_channel::tech, ast_channel::tech_pvt, and ast_channel::writeformat.
Referenced by local_request().
01183 { 01184 struct ast_channel *tmp = NULL, *tmp2 = NULL; 01185 int fmt = 0; 01186 int generated_seqno = ast_atomic_fetchadd_int((int *)&name_sequence, +1); 01187 const char *t; 01188 int ama; 01189 01190 /* Allocate two new Asterisk channels */ 01191 /* safe accountcode */ 01192 if (p->owner && p->owner->accountcode) 01193 t = p->owner->accountcode; 01194 else 01195 t = ""; 01196 01197 if (p->owner) 01198 ama = p->owner->amaflags; 01199 else 01200 ama = 0; 01201 01202 /* Make sure that the ;2 channel gets the same linkedid as ;1. You can't pass linkedid to both 01203 * allocations since if linkedid isn't set, then each channel will generate its own linkedid. */ 01204 if (!(tmp = ast_channel_alloc(1, state, 0, 0, t, p->exten, p->context, linkedid, ama, "Local/%s@%s-%08x;1", p->exten, p->context, generated_seqno)) 01205 || !(tmp2 = ast_channel_alloc(1, AST_STATE_RING, 0, 0, t, p->exten, p->context, tmp->linkedid, ama, "Local/%s@%s-%08x;2", p->exten, p->context, generated_seqno))) { 01206 if (tmp) { 01207 tmp = ast_channel_release(tmp); 01208 } 01209 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n"); 01210 return NULL; 01211 } 01212 01213 tmp2->tech = tmp->tech = &local_tech; 01214 01215 tmp->nativeformats = p->reqformat; 01216 tmp2->nativeformats = p->reqformat; 01217 01218 /* Determine our read/write format and set it on each channel */ 01219 fmt = ast_best_codec(p->reqformat); 01220 tmp->writeformat = fmt; 01221 tmp2->writeformat = fmt; 01222 tmp->rawwriteformat = fmt; 01223 tmp2->rawwriteformat = fmt; 01224 tmp->readformat = fmt; 01225 tmp2->readformat = fmt; 01226 tmp->rawreadformat = fmt; 01227 tmp2->rawreadformat = fmt; 01228 01229 tmp->tech_pvt = p; 01230 tmp2->tech_pvt = p; 01231 01232 tmp->flags |= AST_FLAG_DISABLE_DEVSTATE_CACHE; 01233 tmp2->flags |= AST_FLAG_DISABLE_DEVSTATE_CACHE; 01234 01235 p->owner = tmp; 01236 p->chan = tmp2; 01237 01238 ast_copy_string(tmp->context, p->context, sizeof(tmp->context)); 01239 ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context)); 01240 ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten)); 01241 tmp->priority = 1; 01242 tmp2->priority = 1; 01243 01244 ast_jb_configure(tmp, &p->jb_conf); 01245 01246 return tmp; 01247 }
static void local_pvt_destructor | ( | void * | vdoomed | ) | [static] |
Definition at line 1113 of file chan_local.c.
References ast_module_unref().
Referenced by local_alloc().
01114 { 01115 ast_module_unref(ast_module_info->self); 01116 }
static int local_queryoption | ( | struct ast_channel * | ast, | |
int | option, | |||
void * | data, | |||
int * | datalen | |||
) | [static] |
Definition at line 361 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.
00362 { 00363 struct local_pvt *p; 00364 struct ast_channel *bridged = NULL; 00365 struct ast_channel *tmp = NULL; 00366 int res = 0; 00367 00368 if (option != AST_OPTION_T38_STATE) { 00369 /* AST_OPTION_T38_STATE is the only supported option at this time */ 00370 return -1; 00371 } 00372 00373 /* for some reason the channel is not locked in channel.c when this function is called */ 00374 if (!(p = ast->tech_pvt)) { 00375 return -1; 00376 } 00377 00378 ao2_lock(p); 00379 if (!(tmp = IS_OUTBOUND(ast, p) ? p->owner : p->chan)) { 00380 ao2_unlock(p); 00381 return -1; 00382 } 00383 ast_channel_ref(tmp); 00384 ao2_unlock(p); 00385 ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */ 00386 00387 ast_channel_lock(tmp); 00388 if (!(bridged = ast_bridged_channel(tmp))) { 00389 res = -1; 00390 ast_channel_unlock(tmp); 00391 goto query_cleanup; 00392 } 00393 ast_channel_ref(bridged); 00394 ast_channel_unlock(tmp); 00395 00396 query_cleanup: 00397 if (bridged) { 00398 res = ast_channel_queryoption(bridged, option, data, datalen, 0); 00399 bridged = ast_channel_unref(bridged); 00400 } 00401 if (tmp) { 00402 tmp = ast_channel_unref(tmp); 00403 } 00404 ast_channel_lock(ast); /* Lock back before we leave */ 00405 00406 return res; 00407 }
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 417 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().
00419 { 00420 struct ast_channel *other = NULL; 00421 00422 /* Recalculate outbound channel */ 00423 other = isoutbound ? p->owner : p->chan; 00424 00425 if (!other) { 00426 return 0; 00427 } 00428 00429 /* do not queue frame if generator is on both local channels */ 00430 if (us && us->generator && other->generator) { 00431 return 0; 00432 } 00433 00434 /* grab a ref on the channel before unlocking the pvt, 00435 * other can not go away from us now regardless of locking */ 00436 ast_channel_ref(other); 00437 if (us && us_locked) { 00438 ast_channel_unlock(us); 00439 } 00440 ao2_unlock(p); 00441 00442 if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_RINGING) { 00443 ast_setstate(other, AST_STATE_RINGING); 00444 } 00445 ast_queue_frame(other, f); 00446 00447 other = ast_channel_unref(other); 00448 if (us && us_locked) { 00449 ast_channel_lock(us); 00450 } 00451 ao2_lock(p); 00452 00453 return 0; 00454 }
static struct ast_frame * local_read | ( | struct ast_channel * | ast | ) | [static, read] |
Definition at line 633 of file chan_local.c.
References ast_null_frame.
00634 { 00635 return &ast_null_frame; 00636 }
static struct ast_channel * local_request | ( | const char * | type, | |
format_t | format, | |||
const struct ast_channel * | requestor, | |||
void * | data, | |||
int * | cause | |||
) | [static, read] |
Part of PBX interface.
Definition at line 1250 of file chan_local.c.
References ao2_ref, ao2_unlink, ast_channel_cc_params_init(), ast_channel_get_cc_config_params(), ast_channel_release(), AST_STATE_DOWN, local_pvt::chan, local_alloc(), local_new(), and local_pvt::owner.
01251 { 01252 struct local_pvt *p; 01253 struct ast_channel *chan; 01254 01255 /* Allocate a new private structure and then Asterisk channels */ 01256 p = local_alloc(data, format); 01257 if (!p) { 01258 return NULL; 01259 } 01260 chan = local_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL); 01261 if (!chan) { 01262 ao2_unlink(locals, p); 01263 } else if (ast_channel_cc_params_init(chan, requestor ? ast_channel_get_cc_config_params((struct ast_channel *)requestor) : NULL)) { 01264 ao2_unlink(locals, p); 01265 p->owner = ast_channel_release(p->owner); 01266 p->chan = ast_channel_release(p->chan); 01267 chan = NULL; 01268 } 01269 ao2_ref(p, -1); /* kill the ref from the alloc */ 01270 01271 return chan; 01272 }
static int local_sendhtml | ( | struct ast_channel * | ast, | |
int | subclass, | |||
const char * | data, | |||
int | datalen | |||
) | [static] |
Definition at line 850 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.
00851 { 00852 struct local_pvt *p = ast->tech_pvt; 00853 int res = -1; 00854 struct ast_frame f = { AST_FRAME_HTML, }; 00855 int isoutbound; 00856 00857 if (!p) 00858 return -1; 00859 00860 ao2_lock(p); 00861 ao2_ref(p, 1); /* ref for local_queue_frame */ 00862 isoutbound = IS_OUTBOUND(ast, p); 00863 f.subclass.integer = subclass; 00864 f.data.ptr = (char *)data; 00865 f.datalen = datalen; 00866 res = local_queue_frame(p, isoutbound, &f, ast, 0); 00867 ao2_unlock(p); 00868 ao2_ref(p, -1); 00869 00870 return res; 00871 }
static int local_sendtext | ( | struct ast_channel * | ast, | |
const char * | text | |||
) | [static] |
Definition at line 829 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.
00830 { 00831 struct local_pvt *p = ast->tech_pvt; 00832 int res = -1; 00833 struct ast_frame f = { AST_FRAME_TEXT, }; 00834 int isoutbound; 00835 00836 if (!p) 00837 return -1; 00838 00839 ao2_lock(p); 00840 ao2_ref(p, 1); /* ref for local_queue_frame */ 00841 isoutbound = IS_OUTBOUND(ast, p); 00842 f.data.ptr = (char *) text; 00843 f.datalen = strlen(text) + 1; 00844 res = local_queue_frame(p, isoutbound, &f, ast, 0); 00845 ao2_unlock(p); 00846 ao2_ref(p, -1); 00847 return res; 00848 }
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 638 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(), ast_frame::frametype, IS_OUTBOUND, LOCAL_ALREADY_MASQED, local_queue_frame(), and ast_channel::tech_pvt.
00639 { 00640 struct local_pvt *p = ast->tech_pvt; 00641 int res = -1; 00642 int isoutbound; 00643 00644 if (!p) { 00645 return -1; 00646 } 00647 00648 /* Just queue for delivery to the other side */ 00649 ao2_ref(p, 1); /* ref for local_queue_frame */ 00650 ao2_lock(p); 00651 isoutbound = IS_OUTBOUND(ast, p); 00652 00653 if (isoutbound 00654 && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) { 00655 check_bridge(ast, p); 00656 } 00657 00658 if (!ast_test_flag(p, LOCAL_ALREADY_MASQED)) { 00659 res = local_queue_frame(p, isoutbound, f, ast, 1); 00660 } else { 00661 ast_debug(1, "Not posting to '%s' queue since already masqueraded out\n", 00662 ast->name); 00663 res = 0; 00664 } 00665 ao2_unlock(p); 00666 ao2_ref(p, -1); 00667 00668 return res; 00669 }
static int locals_cmp_cb | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 1364 of file chan_local.c.
References CMP_MATCH.
Referenced by load_module().
01365 { 01366 return (obj == arg) ? CMP_MATCH : 0; 01367 }
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 1275 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, local_pvt::context, local_pvt::exten, ast_cli_args::fd, local_pvt::owner, RESULT_SUCCESS, and ast_cli_entry::usage.
01276 { 01277 struct local_pvt *p = NULL; 01278 struct ao2_iterator it; 01279 01280 switch (cmd) { 01281 case CLI_INIT: 01282 e->command = "local show channels"; 01283 e->usage = 01284 "Usage: local show channels\n" 01285 " Provides summary information on active local proxy channels.\n"; 01286 return NULL; 01287 case CLI_GENERATE: 01288 return NULL; 01289 } 01290 01291 if (a->argc != 3) 01292 return CLI_SHOWUSAGE; 01293 01294 if (ao2_container_count(locals) == 0) { 01295 ast_cli(a->fd, "No local channels in use\n"); 01296 return RESULT_SUCCESS; 01297 } 01298 01299 it = ao2_iterator_init(locals, 0); 01300 while ((p = ao2_iterator_next(&it))) { 01301 ao2_lock(p); 01302 ast_cli(a->fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context); 01303 ao2_unlock(p); 01304 ao2_ref(p, -1); 01305 } 01306 ao2_iterator_destroy(&it); 01307 01308 return CLI_SUCCESS; 01309 }
static int manager_optimize_away | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 1315 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().
01316 { 01317 const char *channel; 01318 struct local_pvt *p, *tmp = NULL; 01319 struct ast_channel *c; 01320 int found = 0; 01321 struct ao2_iterator it; 01322 01323 channel = astman_get_header(m, "Channel"); 01324 01325 if (ast_strlen_zero(channel)) { 01326 astman_send_error(s, m, "'Channel' not specified."); 01327 return 0; 01328 } 01329 01330 c = ast_channel_get_by_name(channel); 01331 if (!c) { 01332 astman_send_error(s, m, "Channel does not exist."); 01333 return 0; 01334 } 01335 01336 p = c->tech_pvt; 01337 ast_channel_unref(c); 01338 c = NULL; 01339 01340 it = ao2_iterator_init(locals, 0); 01341 while ((tmp = ao2_iterator_next(&it))) { 01342 if (tmp == p) { 01343 ao2_lock(tmp); 01344 found = 1; 01345 ast_clear_flag(tmp, LOCAL_NO_OPTIMIZATION); 01346 ao2_unlock(tmp); 01347 ao2_ref(tmp, -1); 01348 break; 01349 } 01350 ao2_ref(tmp, -1); 01351 } 01352 ao2_iterator_destroy(&it); 01353 01354 if (found) { 01355 astman_send_ack(s, m, "Queued channel to be optimized away"); 01356 } else { 01357 astman_send_error(s, m, "Unable to find channel"); 01358 } 01359 01360 return 0; 01361 }
static int unload_module | ( | void | ) | [static] |
Unload the local proxy channel from Asterisk.
Definition at line 1389 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, and local_pvt::owner.
01390 { 01391 struct local_pvt *p = NULL; 01392 struct ao2_iterator it; 01393 01394 /* First, take us out of the channel loop */ 01395 ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 01396 ast_manager_unregister("LocalOptimizeAway"); 01397 ast_channel_unregister(&local_tech); 01398 01399 it = ao2_iterator_init(locals, 0); 01400 while ((p = ao2_iterator_next(&it))) { 01401 if (p->owner) { 01402 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); 01403 } 01404 ao2_ref(p, -1); 01405 } 01406 ao2_iterator_destroy(&it); 01407 ao2_ref(locals, -1); 01408 01409 return 0; 01410 }
const int BUCKET_SIZE = 1 [static] |
Definition at line 83 of file chan_local.c.
struct ast_cli_entry cli_local[] [static] |
{ AST_CLI_DEFINE(locals_show, "List status of local channels"), }
Definition at line 1311 of file chan_local.c.
struct ast_jb_conf g_jb_conf [static] |
Definition at line 89 of file chan_local.c.
struct ast_channel_tech local_tech [static] |
Definition at line 115 of file chan_local.c.
struct ao2_container* locals [static] |
Definition at line 85 of file chan_local.c.
unsigned int name_sequence = 0 [static] |
Definition at line 87 of file chan_local.c.
const char tdesc[] = "Local Proxy Channel Driver" [static] |
Definition at line 76 of file chan_local.c.