Mon Jun 27 16:51:06 2011

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 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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .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 74 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 152 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 155 of file chan_local.c.

Referenced by local_alloc(), and local_bridgedchannel().

#define LOCAL_LAUNCHED_PBX   (1 << 1)

PBX was launched

Definition at line 153 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 156 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 154 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 1245 of file chan_local.c.

static void __unreg_module ( void   )  [static]

Definition at line 1245 of file chan_local.c.

static void check_bridge ( struct local_pvt p  )  [static]

Definition at line 434 of file chan_local.c.

References ast_channel::_bridge, ast_party_caller::ani, ast_app_group_update(), ast_bridged_channel(), ast_channel_masquerade(), ast_channel_trylock, ast_channel_unlock, 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().

00435 {
00436    struct ast_channel_monitor *tmp;
00437    if (ast_test_flag(p, LOCAL_ALREADY_MASQED) || ast_test_flag(p, LOCAL_NO_OPTIMIZATION) || !p->chan || !p->owner || (p->chan->_bridge != ast_bridged_channel(p->chan)))
00438       return;
00439 
00440    /* only do the masquerade if we are being called on the outbound channel,
00441       if it has been bridged to another channel and if there are no pending
00442       frames on the owner channel (because they would be transferred to the
00443       outbound channel during the masquerade)
00444    */
00445    if (p->chan->_bridge /* Not ast_bridged_channel!  Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) {
00446       /* Masquerade bridged channel into owner */
00447       /* Lock everything we need, one by one, and give up if
00448          we can't get everything.  Remember, we'll get another
00449          chance in just a little bit */
00450       if (!ast_channel_trylock(p->chan->_bridge)) {
00451          if (!ast_check_hangup(p->chan->_bridge)) {
00452             if (!ast_channel_trylock(p->owner)) {
00453                if (!ast_check_hangup(p->owner)) {
00454                   if (p->owner->monitor && !p->chan->_bridge->monitor) {
00455                      /* If a local channel is being monitored, we don't want a masquerade
00456                       * to cause the monitor to go away. Since the masquerade swaps the monitors,
00457                       * pre-swapping the monitors before the masquerade will ensure that the monitor
00458                       * ends up where it is expected.
00459                       */
00460                      tmp = p->owner->monitor;
00461                      p->owner->monitor = p->chan->_bridge->monitor;
00462                      p->chan->_bridge->monitor = tmp;
00463                   }
00464                   if (p->chan->audiohooks) {
00465                      struct ast_audiohook_list *audiohooks_swapper;
00466                      audiohooks_swapper = p->chan->audiohooks;
00467                      p->chan->audiohooks = p->owner->audiohooks;
00468                      p->owner->audiohooks = audiohooks_swapper;
00469                   }
00470 
00471                   /* If any Caller ID was set, preserve it after masquerade like above. We must check
00472                    * to see if Caller ID was set because otherwise we'll mistakingly copy info not
00473                    * set from the dialplan and will overwrite the real channel Caller ID. The reason
00474                    * for this whole preswapping action is because the Caller ID is set on the channel
00475                    * thread (which is the to be masqueraded away local channel) before both local
00476                    * channels are optimized away.
00477                    */
00478                   if (p->owner->caller.id.name.valid || p->owner->caller.id.number.valid
00479                      || p->owner->caller.id.subaddress.valid || p->owner->caller.ani.name.valid
00480                      || p->owner->caller.ani.number.valid || p->owner->caller.ani.subaddress.valid) {
00481                      struct ast_party_caller tmp;
00482                      tmp = p->owner->caller;
00483                      p->owner->caller = p->chan->_bridge->caller;
00484                      p->chan->_bridge->caller = tmp;
00485                   }
00486                   if (p->owner->redirecting.from.name.valid || p->owner->redirecting.from.number.valid
00487                      || p->owner->redirecting.from.subaddress.valid || p->owner->redirecting.to.name.valid
00488                      || p->owner->redirecting.to.number.valid || p->owner->redirecting.to.subaddress.valid) {
00489                      struct ast_party_redirecting tmp;
00490                      tmp = p->owner->redirecting;
00491                      p->owner->redirecting = p->chan->_bridge->redirecting;
00492                      p->chan->_bridge->redirecting = tmp;
00493                   }
00494                   if (p->owner->dialed.number.str || p->owner->dialed.subaddress.valid) {
00495                      struct ast_party_dialed tmp;
00496                      tmp = p->owner->dialed;
00497                      p->owner->dialed = p->chan->_bridge->dialed;
00498                      p->chan->_bridge->dialed = tmp;
00499                   }
00500 
00501 
00502                   ast_app_group_update(p->chan, p->owner);
00503                   ast_channel_masquerade(p->owner, p->chan->_bridge);
00504                   ast_set_flag(p, LOCAL_ALREADY_MASQED);
00505                }
00506                ast_channel_unlock(p->owner);
00507             }
00508             ast_channel_unlock(p->chan->_bridge);
00509          }
00510       }
00511    }
00512 }

static int load_module ( void   )  [static]

