Thu Jul 9 13:41:00 2009

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_CANCEL_QUEUE   (1 << 1)
#define LOCAL_GLARE_DETECT   (1 << 0)
#define LOCAL_LAUNCHED_PBX   (1 << 3)
#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 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 = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, }
static const 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.

#define LOCAL_ALREADY_MASQED   (1 << 2)

Already masqueraded

Definition at line 116 of file chan_local.c.

Referenced by check_bridge(), and local_write().

#define LOCAL_CANCEL_QUEUE   (1 << 1)

Cancel queue

Definition at line 115 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 114 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 117 of file chan_local.c.

Referenced by local_call(), and local_hangup().

#define LOCAL_NO_OPTIMIZATION   (1 << 4)

Do not optimize using masquerading

Definition at line 118 of file chan_local.c.

Referenced by check_bridge(), and local_alloc().


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 817 of file chan_local.c.

00817 : used internally by other modules)");

static void __unreg_module ( void   )  [static]

Definition at line 817 of file chan_local.c.

00817 : used internally by other modules)");

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

Definition at line 247 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, local_pvt::owner, and ast_channel::readq.

Referenced by local_write().

00248 {
00249    struct ast_channel_monitor *tmp;
00250    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)))
00251       return;
00252 
00253    /* only do the masquerade if we are being called on the outbound channel,
00254       if it has been bridged to another channel and if there are no pending
00255       frames on the owner channel (because they would be transferred to the
00256       outbound channel during the masquerade)
00257    */
00258    if (isoutbound && p->chan->_bridge /* Not ast_bridged_channel!  Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) {
00259       /* Masquerade bridged channel into owner */
00260       /* Lock everything we need, one by one, and give up if
00261          we can't get everything.  Remember, we'll get another
00262          chance in just a little bit */
00263       if (!ast_channel_trylock(p->chan->_bridge)) {
00264          if (!ast_check_hangup(p->chan->_bridge)) {
00265             if (!ast_channel_trylock(p->owner)) {
00266                if (!ast_check_hangup(p->owner)) {
00267                   if (p->owner->monitor && !p->chan->_bridge->monitor) {
00268                      /* If a local channel is being monitored, we don't want a masquerade
00269                       * to cause the monitor to go away. Since the masquerade swaps the monitors,
00270                       * pre-swapping the monitors before the masquerade will ensure that the monitor
00271                       * ends up where it is expected.
00272                       */
00273                      tmp = p->owner->monitor;
00274                      p->owner->monitor = p->chan->_bridge->monitor;
00275                      p->chan->_bridge->monitor = tmp;
00276                   }
00277                   if (p->chan->audiohooks) {
00278                      struct ast_audiohook_list *audiohooks_swapper;
00279                      audiohooks_swapper = p->chan->audiohooks;
00280                      p->chan->audiohooks = p->owner->audiohooks;
00281                      p->owner->audiohooks = audiohooks_swapper;
00282                   }
00283                   ast_app_group_update(p->chan, p->owner);
00284                   ast_channel_masquerade(p->owner, p->chan->_bridge);
00285                   ast_set_flag(p, LOCAL_ALREADY_MASQED);
00286                }
00287                ast_channel_unlock(p->owner);
00288             }
00289             ast_channel_unlock(p->chan->_bridge);
00290          }
00291       }
00292    /* We only allow masquerading in one 'direction'... it's important to preserve the state
00293       (group variables, etc.) that live on p->chan->_bridge (and were put there by the dialplan)
00294       when the local channels go away.
00295    */
00296 #if 0
00297    } else if (!isoutbound && p->owner && p->owner->_bridge && p->chan && AST_LIST_EMPTY(&p->chan->readq)) {
00298       /* Masquerade bridged channel into chan */
00299       if (!ast_mutex_trylock(&(p->owner->_bridge)->lock)) {
00300          if (!ast_check_hangup(p->owner->_bridge)) {
00301             if (!ast_mutex_trylock(&p->chan->lock)) {
00302                if (!ast_check_hangup(p->chan)) {
00303                   ast_channel_masquerade(p->chan, p->owner->_bridge);
00304                   ast_set_flag(p, LOCAL_ALREADY_MASQED);
00305                }
00306                ast_mutex_unlock(&p->chan->lock);
00307             }
00308          }
00309          ast_mutex_unlock(&(p->owner->_bridge)->lock);
00310       }
00311 #endif
00312    }
00313 }

static int load_module ( void   )  [static]

Load module into PBX, register channel.

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

