Sun Aug 15 20:33:35 2010

Asterisk developer's documentation


chan_local.c File Reference

Local Proxy Channel. More...

#include "asterisk.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/signal.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/logger.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/options.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_MOH_PASSTHRU   (1 << 5)
#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 int locals_show (int fd, int argc, char **argv)
 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 | AST_MODFLAG_BUILDSUM, .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 = "361d7bb937402d51e4658efb5b4d76e4" , .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_channel_tech local_tech
static char show_locals_usage []
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 67 of file chan_local.c.

#define LOCAL_ALREADY_MASQED   (1 << 2)

Already masqueraded

Definition at line 120 of file chan_local.c.

Referenced by check_bridge(), and local_write().

#define LOCAL_CANCEL_QUEUE   (1 << 1)

Cancel queue

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

Referenced by local_call(), and local_hangup().

#define LOCAL_MOH_PASSTHRU   (1 << 5)

Pass through music on hold start/stop frames

Definition at line 123 of file chan_local.c.

Referenced by local_alloc(), and local_indicate().

#define LOCAL_NO_OPTIMIZATION   (1 << 4)

Do not optimize using masquerading

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

References ast_channel::_bridge, ast_channel::_softhangup, ast_app_group_update(), ast_bridged_channel(), ast_channel_masquerade(), 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::lock, ast_channel::monitor, local_pvt::owner, and ast_channel::readq.

Referenced by local_write().

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

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(), 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 -1;
00790    }
00791    ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00792    return 0;
00793 }

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

Create a call structure.

Definition at line 621 of file chan_local.c.

References ast_calloc, ast_copy_string(), ast_exists_extension(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_mutex_init(), ast_set_flag, local_pvt::list, LOCAL_MOH_PASSTHRU, LOCAL_NO_OPTIMIZATION, local_pvt_destroy(), and LOG_NOTICE.

Referenced by local_request().

00622 {
00623    struct local_pvt *tmp = NULL;
00624    char *c = NULL, *opts = NULL;
00625 
00626    if (!(tmp = ast_calloc(1, sizeof(*tmp))))
00627       return NULL;
00628 
00629    /* Initialize private structure information */
00630    ast_mutex_init(&tmp->lock);
00631    ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
00632 
00633    /* Look for options */
00634    if ((opts = strchr(tmp->exten, '/'))) {
00635       *opts++ = '\0';
00636       if (strchr(opts, 'n'))
00637          ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
00638       if (strchr(opts, 'm'))
00639          ast_set_flag(tmp, LOCAL_MOH_PASSTHRU);
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 0
00651    /* We can't do this check here, because we don't know the CallerID yet, and
00652     * the CallerID could potentially affect what step is actually taken (or
00653     * even if that step exists). */
00654    if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
00655       ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
00656       tmp = local_pvt_destroy(tmp);
00657    } else {
00658 #endif
00659       /* Add to list */
00660       AST_LIST_LOCK(&locals);
00661       AST_LIST_INSERT_HEAD(&locals, tmp, list);
00662       AST_LIST_UNLOCK(&locals);
00663 #if 0
00664    }
00665 #endif
00666    
00667    return tmp;
00668 }

static int local_answer ( struct ast_channel ast  )  [static]

Definition at line 224 of file chan_local.c.

References answer, 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.

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

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

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    if (!ast_exists_extension(NULL, p->chan->context, p->chan->exten, 1, p->owner->cid.cid_num)) {
00508       ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->chan->exten, p->chan->context);
00509       ast_mutex_unlock(&p->lock);
00510       return -1;
00511    }
00512 
00513    /* copy the channel variables from the incoming channel to the outgoing channel */
00514    /* Note that due to certain assumptions, they MUST be in the same order */
00515    AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) {
00516       namelen = strlen(varptr->name);
00517       len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
00518       if ((new = ast_calloc(1, len))) {
00519          memcpy(new, varptr, len);
00520          new->value = &(new->name[0]) + namelen + 1;
00521          AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries);
00522       }
00523    }
00524    ast_channel_datastore_inherit(p->owner, p->chan);
00525 
00526    /* Start switch on sub channel */
00527    if (!(res = ast_pbx_start(p->chan)))
00528       ast_set_flag(p, LOCAL_LAUNCHED_PBX);
00529 
00530    ast_mutex_unlock(&p->lock);
00531    return res;
00532 }

static int local_devicestate ( void *  data  )  [static]

Adds devicestate to local channels.

Definition at line 128 of file chan_local.c.

References AST_DEVICE_INVALID, AST_DEVICE_UNKNOWN, ast_exists_extension(), ast_log(), ast_strdupa, local_pvt::context, local_pvt::exten, LOG_DEBUG, LOG_WARNING, and option_debug.