Load module into PBX, register channel.

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

01200 {
01201    if (!(locals = ao2_container_alloc(BUCKET_SIZE, NULL, locals_cmp_cb))) {
01202       return AST_MODULE_LOAD_FAILURE;
01203    }
01204 
01205    /* Make sure we can register our channel type */
01206    if (ast_channel_register(&local_tech)) {
01207       ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
01208       ao2_ref(locals, -1);
01209       return AST_MODULE_LOAD_FAILURE;
01210    }
01211    ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
01212    ast_manager_register_xml("LocalOptimizeAway", EVENT_FLAG_SYSTEM|EVENT_FLAG_CALL, manager_optimize_away);
01213 
01214    return AST_MODULE_LOAD_SUCCESS;
01215 }

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

Create a call structure.

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

00960 {
00961    struct local_pvt *tmp = NULL;
00962    char *c = NULL, *opts = NULL;
00963 
00964    if (!(tmp = ao2_alloc(sizeof(*tmp), NULL))) {
00965       return NULL;
00966    }
00967 
00968    /* Initialize private structure information */
00969    ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
00970 
00971    memcpy(&tmp->jb_conf, &g_jb_conf, sizeof(tmp->jb_conf));
00972 
00973    /* Look for options */
00974    if ((opts = strchr(tmp->exten, '/'))) {
00975       *opts++ = '\0';
00976       if (strchr(opts, 'n'))
00977          ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
00978       if (strchr(opts, 'j')) {
00979          if (ast_test_flag(tmp, LOCAL_NO_OPTIMIZATION))
00980             ast_set_flag(&tmp->jb_conf, AST_JB_ENABLED);
00981          else {
00982             ast_log(LOG_ERROR, "You must use the 'n' option for chan_local "
00983                "to use the 'j' option to enable the jitterbuffer\n");
00984          }
00985       }
00986       if (strchr(opts, 'b')) {
00987          ast_set_flag(tmp, LOCAL_BRIDGE);
00988       }
00989       if (strchr(opts, 'm')) {
00990          ast_set_flag(tmp, LOCAL_MOH_PASSTHRU);
00991       }
00992    }
00993 
00994    /* Look for a context */
00995    if ((c = strchr(tmp->exten, '@')))
00996       *c++ = '\0';
00997 
00998    ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
00999 
01000    tmp->reqformat = format;
01001 
01002 #if 0
01003    /* We can't do this check here, because we don't know the CallerID yet, and
01004     * the CallerID could potentially affect what step is actually taken (or
01005     * even if that step exists). */
01006    if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
01007       ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
01008       tmp = local_pvt_destroy(tmp);
01009    } else {
01010 #endif
01011       /* Add to list */
01012       ao2_link(locals, tmp);
01013 #if 0
01014    }
01015 #endif
01016    return tmp; /* this is returned with a ref */
01017 }

static int local_answer ( struct ast_channel ast  )  [static]

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

00407 {
00408    struct local_pvt *p = ast->tech_pvt;
00409    int isoutbound;
00410    int res = -1;
00411 
00412    if (!p)
00413       return -1;
00414 
00415    ao2_lock(p);
00416    ao2_ref(p, 1);
00417    isoutbound = IS_OUTBOUND(ast, p);
00418    if (isoutbound) {
00419       /* Pass along answer since somebody answered us */
00420       struct ast_frame answer = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } };
00421       res = local_queue_frame(p, isoutbound, &answer, ast, 1);
00422    } else {
00423       ast_log(LOG_WARNING, "Huh?  Local is being asked to answer?\n");
00424    }
00425    ao2_unlock(p);
00426    ao2_ref(p, -1);
00427    return res;
00428 }

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 266 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.

00267 {
00268    struct local_pvt *p = bridge->tech_pvt;
00269    struct ast_channel *bridged = bridge;
00270 
00271    if (!p) {
00272       ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning <none>\n",
00273          chan->name, bridge->name);
00274       return NULL;
00275    }
00276 
00277    ao2_lock(p);
00278 
00279    if (ast_test_flag(p, LOCAL_BRIDGE)) {
00280       /* Find the opposite channel */
00281       bridged = (bridge == p->owner ? p->chan : p->owner);
00282       
00283       /* Now see if the opposite channel is bridged to anything */
00284       if (!bridged) {
00285          bridged = bridge;
00286       } else if (bridged->_bridge) {
00287          bridged = bridged->_bridge;
00288       }
00289    }
00290 
00291    ao2_unlock(p);
00292 
00293    return bridged;
00294 }

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

References ast_channel::accountcode, accountcode, ao2_lock, ao2_ref, ao2_trylock, 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_trylock, ast_channel_unlock, 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, ast_channel::caller, local_pvt::chan, ast_channel::connected, ast_channel::context, ast_channel::dialed, ast_var_t::entries, ast_channel::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, local_pvt::owner, ast_channel::redirecting, S_COR, ast_party_number::str, ast_channel::tech_pvt, ast_party_number::valid, value, and ast_channel::varshead.

