Wed Oct 28 13:32:05 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/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_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, const char *linkedid)
 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, const struct ast_channel *requestor, void *data, int *cause)
 Part of PBX interface.
static int local_sendhtml (struct ast_channel *ast, int subclass, const char *data, int datalen)
static int local_sendtext (struct ast_channel *ast, const char *text)
static int local_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 = AST_BUILDOPT_SUM, .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 117 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 120 of file chan_local.c.

Referenced by local_alloc(), and local_bridgedchannel().

#define LOCAL_CANCEL_QUEUE   (1 << 1)

Cancel queue

Definition at line 116 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 115 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 118 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 119 of file chan_local.c.

Referenced by check_bridge(), and local_alloc().


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 938 of file chan_local.c.

00938 : used internally by other modules)");

static void __unreg_module ( void   )  [static]

Definition at line 938 of file chan_local.c.

00938 : used internally by other modules)");

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

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

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

static int load_module ( void   )  [static]

Load module into PBX, register channel.

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

00906 {
00907    /* Make sure we can register our channel type */
00908    if (ast_channel_register(&local_tech)) {
00909       ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
00910       return AST_MODULE_LOAD_FAILURE;
00911    }
00912    ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00913    return AST_MODULE_LOAD_SUCCESS;
00914 }

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

Create a call structure.

Definition at line 725 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_NO_OPTIMIZATION, local_pvt_destroy(), local_pvt::lock, LOG_ERROR, LOG_NOTICE, and local_pvt::reqformat.

Referenced by local_request().

00726 {
00727    struct local_pvt *tmp = NULL;
00728    char *c = NULL, *opts = NULL;
00729 
00730    if (!(tmp = ast_calloc(1, sizeof(*tmp))))
00731       return NULL;
00732 
00733    /* Initialize private structure information */
00734    ast_mutex_init(&tmp->lock);
00735    ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
00736 
00737    memcpy(&tmp->jb_conf, &g_jb_conf, sizeof(tmp->jb_conf));
00738 
00739    /* Look for options */
00740    if ((opts = strchr(tmp->exten, '/'))) {
00741       *opts++ = '\0';
00742       if (strchr(opts, 'n'))
00743          ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
00744       if (strchr(opts, 'j')) {
00745          if (ast_test_flag(tmp, LOCAL_NO_OPTIMIZATION))
00746             ast_set_flag(&tmp->jb_conf, AST_JB_ENABLED);
00747          else {
00748             ast_log(LOG_ERROR, "You must use the 'n' option for chan_local "
00749                "to use the 'j' option to enable the jitterbuffer\n");
00750          }
00751       }
00752       if (strchr(opts, 'b')) {
00753          ast_set_flag(tmp, LOCAL_BRIDGE);
00754       }
00755    }
00756 
00757    /* Look for a context */
00758    if ((c = strchr(tmp->exten, '@')))
00759       *c++ = '\0';
00760 
00761    ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
00762 
00763    tmp->reqformat = format;
00764 
00765 #if 0
00766    /* We can't do this check here, because we don't know the CallerID yet, and
00767     * the CallerID could potentially affect what step is actually taken (or
00768     * even if that step exists). */
00769    if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
00770       ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
00771       tmp = local_pvt_destroy(tmp);
00772    } else {
00773 #endif
00774       /* Add to list */
00775       AST_LIST_LOCK(&locals);
00776       AST_LIST_INSERT_HEAD(&locals, tmp, list);
00777       AST_LIST_UNLOCK(&locals);
00778 #if 0
00779    }
00780 #endif
00781    
00782    return tmp;
00783 }

static int local_answer ( struct ast_channel ast  )  [static]

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

00256 {
00257    struct local_pvt *p = ast->tech_pvt;
00258    int isoutbound;
00259    int res = -1;
00260 
00261    if (!p)
00262       return -1;
00263 
00264    ast_mutex_lock(&p->lock);
00265    isoutbound = IS_OUTBOUND(ast, p);
00266    if (isoutbound) {
00267       /* Pass along answer since somebody answered us */
00268       struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
00269       res = local_queue_frame(p, isoutbound, &answer, ast, 1);
00270    } else
00271       ast_log(LOG_WARNING, "Huh?  Local is being asked to answer?\n");
00272    if (!res)
00273       ast_mutex_unlock(&p->lock);
00274    return res;
00275 }

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

References ast_channel::_bridge, 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.

