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