Tue Aug 20 16:34:52 2013

Asterisk developer's documentation


chan_local.c File Reference

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_pvtlocal_alloc (const char *data, format_t format)
 Create a call structure.
static int local_answer (struct ast_channel *ast)
static struct ast_channellocal_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_channellocal_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_framelocal_read (struct ast_channel *ast)
static struct ast_channellocal_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_containerlocals
static unsigned int name_sequence = 0
static const char tdesc [] = "Local Proxy Channel Driver"

Detailed Description

Local Proxy Channel.

Author:
Mark Spencer <markster@digium.com>

Definition in file chan_local.c.


Define Documentation

#define IS_OUTBOUND ( a,
 )     (a == b->chan ? 1 : 0)
#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().


Function Documentation

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 }

static struct local_pvt* local_alloc ( const char *  data,
format_t  format 
) [static, read]

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

Note:
the local_pvt MUST have it's ref count bumped before entering this function and decremented after this function is called. This is a side effect of the deadlock avoidance that is necessary to lock 2 channels and a tech_pvt. Without a ref counted local_pvt, it is impossible to guarantee it will not be destroyed by another thread during deadlock avoidance.

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 }


Variable Documentation

const int BUCKET_SIZE = 1 [static]

Definition at line 83 of file chan_local.c.

struct ast_cli_entry cli_local[] [static]
Initial value:
 {
   AST_CLI_DEFINE(locals_show, "List status of local channels"),
}

Definition at line 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.


Generated on 20 Aug 2013 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1