00174 {
00175    struct local_pvt *p = bridge->tech_pvt;
00176    struct ast_channel *bridged = bridge;
00177 
00178    ast_mutex_lock(&p->lock);
00179 
00180    if (ast_test_flag(p, LOCAL_BRIDGE)) {
00181       /* Find the opposite channel */
00182       bridged = (bridge == p->owner ? p->chan : p->owner);
00183       
00184       /* Now see if the opposite channel is bridged to anything */
00185       if (!bridged) {
00186          bridged = bridge;
00187       } else if (bridged->_bridge) {
00188          bridged = bridged->_bridge;
00189       }
00190    }
00191 
00192    ast_mutex_unlock(&p->lock);
00193 
00194    return bridged;
00195 }

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

References ast_channel::accountcode, accountcode, ast_calloc, ast_cdr_update(), ast_channel_datastore_inherit(), ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_connected_line_copy_from_caller(), ast_connected_line_copy_to_caller(), ast_exists_extension(), AST_FLAG_ANSWERED_ELSEWHERE, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), ast_mutex_trylock(), ast_mutex_unlock(), ast_party_redirecting_copy(), ast_pbx_start(), ast_set_flag, ast_strdup, ast_string_field_set, ast_test_flag, ast_channel::cdrflags, local_pvt::chan, ast_channel::cid, ast_callerid::cid_dnid, ast_callerid::cid_num, ast_callerid::cid_rdnis, ast_callerid::cid_tns, ast_channel::connected, 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::redirecting, ast_channel::tech_pvt, and ast_channel::varshead.

00541 {
00542    struct local_pvt *p = ast->tech_pvt;
00543    int res;
00544    struct ast_var_t *varptr = NULL, *new;
00545    size_t len, namelen;
00546 
00547    if (!p)
00548       return -1;
00549 
00550    /* If you value your sanity, please don't look at this code */
00551 start_over:
00552    while (ast_channel_trylock(p->chan)) {
00553       ast_channel_unlock(p->owner);
00554       usleep(1);
00555       ast_channel_lock(p->owner);
00556    }
00557 
00558    /* p->owner and p->chan are locked now. Let's get p locked */
00559    if (ast_mutex_trylock(&p->lock)) {
00560       /* @#$&$@ */
00561       ast_channel_unlock(p->chan);
00562       ast_channel_unlock(p->owner);
00563       usleep(1);
00564       ast_channel_lock(p->owner);
00565       goto start_over;
00566    }
00567 
00568    /*
00569     * Note that cid_num and cid_name aren't passed in the ast_channel_alloc
00570     * call, so it's done here instead.
00571     *
00572     * All these failure points just return -1. The individual strings will
00573     * be cleared when we destroy the channel.
00574     */
00575    if (p->owner->cid.cid_rdnis) {
00576       if (!(p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis))) {
00577          ast_mutex_unlock(&p->lock);
00578          ast_channel_unlock(p->chan);
00579          return -1;
00580       }
00581    }
00582    ast_party_redirecting_copy(&p->chan->redirecting, &p->owner->redirecting);
00583 
00584    if (p->owner->cid.cid_dnid) {
00585       if (!(p->chan->cid.cid_dnid = ast_strdup(p->owner->cid.cid_dnid))) {
00586          ast_mutex_unlock(&p->lock);
00587          ast_channel_unlock(p->chan);
00588          return -1;
00589       }
00590    }
00591    p->chan->cid.cid_tns = p->owner->cid.cid_tns;
00592 
00593    ast_connected_line_copy_to_caller(&p->chan->cid, &p->owner->connected);
00594    ast_connected_line_copy_from_caller(&p->chan->connected, &p->owner->cid);
00595 
00596    ast_string_field_set(p->chan, language, p->owner->language);
00597    ast_string_field_set(p->chan, accountcode, p->owner->accountcode);
00598    ast_string_field_set(p->chan, musicclass, p->owner->musicclass);
00599    ast_cdr_update(p->chan);
00600    p->chan->cdrflags = p->owner->cdrflags;
00601 
00602    if (!ast_exists_extension(NULL, p->chan->context, p->chan->exten, 1, p->owner->cid.cid_num)) {
00603       ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->chan->exten, p->chan->context);
00604       ast_mutex_unlock(&p->lock);
00605       ast_channel_unlock(p->chan);
00606       return -1;
00607    }
00608 
00609    /* Make sure we inherit the ANSWERED_ELSEWHERE flag if it's set on the queue/dial call request in the dialplan */
00610    if (ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
00611       ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE);
00612    }
00613 
00614    /* copy the channel variables from the incoming channel to the outgoing channel */
00615    /* Note that due to certain assumptions, they MUST be in the same order */
00616    AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) {
00617       namelen = strlen(varptr->name);
00618       len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
00619       if ((new = ast_calloc(1, len))) {
00620          memcpy(new, varptr, len);
00621          new->value = &(new->name[0]) + namelen + 1;
00622          AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries);
00623       }
00624    }
00625    ast_channel_datastore_inherit(p->owner, p->chan);
00626 
00627    /* Start switch on sub channel */
00628    if (!(res = ast_pbx_start(p->chan)))
00629       ast_set_flag(p, LOCAL_LAUNCHED_PBX);
00630 
00631    ast_mutex_unlock(&p->lock);
00632    ast_channel_unlock(p->chan);
00633    return res;
00634 }

