Fri Aug 24 02:23:43 2007

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")
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 int local_queue_frame (struct local_pvt *p, int isoutbound, struct ast_frame *f, struct ast_channel *us)
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"   
)

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

Definition at line 222 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, and local_pvt::owner.

Referenced by local_write().

00223 {
00224    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)))
00225       return;
00226 
00227    /* only do the masquerade if we are being called on the outbound channel,
00228       if it has been bridged to another channel and if there are no pending
00229       frames on the owner channel (because they would be transferred to the
00230       outbound channel during the masquerade)
00231    */
00232    if (isoutbound && p->chan->_bridge /* Not ast_bridged_channel!  Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) {
00233       /* Masquerade bridged channel into owner */
00234       /* Lock everything we need, one by one, and give up if
00235          we can't get everything.  Remember, we'll get another
00236          chance in just a little bit */
00237       if (!ast_mutex_trylock(&(p->chan->_bridge)->lock)) {
00238          if (!p->chan->_bridge->_softhangup) {
00239             if (!ast_mutex_trylock(&p->owner->lock)) {
00240                if (!p->owner->_softhangup) {
00241                   ast_channel_masquerade(p->owner, p->chan->_bridge);
00242                   ast_set_flag(p, LOCAL_ALREADY_MASQED);
00243                }
00244                ast_mutex_unlock(&p->owner->lock);
00245             }
00246             ast_mutex_unlock(&(p->chan->_bridge)->lock);
00247          }
00248       }
00249    /* We only allow masquerading in one 'direction'... it's important to preserve the state
00250       (group variables, etc.) that live on p->chan->_bridge (and were put there by the dialplan)
00251       when the local channels go away.
00252    */
00253 #if 0
00254    } else if (!isoutbound && p->owner && p->owner->_bridge && p->chan && AST_LIST_EMPTY(&p->chan->readq)) {
00255       /* Masquerade bridged channel into chan */
00256       if (!ast_mutex_trylock(&(p->owner->_bridge)->lock)) {
00257          if (!p->owner->_bridge->_softhangup) {
00258             if (!ast_mutex_trylock(&p->chan->lock)) {
00259                if (!p->chan->_softhangup) {
00260                   ast_channel_masquerade(p->chan, p->owner->_bridge);
00261                   ast_set_flag(p, LOCAL_ALREADY_MASQED);
00262                }
00263                ast_mutex_unlock(&p->chan->lock);
00264             }
00265          }
00266          ast_mutex_unlock(&(p->owner->_bridge)->lock);
00267       }
00268 #endif
00269    }
00270 }

static int load_module ( void   )  [static]

Load module into PBX, register channel.

Definition at line 693 of file chan_local.c.

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

00694 {
00695    /* Make sure we can register our channel type */
00696    if (ast_channel_register(&local_tech)) {
00697       ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
00698       return -1;
00699    }
00700    ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00701    return 0;
00702 }

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

Create a call structure.

Definition at line 542 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_destroy(), ast_mutex_init(), ast_set_flag, free, LOCAL_NO_OPTIMIZATION, locals, and LOG_NOTICE.

Referenced by local_request().

00543 {
00544    struct local_pvt *tmp = NULL;
00545    char *c = NULL, *opts = NULL;
00546 
00547    if (!(tmp = ast_calloc(1, sizeof(*tmp))))
00548       return NULL;
00549 
00550    /* Initialize private structure information */
00551    ast_mutex_init(&tmp->lock);
00552    ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
00553 
00554    /* Look for options */
00555    if ((opts = strchr(tmp->exten, '/'))) {
00556       *opts++ = '\0';
00557       if (strchr(opts, 'n'))
00558          ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
00559    }
00560 
00561    /* Look for a context */
00562    if ((c = strchr(tmp->exten, '@')))
00563       *c++ = '\0';
00564 
00565    ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
00566 
00567    tmp->reqformat = format;
00568 
00569    if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
00570       ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
00571       ast_mutex_destroy(&tmp->lock);
00572       free(tmp);
00573       tmp = NULL;
00574    } else {
00575       /* Add to list */
00576       AST_LIST_LOCK(&locals);
00577       AST_LIST_INSERT_HEAD(&locals, tmp, list);
00578       AST_LIST_UNLOCK(&locals);
00579    }
00580    
00581    return tmp;
00582 }

static int local_answer ( struct ast_channel ast  )  [static]

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

00201 {
00202    struct local_pvt *p = ast->tech_pvt;
00203    int isoutbound;
00204    int res = -1;
00205 
00206    if (!p)
00207       return -1;
00208 
00209    ast_mutex_lock(&p->lock);
00210    isoutbound = IS_OUTBOUND(ast, p);
00211    if (isoutbound) {
00212       /* Pass along answer since somebody answered us */
00213       struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
00214       res = local_queue_frame(p, isoutbound, &answer, ast);
00215    } else
00216       ast_log(LOG_WARNING, "Huh?  Local is being asked to answer?\n");
00217    if (!res)
00218       ast_mutex_unlock(&p->lock);
00219    return res;
00220 }

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