00733 {
00734    struct local_pvt *p = ast->tech_pvt;
00735    int res;
00736    struct ast_var_t *varptr = NULL, *new;
00737    size_t len, namelen;
00738    char *reduced_dest = ast_strdupa(dest);
00739    char *slash;
00740 
00741    if (!p || p->owner != ast) {
00742       return -1;
00743    }
00744 
00745    /* since we are letting go of channel locks that were locked coming into
00746     * this function, then we need to give the tech pvt a ref */
00747    ao2_ref(p, 1);
00748 
00749    while (ao2_trylock(p)) {
00750       ast_channel_unlock(ast);
00751       sched_yield();
00752       ast_channel_lock(ast);
00753    }
00754    while ((p->chan && p->owner) && ast_channel_trylock(p->chan)) {
00755       ao2_unlock(p);
00756       if (p->owner) {
00757          ast_channel_unlock(p->owner);
00758       }
00759       sched_yield();
00760       if (p->owner) {
00761          ast_channel_lock(p->owner);
00762       }
00763       ao2_lock(p);
00764    }
00765 
00766    if (!p->owner || !p->chan) {
00767       /* someone went away during the locking madness.
00768        * time to bail. */
00769       if (p->chan) {
00770          ast_channel_unlock(p->chan);
00771       }
00772       ao2_unlock(p);
00773       ao2_ref(p,-1);
00774       return -1;
00775    }
00776 
00777    /*
00778     * Note that cid_num and cid_name aren't passed in the ast_channel_alloc
00779     * call, so it's done here instead.
00780     *
00781     * All these failure points just return -1. The individual strings will
00782     * be cleared when we destroy the channel.
00783     */
00784    ast_party_redirecting_copy(&p->chan->redirecting, &p->owner->redirecting);
00785 
00786    ast_party_dialed_copy(&p->chan->dialed, &p->owner->dialed);
00787 
00788    ast_connected_line_copy_to_caller(&p->chan->caller, &p->owner->connected);
00789    ast_connected_line_copy_from_caller(&p->chan->connected, &p->owner->caller);
00790 
00791    ast_string_field_set(p->chan, language, p->owner->language);
00792    ast_string_field_set(p->chan, accountcode, p->owner->accountcode);
00793    ast_string_field_set(p->chan, musicclass, p->owner->musicclass);
00794    ast_cdr_update(p->chan);
00795 
00796    ast_channel_cc_params_init(p->chan, ast_channel_get_cc_config_params(p->owner));
00797 
00798    /* Make sure we inherit the ANSWERED_ELSEWHERE flag if it's set on the queue/dial call request in the dialplan */
00799    if (ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
00800       ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE);
00801    }
00802 
00803    /* copy the channel variables from the incoming channel to the outgoing channel */
00804    /* Note that due to certain assumptions, they MUST be in the same order */
00805    AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) {
00806       namelen = strlen(varptr->name);
00807       len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
00808       if ((new = ast_calloc(1, len))) {
00809          memcpy(new, varptr, len);
00810          new->value = &(new->name[0]) + namelen + 1;
00811          AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries);
00812       }
00813    }
00814    ast_channel_datastore_inherit(p->owner, p->chan);
00815    /* If the local channel has /n or /b on the end of it,
00816     * we need to lop that off for our argument to setting
00817     * up the CC_INTERFACES variable
00818     */
00819    if ((slash = strrchr(reduced_dest, '/'))) {
00820       *slash = '\0';
00821    }
00822    ast_set_cc_interfaces_chanvar(p->chan, reduced_dest);
00823 
00824    if (!ast_exists_extension(p->chan, p->chan->context, p->chan->exten, 1,
00825       S_COR(p->owner->caller.id.number.valid, p->owner->caller.id.number.str, NULL))) {
00826       ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->chan->exten, p->chan->context);
00827       ao2_unlock(p);
00828       ast_channel_unlock(p->chan);
00829       ao2_ref(p, -1);
00830       return -1;
00831    }
00832 
00833    /* Start switch on sub channel */
00834    if (!(res = ast_pbx_start(p->chan)))
00835       ast_set_flag(p, LOCAL_LAUNCHED_PBX);
00836 
00837    ao2_unlock(p);
00838    ast_channel_unlock(p->chan);
00839    ao2_ref(p, -1);
00840    return res;
00841 }

static int local_devicestate ( void *  data  )  [static]

Adds devicestate to local channels.

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

