Thu Apr 8 01:22:01 2010

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/rtp.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 dependency graph for chan_local.c:

Go to the source code of this file.

Data Structures

struct  local_pvt
struct  locals

Defines

#define IS_OUTBOUND(a, b)   (a == b->chan ? 1 : 0)
#define LOCAL_ALREADY_MASQED   (1 << 2)
#define LOCAL_BRIDGE   (1 << 5)
#define LOCAL_CANCEL_QUEUE   (1 << 1)
#define LOCAL_GLARE_DETECT   (1 << 0)
#define LOCAL_LAUNCHED_PBX   (1 << 3)
#define LOCAL_MOH_PASSTHRU   (1 << 6)
#define LOCAL_NO_OPTIMIZATION   (1 << 4)

Functions

static void __reg_module (void)
static void __unreg_module (void)
static void check_bridge (struct local_pvt *p, int isoutbound)
static int load_module (void)
 Load module into PBX, register channel.
static struct local_pvtlocal_alloc (const char *data, int 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)
 Start new local channel.
static struct local_pvtlocal_pvt_destroy (struct local_pvt *pvt)
static int local_queue_frame (struct local_pvt *p, int isoutbound, struct ast_frame *f, struct ast_channel *us, int us_locked)
static struct ast_framelocal_read (struct ast_channel *ast)
static struct ast_channellocal_request (const char *type, int format, 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_write (struct ast_channel *ast, struct ast_frame *f)
static char * locals_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command "local show channels".
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_DEFAULT , .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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, }
static struct ast_module_infoast_module_info = &__mod_info
static struct ast_cli_entry cli_local []
static struct ast_jb_conf g_jb_conf
static struct ast_channel_tech local_tech
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 << 2)

Already masqueraded

Definition at line 119 of file chan_local.c.

Referenced by check_bridge(), and local_write().

#define LOCAL_BRIDGE   (1 << 5)

Report back the "true" channel as being bridged to

Definition at line 122 of file chan_local.c.

Referenced by local_alloc(), and local_bridgedchannel().

#define LOCAL_CANCEL_QUEUE   (1 << 1)

Cancel queue

Definition at line 118 of file chan_local.c.

Referenced by local_hangup(), and local_queue_frame().

#define LOCAL_GLARE_DETECT   (1 << 0)

Detect glare on hangup

Definition at line 117 of file chan_local.c.

Referenced by local_hangup(), and local_queue_frame().

#define LOCAL_LAUNCHED_PBX   (1 << 3)

PBX was launched

Definition at line 120 of file chan_local.c.

Referenced by local_call(), and local_hangup().

#define LOCAL_MOH_PASSTHRU   (1 << 6)

Pass through music on hold start/stop frames

Definition at line 123 of file chan_local.c.

Referenced by local_alloc(), and local_indicate().

#define LOCAL_NO_OPTIMIZATION   (1 << 4)

Do not optimize using masquerading

Definition at line 121 of file chan_local.c.

Referenced by check_bridge(), and local_alloc().


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 878 of file chan_local.c.

00878 : used internally by other modules)");

static void __unreg_module ( void   )  [static]

Definition at line 878 of file chan_local.c.

00878 : used internally by other modules)");

static void check_bridge ( struct local_pvt p,
int  isoutbound 
) [static]

Definition at line 289 of file chan_local.c.

References ast_channel::_bridge, ast_app_group_update(), ast_bridged_channel(), ast_channel_masquerade(), ast_channel_trylock, ast_channel_unlock, ast_check_hangup(), AST_LIST_EMPTY, ast_mutex_trylock(), ast_mutex_unlock(), ast_set_flag, ast_test_flag, ast_channel::audiohooks, local_pvt::chan, LOCAL_ALREADY_MASQED, LOCAL_NO_OPTIMIZATION, ast_channel::monitor, and local_pvt::owner.

Referenced by local_write().