00785 {
00786    /* Make sure we can register our channel type */
00787    if (ast_channel_register(&local_tech)) {
00788       ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
00789       return AST_MODULE_LOAD_FAILURE;
00790    }
00791    ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00792    return AST_MODULE_LOAD_SUCCESS;
00793 }

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

Create a call structure.

Definition at line 613 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_NO_OPTIMIZATION, local_pvt_destroy(), LOG_ERROR, and LOG_NOTICE.

Referenced by local_request().

00614 {
00615    struct local_pvt *tmp = NULL;
00616    char *c = NULL, *opts = NULL;
00617 
00618    if (!(tmp = ast_calloc(1, sizeof(*tmp))))
00619       return NULL;
00620 
00621    /* Initialize private structure information */
00622    ast_mutex_init(&tmp->lock);
00623    ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
00624 
00625    memcpy(&tmp->jb_conf, &g_jb_conf, sizeof(tmp->jb_conf));
00626 
00627    /* Look for options */
00628    if ((opts = strchr(tmp->exten, '/'))) {
00629       *opts++ = '\0';
00630       if (strchr(opts, 'n'))
00631          ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
00632       if (strchr(opts, 'j')) {
00633          if (ast_test_flag(tmp, LOCAL_NO_OPTIMIZATION))
00634             ast_set_flag(&tmp->jb_conf, AST_JB_ENABLED);
00635          else {
00636             ast_log(LOG_ERROR, "You must use the 'n' option for chan_local "
00637                "to use the 'j' option to enable the jitterbuffer\n");
00638          }
00639       }
00640    }
00641 
00642    /* Look for a context */
00643    if ((c = strchr(tmp->exten, '@')))
00644       *c++ = '\0';
00645 
00646    ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
00647 
00648    tmp->reqformat = format;
00649 
00650    if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
00651       ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
00652       tmp = local_pvt_destroy(tmp);
00653    } else {
00654       /* Add to list */
00655       AST_LIST_LOCK(&locals);
00656       AST_LIST_INSERT_HEAD(&locals, tmp, list);
00657       AST_LIST_UNLOCK(&locals);
00658    }
00659    
00660    return tmp;
00661 }

static int local_answer ( struct ast_channel ast  )  [static]

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

00226 {
00227    struct local_pvt *p = ast->tech_pvt;
00228    int isoutbound;
00229    int res = -1;
00230 
00231    if (!p)
00232       return -1;
00233 
00234    ast_mutex_lock(&p->lock);
00235    isoutbound = IS_OUTBOUND(ast, p);
00236    if (isoutbound) {
00237       /* Pass along answer since somebody answered us */
00238       struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
00239       res = local_queue_frame(p, isoutbound, &answer, ast, 1);
00240    } else
00241       ast_log(LOG_WARNING, "Huh?  Local is being asked to answer?\n");
00242    if (!res)
00243       ast_mutex_unlock(&p->lock);
00244    return res;
00245 }

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

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

00477 {
00478    struct local_pvt *p = ast->tech_pvt;
00479    int res;
00480    struct ast_var_t *varptr = NULL, *new;
00481    size_t len, namelen;
00482 
00483    if (!p)
00484       return -1;
00485    
00486    ast_mutex_lock(&p->lock);
00487 
00488    /*
00489     * Note that cid_num and cid_name aren't passed in the ast_channel_alloc
00490     * call, so it's done here instead.
00491     */
00492    p->chan->cid.cid_dnid = ast_strdup(p->owner->cid.cid_dnid);
00493    p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num);
00494    p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name);
00495    p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis);
00496    p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani);
00497    p->chan->cid.cid_pres = p->owner->cid.cid_pres;
00498    p->chan->cid.cid_ani2 = p->owner->cid.cid_ani2;
00499    p->chan->cid.cid_ton = p->owner->cid.cid_ton;
00500    p->chan->cid.cid_tns = p->owner->cid.cid_tns;
00501    ast_string_field_set(p->chan, language, p->owner->language);
00502    ast_string_field_set(p->chan, accountcode, p->owner->accountcode);
00503    ast_string_field_set(p->chan, musicclass, p->owner->musicclass);
00504    ast_cdr_update(p->chan);
00505    p->chan->cdrflags = p->owner->cdrflags;
00506 
00507    /* copy the channel variables from the incoming channel to the outgoing channel */
00508    /* Note that due to certain assumptions, they MUST be in the same order */
00509    AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) {
00510       namelen = strlen(varptr->name);
00511       len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
00512       if ((new = ast_calloc(1, len))) {
00513          memcpy(new, varptr, len);
00514          new->value = &(new->name[0]) + namelen + 1;
00515          AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries);
00516       }
00517    }
00518    ast_channel_datastore_inherit(p->owner, p->chan);
00519 
00520    /* Start switch on sub channel */
00521    if (!(res = ast_pbx_start(p->chan)))
00522       ast_set_flag(p, LOCAL_LAUNCHED_PBX);
00523 
00524    ast_mutex_unlock(&p->lock);
00525    return res;
00526 }

