Sat Feb 11 06:34:37 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"

Include dependency graph for chan_local.c:

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, struct ast_format_cap *cap)
 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, const char *dest, int timeout)
 Initiate new call, part of PBX interface dest is the dial string.
static void local_destroy (void *obj)
static int local_devicestate (const char *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, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *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 = AST_BUILDOPT_SUM, .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)

#define LOCAL_ALREADY_MASQED   (1 << 0)

Already masqueraded

Definition at line 155 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 158 of file chan_local.c.

Referenced by local_alloc(), and local_bridgedchannel().

#define LOCAL_LAUNCHED_PBX   (1 << 1)

PBX was launched

Definition at line 156 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 159 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 157 of file chan_local.c.

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


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 1359 of file chan_local.c.

static void __unreg_module ( void   )  [static]

Definition at line 1359 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 170 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().

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

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]

static struct local_pvt* local_alloc ( const char *  data,
struct ast_format_cap cap 
) [static, read]

Create a call structure.

Definition at line 1062 of file chan_local.c.

References ao2_alloc, ao2_link, ao2_ref, ast_copy_string(), ast_exists_extension(), ast_format_cap_dup(), AST_JB_ENABLED, ast_log(), ast_set_flag, ast_test_flag, local_pvt::context, local_pvt::exten, local_pvt::jb_conf, LOCAL_BRIDGE, local_destroy(), LOCAL_MOH_PASSTHRU, LOCAL_NO_OPTIMIZATION, LOG_ERROR, LOG_NOTICE, and local_pvt::reqcap.

Referenced by local_request().

01063 {
01064    struct local_pvt *tmp = NULL;
01065    char *c = NULL, *opts = NULL;
01066 
01067    if (!(tmp = ao2_alloc(sizeof(*tmp), local_destroy))) {
01068       return NULL;
01069    }
01070    if (!(tmp->reqcap = ast_format_cap_dup(cap))) {
01071       ao2_ref(tmp, -1);
01072       return NULL;
01073    }
01074 
01075    /* Initialize private structure information */
01076    ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
01077 
01078    memcpy(&tmp->jb_conf, &g_jb_conf, sizeof(tmp->jb_conf));
01079 
01080    /* Look for options */
01081    if ((opts = strchr(tmp->exten, '/'))) {
01082       *opts++ = '\0';
01083       if (strchr(opts, 'n'))
01084          ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
01085       if (strchr(opts, 'j')) {
01086          if (ast_test_flag(tmp, LOCAL_NO_OPTIMIZATION))
01087             ast_set_flag(&tmp->jb_conf, AST_JB_ENABLED);
01088          else {
01089             ast_log(LOG_ERROR, "You must use the 'n' option for chan_local "
01090                "to use the 'j' option to enable the jitterbuffer\n");
01091          }
01092       }
01093       if (strchr(opts, 'b')) {
01094          ast_set_flag(tmp, LOCAL_BRIDGE);
01095       }
01096       if (strchr(opts, 'm')) {
01097          ast_set_flag(tmp, LOCAL_MOH_PASSTHRU);
01098       }
01099    }
01100 
01101    /* Look for a context */
01102    if ((c = strchr(tmp->exten, '@')))
01103       *c++ = '\0';
01104 
01105    ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
01106 #if 0
01107    /* We can't do this check here, because we don't know the CallerID yet, and
01108     * the CallerID could potentially affect what step is actually taken (or
01109     * even if that step exists). */
01110    if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
01111       ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
01112       tmp = local_pvt_destroy(tmp);
01113    } else {
01114 #endif
01115       /* Add to list */
01116       ao2_link(locals, tmp);
01117 #if 0
01118    }
01119 #endif
01120    return tmp; /* this is returned with a ref */
01121 }

static int local_answer ( struct ast_channel ast  )  [static]

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

00449 {
00450    struct local_pvt *p = ast->tech_pvt;
00451    int isoutbound;
00452    int res = -1;
00453 
00454    if (!p) {
00455       return -1;
00456    }
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, read]

Return the bridged channel of a Local channel.

Definition at line 322 of file chan_local.c.

References ast_channel::_bridge, ao2_lock, ao2_unlock, ast_channel_name(), ast_debug, ast_test_flag, local_pvt::chan, LOCAL_BRIDGE, local_pvt::owner, and ast_channel::tech_pvt.

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

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

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

Definition at line 812 of file chan_local.c.

