Mon Nov 24 15:34:30 2008

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

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 AST_LIST_HEAD_STATIC (locals, local_pvt)
 AST_MODULE_INFO_STANDARD (ASTERISK_GPL_KEY,"Local Proxy Channel (Note: used internally by other modules)")
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_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 AST_LIST_HEAD_STATIC ( locals  ,
local_pvt   
) [static]

AST_MODULE_INFO_STANDARD ( ASTERISK_GPL_KEY  ,
"Local Proxy Channel (Note: used internally by other modules)"   
)

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

Definition at line 233 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, local_pvt::chan, LOCAL_ALREADY_MASQED, LOCAL_NO_OPTIMIZATION, ast_channel::lock, ast_channel::monitor, and local_pvt::owner.

Referenced by local_write().

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

static int load_module ( void   )  [static]

Load module into PBX, register channel.

Definition at line 743 of file chan_local.c.

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

00744 {
00745    /* Make sure we can register our channel type */
00746    if (ast_channel_register(&local_tech)) {
00747       ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
00748       return -1;
00749    }
00750    ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00751    return 0;
00752 }

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

Create a call structure.

Definition at line 589 of file chan_local.c.

References ast_calloc, ast_exists_extension(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_mutex_init(), ast_set_flag, LOCAL_NO_OPTIMIZATION, local_pvt_destroy(), locals, and LOG_NOTICE.

Referenced by local_request().

00590 {
00591    struct local_pvt *tmp = NULL;
00592    char *c = NULL, *opts = NULL;
00593 
00594    if (!(tmp = ast_calloc(1, sizeof(*tmp))))
00595       return NULL;
00596 
00597    /* Initialize private structure information */
00598    ast_mutex_init(&tmp->lock);
00599    ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
00600 
00601    /* Look for options */
00602    if ((opts = strchr(tmp->exten, '/'))) {
00603       *opts++ = '\0';
00604       if (strchr(opts, 'n'))
00605          ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
00606    }
00607 
00608    /* Look for a context */
00609    if ((c = strchr(tmp->exten, '@')))
00610       *c++ = '\0';
00611 
00612    ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
00613 
00614    tmp->reqformat = format;
00615 
00616    if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
00617       ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
00618       tmp = local_pvt_destroy(tmp);
00619    } else {
00620       /* Add to list */
00621       AST_LIST_LOCK(&locals);
00622       AST_LIST_INSERT_HEAD(&locals, tmp, list);
00623       AST_LIST_UNLOCK(&locals);
00624    }
00625    
00626    return tmp;
00627 }

static int local_answer ( struct ast_channel ast  )  [static]

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

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

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

References accountcode, ast_calloc, ast_cdr_update(), ast_channel_datastore_inherit(), AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, 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_name, ast_callerid::cid_num, ast_callerid::cid_pres, ast_callerid::cid_rdnis, language, len, LOCAL_LAUNCHED_PBX, local_pvt::lock, ast_var_t::name, local_pvt::owner, ast_channel::tech_pvt, ast_var_t::value, and ast_channel::varshead.

00457 {
00458    struct local_pvt *p = ast->tech_pvt;
00459    int res;
00460    struct ast_var_t *varptr = NULL, *new;
00461    size_t len, namelen;
00462 
00463    if (!p)
00464       return -1;
00465    
00466    ast_mutex_lock(&p->lock);
00467 
00468    /*
00469     * Note that cid_num and cid_name aren't passed in the ast_channel_alloc
00470     * call, so it's done here instead.
00471     */
00472    p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num);
00473    p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name);
00474    p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis);
00475    p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani);
00476    p->chan->cid.cid_pres = p->owner->cid.cid_pres;
00477    ast_string_field_set(p->chan, language, p->owner->language);
00478    ast_string_field_set(p->chan, accountcode, p->owner->accountcode);
00479    ast_cdr_update(p->chan);
00480    p->chan->cdrflags = p->owner->cdrflags;
00481 
00482    /* copy the channel variables from the incoming channel to the outgoing channel */
00483    /* Note that due to certain assumptions, they MUST be in the same order */
00484    AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) {
00485       namelen = strlen(varptr->name);
00486       len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
00487       if ((new = ast_calloc(1, len))) {
00488          memcpy(new, varptr, len);
00489          new->value = &(new->name[0]) + namelen + 1;
00490          AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries);
00491       }
00492    }
00493    ast_channel_datastore_inherit(p->owner, p->chan);
00494 
00495    /* Start switch on sub channel */
00496    if (!(res = ast_pbx_start(p->chan)))
00497       ast_set_flag(p, LOCAL_LAUNCHED_PBX);
00498 
00499    ast_mutex_unlock(&p->lock);
00500    return res;
00501 }

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