00225 {
00226    char *exten = ast_strdupa(data);
00227    char *context = NULL, *opts = NULL;
00228    int res;
00229    struct local_pvt *lp;
00230    struct ao2_iterator it;
00231 
00232    if (!(context = strchr(exten, '@'))) {
00233       ast_log(LOG_WARNING, "Someone used Local/%s somewhere without a @context. This is bad.\n", exten);
00234       return AST_DEVICE_INVALID; 
00235    }
00236 
00237    *context++ = '\0';
00238 
00239    /* Strip options if they exist */
00240    if ((opts = strchr(context, '/')))
00241       *opts = '\0';
00242 
00243    ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
00244 
00245    res = ast_exists_extension(NULL, context, exten, 1, NULL);
00246    if (!res)      
00247       return AST_DEVICE_INVALID;
00248    
00249    res = AST_DEVICE_NOT_INUSE;
00250 
00251    it = ao2_iterator_init(locals, 0);
00252    while ((lp = ao2_iterator_next(&it))) {
00253       if (!strcmp(exten, lp->exten) && !strcmp(context, lp->context) && lp->owner) {
00254          res = AST_DEVICE_INUSE;
00255          ao2_ref(lp, -1);
00256          break;
00257       }
00258       ao2_ref(lp, -1);
00259    }
00260    ao2_iterator_destroy(&it);
00261 
00262    return res;
00263 }

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

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

00644 {
00645    struct local_pvt *p = ast->tech_pvt;
00646    int res = -1;
00647    struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
00648    int isoutbound;
00649 
00650    if (!p)
00651       return -1;
00652 
00653    ao2_ref(p, 1); /* ref for local_queue_frame */
00654    ao2_lock(p);
00655    isoutbound = IS_OUTBOUND(ast, p);
00656    f.subclass.integer = digit;
00657    res = local_queue_frame(p, isoutbound, &f, ast, 0);
00658    ao2_unlock(p);
00659    ao2_ref(p, -1);
00660 
00661    return res;
00662 }

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

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

00665 {
00666    struct local_pvt *p = ast->tech_pvt;
00667    int res = -1;
00668    struct ast_frame f = { AST_FRAME_DTMF_END, };
00669    int isoutbound;
00670 
00671    if (!p)
00672       return -1;
00673 
00674    ao2_ref(p, 1); /* ref for local_queue_frame */
00675    ao2_lock(p);
00676    isoutbound = IS_OUTBOUND(ast, p);
00677    f.subclass.integer = digit;
00678    f.len = duration;
00679    res = local_queue_frame(p, isoutbound, &f, ast, 0);
00680    ao2_unlock(p);
00681    ao2_ref(p, -1);
00682 
00683    return res;
00684 }

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

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

00547 {
00548    struct local_pvt *p = newchan->tech_pvt;
00549 
00550    if (!p)
00551       return -1;
00552 
00553    ao2_lock(p);
00554 
00555    if ((p->owner != oldchan) && (p->chan != oldchan)) {
00556       ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
00557       ao2_unlock(p);
00558       return -1;
00559    }
00560    if (p->owner == oldchan)
00561       p->owner = newchan;
00562    else
00563       p->chan = newchan;
00564 
00565    /* Do not let a masquerade cause a Local channel to be bridged to itself! */
00566    if (!ast_check_hangup(newchan) && (p->owner->_bridge == p->chan || p->chan->_bridge == p->owner)) {
00567       ast_log(LOG_WARNING, "You can not bridge a Local channel to itself!\n");
00568       ao2_unlock(p);
00569       ast_queue_hangup(newchan);
00570       return -1;
00571    }
00572 
00573    ao2_unlock(p);
00574    return 0;
00575 }

static int local_hangup ( struct ast_channel ast  )  [static]

Hangup a call through the local proxy channel.

Definition at line 844 of file chan_local.c.

References ao2_lock, ao2_ref, ao2_unlink, ao2_unlock, ast_channel_lock, ast_channel_trylock, ast_channel_unlock, 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, local_pvt::chan, f, 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.