00290 {
00291    struct ast_channel_monitor *tmp;
00292    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)))
00293       return;
00294 
00295    /* only do the masquerade if we are being called on the outbound channel,
00296       if it has been bridged to another channel and if there are no pending
00297       frames on the owner channel (because they would be transferred to the
00298       outbound channel during the masquerade)
00299    */
00300    if (isoutbound && p->chan->_bridge /* Not ast_bridged_channel!  Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) {
00301       /* Masquerade bridged channel into owner */
00302       /* Lock everything we need, one by one, and give up if
00303          we can't get everything.  Remember, we'll get another
00304          chance in just a little bit */
00305       if (!ast_channel_trylock(p->chan->_bridge)) {
00306          if (!ast_check_hangup(p->chan->_bridge)) {
00307             if (!ast_channel_trylock(p->owner)) {
00308                if (!ast_check_hangup(p->owner)) {
00309                   if (p->owner->monitor && !p->chan->_bridge->monitor) {
00310                      /* If a local channel is being monitored, we don't want a masquerade
00311                       * to cause the monitor to go away. Since the masquerade swaps the monitors,
00312                       * pre-swapping the monitors before the masquerade will ensure that the monitor
00313                       * ends up where it is expected.
00314                       */
00315                      tmp = p->owner->monitor;
00316                      p->owner->monitor = p->chan->_bridge->monitor;
00317                      p->chan->_bridge->monitor = tmp;
00318                   }
00319                   if (p->chan->audiohooks) {
00320                      struct ast_audiohook_list *audiohooks_swapper;
00321                      audiohooks_swapper = p->chan->audiohooks;
00322                      p->chan->audiohooks = p->owner->audiohooks;
00323                      p->owner->audiohooks = audiohooks_swapper;
00324                   }
00325                   ast_app_group_update(p->chan, p->owner);
00326                   ast_channel_masquerade(p->owner, p->chan->_bridge);
00327                   ast_set_flag(p, LOCAL_ALREADY_MASQED);
00328                }
00329                ast_channel_unlock(p->owner);
00330             }
00331             ast_channel_unlock(p->chan->_bridge);
00332          }
00333       }
00334    /* We only allow masquerading in one 'direction'... it's important to preserve the state
00335       (group variables, etc.) that live on p->chan->_bridge (and were put there by the dialplan)
00336       when the local channels go away.
00337    */
00338 #if 0
00339    } else if (!isoutbound && p->owner && p->owner->_bridge && p->chan && AST_LIST_EMPTY(&p->chan->readq)) {
00340       /* Masquerade bridged channel into chan */
00341       if (!ast_mutex_trylock(&(p->owner->_bridge)->lock)) {
00342          if (!ast_check_hangup(p->owner->_bridge)) {
00343             if (!ast_mutex_trylock(&p->chan->lock)) {
00344                if (!ast_check_hangup(p->chan)) {
00345                   ast_channel_masquerade(p->chan, p->owner->_bridge);
00346                   ast_set_flag(p, LOCAL_ALREADY_MASQED);
00347                }
00348                ast_mutex_unlock(&p->chan->lock);
00349             }
00350          }
00351          ast_mutex_unlock(&(p->owner->_bridge)->lock);
00352       }
00353 #endif
00354    }
00355 }

static int load_module ( void   )  [static]

Load module into PBX, register channel.

Definition at line 845 of file chan_local.c.

References ast_channel_register(), ast_cli_register_multiple(), ast_log(), AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, cli_local, and LOG_ERROR.

00846 {
00847    /* Make sure we can register our channel type */
00848    if (ast_channel_register(&local_tech)) {
00849       ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
00850       return AST_MODULE_LOAD_FAILURE;
00851    }
00852    ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00853    return AST_MODULE_LOAD_SUCCESS;
00854 }

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

Create a call structure.

Definition at line 661 of file chan_local.c.

References ast_calloc, ast_copy_string(), ast_exists_extension(), AST_JB_ENABLED, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_mutex_init(), ast_set_flag, ast_test_flag, local_pvt::context, local_pvt::exten, local_pvt::jb_conf, LOCAL_BRIDGE, LOCAL_MOH_PASSTHRU, LOCAL_NO_OPTIMIZATION, local_pvt_destroy(), local_pvt::lock, LOG_ERROR, LOG_NOTICE, and local_pvt::reqformat.

Referenced by local_request().