References accountcode, ast_calloc, 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.

00435 {
00436    struct local_pvt *p = ast->tech_pvt;
00437    int res;
00438    struct ast_var_t *varptr = NULL, *new;
00439    size_t len, namelen;
00440 
00441    if (!p)
00442       return -1;
00443    
00444    ast_mutex_lock(&p->lock);
00445 
00446    /*
00447     * Note that cid_num and cid_name aren't passed in the ast_channel_alloc
00448     * call, so it's done here instead.
00449     */
00450    p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num);
00451    p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name);
00452    p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis);
00453    p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani);
00454    p->chan->cid.cid_pres = p->owner->cid.cid_pres;
00455    ast_string_field_set(p->chan, language, p->owner->language);
00456    ast_string_field_set(p->chan, accountcode, p->owner->accountcode);
00457    p->chan->cdrflags = p->owner->cdrflags;
00458 
00459    /* copy the channel variables from the incoming channel to the outgoing channel */
00460    /* Note that due to certain assumptions, they MUST be in the same order */
00461    AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) {
00462       namelen = strlen(varptr->name);
00463       len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
00464       if ((new = ast_calloc(1, len))) {
00465          memcpy(new, varptr, len);
00466          new->value = &(new->name[0]) + namelen + 1;
00467          AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries);
00468       }
00469    }
00470 
00471    /* Start switch on sub channel */
00472    if (!(res = ast_pbx_start(p->chan)))
00473       ast_set_flag(p, LOCAL_LAUNCHED_PBX);
00474 
00475    ast_mutex_unlock(&p->lock);
00476    return res;
00477 }

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

00355 {
00356    struct local_pvt *p = ast->tech_pvt;
00357    int res = -1;
00358    struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
00359    int isoutbound;
00360 
00361    if (!p)
00362       return -1;
00363 
00364    ast_mutex_lock(&p->lock);
00365    isoutbound = IS_OUTBOUND(ast, p);
00366    f.subclass = digit;
00367    if (!(res = local_queue_frame(p, isoutbound, &f, ast)))
00368       ast_mutex_unlock(&p->lock);
00369 
00370    return res;
00371 }

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

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

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

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

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

00304 {
00305    struct local_pvt *p = newchan->tech_pvt;
00306 
00307    if (!p)
00308       return -1;
00309 
00310    ast_mutex_lock(&p->lock);
00311 
00312    if ((p->owner != oldchan) && (p->chan != oldchan)) {
00313       ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
00314       ast_mutex_unlock(&p->lock);
00315       return -1;
00316    }
00317    if (p->owner == oldchan)
00318       p->owner = newchan;
00319    else
00320       p->chan = newchan;
00321    ast_mutex_unlock(&p->lock);
00322    return 0;
00323 }

static int local_hangup ( struct ast_channel ast  )  [static]

Hangup a call through the local proxy channel.

Definition at line 480 of file chan_local.c.

References 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_destroy(), ast_mutex_lock(), ast_mutex_unlock(), ast_set_flag, ast_test_flag, local_pvt::chan, f, free, IS_OUTBOUND, LOCAL_CANCEL_QUEUE, LOCAL_GLARE_DETECT, LOCAL_LAUNCHED_PBX, 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.

00481 {
00482    struct local_pvt *p = ast->tech_pvt;
00483    int isoutbound;
00484    struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP };
00485    struct ast_channel *ochan = NULL;
00486    int glaredetect = 0, res = 0;
00487 
00488    if (!p)
00489       return -1;
00490 
00491    ast_mutex_lock(&p->lock);
00492    isoutbound = IS_OUTBOUND(ast, p);
00493    if (isoutbound) {
00494       const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
00495       if ((status) && (p->owner))
00496          pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
00497       p->chan = NULL;
00498       ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
00499       ast_module_user_remove(p->u_chan);
00500    } else {
00501       p->owner = NULL;
00502       ast_module_user_remove(p->u_owner);
00503    }
00504    
00505    ast->tech_pvt = NULL;
00506    
00507    if (!p->owner && !p->chan) {
00508       /* Okay, done with the private part now, too. */
00509       glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT);
00510       /* If we have a queue holding, don't actually destroy p yet, but
00511          let local_queue do it. */
00512       if (glaredetect)
00513          ast_set_flag(p, LOCAL_CANCEL_QUEUE);
00514       ast_mutex_unlock(&p->lock);
00515       /* Remove from list */
00516       AST_LIST_LOCK(&locals);
00517       AST_LIST_REMOVE(&locals, p, list);
00518       AST_LIST_UNLOCK(&locals);
00519       /* Grab / release lock just in case */
00520       ast_mutex_lock(&p->lock);
00521       ast_mutex_unlock(&p->lock);
00522       /* And destroy */
00523       if (!glaredetect) {
00524          ast_mutex_destroy(&p->lock);
00525          free(p);
00526       }
00527       return 0;
00528    }
00529    if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX))
00530       /* Need to actually hangup since there is no PBX */
00531       ochan = p->chan;
00532    else
00533       res = local_queue_frame(p, isoutbound, &f, NULL);
00534    if (!res)
00535       ast_mutex_unlock(&p->lock);
00536    if (ochan)
00537       ast_hangup(ochan);
00538    return 0;
00539 }

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

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

