Wed Feb 11 12:00:13 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 808 of file chan_local.c.

00808 : used internally by other modules)");

static void __unreg_module ( void   )  [static]

Definition at line 808 of file chan_local.c.

00808 : 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_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_channel_masquerade(p->owner, p->chan->_bridge);
00274                   ast_set_flag(p, LOCAL_ALREADY_MASQED);
00275                }
00276                ast_mutex_unlock(&p->owner->lock);
00277             }
00278             ast_mutex_unlock(&(p->chan->_bridge)->lock);
00279          }
00280       }
00281    /* We only allow masquerading in one 'direction'... it's important to preserve the state
00282       (group variables, etc.) that live on p->chan->_bridge (and were put there by the dialplan)
00283       when the local channels go away.
00284    */
00285 #if 0
00286    } else if (!isoutbound && p->owner && p->owner->_bridge && p->chan && AST_LIST_EMPTY(&p->chan->readq)) {
00287       /* Masquerade bridged channel into chan */
00288       if (!ast_mutex_trylock(&(p->owner->_bridge)->lock)) {
00289          if (!p->owner->_bridge->_softhangup) {
00290             if (!ast_mutex_trylock(&p->chan->lock)) {
00291                if (!p->chan->_softhangup) {
00292                   ast_channel_masquerade(p->chan, p->owner->_bridge);
00293                   ast_set_flag(p, LOCAL_ALREADY_MASQED);
00294                }
00295                ast_mutex_unlock(&p->chan->lock);
00296             }
00297          }
00298          ast_mutex_unlock(&(p->owner->_bridge)->lock);
00299       }
00300 #endif
00301    }
00302 }

static int load_module ( void   )  [static]

Load module into PBX, register channel.

Definition at line 775 of file chan_local.c.

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

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

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

Create a call structure.

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

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

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

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

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

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

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

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

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

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

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

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

static int local_hangup ( struct ast_channel ast  )  [static]

Hangup a call through the local proxy channel.

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

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

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

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

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

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

Start new local channel.

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

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

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    /* do not queue frame if generator is on both local channels */
00172    if (us && us->generator && other->generator)
00173       return 0;
00174 
00175    /* Set glare detection */
00176    ast_set_flag(p, LOCAL_GLARE_DETECT);
00177    if (ast_test_flag(p, LOCAL_CANCEL_QUEUE)) {
00178       /* We had a glare on the hangup.  Forget all this business,
00179       return and destroy p.  */
00180       ast_mutex_unlock(&p->lock);
00181       p = local_pvt_destroy(p);
00182       return -1;
00183    }
00184    if (!other) {
00185       ast_clear_flag(p, LOCAL_GLARE_DETECT);
00186       return 0;
00187    }
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 304 of file chan_local.c.

References ast_null_frame.

00305 {
00306    return &ast_null_frame;
00307 }

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

Part of PBX interface.

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

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

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

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

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

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

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

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

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

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

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

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

CLI command "local show channels".

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

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

static int unload_module ( void   )  [static]

Unload the local proxy channel from Asterisk.

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

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


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

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 808 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 768 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 764 of file chan_local.c.

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

Definition at line 65 of file chan_local.c.


Generated on Wed Feb 11 12:00:13 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7