00662 {
00663    struct local_pvt *tmp = NULL;
00664    char *c = NULL, *opts = NULL;
00665 
00666    if (!(tmp = ast_calloc(1, sizeof(*tmp))))
00667       return NULL;
00668 
00669    /* Initialize private structure information */
00670    ast_mutex_init(&tmp->lock);
00671    ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
00672 
00673    memcpy(&tmp->jb_conf, &g_jb_conf, sizeof(tmp->jb_conf));
00674 
00675    /* Look for options */
00676    if ((opts = strchr(tmp->exten, '/'))) {
00677       *opts++ = '\0';
00678       if (strchr(opts, 'n'))
00679          ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
00680       if (strchr(opts, 'j')) {
00681          if (ast_test_flag(tmp, LOCAL_NO_OPTIMIZATION))
00682             ast_set_flag(&tmp->jb_conf, AST_JB_ENABLED);
00683          else {
00684             ast_log(LOG_ERROR, "You must use the 'n' option for chan_local "
00685                "to use the 'j' option to enable the jitterbuffer\n");
00686          }
00687       }
00688       if (strchr(opts, 'b')) {
00689          ast_set_flag(tmp, LOCAL_BRIDGE);
00690       }
00691       if (strchr(opts, 'm')) {
00692          ast_set_flag(tmp, LOCAL_MOH_PASSTHRU);
00693       }
00694    }
00695 
00696    /* Look for a context */
00697    if ((c = strchr(tmp->exten, '@')))
00698       *c++ = '\0';
00699 
00700    ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
00701 
00702    tmp->reqformat = format;
00703 
00704 #if 0
00705    /* We can't do this check here, because we don't know the CallerID yet, and
00706     * the CallerID could potentially affect what step is actually taken (or
00707     * even if that step exists). */
00708    if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
00709       ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
00710       tmp = local_pvt_destroy(tmp);
00711    } else {
00712 #endif
00713       /* Add to list */
00714       AST_LIST_LOCK(&locals);
00715       AST_LIST_INSERT_HEAD(&locals, tmp, list);
00716       AST_LIST_UNLOCK(&locals);
00717 #if 0
00718    }
00719 #endif
00720    
00721    return tmp;
00722 }

static int local_answer ( struct ast_channel ast  )  [static]

Definition at line 267 of file chan_local.c.

References AST_CONTROL_ANSWER, AST_FRAME_CONTROL, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), IS_OUTBOUND, local_queue_frame(), local_pvt::lock, LOG_WARNING, and ast_channel::tech_pvt.

00268 {
00269    struct local_pvt *p = ast->tech_pvt;
00270    int isoutbound;
00271    int res = -1;
00272 
00273    if (!p)
00274       return -1;
00275 
00276    ast_mutex_lock(&p->lock);
00277    isoutbound = IS_OUTBOUND(ast, p);
00278    if (isoutbound) {
00279       /* Pass along answer since somebody answered us */
00280       struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
00281       res = local_queue_frame(p, isoutbound, &answer, ast, 1);
00282    } else
00283       ast_log(LOG_WARNING, "Huh?  Local is being asked to answer?\n");
00284    if (!res)
00285       ast_mutex_unlock(&p->lock);
00286    return res;
00287 }

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

References ast_channel::_bridge, ast_debug, ast_mutex_lock(), ast_mutex_unlock(), ast_test_flag, local_pvt::chan, LOCAL_BRIDGE, local_pvt::lock, local_pvt::owner, and ast_channel::tech_pvt.

00177 {
00178    struct local_pvt *p = bridge->tech_pvt;
00179    struct ast_channel *bridged = bridge;
00180 
00181    if (!p) {
00182       ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning <none>\n",
00183          chan->name, bridge->name);
00184       return NULL;
00185    }
00186 
00187    ast_mutex_lock(&p->lock);
00188 
00189    if (ast_test_flag(p, LOCAL_BRIDGE)) {
00190       /* Find the opposite channel */
00191       bridged = (bridge == p->owner ? p->chan : p->owner);
00192       
00193       /* Now see if the opposite channel is bridged to anything */
00194       if (!bridged) {
00195          bridged = bridge;
00196       } else if (bridged->_bridge) {
00197          bridged = bridged->_bridge;
00198       }
00199    }
00200 
00201    ast_mutex_unlock(&p->lock);
00202 
00203    return bridged;
00204 }

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

References accountcode, ast_calloc, ast_cdr_update(), ast_channel_datastore_inherit(), ast_exists_extension(), AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_pbx_start(), ast_set_flag, ast_strdup, ast_string_field_set, ast_channel::cdrflags, local_pvt::chan, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_ani2, ast_callerid::cid_dnid, ast_callerid::cid_name, ast_callerid::cid_num, ast_callerid::cid_pres, ast_callerid::cid_rdnis, ast_callerid::cid_tns, ast_callerid::cid_ton, ast_channel::context, ast_channel::exten, language, len(), LOCAL_LAUNCHED_PBX, local_pvt::lock, LOG_NOTICE, musicclass, ast_var_t::name, local_pvt::owner, ast_channel::tech_pvt, and ast_channel::varshead.