00326 {
00327    struct local_pvt *p = ast->tech_pvt;
00328    int res = 0;
00329    struct ast_frame f = { AST_FRAME_CONTROL, };
00330    int isoutbound;
00331 
00332    if (!p)
00333       return -1;
00334 
00335    /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */
00336    if (condition == AST_CONTROL_HOLD) {
00337       ast_moh_start(ast, data, NULL);
00338    } else if (condition == AST_CONTROL_UNHOLD) {
00339       ast_moh_stop(ast);
00340    } else {
00341       /* Queue up a frame representing the indication as a control frame */
00342       ast_mutex_lock(&p->lock);
00343       isoutbound = IS_OUTBOUND(ast, p);
00344       f.subclass = condition;
00345       f.data = (void*)data;
00346       f.datalen = datalen;
00347       if (!(res = local_queue_frame(p, isoutbound, &f, ast)))
00348          ast_mutex_unlock(&p->lock);
00349    }
00350 
00351    return res;
00352 }

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

Start new local channel.

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

00586 {
00587    struct ast_channel *tmp = NULL, *tmp2 = NULL;
00588    int randnum = ast_random() & 0xffff, fmt = 0;
00589    const char *t;
00590    int ama;
00591 
00592    /* Allocate two new Asterisk channels */
00593    /* safe accountcode */
00594    if (p->owner && p->owner->accountcode)
00595       t = p->owner->accountcode;
00596    else
00597       t = "";
00598 
00599    if (p->owner)
00600       ama = p->owner->amaflags;
00601    else
00602       ama = 0;
00603    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)) 
00604          || !(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))) {
00605       if (tmp)
00606          ast_channel_free(tmp);
00607       if (tmp2)
00608          ast_channel_free(tmp2);
00609       ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
00610       return NULL;
00611    } 
00612 
00613    tmp2->tech = tmp->tech = &local_tech;
00614 
00615    tmp->nativeformats = p->reqformat;
00616    tmp2->nativeformats = p->reqformat;
00617 
00618    /* Determine our read/write format and set it on each channel */
00619    fmt = ast_best_codec(p->reqformat);
00620    tmp->writeformat = fmt;
00621    tmp2->writeformat = fmt;
00622    tmp->rawwriteformat = fmt;
00623    tmp2->rawwriteformat = fmt;
00624    tmp->readformat = fmt;
00625    tmp2->readformat = fmt;
00626    tmp->rawreadformat = fmt;
00627    tmp2->rawreadformat = fmt;
00628 
00629    tmp->tech_pvt = p;
00630    tmp2->tech_pvt = p;
00631 
00632    p->owner = tmp;
00633    p->chan = tmp2;
00634    p->u_owner = ast_module_user_add(p->owner);
00635    p->u_chan = ast_module_user_add(p->chan);
00636 
00637    ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
00638    ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
00639    ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten));
00640    tmp->priority = 1;
00641    tmp2->priority = 1;
00642 
00643    return tmp;
00644 }

static int local_queue_frame ( struct local_pvt p,
int  isoutbound,
struct ast_frame f,
struct ast_channel us 
) [static]

Definition at line 153 of file chan_local.c.

References ast_clear_flag, ast_log(), ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_trylock(), ast_mutex_unlock(), ast_queue_frame(), ast_set_flag, ast_test_flag, local_pvt::chan, f, free, LOCAL_CANCEL_QUEUE, LOCAL_GLARE_DETECT, ast_channel::lock, local_pvt::lock, LOG_WARNING, 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().