References ao2_lock, ao2_ref, ao2_unlock, ast_calloc, ast_cdr_update(), ast_channel_accountcode(), ast_channel_cc_params_init(), ast_channel_datastore_inherit(), ast_channel_get_cc_config_params(), ast_channel_language(), ast_channel_lock, ast_channel_musicclass(), ast_channel_name(), ast_channel_uniqueid(), 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_test_flag, awesome_locking(), ast_channel::caller, local_pvt::chan, ast_channel::connected, local_pvt::context, ast_channel::context, context, ast_channel::dialed, ast_var_t::entries, EVENT_FLAG_CALL, local_pvt::exten, ast_channel::exten, exten, ast_party_caller::id, len(), LOCAL_LAUNCHED_PBX, LOCAL_NO_OPTIMIZATION, LOG_NOTICE, manager_event, ast_var_t::name, ast_party_id::number, local_pvt::owner, ast_channel::redirecting, S_COR, ast_party_number::str, ast_channel::tech_pvt, ast_party_number::valid, and ast_channel::varshead.

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

static void local_destroy ( void *  obj  )  [static]

Definition at line 1055 of file chan_local.c.

References ast_format_cap_destroy(), and local_pvt::reqcap.

Referenced by local_alloc().

01056 {
01057    struct local_pvt *pvt = obj;
01058    pvt->reqcap = ast_format_cap_destroy(pvt->reqcap);
01059 }

static int local_devicestate ( const char *  data  )  [static]

Adds devicestate to local channels.

Definition at line 280 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, LOG_WARNING, and local_pvt::owner.

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

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

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

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

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

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

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

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

static int local_hangup ( struct ast_channel ast  )  [static]

Hangup a call through the local proxy channel.

Definition at line 962 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, 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, ast_channel::tech_pvt, local_pvt::u_chan, and local_pvt::u_owner.

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

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

Definition at line 652 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, ast_frame::data, ast_frame::datalen, ast_frame_subclass::integer, IS_OUTBOUND, LOCAL_MOH_PASSTHRU, local_queue_frame(), local_pvt::owner, ast_frame::ptr, ast_channel::redirecting, ast_frame::subclass, and ast_channel::tech_pvt.

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

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

Start new local channel.

Definition at line 1124 of file chan_local.c.

References ast_channel::amaflags, ast_best_codec(), ast_channel_accountcode(), ast_channel_alloc, ast_channel_release(), ast_copy_string(), ast_format_cap_copy(), ast_format_copy(), 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, LOG_WARNING, ast_channel::nativeformats, local_pvt::owner, ast_channel::priority, ast_channel::rawreadformat, ast_channel::rawwriteformat, ast_channel::readformat, local_pvt::reqcap, ast_channel::tech, ast_channel::tech_pvt, local_pvt::u_chan, local_pvt::u_owner, and ast_channel::writeformat.

Referenced by local_request().

01125 {
01126    struct ast_channel *tmp = NULL, *tmp2 = NULL;
01127    int randnum = ast_random() & 0xffff;
01128    struct ast_format fmt;
01129    const char *t;
01130    int ama;
01131 
01132    /* Allocate two new Asterisk channels */
01133    /* safe accountcode */
01134    if (p->owner && ast_channel_accountcode(p->owner))
01135       t = ast_channel_accountcode(p->owner);
01136    else
01137       t = "";
01138 
01139    if (p->owner)
01140       ama = p->owner->amaflags;
01141    else
01142       ama = 0;
01143    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))
01144       || !(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))) {
01145       if (tmp) {
01146          tmp = ast_channel_release(tmp);
01147       }
01148       ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
01149       return NULL;
01150    }
01151 
01152    tmp2->tech = tmp->tech = &local_tech;
01153 
01154    ast_format_cap_copy(tmp->nativeformats, p->reqcap);
01155    ast_format_cap_copy(tmp2->nativeformats, p->reqcap);
01156 
01157    /* Determine our read/write format and set it on each channel */
01158    ast_best_codec(p->reqcap, &fmt);
01159    ast_format_copy(&tmp->writeformat, &fmt);
01160    ast_format_copy(&tmp2->writeformat, &fmt);
01161    ast_format_copy(&tmp->rawwriteformat, &fmt);
01162    ast_format_copy(&tmp2->rawwriteformat, &fmt);
01163    ast_format_copy(&tmp->readformat, &fmt);
01164    ast_format_copy(&tmp2->readformat, &fmt);
01165    ast_format_copy(&tmp->rawreadformat, &fmt);
01166    ast_format_copy(&tmp2->rawreadformat, &fmt);
01167 
01168    tmp->tech_pvt = p;
01169    tmp2->tech_pvt = p;
01170 
01171    p->owner = tmp;
01172    p->chan = tmp2;
01173    p->u_owner = ast_module_user_add(p->owner);
01174    p->u_chan = ast_module_user_add(p->chan);
01175 
01176    ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
01177    ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
01178    ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten));
01179    tmp->priority = 1;
01180    tmp2->priority = 1;
01181 
01182    ast_jb_configure(tmp, &p->jb_conf);
01183 
01184    return tmp;
01185 }

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

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

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

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

