Sat Mar 10 01:54:58 2012

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

static void __reg_module (void)
static void __unreg_module (void)
static void awesome_locking (struct local_pvt *p, struct ast_channel **outchan, struct ast_channel **outowner)
static void check_bridge (struct 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 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 struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Local Proxy Channel (Note: used internally by other modules)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DRIVER, }
static struct ast_module_infoast_module_info = &__mod_info
static const int BUCKET_SIZE = 1
static struct ast_cli_entry cli_local []
static struct ast_jb_conf g_jb_conf
static struct ast_channel_tech local_tech
static struct ao2_containerlocals
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)

Definition at line 78 of file chan_local.c.

Referenced by local_answer(), local_digit_begin(), local_digit_end(), local_hangup(), local_indicate(), local_queryoption(), local_sendhtml(), local_sendtext(), and local_write().

#define LOCAL_ALREADY_MASQED   (1 << 0)

Already masqueraded

Definition at line 156 of file chan_local.c.

Referenced by check_bridge(), and local_write().

#define LOCAL_BRIDGE   (1 << 3)

Report back the "true" channel as being bridged to

Definition at line 159 of file chan_local.c.

Referenced by local_alloc(), and local_bridgedchannel().

#define LOCAL_LAUNCHED_PBX   (1 << 1)

PBX was launched

Definition at line 157 of file chan_local.c.

Referenced by local_call(), and local_hangup().

#define LOCAL_MOH_PASSTHRU   (1 << 4)

Pass through music on hold start/stop frames

Definition at line 160 of file chan_local.c.

Referenced by local_alloc(), and local_indicate().

#define LOCAL_NO_OPTIMIZATION   (1 << 2)

Do not optimize using masquerading

Definition at line 158 of file chan_local.c.

Referenced by check_bridge(), local_alloc(), and manager_optimize_away().


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 1322 of file chan_local.c.

static void __unreg_module ( void   )  [static]

Definition at line 1322 of file chan_local.c.

static void awesome_locking ( struct local_pvt p,
struct ast_channel **  outchan,
struct ast_channel **  outowner 
) [static]

Definition at line 171 of file chan_local.c.

References ao2_lock, ast_channel_ref, local_pvt::chan, and local_pvt::owner.

Referenced by local_call(), and local_hangup().

00172 {
00173    struct ast_channel *chan = NULL;
00174    struct ast_channel *owner = NULL;
00175 
00176    for (;;) {
00177       ao2_lock(p);
00178       if (p->chan) {
00179          chan = p->chan;
00180          ast_channel_ref(chan);
00181       }
00182       if (p->owner) {
00183          owner = p->owner;
00184          ast_channel_ref(owner);
00185       }
00186       ao2_unlock(p);
00187 
00188       /* if we don't have both channels, then this is very easy */
00189       if (!owner || !chan) {
00190          if (owner) {
00191             ast_channel_lock(owner);
00192          } else if(chan) {
00193             ast_channel_lock(chan);
00194          }
00195          ao2_lock(p);
00196       } else {
00197          /* lock both channels first, then get the pvt lock */
00198          ast_channel_lock(chan);
00199          while (ast_channel_trylock(owner)) {
00200             CHANNEL_DEADLOCK_AVOIDANCE(chan);
00201          }
00202          ao2_lock(p);
00203       }
00204 
00205       /* Now that we have all the locks, validate that nothing changed */
00206       if (p->owner != owner || p->chan != chan) {
00207          if (owner) {
00208             ast_channel_unlock(owner);
00209             owner = ast_channel_unref(owner);
00210          }
00211          if (chan) {
00212             ast_channel_unlock(chan);
00213             chan = ast_channel_unref(chan);
00214          }
00215          ao2_unlock(p);
00216          continue;
00217       }
00218 
00219       break;
00220    }
00221    *outowner = p->owner;
00222    *outchan = p->chan;
00223 }

static void check_bridge ( struct local_pvt p  )  [static]

Definition at line 479 of file chan_local.c.

References ast_channel::_bridge, ast_party_caller::ani, ao2_lock, ao2_unlock, ast_app_group_update(), ast_bridged_channel(), ast_channel_masquerade(), ast_channel_ref, ast_channel_trylock, ast_channel_unlock, ast_channel_unref, ast_check_hangup(), AST_LIST_EMPTY, ast_set_flag, ast_test_flag, ast_channel::audiohooks, ast_channel::caller, local_pvt::chan, ast_channel::dialed, 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::readq, ast_channel::redirecting, ast_party_dialed::str, ast_party_dialed::subaddress, ast_party_id::subaddress, ast_party_redirecting::to, ast_party_subaddress::valid, ast_party_number::valid, and ast_party_name::valid.

Referenced by local_write().

