Sun Dec 18 20:55:46 2011

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"

Include dependency graph for chan_local.c:

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

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

static int load_module ( void   )  [static]

Load module into PBX, register channel.

Definition at line 733 of file chan_local.c.

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

00734 {
00735    /* Make sure we can register our channel type */
00736    if (ast_channel_register(&local_tech)) {
00737       ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
00738       return -1;
00739    }
00740    ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00741    return 0;
00742 }

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

Create a call structure.

Definition at line 579 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_pvt::context, local_pvt::exten, LOCAL_NO_OPTIMIZATION, local_pvt_destroy(), locals, local_pvt::lock, LOG_NOTICE, and local_pvt::reqformat.

Referenced by local_request().

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

static int local_answer ( struct ast_channel ast  )  [static]

Definition at line 209 of file chan_local.c.

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

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

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 454 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, and ast_channel::varshead.

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

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

References AST_FRAME_DTMF_BEGIN, ast_mutex_lock(), ast_mutex_unlock(), IS_OUTBOUND, local_queue_frame(), local_pvt::lock, ast_frame::subclass, and ast_channel::tech_pvt.

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

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

Definition at line 393 of file chan_local.c.

References AST_FRAME_DTMF_END, ast_mutex_lock(), ast_mutex_unlock(), IS_OUTBOUND, ast_frame::len, local_queue_frame(), local_pvt::lock, ast_frame::subclass, and ast_channel::tech_pvt.

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

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

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

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

static int local_hangup ( struct ast_channel ast  )  [static]

Hangup a call through the local proxy channel.

Definition at line 502 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_unlock(), ast_set_flag, ast_test_flag, local_pvt::chan, 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.

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

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

Definition at line 345 of file chan_local.c.

References AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, ast_moh_start(), ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_frame::data, ast_frame::datalen, IS_OUTBOUND, local_queue_frame(), local_pvt::lock, ast_frame::subclass, and ast_channel::tech_pvt.

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

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

Start new local channel.

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

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

static struct local_pvt* local_pvt_destroy ( struct local_pvt pvt  )  [static, read]

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_unlock(), ast_queue_frame(), ast_set_flag, ast_test_flag, local_pvt::chan, 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          ast_channel_unlock(us);
00190       }
00191       usleep(1);
00192       if (us && us_locked) {
00193          ast_channel_lock(us);
00194       }
00195       ast_mutex_lock(&p->lock);
00196       other = isoutbound ? p->owner : p->chan;
00197    }
00198 
00199    if (other) {
00200       ast_queue_frame(other, f);
00201       ast_channel_unlock(other);
00202    }
00203 
00204    ast_clear_flag(p, LOCAL_GLARE_DETECT);
00205 
00206    return 0;
00207 }

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

Definition at line 292 of file chan_local.c.

References ast_null_frame.

00293 {
00294    return &ast_null_frame;
00295 }

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

Part of PBX interface.

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

00683 {
00684    struct local_pvt *p = NULL;
00685    struct ast_channel *chan = NULL;
00686 
00687    /* Allocate a new private structure and then Asterisk channel */
00688    if ((p = local_alloc(data, format))) {
00689       if (!(chan = local_new(p, AST_STATE_DOWN))) {
00690          AST_LIST_LOCK(&locals);
00691          AST_LIST_REMOVE(&locals, p, list);
00692          AST_LIST_UNLOCK(&locals);
00693          p = local_pvt_destroy(p);
00694       }
00695    }
00696 
00697    return chan;
00698 }

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

Definition at line 432 of file chan_local.c.

References AST_FRAME_HTML, ast_mutex_lock(), ast_mutex_unlock(), ast_frame::data, ast_frame::datalen, IS_OUTBOUND, local_queue_frame(), local_pvt::lock, ast_frame::subclass, and ast_channel::tech_pvt.

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

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

Definition at line 413 of file chan_local.c.

References AST_FRAME_TEXT, ast_mutex_lock(), ast_mutex_unlock(), ast_frame::data, ast_frame::datalen, IS_OUTBOUND, local_queue_frame(), local_pvt::lock, and ast_channel::tech_pvt.

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

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

Definition at line 297 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(), ast_frame::frametype, IS_OUTBOUND, LOCAL_ALREADY_MASQED, local_queue_frame(), local_pvt::lock, LOG_DEBUG, option_debug, and ast_channel::tech_pvt.

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

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

CLI command "local show channels".

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

00702 {
00703    struct local_pvt *p = NULL;
00704 
00705    if (argc != 3)
00706       return RESULT_SHOWUSAGE;
00707 
00708    AST_LIST_LOCK(&locals);
00709    if (!AST_LIST_EMPTY(&locals)) {
00710       AST_LIST_TRAVERSE(&locals, p, list) {
00711          ast_mutex_lock(&p->lock);
00712          ast_cli(fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
00713          ast_mutex_unlock(&p->lock);
00714       }
00715    } else
00716       ast_cli(fd, "No local channels in use\n");
00717    AST_LIST_UNLOCK(&locals);
00718 
00719    return RESULT_SUCCESS;
00720 }

static int unload_module ( void   )  [static]

Unload the local proxy channel from Asterisk.

Definition at line 745 of file chan_local.c.

References ast_channel_unregister(), ast_cli_unregister_multiple(), AST_LIST_HEAD_DESTROY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, cli_local, locals, LOG_WARNING, and local_pvt::owner.

00746 {
00747    struct local_pvt *p = NULL;
00748 
00749    /* First, take us out of the channel loop */
00750    ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00751    ast_channel_unregister(&local_tech);
00752    if (!AST_LIST_LOCK(&locals)) {
00753       /* Hangup all interfaces if they have an owner */
00754       AST_LIST_TRAVERSE(&locals, p, list) {
00755          if (p->owner)
00756             ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
00757       }
00758       AST_LIST_UNLOCK(&locals);
00759       AST_LIST_HEAD_DESTROY(&locals);
00760    } else {
00761       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
00762       return -1;
00763    }     
00764    return 0;
00765 }


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

char show_locals_usage[] [static]

Initial value:

 
"Usage: local show channels\n"
"       Provides summary information on active local proxy channels.\n"

Definition at line 722 of file chan_local.c.

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

Definition at line 65 of file chan_local.c.


Generated on Sun Dec 18 20:55:46 2011 for Asterisk - the Open Source PBX by  doxygen 1.5.6