00519 {
00520    struct local_pvt *p = ast->tech_pvt;
00521    int res;
00522    struct ast_var_t *varptr = NULL, *new;
00523    size_t len, namelen;
00524 
00525    if (!p)
00526       return -1;
00527    
00528    ast_mutex_lock(&p->lock);
00529 
00530    /*
00531     * Note that cid_num and cid_name aren't passed in the ast_channel_alloc
00532     * call, so it's done here instead.
00533     */
00534    p->chan->cid.cid_dnid = ast_strdup(p->owner->cid.cid_dnid);
00535    p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num);
00536    p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name);
00537    p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis);
00538    p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani);
00539    p->chan->cid.cid_pres = p->owner->cid.cid_pres;
00540    p->chan->cid.cid_ani2 = p->owner->cid.cid_ani2;
00541    p->chan->cid.cid_ton = p->owner->cid.cid_ton;
00542    p->chan->cid.cid_tns = p->owner->cid.cid_tns;
00543    ast_string_field_set(p->chan, language, p->owner->language);
00544    ast_string_field_set(p->chan, accountcode, p->owner->accountcode);
00545    ast_string_field_set(p->chan, musicclass, p->owner->musicclass);
00546    ast_cdr_update(p->chan);
00547    p->chan->cdrflags = p->owner->cdrflags;
00548 
00549    if (!ast_exists_extension(NULL, p->chan->context, p->chan->exten, 1, p->owner->cid.cid_num)) {
00550       ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->chan->exten, p->chan->context);
00551       ast_mutex_unlock(&p->lock);
00552       return -1;
00553    }
00554 
00555    /* copy the channel variables from the incoming channel to the outgoing channel */
00556    /* Note that due to certain assumptions, they MUST be in the same order */
00557    AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) {
00558       namelen = strlen(varptr->name);
00559       len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
00560       if ((new = ast_calloc(1, len))) {
00561          memcpy(new, varptr, len);
00562          new->value = &(new->name[0]) + namelen + 1;
00563          AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries);
00564       }
00565    }
00566    ast_channel_datastore_inherit(p->owner, p->chan);
00567 
00568    /* Start switch on sub channel */
00569    if (!(res = ast_pbx_start(p->chan)))
00570       ast_set_flag(p, LOCAL_LAUNCHED_PBX);
00571 
00572    ast_mutex_unlock(&p->lock);
00573    return res;
00574 }

static int local_devicestate ( void *  data  )  [static]

Adds devicestate to local channels.

Definition at line 128 of file chan_local.c.

References ast_debug, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, ast_exists_extension(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_strdupa, local_pvt::context, local_pvt::exten, LOG_WARNING, and local_pvt::owner.

00129 {
00130    char *exten = ast_strdupa(data);
00131    char *context = NULL, *opts = NULL;
00132    int res;
00133    struct local_pvt *lp;
00134 
00135    if (!(context = strchr(exten, '@'))) {
00136       ast_log(LOG_WARNING, "Someone used Local/%s somewhere without a @context. This is bad.\n", exten);
00137       return AST_DEVICE_INVALID; 
00138    }
00139 
00140    *context++ = '\0';
00141 
00142    /* Strip options if they exist */
00143    if ((opts = strchr(context, '/')))
00144       *opts = '\0';
00145 
00146    ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
00147 
00148    res = ast_exists_extension(NULL, context, exten, 1, NULL);
00149    if (!res)      
00150       return AST_DEVICE_INVALID;
00151    
00152    res = AST_DEVICE_NOT_INUSE;
00153    AST_LIST_LOCK(&locals);
00154    AST_LIST_TRAVERSE(&locals, lp, list) {
00155       if (!strcmp(exten, lp->exten) && !strcmp(context, lp->context) && lp->owner) {
00156          res = AST_DEVICE_INUSE;
00157          break;
00158       }
00159    }
00160    AST_LIST_UNLOCK(&locals);
00161 
00162    return res;
00163 }

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

Definition at line 438 of file chan_local.c.

References AST_FRAME_DTMF_BEGIN, ast_mutex_lock(), ast_mutex_unlock(), IS_OUTBOUND, local_queue_frame(), local_pvt::lock, ast_frame::subclass, and ast_channel::tech_pvt.

00439 {
00440    struct local_pvt *p = ast->tech_pvt;
00441    int res = -1;
00442    struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
00443    int isoutbound;
00444 
00445    if (!p)
00446       return -1;
00447 
00448    ast_mutex_lock(&p->lock);
00449    isoutbound = IS_OUTBOUND(ast, p);
00450    f.subclass = digit;
00451    if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00452       ast_mutex_unlock(&p->lock);
00453 
00454    return res;
00455 }

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

Definition at line 457 of file chan_local.c.

References AST_FRAME_DTMF_END, ast_mutex_lock(), ast_mutex_unlock(), IS_OUTBOUND, ast_frame::len, local_queue_frame(), local_pvt::lock, ast_frame::subclass, and ast_channel::tech_pvt.

00458 {
00459    struct local_pvt *p = ast->tech_pvt;
00460    int res = -1;
00461    struct ast_frame f = { AST_FRAME_DTMF_END, };
00462    int isoutbound;
00463 
00464    if (!p)
00465       return -1;
00466 
00467    ast_mutex_lock(&p->lock);
00468    isoutbound = IS_OUTBOUND(ast, p);
00469    f.subclass = digit;
00470    f.len = duration;
00471    if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00472       ast_mutex_unlock(&p->lock);
00473 
00474    return res;
00475 }

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

Definition at line 387 of file chan_local.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), local_pvt::chan, local_pvt::lock, LOG_WARNING, local_pvt::owner, and ast_channel::tech_pvt.

