Fri Nov 12 11:46:06 2010

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: 249895 $")
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 static void check_bridge(struct local_pvt *p, int isoutbound)
00290 {
00291    struct ast_channel_monitor *tmp;
00292    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)))
00293       return;
00294 
00295    /* only do the masquerade if we are being called on the outbound channel,
00296       if it has been bridged to another channel and if there are no pending
00297       frames on the owner channel (because they would be transferred to the
00298       outbound channel during the masquerade)
00299    */
00300    if (isoutbound && p->chan->_bridge /* Not ast_bridged_channel!  Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) {
00301       /* Masquerade bridged channel into owner */
00302       /* Lock everything we need, one by one, and give up if
00303          we can't get everything.  Remember, we'll get another
00304          chance in just a little bit */
00305       if (!ast_channel_trylock(p->chan->_bridge)) {
00306          if (!ast_check_hangup(p->chan->_bridge)) {
00307             if (!ast_channel_trylock(p->owner)) {
00308                if (!ast_check_hangup(p->owner)) {
00309                   if (p->owner->monitor && !p->chan->_bridge->monitor) {
00310                      /* If a local channel is being monitored, we don't want a masquerade
00311                       * to cause the monitor to go away. Since the masquerade swaps the monitors,
00312                       * pre-swapping the monitors before the masquerade will ensure that the monitor
00313                       * ends up where it is expected.
00314                       */
00315                      tmp = p->owner->monitor;
00316                      p->owner->monitor = p->chan->_bridge->monitor;
00317                      p->chan->_bridge->monitor = tmp;
00318                   }
00319                   if (p->chan->audiohooks) {
00320                      struct ast_audiohook_list *audiohooks_swapper;
00321                      audiohooks_swapper = p->chan->audiohooks;
00322                      p->chan->audiohooks = p->owner->audiohooks;
00323                      p->owner->audiohooks = audiohooks_swapper;
00324                   }
00325                   ast_app_group_update(p->chan, p->owner);
00326                   ast_channel_masquerade(p->owner, p->chan->_bridge);
00327                   ast_set_flag(p, LOCAL_ALREADY_MASQED);
00328                }
00329                ast_channel_unlock(p->owner);
00330             }
00331             ast_channel_unlock(p->chan->_bridge);
00332          }
00333       }
00334    /* We only allow masquerading in one 'direction'... it's important to preserve the state
00335       (group variables, etc.) that live on p->chan->_bridge (and were put there by the dialplan)
00336       when the local channels go away.
00337    */
00338 #if 0
00339    } else if (!isoutbound && p->owner && p->owner->_bridge && p->chan && AST_LIST_EMPTY(&p->chan->readq)) {
00340       /* Masquerade bridged channel into chan */
00341       if (!ast_mutex_trylock(&(p->owner->_bridge)->lock)) {
00342          if (!ast_check_hangup(p->owner->_bridge)) {
00343             if (!ast_mutex_trylock(&p->chan->lock)) {
00344                if (!ast_check_hangup(p->chan)) {
00345                   ast_channel_masquerade(p->chan, p->owner->_bridge);
00346                   ast_set_flag(p, LOCAL_ALREADY_MASQED);
00347                }
00348                ast_mutex_unlock(&p->chan->lock);
00349             }
00350          }
00351          ast_mutex_unlock(&(p->owner->_bridge)->lock);
00352       }
00353 #endif
00354    }
00355 }
00356 
00357 static struct ast_frame  *local_read(struct ast_channel *ast)
00358 {
00359    return &ast_null_frame;
00360 }
00361 
00362 static int local_write(struct ast_channel *ast, struct ast_frame *f)
00363 {
00364    struct local_pvt *p = ast->tech_pvt;
00365    int res = -1;
00366    int isoutbound;
00367 
00368    if (!p)
00369       return -1;
00370 
00371    /* Just queue for delivery to the other side */
00372    ast_mutex_lock(&p->lock);
00373    isoutbound = IS_OUTBOUND(ast, p);
00374    if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO))
00375       check_bridge(p, isoutbound);
00376    if (!ast_test_flag(p, LOCAL_ALREADY_MASQED))
00377       res = local_queue_frame(p, isoutbound, f, ast, 1);
00378    else {
00379       ast_debug(1, "Not posting to queue since already masked on '%s'\n", ast->name);
00380       res = 0;
00381    }
00382    if (!res)
00383       ast_mutex_unlock(&p->lock);
00384    return res;
00385 }
00386 
00387 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
00388 {
00389    struct local_pvt *p = newchan->tech_pvt;
00390 
00391    if (!p)
00392       return -1;
00393 
00394    ast_mutex_lock(&p->lock);
00395 
00396    if ((p->owner != oldchan) && (p->chan != oldchan)) {
00397       ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
00398       ast_mutex_unlock(&p->lock);
00399       return -1;
00400    }
00401    if (p->owner == oldchan)
00402       p->owner = newchan;
00403    else
00404       p->chan = newchan;
00405    ast_mutex_unlock(&p->lock);
00406    return 0;
00407 }
00408 
00409 static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
00410 {
00411    struct local_pvt *p = ast->tech_pvt;
00412    int res = 0;
00413    struct ast_frame f = { AST_FRAME_CONTROL, };
00414    int isoutbound;
00415 
00416    if (!p)
00417       return -1;
00418 
00419    /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */
00420    if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) {
00421       ast_moh_start(ast, data, NULL);
00422    } else if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_UNHOLD) {
00423       ast_moh_stop(ast);
00424    } else {
00425       /* Queue up a frame representing the indication as a control frame */
00426       ast_mutex_lock(&p->lock);
00427       isoutbound = IS_OUTBOUND(ast, p);
00428       f.subclass = condition;
00429       f.data.ptr = (void*)data;
00430       f.datalen = datalen;
00431       if (!(res = local_queue_frame(p, isoutbound, &f, ast, 1)))
00432          ast_mutex_unlock(&p->lock);
00433    }
00434 
00435    return res;
00436 }
00437 
00438 static int local_digit_begin(struct ast_channel *ast, char digit)
00439 {
00440    struct local_pvt *p = ast->tech_pvt;
00441    int res = -1;
00442    struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
00443    int isoutbound;
00444 
00445    if (!p)
00446       return -1;
00447 
00448    ast_mutex_lock(&p->lock);
00449    isoutbound = IS_OUTBOUND(ast, p);
00450    f.subclass = digit;
00451    if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00452       ast_mutex_unlock(&p->lock);
00453 
00454    return res;
00455 }
00456 
00457 static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
00458 {
00459    struct local_pvt *p = ast->tech_pvt;
00460    int res = -1;
00461    struct ast_frame f = { AST_FRAME_DTMF_END, };
00462    int isoutbound;
00463 
00464    if (!p)
00465       return -1;
00466 
00467    ast_mutex_lock(&p->lock);
00468    isoutbound = IS_OUTBOUND(ast, p);
00469    f.subclass = digit;
00470    f.len = duration;
00471    if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00472       ast_mutex_unlock(&p->lock);
00473 
00474    return res;
00475 }
00476 
00477 static int local_sendtext(struct ast_channel *ast, const char *text)
00478 {
00479    struct local_pvt *p = ast->tech_pvt;
00480    int res = -1;
00481    struct ast_frame f = { AST_FRAME_TEXT, };
00482    int isoutbound;
00483 
00484    if (!p)
00485       return -1;
00486 
00487    ast_mutex_lock(&p->lock);
00488    isoutbound = IS_OUTBOUND(ast, p);
00489    f.data.ptr = (char *) text;
00490    f.datalen = strlen(text) + 1;
00491    if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00492       ast_mutex_unlock(&p->lock);
00493    return res;
00494 }
00495 
00496 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
00497 {
00498    struct local_pvt *p = ast->tech_pvt;
00499    int res = -1;
00500    struct ast_frame f = { AST_FRAME_HTML, };
00501    int isoutbound;
00502 
00503    if (!p)
00504       return -1;
00505    
00506    ast_mutex_lock(&p->lock);
00507    isoutbound = IS_OUTBOUND(ast, p);
00508    f.subclass = subclass;
00509    f.data.ptr = (char *)data;
00510    f.datalen = datalen;
00511    if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00512       ast_mutex_unlock(&p->lock);
00513    return res;
00514 }
00515 
00516 /*! \brief Initiate new call, part of PBX interface 
00517  *    dest is the dial string */
00518 static int local_call(struct ast_channel *ast, char *dest, int timeout)
00519 {
00520    struct local_pvt *p = ast->tech_pvt;
00521    int res;
00522    struct ast_var_t *varptr = NULL, *new;
00523    size_t len, namelen;
00524 
00525    if (!p)
00526       return -1;
00527    
00528    ast_mutex_lock(&p->lock);
00529 
00530    /*
00531     * Note that cid_num and cid_name aren't passed in the ast_channel_alloc
00532     * call, so it's done here instead.
00533     */
00534    p->chan->cid.cid_dnid = ast_strdup(p->owner->cid.cid_dnid);
00535    p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num);
00536    p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name);
00537    p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis);
00538    p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani);
00539    p->chan->cid.cid_pres = p->owner->cid.cid_pres;
00540    p->chan->cid.cid_ani2 = p->owner->cid.cid_ani2;
00541    p->chan->cid.cid_ton = p->owner->cid.cid_ton;
00542    p->chan->cid.cid_tns = p->owner->cid.cid_tns;
00543    ast_string_field_set(p->chan, language, p->owner->language);
00544    ast_string_field_set(p->chan, accountcode, p->owner->accountcode);
00545    ast_string_field_set(p->chan, musicclass, p->owner->musicclass);
00546    ast_cdr_update(p->chan);
00547    p->chan->cdrflags = p->owner->cdrflags;
00548 
00549    if (!ast_exists_extension(NULL, p->chan->context, p->chan->exten, 1, p->owner->cid.cid_num)) {
00550       ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->chan->exten, p->chan->context);
00551       ast_mutex_unlock(&p->lock);
00552       return -1;
00553    }
00554 
00555    /* Make sure we inherit the ANSWERED_ELSEWHERE flag if it's set on the queue/dial call request in the dialplan */
00556    if (ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
00557       ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE);
00558    }
00559 
00560    /* copy the channel variables from the incoming channel to the outgoing channel */
00561    /* Note that due to certain assumptions, they MUST be in the same order */
00562    AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) {
00563       namelen = strlen(varptr->name);
00564       len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
00565       if ((new = ast_calloc(1, len))) {
00566          memcpy(new, varptr, len);
00567          new->value = &(new->name[0]) + namelen + 1;
00568          AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries);
00569       }
00570    }
00571    ast_channel_datastore_inherit(p->owner, p->chan);
00572 
00573    /* Start switch on sub channel */
00574    if (!(res = ast_pbx_start(p->chan)))
00575       ast_set_flag(p, LOCAL_LAUNCHED_PBX);
00576 
00577    ast_mutex_unlock(&p->lock);
00578    return res;
00579 }
00580 
00581 /*! \brief Hangup a call through the local proxy channel */
00582 static int local_hangup(struct ast_channel *ast)
00583 {
00584    struct local_pvt *p = ast->tech_pvt;
00585    int isoutbound;
00586    struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP, .data.uint32 = ast->hangupcause };
00587    struct ast_channel *ochan = NULL;
00588    int glaredetect = 0, res = 0;
00589 
00590    if (!p)
00591       return -1;
00592 
00593    ast_mutex_lock(&p->lock);
00594 
00595    isoutbound = IS_OUTBOUND(ast, p);
00596 
00597    if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
00598       ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE);
00599       ast_debug(2, "This local call has the ANSWERED_ELSEWHERE flag set.\n");
00600    }
00601 
00602    if (isoutbound) {
00603       const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
00604       if ((status) && (p->owner)) {
00605          /* Deadlock avoidance */
00606          while (p->owner && ast_channel_trylock(p->owner)) {
00607             ast_mutex_unlock(&p->lock);
00608             if (ast) {
00609                ast_channel_unlock(ast);
00610             }
00611             usleep(1);
00612             if (ast) {
00613                ast_channel_lock(ast);
00614             }
00615             ast_mutex_lock(&p->lock);
00616          }
00617          if (p->owner) {
00618             pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
00619             ast_channel_unlock(p->owner);
00620          }
00621       }
00622       p->chan = NULL;
00623       ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
00624       ast_module_user_remove(p->u_chan);
00625    } else {
00626       ast_module_user_remove(p->u_owner);
00627       while (p->chan && ast_channel_trylock(p->chan)) {
00628          DEADLOCK_AVOIDANCE(&p->lock);
00629       }
00630       p->owner = NULL;
00631       if (p->chan) {
00632          ast_queue_hangup(p->chan);
00633          ast_channel_unlock(p->chan);
00634       }
00635    }
00636    
00637    ast->tech_pvt = NULL;
00638    
00639    if (!p->owner && !p->chan) {
00640       /* Okay, done with the private part now, too. */
00641       glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT);
00642       /* If we have a queue holding, don't actually destroy p yet, but
00643          let local_queue do it. */
00644       if (glaredetect)
00645          ast_set_flag(p, LOCAL_CANCEL_QUEUE);
00646       /* Remove from list */
00647       AST_LIST_LOCK(&locals);
00648       AST_LIST_REMOVE(&locals, p, list);
00649       AST_LIST_UNLOCK(&locals);
00650       ast_mutex_unlock(&p->lock);
00651       /* And destroy */
00652       if (!glaredetect) {
00653          p = local_pvt_destroy(p);
00654       }
00655       return 0;
00656    }
00657    if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX))
00658       /* Need to actually hangup since there is no PBX */
00659       ochan = p->chan;
00660    else
00661       res = local_queue_frame(p, isoutbound, &f, NULL, 1);
00662    if (!res)
00663       ast_mutex_unlock(&p->lock);
00664    if (ochan)
00665       ast_hangup(ochan);
00666    return 0;
00667 }
00668 
00669 /*! \brief Create a call structure */
00670 static struct local_pvt *local_alloc(const char *data, int format)
00671 {
00672    struct local_pvt *tmp = NULL;
00673    char *c = NULL, *opts = NULL;
00674 
00675    if (!(tmp = ast_calloc(1, sizeof(*tmp))))
00676       return NULL;
00677 
00678    /* Initialize private structure information */
00679    ast_mutex_init(&tmp->lock);
00680    ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
00681 
00682    memcpy(&tmp->jb_conf, &g_jb_conf, sizeof(tmp->jb_conf));
00683 
00684    /* Look for options */
00685    if ((opts = strchr(tmp->exten, '/'))) {
00686       *opts++ = '\0';
00687       if (strchr(opts, 'n'))
00688          ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
00689       if (strchr(opts, 'j')) {
00690          if (ast_test_flag(tmp, LOCAL_NO_OPTIMIZATION))
00691             ast_set_flag(&tmp->jb_conf, AST_JB_ENABLED);
00692          else {
00693             ast_log(LOG_ERROR, "You must use the 'n' option for chan_local "
00694                "to use the 'j' option to enable the jitterbuffer\n");
00695          }
00696       }
00697       if (strchr(opts, 'b')) {
00698          ast_set_flag(tmp, LOCAL_BRIDGE);
00699       }
00700       if (strchr(opts, 'm')) {
00701          ast_set_flag(tmp, LOCAL_MOH_PASSTHRU);
00702       }
00703    }
00704 
00705    /* Look for a context */
00706    if ((c = strchr(tmp->exten, '@')))
00707       *c++ = '\0';
00708 
00709    ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
00710 
00711    tmp->reqformat = format;
00712 
00713 #if 0
00714    /* We can't do this check here, because we don't know the CallerID yet, and
00715     * the CallerID could potentially affect what step is actually taken (or
00716     * even if that step exists). */
00717    if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
00718       ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
00719       tmp = local_pvt_destroy(tmp);
00720    } else {
00721 #endif
00722       /* Add to list */
00723       AST_LIST_LOCK(&locals);
00724       AST_LIST_INSERT_HEAD(&locals, tmp, list);
00725       AST_LIST_UNLOCK(&locals);
00726 #if 0
00727    }
00728 #endif
00729    
00730    return tmp;
00731 }
00732 
00733 /*! \brief Start new local channel */
00734 static struct ast_channel *local_new(struct local_pvt *p, int state)
00735 {
00736    struct ast_channel *tmp = NULL, *tmp2 = NULL;
00737    int randnum = ast_random() & 0xffff, fmt = 0;
00738    const char *t;
00739    int ama;
00740 
00741    /* Allocate two new Asterisk channels */
00742    /* safe accountcode */
00743    if (p->owner && p->owner->accountcode)
00744       t = p->owner->accountcode;
00745    else
00746       t = "";
00747 
00748    if (p->owner)
00749       ama = p->owner->amaflags;
00750    else
00751       ama = 0;
00752    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)) 
00753          || !(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))) {
00754       if (tmp)
00755          ast_channel_free(tmp);
00756       if (tmp2)
00757          ast_channel_free(tmp2);
00758       ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
00759       return NULL;
00760    } 
00761 
00762    tmp2->tech = tmp->tech = &local_tech;
00763 
00764    tmp->nativeformats = p->reqformat;
00765    tmp2->nativeformats = p->reqformat;
00766 
00767    /* Determine our read/write format and set it on each channel */
00768    fmt = ast_best_codec(p->reqformat);
00769    tmp->writeformat = fmt;
00770    tmp2->writeformat = fmt;
00771    tmp->rawwriteformat = fmt;
00772    tmp2->rawwriteformat = fmt;
00773    tmp->readformat = fmt;
00774    tmp2->readformat = fmt;
00775    tmp->rawreadformat = fmt;
00776    tmp2->rawreadformat = fmt;
00777 
00778    tmp->tech_pvt = p;
00779    tmp2->tech_pvt = p;
00780 
00781    p->owner = tmp;
00782    p->chan = tmp2;
00783    p->u_owner = ast_module_user_add(p->owner);
00784    p->u_chan = ast_module_user_add(p->chan);
00785 
00786    ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
00787    ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
00788    ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten));
00789    tmp->priority = 1;
00790    tmp2->priority = 1;
00791 
00792    ast_jb_configure(tmp, &p->jb_conf);
00793 
00794    return tmp;
00795 }
00796 
00797 /*! \brief Part of PBX interface */
00798 static struct ast_channel *local_request(const char *type, int format, void *data, int *cause)
00799 {
00800    struct local_pvt *p = NULL;
00801    struct ast_channel *chan = NULL;
00802 
00803    /* Allocate a new private structure and then Asterisk channel */
00804    if ((p = local_alloc(data, format))) {
00805       if (!(chan = local_new(p, AST_STATE_DOWN))) {
00806          AST_LIST_LOCK(&locals);
00807          AST_LIST_REMOVE(&locals, p, list);
00808          AST_LIST_UNLOCK(&locals);
00809          p = local_pvt_destroy(p);
00810       }
00811    }
00812 
00813    return chan;
00814 }
00815 
00816 /*! \brief CLI command "local show channels" */
00817 static char *locals_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00818 {
00819    struct local_pvt *p = NULL;
00820 
00821    switch (cmd) {
00822    case CLI_INIT:
00823       e->command = "local show channels";
00824       e->usage =
00825          "Usage: local show channels\n"
00826          "       Provides summary information on active local proxy channels.\n";
00827       return NULL;
00828    case CLI_GENERATE:
00829       return NULL;
00830    }
00831 
00832    if (a->argc != 3)
00833       return CLI_SHOWUSAGE;
00834 
00835    AST_LIST_LOCK(&locals);
00836    if (!AST_LIST_EMPTY(&locals)) {
00837       AST_LIST_TRAVERSE(&locals, p, list) {
00838          ast_mutex_lock(&p->lock);
00839          ast_cli(a->fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
00840          ast_mutex_unlock(&p->lock);
00841       }
00842    } else
00843       ast_cli(a->fd, "No local channels in use\n");
00844    AST_LIST_UNLOCK(&locals);
00845 
00846    return CLI_SUCCESS;
00847 }
00848 
00849 static struct ast_cli_entry cli_local[] = {
00850    AST_CLI_DEFINE(locals_show, "List status of local channels"),
00851 };
00852 
00853 /*! \brief Load module into PBX, register channel */
00854 static int load_module(void)
00855 {
00856    /* Make sure we can register our channel type */
00857    if (ast_channel_register(&local_tech)) {
00858       ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
00859       return AST_MODULE_LOAD_FAILURE;
00860    }
00861    ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00862    return AST_MODULE_LOAD_SUCCESS;
00863 }
00864 
00865 /*! \brief Unload the local proxy channel from Asterisk */
00866 static int unload_module(void)
00867 {
00868    struct local_pvt *p = NULL;
00869 
00870    /* First, take us out of the channel loop */
00871    ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00872    ast_channel_unregister(&local_tech);
00873    if (!AST_LIST_LOCK(&locals)) {
00874       /* Hangup all interfaces if they have an owner */
00875       AST_LIST_TRAVERSE(&locals, p, list) {
00876          if (p->owner)
00877             ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
00878       }
00879       AST_LIST_UNLOCK(&locals);
00880    } else {
00881       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
00882       return -1;
00883    }     
00884    return 0;
00885 }
00886 
00887 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Local Proxy Channel (Note: used internally by other modules)");

Generated by  doxygen 1.6.2