00480 {
00481    struct ast_channel_monitor *tmp;
00482    struct ast_channel *chan = NULL;
00483    struct ast_channel *bridged_chan = NULL;
00484 
00485    /* Do a few conditional checks early on just to see if this optimization is possible */
00486    if (ast_test_flag(p, LOCAL_NO_OPTIMIZATION)) {
00487       return;
00488    }
00489    if (ast_test_flag(p, LOCAL_ALREADY_MASQED) || !p->chan || !p->owner) {
00490       return;
00491    }
00492 
00493    /* Safely get the channel bridged to p->chan */
00494    chan = ast_channel_ref(p->chan);
00495 
00496    ao2_unlock(p); /* don't call bridged channel with the pvt locked */
00497    bridged_chan = ast_bridged_channel(chan);
00498    ao2_lock(p);
00499 
00500    chan = ast_channel_unref(chan);
00501 
00502    /* since we had to unlock p to get the bridged chan, validate our
00503     * data once again and verify the bridged channel is what we expect
00504     * it to be in order to perform this optimization */
00505    if (ast_test_flag(p, LOCAL_ALREADY_MASQED) || !p->owner || !p->chan || (p->chan->_bridge != bridged_chan)) {
00506       return;
00507    }
00508 
00509    /* only do the masquerade if we are being called on the outbound channel,
00510       if it has been bridged to another channel and if there are no pending
00511       frames on the owner channel (because they would be transferred to the
00512       outbound channel during the masquerade)
00513    */
00514    if (p->chan->_bridge /* Not ast_bridged_channel!  Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) {
00515       /* Masquerade bridged channel into owner */
00516       /* Lock everything we need, one by one, and give up if
00517          we can't get everything.  Remember, we'll get another
00518          chance in just a little bit */
00519       if (!ast_channel_trylock(p->chan->_bridge)) {
00520          if (!ast_check_hangup(p->chan->_bridge)) {
00521             if (!ast_channel_trylock(p->owner)) {
00522                if (!ast_check_hangup(p->owner)) {
00523                   if (p->owner->monitor && !p->chan->_bridge->monitor) {
00524                      /* If a local channel is being monitored, we don't want a masquerade
00525                       * to cause the monitor to go away. Since the masquerade swaps the monitors,
00526                       * pre-swapping the monitors before the masquerade will ensure that the monitor
00527                       * ends up where it is expected.
00528                       */
00529                      tmp = p->owner->monitor;
00530                      p->owner->monitor = p->chan->_bridge->monitor;
00531                      p->chan->_bridge->monitor = tmp;
00532                   }
00533                   if (p->chan->audiohooks) {
00534                      struct ast_audiohook_list *audiohooks_swapper;
00535                      audiohooks_swapper = p->chan->audiohooks;
00536                      p->chan->audiohooks = p->owner->audiohooks;
00537                      p->owner->audiohooks = audiohooks_swapper;
00538                   }
00539 
00540                   /* If any Caller ID was set, preserve it after masquerade like above. We must check
00541                    * to see if Caller ID was set because otherwise we'll mistakingly copy info not
00542                    * set from the dialplan and will overwrite the real channel Caller ID. The reason
00543                    * for this whole preswapping action is because the Caller ID is set on the channel
00544                    * thread (which is the to be masqueraded away local channel) before both local
00545                    * channels are optimized away.
00546                    */
00547                   if (p->owner->caller.id.name.valid || p->owner->caller.id.number.valid
00548                      || p->owner->caller.id.subaddress.valid || p->owner->caller.ani.name.valid
00549                      || p->owner->caller.ani.number.valid || p->owner->caller.ani.subaddress.valid) {
00550                      struct ast_party_caller tmp;
00551                      tmp = p->owner->caller;
00552                      p->owner->caller = p->chan->_bridge->caller;
00553                      p->chan->_bridge->caller = tmp;
00554                   }
00555                   if (p->owner->redirecting.from.name.valid || p->owner->redirecting.from.number.valid
00556                      || p->owner->redirecting.from.subaddress.valid || p->owner->redirecting.to.name.valid
00557                      || p->owner->redirecting.to.number.valid || p->owner->redirecting.to.subaddress.valid) {
00558                      struct ast_party_redirecting tmp;
00559                      tmp = p->owner->redirecting;
00560                      p->owner->redirecting = p->chan->_bridge->redirecting;
00561                      p->chan->_bridge->redirecting = tmp;
00562                   }
00563                   if (p->owner->dialed.number.str || p->owner->dialed.subaddress.valid) {
00564                      struct ast_party_dialed tmp;
00565                      tmp = p->owner->dialed;
00566                      p->owner->dialed = p->chan->_bridge->dialed;
00567                      p->chan->_bridge->dialed = tmp;
00568                   }
00569 
00570 
00571                   ast_app_group_update(p->chan, p->owner);
00572                   ast_channel_masquerade(p->owner, p->chan->_bridge);
00573                   ast_set_flag(p, LOCAL_ALREADY_MASQED);
00574                }
00575                ast_channel_unlock(p->owner);
00576             }
00577          }
00578          ast_channel_unlock(p->chan->_bridge);
00579       }
00580    }
00581 }

static int load_module ( void   )  [static]

Load module into PBX, register channel.

Definition at line 1276 of file chan_local.c.

References ao2_container_alloc, ao2_ref, ast_channel_register(), ast_cli_register_multiple(), ast_log(), ast_manager_register_xml, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, cli_local, EVENT_FLAG_CALL, EVENT_FLAG_SYSTEM, local_tech, locals, locals_cmp_cb(), LOG_ERROR, and manager_optimize_away().

01277 {
01278    if (!(locals = ao2_container_alloc(BUCKET_SIZE, NULL, locals_cmp_cb))) {
01279       return AST_MODULE_LOAD_FAILURE;
01280    }
01281 
01282    /* Make sure we can register our channel type */
01283    if (ast_channel_register(&local_tech)) {
01284       ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
01285       ao2_ref(locals, -1);
01286       return AST_MODULE_LOAD_FAILURE;
01287    }
01288    ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
01289    ast_manager_register_xml("LocalOptimizeAway", EVENT_FLAG_SYSTEM|EVENT_FLAG_CALL, manager_optimize_away);
01290 
01291    return AST_MODULE_LOAD_SUCCESS;
01292 }

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

Create a call structure.

Definition at line 1036 of file chan_local.c.

References ao2_alloc, ao2_link, ast_copy_string(), ast_exists_extension(), AST_JB_ENABLED, ast_log(), ast_set_flag, ast_test_flag, g_jb_conf, LOCAL_BRIDGE, LOCAL_MOH_PASSTHRU, LOCAL_NO_OPTIMIZATION, locals, LOG_ERROR, and LOG_NOTICE.

Referenced by local_request().

01037 {
01038    struct local_pvt *tmp = NULL;
01039    char *c = NULL, *opts = NULL;
01040 
01041    if (!(tmp = ao2_alloc(sizeof(*tmp), NULL))) {
01042       return NULL;
01043    }
01044 
01045    /* Initialize private structure information */
01046    ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
01047 
01048    memcpy(&tmp->jb_conf, &g_jb_conf, sizeof(tmp->jb_conf));
01049 
01050    /* Look for options */
01051    if ((opts = strchr(tmp->exten, '/'))) {
01052       *opts++ = '\0';
01053       if (strchr(opts, 'n'))
01054          ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
01055       if (strchr(opts, 'j')) {
01056          if (ast_test_flag(tmp, LOCAL_NO_OPTIMIZATION))
01057             ast_set_flag(&tmp->jb_conf, AST_JB_ENABLED);
01058          else {
01059             ast_log(LOG_ERROR, "You must use the 'n' option for chan_local "
01060                "to use the 'j' option to enable the jitterbuffer\n");
01061          }
01062       }
01063       if (strchr(opts, 'b')) {
01064          ast_set_flag(tmp, LOCAL_BRIDGE);
01065       }
01066       if (strchr(opts, 'm')) {
01067          ast_set_flag(tmp, LOCAL_MOH_PASSTHRU);
01068       }
01069    }
01070 
01071    /* Look for a context */
01072    if ((c = strchr(tmp->exten, '@')))
01073       *c++ = '\0';
01074 
01075    ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
01076 
01077    tmp->reqformat = format;
01078 
01079 #if 0
01080    /* We can't do this check here, because we don't know the CallerID yet, and
01081     * the CallerID could potentially affect what step is actually taken (or
01082     * even if that step exists). */
01083    if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
01084       ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
01085       tmp = local_pvt_destroy(tmp);
01086    } else {
01087 #endif
01088       /* Add to list */
01089       ao2_link(locals, tmp);
01090 #if 0
01091    }
01092 #endif
01093    return tmp; /* this is returned with a ref */
01094 }