00388 {
00389    struct local_pvt *p = newchan->tech_pvt;
00390 
00391    if (!p)
00392       return -1;
00393 
00394    ast_mutex_lock(&p->lock);
00395 
00396    if ((p->owner != oldchan) && (p->chan != oldchan)) {
00397       ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
00398       ast_mutex_unlock(&p->lock);
00399       return -1;
00400    }
00401    if (p->owner == oldchan)
00402       p->owner = newchan;
00403    else
00404       p->chan = newchan;
00405    ast_mutex_unlock(&p->lock);
00406    return 0;
00407 }

static int local_hangup ( struct ast_channel ast  )  [static]

Hangup a call through the local proxy channel.

Definition at line 577 of file chan_local.c.

References ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_clear_flag, AST_CONTROL_HANGUP, AST_FLAG_ANSWERED_ELSEWHERE, AST_FRAME_CONTROL, ast_hangup(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_module_user_remove, ast_mutex_lock(), ast_mutex_unlock(), ast_queue_hangup(), ast_set_flag, ast_test_flag, local_pvt::chan, DEADLOCK_AVOIDANCE, ast_channel::hangupcause, IS_OUTBOUND, LOCAL_CANCEL_QUEUE, LOCAL_GLARE_DETECT, LOCAL_LAUNCHED_PBX, local_pvt_destroy(), local_queue_frame(), local_pvt::lock, 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.

00578 {
00579    struct local_pvt *p = ast->tech_pvt;
00580    int isoutbound;
00581    struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP, .data.uint32 = ast->hangupcause };
00582    struct ast_channel *ochan = NULL;
00583    int glaredetect = 0, res = 0;
00584 
00585    if (!p)
00586       return -1;
00587 
00588    ast_mutex_lock(&p->lock);
00589 
00590    if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) 
00591       ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE);
00592    isoutbound = IS_OUTBOUND(ast, p);
00593    if (isoutbound) {
00594       const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
00595       if ((status) && (p->owner)) {
00596          /* Deadlock avoidance */
00597          while (p->owner && ast_channel_trylock(p->owner)) {
00598             ast_mutex_unlock(&p->lock);
00599             if (ast) {
00600                ast_channel_unlock(ast);
00601             }
00602             usleep(1);
00603             if (ast) {
00604                ast_channel_lock(ast);
00605             }
00606             ast_mutex_lock(&p->lock);
00607          }
00608          if (p->owner) {
00609             pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
00610             ast_channel_unlock(p->owner);
00611          }
00612       }
00613       p->chan = NULL;
00614       ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
00615       ast_module_user_remove(p->u_chan);
00616    } else {
00617       ast_module_user_remove(p->u_owner);
00618       while (p->chan && ast_channel_trylock(p->chan)) {
00619          DEADLOCK_AVOIDANCE(&p->lock);
00620       }
00621       p->owner = NULL;
00622       if (p->chan) {
00623          ast_queue_hangup(p->chan);
00624          ast_channel_unlock(p->chan);
00625       }
00626    }
00627    
00628    ast->tech_pvt = NULL;
00629    
00630    if (!p->owner && !p->chan) {
00631       /* Okay, done with the private part now, too. */
00632       glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT);
00633       /* If we have a queue holding, don't actually destroy p yet, but
00634          let local_queue do it. */
00635       if (glaredetect)
00636          ast_set_flag(p, LOCAL_CANCEL_QUEUE);
00637       /* Remove from list */
00638       AST_LIST_LOCK(&locals);
00639       AST_LIST_REMOVE(&locals, p, list);
00640       AST_LIST_UNLOCK(&locals);
00641       ast_mutex_unlock(&p->lock);
00642       /* And destroy */
00643       if (!glaredetect) {
00644          p = local_pvt_destroy(p);
00645       }
00646       return 0;
00647    }
00648    if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX))
00649       /* Need to actually hangup since there is no PBX */
00650       ochan = p->chan;
00651    else
00652       res = local_queue_frame(p, isoutbound, &f, NULL, 1);
00653    if (!res)
00654       ast_mutex_unlock(&p->lock);
00655    if (ochan)
00656       ast_hangup(ochan);
00657    return 0;
00658 }

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