static int local_devicestate ( void *  data  )  [static]

Adds devicestate to local channels.

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

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

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

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

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

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

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

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

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

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

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

static int local_hangup ( struct ast_channel ast  )  [static]

Hangup a call through the local proxy channel.

Definition at line 637 of file chan_local.c.

References ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_clear_flag, AST_CONTROL_HANGUP, ast_debug, AST_FLAG_ANSWERED_ELSEWHERE, AST_FRAME_CONTROL, ast_hangup(), AST_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.

00638 {
00639    struct local_pvt *p = ast->tech_pvt;
00640    int isoutbound;
00641    struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP, .data.uint32 = ast->hangupcause };
00642    struct ast_channel *ochan = NULL;
00643    int glaredetect = 0, res = 0;
00644 
00645    if (!p)
00646       return -1;
00647 
00648    ast_mutex_lock(&p->lock);
00649 
00650    isoutbound = IS_OUTBOUND(ast, p);
00651 
00652    if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
00653       ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE);
00654       ast_debug(2, "This local call has the ANSWERED_ELSEWHERE flag set.\n");
00655    }
00656 
00657    if (isoutbound) {
00658       const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
00659       if ((status) && (p->owner)) {
00660          /* Deadlock avoidance */
00661          while (p->owner && ast_channel_trylock(p->owner)) {
00662             ast_mutex_unlock(&p->lock);
00663             if (ast) {
00664                ast_channel_unlock(ast);
00665             }
00666             usleep(1);
00667             if (ast) {
00668                ast_channel_lock(ast);
00669             }
00670             ast_mutex_lock(&p->lock);
00671          }
00672          if (p->owner) {
00673             pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
00674             ast_channel_unlock(p->owner);
00675          }
00676       }
00677       p->chan = NULL;
00678       ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
00679       ast_module_user_remove(p->u_chan);
00680    } else {
00681       p->owner = NULL;
00682       ast_module_user_remove(p->u_owner);
00683       while (p->chan && ast_channel_trylock(p->chan)) {
00684          DEADLOCK_AVOIDANCE(&p->lock);
00685       }
00686       if (p->chan) {
00687          ast_queue_hangup(p->chan);
00688          ast_channel_unlock(p->chan);
00689       }
00690    }
00691    
00692    ast->tech_pvt = NULL;
00693    
00694    if (!p->owner && !p->chan) {
00695       /* Okay, done with the private part now, too. */
00696       glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT);
00697       /* If we have a queue holding, don't actually destroy p yet, but
00698          let local_queue do it. */
00699       if (glaredetect)
00700          ast_set_flag(p, LOCAL_CANCEL_QUEUE);
00701       /* Remove from list */
00702       AST_LIST_LOCK(&locals);
00703       AST_LIST_REMOVE(&locals, p, list);
00704       AST_LIST_UNLOCK(&locals);
00705       ast_mutex_unlock(&p->lock);
00706       /* And destroy */
00707       if (!glaredetect) {
00708          p = local_pvt_destroy(p);
00709       }
00710       return 0;
00711    }
00712    if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX))
00713       /* Need to actually hangup since there is no PBX */
00714       ochan = p->chan;
00715    else
00716       res = local_queue_frame(p, isoutbound, &f, NULL, 1);
00717    if (!res)
00718       ast_mutex_unlock(&p->lock);
00719    if (ochan)
00720       ast_hangup(ochan);
00721    return 0;
00722 }

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

Definition at line 397 of file chan_local.c.

References ast_connected_line_build_data(), AST_CONTROL_CONNECTED_LINE, AST_CONTROL_HOLD, AST_CONTROL_REDIRECTING, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, ast_moh_start(), ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_redirecting_build_data(), local_pvt::chan, ast_channel::connected, ast_frame::data, ast_frame::datalen, IS_OUTBOUND, local_queue_frame(), local_pvt::lock, local_pvt::owner, ast_frame::ptr, ast_channel::redirecting, ast_frame::subclass, and ast_channel::tech_pvt.