static int local_answer ( struct ast_channel ast  )  [static]

Definition at line 449 of file chan_local.c.

References ao2_lock, ao2_ref, ao2_unlock, AST_CONTROL_ANSWER, AST_FRAME_CONTROL, ast_log(), IS_OUTBOUND, local_queue_frame(), LOG_WARNING, and ast_channel::tech_pvt.

00450 {
00451    struct local_pvt *p = ast->tech_pvt;
00452    int isoutbound;
00453    int res = -1;
00454 
00455    if (!p)
00456       return -1;
00457 
00458    ao2_lock(p);
00459    ao2_ref(p, 1);
00460    isoutbound = IS_OUTBOUND(ast, p);
00461    if (isoutbound) {
00462       /* Pass along answer since somebody answered us */
00463       struct ast_frame answer = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } };
00464       res = local_queue_frame(p, isoutbound, &answer, ast, 1);
00465    } else {
00466       ast_log(LOG_WARNING, "Huh?  Local is being asked to answer?\n");
00467    }
00468    ao2_unlock(p);
00469    ao2_ref(p, -1);
00470    return res;
00471 }

static struct ast_channel * local_bridgedchannel ( struct ast_channel chan,
struct ast_channel bridge 
) [static]

Return the bridged channel of a Local channel.

Definition at line 323 of file chan_local.c.

References ast_channel::_bridge, ao2_lock, ao2_unlock, ast_debug, ast_test_flag, ast_channel::bridge, local_pvt::chan, LOCAL_BRIDGE, ast_channel::name, local_pvt::owner, and ast_channel::tech_pvt.

00324 {
00325    struct local_pvt *p = bridge->tech_pvt;
00326    struct ast_channel *bridged = bridge;
00327 
00328    if (!p) {
00329       ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning <none>\n",
00330          chan->name, bridge->name);
00331       return NULL;
00332    }
00333 
00334    ao2_lock(p);
00335 
00336    if (ast_test_flag(p, LOCAL_BRIDGE)) {
00337       /* Find the opposite channel */
00338       bridged = (bridge == p->owner ? p->chan : p->owner);
00339       
00340       /* Now see if the opposite channel is bridged to anything */
00341       if (!bridged) {
00342          bridged = bridge;
00343       } else if (bridged->_bridge) {
00344          bridged = bridged->_bridge;
00345       }
00346    }
00347 
00348    ao2_unlock(p);
00349 
00350    return bridged;
00351 }

static int local_call ( struct ast_channel ast,
char *  dest,
int  timeout 
) [static]

Initiate new call, part of PBX interface dest is the dial string.

Definition at line 805 of file chan_local.c.

References ast_channel::accountcode, accountcode, ao2_lock, ao2_ref, ao2_unlock, ast_calloc, ast_cdr_update(), ast_channel_cc_params_init(), ast_channel_datastore_inherit(), ast_channel_get_cc_config_params(), ast_channel_lock, ast_channel_unlock, ast_channel_unref, ast_connected_line_copy_from_caller(), ast_connected_line_copy_to_caller(), ast_exists_extension(), AST_FLAG_ANSWERED_ELSEWHERE, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), ast_party_dialed_copy(), ast_party_redirecting_copy(), ast_pbx_start(), ast_set_cc_interfaces_chanvar(), ast_set_flag, ast_strdupa, ast_string_field_set, ast_test_flag, awesome_locking(), ast_channel::caller, ast_channel::connected, ast_channel::context, context, ast_channel::dialed, ast_var_t::entries, ast_channel::exten, exten, ast_party_caller::id, ast_channel::language, language, len(), LOCAL_LAUNCHED_PBX, LOG_NOTICE, ast_channel::musicclass, musicclass, ast_var_t::name, ast_party_id::number, ast_channel::redirecting, S_COR, ast_party_number::str, ast_channel::tech_pvt, ast_party_number::valid, value, and ast_channel::varshead.