Definition at line 409 of file chan_local.c.

References AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, ast_moh_start(), ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_test_flag, ast_frame::data, ast_frame::datalen, IS_OUTBOUND, LOCAL_MOH_PASSTHRU, local_queue_frame(), local_pvt::lock, ast_frame::ptr, ast_frame::subclass, and ast_channel::tech_pvt.

00410 {
00411    struct local_pvt *p = ast->tech_pvt;
00412    int res = 0;
00413    struct ast_frame f = { AST_FRAME_CONTROL, };
00414    int isoutbound;
00415 
00416    if (!p)
00417       return -1;
00418 
00419    /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */
00420    if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) {
00421       ast_moh_start(ast, data, NULL);
00422    } else if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_UNHOLD) {
00423       ast_moh_stop(ast);
00424    } else {
00425       /* Queue up a frame representing the indication as a control frame */
00426       ast_mutex_lock(&p->lock);
00427       isoutbound = IS_OUTBOUND(ast, p);
00428       f.subclass = condition;
00429       f.data.ptr = (void*)data;
00430       f.datalen = datalen;
00431       if (!(res = local_queue_frame(p, isoutbound, &f, ast, 1)))
00432          ast_mutex_unlock(&p->lock);
00433    }
00434 
00435    return res;
00436 }

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

Start new local channel.

Definition at line 725 of file chan_local.c.

References ast_channel::amaflags, ast_best_codec(), ast_channel_alloc, ast_channel_free(), 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, 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().

00726 {
00727    struct ast_channel *tmp = NULL, *tmp2 = NULL;
00728    int randnum = ast_random() & 0xffff, fmt = 0;
00729    const char *t;
00730    int ama;
00731 
00732    /* Allocate two new Asterisk channels */
00733    /* safe accountcode */
00734    if (p->owner && p->owner->accountcode)
00735       t = p->owner->accountcode;
00736    else
00737       t = "";
00738 
00739    if (p->owner)
00740       ama = p->owner->amaflags;
00741    else
00742       ama = 0;
00743    if (!(tmp = ast_channel_alloc(1, state, 0, 0, t, p->exten, p->context, ama, "Local/%s@%s-%04x;1", p->exten, p->context, randnum)) 
00744          || !(tmp2 = ast_channel_alloc(1, AST_STATE_RING, 0, 0, t, p->exten, p->context, ama, "Local/%s@%s-%04x;2", p->exten, p->context, randnum))) {
00745       if (tmp)
00746          ast_channel_free(tmp);
00747       if (tmp2)
00748          ast_channel_free(tmp2);
00749       ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
00750       return NULL;
00751    } 
00752 
00753    tmp2->tech = tmp->tech = &local_tech;
00754 
00755    tmp->nativeformats = p->reqformat;
00756    tmp2->nativeformats = p->reqformat;
00757 
00758    /* Determine our read/write format and set it on each channel */
00759    fmt = ast_best_codec(p->reqformat);
00760    tmp->writeformat = fmt;
00761    tmp2->writeformat = fmt;
00762    tmp->rawwriteformat = fmt;
00763    tmp2->rawwriteformat = fmt;
00764    tmp->readformat = fmt;
00765    tmp2->readformat = fmt;
00766    tmp->rawreadformat = fmt;
00767    tmp2->rawreadformat = fmt;
00768 
00769    tmp->tech_pvt = p;
00770    tmp2->tech_pvt = p;
00771 
00772    p->owner = tmp;
00773    p->chan = tmp2;
00774    p->u_owner = ast_module_user_add(p->owner);
00775    p->u_chan = ast_module_user_add(p->chan);
00776 
00777    ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
00778    ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
00779    ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten));
00780    tmp->priority = 1;
00781    tmp2->priority = 1;
00782 
00783    ast_jb_configure(tmp, &p->jb_conf);
00784 
00785    return tmp;
00786 }

static struct local_pvt* local_pvt_destroy ( struct local_pvt pvt  )  [static, read]
Note:
Assumes the pvt is no longer in the pvts list

Definition at line 168 of file chan_local.c.

References ast_free, ast_mutex_destroy(), and local_pvt::lock.

Referenced by local_alloc(), local_hangup(), local_queue_frame(), and local_request().

