Sat Nov 1 06:28:54 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, 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 237 of file chan_local.c.

References ast_channel::_bridge, ast_channel::_softhangup, ast_bridged_channel(), ast_channel_masquerade(), AST_LIST_EMPTY, ast_mutex_trylock(), ast_mutex_unlock(), ast_set_flag, ast_test_flag, local_pvt::chan, LOCAL_ALREADY_MASQED, LOCAL_NO_OPTIMIZATION, ast_channel::lock, ast_channel::monitor, and local_pvt::owner.

Referenced by local_write().

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

static int load_module ( void   )  [static]

Load module into PBX, register channel.

Definition at line 768 of file chan_local.c.

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

00769 {
00770    /* Make sure we can register our channel type */
00771    if (ast_channel_register(&local_tech)) {
00772       ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
00773       return -1;
00774    }
00775    ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00776    return 0;
00777 }

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

Create a call structure.

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

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

static int local_answer ( struct ast_channel ast  )  [static]

Definition at line 215 of file chan_local.c.

References answer, AST_CONTROL_ANSWER, AST_FRAME_CONTROL, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), IS_OUTBOUND, local_queue_frame(), local_pvt::lock, LOG_WARNING, and ast_channel::tech_pvt.

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

static int local_call ( struct ast_channel ast,
char *  dest,
int  timeout 
) [static]

Initiate new call, part of PBX interface dest is the dial string.

Definition at line 460 of file chan_local.c.

References accountcode, ast_calloc, ast_cdr_update(), ast_channel_datastore_inherit(), ast_exists_extension(), AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_pbx_start(), ast_set_flag, ast_strdup, ast_string_field_set, ast_channel::cdrflags, local_pvt::chan, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_ani2, ast_callerid::cid_dnid, ast_callerid::cid_name, ast_callerid::cid_num, ast_callerid::cid_pres, ast_callerid::cid_rdnis, ast_callerid::cid_tns, ast_callerid::cid_ton, ast_channel::context, ast_channel::exten, language, len, LOCAL_LAUNCHED_PBX, local_pvt::lock, LOG_NOTICE, ast_var_t::name, local_pvt::owner, ast_channel::tech_pvt, ast_var_t::value, and ast_channel::varshead.

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

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

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

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

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

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

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

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

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

static int local_hangup ( struct ast_channel ast  )  [static]

Hangup a call through the local proxy channel.

Definition at line 518 of file chan_local.c.

References ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_clear_flag, AST_CONTROL_HANGUP, AST_FRAME_CONTROL, ast_hangup(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_module_user_remove, ast_mutex_lock(), ast_mutex_trylock(), ast_mutex_unlock(), ast_queue_hangup(), ast_set_flag, ast_test_flag, local_pvt::chan, DEADLOCK_AVOIDANCE, f, IS_OUTBOUND, LOCAL_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.

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

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

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

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

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

Start new local channel.

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

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

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

Note:
Assumes the pvt is no longer in the pvts list

Definition at line 156 of file chan_local.c.

References ast_mutex_destroy(), free, and local_pvt::lock.

Referenced by local_alloc(), local_hangup(), local_queue_frame(), and local_request().

00157 {
00158    ast_mutex_destroy(&pvt->lock);
00159    free(pvt);
00160    return NULL;
00161 }

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

Definition at line 163 of file chan_local.c.

References ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_clear_flag, ast_mutex_lock(), ast_mutex_trylock(), ast_mutex_unlock(), ast_queue_frame(), ast_set_flag, ast_test_flag, local_pvt::chan, f, ast_channel::generator, LOCAL_CANCEL_QUEUE, LOCAL_GLARE_DETECT, local_pvt_destroy(), local_pvt::lock, and local_pvt::owner.

Referenced by local_answer(), local_digit_begin(), local_digit_end(), local_hangup(), local_indicate(), local_sendhtml(), local_sendtext(), and local_write().

00165 {
00166    struct ast_channel *other = NULL;
00167 
00168    /* Recalculate outbound channel */
00169    other = isoutbound ? p->owner : p->