00377 {
00378    struct local_pvt *p = ast->tech_pvt;
00379    int res = -1;
00380    struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
00381    int isoutbound;
00382 
00383    if (!p)
00384       return -1;
00385 
00386    ast_mutex_lock(&p->lock);
00387    isoutbound = IS_OUTBOUND(ast, p);
00388    f.subclass = digit;
00389    if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00390       ast_mutex_unlock(&p->lock);
00391 
00392    return res;
00393 }

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

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

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

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

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

00326 {
00327    struct local_pvt *p = newchan->tech_pvt;
00328 
00329    if (!p)
00330       return -1;
00331 
00332    ast_mutex_lock(&p->lock);
00333 
00334    if ((p->owner != oldchan) && (p->chan != oldchan)) {
00335       ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
00336       ast_mutex_unlock(&p->lock);
00337       return -1;
00338    }
00339    if (p->owner == oldchan)
00340       p->owner = newchan;
00341    else
00342       p->chan = newchan;
00343    ast_mutex_unlock(&p->lock);
00344    return 0;
00345 }

static int local_hangup ( struct ast_channel ast  )  [static]

Hangup a call through the local proxy channel.

Definition at line 504 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, f, IS_OUTBOUND, LOCAL_CANCEL_QUEUE, LOCAL_GLARE_DETECT, LOCAL_LAUNCHED_PBX, local_pvt_destroy(), local_queue_frame(), locals, 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.

00505 {
00506    struct local_pvt *p = ast->tech_pvt;
00507    int isoutbound;
00508    struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP };
00509    struct ast_channel *ochan = NULL;
00510    int glaredetect = 0, res = 0;
00511 
00512    if (!p)
00513       return -1;
00514 
00515    while (ast_mutex_trylock(&p->lock)) {
00516       ast_channel_unlock(ast);
00517       usleep(1);
00518       ast_channel_lock(ast);
00519    }
00520 
00521    isoutbound = IS_OUTBOUND(ast, p);
00522    if (isoutbound) {
00523       const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
00524       if ((status) && (p->owner)) {
00525          /* Deadlock avoidance */
00526          while (p->owner && ast_channel_trylock(p->owner)) {
00527             ast_mutex_unlock(&p->lock);
00528             if (ast) {
00529                ast_channel_unlock(ast);
00530             }
00531             usleep(1);
00532             if (ast) {
00533                ast_channel_lock(ast);
00534             }
00535             ast_mutex_lock(&p->lock);
00536          }
00537          if (p->owner) {
00538             pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
00539             ast_channel_unlock(p->owner);
00540          }
00541       }
00542       p->chan = NULL;
00543       ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
00544       ast_module_user_remove(p->u_chan);
00545    } else {
00546       p->owner = NULL;
00547       ast_module_user_remove(p->u_owner);
00548       if (p->chan) {
00549          ast_queue_hangup(p->chan);
00550       }
00551    }
00552    
00553    ast->tech_pvt = NULL;
00554    
00555    if (!p->owner && !p->chan) {
00556       /* Okay, done with the private part now, too. */
00557       glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT);
00558       /* If we have a queue holding, don't actually destroy p yet, but
00559          let local_queue do it. */
00560       if (glaredetect)
00561          ast_set_flag(p, LOCAL_CANCEL_QUEUE);
00562       ast_mutex_unlock(&p->lock);
00563       /* Remove from list */
00564       AST_LIST_LOCK(&locals);
00565       AST_LIST_REMOVE(&locals, p, list);
00566       AST_LIST_UNLOCK(&locals);
00567       /* Grab / release lock just in case */
00568       ast_mutex_lock(&p->lock);
00569       ast_mutex_unlock(&p->lock);
00570       /* And destroy */
00571       if (!glaredetect) {
00572          p = local_pvt_destroy(p);
00573       }
00574       return 0;
00575    }
00576    if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX))
00577       /* Need to actually hangup since there is no PBX */
00578       ochan = p->chan;
00579    else
00580       res = local_queue_frame(p, isoutbound, &f, NULL, 1);
00581    if (!res)
00582       ast_mutex_unlock(&p->lock);
00583    if (ochan)
00584       ast_hangup(ochan);
00585    return 0;
00586 }

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

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

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

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