References ao2_lock, ao2_unlock, ast_channel_lock, ast_channel_ref, ast_channel_unlock, ast_channel_unref, AST_CONTROL_RINGING, AST_FRAME_CONTROL, ast_queue_frame(), ast_setstate(), AST_STATE_RINGING, local_pvt::chan, ast_frame::frametype, ast_channel::generator, ast_frame_subclass::integer, local_pvt::owner, and ast_frame::subclass.

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

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

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

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,
struct ast_format_cap cap,
const struct ast_channel requestor,
const char *  data,
int *  cause 
) [static, read]

Part of PBX interface.

Definition at line 1188 of file chan_local.c.

References ao2_ref, ao2_unlink, ast_channel_cc_params_init(), ast_channel_get_cc_config_params(), ast_channel_linkedid(), ast_channel_release(), AST_STATE_DOWN, local_alloc(), and local_new().

01189 {
01190    struct local_pvt *p = NULL;
01191    struct ast_channel *chan = NULL;
01192 
01193    /* Allocate a new private structure and then Asterisk channel */
01194    if ((p = local_alloc(data, cap))) {
01195       if (!(chan = local_new(p, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL))) {
01196          ao2_unlink(locals, p);
01197       }
01198       if (chan && ast_channel_cc_params_init(chan, requestor ? ast_channel_get_cc_config_params((struct ast_channel *)requestor) : NULL)) {
01199          chan = ast_channel_release(chan);
01200          ao2_unlink(locals, p);
01201       }
01202       ao2_ref(p, -1); /* kill the ref from the alloc */
01203    }
01204 
01205    return chan;
01206 }

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

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

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

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

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

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

static int local_setoption ( struct ast_channel chan,
int  option,
void *  data,
int  datalen 
) [static]

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

00226 {
00227    int res = 0;
00228    struct local_pvt *p = NULL;
00229    struct ast_channel *otherchan = NULL;
00230    ast_chan_write_info_t *write_info;
00231 
00232    if (option != AST_OPTION_CHANNEL_WRITE) {
00233       return -1;
00234    }
00235 
00236    write_info = data;
00237 
00238    if (write_info->version != AST_CHAN_WRITE_INFO_T_VERSION) {
00239       ast_log(LOG_ERROR, "The chan_write_info_t type has changed, and this channel hasn't been updated!\n");
00240       return -1;
00241    }
00242 
00243    /* get the tech pvt */
00244    if (!(p = ast->tech_pvt)) {
00245       return -1;
00246    }
00247    ao2_ref(p, 1);
00248    ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */
00249 
00250    /* get the channel we are supposed to write to */
00251    ao2_lock(p);
00252    otherchan = (write_info->chan == p->owner) ? p->chan : p->owner;
00253    if (!otherchan || otherchan == write_info->chan) {
00254       res = -1;
00255       otherchan = NULL;
00256       ao2_unlock(p);
00257       goto setoption_cleanup;
00258    }
00259    ast_channel_ref(otherchan);
00260 
00261    /* clear the pvt lock before grabbing the channel */
00262    ao2_unlock(p);
00263 
00264    ast_channel_lock(otherchan);
00265    res = write_info->write_fn(otherchan, write_info->function, write_info->data, write_info->value);
00266    ast_channel_unlock(otherchan);
00267 
00268 setoption_cleanup:
00269    if (p) {
00270       ao2_ref(p, -1);
00271    }
00272    if (otherchan) {
00273       ast_channel_unref(otherchan);
00274    }
00275    ast_channel_lock(ast); /* Lock back before we leave */
00276    return res;
00277 }

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_channel_name(), 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.

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_channel_name(ast));
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 1299 of file chan_local.c.

References CMP_MATCH.

Referenced by load_module().

