Mon Mar 31 07:39: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"

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

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

static int load_module ( void   )  [static]

Load module into PBX, register channel.

Definition at line 723 of file chan_local.c.

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

00724 {
00725    /* Make sure we can register our channel type */
00726    if (ast_channel_register(&local_tech)) {
00727       ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
00728       return -1;
00729    }
00730    ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00731    return 0;
00732 }

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

Create a call structure.

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

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

static int local_answer ( struct ast_channel ast  )  [static]

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

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

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

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

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

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

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

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

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

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

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

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

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

static int local_hangup ( struct ast_channel ast  )  [static]

Hangup a call through the local proxy channel.

Definition at line 498 of file chan_local.c.

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

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

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

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

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

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

Start new local channel.

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

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

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 
) [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, 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().

00164 {
00165    struct ast_channel *other = NULL;
00166 
00167    /* Recalculate outbound channel */
00168    other = isoutbound ? p->owner : p->chan;
00169 
00170    /* Set glare detection */
00171    ast_set_flag(p, LOCAL_GLARE_DETECT);
00172    if (ast_test_flag(p, LOCAL_CANCEL_QUEUE)) {
00173       /* We had a glare on the hangup.  Forget all this business,
00174       return and destroy p.  */
00175       ast_mutex_unlock(&p->lock);
00176       p = local_pvt_destroy(p);
00177       return -1;
00178    }
00179    if (!other) {
00180       ast_clear_flag(p, LOCAL_GLARE_DETECT);
00181       return 0;
00182    }
00183 
00184    /* Ensure that we have both channels locked */
00185    while (other && ast_channel_trylock(other)) {
00186       ast_mutex_unlock(&p->lock);
00187       if (us)
00188          ast_channel_unlock(us);
00189       usleep(1);
00190       if (us)
00191          ast_channel_lock(us);
00192       ast_mutex_lock(&p->lock);
00193       other = isoutbound ? p->owner : p->chan;
00194    }
00195 
00196    if (other) {
00197       ast_queue_frame(other, f);
00198       ast_channel_unlock(other);
00199    }
00200 
00201    ast_clear_flag(p, LOCAL_GLARE_DETECT);
00202 
00203    return 0;
00204 }

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

Definition at line 289 of file chan_local.c.

References ast_null_frame.

00290 {
00291    return &ast_null_frame;
00292 }

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

Part of PBX interface.

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

00673 {
00674    struct local_pvt *p = NULL;
00675    struct ast_channel *chan = NULL;
00676 
00677    /* Allocate a new private structure and then Asterisk channel */
00678    if ((p = local_alloc(data, format))) {
00679       if (!(chan = local_new(p, AST_STATE_DOWN))) {
00680          AST_LIST_LOCK(&locals);
00681          AST_LIST_REMOVE(&locals, p, list);
00682          AST_LIST_UNLOCK(&locals);
00683          p = local_pvt_destroy(p);
00684       }
00685    }
00686 
00687    return chan;
00688 }

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

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

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

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

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

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

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

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

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

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

CLI command "local show channels".

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

00692 {
00693    struct local_pvt *p = NULL;
00694 
00695    if (argc != 3)
00696       return RESULT_SHOWUSAGE;
00697 
00698    AST_LIST_LOCK(&locals);
00699    if (!AST_LIST_EMPTY(&locals)) {
00700       AST_LIST_TRAVERSE(&locals, p, list) {
00701          ast_mutex_lock(&p->lock);
00702          ast_cli(fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
00703          ast_mutex_unlock(&p->lock);
00704       }
00705    } else
00706       ast_cli(fd, "No local channels in use\n");
00707    AST_LIST_UNLOCK(&locals);
00708 
00709    return RESULT_SUCCESS;
00710 }

static int unload_module ( void   )  [static]

Unload the local proxy channel from Asterisk.

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

00736 {
00737    struct local_pvt *p = NULL;
00738 
00739    /* First, take us out of the channel loop */
00740    ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00741    ast_channel_unregister(&local_tech);
00742    if (!AST_LIST_LOCK(&locals)) {
00743       /* Hangup all interfaces if they have an owner */
00744       AST_LIST_TRAVERSE(&locals, p, list) {
00745          if (p->owner)
00746             ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
00747       }
00748       AST_LIST_UNLOCK(&locals);
00749       AST_LIST_HEAD_DESTROY(&locals);
00750    } else {
00751       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
00752       return -1;
00753    }     
00754    return 0;
00755 }


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 716 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 712 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 Mar 31 07:39:31 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.1