00845 {
00846    struct local_pvt *p = ast->tech_pvt;
00847    int isoutbound;
00848    struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_HANGUP }, .data.uint32 = ast->hangupcause };
00849    struct ast_channel *ochan = NULL;
00850 
00851    if (!p)
00852       return -1;
00853 
00854    /* we MUST give the tech_pvt a ref here since we are unlocking the
00855     * channel during deadlock avoidance. */
00856    ao2_ref(p, 1);
00857 
00858    ao2_lock(p);
00859 
00860    isoutbound = IS_OUTBOUND(ast, p);
00861 
00862    if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
00863       ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE);
00864       ast_debug(2, "This local call has the ANSWERED_ELSEWHERE flag set.\n");
00865    }
00866 
00867    if (isoutbound) {
00868       const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
00869       if ((status) && (p->owner)) {
00870          /* Deadlock avoidance */
00871          while (p->owner && ast_channel_trylock(p->owner)) {
00872             ao2_unlock(p);
00873             if (p->chan) {
00874                ast_channel_unlock(p->chan);
00875             }
00876             sched_yield();
00877             if (p->chan) {
00878                ast_channel_lock(p->chan);
00879             }
00880             ao2_lock(p);
00881          }
00882          if (p->owner) {
00883             p->owner->hangupcause = p->chan->hangupcause;
00884             pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
00885             ast_channel_unlock(p->owner);
00886          }
00887       }
00888       if (!p->chan) {
00889          /* chan was == to ast and was !NULL before deadlock avoidance started, if chan
00890           * is NULL now, then we should bail because that channel
00891           * hungup already. This is possible because we let go of the
00892           * lock given to the ast channel passed to this function during
00893           * deadlock avoidance. */
00894          ao2_unlock(p);
00895          ao2_ref(p, -1);
00896          return 0;
00897       }
00898       p->chan = NULL;
00899       ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
00900       ast_module_user_remove(p->u_chan);
00901    } else {
00902       ast_module_user_remove(p->u_owner);
00903       while (p->chan && ast_channel_trylock(p->chan)) {
00904             ao2_unlock(p);
00905             if (p->owner) {
00906                ast_channel_unlock(p->owner);
00907             }
00908             sched_yield();
00909             if (p->owner) {
00910                ast_channel_lock(p->owner);
00911             }
00912             ao2_lock(p);
00913       }
00914       if (p->chan) {
00915          ast_queue_hangup(p->chan);
00916          ast_channel_unlock(p->chan);
00917       }
00918 
00919       if (!p->owner) {
00920          /* owner was == to ast and was !NULL before deadlock avoidance started, if
00921           * owner is NULL now, then we should bail because that channel
00922           * hungup already. This is possible because we let go of the
00923           * lock given to the ast channel passed to this function during
00924           * deadlock avoidance. */
00925          ao2_unlock(p);
00926          ao2_ref(p, -1);
00927          return 0;
00928       }
00929       p->owner = NULL;
00930    }
00931 
00932    ast->tech_pvt = NULL;
00933 
00934    if (!p->owner && !p->chan) {
00935       ao2_unlock(p);
00936 
00937       /* Remove from list */
00938       ao2_unlink(locals, p);
00939       ao2_ref(p, -1);
00940       return 0;
00941    }
00942    if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) {
00943       /* Need to actually hangup since there is no PBX */
00944       ochan = p->chan;
00945    } else {
00946       local_queue_frame(p, isoutbound, &f, NULL, 1);
00947    }
00948 
00949    ao2_unlock(p);
00950    if (ochan) {
00951       ast_hangup(ochan);
00952    }
00953 
00954    ao2_ref(p, -1);
00955    return 0;
00956 }

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

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

00578 {
00579    struct local_pvt *p = ast->tech_pvt;
00580    int res = 0;
00581    struct ast_frame f = { AST_FRAME_CONTROL, };
00582    int isoutbound;
00583 
00584    if (!p)
00585       return -1;
00586 
00587    ao2_ref(p, 1); /* ref for local_queue_frame */
00588 
00589    /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */
00590    if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) {
00591       ast_moh_start(ast, data, NULL);
00592    } else if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_UNHOLD) {
00593       ast_moh_stop(ast);
00594    } else if (condition == AST_CONTROL_CONNECTED_LINE || condition == AST_CONTROL_REDIRECTING) {
00595       struct ast_channel *this_channel;
00596       struct ast_channel *the_other_channel;
00597       /* A connected line update frame may only contain a partial amount of data, such
00598        * as just a source, or just a ton, and not the full amount of information. However,
00599        * the collected information is all stored in the outgoing channel's connectedline
00600        * structure, so when receiving a connected line update on an outgoing local channel,
00601        * we need to transmit the collected connected line information instead of whatever
00602        * happens to be in this control frame. The same applies for redirecting information, which
00603        * is why it is handled here as well.*/
00604       ao2_lock(p);
00605       isoutbound = IS_OUTBOUND(ast, p);
00606       if (isoutbound) {
00607          this_channel = p->chan;
00608          the_other_channel = p->owner;
00609       } else {
00610          this_channel = p->owner;
00611          the_other_channel = p->chan;
00612       }
00613       if (the_other_channel) {
00614          unsigned char frame_data[1024];
00615          if (condition == AST_CONTROL_CONNECTED_LINE) {
00616             if (isoutbound) {
00617                ast_connected_line_copy_to_caller(&the_other_channel->caller, &this_channel->connected);
00618             }
00619             f.datalen = ast_connected_line_build_data(frame_data, sizeof(frame_data), &this_channel->connected, NULL);
00620          } else {
00621             f.datalen = ast_redirecting_build_data(frame_data, sizeof(frame_data), &this_channel->redirecting, NULL);
00622          }
00623          f.subclass.integer = condition;
00624          f.data.ptr = frame_data;
00625          res = local_queue_frame(p, isoutbound, &f, ast, 1);
00626       }
00627       ao2_unlock(p);
00628    } else {
00629       /* Queue up a frame representing the indication as a control frame */
00630       ao2_lock(p);
00631       isoutbound = IS_OUTBOUND(ast, p);
00632       f.subclass.integer = condition;
00633       f.data.ptr = (void*)data;
00634       f.datalen = datalen;
00635       res = local_queue_frame(p, isoutbound, &f, ast, 1);
00636       ao2_unlock(p);
00637    }
00638 
00639    ao2_ref(p, -1);
00640    return res;
00641 }

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

Start new local channel.

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