00169 {
00170    ast_mutex_destroy(&pvt->lock);
00171    ast_free(pvt);
00172    return NULL;
00173 }

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

Definition at line 206 of file chan_local.c.

References ast_channel_trylock, ast_channel_unlock, ast_clear_flag, AST_CONTROL_RINGING, AST_FRAME_CONTROL, ast_mutex_lock(), ast_mutex_trylock(), ast_mutex_unlock(), ast_queue_frame(), ast_set_flag, ast_setstate(), AST_STATE_RINGING, ast_test_flag, local_pvt::chan, CHANNEL_DEADLOCK_AVOIDANCE, ast_frame::frametype, ast_channel::generator, LOCAL_CANCEL_QUEUE, LOCAL_GLARE_DETECT, local_pvt_destroy(), local_pvt::lock, 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().

00208 {
00209    struct ast_channel *other = NULL;
00210 
00211    /* Recalculate outbound channel */
00212    other = isoutbound ? p->owner : p->chan;
00213 
00214    if (!other) {
00215       return 0;
00216    }
00217 
00218    /* do not queue frame if generator is on both local channels */
00219    if (us && us->generator && other->generator) {
00220       return 0;
00221    }
00222 
00223    /* Set glare detection */
00224    ast_set_flag(p, LOCAL_GLARE_DETECT);
00225 
00226    /* Ensure that we have both channels locked */
00227    while (other && ast_channel_trylock(other)) {
00228       ast_mutex_unlock(&p->lock);
00229       if (us && us_locked) {
00230          do {
00231             CHANNEL_DEADLOCK_AVOIDANCE(us);
00232          } while (ast_mutex_trylock(&p->lock));
00233       } else {
00234          usleep(1);
00235          ast_mutex_lock(&p->lock);
00236       }
00237       other = isoutbound ? p->owner : p->chan;
00238    }
00239 
00240    /* Since glare detection only occurs within this function, and because
00241     * a pvt flag cannot be set without having the pvt lock, this is the only
00242     * location where we could detect a cancelling of the queue. */
00243    if (ast_test_flag(p, LOCAL_CANCEL_QUEUE)) {
00244       /* We had a glare on the hangup.  Forget all this business,
00245       return and destroy p.  */
00246       ast_mutex_unlock(&p->lock);
00247       p = local_pvt_destroy(p);
00248       if (other) {
00249          ast_channel_unlock(other);
00250       }
00251       return -1;
00252    }
00253 
00254    if (other) {
00255       if (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_RINGING) {
00256          ast_setstate(other, AST_STATE_RINGING);
00257       }
00258       ast_queue_frame(other, f);
00259       ast_channel_unlock(other);
00260    }
00261 
00262    ast_clear_flag(p, LOCAL_GLARE_DETECT);
00263 
00264    return 0;
00265 }

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

Definition at line 357 of file chan_local.c.

References ast_null_frame.

00358 {
00359    return &ast_null_frame;
00360 }

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

Part of PBX interface.

Definition at line 789 of file chan_local.c.

References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, AST_STATE_DOWN, local_pvt::chan, local_alloc(), local_new(), and local_pvt_destroy().

00790 {
00791    struct local_pvt *p = NULL;
00792    struct ast_channel *chan = NULL;
00793 
00794    /* Allocate a new private structure and then Asterisk channel */
00795    if ((p = local_alloc(data, format))) {
00796       if (!(chan = local_new(p, AST_STATE_DOWN))) {
00797          AST_LIST_LOCK(&locals);
00798          AST_LIST_REMOVE(&locals, p, list);
00799          AST_LIST_UNLOCK(&locals);
00800          p = local_pvt_destroy(p);
00801       }
00802    }
00803 
00804    return chan;
00805 }

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

Definition at line 496 of file chan_local.c.

References AST_FRAME_HTML, ast_mutex_lock(), ast_mutex_unlock(), ast_frame::data, ast_frame::datalen, IS_OUTBOUND, local_queue_frame(), local_pvt::lock, ast_frame::ptr, ast_frame::subclass, and ast_channel::tech_pvt.

00497 {
00498    struct local_pvt *p = ast->tech_pvt;
00499    int res = -1;
00500    struct ast_frame f = { AST_FRAME_HTML, };
00501    int isoutbound;
00502 
00503    if (!p)
00504       return -1;
00505    
00506    ast_mutex_lock(&p->lock);
00507    isoutbound = IS_OUTBOUND(ast, p);
00508    f.subclass = subclass;
00509    f.data.ptr = (char *)data;
00510    f.datalen = datalen;
00511    if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00512       ast_mutex_unlock(&p->lock);
00513    return res;
00514 }

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

