Thu Jan 28 17:35:54 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 = "6989f2ec67f8497e38c12890500c525b" , .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 819 of file chan_local.c.

00819 : used internally by other modules)");

static void __unreg_module ( void   )  [static]

Definition at line 819 of file chan_local.c.

00819 : used internally by other modules)");

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

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

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

static int load_module ( void   )  [static]

Load module into PBX, register channel.

Definition at line 786 of file chan_local.c.

References ast_channel_register(), ast_cli_register_multiple(), ast_log(), cli_local, local_tech, and LOG_ERROR.

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

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

Create a call structure.

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

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

static int local_answer ( struct ast_channel ast  )  [static]

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

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

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

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

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

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

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

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

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

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

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

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

static int local_hangup ( struct ast_channel ast  )  [static]

Hangup a call through the local proxy channel.

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

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

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

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

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

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

Start new local channel.

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

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

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::_bridge, ast_channel::appl, 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_strlen_zero(), ast_test_flag, local_pvt::chan, f, ast_channel::generator, LOCAL_CANCEL_QUEUE, LOCAL_GLARE_DETECT, local_pvt_destroy(), local_pvt::lock, local_pvt::owner, and ast_channel::pbx.

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       if (other->pbx || other->_bridge || !ast_strlen_zero(other->appl)) {
00216          ast_queue_frame(other, f);
00217       } /* else the frame won't go anywhere */
00218       ast_channel_unlock(other);
00219    }
00220 
00221    ast_clear_flag(p, LOCAL_GLARE_DETECT);
00222 
00223    return 0;
00224 }

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

Definition at line 316 of file chan_local.c.

References ast_null_frame.

00317 {
00318    return &ast_null_frame;
00319 }

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

Part of PBX interface.

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

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

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

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

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

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

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

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

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

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

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

static int locals_show ( int  fd,
int  argc,
char **  argv 
) [static]

CLI command "local show channels".

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

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

static int unload_module ( void   )  [static]

Unload the local proxy channel from Asterisk.

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

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


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

Definition at line 819 of file chan_local.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 819 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 779 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 775 of file chan_local.c.

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

Definition at line 65 of file chan_local.c.


Generated on Thu Jan 28 17:35:54 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7