00806 {
00807    struct local_pvt *p = ast->tech_pvt;
00808    int pvt_locked = 0;
00809 
00810    struct ast_channel *owner = NULL;
00811    struct ast_channel *chan = NULL;
00812    int res;
00813    struct ast_var_t *varptr = NULL, *new;
00814    size_t len, namelen;
00815    char *reduced_dest = ast_strdupa(dest);
00816    char *slash;
00817    const char *exten;
00818    const char *context;
00819 
00820    if (!p) {
00821       return -1;
00822    }
00823 
00824    /* since we are letting go of channel locks that were locked coming into
00825     * this function, then we need to give the tech pvt a ref */
00826    ao2_ref(p, 1);
00827    ast_channel_unlock(ast);
00828 
00829    awesome_locking(p, &chan, &owner);
00830    pvt_locked = 1;
00831 
00832    if (owner != ast) {
00833       res = -1;
00834       goto return_cleanup;
00835    }
00836 
00837    if (!owner || !chan) {
00838       res = -1;
00839       goto return_cleanup;
00840    }
00841 
00842    /*
00843     * Note that cid_num and cid_name aren't passed in the ast_channel_alloc
00844     * call, so it's done here instead.
00845     *
00846     * All these failure points just return -1. The individual strings will
00847     * be cleared when we destroy the channel.
00848     */
00849    ast_party_redirecting_copy(&chan->redirecting, &owner->redirecting);
00850 
00851    ast_party_dialed_copy(&chan->dialed, &owner->dialed);
00852 
00853    ast_connected_line_copy_to_caller(&chan->caller, &owner->connected);
00854    ast_connected_line_copy_from_caller(&chan->connected, &owner->caller);
00855 
00856    ast_string_field_set(chan, language, owner->language);
00857    ast_string_field_set(chan, accountcode, owner->accountcode);
00858    ast_string_field_set(chan, musicclass, owner->musicclass);
00859    ast_cdr_update(chan);
00860 
00861    ast_channel_cc_params_init(chan, ast_channel_get_cc_config_params(owner));
00862 
00863    /* Make sure we inherit the ANSWERED_ELSEWHERE flag if it's set on the queue/dial call request in the dialplan */
00864    if (ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
00865       ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE);
00866    }
00867 
00868    /* copy the channel variables from the incoming channel to the outgoing channel */
00869    /* Note that due to certain assumptions, they MUST be in the same order */
00870    AST_LIST_TRAVERSE(&owner->varshead, varptr, entries) {
00871       namelen = strlen(varptr->name);
00872       len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
00873       if ((new = ast_calloc(1, len))) {
00874          memcpy(new, varptr, len);
00875          new->value = &(new->name[0]) + namelen + 1;
00876          AST_LIST_INSERT_TAIL(&chan->varshead, new, entries);
00877       }
00878    }
00879    ast_channel_datastore_inherit(owner, chan);
00880    /* If the local channel has /n or /b on the end of it,
00881     * we need to lop that off for our argument to setting
00882     * up the CC_INTERFACES variable
00883     */
00884    if ((slash = strrchr(reduced_dest, '/'))) {
00885       *slash = '\0';
00886    }
00887    ast_set_cc_interfaces_chanvar(chan, reduced_dest);
00888 
00889    exten = ast_strdupa(chan->exten);
00890    context = ast_strdupa(chan->context);
00891 
00892    ao2_unlock(p);
00893    pvt_locked = 0;
00894 
00895    ast_channel_unlock(chan);
00896 
00897    if (!ast_exists_extension(chan, context, exten, 1,
00898       S_COR(owner->caller.id.number.valid, owner->caller.id.number.str, NULL))) {
00899       ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", exten, context);
00900       res = -1;
00901       chan = ast_channel_unref(chan); /* we already unlocked it, so clear it hear so the cleanup label won't touch it. */
00902       goto return_cleanup;
00903    }
00904 
00905    /* Start switch on sub channel */
00906    if (!(res = ast_pbx_start(chan))) {
00907       ao2_lock(p);
00908       ast_set_flag(p, LOCAL_LAUNCHED_PBX);
00909       ao2_unlock(p);
00910    }
00911    chan = ast_channel_unref(chan); /* chan is already unlocked, clear it here so the cleanup lable won't touch it. */
00912 
00913 return_cleanup:
00914    if (p) {
00915       if (pvt_locked) {
00916          ao2_unlock(p);
00917       }
00918       ao2_ref(p, -1);
00919    }
00920    if (chan) {
00921       ast_channel_unlock(chan);
00922       chan = ast_channel_unref(chan);
00923    }
00924 
00925    /* owner is supposed to be == to ast,  if it
00926     * is, don't unlock it because ast must exit locked */
00927    if (owner) {
00928       if (owner != ast) {
00929          ast_channel_unlock(owner);
00930          ast_channel_lock(ast);
00931       }
00932       owner = ast_channel_unref(owner);
00933    } else {
00934       /* we have to exit with ast locked */
00935       ast_channel_lock(ast);
00936    }
00937 
00938    return res;
00939 }

static int local_devicestate ( void *  data  )  [static]

Adds devicestate to local channels.

Definition at line 281 of file chan_local.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_debug, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, ast_exists_extension(), ast_log(), ast_strdupa, local_pvt::context, context, local_pvt::exten, exten, locals, LOG_WARNING, and local_pvt::owner.

00282 {
00283    char *exten = ast_strdupa(data);
00284    char *context = NULL, *opts = NULL;
00285    int res;
00286    struct local_pvt *lp;
00287    struct ao2_iterator it;
00288 
00289    if (!(context = strchr(exten, '@'))) {
00290       ast_log(LOG_WARNING, "Someone used Local/%s somewhere without a @context. This is bad.\n", exten);
00291       return AST_DEVICE_INVALID; 
00292    }
00293 
00294    *context++ = '\0';
00295 
00296    /* Strip options if they exist */
00297    if ((opts = strchr(context, '/')))
00298       *opts = '\0';
00299 
00300    ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
00301 
00302    res = ast_exists_extension(NULL, context, exten, 1, NULL);
00303    if (!res)      
00304       return AST_DEVICE_INVALID;
00305    
00306    res = AST_DEVICE_NOT_INUSE;
00307 
00308    it = ao2_iterator_init(locals, 0);
00309    while ((lp = ao2_iterator_next(&it))) {
00310       if (!strcmp(exten, lp->exten) && !strcmp(context, lp->context) && lp->owner) {
00311          res = AST_DEVICE_INUSE;
00312          ao2_ref(lp, -1);
00313          break;
00314       }
00315       ao2_ref(lp, -1);
00316    }
00317    ao2_iterator_destroy(&it);
00318 
00319    return res;
00320 }

static int local_digit_begin ( struct ast_channel ast,
char  digit 
) [static]

Definition at line 716 of file chan_local.c.

References ao2_lock, ao2_ref, ao2_unlock, AST_FRAME_DTMF_BEGIN, f, IS_OUTBOUND, local_queue_frame(), and ast_channel::tech_pvt.

00717 {
00718    struct local_pvt *p = ast->tech_pvt;
00719    int res = -1;
00720    struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
00721    int isoutbound;
00722 
00723    if (!p)
00724       return -1;
00725 
00726    ao2_ref(p, 1); /* ref for local_queue_frame */
00727    ao2_lock(p);
00728    isoutbound = IS_OUTBOUND(ast, p);
00729    f.subclass.integer = digit;
00730    res = local_queue_frame(p, isoutbound, &f, ast, 0);
00731    ao2_unlock(p);
00732    ao2_ref(p, -1);
00733 
00734    return res;
00735 }

static int local_digit_end ( struct ast_channel ast,
char  digit,
unsigned int  duration 
) [static]

Definition at line 737 of file chan_local.c.

References ao2_lock, ao2_ref, ao2_unlock, AST_FRAME_DTMF_END, f, IS_OUTBOUND, local_queue_frame(), and ast_channel::tech_pvt.

00738 {
00739    struct local_pvt *p = ast->tech_pvt;
00740    int res = -1;
00741    struct ast_frame f = { AST_FRAME_DTMF_END, };
00742    int isoutbound;
00743 
00744    if (!p)
00745       return -1;
00746 
00747    ao2_ref(p, 1); /* ref for local_queue_frame */
00748    ao2_lock(p);
00749    isoutbound = IS_OUTBOUND(ast, p);
00750    f.subclass.integer = digit;
00751    f.len = duration;
00752    res = local_queue_frame(p, isoutbound, &f, ast, 0);
00753    ao2_unlock(p);
00754    ao2_ref(p, -1);
00755 
00756    return res;
00757 }

