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

Generated on 3 Mar 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1