Tue Jul 14 23:10:11 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 811 of file chan_local.c.

00811 : used internally by other modules)");

static void __unreg_module ( void   )  [static]

Definition at line 811 of file chan_local.c.

00811 : used internally by other modules)");

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

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

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

static int load_module ( void   )  [static]

Load module into PBX, register channel.

Definition at line 778 of file chan_local.c.

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

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

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

Create a call structure.

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

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

static int local_answer ( struct ast_channel ast  )  [static]

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

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

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

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

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

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

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

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

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

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

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

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

static int local_hangup ( struct ast_channel ast  )  [static]

Hangup a call through the local proxy channel.

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

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

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

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

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

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

Start new local channel.

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

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

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

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

Definition at line 310 of file chan_local.c.

References ast_null_frame.

00311 {
00312    return &ast_null_frame;
00313 }

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

Part of PBX interface.

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

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

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

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

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

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

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

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

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

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

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

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

CLI command "local show channels".

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

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

static int unload_module ( void   )  [static]

Unload the local proxy channel from Asterisk.

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

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


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

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 811 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 771 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 767 of file chan_local.c.

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

Definition at line 65 of file chan_local.c.


Generated on Tue Jul 14 23:10:12 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7