00398 {
00399    struct local_pvt *p = ast->tech_pvt;
00400    int res = 0;
00401    struct ast_frame f = { AST_FRAME_CONTROL, };
00402    int isoutbound;
00403 
00404    if (!p)
00405       return -1;
00406 
00407    /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */
00408    if (condition == AST_CONTROL_HOLD) {
00409       ast_moh_start(ast, data, NULL);
00410    } else if (condition == AST_CONTROL_UNHOLD) {
00411       ast_moh_stop(ast);
00412    } else if (condition == AST_CONTROL_CONNECTED_LINE || condition == AST_CONTROL_REDIRECTING) {
00413       struct ast_channel *this_channel;
00414       struct ast_channel *the_other_channel;
00415       /* A connected line update frame may only contain a partial amount of data, such
00416        * as just a source, or just a ton, and not the full amount of information. However,
00417        * the collected information is all stored in the outgoing channel's connectedline
00418        * structure, so when receiving a connected line update on an outgoing local channel,
00419        * we need to transmit the collected connected line information instead of whatever
00420        * happens to be in this control frame. The same applies for redirecting information, which
00421        * is why it is handled here as well.*/
00422       ast_mutex_lock(&p->lock);
00423       isoutbound = IS_OUTBOUND(ast, p);
00424       if (isoutbound) {
00425          this_channel = p->chan;
00426          the_other_channel = p->owner;
00427       } else {
00428          this_channel = p->owner;
00429          the_other_channel = p->chan;
00430       }
00431       if (the_other_channel) {
00432          unsigned char frame_data[1024];
00433          if (condition == AST_CONTROL_CONNECTED_LINE) {
00434             f.datalen = ast_connected_line_build_data(frame_data, sizeof(frame_data), &this_channel->connected);
00435          } else {
00436             f.datalen = ast_redirecting_build_data(frame_data, sizeof(frame_data), &this_channel->redirecting);
00437          }
00438          f.subclass = condition;
00439          f.data.ptr = frame_data;
00440          if (!(res = local_queue_frame(p, isoutbound, &f, ast, 1))) {
00441             ast_mutex_unlock(&p->lock);
00442          }
00443       } else {
00444          ast_mutex_unlock(&p->lock);
00445       }
00446    } else {
00447       /* Queue up a frame representing the indication as a control frame */
00448       ast_mutex_lock(&p->lock);
00449       isoutbound = IS_OUTBOUND(ast, p);
00450       f.subclass = condition;
00451       f.data.ptr = (void*)data;
00452       f.datalen = datalen;
00453       if (!(res = local_queue_frame(p, isoutbound, &f, ast, 1)))
00454          ast_mutex_unlock(&p->lock);
00455    }
00456 
00457    return res;
00458 }

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

Start new local channel.

Definition at line 786 of file chan_local.c.

References ast_channel::accountcode, ast_channel::amaflags, ast_best_codec(), ast_channel_alloc, ast_channel_release(), ast_copy_string(), ast_jb_configure(), ast_log(), ast_module_user_add, ast_random(), AST_STATE_RING, local_pvt::chan, ast_channel::context, local_pvt::context, ast_channel::exten, local_pvt::exten, local_pvt::jb_conf, 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().

00787 {
00788    struct ast_channel *tmp = NULL, *tmp2 = NULL;
00789    int randnum = ast_random() & 0xffff, fmt = 0;
00790    const char *t;
00791    int ama;
00792 
00793    /* Allocate two new Asterisk channels */
00794    /* safe accountcode */
00795    if (p->owner && p->owner->accountcode)
00796       t = p->owner->accountcode;
00797    else
00798       t = "";
00799 
00800    if (p->owner)
00801       ama = p->owner->amaflags;
00802    else
00803       ama = 0;
00804    if (!(tmp = ast_channel_alloc(1, state, 0, 0, t, p->exten, p->context, linkedid, ama, "Local/%s@%s-%04x;1", p->exten, p->context, randnum)) 
00805       || !(tmp2 = ast_channel_alloc(1, AST_STATE_RING, 0, 0, t, p->exten, p->context, linkedid, ama, "Local/%s@%s-%04x;2", p->exten, p->context, randnum))) {
00806       if (tmp) {
00807          tmp = ast_channel_release(tmp);
00808       }
00809       ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
00810       return NULL;
00811    }
00812 
00813    tmp2->tech = tmp->tech = &local_tech;
00814 
00815    tmp->nativeformats = p->reqformat;
00816    tmp2->nativeformats = p->reqformat;
00817 
00818    /* Determine our read/write format and set it on each channel */
00819    fmt = ast_best_codec(p->reqformat);
00820    tmp->writeformat = fmt;
00821    tmp2->writeformat = fmt;
00822    tmp->rawwriteformat = fmt;
00823    tmp2->rawwriteformat = fmt;
00824    tmp->readformat = fmt;
00825    tmp2->readformat = fmt;
00826    tmp->rawreadformat = fmt;
00827    tmp2->rawreadformat = fmt;
00828 
00829    tmp->tech_pvt = p;
00830    tmp2->tech_pvt = p;
00831 
00832    p->owner = tmp;
00833    p->chan = tmp2;
00834    p->u_owner = ast_module_user_add(p->owner);
00835    p->u_chan = ast_module_user_add(p->chan);
00836 
00837    ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
00838    ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
00839    ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten));
00840    tmp->priority = 1;
00841    tmp2->priority = 1;
00842 
00843    ast_jb_configure(tmp, &p->jb_conf);
00844 
00845    return tmp;
00846 }

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

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

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 197 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, 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().

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

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