01021 {
01022    struct ast_channel *tmp = NULL, *tmp2 = NULL;
01023    int randnum = ast_random() & 0xffff, fmt = 0;
01024    const char *t;
01025    int ama;
01026 
01027    /* Allocate two new Asterisk channels */
01028    /* safe accountcode */
01029    if (p->owner && p->owner->accountcode)
01030       t = p->owner->accountcode;
01031    else
01032       t = "";
01033 
01034    if (p->owner)
01035       ama = p->owner->amaflags;
01036    else
01037       ama = 0;
01038    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)) 
01039       || !(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))) {
01040       if (tmp) {
01041          tmp = ast_channel_release(tmp);
01042       }
01043       ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
01044       return NULL;
01045    }
01046 
01047    tmp2->tech = tmp->tech = &local_tech;
01048 
01049    tmp->nativeformats = p->reqformat;
01050    tmp2->nativeformats = p->reqformat;
01051 
01052    /* Determine our read/write format and set it on each channel */
01053    fmt = ast_best_codec(p->reqformat);
01054    tmp->writeformat = fmt;
01055    tmp2->writeformat = fmt;
01056    tmp->rawwriteformat = fmt;
01057    tmp2->rawwriteformat = fmt;
01058    tmp->readformat = fmt;
01059    tmp2->readformat = fmt;
01060    tmp->rawreadformat = fmt;
01061    tmp2->rawreadformat = fmt;
01062 
01063    tmp->tech_pvt = p;
01064    tmp2->tech_pvt = p;
01065 
01066    p->owner = tmp;
01067    p->chan = tmp2;
01068    p->u_owner = ast_module_user_add(p->owner);
01069    p->u_chan = ast_module_user_add(p->chan);
01070 
01071    ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
01072    ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
01073    ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten));
01074    tmp->priority = 1;
01075    tmp2->priority = 1;
01076 
01077    ast_jb_configure(tmp, &p->jb_conf);
01078 
01079    return tmp;
01080 }

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

Definition at line 296 of file chan_local.c.

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

00297 {
00298    struct local_pvt *p = ast->tech_pvt;
00299    struct ast_channel *chan, *bridged;
00300    int res;
00301 
00302    if (!p) {
00303       return -1;
00304    }
00305 
00306    if (option != AST_OPTION_T38_STATE) {
00307       /* AST_OPTION_T38_STATE is the only supported option at this time */
00308       return -1;
00309    }
00310 
00311    ao2_lock(p);
00312    chan = IS_OUTBOUND(ast, p) ? p->owner : p->chan;
00313 
00314 try_again:
00315    if (!chan) {
00316       ao2_unlock(p);
00317       return -1;
00318    }
00319 
00320    if (ast_channel_trylock(chan)) {
00321       ao2_unlock(p);
00322       sched_yield();
00323       ao2_lock(p);
00324       chan = IS_OUTBOUND(ast, p) ? p->owner : p->chan;
00325       goto try_again;
00326    }
00327 
00328    bridged = ast_bridged_channel(chan);
00329    if (!bridged) {
00330       /* can't query channel unless we are bridged */
00331       ao2_unlock(p);
00332       ast_channel_unlock(chan);
00333       return -1;
00334    }
00335 
00336    if (ast_channel_trylock(bridged)) {
00337       ast_channel_unlock(chan);
00338       ao2_unlock(p);
00339       sched_yield();
00340       ao2_lock(p);
00341       chan = IS_OUTBOUND(ast, p) ? p->owner : p->chan;
00342       goto try_again;
00343    }
00344 
00345    res = ast_channel_queryoption(bridged, option, data, datalen, 0);
00346    ao2_unlock(p);
00347    ast_channel_unlock(chan);
00348    ast_channel_unlock(bridged);
00349    return res;
00350 }

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

References ao2_lock, ao2_trylock, ao2_unlock, ast_channel_trylock, ast_channel_unlock, AST_CONTROL_RINGING, AST_FRAME_CONTROL, ast_log(), ast_queue_frame(), ast_setstate(), AST_STATE_RINGING, local_pvt::chan, CHANNEL_DEADLOCK_AVOIDANCE, f, ast_channel::generator, LOG_ERROR, 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().

00362 {
00363    struct ast_channel *other = NULL;
00364 
00365    /* Recalculate outbound channel */
00366    other = isoutbound ? p->owner : p->chan;
00367 
00368    if (!other) {
00369       return 0;
00370    }
00371 
00372    /* do not queue frame if generator is on both local channels */
00373    if (us && us->generator && other->generator) {
00374       return 0;
00375    }
00376 
00377    /* Ensure that we have both channels locked */
00378    while (other && ast_channel_trylock(other)) {
00379       int res;
00380       if ((res = ao2_unlock(p))) {
00381          ast_log(LOG_ERROR, "chan_local bug! '&p->lock' was not locked when entering local_queue_frame! (%s)\n", strerror(res));
00382          return -1;
00383       }
00384       if (us && us_locked) {
00385          do {
00386             CHANNEL_DEADLOCK_AVOIDANCE(us);
00387          } while (ao2_trylock(p));
00388       } else {
00389          usleep(1);
00390          ao2_lock(p);
00391       }
00392       other = isoutbound ? p->owner : p->chan;
00393    }
00394 
00395    if (other) {
00396       if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_RINGING) {
00397          ast_setstate(other, AST_STATE_RINGING);
00398       }
00399       ast_queue_frame(other, f);
00400       ast_channel_unlock(other);
00401    }
00402 
00403    return 0;
00404 }

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

