Wed Aug 18 22:34:10 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"

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)
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)

Definition at line 55 of file chan_local.c.

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

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

00871 : used internally by other modules)");

static void __unreg_module ( void   )  [static]

Definition at line 871 of file chan_local.c.

00871 : used internally by other modules)");

static void check_bridge ( struct local_pvt p  )  [static]

Definition at line 293 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_set_flag, ast_test_flag, ast_channel::audiohooks, local_pvt::chan, LOCAL_ALREADY_MASQED, LOCAL_NO_OPTIMIZATION, ast_channel::monitor, local_pvt::owner, and ast_channel::readq.

Referenced by local_write().

00294 {
00295    struct ast_channel_monitor *tmp;
00296    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)))
00297       return;
00298 
00299    /* only do the masquerade if we are being called on the outbound channel,
00300       if it has been bridged to another channel and if there are no pending
00301       frames on the owner channel (because they would be transferred to the
00302       outbound channel during the masquerade)
00303    */
00304    if (p->chan->_bridge /* Not ast_bridged_channel!  Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) {
00305       /* Masquerade bridged channel into owner */
00306       /* Lock everything we need, one by one, and give up if
00307          we can't get everything.  Remember, we'll get another
00308          chance in just a little bit */
00309       if (!ast_channel_trylock(p->chan->_bridge)) {
00310          if (!ast_check_hangup(p->chan->_bridge)) {
00311             if (!ast_channel_trylock(p->owner)) {
00312                if (!ast_check_hangup(p->owner)) {
00313                   if (p->owner->monitor && !p->chan->_bridge->monitor) {
00314                      /* If a local channel is being monitored, we don't want a masquerade
00315                       * to cause the monitor to go away. Since the masquerade swaps the monitors,
00316                       * pre-swapping the monitors before the masquerade will ensure that the monitor
00317                       * ends up where it is expected.
00318                       */
00319                      tmp = p->owner->monitor;
00320                      p->owner->monitor = p->chan->_bridge->monitor;
00321                      p->chan->_bridge->monitor = tmp;
00322                   }
00323                   if (p->chan->audiohooks) {
00324                      struct ast_audiohook_list *audiohooks_swapper;
00325                      audiohooks_swapper = p->chan->audiohooks;
00326                      p->chan->audiohooks = p->owner->audiohooks;
00327                      p->owner->audiohooks = audiohooks_swapper;
00328                   }
00329                   ast_app_group_update(p->chan, p->owner);
00330                   ast_channel_masquerade(p->owner, p->chan->_bridge);
00331                   ast_set_flag(p, LOCAL_ALREADY_MASQED);
00332                }
00333                ast_channel_unlock(p->owner);
00334             }
00335             ast_channel_unlock(p->chan->_bridge);
00336          }
00337       }
00338    }
00339 }

static int load_module ( void   )  [static]

Load module into PBX, register channel.

Definition at line 838 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, local_tech, and LOG_ERROR.

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

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

Create a call structure.

Definition at line 654 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, g_jb_conf, local_pvt::list, LOCAL_BRIDGE, LOCAL_MOH_PASSTHRU, LOCAL_NO_OPTIMIZATION, local_pvt_destroy(), LOG_ERROR, and LOG_NOTICE.

Referenced by local_request().

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

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]

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, ast_channel::name, 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 502 of file chan_local.c.

References ast_channel::accountcode, 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_var_t::entries, ast_channel::exten, ast_channel::language, language, len(), LOCAL_LAUNCHED_PBX, local_pvt::lock, LOG_NOTICE, ast_channel::musicclass, musicclass, ast_var_t::name, local_pvt::owner, ast_channel::tech_pvt, ast_var_t::value, and ast_channel::varshead.

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

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, local_pvt::list, 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 422 of file chan_local.c.

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

00423 {
00424    struct local_pvt *p = ast->tech_pvt;
00425    int res = -1;
00426    struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
00427    int isoutbound;
00428 
00429    if (!p)
00430       return -1;
00431 
00432    ast_mutex_lock(&p->lock);
00433    isoutbound = IS_OUTBOUND(ast, p);
00434    f.subclass = digit;
00435    if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00436       ast_mutex_unlock(&p->lock);
00437 
00438    return res;
00439 }

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

Definition at line 441 of file chan_local.c.

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

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

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

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

00372 {
00373    struct local_pvt *p = newchan->tech_pvt;
00374 
00375    if (!p)
00376       return -1;
00377 
00378    ast_mutex_lock(&p->lock);
00379 
00380    if ((p->owner != oldchan) && (p->chan != oldchan)) {
00381       ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
00382       ast_mutex_unlock(&p->lock);
00383       return -1;
00384    }
00385    if (p->owner == oldchan)
00386       p->owner = newchan;
00387    else
00388       p->chan = newchan;
00389    ast_mutex_unlock(&p->lock);
00390    return 0;
00391 }

static int local_hangup ( struct ast_channel ast  )  [static]

Hangup a call through the local proxy channel.

Definition at line 561 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, f, ast_channel::hangupcause, IS_OUTBOUND, local_pvt::list, 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.

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

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