Definition at line 477 of file chan_local.c.

References AST_FRAME_TEXT, ast_mutex_lock(), ast_mutex_unlock(), ast_frame::data, ast_frame::datalen, IS_OUTBOUND, local_queue_frame(), local_pvt::lock, ast_frame::ptr, and ast_channel::tech_pvt.

00478 {
00479    struct local_pvt *p = ast->tech_pvt;
00480    int res = -1;
00481    struct ast_frame f = { AST_FRAME_TEXT, };
00482    int isoutbound;
00483 
00484    if (!p)
00485       return -1;
00486 
00487    ast_mutex_lock(&p->lock);
00488    isoutbound = IS_OUTBOUND(ast, p);
00489    f.data.ptr = (char *) text;
00490    f.datalen = strlen(text) + 1;
00491    if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00492       ast_mutex_unlock(&p->lock);
00493    return res;
00494 }

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

Definition at line 362 of file chan_local.c.

References ast_debug, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_mutex_lock(), ast_mutex_unlock(), ast_test_flag, check_bridge(), ast_frame::frametype, IS_OUTBOUND, LOCAL_ALREADY_MASQED, local_queue_frame(), local_pvt::lock, and ast_channel::tech_pvt.

00363 {
00364    struct local_pvt *p = ast->tech_pvt;
00365    int res = -1;
00366    int isoutbound;
00367 
00368    if (!p)
00369       return -1;
00370 
00371    /* Just queue for delivery to the other side */
00372    ast_mutex_lock(&p->lock);
00373    isoutbound = IS_OUTBOUND(ast, p);
00374    if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO))
00375       check_bridge(p, isoutbound);
00376    if (!ast_test_flag(p, LOCAL_ALREADY_MASQED))
00377       res = local_queue_frame(p, isoutbound, f, ast, 1);
00378    else {
00379       ast_debug(1, "Not posting to queue since already masked on '%s'\n", ast->name);
00380       res = 0;
00381    }
00382    if (!res)
00383       ast_mutex_unlock(&p->lock);
00384    return res;
00385 }

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

References ast_cli_args::argc, ast_cli(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, local_pvt::context, local_pvt::exten, ast_cli_args::fd, local_pvt::lock, local_pvt::owner, and ast_cli_entry::usage.

00809 {
00810    struct local_pvt *p = NULL;
00811 
00812    switch (cmd) {
00813    case CLI_INIT:
00814       e->command = "local show channels";
00815       e->usage =
00816          "Usage: local show channels\n"
00817          "       Provides summary information on active local proxy channels.\n";
00818       return NULL;
00819    case CLI_GENERATE:
00820       return NULL;
00821    }
00822 
00823    if (a->argc != 3)
00824       return CLI_SHOWUSAGE;
00825 
00826    AST_LIST_LOCK(&locals);
00827    if (!AST_LIST_EMPTY(&locals)) {
00828       AST_LIST_TRAVERSE(&locals, p, list) {
00829          ast_mutex_lock(&p->lock);
00830          ast_cli(a->fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
00831          ast_mutex_unlock(&p->lock);
00832       }
00833    } else
00834       ast_cli(a->fd, "No local channels in use\n");
00835    AST_LIST_UNLOCK(&locals);
00836 
00837    return CLI_SUCCESS;
00838 }

static int unload_module ( void   )  [static]

Unload the local proxy channel from Asterisk.

Definition at line 857 of file chan_local.c.

References ast_channel_unregister(), ast_cli_unregister_multiple(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, cli_local, LOG_WARNING, and local_pvt::owner.

00858 {
00859    struct local_pvt *p = NULL;
00860 
00861    /* First, take us out of the channel loop */
00862    ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00863    ast_channel_unregister(&local_tech);
00864    if (!AST_LIST_LOCK(&locals)) {
00865       /* Hangup all interfaces if they have an owner */
00866       AST_LIST_TRAVERSE(&locals, p, list) {
00867          if (p->owner)
00868             ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
00869       }
00870       AST_LIST_UNLOCK(&locals);
00871    } else {
00872       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
00873       return -1;
00874    }     
00875    return 0;
00876 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, } [static]

Definition at line 878 of file chan_local.c.

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

Referenced by load_module(), and unload_module().

struct ast_jb_conf g_jb_conf [static]

Definition at line 57 of file chan_local.c.

struct ast_channel_tech local_tech [static]

Definition at line 81 of file chan_local.c.

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

Definition at line 53 of file chan_local.c.


Generated on 8 Apr 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1