Definition at line 514 of file chan_local.c.

References ast_null_frame.

00515 {
00516    return &ast_null_frame;
00517 }

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 1083 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.

01084 {
01085    struct local_pvt *p = NULL;
01086    struct ast_channel *chan = NULL;
01087 
01088    /* Allocate a new private structure and then Asterisk channel */
01089    if ((p = local_alloc(data, format))) {
01090       if (!(chan = local_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL))) {
01091          ao2_unlink(locals, p);
01092       }
01093       if (chan && ast_channel_cc_params_init(chan, requestor ? ast_channel_get_cc_config_params((struct ast_channel *)requestor) : NULL)) {
01094          chan = ast_channel_release(chan);
01095          ao2_unlink(locals, p);
01096       }
01097       ao2_ref(p, -1); /* kill the ref from the alloc */
01098    }
01099 
01100    return chan;
01101 }

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

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

00708 {
00709    struct local_pvt *p = ast->tech_pvt;
00710    int res = -1;
00711    struct ast_frame f = { AST_FRAME_HTML, };
00712    int isoutbound;
00713 
00714    if (!p)
00715       return -1;
00716 
00717    ao2_lock(p);
00718    ao2_ref(p, 1); /* ref for local_queue_frame */
00719    isoutbound = IS_OUTBOUND(ast, p);
00720    f.subclass.integer = subclass;
00721    f.data.ptr = (char *)data;
00722    f.datalen = datalen;
00723    res = local_queue_frame(p, isoutbound, &f, ast, 0);
00724    ao2_unlock(p);
00725    ao2_ref(p, -1);
00726 
00727    return res;
00728 }

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

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

00687 {
00688    struct local_pvt *p = ast->tech_pvt;
00689    int res = -1;
00690    struct ast_frame f = { AST_FRAME_TEXT, };
00691    int isoutbound;
00692 
00693    if (!p)
00694       return -1;
00695 
00696    ao2_lock(p);
00697    ao2_ref(p, 1); /* ref for local_queue_frame */
00698    isoutbound = IS_OUTBOUND(ast, p);
00699    f.data.ptr = (char *) text;
00700    f.datalen = strlen(text) + 1;
00701    res = local_queue_frame(p, isoutbound, &f, ast, 0);
00702    ao2_unlock(p);
00703    ao2_ref(p, -1);
00704    return res;
00705 }

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

Definition at line 158 of file chan_local.c.

References ao2_trylock, ao2_unlock, AST_CHAN_WRITE_INFO_T_VERSION, ast_channel_lock, ast_channel_trylock, ast_channel_unlock, 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, LOG_WARNING, ast_channel::name, 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.

00159 {
00160    int res;
00161    struct local_pvt *p;
00162    struct ast_channel *otherchan;
00163    ast_chan_write_info_t *write_info;
00164 
00165    if (option != AST_OPTION_CHANNEL_WRITE) {
00166       return -1;
00167    }
00168 
00169    write_info = data;
00170 
00171    if (write_info->version != AST_CHAN_WRITE_INFO_T_VERSION) {
00172       ast_log(LOG_ERROR, "The chan_write_info_t type has changed, and this channel hasn't been updated!\n");
00173       return -1;
00174    }
00175 
00176 
00177 startover:
00178    ast_channel_lock(chan);
00179 
00180    p = chan->tech_pvt;
00181    if (!p) {
00182       ast_channel_unlock(chan);
00183       ast_log(LOG_WARNING, "Could not update other side of %s, local_pvt went away.\n", chan->name);
00184       return -1;
00185    }
00186 
00187    while (ao2_trylock(p)) {
00188       ast_channel_unlock(chan);
00189       sched_yield();
00190       ast_channel_lock(chan);
00191       p = chan->tech_pvt;
00192       if (!p) {
00193          ast_channel_unlock(chan);
00194          ast_log(LOG_WARNING, "Could not update other side of %s, local_pvt went away.\n", chan->name);
00195          return -1;
00196       }
00197    }
00198 
00199    otherchan = (write_info->chan == p->owner) ? p->chan : p->owner;
00200 
00201    if (!otherchan || otherchan == write_info->chan) {
00202       ao2_unlock(p);
00203       ast_channel_unlock(chan);
00204       ast_log(LOG_WARNING, "Could not update other side of %s, other side went away.\n", chan->name);
00205       return 0;
00206    }
00207 
00208    if (ast_channel_trylock(otherchan)) {
00209       ao2_unlock(p);
00210       ast_channel_unlock(chan);
00211       goto startover;
00212    }
00213 
00214    res = write_info->write_fn(otherchan, write_info->function, write_info->data, write_info->value);
00215 
00216    ast_channel_unlock(otherchan);
00217    ao2_unlock(p);
00218    ast_channel_unlock(chan);
00219 
00220    return res;
00221 }