static int local_devicestate ( void *  data  )  [static]

Adds devicestate to local channels.

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

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

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

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

00397 {
00398    struct local_pvt *p = ast->tech_pvt;
00399    int res = -1;
00400    struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
00401    int isoutbound;
00402 
00403    if (!p)
00404       return -1;
00405 
00406    ast_mutex_lock(&p->lock);
00407    isoutbound = IS_OUTBOUND(ast, p);
00408    f.subclass = digit;
00409    if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00410       ast_mutex_unlock(&p->lock);
00411 
00412    return res;
00413 }

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

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

00416 {
00417    struct local_pvt *p = ast->tech_pvt;
00418    int res = -1;
00419    struct ast_frame f = { AST_FRAME_DTMF_END, };
00420    int isoutbound;
00421 
00422    if (!p)
00423       return -1;
00424 
00425    ast_mutex_lock(&p->lock);
00426    isoutbound = IS_OUTBOUND(ast, p);
00427    f.subclass = digit;
00428    f.len = duration;
00429    if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00430       ast_mutex_unlock(&p->lock);
00431 
00432    return res;
00433 }

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

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

00346 {
00347    struct local_pvt *p = newchan->tech_pvt;
00348 
00349    if (!p)
00350       return -1;
00351 
00352    ast_mutex_lock(&p->lock);
00353 
00354    if ((p->owner != oldchan) && (p->chan != oldchan)) {
00355       ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
00356       ast_mutex_unlock(&p->lock);
00357       return -1;
00358    }
00359    if (p->owner == oldchan)
00360       p->owner = newchan;
00361    else
00362       p->chan = newchan;
00363    ast_mutex_unlock(&p->lock);
00364    return 0;
00365 }

static int local_hangup ( struct ast_channel ast  )  [static]

Hangup a call through the local proxy channel.

Definition at line 529 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, f, 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.

00530 {
00531    struct local_pvt *p = ast->tech_pvt;
00532    int isoutbound;
00533    struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP };
00534    struct ast_channel *ochan = NULL;
00535    int glaredetect = 0, res = 0;
00536 
00537    if (!p)
00538       return -1;
00539 
00540    ast_mutex_lock(&p->lock);
00541 
00542    if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) 
00543       ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE);
00544    isoutbound = IS_OUTBOUND(ast, p);
00545    if (isoutbound) {
00546       const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
00547       if ((status) && (p->owner)) {
00548          /* Deadlock avoidance */
00549          while (p->owner && ast_channel_trylock(p->owner)) {
00550             ast_mutex_unlock(&p->lock);
00551             if (ast) {
00552                ast_channel_unlock(ast);
00553             }
00554             usleep(1);
00555             if (ast) {
00556                ast_channel_lock(ast);
00557             }
00558             ast_mutex_lock(&p->lock);
00559          }
00560          if (p->owner) {
00561             pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
00562             ast_channel_unlock(p->owner);
00563          }
00564       }
00565       p->chan = NULL;
00566       ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
00567       ast_module_user_remove(p->u_chan);
00568    } else {
00569       p->owner = NULL;
00570       ast_module_user_remove(p->u_owner);
00571       while (p->chan && ast_channel_trylock(p->chan)) {
00572          DEADLOCK_AVOIDANCE(&p->lock);
00573       }
00574       if (p->chan) {
00575          ast_queue_hangup(p->chan);
00576          ast_channel_unlock(p->chan);
00577       }
00578    }
00579    
00580    ast->tech_pvt = NULL;
00581    
00582    if (!p->owner && !p->chan) {
00583       /* Okay, done with the private part now, too. */
00584       glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT);
00585       /* If we have a queue holding, don't actually destroy p yet, but
00586          let local_queue do it. */
00587       if (glaredetect)
00588          ast_set_flag(p, LOCAL_CANCEL_QUEUE);
00589       /* Remove from list */
00590       AST_LIST_LOCK(&locals);
00591       AST_LIST_REMOVE(&locals, p, list);
00592       AST_LIST_UNLOCK(&locals);
00593       ast_mutex_unlock(&p->lock);
00594       /* And destroy */
00595       if (!glaredetect) {
00596          p = local_pvt_destroy(p);
00597       }
00598       return 0;
00599    }
00600    if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX))
00601       /* Need to actually hangup since there is no PBX */
00602       ochan = p->chan;
00603    else
00604       res = local_queue_frame(p, isoutbound, &f, NULL, 1);
00605    if (!res)
00606       ast_mutex_unlock(&p->lock);
00607    if (ochan)
00608       ast_hangup(ochan);
00609    return 0;
00610 }

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

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