00154 {
00155    struct ast_channel *other = NULL;
00156 
00157 retrylock:     
00158 
00159    /* Recalculate outbound channel */
00160    other = isoutbound ? p->owner : p->chan;
00161 
00162    /* Set glare detection */
00163    ast_set_flag(p, LOCAL_GLARE_DETECT);
00164    if (ast_test_flag(p, LOCAL_CANCEL_QUEUE)) {
00165       /* We had a glare on the hangup.  Forget all this business,
00166       return and destroy p.  */
00167       ast_mutex_unlock(&p->lock);
00168       ast_mutex_destroy(&p->lock);
00169       free(p);
00170       return -1;
00171    }
00172    if (!other) {
00173       ast_clear_flag(p, LOCAL_GLARE_DETECT);
00174       return 0;
00175    }
00176    if (ast_mutex_trylock(&other->lock)) {
00177       /* Failed to lock.  Release main lock and try again */
00178       ast_mutex_unlock(&p->lock);
00179       if (us) {
00180          if (ast_mutex_unlock(&us->lock)) {
00181             ast_log(LOG_WARNING, "%s wasn't locked while sending %d/%d\n",
00182                us->name, f->frametype, f->subclass);
00183             us = NULL;
00184          }
00185       }
00186       /* Wait just a bit */
00187       usleep(1);
00188       /* Only we can destroy ourselves, so we can't disappear here */
00189       if (us)
00190          ast_mutex_lock(&us->lock);
00191       ast_mutex_lock(&p->lock);
00192       goto retrylock;
00193    }
00194    ast_queue_frame(other, f);
00195    ast_mutex_unlock(&other->lock);
00196    ast_clear_flag(p, LOCAL_GLARE_DETECT);
00197    return 0;
00198 }

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

Definition at line 272 of file chan_local.c.

References ast_null_frame.

00273 {
00274    return &ast_null_frame;
00275 }

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

Part of PBX interface.

Definition at line 648 of file chan_local.c.

References AST_STATE_DOWN, local_pvt::chan, local_alloc(), and local_new().

00649 {
00650    struct local_pvt *p = NULL;
00651    struct ast_channel *chan = NULL;
00652 
00653    /* Allocate a new private structure and then Asterisk channel */
00654    if ((p = local_alloc(data, format)))
00655       chan = local_new(p, AST_STATE_DOWN);
00656 
00657    return chan;
00658 }

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

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

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

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

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

00394 {
00395    struct local_pvt *p = ast->tech_pvt;
00396    int res = -1;
00397    struct ast_frame f = { AST_FRAME_TEXT, };
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.data = (char *) text;
00406    f.datalen = strlen(text) + 1;
00407    if (!(res = local_queue_frame(p, isoutbound, &f, ast)))
00408       ast_mutex_unlock(&p->lock);
00409    return res;
00410 }

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

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

00278 {
00279    struct local_pvt *p = ast->tech_pvt;
00280    int res = -1;
00281    int isoutbound;
00282 
00283    if (!p)
00284       return -1;
00285 
00286    /* Just queue for delivery to the other side */
00287    ast_mutex_lock(&p->lock);
00288    isoutbound = IS_OUTBOUND(ast, p);
00289    if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO))
00290       check_bridge(p, isoutbound);
00291    if (!ast_test_flag(p, LOCAL_ALREADY_MASQED))
00292       res = local_queue_frame(p, isoutbound, f, ast);
00293    else {
00294       if (option_debug)
00295          ast_log(LOG_DEBUG, "Not posting to queue since already masked on '%s'\n", ast->name);
00296       res = 0;
00297    }
00298    if (!res)
00299       ast_mutex_unlock(&p->lock);
00300    return res;
00301 }

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

CLI command "local show channels".

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

00662 {
00663    struct local_pvt *p = NULL;
00664 
00665    if (argc != 3)
00666       return RESULT_SHOWUSAGE;
00667 
00668    AST_LIST_LOCK(&locals);
00669    if (!AST_LIST_EMPTY(&locals)) {
00670       AST_LIST_TRAVERSE(&locals, p, list) {
00671          ast_mutex_lock(&p->lock);
00672          ast_cli(fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
00673          ast_mutex_unlock(&p->lock);
00674       }
00675    } else
00676       ast_cli(fd, "No local channels in use\n");
00677    AST_LIST_UNLOCK(&locals);
00678 
00679    return RESULT_SUCCESS;
00680 }

static int unload_module ( void   )  [static]

Unload the local proxy channel from Asterisk.

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

00706 {
00707    struct local_pvt *p = NULL;
00708 
00709    /* First, take us out of the channel loop */
00710    ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00711    ast_channel_unregister(&local_tech);
00712    if (!AST_LIST_LOCK(&locals)) {
00713       /* Hangup all interfaces if they have an owner */
00714       AST_LIST_TRAVERSE(&locals, p, list) {
00715          if (p->owner)
00716             ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
00717       }
00718       AST_LIST_UNLOCK(&locals);
00719       AST_LIST_HEAD_DESTROY(&locals);
00720    } else {
00721       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
00722       return -1;
00723    }     
00724    return 0;
00725 }


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

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

Definition at line 65 of file chan_local.c.


Generated on Fri Aug 24 02:23:43 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1