Thu Sep 7 01:03:17 2017

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/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_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 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().


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 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 }

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

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

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 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 }


Variable Documentation

const int BUCKET_SIZE = 1 [static]

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


Generated on 7 Sep 2017 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1