Start new local channel.

Definition at line 630 of file chan_local.c.

References ast_channel::amaflags, ast_best_codec(), ast_channel_alloc(), ast_channel_free(), 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, fmt, 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().

00631 {
00632    struct ast_channel *tmp = NULL, *tmp2 = NULL;
00633    int randnum = ast_random() & 0xffff, fmt = 0;
00634    const char *t;
00635    int ama;
00636 
00637    /* Allocate two new Asterisk channels */
00638    /* safe accountcode */
00639    if (p->owner && p->owner->accountcode)
00640       t = p->owner->accountcode;
00641    else
00642       t = "";
00643 
00644    if (p->owner)
00645       ama = p->owner->amaflags;
00646    else
00647       ama = 0;
00648    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)) 
00649          || !(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))) {
00650       if (tmp)
00651          ast_channel_free(tmp);
00652       if (tmp2)
00653          ast_channel_free(tmp2);
00654       ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
00655       return NULL;
00656    } 
00657 
00658    tmp2->tech = tmp->tech = &local_tech;
00659 
00660    tmp->nativeformats = p->reqformat;
00661    tmp2->nativeformats = p->reqformat;
00662 
00663    /* Determine our read/write format and set it on each channel */
00664    fmt = ast_best_codec(p->reqformat);
00665    tmp->writeformat = fmt;
00666    tmp2->writeformat = fmt;
00667    tmp->rawwriteformat = fmt;
00668    tmp2->rawwriteformat = fmt;
00669    tmp->readformat = fmt;
00670    tmp2->readformat = fmt;
00671    tmp->rawreadformat = fmt;
00672    tmp2->rawreadformat = fmt;
00673 
00674    tmp->tech_pvt = p;
00675    tmp2->tech_pvt = p;
00676 
00677    p->owner = tmp;
00678    p->chan = tmp2;
00679    p->u_owner = ast_module_user_add(p->owner);
00680    p->u_chan = ast_module_user_add(p->chan);
00681 
00682    ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
00683    ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
00684    ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten));
00685    tmp->priority = 1;
00686    tmp2->priority = 1;
00687 
00688    return tmp;
00689 }

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, 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    /* Ensure that we have both channels locked */
00186    while (other && ast_channel_trylock(other)) {
00187       ast_mutex_unlock(&p->lock);
00188       if (us && us_locked) {
00189          do {
00190             ast_channel_unlock(us);
00191             usleep(1);
00192             ast_channel_lock(us);
00193          } while (ast_mutex_trylock(&p->lock));
00194       } else {
00195          usleep(1);
00196          ast_mutex_lock(&p->lock);
00197       }
00198       other = isoutbound ? p->owner : p->chan;
00199    }
00200 
00201    if (other) {
00202       ast_queue_frame(other, f);
00203       ast_channel_unlock(other);
00204    }
00205 
00206    ast_clear_flag(p, LOCAL_GLARE_DETECT);
00207 
00208    return 0;
00209 }

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

Definition at line 294 of file chan_local.c.

References ast_null_frame.

00295 {
00296    return &ast_null_frame;
00297 }

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

Part of PBX interface.