static int local_fixup ( struct ast_channel oldchan,
struct ast_channel newchan 
) [static]

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

00620 {
00621    struct local_pvt *p = newchan->tech_pvt;
00622 
00623    if (!p)
00624       return -1;
00625 
00626    ao2_lock(p);
00627 
00628    if ((p->owner != oldchan) && (p->chan != oldchan)) {
00629       ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
00630       ao2_unlock(p);
00631       return -1;
00632    }
00633    if (p->owner == oldchan)
00634       p->owner = newchan;
00635    else
00636       p->chan = newchan;
00637 
00638    /* Do not let a masquerade cause a Local channel to be bridged to itself! */
00639    if (!ast_check_hangup(newchan) && ((p->owner && p->owner->_bridge == p->chan) || (p->chan && p->chan->_bridge == p->owner))) {
00640       ast_log(LOG_WARNING, "You can not bridge a Local channel to itself!\n");
00641       ao2_unlock(p);
00642       ast_queue_hangup(newchan);
00643       return -1;
00644    }
00645 
00646    ao2_unlock(p);
00647    return 0;
00648 }

static int local_hangup ( struct ast_channel ast  )  [static]

Hangup a call through the local proxy channel.

Definition at line 942 of file chan_local.c.

References ao2_ref, ao2_unlink, ao2_unlock, ast_channel_lock, ast_channel_unlock, ast_channel_unref, ast_clear_flag, AST_CONTROL_HANGUP, ast_debug, AST_FLAG_ANSWERED_ELSEWHERE, AST_FRAME_CONTROL, ast_hangup(), ast_module_user_remove, ast_queue_hangup(), ast_set_flag, ast_test_flag, awesome_locking(), local_pvt::chan, f, hangup_chan(), ast_channel::hangupcause, IS_OUTBOUND, LOCAL_LAUNCHED_PBX, local_queue_frame(), locals, local_pvt::owner, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), status, ast_channel::tech_pvt, local_pvt::u_chan, and local_pvt::u_owner.

00943 {
00944    struct local_pvt *p = ast->tech_pvt;
00945    int isoutbound;
00946    int hangup_chan = 0;
00947    int res = 0;
00948    struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_HANGUP }, .data.uint32 = ast->hangupcause };
00949    struct ast_channel *owner = NULL;
00950    struct ast_channel *chan = NULL;
00951 
00952    if (!p) {
00953       return -1;
00954    }
00955 
00956    /* give the pvt a ref since we are unlocking the channel. */
00957    ao2_ref(p, 1);
00958 
00959    /* the pvt isn't going anywhere, we gave it a ref */
00960    ast_channel_unlock(ast);
00961 
00962    /* lock everything */
00963    awesome_locking(p, &chan, &owner);
00964 
00965    if (ast != chan && ast != owner) {
00966       res = -1;
00967       goto local_hangup_cleanup;
00968    }
00969 
00970    isoutbound = IS_OUTBOUND(ast, p); /* just comparing pointer of ast */
00971 
00972    if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
00973       ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE);
00974       ast_debug(2, "This local call has the ANSWERED_ELSEWHERE flag set.\n");
00975    }
00976 
00977    if (isoutbound) {
00978       const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
00979       if ((status) && (p->owner)) {
00980          p->owner->hangupcause = p->chan->hangupcause;
00981          pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
00982       }
00983 
00984       ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
00985       ast_module_user_remove(p->u_chan);
00986       p->chan = NULL;
00987    } else {
00988       ast_module_user_remove(p->u_owner);
00989       if (p->chan) {
00990          ast_queue_hangup(p->chan);
00991       }
00992       p->owner = NULL;
00993    }
00994 
00995    ast->tech_pvt = NULL; /* this is one of our locked channels, doesn't matter which */
00996 
00997    if (!p->owner && !p->chan) {
00998       ao2_unlock(p);
00999       /* Remove from list */
01000       ao2_unlink(locals, p);
01001       ao2_ref(p, -1);
01002       p = NULL;
01003       res = 0;
01004       goto local_hangup_cleanup;
01005    }
01006    if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) {
01007       /* Need to actually hangup since there is no PBX */
01008       hangup_chan = 1;
01009    } else {
01010       local_queue_frame(p, isoutbound, &f, NULL, 0);
01011    }
01012 
01013 local_hangup_cleanup:
01014    if (p) {
01015       ao2_unlock(p);
01016       ao2_ref(p, -1);
01017    }
01018    if (chan) {
01019       ast_channel_unlock(chan);
01020       if (hangup_chan) {
01021          ast_hangup(chan);
01022       }
01023       chan = ast_channel_unref(chan);
01024    }
01025    if (owner) {
01026       ast_channel_unlock(owner);
01027       owner = ast_channel_unref(owner);
01028    }
01029 
01030    /* leave with the same stupid channel locked that came in */
01031    ast_channel_lock(ast);
01032    return res;
01033 }

static int local_indicate ( struct ast_channel ast,
int  condition,
const void *  data,
size_t  datalen 
) [static]

Definition at line 650 of file chan_local.c.

References ao2_lock, ao2_ref, ao2_unlock, ast_connected_line_build_data(), ast_connected_line_copy_to_caller(), AST_CONTROL_CONNECTED_LINE, AST_CONTROL_HOLD, AST_CONTROL_REDIRECTING, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, ast_moh_start(), ast_moh_stop(), ast_redirecting_build_data(), ast_test_flag, ast_channel::caller, local_pvt::chan, ast_channel::connected, f, IS_OUTBOUND, LOCAL_MOH_PASSTHRU, local_queue_frame(), local_pvt::owner, ast_channel::redirecting, and ast_channel::tech_pvt.