00368 {
00369    struct local_pvt *p = ast->tech_pvt;
00370    int res = 0;
00371    struct ast_frame f = { AST_FRAME_CONTROL, };
00372    int isoutbound;
00373 
00374    if (!p)
00375       return -1;
00376 
00377    /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */
00378    if (condition == AST_CONTROL_HOLD) {
00379       ast_moh_start(ast, data, NULL);
00380    } else if (condition == AST_CONTROL_UNHOLD) {
00381       ast_moh_stop(ast);
00382    } else {
00383       /* Queue up a frame representing the indication as a control frame */
00384       ast_mutex_lock(&p->lock);
00385       isoutbound = IS_OUTBOUND(ast, p);
00386       f.subclass = condition;
00387       f.data = (void*)data;
00388       f.datalen = datalen;
00389       if (!(res = local_queue_frame(p, isoutbound, &f, ast, 1)))
00390          ast_mutex_unlock(&p->lock);
00391    }
00392 
00393    return res;
00394 }

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

Start new local channel.

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

00665 {
00666    struct ast_channel *tmp = NULL, *tmp2 = NULL;
00667    int randnum = ast_random() & 0xffff, fmt = 0;
00668    const char *t;
00669    int ama;
00670 
00671    /* Allocate two new Asterisk channels */
00672    /* safe accountcode */
00673    if (p->owner && p->owner->accountcode)
00674       t = p->owner->accountcode;
00675    else
00676       t = "";
00677 
00678    if (p->owner)
00679       ama = p->owner->amaflags;
00680    else
00681       ama = 0;
00682    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)) 
00683          || !(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))) {
00684       if (tmp)
00685          ast_channel_free(tmp);
00686       if (tmp2)
00687          ast_channel_free(tmp2);
00688       ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
00689       return NULL;
00690    } 
00691 
00692    tmp2->tech = tmp->tech = &local_tech;
00693 
00694    tmp->nativeformats = p->reqformat;
00695    tmp2->nativeformats = p->reqformat;
00696 
00697    /* Determine our read/write format and set it on each channel */
00698    fmt = ast_best_codec(p->reqformat);
00699    tmp->writeformat = fmt;
00700    tmp2->writeformat = fmt;
00701    tmp->rawwriteformat = fmt;
00702    tmp2->rawwriteformat = fmt;
00703    tmp->readformat = fmt;
00704    tmp2->readformat = fmt;
00705    tmp->rawreadformat = fmt;
00706    tmp2->rawreadformat = fmt;
00707 
00708    tmp->tech_pvt = p;
00709    tmp2->tech_pvt = p;
00710 
00711    p->owner = tmp;
00712    p->chan = tmp2;
00713    p->u_owner = ast_module_user_add(p->owner);
00714    p->u_chan = ast_module_user_add(p->chan);
00715 
00716    ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
00717    ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
00718    ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten));
00719    tmp->priority = 1;
00720    tmp2->priority = 1;
00721 
00722    ast_jb_configure(tmp, &p->jb_conf);
00723 
00724    return tmp;
00725 }

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

00164 {
00165    ast_mutex_destroy(&pvt->lock);
00166    ast_free(pvt);
00167    return NULL;
00168 }

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

References 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_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().