Definition at line 692 of file chan_local.c.

References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, AST_STATE_DOWN, local_pvt::chan, local_alloc(), local_new(), local_pvt_destroy(), and locals.

00693 {
00694    struct local_pvt *p = NULL;
00695    struct ast_channel *chan = NULL;
00696 
00697    /* Allocate a new private structure and then Asterisk channel */
00698    if ((p = local_alloc(data, format))) {
00699       if (!(chan = local_new(p, AST_STATE_DOWN))) {
00700          AST_LIST_LOCK(&locals);
00701          AST_LIST_REMOVE(&locals, p, list);
00702          AST_LIST_UNLOCK(&locals);
00703          p = local_pvt_destroy(p);
00704       }
00705    }
00706 
00707    return chan;
00708 }

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

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

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

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

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

00416 {
00417    struct local_pvt *p = ast->tech_pvt;
00418    int res = -1;
00419    struct ast_frame f = { AST_FRAME_TEXT, };
00420    int isoutbound;
00421 
00422    if (!p)
00423       return -1;
00424 
00425    ast_mutex_lock(&p->lock);
00426    isoutbound = IS_OUTBOUND(ast, p);
00427    f.data = (char *) text;
00428    f.datalen = strlen(text) + 1;
00429    if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00430       ast_mutex_unlock(&p->lock);
00431    return res;
00432 }

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

Definition at line 299 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, option_debug, and ast_channel::tech_pvt.

00300 {
00301    struct local_pvt *p = ast->tech_pvt;
00302    int res = -1;
00303    int isoutbound;
00304 
00305    if (!p)
00306       return -1;
00307 
00308    /* Just queue for delivery to the other side */
00309    ast_mutex_lock(&p->lock);
00310    isoutbound = IS_OUTBOUND(ast, p);
00311    if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO))
00312       check_bridge(p, isoutbound);
00313    if (!ast_test_flag(p, LOCAL_ALREADY_MASQED))
00314       res = local_queue_frame(p, isoutbound, f, ast, 1);
00315    else {
00316       if (option_debug)
00317          ast_log(LOG_DEBUG, "Not posting to queue since already masked on '%s'\n", ast->name);
00318       res = 0;
00319    }
00320    if (!res)
00321       ast_mutex_unlock(&p->lock);
00322    return res;
00323 }

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

CLI command "local show channels".

Definition at line 711 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, locals, local_pvt::lock, local_pvt::owner, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

00712 {
00713    struct local_pvt *p = NULL;
00714 
00715    if (argc != 3)
00716       return RESULT_SHOWUSAGE;
00717 
00718    AST_LIST_LOCK(&locals);
00719    if (!AST_LIST_EMPTY(&locals)) {
00720       AST_LIST_TRAVERSE(&locals, p, list) {
00721          ast_mutex_lock(&p->lock);
00722          ast_cli(fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
00723          ast_mutex_unlock(&p->lock);
00724       }
00725    } else
00726       ast_cli(fd, "No local channels in use\n");
00727    AST_LIST_UNLOCK(&locals);
00728 
00729    return RESULT_SUCCESS;
00730 }

static int unload_module ( void   )  [static]

Unload the local proxy channel from Asterisk.

Definition at line 755 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_tech, locals, LOG_WARNING, and local_pvt::owner.

00756 {
00757    struct local_pvt *p = NULL;
00758 
00759    /* First, take us out of the channel loop */
00760    ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00761    ast_channel_unregister(&local_tech);
00762    if (!AST_LIST_LOCK(&locals)) {
00763       /* Hangup all interfaces if they have an owner */
00764       AST_LIST_TRAVERSE(&locals, p, list) {
00765          if (p->owner)
00766             ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
00767       }
00768       AST_LIST_UNLOCK(&locals);
00769    } else {
00770       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
00771       return -1;
00772    }     
00773    return 0;
00774 }


Variable Documentation

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

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

Definition at line 65 of file chan_local.c.


Generated on Mon Nov 24 15:34:30 2008 for Asterisk - the Open Source PBX by  doxygen 1.4.7