Fri Jun 19 12:10:16 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_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)
 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 118 of file chan_local.c.

Referenced by check_bridge(), and local_write().

#define LOCAL_BRIDGE   (1 << 5)

Report back the "true" channel as being bridged to

Definition at line 121 of file chan_local.c.

Referenced by local_alloc(), and local_bridgedchannel().

#define LOCAL_CANCEL_QUEUE   (1 << 1)

Cancel queue

Definition at line 117 of file chan_local.c.

Referenced by local_hangup(), and local_queue_frame().

#define LOCAL_GLARE_DETECT   (1 << 0)

Detect glare on hangup

Definition at line 116 of file chan_local.c.

Referenced by local_hangup(), and local_queue_frame().

#define LOCAL_LAUNCHED_PBX   (1 << 3)

PBX was launched

Definition at line 119 of file chan_local.c.

Referenced by local_call(), and local_hangup().

#define LOCAL_NO_OPTIMIZATION   (1 << 4)

Do not optimize using masquerading

Definition at line 120 of file chan_local.c.

Referenced by check_bridge(), and local_alloc().


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 864 of file chan_local.c.

00864 : used internally by other modules)");

static void __unreg_module ( void   )  [static]

Definition at line 864 of file chan_local.c.

00864 : used internally by other modules)");

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

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

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

static int load_module ( void   )  [static]

Load module into PBX, register channel.

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

00832 {
00833    /* Make sure we can register our channel type */
00834    if (ast_channel_register(&local_tech)) {
00835       ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
00836       return AST_MODULE_LOAD_FAILURE;
00837    }
00838    ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00839    return AST_MODULE_LOAD_SUCCESS;
00840 }

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

Create a call structure.

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

Referenced by local_request().

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

static int local_answer ( struct ast_channel ast  )  [static]

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

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

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

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

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

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

static int local_devicestate ( void *  data  )  [static]

Adds devicestate to local channels.

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

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

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

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

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

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

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

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

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

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

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

static int local_hangup ( struct ast_channel ast  )  [static]

Hangup a call through the local proxy channel.

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

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

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

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

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

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

Start new local channel.

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

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

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

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

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

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

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

Definition at line 343 of file chan_local.c.

References ast_null_frame.

00344 {
00345    return &ast_null_frame;
00346 }

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

Part of PBX interface.

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

00776 {
00777    struct local_pvt *p = NULL;
00778    struct ast_channel *chan = NULL;
00779 
00780    /* Allocate a new private structure and then Asterisk channel */
00781    if ((p = local_alloc(data, format))) {
00782       if (!(chan = local_new(p, AST_STATE_DOWN))) {
00783          AST_LIST_LOCK(&locals);
00784          AST_LIST_REMOVE(&locals, p, list);
00785          AST_LIST_UNLOCK(&locals);
00786          p = local_pvt_destroy(p);
00787       }
00788    }
00789 
00790    return chan;
00791 }

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

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

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

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

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

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

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

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

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

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

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

static int unload_module ( void   )  [static]

Unload the local proxy channel from Asterisk.

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

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


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

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 864 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 826 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 80 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 Fri Jun 19 12:10:16 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7