00172 {
00173    struct ast_channel *other = NULL;
00174 
00175    /* Recalculate outbound channel */
00176    other = isoutbound ? p->owner : p->chan;
00177 
00178    if (!other) {
00179       return 0;
00180    }
00181 
00182    /* do not queue frame if generator is on both local channels */
00183    if (us && us->generator && other->generator) {
00184       return 0;
00185    }
00186 
00187    /* Set glare detection */
00188    ast_set_flag(p, LOCAL_GLARE_DETECT);
00189 
00190    /* Ensure that we have both channels locked */
00191    while (other && ast_channel_trylock(other)) {
00192       ast_mutex_unlock(&p->lock);
00193       if (us && us_locked) {
00194          do {
00195             CHANNEL_DEADLOCK_AVOIDANCE(us);
00196          } while (ast_mutex_trylock(&p->lock));
00197       } else {
00198          usleep(1);
00199          ast_mutex_lock(&p->lock);
00200       }
00201       other = isoutbound ? p->owner : p->chan;
00202    }
00203 
00204    /* Since glare detection only occurs within this function, and because
00205     * a pvt flag cannot be set without having the pvt lock, this is the only
00206     * location where we could detect a cancelling of the queue. */
00207    if (ast_test_flag(p, LOCAL_CANCEL_QUEUE)) {
00208       /* We had a glare on the hangup.  Forget all this business,
00209       return and destroy p.  */
00210       ast_mutex_unlock(&p->lock);
00211       p = local_pvt_destroy(p);
00212       return -1;
00213    }
00214 
00215    if (other) {
00216       ast_queue_frame(other, f);
00217       ast_channel_unlock(other);
00218    }
00219 
00220    ast_clear_flag(p, LOCAL_GLARE_DETECT);
00221 
00222    return 0;
00223 }

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

Definition at line 315 of file chan_local.c.

References ast_null_frame.

00316 {
00317    return &ast_null_frame;
00318 }

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

Part of PBX interface.

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

00729 {
00730    struct local_pvt *p = NULL;
00731    struct ast_channel *chan = NULL;
00732 
00733    /* Allocate a new private structure and then Asterisk channel */
00734    if ((p = local_alloc(data, format))) {
00735       if (!(chan = local_new(p, AST_STATE_DOWN))) {
00736          AST_LIST_LOCK(&locals);
00737          AST_LIST_REMOVE(&locals, p, list);
00738          AST_LIST_UNLOCK(&locals);
00739          p = local_pvt_destroy(p);
00740       }
00741    }
00742 
00743    return chan;
00744 }

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

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

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

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

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

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

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

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

00321 {
00322    struct local_pvt *p = ast->tech_pvt;
00323    int res = -1;
00324    int isoutbound;
00325 
00326    if (!p)
00327       return -1;
00328 
00329    /* Just queue for delivery to the other side */
00330    ast_mutex_lock(&p->lock);
00331    isoutbound = IS_OUTBOUND(ast, p);
00332    if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO))
00333       check_bridge(p, isoutbound);
00334    if (!ast_test_flag(p, LOCAL_ALREADY_MASQED))
00335       res = local_queue_frame(p, isoutbound, f, ast, 1);
00336    else {
00337       ast_debug(1, "Not posting to queue since already masked on '%s'\n", ast->name);
00338       res = 0;
00339    }
00340    if (!res)
00341       ast_mutex_unlock(&p->lock);
00342    return res;
00343 }

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

00748 {
00749    struct local_pvt *p = NULL;
00750 
00751    switch (cmd) {
00752    case CLI_INIT:
00753       e->command = "local show channels";
00754       e->usage =
00755          "Usage: local show channels\n"
00756          "       Provides summary information on active local proxy channels.\n";
00757       return NULL;
00758    case CLI_GENERATE:
00759       return NULL;
00760    }
00761 
00762    if (a->argc != 3)
00763       return CLI_SHOWUSAGE;
00764 
00765    AST_LIST_LOCK(&locals);
00766    if (!AST_LIST_EMPTY(&locals)) {
00767       AST_LIST_TRAVERSE(&locals, p, list) {
00768          ast_mutex_lock(&p->lock);
00769          ast_cli(a->fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
00770          ast_mutex_unlock(&p->lock);
00771       }
00772    } else
00773       ast_cli(a->fd, "No local channels in use\n");
00774    AST_LIST_UNLOCK(&locals);
00775 
00776    return CLI_SUCCESS;
00777 }

static int unload_module ( void   )  [static]

Unload the local proxy channel from Asterisk.

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

00797 {
00798    struct local_pvt *p = NULL;
00799 
00800    /* First, take us out of the channel loop */
00801    ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00802    ast_channel_unregister(&local_tech);
00803    if (!AST_LIST_LOCK(&locals)) {
00804       /* Hangup all interfaces if they have an owner */
00805       AST_LIST_TRAVERSE(&locals, p, list) {
00806          if (p->owner)
00807             ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
00808       }
00809       AST_LIST_UNLOCK(&locals);
00810    } else {
00811       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
00812       return -1;
00813    }     
00814    return 0;
00815 }


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 = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, } [static]

Definition at line 817 of file chan_local.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 817 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 779 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 79 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 Thu Jul 9 13:41:01 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7