00651 {
00652    struct local_pvt *p = ast->tech_pvt;
00653    int res = 0;
00654    struct ast_frame f = { AST_FRAME_CONTROL, };
00655    int isoutbound;
00656 
00657    if (!p)
00658       return -1;
00659 
00660    ao2_ref(p, 1); /* ref for local_queue_frame */
00661 
00662    /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */
00663    if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) {
00664       ast_moh_start(ast, data, NULL);
00665    } else if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_UNHOLD) {
00666       ast_moh_stop(ast);
00667    } else if (condition == AST_CONTROL_CONNECTED_LINE || condition == AST_CONTROL_REDIRECTING) {
00668       struct ast_channel *this_channel;
00669       struct ast_channel *the_other_channel;
00670       /* A connected line update frame may only contain a partial amount of data, such
00671        * as just a source, or just a ton, and not the full amount of information. However,
00672        * the collected information is all stored in the outgoing channel's connectedline
00673        * structure, so when receiving a connected line update on an outgoing local channel,
00674        * we need to transmit the collected connected line information instead of whatever
00675        * happens to be in this control frame. The same applies for redirecting information, which
00676        * is why it is handled here as well.*/
00677       ao2_lock(p);
00678       isoutbound = IS_OUTBOUND(ast, p);
00679       if (isoutbound) {
00680          this_channel = p->chan;
00681          the_other_channel = p->owner;
00682       } else {
00683          this_channel = p->owner;
00684          the_other_channel = p->chan;
00685       }
00686       if (the_other_channel) {
00687          unsigned char frame_data[1024];
00688          if (condition == AST_CONTROL_CONNECTED_LINE) {
00689             if (isoutbound) {
00690                ast_connected_line_copy_to_caller(&the_other_channel->caller, &this_channel->connected);
00691             }
00692             f.datalen = ast_connected_line_build_data(frame_data, sizeof(frame_data), &this_channel->connected, NULL);
00693          } else {
00694             f.datalen = ast_redirecting_build_data(frame_data, sizeof(frame_data), &this_channel->redirecting, NULL);
00695          }
00696          f.subclass.integer = condition;
00697          f.data.ptr = frame_data;
00698          res = local_queue_frame(p, isoutbound, &f, ast, 1);
00699       }
00700       ao2_unlock(p);
00701    } else {
00702       /* Queue up a frame representing the indication as a control frame */
00703       ao2_lock(p);
00704       isoutbound = IS_OUTBOUND(ast, p);
00705       f.subclass.integer = condition;
00706       f.data.ptr = (void*)data;
00707       f.datalen = datalen;
00708       res = local_queue_frame(p, isoutbound, &f, ast, 1);
00709       ao2_unlock(p);
00710    }
00711 
00712    ao2_ref(p, -1);
00713    return res;
00714 }

static struct ast_channel* local_new ( struct local_pvt p,
int  state,
const char *  linkedid 
) [static]

Start new local channel.

Definition at line 1097 of file chan_local.c.

References ast_channel::accountcode, ast_channel::amaflags, ast_best_codec(), ast_channel_alloc, ast_channel_release(), ast_copy_string(), ast_jb_configure(), ast_log(), ast_module_user_add, ast_random(), AST_STATE_RING, local_pvt::chan, ast_channel::context, local_pvt::context, ast_channel::exten, local_pvt::exten, local_pvt::jb_conf, local_tech, LOG_WARNING, ast_channel::nativeformats, local_pvt::owner, ast_channel::priority, ast_channel::rawreadformat, ast_channel::rawwriteformat, ast_channel::readformat, local_pvt::reqformat, ast_channel::tech, ast_channel::tech_pvt, local_pvt::u_chan, local_pvt::u_owner, and ast_channel::writeformat.

Referenced by local_request().

01098 {
01099    struct ast_channel *tmp = NULL, *tmp2 = NULL;
01100    int randnum = ast_random() & 0xffff, fmt = 0;
01101    const char *t;
01102    int ama;
01103 
01104    /* Allocate two new Asterisk channels */
01105    /* safe accountcode */
01106    if (p->owner && p->owner->accountcode)
01107       t = p->owner->accountcode;
01108    else
01109       t = "";
01110 
01111    if (p->owner)
01112       ama = p->owner->amaflags;
01113    else
01114       ama = 0;
01115    if (!(tmp = ast_channel_alloc(1, state, 0, 0, t, p->exten, p->context, linkedid, ama, "Local/%s@%s-%04x;1", p->exten, p->context, randnum)) 
01116       || !(tmp2 = ast_channel_alloc(1, AST_STATE_RING, 0, 0, t, p->exten, p->context, linkedid, ama, "Local/%s@%s-%04x;2", p->exten, p->context, randnum))) {
01117       if (tmp) {
01118          tmp = ast_channel_release(tmp);
01119       }
01120       ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
01121       return NULL;
01122    }
01123 
01124    tmp2->tech = tmp->tech = &local_tech;
01125 
01126    tmp->nativeformats = p->reqformat;
01127    tmp2->nativeformats = p->reqformat;
01128 
01129    /* Determine our read/write format and set it on each channel */
01130    fmt = ast_best_codec(p->reqformat);
01131    tmp->writeformat = fmt;
01132    tmp2->writeformat = fmt;
01133    tmp->rawwriteformat = fmt;
01134    tmp2->rawwriteformat = fmt;
01135    tmp->readformat = fmt;
01136    tmp2->readformat = fmt;
01137    tmp->rawreadformat = fmt;
01138    tmp2->rawreadformat = fmt;
01139 
01140    tmp->tech_pvt = p;
01141    tmp2->tech_pvt = p;
01142 
01143    p->owner = tmp;
01144    p->chan = tmp2;
01145    p->u_owner = ast_module_user_add(p->owner);
01146    p->u_chan = ast_module_user_add(p->chan);
01147 
01148    ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
01149    ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
01150    ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten));
01151    tmp->priority = 1;
01152    tmp2->priority = 1;
01153 
01154    ast_jb_configure(tmp, &p->jb_conf);
01155 
01156    return tmp;
01157 }

static int local_queryoption ( struct ast_channel ast,
int  option,
void *  data,
int *  datalen 
) [static]

Definition at line 354 of file chan_local.c.

References ao2_lock, ao2_unlock, ast_bridged_channel(), ast_channel_lock, ast_channel_queryoption(), ast_channel_ref, ast_channel_unlock, ast_channel_unref, AST_OPTION_T38_STATE, local_pvt::chan, IS_OUTBOUND, local_pvt::owner, and ast_channel::tech_pvt.