static int local_write ( struct ast_channel ast,
struct ast_frame f 
) [static]

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

00520 {
00521    struct local_pvt *p = ast->tech_pvt;
00522    int res = -1;
00523    int isoutbound;
00524 
00525    if (!p)
00526       return -1;
00527 
00528    /* Just queue for delivery to the other side */
00529    ao2_lock(p);
00530    ao2_ref(p, 1); /* ref for local_queue_frame */
00531    isoutbound = IS_OUTBOUND(ast, p);
00532    if (isoutbound && f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO))
00533       check_bridge(p);
00534    if (!ast_test_flag(p, LOCAL_ALREADY_MASQED))
00535       res = local_queue_frame(p, isoutbound, f, ast, 1);
00536    else {
00537       ast_debug(1, "Not posting to queue since already masked on '%s'\n", ast->name);
00538       res = 0;
00539    }
00540    ao2_unlock(p);
00541    ao2_ref(p, -1);
00542 
00543    return res;
00544 }

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

Definition at line 1193 of file chan_local.c.

References CMP_MATCH.

Referenced by load_module().

01194 {
01195    return (obj == arg) ? CMP_MATCH : 0;
01196 }

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 1104 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.

01105 {
01106    struct local_pvt *p = NULL;
01107    struct ao2_iterator it;
01108 
01109    switch (cmd) {
01110    case CLI_INIT:
01111       e->command = "local show channels";
01112       e->usage =
01113          "Usage: local show channels\n"
01114          "       Provides summary information on active local proxy channels.\n";
01115       return NULL;
01116    case CLI_GENERATE:
01117       return NULL;
01118    }
01119 
01120    if (a->argc != 3)
01121       return CLI_SHOWUSAGE;
01122 
01123    if (ao2_container_count(locals) == 0) {
01124       ast_cli(a->fd, "No local channels in use\n");
01125       return RESULT_SUCCESS;
01126    }
01127 
01128    it = ao2_iterator_init(locals, 0);
01129    while ((p = ao2_iterator_next(&it))) {
01130       ao2_lock(p);
01131       ast_cli(a->fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
01132       ao2_unlock(p);
01133       ao2_ref(p, -1);
01134    }
01135    ao2_iterator_destroy(&it);
01136 
01137    return CLI_SUCCESS;
01138 }

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

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

01145 {
01146    const char *channel;
01147    struct local_pvt *p, *tmp = NULL;
01148    struct ast_channel *c;
01149    int found = 0;
01150    struct ao2_iterator it;
01151 
01152    channel = astman_get_header(m, "Channel");
01153 
01154    if (ast_strlen_zero(channel)) {
01155       astman_send_error(s, m, "'Channel' not specified.");
01156       return 0;
01157    }
01158 
01159    c = ast_channel_get_by_name(channel);
01160    if (!c) {
01161       astman_send_error(s, m, "Channel does not exist.");
01162       return 0;
01163    }
01164 
01165    p = c->tech_pvt;
01166    ast_channel_unref(c);
01167    c = NULL;
01168 
01169    it = ao2_iterator_init(locals, 0);
01170    while ((tmp = ao2_iterator_next(&it))) {
01171       if (tmp == p) {
01172          ao2_lock(tmp);
01173          found = 1;
01174          ast_clear_flag(tmp, LOCAL_NO_OPTIMIZATION);
01175          ao2_unlock(tmp);
01176          ao2_ref(tmp, -1);
01177          break;
01178       }
01179       ao2_ref(tmp, -1);
01180    }
01181    ao2_iterator_destroy(&it);
01182 
01183    if (found) {
01184       astman_send_ack(s, m, "Queued channel to be optimized away");
01185    } else {
01186       astman_send_error(s, m, "Unable to find channel");
01187    }
01188 
01189    return 0;
01190 }

static int unload_module ( void   )  [static]

Unload the local proxy channel from Asterisk.

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

01219 {
01220    struct local_pvt *p = NULL;
01221    struct ao2_iterator it;
01222 
01223    /* First, take us out of the channel loop */
01224    ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
01225    ast_manager_unregister("LocalOptimizeAway");
01226    ast_channel_unregister(&local_tech);
01227 
01228    it = ao2_iterator_init(locals, 0);
01229    while ((p = ao2_iterator_next(&it))) {
01230       if (p->owner) {
01231          ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
01232       }
01233       ao2_ref(p, -1);
01234    }
01235    ao2_iterator_destroy(&it);
01236    ao2_ref(locals, -1);
01237 
01238    return 0;
01239 }


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

Definition at line 1245 of file chan_local.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 1245 of file chan_local.c.

const int BUCKET_SIZE = 1 [static]

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

Referenced by load_module(), and unload_module().

struct ast_jb_conf g_jb_conf [static]

Definition at line 83 of file chan_local.c.

Referenced by local_alloc().

struct ast_channel_tech local_tech [static]

Definition at line 109 of file chan_local.c.

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

struct ao2_container* locals [static]

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


Generated on Mon Jun 27 16:51:06 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7