Tue Mar 2 17:32:53 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 118 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 121 of file chan_local.c.

Referenced by local_alloc(), and local_bridgedchannel().

#define LOCAL_CANCEL_QUEUE   (1 << 1)

Cancel queue

Definition at line 117 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 116 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 119 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 122 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 120 of file chan_local.c.

Referenced by check_bridge(), and local_alloc().


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 876 of file chan_local.c.

00876 : used internally by other modules)");

static void __unreg_module ( void   )  [static]

Definition at line 876 of file chan_local.c.

00876 : used internally by other modules)");

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

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

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

static int load_module ( void   )  [static]

Load module into PBX, register channel.

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

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

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

Create a call structure.

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

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

static int local_answer ( struct ast_channel ast  )  [static]

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

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

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

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

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

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

static int local_devicestate ( void *  data  )  [static]

Adds devicestate to local channels.

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

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

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

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

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

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

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

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

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

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

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

static int local_hangup ( struct ast_channel ast  )  [static]

Hangup a call through the local proxy channel.

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

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

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

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

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

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

Start new local channel.

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

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

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 167 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().

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

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

References ast_channel::_bridge, ast_channel::appl, ast_channel_trylock, ast_channel_unlock, ast_clear_flag, ast_mutex_lock(), ast_mutex_trylock(), ast_mutex_unlock(), ast_queue_frame(), ast_set_flag, ast_strlen_zero(), ast_test_flag, local_pvt::chan, CHANNEL_DEADLOCK_AVOIDANCE, ast_channel::generator, LOCAL_CANCEL_QUEUE, LOCAL_GLARE_DETECT, local_pvt_destroy(), local_pvt::lock, local_pvt::owner, and ast_channel::pbx.

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

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

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

Definition at line 355 of file chan_local.c.

References ast_null_frame.

00356 {
00357    return &ast_null_frame;
00358 }

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

Part of PBX interface.

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

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

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

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

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

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

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

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

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

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

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

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

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

static int unload_module ( void   )  [static]

Unload the local proxy channel from Asterisk.

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

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


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

Definition at line 876 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 838 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 80 of file chan_local.c.

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

Definition at line 53 of file chan_local.c.


Generated on 2 Mar 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1