00355 {
00356    struct local_pvt *p;
00357    struct ast_channel *bridged = NULL;
00358    struct ast_channel *tmp = NULL;
00359    int res = 0;
00360 
00361    if (option != AST_OPTION_T38_STATE) {
00362       /* AST_OPTION_T38_STATE is the only supported option at this time */
00363       return -1;
00364    }
00365 
00366    /* for some reason the channel is not locked in channel.c when this function is called */
00367    if (!(p = ast->tech_pvt)) {
00368       return -1;
00369    }
00370 
00371    ao2_lock(p);
00372    if (!(tmp = IS_OUTBOUND(ast, p) ? p->owner : p->chan)) {
00373       ao2_unlock(p);
00374       return -1;
00375    }
00376    ast_channel_ref(tmp);
00377    ao2_unlock(p);
00378    ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */
00379 
00380    ast_channel_lock(tmp);
00381    if (!(bridged = ast_bridged_channel(tmp))) {
00382       res = -1;
00383       ast_channel_unlock(tmp);
00384       goto query_cleanup;
00385    }
00386    ast_channel_ref(bridged);
00387    ast_channel_unlock(tmp);
00388 
00389 query_cleanup:
00390    if (bridged) {
00391       res = ast_channel_queryoption(bridged, option, data, datalen, 0);
00392       bridged = ast_channel_unref(bridged);
00393    }
00394    if (tmp) {
00395       tmp = ast_channel_unref(tmp);
00396    }
00397    ast_channel_lock(ast); /* Lock back before we leave */
00398 
00399    return res;
00400 }

static int local_queue_frame ( struct local_pvt p,
int  isoutbound,
struct ast_frame f,
struct ast_channel us,
int  us_locked 
) [static]

queue a frame on a to either the p->owner or p->chan

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 410 of file chan_local.c.

References ao2_lock, ao2_unlock, ast_channel_lock, ast_channel_ref, ast_channel_unlock, ast_channel_unref, AST_CONTROL_RINGING, AST_FRAME_CONTROL, ast_queue_frame(), ast_setstate(), AST_STATE_RINGING, local_pvt::chan, f, ast_channel::generator, and local_pvt::owner.

Referenced by local_answer(), local_digit_begin(), local_digit_end(), local_hangup(), local_indicate(), local_sendhtml(), local_sendtext(), and local_write().

00412 {
00413    struct ast_channel *other = NULL;
00414 
00415    /* Recalculate outbound channel */
00416    other = isoutbound ? p->owner : p->chan;
00417 
00418    if (!other) {
00419       return 0;
00420    }
00421 
00422    /* do not queue frame if generator is on both local channels */
00423    if (us && us->generator && other->generator) {
00424       return 0;
00425    }
00426 
00427    /* grab a ref on the channel before unlocking the pvt,
00428     * other can not go away from us now regardless of locking */
00429    ast_channel_ref(other);
00430    if (us && us_locked) {
00431       ast_channel_unlock(us);
00432    }
00433    ao2_unlock(p);
00434 
00435    if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_RINGING) {
00436       ast_setstate(other, AST_STATE_RINGING);
00437    }
00438    ast_queue_frame(other, f);
00439 
00440    other = ast_channel_unref(other);
00441    if (us && us_locked) {
00442       ast_channel_lock(us);
00443    }
00444    ao2_lock(p);
00445 
00446    return 0;
00447 }

static struct ast_frame * local_read ( struct ast_channel ast  )  [static]

Definition at line 583 of file chan_local.c.

References ast_null_frame.

00584 {
00585    return &ast_null_frame;
00586 }

static struct ast_channel * local_request ( const char *  type,
format_t  format,
const struct ast_channel requestor,
void *  data,
int *  cause 
) [static]

Part of PBX interface.

Definition at line 1160 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, ast_channel::linkedid, local_alloc(), local_new(), and locals.

01161 {
01162    struct local_pvt *p = NULL;
01163    struct ast_channel *chan = NULL;
01164 
01165    /* Allocate a new private structure and then Asterisk channel */
01166    if ((p = local_alloc(data, format))) {
01167       if (!(chan = local_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL))) {
01168          ao2_unlink(locals, p);
01169       }
01170       if (chan && ast_channel_cc_params_init(chan, requestor ? ast_channel_get_cc_config_params((struct ast_channel *)requestor) : NULL)) {
01171          chan = ast_channel_release(chan);
01172          ao2_unlink(locals, p);
01173       }
01174       ao2_ref(p, -1); /* kill the ref from the alloc */
01175    }
01176 
01177    return chan;
01178 }

static int local_sendhtml ( struct ast_channel ast,
int  subclass,
const char *  data,
int  datalen 
) [static]

Definition at line 780 of file chan_local.c.

References ao2_lock, ao2_ref, ao2_unlock, AST_FRAME_HTML, f, IS_OUTBOUND, local_queue_frame(), and ast_channel::tech_pvt.

00781 {
00782    struct local_pvt *p = ast->tech_pvt;
00783    int res = -1;
00784    struct ast_frame f = { AST_FRAME_HTML, };
00785    int isoutbound;
00786 
00787    if (!p)
00788       return -1;
00789 
00790    ao2_lock(p);
00791    ao2_ref(p, 1); /* ref for local_queue_frame */
00792    isoutbound = IS_OUTBOUND(ast, p);
00793    f.subclass.integer = subclass;
00794    f.data.ptr = (char *)data;
00795    f.datalen = datalen;
00796    res = local_queue_frame(p, isoutbound, &f, ast, 0);
00797    ao2_unlock(p);
00798    ao2_ref(p, -1);
00799 
00800    return res;
00801 }

static int local_sendtext ( struct ast_channel ast,
const char *  text 
) [static]

Definition at line 759 of file chan_local.c.

References ao2_lock, ao2_ref, ao2_unlock, AST_FRAME_TEXT, f, IS_OUTBOUND, local_queue_frame(), and ast_channel::tech_pvt.

00760 {
00761    struct local_pvt *p = ast->tech_pvt;
00762    int res = -1;
00763    struct ast_frame f = { AST_FRAME_TEXT, };
00764    int isoutbound;
00765 
00766    if (!p)
00767       return -1;
00768 
00769    ao2_lock(p);
00770    ao2_ref(p, 1); /* ref for local_queue_frame */
00771    isoutbound = IS_OUTBOUND(ast, p);
00772    f.data.ptr = (char *) text;
00773    f.datalen = strlen(text) + 1;
00774    res = local_queue_frame(p, isoutbound, &f, ast, 0);
00775    ao2_unlock(p);
00776    ao2_ref(p, -1);
00777    return res;
00778 }

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 588 of file chan_local.c.