00129 {
00130    char *exten = ast_strdupa(data);
00131    char *context = NULL, *opts = NULL;
00132    int res;
00133 
00134    if (!(context = strchr(exten, '@'))) {
00135       ast_log(LOG_WARNING, "Someone used Local/%s somewhere without a @context. This is bad.\n", exten);
00136       return AST_DEVICE_INVALID; 
00137    }
00138 
00139    *context++ = '\0';
00140 
00141    /* Strip options if they exist */
00142    if ((opts = strchr(context, '/')))
00143       *opts = '\0';
00144 
00145    if (option_debug > 2)
00146       ast_log(LOG_DEBUG, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
00147    res = ast_exists_extension(NULL, context, exten, 1, NULL);
00148    if (!res)      
00149       return AST_DEVICE_INVALID;
00150    else
00151       return AST_DEVICE_UNKNOWN;
00152 }

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

References ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_clear_flag, AST_CONTROL_HANGUP, AST_FRAME_CONTROL, ast_hangup(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_module_user_remove, ast_mutex_lock(), ast_mutex_trylock(), 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(), ast_channel::tech_pvt, local_pvt::u_chan, and local_pvt::u_owner.

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

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(), ast_test_flag, f, IS_OUTBOUND, LOCAL_MOH_PASSTHRU, 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 (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) {
00379       ast_moh_start(ast, data, NULL);
00380    } else if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && 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 671 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_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_tech, LOG_WARNING, ast_channel::nativeformats, local_pvt::owner, ast_channel::priority, ast_channel::rawreadformat, ast_channel::rawwriteformat, ast_channel::readformat, local_pvt::reqformat, t, ast_channel::tech, ast_channel::tech_pvt, local_pvt::u_chan, local_pvt::u_owner, and ast_channel::writeformat.

Referenced by local_request().

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

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

References ast_mutex_destroy(), free, and local_pvt::lock.

Referenced by local_alloc(), local_hangup(), local_queue_frame(), and local_request().

00158 {
00159    ast_mutex_destroy(&pvt->lock);
00160    free(pvt);
00161    return NULL;
00162 }

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

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

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

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

Definition at line 314 of file chan_local.c.

References ast_null_frame.

00315 {
00316    return &ast_null_frame;
00317 }

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

Part of PBX interface.

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

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

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

References AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_test_flag, check_bridge(), f, IS_OUTBOUND, LOCAL_ALREADY_MASQED, local_queue_frame(), local_pvt::lock, LOG_DEBUG, ast_channel::name, option_debug, and ast_channel::tech_pvt.

00320 {
00321    struct local_pvt *p = ast->tech_pvt;
00322    int res = -1;
00323    int isoutbound;
00324 
00325    if (!p)
00326       return -1;
00327 
00328    /* Just queue for delivery to the other side */
00329    ast_mutex_lock(&p->lock);
00330    isoutbound = IS_OUTBOUND(ast, p);
00331    if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO))
00332       check_bridge(p, isoutbound);
00333    if (!ast_test_flag(p, LOCAL_ALREADY_MASQED))
00334       res = local_queue_frame(p, isoutbound, f, ast, 1);
00335    else {
00336       if (option_debug)
00337          ast_log(LOG_DEBUG, "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 int locals_show ( int  fd,
int  argc,
char **  argv 
) [static]

CLI command "local show channels".

Definition at line 752 of file chan_local.c.

References ast_cli(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), local_pvt::context, local_pvt::exten, local_pvt::list, local_pvt::lock, ast_channel::name, local_pvt::owner, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

00753 {
00754    struct local_pvt *p = NULL;
00755 
00756    if (argc != 3)
00757       return RESULT_SHOWUSAGE;
00758 
00759    AST_LIST_LOCK(&locals);
00760    if (!AST_LIST_EMPTY(&locals)) {
00761       AST_LIST_TRAVERSE(&locals, p, list) {
00762          ast_mutex_lock(&p->lock);
00763          ast_cli(fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
00764          ast_mutex_unlock(&p->lock);
00765       }
00766    } else
00767       ast_cli(fd, "No local channels in use\n");
00768    AST_LIST_UNLOCK(&locals);
00769 
00770    return RESULT_SUCCESS;
00771 }

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 | AST_MODFLAG_BUILDSUM, .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 = "361d7bb937402d51e4658efb5b4d76e4" , .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:

 {
   { { "local", "show", "channels", NULL },
   locals_show, "List status of local channels",
   show_locals_usage },
}

Definition at line 777 of file chan_local.c.

Referenced by load_module(), and unload_module().

struct ast_channel_tech local_tech [static]

Definition at line 84 of file chan_local.c.

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

char show_locals_usage[] [static]

Initial value:

 
"Usage: local show channels\n"
"       Provides summary information on active local proxy channels.\n"

Definition at line 773 of file chan_local.c.

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

Definition at line 65 of file chan_local.c.


Generated on Sun Aug 15 20:33:35 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7