Definition at line 393 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, f, IS_OUTBOUND, LOCAL_MOH_PASSTHRU, local_queue_frame(), local_pvt::lock, and ast_channel::tech_pvt.

00394 {
00395    struct local_pvt *p = ast->tech_pvt;
00396    int res = 0;
00397    struct ast_frame f = { AST_FRAME_CONTROL, };
00398    int isoutbound;
00399 
00400    if (!p)
00401       return -1;
00402 
00403    /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */
00404    if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) {
00405       ast_moh_start(ast, data, NULL);
00406    } else if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_UNHOLD) {
00407       ast_moh_stop(ast);
00408    } else {
00409       /* Queue up a frame representing the indication as a control frame */
00410       ast_mutex_lock(&p->lock);
00411       isoutbound = IS_OUTBOUND(ast, p);
00412       f.subclass = condition;
00413       f.data.ptr = (void*)data;
00414       f.datalen = datalen;
00415       if (!(res = local_queue_frame(p, isoutbound, &f, ast, 1)))
00416          ast_mutex_unlock(&p->lock);
00417    }
00418 
00419    return res;
00420 }

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

Start new local channel.

Definition at line 718 of file chan_local.c.

References ast_channel::accountcode, 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, 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().

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

static struct local_pvt* local_pvt_destroy ( struct local_pvt pvt  )  [static]

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, f, ast_channel::generator, LOCAL_CANCEL_QUEUE, LOCAL_GLARE_DETECT, local_pvt_destroy(), local_pvt::lock, 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().

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]

Definition at line 341 of file chan_local.c.

References ast_null_frame.

00342 {
00343    return &ast_null_frame;
00344 }

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

Part of PBX interface.

Definition at line 782 of file chan_local.c.

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

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

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

Definition at line 480 of file chan_local.c.

References AST_FRAME_HTML, ast_mutex_lock(), ast_mutex_unlock(), f, IS_OUTBOUND, local_queue_frame(), local_pvt::lock, and ast_channel::tech_pvt.

00481 {
00482    struct local_pvt *p = ast->tech_pvt;
00483    int res = -1;
00484    struct ast_frame f = { AST_FRAME_HTML, };
00485    int isoutbound;
00486 
00487    if (!p)
00488       return -1;
00489    
00490    ast_mutex_lock(&p->lock);
00491    isoutbound = IS_OUTBOUND(ast, p);
00492    f.subclass = subclass;
00493    f.data.ptr = (char *)data;
00494    f.datalen = datalen;
00495    if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00496       ast_mutex_unlock(&p->lock);
00497    return res;
00498 }

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

Definition at line 461 of file chan_local.c.

References AST_FRAME_TEXT, ast_mutex_lock(), ast_mutex_unlock(), f, IS_OUTBOUND, local_queue_frame(), local_pvt::lock, and ast_channel::tech_pvt.

00462 {
00463    struct local_pvt *p = ast->tech_pvt;
00464    int res = -1;
00465    struct ast_frame f = { AST_FRAME_TEXT, };
00466    int isoutbound;
00467 
00468    if (!p)
00469       return -1;
00470 
00471    ast_mutex_lock(&p->lock);
00472    isoutbound = IS_OUTBOUND(ast, p);
00473    f.data.ptr = (char *) text;
00474    f.datalen = strlen(text) + 1;
00475    if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00476       ast_mutex_unlock(&p->lock);
00477    return res;
00478 }

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

Definition at line 346 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(), f, IS_OUTBOUND, LOCAL_ALREADY_MASQED, local_queue_frame(), local_pvt::lock, ast_channel::name, and ast_channel::tech_pvt.

00347 {
00348    struct local_pvt *p = ast->tech_pvt;
00349    int res = -1;
00350    int isoutbound;
00351 
00352    if (!p)
00353       return -1;
00354 
00355    /* Just queue for delivery to the other side */
00356    ast_mutex_lock(&p->lock);
00357    isoutbound = IS_OUTBOUND(ast, p);
00358    if (isoutbound && f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO))
00359       check_bridge(p);
00360    if (!ast_test_flag(p, LOCAL_ALREADY_MASQED))
00361       res = local_queue_frame(p, isoutbound, f, ast, 1);
00362    else {
00363       ast_debug(1, "Not posting to queue since already masked on '%s'\n", ast->name);
00364       res = 0;
00365    }
00366    if (!res)
00367       ast_mutex_unlock(&p->lock);
00368    return res;
00369 }

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 801 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::list, local_pvt::lock, ast_channel::name, local_pvt::owner, and ast_cli_entry::usage.

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

static int unload_module ( void   )  [static]

Unload the local proxy channel from Asterisk.

Definition at line 850 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, local_pvt::list, local_tech, locals, LOG_WARNING, and local_pvt::owner.

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


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

struct ast_module_info* ast_module_info = &__mod_info [static]

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

Referenced by local_alloc().

struct ast_channel_tech local_tech [static]

Definition at line 81 of file chan_local.c.

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

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

Definition at line 53 of file chan_local.c.


Generated on Wed Aug 18 22:34:10 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7