Mon Sep 20 2010 00:21:16

Asterisk developer's documentation


chan_local.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2005, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \author Mark Spencer <markster@digium.com>
00022  *
00023  * \brief Local Proxy Channel
00024  * 
00025  * \ingroup channel_drivers
00026  */
00027 
00028 #include "asterisk.h"
00029 
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 259899 $")
00031 
00032 #include <fcntl.h>
00033 #include <sys/signal.h>
00034 
00035 #include "asterisk/lock.h"
00036 #include "asterisk/channel.h"
00037 #include "asterisk/config.h"
00038 #include "asterisk/module.h"
00039 #include "asterisk/pbx.h"
00040 #include "asterisk/sched.h"
00041 #include "asterisk/io.h"
00042 #include "asterisk/rtp.h"
00043 #include "asterisk/acl.h"
00044 #include "asterisk/callerid.h"
00045 #include "asterisk/file.h"
00046 #include "asterisk/cli.h"
00047 #include "asterisk/app.h"
00048 #include "asterisk/musiconhold.h"
00049 #include "asterisk/manager.h"
00050 #include "asterisk/stringfields.h"
00051 #include "asterisk/devicestate.h"
00052 
00053 static const char tdesc[] = "Local Proxy Channel Driver";
00054 
00055 #define IS_OUTBOUND(a,b) (a == b->chan ? 1 : 0)
00056 
00057 static struct ast_jb_conf g_jb_conf = {
00058    .flags = 0,
00059    .max_size = -1,
00060    .resync_threshold = -1,
00061    .impl = "",
00062    .target_extra = -1,
00063 };
00064 
00065 static struct ast_channel *local_request(const char *type, int format, void *data, int *cause);
00066 static int local_digit_begin(struct ast_channel *ast, char digit);
00067 static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
00068 static int local_call(struct ast_channel *ast, char *dest, int timeout);
00069 static int local_hangup(struct ast_channel *ast);
00070 static int local_answer(struct ast_channel *ast);
00071 static struct ast_frame *local_read(struct ast_channel *ast);
00072 static int local_write(struct ast_channel *ast, struct ast_frame *f);
00073 static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
00074 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00075 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
00076 static int local_sendtext(struct ast_channel *ast, const char *text);
00077 static int local_devicestate(void *data);
00078 static struct ast_channel *local_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge);
00079 
00080 /* PBX interface structure for channel registration */
00081 static const struct ast_channel_tech local_tech = {
00082    .type = "Local",
00083    .description = tdesc,
00084    .capabilities = -1,
00085    .requester = local_request,
00086    .send_digit_begin = local_digit_begin,
00087    .send_digit_end = local_digit_end,
00088    .call = local_call,
00089    .hangup = local_hangup,
00090    .answer = local_answer,
00091    .read = local_read,
00092    .write = local_write,
00093    .write_video = local_write,
00094    .exception = local_read,
00095    .indicate = local_indicate,
00096    .fixup = local_fixup,
00097    .send_html = local_sendhtml,
00098    .send_text = local_sendtext,
00099    .devicestate = local_devicestate,
00100    .bridged_channel = local_bridgedchannel,
00101 };
00102 
00103 struct local_pvt {
00104    ast_mutex_t lock;       /* Channel private lock */
00105    unsigned int flags;                     /* Private flags */
00106    char context[AST_MAX_CONTEXT];      /* Context to call */
00107    char exten[AST_MAX_EXTENSION];      /* Extension to call */
00108    int reqformat;          /* Requested format */
00109    struct ast_jb_conf jb_conf;      /*!< jitterbuffer configuration for this local channel */
00110    struct ast_channel *owner;    /* Master Channel - Bridging happens here */
00111    struct ast_channel *chan;     /* Outbound channel - PBX is run here */
00112    struct ast_module_user *u_owner; /*! reference to keep the module loaded while in use */
00113    struct ast_module_user *u_chan;     /*! reference to keep the module loaded while in use */
00114    AST_LIST_ENTRY(local_pvt) list;     /* Next entity */
00115 };
00116 
00117 #define LOCAL_GLARE_DETECT    (1 << 0) /*!< Detect glare on hangup */
00118 #define LOCAL_CANCEL_QUEUE    (1 << 1) /*!< Cancel queue */
00119 #define LOCAL_ALREADY_MASQED  (1 << 2) /*!< Already masqueraded */
00120 #define LOCAL_LAUNCHED_PBX    (1 << 3) /*!< PBX was launched */
00121 #define LOCAL_NO_OPTIMIZATION (1 << 4) /*!< Do not optimize using masquerading */
00122 #define LOCAL_BRIDGE          (1 << 5) /*!< Report back the "true" channel as being bridged to */
00123 #define LOCAL_MOH_PASSTHRU    (1 << 6) /*!< Pass through music on hold start/stop frames */
00124 
00125 static AST_LIST_HEAD_STATIC(locals, local_pvt);
00126 
00127 /*! \brief Adds devicestate to local channels */
00128 static int local_devicestate(void *data)
00129 {
00130    char *exten = ast_strdupa(data);
00131    char *context = NULL, *opts = NULL;
00132    int res;
00133    struct local_pvt *lp;
00134 
00135    if (!(context = strchr(exten, '@'))) {
00136       ast_log(LOG_WARNING, "Someone used Local/%s somewhere without a @context. This is bad.\n", exten);
00137       return AST_DEVICE_INVALID; 
00138    }
00139 
00140    *context++ = '\0';
00141 
00142    /* Strip options if they exist */
00143    if ((opts = strchr(context, '/')))
00144       *opts = '\0';
00145 
00146    ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
00147 
00148    res = ast_exists_extension(NULL, context, exten, 1, NULL);
00149    if (!res)      
00150       return AST_DEVICE_INVALID;
00151    
00152    res = AST_DEVICE_NOT_INUSE;
00153    AST_LIST_LOCK(&locals);
00154    AST_LIST_TRAVERSE(&locals, lp, list) {
00155       if (!strcmp(exten, lp->exten) && !strcmp(context, lp->context) && lp->owner) {
00156          res = AST_DEVICE_INUSE;
00157          break;
00158       }
00159    }
00160    AST_LIST_UNLOCK(&locals);
00161 
00162    return res;
00163 }
00164 
00165 /*!
00166  * \note Assumes the pvt is no longer in the pvts list
00167  */
00168 static struct local_pvt *local_pvt_destroy(struct local_pvt *pvt)
00169 {
00170    ast_mutex_destroy(&pvt->lock);
00171    ast_free(pvt);
00172    return NULL;
00173 }
00174 
00175 /*! \brief Return the bridged channel of a Local channel */
00176 static struct ast_channel *local_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
00177 {
00178    struct local_pvt *p = bridge->tech_pvt;
00179    struct ast_channel *bridged = bridge;
00180 
00181    if (!p) {
00182       ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning <none>\n",
00183          chan->name, bridge->name);
00184       return NULL;
00185    }
00186 
00187    ast_mutex_lock(&p->lock);
00188 
00189    if (ast_test_flag(p, LOCAL_BRIDGE)) {
00190       /* Find the opposite channel */
00191       bridged = (bridge == p->owner ? p->chan : p->owner);
00192       
00193       /* Now see if the opposite channel is bridged to anything */
00194       if (!bridged) {
00195          bridged = bridge;
00196       } else if (bridged->_bridge) {
00197          bridged = bridged->_bridge;
00198       }
00199    }
00200 
00201    ast_mutex_unlock(&p->lock);
00202 
00203    return bridged;
00204 }
00205 
00206 static int local_queue_frame(struct local_pvt *p, int isoutbound, struct ast_frame *f, 
00207    struct ast_channel *us, int us_locked)
00208 {
00209    struct ast_channel *other = NULL;
00210 
00211    /* Recalculate outbound channel */
00212    other = isoutbound ? p->owner : p->chan;
00213 
00214    if (!other) {
00215       return 0;
00216    }
00217 
00218    /* do not queue frame if generator is on both local channels */
00219    if (us && us->generator && other->generator) {
00220       return 0;
00221    }
00222 
00223    /* Set glare detection */
00224    ast_set_flag(p, LOCAL_GLARE_DETECT);
00225 
00226    /* Ensure that we have both channels locked */
00227    while (other && ast_channel_trylock(other)) {
00228       ast_mutex_unlock(&p->lock);
00229       if (us && us_locked) {
00230          do {
00231             CHANNEL_DEADLOCK_AVOIDANCE(us);
00232          } while (ast_mutex_trylock(&p->lock));
00233       } else {
00234          usleep(1);
00235          ast_mutex_lock(&p->lock);
00236       }
00237       other = isoutbound ? p->owner : p->chan;
00238    }
00239 
00240    /* Since glare detection only occurs within this function, and because
00241     * a pvt flag cannot be set without having the pvt lock, this is the only
00242     * location where we could detect a cancelling of the queue. */
00243    if (ast_test_flag(p, LOCAL_CANCEL_QUEUE)) {
00244       /* We had a glare on the hangup.  Forget all this business,
00245       return and destroy p.  */
00246       ast_mutex_unlock(&p->lock);
00247       p = local_pvt_destroy(p);
00248       if (other) {
00249          ast_channel_unlock(other);
00250       }
00251       return -1;
00252    }
00253 
00254    if (other) {
00255       if (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_RINGING) {
00256          ast_setstate(other, AST_STATE_RINGING);
00257       }
00258       ast_queue_frame(other, f);
00259       ast_channel_unlock(other);
00260    }
00261 
00262    ast_clear_flag(p, LOCAL_GLARE_DETECT);
00263 
00264    return 0;
00265 }
00266 
00267 static int local_answer(struct ast_channel *ast)
00268 {
00269    struct local_pvt *p = ast->tech_pvt;
00270    int isoutbound;
00271    int res = -1;
00272 
00273    if (!p)
00274       return -1;
00275 
00276    ast_mutex_lock(&p->lock);
00277    isoutbound = IS_OUTBOUND(ast, p);
00278    if (isoutbound) {
00279       /* Pass along answer since somebody answered us */
00280       struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
00281       res = local_queue_frame(p, isoutbound, &answer, ast, 1);
00282    } else
00283       ast_log(LOG_WARNING, "Huh?  Local is being asked to answer?\n");
00284    if (!res)
00285       ast_mutex_unlock(&p->lock);
00286    return res;
00287 }
00288 
00289 /*!
00290  * \internal
00291  * \note This function assumes that we're only called from the "outbound" local channel side
00292  */
00293 static void check_bridge(struct local_pvt *p)
00294 {
00295    struct ast_channel_monitor *tmp;
00296    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)))
00297       return;
00298 
00299    /* only do the masquerade if we are being called on the outbound channel,
00300       if it has been bridged to another channel and if there are no pending
00301       frames on the owner channel (because they would be transferred to the
00302       outbound channel during the masquerade)
00303    */
00304    if (p->chan->_bridge /* Not ast_bridged_channel!  Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) {
00305       /* Masquerade bridged channel into owner */
00306       /* Lock everything we need, one by one, and give up if
00307          we can't get everything.  Remember, we'll get another
00308          chance in just a little bit */
00309       if (!ast_channel_trylock(p->chan->_bridge)) {
00310          if (!ast_check_hangup(p->chan->_bridge)) {
00311             if (!ast_channel_trylock(p->owner)) {
00312                if (!ast_check_hangup(p->owner)) {
00313                   if (p->owner->monitor && !p->chan->_bridge->monitor) {
00314                      /* If a local channel is being monitored, we don't want a masquerade
00315                       * to cause the monitor to go away. Since the masquerade swaps the monitors,
00316                       * pre-swapping the monitors before the masquerade will ensure that the monitor
00317                       * ends up where it is expected.
00318                       */
00319                      tmp = p->owner->monitor;
00320                      p->owner->monitor = p->chan->_bridge->monitor;
00321                      p->chan->_bridge->monitor = tmp;
00322                   }
00323                   if (p->chan->audiohooks) {
00324                      struct ast_audiohook_list *audiohooks_swapper;
00325                      audiohooks_swapper = p->chan->audiohooks;
00326                      p->chan->audiohooks = p->owner->audiohooks;
00327                      p->owner->audiohooks = audiohooks_swapper;
00328                   }
00329                   ast_app_group_update(p->chan, p->owner);
00330                   ast_channel_masquerade(p->owner, p->chan->_bridge);
00331                   ast_set_flag(p, LOCAL_ALREADY_MASQED);
00332                }
00333                ast_channel_unlock(p->owner);
00334             }
00335             ast_channel_unlock(p->chan->_bridge);
00336          }
00337       }
00338    }
00339 }
00340 
00341 static struct ast_frame  *local_read(struct ast_channel *ast)
00342 {
00343    return &ast_null_frame;
00344 }
00345 
00346 static int local_write(struct ast_channel *ast, struct ast_frame *f)
00347 {
00348    struct local_pvt *p = ast->tech_pvt;
00349    int res = -1;
00350    int isoutbound;
00351 
00352    if (!p)
00353       return -1;
00354 
00355    /* Just queue for delivery to the other side */
00356    ast_mutex_lock(&p->lock);
00357    isoutbound = IS_OUTBOUND(ast, p);
00358    if (isoutbound && f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO))
00359       check_bridge(p);
00360    if (!ast_test_flag(p, LOCAL_ALREADY_MASQED))
00361       res = local_queue_frame(p, isoutbound, f, ast, 1);
00362    else {
00363       ast_debug(1, "Not posting to queue since already masked on '%s'\n", ast->name);
00364       res = 0;
00365    }
00366    if (!res)
00367       ast_mutex_unlock(&p->lock);
00368    return res;
00369 }
00370 
00371 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
00372 {
00373    struct local_pvt *p = newchan->tech_pvt;
00374 
00375    if (!p)
00376       return -1;
00377 
00378    ast_mutex_lock(&p->lock);
00379 
00380    if ((p->owner != oldchan) && (p->chan != oldchan)) {
00381       ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
00382       ast_mutex_unlock(&p->lock);
00383       return -1;
00384    }
00385    if (p->owner == oldchan)
00386       p->owner = newchan;
00387    else
00388       p->chan = newchan;
00389    ast_mutex_unlock(&p->lock);
00390    return 0;
00391 }
00392 
00393 static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
00394 {
00395    struct local_pvt *p = ast->tech_pvt;
00396    int res = 0;
00397    struct ast_frame f = { AST_FRAME_CONTROL, };
00398    int isoutbound;
00399 
00400    if (!p)
00401       return -1;
00402 
00403    /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */
00404    if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) {
00405       ast_moh_start(ast, data, NULL);
00406    } else if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_UNHOLD) {
00407       ast_moh_stop(ast);
00408    } else {
00409       /* Queue up a frame representing the indication as a control frame */
00410       ast_mutex_lock(&p->lock);
00411       isoutbound = IS_OUTBOUND(ast, p);
00412       f.subclass = condition;
00413       f.data.ptr = (void*)data;
00414       f.datalen = datalen;
00415       if (!(res = local_queue_frame(p, isoutbound, &f, ast, 1)))
00416          ast_mutex_unlock(&p->lock);
00417    }
00418 
00419    return res;
00420 }
00421 
00422 static int local_digit_begin(struct ast_channel *ast, char digit)
00423 {
00424    struct local_pvt *p = ast->tech_pvt;
00425    int res = -1;
00426    struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
00427    int isoutbound;
00428 
00429    if (!p)
00430       return -1;
00431 
00432    ast_mutex_lock(&p->lock);
00433    isoutbound = IS_OUTBOUND(ast, p);
00434    f.subclass = digit;
00435    if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00436       ast_mutex_unlock(&p->lock);
00437 
00438    return res;
00439 }
00440 
00441 static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
00442 {
00443    struct local_pvt *p = ast->tech_pvt;
00444    int res = -1;
00445    struct ast_frame f = { AST_FRAME_DTMF_END, };
00446    int isoutbound;
00447 
00448    if (!p)
00449       return -1;
00450 
00451    ast_mutex_lock(&p->lock);
00452    isoutbound = IS_OUTBOUND(ast, p);
00453    f.subclass = digit;
00454    f.len = duration;
00455    if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00456       ast_mutex_unlock(&p->lock);
00457 
00458    return res;
00459 }
00460 
00461 static int local_sendtext(struct ast_channel *ast, const char *text)
00462 {
00463    struct local_pvt *p = ast->tech_pvt;
00464    int res = -1;
00465    struct ast_frame f = { AST_FRAME_TEXT, };
00466    int isoutbound;
00467 
00468    if (!p)
00469       return -1;
00470 
00471    ast_mutex_lock(&p->lock);
00472    isoutbound = IS_OUTBOUND(ast, p);
00473    f.data.ptr = (char *) text;
00474    f.datalen = strlen(text) + 1;
00475    if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00476       ast_mutex_unlock(&p->lock);
00477    return res;
00478 }
00479 
00480 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
00481 {
00482    struct local_pvt *p = ast->tech_pvt;
00483    int res = -1;
00484    struct ast_frame f = { AST_FRAME_HTML, };
00485    int isoutbound;
00486 
00487    if (!p)
00488       return -1;
00489    
00490    ast_mutex_lock(&p->lock);
00491    isoutbound = IS_OUTBOUND(ast, p);
00492    f.subclass = subclass;
00493    f.data.ptr = (char *)data;
00494    f.datalen = datalen;
00495    if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00496       ast_mutex_unlock(&p->lock);
00497    return res;
00498 }
00499 
00500 /*! \brief Initiate new call, part of PBX interface 
00501  *    dest is the dial string */
00502 static int local_call(struct ast_channel *ast, char *dest, int timeout)
00503 {
00504    struct local_pvt *p = ast->tech_pvt;
00505    int res;
00506    struct ast_var_t *varptr = NULL, *new;
00507    size_t len, namelen;
00508 
00509    if (!p)
00510       return -1;
00511    
00512    ast_mutex_lock(&p->lock);
00513 
00514    /*
00515     * Note that cid_num and cid_name aren't passed in the ast_channel_alloc
00516     * call, so it's done here instead.
00517     */
00518    p->chan->cid.cid_dnid = ast_strdup(p->owner->cid.cid_dnid);
00519    p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num);
00520    p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name);
00521    p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis);
00522    p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani);
00523    p->chan->cid.cid_pres = p->owner->cid.cid_pres;
00524    p->chan->cid.cid_ani2 = p->owner->cid.cid_ani2;
00525    p->chan->cid.cid_ton = p->owner->cid.cid_ton;
00526    p->chan->cid.cid_tns = p->owner->cid.cid_tns;
00527    ast_string_field_set(p->chan, language, p->owner->language);
00528    ast_string_field_set(p->chan, accountcode, p->owner->accountcode);
00529    ast_string_field_set(p->chan, musicclass, p->owner->musicclass);
00530    ast_cdr_update(p->chan);
00531    p->chan->cdrflags = p->owner->cdrflags;
00532 
00533    if (!ast_exists_extension(NULL, p->chan->context, p->chan->exten, 1, p->owner->cid.cid_num)) {
00534       ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->chan->exten, p->chan->context);
00535       ast_mutex_unlock(&p->lock);
00536       return -1;
00537    }
00538 
00539    /* Make sure we inherit the ANSWERED_ELSEWHERE flag if it's set on the queue/dial call request in the dialplan */
00540    if (ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
00541       ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE);
00542    }
00543 
00544    /* copy the channel variables from the incoming channel to the outgoing channel */
00545    /* Note that due to certain assumptions, they MUST be in the same order */
00546    AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) {
00547       namelen = strlen(varptr->name);
00548       len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
00549       if ((new = ast_calloc(1, len))) {
00550          memcpy(new, varptr, len);
00551          new->value = &(new->name[0]) + namelen + 1;
00552          AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries);
00553       }
00554    }
00555    ast_channel_datastore_inherit(p->owner, p->chan);
00556 
00557    /* Start switch on sub channel */
00558    if (!(res = ast_pbx_start(p->chan)))
00559       ast_set_flag(p, LOCAL_LAUNCHED_PBX);
00560 
00561    ast_mutex_unlock(&p->lock);
00562    return res;
00563 }
00564 
00565 /*! \brief Hangup a call through the local proxy channel */
00566 static int local_hangup(struct ast_channel *ast)
00567 {
00568    struct local_pvt *p = ast->tech_pvt;
00569    int isoutbound;
00570    struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP, .data.uint32 = ast->hangupcause };
00571    struct ast_channel *ochan = NULL;
00572    int glaredetect = 0, res = 0;
00573 
00574    if (!p)
00575       return -1;
00576 
00577    ast_mutex_lock(&p->lock);
00578 
00579    isoutbound = IS_OUTBOUND(ast, p);
00580 
00581    if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
00582       ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE);
00583       ast_debug(2, "This local call has the ANSWERED_ELSEWHERE flag set.\n");
00584    }
00585 
00586    if (isoutbound) {
00587       const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
00588       if ((status) && (p->owner)) {
00589          /* Deadlock avoidance */
00590          while (p->owner && ast_channel_trylock(p->owner)) {
00591             ast_mutex_unlock(&p->lock);
00592             if (p->chan) {
00593                ast_channel_unlock(p->chan);
00594             }
00595             usleep(1);
00596             if (p->chan) {
00597                ast_channel_lock(p->chan);
00598             }
00599             ast_mutex_lock(&p->lock);
00600          }
00601          if (p->owner) {
00602             pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
00603             ast_channel_unlock(p->owner);
00604          }
00605       }
00606       p->chan = NULL;
00607       ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
00608       ast_module_user_remove(p->u_chan);
00609    } else {
00610       ast_module_user_remove(p->u_owner);
00611       while (p->chan && ast_channel_trylock(p->chan)) {
00612             ast_mutex_unlock(&p->lock);
00613             if (p->owner) {
00614                ast_channel_unlock(p->owner);
00615             }
00616             usleep(1);
00617             if (p->owner) {
00618                ast_channel_lock(p->owner);
00619             }
00620             ast_mutex_lock(&p->lock);
00621       }
00622 
00623       p->owner = NULL;
00624       if (p->chan) {
00625          ast_queue_hangup(p->chan);
00626          ast_channel_unlock(p->chan);
00627       }
00628    }
00629    
00630    ast->tech_pvt = NULL;
00631    
00632    if (!p->owner && !p->chan) {
00633       /* Okay, done with the private part now, too. */
00634       glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT);
00635       /* If we have a queue holding, don't actually destroy p yet, but
00636          let local_queue do it. */
00637       if (glaredetect)
00638          ast_set_flag(p, LOCAL_CANCEL_QUEUE);
00639       /* Remove from list */
00640       AST_LIST_LOCK(&locals);
00641       AST_LIST_REMOVE(&locals, p, list);
00642       AST_LIST_UNLOCK(&locals);
00643       ast_mutex_unlock(&p->lock);
00644       /* And destroy */
00645       if (!glaredetect) {
00646          p = local_pvt_destroy(p);
00647       }
00648       return 0;
00649    }
00650    if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX))
00651       /* Need to actually hangup since there is no PBX */
00652       ochan = p->chan;
00653    else
00654       res = local_queue_frame(p, isoutbound, &f, NULL, 1);
00655    if (!res)
00656       ast_mutex_unlock(&p->lock);
00657    if (ochan)
00658       ast_hangup(ochan);
00659    return 0;
00660 }
00661 
00662 /*! \brief Create a call structure */
00663 static struct local_pvt *local_alloc(const char *data, int format)
00664 {
00665    struct local_pvt *tmp = NULL;
00666    char *c = NULL, *opts = NULL;
00667 
00668    if (!(tmp = ast_calloc(1, sizeof(*tmp))))
00669       return NULL;
00670 
00671    /* Initialize private structure information */
00672    ast_mutex_init(&tmp->lock);
00673    ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
00674 
00675    memcpy(&tmp->jb_conf, &g_jb_conf, sizeof(tmp->jb_conf));
00676 
00677    /* Look for options */
00678    if ((opts = strchr(tmp->exten, '/'))) {
00679       *opts++ = '\0';
00680       if (strchr(opts, 'n'))
00681          ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
00682       if (strchr(opts, 'j')) {
00683          if (ast_test_flag(tmp, LOCAL_NO_OPTIMIZATION))
00684             ast_set_flag(&tmp->jb_conf, AST_JB_ENABLED);
00685          else {
00686             ast_log(LOG_ERROR, "You must use the 'n' option for chan_local "
00687                "to use the 'j' option to enable the jitterbuffer\n");
00688          }
00689       }
00690       if (strchr(opts, 'b')) {
00691          ast_set_flag(tmp, LOCAL_BRIDGE);
00692       }
00693       if (strchr(opts, 'm')) {
00694          ast_set_flag(tmp, LOCAL_MOH_PASSTHRU);
00695       }
00696    }
00697 
00698    /* Look for a context */
00699    if ((c = strchr(tmp->exten, '@')))
00700       *c++ = '\0';
00701 
00702    ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
00703 
00704    tmp->reqformat = format;
00705 
00706 #if 0
00707    /* We can't do this check here, because we don't know the CallerID yet, and
00708     * the CallerID could potentially affect what step is actually taken (or
00709     * even if that step exists). */
00710    if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
00711       ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
00712       tmp = local_pvt_destroy(tmp);
00713    } else {
00714 #endif
00715       /* Add to list */
00716       AST_LIST_LOCK(&locals);
00717       AST_LIST_INSERT_HEAD(&locals, tmp, list);
00718       AST_LIST_UNLOCK(&locals);
00719 #if 0
00720    }
00721 #endif
00722    
00723    return tmp;
00724 }
00725 
00726 /*! \brief Start new local channel */
00727 static struct ast_channel *local_new(struct local_pvt *p, int state)
00728 {
00729    struct ast_channel *tmp = NULL, *tmp2 = NULL;
00730    int randnum = ast_random() & 0xffff, fmt = 0;
00731    const char *t;
00732    int ama;
00733 
00734    /* Allocate two new Asterisk channels */
00735    /* safe accountcode */
00736    if (p->owner && p->owner->accountcode)
00737       t = p->owner->accountcode;
00738    else
00739       t = "";
00740 
00741    if (p->owner)
00742       ama = p->owner->amaflags;
00743    else
00744       ama = 0;
00745    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)) 
00746          || !(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))) {
00747       if (tmp)
00748          ast_channel_free(tmp);
00749       if (tmp2)
00750          ast_channel_free(tmp2);
00751       ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
00752       return NULL;
00753    } 
00754 
00755    tmp2->tech = tmp->tech = &local_tech;
00756 
00757    tmp->nativeformats = p->reqformat;
00758    tmp2->nativeformats = p->reqformat;
00759 
00760    /* Determine our read/write format and set it on each channel */
00761    fmt = ast_best_codec(p->reqformat);
00762    tmp->writeformat = fmt;
00763    tmp2->writeformat = fmt;
00764    tmp->rawwriteformat = fmt;
00765    tmp2->rawwriteformat = fmt;
00766    tmp->readformat = fmt;
00767    tmp2->readformat = fmt;
00768    tmp->rawreadformat = fmt;
00769    tmp2->rawreadformat = fmt;
00770 
00771    tmp->tech_pvt = p;
00772    tmp2->tech_pvt = p;
00773 
00774    p->owner = tmp;
00775    p->chan = tmp2;
00776    p->u_owner = ast_module_user_add(p->owner);
00777    p->u_chan = ast_module_user_add(p->chan);
00778 
00779    ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
00780    ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
00781    ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten));
00782    tmp->priority = 1;
00783    tmp2->priority = 1;
00784 
00785    ast_jb_configure(tmp, &p->jb_conf);
00786 
00787    return tmp;
00788 }
00789 
00790 /*! \brief Part of PBX interface */
00791 static struct ast_channel *local_request(const char *type, int format, void *data, int *cause)
00792 {
00793    struct local_pvt *p = NULL;
00794    struct ast_channel *chan = NULL;
00795 
00796    /* Allocate a new private structure and then Asterisk channel */
00797    if ((p = local_alloc(data, format))) {
00798       if (!(chan = local_new(p, AST_STATE_DOWN))) {
00799          AST_LIST_LOCK(&locals);
00800          AST_LIST_REMOVE(&locals, p, list);
00801          AST_LIST_UNLOCK(&locals);
00802          p = local_pvt_destroy(p);
00803       }
00804    }
00805 
00806    return chan;
00807 }
00808 
00809 /*! \brief CLI command "local show channels" */
00810 static char *locals_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00811 {
00812    struct local_pvt *p = NULL;
00813 
00814    switch (cmd) {
00815    case CLI_INIT:
00816       e->command = "local show channels";
00817       e->usage =
00818          "Usage: local show channels\n"
00819          "       Provides summary information on active local proxy channels.\n";
00820       return NULL;
00821    case CLI_GENERATE:
00822       return NULL;
00823    }
00824 
00825    if (a->argc != 3)
00826       return CLI_SHOWUSAGE;
00827 
00828    AST_LIST_LOCK(&locals);
00829    if (!AST_LIST_EMPTY(&locals)) {
00830       AST_LIST_TRAVERSE(&locals, p, list) {
00831          ast_mutex_lock(&p->lock);
00832          ast_cli(a->fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
00833          ast_mutex_unlock(&p->lock);
00834       }
00835    } else
00836       ast_cli(a->fd, "No local channels in use\n");
00837    AST_LIST_UNLOCK(&locals);
00838 
00839    return CLI_SUCCESS;
00840 }
00841 
00842 static struct ast_cli_entry cli_local[] = {
00843    AST_CLI_DEFINE(locals_show, "List status of local channels"),
00844 };
00845 
00846 /*! \brief Load module into PBX, register channel */
00847 static int load_module(void)
00848 {
00849    /* Make sure we can register our channel type */
00850    if (ast_channel_register(&local_tech)) {
00851       ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
00852       return AST_MODULE_LOAD_FAILURE;
00853    }
00854    ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00855    return AST_MODULE_LOAD_SUCCESS;
00856 }
00857 
00858 /*! \brief Unload the local proxy channel from Asterisk */
00859 static int unload_module(void)
00860 {
00861    struct local_pvt *p = NULL;
00862 
00863    /* First, take us out of the channel loop */
00864    ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00865    ast_channel_unregister(&local_tech);
00866    if (!AST_LIST_LOCK(&locals)) {
00867       /* Hangup all interfaces if they have an owner */
00868       AST_LIST_TRAVERSE(&locals, p, list) {
00869          if (p->owner)
00870             ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
00871       }
00872       AST_LIST_UNLOCK(&locals);
00873    } else {
00874       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
00875       return -1;
00876    }     
00877    return 0;
00878 }
00879 
00880 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Local Proxy Channel (Note: used internally by other modules)");