Thu May 14 14:49:37 2009

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_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 = "f450f61f60e761b3aa089ebed76ca8a5" , .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_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 809 of file chan_local.c.

00809 : used internally by other modules)");

static void __unreg_module ( void   )  [static]

Definition at line 809 of file chan_local.c.

00809 : used internally by other modules)");

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

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

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

static int load_module ( void   )  [static]

Load module into PBX, register channel.

Definition at line 776 of file chan_local.c.

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

00777 {
00778    /* Make sure we can register our channel type */
00779    if (ast_channel_register(&local_tech)) {
00780       ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
00781       return -1;
00782    }
00783    ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00784    return 0;
00785 }

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

Create a call structure.

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

Referenced by local_request().

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

static int local_answer ( struct ast_channel ast  )  [static]

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

00216 {
00217    struct local_pvt *p = ast->tech_pvt;
00218    int isoutbound;
00219    int res = -1;
00220 
00221    if (!p)
00222       return -1;
00223 
00224    ast_mutex_lock(&p->lock);
00225    isoutbound = IS_OUTBOUND(ast, p);
00226    if (isoutbound) {
00227       /* Pass along answer since somebody answered us */
00228       struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
00229       res = local_queue_frame(p, isoutbound, &answer, ast, 1);
00230    } else
00231       ast_log(LOG_WARNING, "Huh?  Local is being asked to answer?\n");
00232    if (!res)
00233       ast_mutex_unlock(&p->lock);
00234    return res;
00235 }

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

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

static int local_devicestate ( void *  data  )  [static]

Adds devicestate to local channels.

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

00128 {
00129    char *exten = ast_strdupa(data);
00130    char *context = NULL, *opts = NULL;
00131    int res;
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    if (option_debug > 2)
00145       ast_log(LOG_DEBUG, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
00146    res = ast_exists_extension(NULL, context, exten, 1, NULL);
00147    if (!res)      
00148       return AST_DEVICE_INVALID;
00149    else
00150       return AST_DEVICE_UNKNOWN;
00151 }

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

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

00388 {
00389    struct local_pvt *p = ast->tech_pvt;
00390    int res = -1;
00391    struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
00392    int isoutbound;
00393 
00394    if (!p)
00395       return -1;
00396 
00397    ast_mutex_lock(&p->lock);
00398    isoutbound = IS_OUTBOUND(ast, p);
00399    f.subclass = digit;
00400    if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00401       ast_mutex_unlock(&p->lock);
00402 
00403    return res;
00404 }

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

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

00407 {
00408    struct local_pvt *p = ast->tech_pvt;
00409    int res = -1;
00410    struct ast_frame f = { AST_FRAME_DTMF_END, };
00411    int isoutbound;
00412 
00413    if (!p)
00414       return -1;
00415 
00416    ast_mutex_lock(&p->lock);
00417    isoutbound = IS_OUTBOUND(ast, p);
00418    f.subclass = digit;
00419    f.len = duration;
00420    if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00421       ast_mutex_unlock(&p->lock);
00422 
00423    return res;
00424 }

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

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

00337 {
00338    struct local_pvt *p = newchan->tech_pvt;
00339 
00340    if (!p)
00341       return -1;
00342 
00343    ast_mutex_lock(&p->lock);
00344 
00345    if ((p->owner != oldchan) && (p->chan != oldchan)) {
00346       ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
00347       ast_mutex_unlock(&p->lock);
00348       return -1;
00349    }
00350    if (p->owner == oldchan)
00351       p->owner = newchan;
00352    else
00353       p->chan = newchan;
00354    ast_mutex_unlock(&p->lock);
00355    return 0;
00356 }

static int local_hangup ( struct ast_channel ast  )  [static]

Hangup a call through the local proxy channel.

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

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

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

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

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

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

Start new local channel.

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

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

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

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

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

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

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

Definition at line 305 of file chan_local.c.

References ast_null_frame.

00306 {
00307    return &ast_null_frame;
00308 }

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

Part of PBX interface.

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

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

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

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

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

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

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

00427 {
00428    struct local_pvt *p = ast->tech_pvt;
00429    int res = -1;
00430    struct ast_frame f = { AST_FRAME_TEXT, };
00431    int isoutbound;
00432 
00433    if (!p)
00434       return -1;
00435 
00436    ast_mutex_lock(&p->lock);
00437    isoutbound = IS_OUTBOUND(ast, p);
00438    f.data = (char *) text;
00439    f.datalen = strlen(text) + 1;
00440    if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00441       ast_mutex_unlock(&p->lock);
00442    return res;
00443 }

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

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

00311 {
00312    struct local_pvt *p = ast->tech_pvt;
00313    int res = -1;
00314    int isoutbound;
00315 
00316    if (!p)
00317       return -1;
00318 
00319    /* Just queue for delivery to the other side */
00320    ast_mutex_lock(&p->lock);
00321    isoutbound = IS_OUTBOUND(ast, p);
00322    if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO))
00323       check_bridge(p, isoutbound);
00324    if (!ast_test_flag(p, LOCAL_ALREADY_MASQED))
00325       res = local_queue_frame(p, isoutbound, f, ast, 1);
00326    else {
00327       if (option_debug)
00328          ast_log(LOG_DEBUG, "Not posting to queue since already masked on '%s'\n", ast->name);
00329       res = 0;
00330    }
00331    if (!res)
00332       ast_mutex_unlock(&p->lock);
00333    return res;
00334 }

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

CLI command "local show channels".

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

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

static int unload_module ( void   )  [static]

Unload the local proxy channel from Asterisk.

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

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


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

Definition at line 809 of file chan_local.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 809 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 769 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 765 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 May 14 14:49:37 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7