01300 {
01301    return (obj == arg) ? CMP_MATCH : 0;
01302 }

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 1209 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_channel_name(), 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.

01210 {
01211    struct local_pvt *p = NULL;
01212    struct ao2_iterator it;
01213 
01214    switch (cmd) {
01215    case CLI_INIT:
01216       e->command = "local show channels";
01217       e->usage =
01218          "Usage: local show channels\n"
01219          "       Provides summary information on active local proxy channels.\n";
01220       return NULL;
01221    case CLI_GENERATE:
01222       return NULL;
01223    }
01224 
01225    if (a->argc != 3) {
01226       return CLI_SHOWUSAGE;
01227    }
01228 
01229    if (ao2_container_count(locals) == 0) {
01230       ast_cli(a->fd, "No local channels in use\n");
01231       return RESULT_SUCCESS;
01232    }
01233 
01234    it = ao2_iterator_init(locals, 0);
01235    while ((p = ao2_iterator_next(&it))) {
01236       ao2_lock(p);
01237       ast_cli(a->fd, "%s -- %s@%s\n", p->owner ? ast_channel_name(p->owner) : "<unowned>", p->exten, p->context);
01238       ao2_unlock(p);
01239       ao2_ref(p, -1);
01240    }
01241    ao2_iterator_destroy(&it);
01242 
01243    return CLI_SUCCESS;
01244 }

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

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

01251 {
01252    const char *channel;
01253    struct local_pvt *p, *tmp = NULL;
01254    struct ast_channel *c;
01255    int found = 0;
01256    struct ao2_iterator it;
01257 
01258    channel = astman_get_header(m, "Channel");
01259 
01260    if (ast_strlen_zero(channel)) {
01261       astman_send_error(s, m, "'Channel' not specified.");
01262       return 0;
01263    }
01264 
01265    c = ast_channel_get_by_name(channel);
01266    if (!c) {
01267       astman_send_error(s, m, "Channel does not exist.");
01268       return 0;
01269    }
01270 
01271    p = c->tech_pvt;
01272    ast_channel_unref(c);
01273    c = NULL;
01274 
01275    it = ao2_iterator_init(locals, 0);
01276    while ((tmp = ao2_iterator_next(&it))) {
01277       if (tmp == p) {
01278          ao2_lock(tmp);
01279          found = 1;
01280          ast_clear_flag(tmp, LOCAL_NO_OPTIMIZATION);
01281          ao2_unlock(tmp);
01282          ao2_ref(tmp, -1);
01283          break;
01284       }
01285       ao2_ref(tmp, -1);
01286    }
01287    ao2_iterator_destroy(&it);
01288 
01289    if (found) {
01290       astman_send_ack(s, m, "Queued channel to be optimized away");
01291    } else {
01292       astman_send_error(s, m, "Unable to find channel");
01293    }
01294 
01295    return 0;
01296 }

static int unload_module ( void   )  [static]

Unload the local proxy channel from Asterisk.

Definition at line 1331 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_format_cap_destroy(), ast_manager_unregister(), ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, ast_channel_tech::capabilities, and local_pvt::owner.

01332 {
01333    struct local_pvt *p = NULL;
01334    struct ao2_iterator it;
01335 
01336    /* First, take us out of the channel loop */
01337    ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
01338    ast_manager_unregister("LocalOptimizeAway");
01339    ast_channel_unregister(&local_tech);
01340 
01341    it = ao2_iterator_init(locals, 0);
01342    while ((p = ao2_iterator_next(&it))) {
01343       if (p->owner) {
01344          ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
01345       }
01346       ao2_ref(p, -1);
01347    }
01348    ao2_iterator_destroy(&it);
01349    ao2_ref(locals, -1);
01350 
01351    ast_format_cap_destroy(local_tech.capabilities);
01352    return 0;
01353 }


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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DRIVER, } [static]

Definition at line 1359 of file chan_local.c.

Definition at line 1359 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:

 {
   AST_CLI_DEFINE(locals_show, "List status of local channels"),
}

Definition at line 1246 of file chan_local.c.

struct ast_jb_conf g_jb_conf [static]

Definition at line 87 of file chan_local.c.

struct ast_channel_tech local_tech [static]

Definition at line 113 of file chan_local.c.

struct ao2_container* locals [static]

Definition at line 85 of file chan_local.c.

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

Definition at line 76 of file chan_local.c.


Generated on Sat Feb 11 06:34:37 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6