References ao2_lock, ao2_ref, ao2_unlock, ast_debug, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_test_flag, check_bridge(), f, IS_OUTBOUND, LOCAL_ALREADY_MASQED, local_queue_frame(), ast_channel::name, and ast_channel::tech_pvt.

00589 {
00590    struct local_pvt *p = ast->tech_pvt;
00591    int res = -1;
00592    int isoutbound;
00593 
00594    if (!p) {
00595       return -1;
00596    }
00597 
00598    /* Just queue for delivery to the other side */
00599    ao2_ref(p, 1); /* ref for local_queue_frame */
00600    ao2_lock(p);
00601    isoutbound = IS_OUTBOUND(ast, p);
00602 
00603    if (isoutbound && f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) {
00604       check_bridge(p);
00605    }
00606 
00607    if (!ast_test_flag(p, LOCAL_ALREADY_MASQED)) {
00608       res = local_queue_frame(p, isoutbound, f, ast, 1);
00609    } else {
00610       ast_debug(1, "Not posting to queue since already masked on '%s'\n", ast->name);
00611       res = 0;
00612    }
00613    ao2_unlock(p);
00614    ao2_ref(p, -1);
00615 
00616    return res;
00617 }

static int locals_cmp_cb ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 1270 of file chan_local.c.

References CMP_MATCH.

Referenced by load_module().

01271 {
01272    return (obj == arg) ? CMP_MATCH : 0;
01273 }

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 1181 of file chan_local.c.

References ao2_container_count(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_cli_args::argc, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, locals, RESULT_SUCCESS, and ast_cli_entry::usage.

01182 {
01183    struct local_pvt *p = NULL;
01184    struct ao2_iterator it;
01185 
01186    switch (cmd) {
01187    case CLI_INIT:
01188       e->command = "local show channels";
01189       e->usage =
01190          "Usage: local show channels\n"
01191          "       Provides summary information on active local proxy channels.\n";
01192       return NULL;
01193    case CLI_GENERATE:
01194       return NULL;
01195    }
01196 
01197    if (a->argc != 3)
01198       return CLI_SHOWUSAGE;
01199 
01200    if (ao2_container_count(locals) == 0) {
01201       ast_cli(a->fd, "No local channels in use\n");
01202       return RESULT_SUCCESS;
01203    }
01204 
01205    it = ao2_iterator_init(locals, 0);
01206    while ((p = ao2_iterator_next(&it))) {
01207       ao2_lock(p);
01208       ast_cli(a->fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
01209       ao2_unlock(p);
01210       ao2_ref(p, -1);
01211    }
01212    ao2_iterator_destroy(&it);
01213 
01214    return CLI_SUCCESS;
01215 }

static int manager_optimize_away ( struct mansession s,
const struct message m 
) [static]

Definition at line 1221 of file chan_local.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_channel_get_by_name(), ast_channel_unref, ast_clear_flag, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), ao2_iterator::c, LOCAL_NO_OPTIMIZATION, and locals.

Referenced by load_module().

01222 {
01223    const char *channel;
01224    struct local_pvt *p, *tmp = NULL;
01225    struct ast_channel *c;
01226    int found = 0;
01227    struct ao2_iterator it;
01228 
01229    channel = astman_get_header(m, "Channel");
01230 
01231    if (ast_strlen_zero(channel)) {
01232       astman_send_error(s, m, "'Channel' not specified.");
01233       return 0;
01234    }
01235 
01236    c = ast_channel_get_by_name(channel);
01237    if (!c) {
01238       astman_send_error(s, m, "Channel does not exist.");
01239       return 0;
01240    }
01241 
01242    p = c->tech_pvt;
01243    ast_channel_unref(c);
01244    c = NULL;
01245 
01246    it = ao2_iterator_init(locals, 0);
01247    while ((tmp = ao2_iterator_next(&it))) {
01248       if (tmp == p) {
01249          ao2_lock(tmp);
01250          found = 1;
01251          ast_clear_flag(tmp, LOCAL_NO_OPTIMIZATION);
01252          ao2_unlock(tmp);
01253          ao2_ref(tmp, -1);
01254          break;
01255       }
01256       ao2_ref(tmp, -1);
01257    }
01258    ao2_iterator_destroy(&it);
01259 
01260    if (found) {
01261       astman_send_ack(s, m, "Queued channel to be optimized away");
01262    } else {
01263       astman_send_error(s, m, "Unable to find channel");
01264    }
01265 
01266    return 0;
01267 }

static int unload_module ( void   )  [static]

Unload the local proxy channel from Asterisk.

Definition at line 1295 of file chan_local.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_channel_unregister(), ast_cli_unregister_multiple(), ast_manager_unregister(), ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, cli_local, local_tech, locals, and local_pvt::owner.

01296 {
01297    struct local_pvt *p = NULL;
01298    struct ao2_iterator it;
01299 
01300    /* First, take us out of the channel loop */
01301    ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
01302    ast_manager_unregister("LocalOptimizeAway");
01303    ast_channel_unregister(&local_tech);
01304 
01305    it = ao2_iterator_init(locals, 0);
01306    while ((p = ao2_iterator_next(&it))) {
01307       if (p->owner) {
01308          ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
01309       }
01310       ao2_ref(p, -1);
01311    }
01312    ao2_iterator_destroy(&it);
01313    ao2_ref(locals, -1);
01314 
01315    return 0;
01316 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Local Proxy Channel (Note: used internally by other modules)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DRIVER, } [static]

Definition at line 1322 of file chan_local.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 1322 of file chan_local.c.

const int BUCKET_SIZE = 1 [static]

Definition at line 83 of file chan_local.c.

struct ast_cli_entry cli_local[] [static]

Initial value:

 {
   { .handler =  locals_show , .summary =  "List status of local channels" ,__VA_ARGS__ },
}

Definition at line 1217 of file chan_local.c.

Referenced by load_module(), and unload_module().

struct ast_jb_conf g_jb_conf [static]

Definition at line 87 of file chan_local.c.

Referenced by local_alloc().

struct ast_channel_tech local_tech [static]

Definition at line 113 of file chan_local.c.

Referenced by load_module(), local_new(), and unload_module().

struct ao2_container* locals [static]

Definition at line 85 of file chan_local.c.

Referenced by load_module(), local_alloc(), local_devicestate(), local_hangup(), local_request(), locals_show(), manager_optimize_away(), and unload_module().

const char tdesc[] = "Local Proxy Channel Driver" [static]

Definition at line 76 of file chan_local.c.


Generated on Sat Mar 10 01:54:58 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7