Definition at line 345 of file chan_local.c.

References ast_null_frame.

00346 {
00347    return &ast_null_frame;
00348 }

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

Part of PBX interface.

Definition at line 849 of file chan_local.c.

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

00850 {
00851    struct local_pvt *p = NULL;
00852    struct ast_channel *chan = NULL;
00853 
00854    /* Allocate a new private structure and then Asterisk channel */
00855    if ((p = local_alloc(data, format))) {
00856       if (!(chan = local_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL))) {
00857          AST_LIST_LOCK(&locals);
00858          AST_LIST_REMOVE(&locals, p, list);
00859          AST_LIST_UNLOCK(&locals);
00860          p = local_pvt_destroy(p);
00861       }
00862    }
00863 
00864    return chan;
00865 }

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

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

00519 {
00520    struct local_pvt *p = ast->tech_pvt;
00521    int res = -1;
00522    struct ast_frame f = { AST_FRAME_HTML, };
00523    int isoutbound;
00524 
00525    if (!p)
00526       return -1;
00527    
00528    ast_mutex_lock(&p->lock);
00529    isoutbound = IS_OUTBOUND(ast, p);
00530    f.subclass = subclass;
00531    f.data.ptr = (char *)data;
00532    f.datalen = datalen;
00533    if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00534       ast_mutex_unlock(&p->lock);
00535    return res;
00536 }

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

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

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

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

Definition at line 350 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, ast_channel::name, and ast_channel::tech_pvt.

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

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

00869 {
00870    struct local_pvt *p = NULL;
00871 
00872    switch (cmd) {
00873    case CLI_INIT:
00874       e->command = "local show channels";
00875       e->usage =
00876          "Usage: local show channels\n"
00877          "       Provides summary information on active local proxy channels.\n";
00878       return NULL;
00879    case CLI_GENERATE:
00880       return NULL;
00881    }
00882 
00883    if (a->argc != 3)
00884       return CLI_SHOWUSAGE;
00885 
00886    AST_LIST_LOCK(&locals);
00887    if (!AST_LIST_EMPTY(&locals)) {
00888       AST_LIST_TRAVERSE(&locals, p, list) {
00889          ast_mutex_lock(&p->lock);
00890          ast_cli(a->fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
00891          ast_mutex_unlock(&p->lock);
00892       }
00893    } else
00894       ast_cli(a->fd, "No local channels in use\n");
00895    AST_LIST_UNLOCK(&locals);
00896 
00897    return CLI_SUCCESS;
00898 }

static int unload_module ( void   )  [static]

Unload the local proxy channel from Asterisk.

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

00918 {
00919    struct local_pvt *p = NULL;
00920 
00921    /* First, take us out of the channel loop */
00922    ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00923    ast_channel_unregister(&local_tech);
00924    if (!AST_LIST_LOCK(&locals)) {
00925       /* Hangup all interfaces if they have an owner */
00926       AST_LIST_TRAVERSE(&locals, p, list) {
00927          if (p->owner)
00928             ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
00929       }
00930       AST_LIST_UNLOCK(&locals);
00931    } else {
00932       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
00933       return -1;
00934    }     
00935    return 0;
00936 }


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

Definition at line 938 of file chan_local.c.

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

Referenced by load_module(), and unload_module().

struct ast_jb_conf g_jb_conf [static]

Definition at line 56 of file chan_local.c.

struct ast_channel_tech local_tech [static]

Definition at line 79 of file chan_local.c.

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

Definition at line 52 of file chan_local.c.


Generated on Wed Oct 28 13:32:05 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6