Mon Oct 8 12:38:59 2012

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 /*** MODULEINFO
00029    <support_level>core</support_level>
00030  ***/
00031 
00032 #include "asterisk.h"
00033 
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 365313 $")
00035 
00036 #include <fcntl.h>
00037 #include <sys/signal.h>
00038 
00039 #include "asterisk/lock.h"
00040 #include "asterisk/channel.h"
00041 #include "asterisk/config.h"
00042 #include "asterisk/module.h"
00043 #include "asterisk/pbx.h"
00044 #include "asterisk/sched.h"
00045 #include "asterisk/io.h"
00046 #include "asterisk/acl.h"
00047 #include "asterisk/callerid.h"
00048 #include "asterisk/file.h"
00049 #include "asterisk/cli.h"
00050 #include "asterisk/app.h"
00051 #include "asterisk/musiconhold.h"
00052 #include "asterisk/manager.h"
00053 #include "asterisk/stringfields.h"
00054 #include "asterisk/devicestate.h"
00055 #include "asterisk/astobj2.h"
00056 
00057 /*** DOCUMENTATION
00058    <manager name="LocalOptimizeAway" language="en_US">
00059       <synopsis>
00060          Optimize away a local channel when possible.
00061       </synopsis>
00062       <syntax>
00063          <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
00064          <parameter name="Channel" required="true">
00065             <para>The channel name to optimize away.</para>
00066          </parameter>
00067       </syntax>
00068       <description>
00069          <para>A local channel created with "/n" will not automatically optimize away.
00070          Calling this command on the local channel will clear that flag and allow
00071          it to optimize away if it's bridged or when it becomes bridged.</para>
00072       </description>
00073    </manager>
00074  ***/
00075 
00076 static const char tdesc[] = "Local Proxy Channel Driver";
00077 
00078 #define IS_OUTBOUND(a,b) (a == b->chan ? 1 : 0)
00079 
00080 /* right now we are treating the locals astobj2 container as a
00081  * list.  If there is ever a reason to make this more efficient
00082  * increasing the bucket size would help. */
00083 static const int BUCKET_SIZE = 1;
00084 
00085 static struct ao2_container *locals;
00086 
00087 static struct ast_jb_conf g_jb_conf = {
00088    .flags = 0,
00089    .max_size = -1,
00090    .resync_threshold = -1,
00091    .impl = "",
00092    .target_extra = -1,
00093 };
00094 
00095 static struct ast_channel *local_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause);
00096 static int local_digit_begin(struct ast_channel *ast, char digit);
00097 static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
00098 static int local_call(struct ast_channel *ast, char *dest, int timeout);
00099 static int local_hangup(struct ast_channel *ast);
00100 static int local_answer(struct ast_channel *ast);
00101 static struct ast_frame *local_read(struct ast_channel *ast);
00102 static int local_write(struct ast_channel *ast, struct ast_frame *f);
00103 static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
00104 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00105 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
00106 static int local_sendtext(struct ast_channel *ast, const char *text);
00107 static int local_devicestate(void *data);
00108 static struct ast_channel *local_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge);
00109 static int local_queryoption(struct ast_channel *ast, int option, void *data, int *datalen);
00110 static int local_setoption(struct ast_channel *chan, int option, void *data, int datalen);
00111 
00112 /* PBX interface structure for channel registration */
00113 static const struct ast_channel_tech local_tech = {
00114    .type = "Local",
00115    .description = tdesc,
00116    .capabilities = -1,
00117    .requester = local_request,
00118    .send_digit_begin = local_digit_begin,
00119    .send_digit_end = local_digit_end,
00120    .call = local_call,
00121    .hangup = local_hangup,
00122    .answer = local_answer,
00123    .read = local_read,
00124    .write = local_write,
00125    .write_video = local_write,
00126    .exception = local_read,
00127    .indicate = local_indicate,
00128    .fixup = local_fixup,
00129    .send_html = local_sendhtml,
00130    .send_text = local_sendtext,
00131    .devicestate = local_devicestate,
00132    .bridged_channel = local_bridgedchannel,
00133    .queryoption = local_queryoption,
00134    .setoption = local_setoption,
00135 };
00136 
00137 /*! \brief the local pvt structure for all channels
00138 
00139    The local channel pvt has two ast_chan objects - the "owner" and the "next channel", the outbound channel
00140 
00141    ast_chan owner -> local_pvt -> ast_chan chan -> yet-another-pvt-depending-on-channel-type
00142 
00143 */
00144 struct local_pvt {
00145    unsigned int flags;                     /*!< Private flags */
00146    char context[AST_MAX_CONTEXT];      /*!< Context to call */
00147    char exten[AST_MAX_EXTENSION];      /*!< Extension to call */
00148    format_t reqformat;           /*!< Requested format */
00149    struct ast_jb_conf jb_conf;      /*!< jitterbuffer configuration for this local channel */
00150    struct ast_channel *owner;    /*!< Master Channel - Bridging happens here */
00151    struct ast_channel *chan;     /*!< Outbound channel - PBX is run here */
00152    struct ast_module_user *u_owner; /*!< reference to keep the module loaded while in use */
00153    struct ast_module_user *u_chan;     /*!< reference to keep the module loaded while in use */
00154 };
00155 
00156 #define LOCAL_ALREADY_MASQED  (1 << 0) /*!< Already masqueraded */
00157 #define LOCAL_LAUNCHED_PBX    (1 << 1) /*!< PBX was launched */
00158 #define LOCAL_NO_OPTIMIZATION (1 << 2) /*!< Do not optimize using masquerading */
00159 #define LOCAL_BRIDGE          (1 << 3) /*!< Report back the "true" channel as being bridged to */
00160 #define LOCAL_MOH_PASSTHRU    (1 << 4) /*!< Pass through music on hold start/stop frames */
00161 
00162 /* 
00163  * \brief Send a pvt in with no locks held and get all locks
00164  *
00165  * \note NO locks should be held prior to calling this function
00166  * \note The pvt must have a ref held before calling this function
00167  * \note if outchan or outowner is set != NULL after calling this function
00168  *       those channels are locked and reffed.
00169  * \note Batman.
00170  */
00171 static void awesome_locking(struct local_pvt *p, struct ast_channel **outchan, struct ast_channel **outowner)
00172 {
00173    struct ast_channel *chan = NULL;
00174    struct ast_channel *owner = NULL;
00175 
00176    for (;;) {
00177       ao2_lock(p);
00178       if (p->chan) {
00179          chan = p->chan;
00180          ast_channel_ref(chan);
00181       }
00182       if (p->owner) {
00183          owner = p->owner;
00184          ast_channel_ref(owner);
00185       }
00186       ao2_unlock(p);
00187 
00188       /* if we don't have both channels, then this is very easy */
00189       if (!owner || !chan) {
00190          if (owner) {
00191             ast_channel_lock(owner);
00192          } else if(chan) {
00193             ast_channel_lock(chan);
00194          }
00195          ao2_lock(p);
00196       } else {
00197          /* lock both channels first, then get the pvt lock */
00198          ast_channel_lock(chan);
00199          while (ast_channel_trylock(owner)) {
00200             CHANNEL_DEADLOCK_AVOIDANCE(chan);
00201          }
00202          ao2_lock(p);
00203       }
00204 
00205       /* Now that we have all the locks, validate that nothing changed */
00206       if (p->owner != owner || p->chan != chan) {
00207          if (owner) {
00208             ast_channel_unlock(owner);
00209             owner = ast_channel_unref(owner);
00210          }
00211          if (chan) {
00212             ast_channel_unlock(chan);
00213             chan = ast_channel_unref(chan);
00214          }
00215          ao2_unlock(p);
00216          continue;
00217       }
00218 
00219       break;
00220    }
00221    *outowner = p->owner;
00222    *outchan = p->chan;
00223 }
00224 
00225 /* Called with ast locked */
00226 static int local_setoption(struct ast_channel *ast, int option, void * data, int datalen)
00227 {
00228    int res = 0;
00229    struct local_pvt *p = NULL;
00230    struct ast_channel *otherchan = NULL;
00231    ast_chan_write_info_t *write_info;
00232 
00233    if (option != AST_OPTION_CHANNEL_WRITE) {
00234       return -1;
00235    }
00236 
00237    write_info = data;
00238 
00239    if (write_info->version != AST_CHAN_WRITE_INFO_T_VERSION) {
00240       ast_log(LOG_ERROR, "The chan_write_info_t type has changed, and this channel hasn't been updated!\n");
00241       return -1;
00242    }
00243 
00244    /* get the tech pvt */
00245    if (!(p = ast->tech_pvt)) {
00246       return -1;
00247    }
00248    ao2_ref(p, 1);
00249    ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */
00250 
00251    /* get the channel we are supposed to write to */
00252    ao2_lock(p);
00253    otherchan = (write_info->chan == p->owner) ? p->chan : p->owner;
00254    if (!otherchan || otherchan == write_info->chan) {
00255       res = -1;
00256       otherchan = NULL;
00257       ao2_unlock(p);
00258       goto setoption_cleanup;
00259    }
00260    ast_channel_ref(otherchan);
00261 
00262    /* clear the pvt lock before grabbing the channel */
00263    ao2_unlock(p);
00264 
00265    ast_channel_lock(otherchan);
00266    res = write_info->write_fn(otherchan, write_info->function, write_info->data, write_info->value);
00267    ast_channel_unlock(otherchan);
00268 
00269 setoption_cleanup:
00270    if (p) {
00271       ao2_ref(p, -1);
00272    }
00273    if (otherchan) {
00274       ast_channel_unref(otherchan);
00275    }
00276    ast_channel_lock(ast); /* Lock back before we leave */
00277    return res;
00278 }
00279 
00280 /*! \brief Adds devicestate to local channels */
00281 static int local_devicestate(void *data)
00282 {
00283    char *exten = ast_strdupa(data);
00284    char *context = NULL, *opts = NULL;
00285    int res;
00286    struct local_pvt *lp;
00287    struct ao2_iterator it;
00288 
00289    if (!(context = strchr(exten, '@'))) {
00290       ast_log(LOG_WARNING, "Someone used Local/%s somewhere without a @context. This is bad.\n", exten);
00291       return AST_DEVICE_INVALID; 
00292    }
00293 
00294    *context++ = '\0';
00295 
00296    /* Strip options if they exist */
00297    if ((opts = strchr(context, '/')))
00298       *opts = '\0';
00299 
00300    ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
00301 
00302    res = ast_exists_extension(NULL, context, exten, 1, NULL);
00303    if (!res)      
00304       return AST_DEVICE_INVALID;
00305    
00306    res = AST_DEVICE_NOT_INUSE;
00307 
00308    it = ao2_iterator_init(locals, 0);
00309    while ((lp = ao2_iterator_next(&it))) {
00310       if (!strcmp(exten, lp->exten) && !strcmp(context, lp->context) && lp->owner) {
00311          res = AST_DEVICE_INUSE;
00312          ao2_ref(lp, -1);
00313          break;
00314       }
00315       ao2_ref(lp, -1);
00316    }
00317    ao2_iterator_destroy(&it);
00318 
00319    return res;
00320 }
00321 
00322 /*! \brief Return the bridged channel of a Local channel */
00323 static struct ast_channel *local_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
00324 {
00325    struct local_pvt *p = bridge->tech_pvt;
00326    struct ast_channel *bridged = bridge;
00327 
00328    if (!p) {
00329       ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning <none>\n",
00330          chan->name, bridge->name);
00331       return NULL;
00332    }
00333 
00334    ao2_lock(p);
00335 
00336    if (ast_test_flag(p, LOCAL_BRIDGE)) {
00337       /* Find the opposite channel */
00338       bridged = (bridge == p->owner ? p->chan : p->owner);
00339       
00340       /* Now see if the opposite channel is bridged to anything */
00341       if (!bridged) {
00342          bridged = bridge;
00343       } else if (bridged->_bridge) {
00344          bridged = bridged->_bridge;
00345       }
00346    }
00347 
00348    ao2_unlock(p);
00349 
00350    return bridged;
00351 }
00352 
00353 /* Called with ast locked */
00354 static int local_queryoption(struct ast_channel *ast, int option, void *data, int *datalen)
00355 {
00356    struct local_pvt *p;
00357    struct ast_channel *bridged = NULL;
00358    struct ast_channel *tmp = NULL;
00359    int res = 0;
00360 
00361    if (option != AST_OPTION_T38_STATE) {
00362       /* AST_OPTION_T38_STATE is the only supported option at this time */
00363       return -1;
00364    }
00365 
00366    /* for some reason the channel is not locked in channel.c when this function is called */
00367    if (!(p = ast->tech_pvt)) {
00368       return -1;
00369    }
00370 
00371    ao2_lock(p);
00372    if (!(tmp = IS_OUTBOUND(ast, p) ? p->owner : p->chan)) {
00373       ao2_unlock(p);
00374       return -1;
00375    }
00376    ast_channel_ref(tmp);
00377    ao2_unlock(p);
00378    ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */
00379 
00380    ast_channel_lock(tmp);
00381    if (!(bridged = ast_bridged_channel(tmp))) {
00382       res = -1;
00383       ast_channel_unlock(tmp);
00384       goto query_cleanup;
00385    }
00386    ast_channel_ref(bridged);
00387    ast_channel_unlock(tmp);
00388 
00389 query_cleanup:
00390    if (bridged) {
00391       res = ast_channel_queryoption(bridged, option, data, datalen, 0);
00392       bridged = ast_channel_unref(bridged);
00393    }
00394    if (tmp) {
00395       tmp = ast_channel_unref(tmp);
00396    }
00397    ast_channel_lock(ast); /* Lock back before we leave */
00398 
00399    return res;
00400 }
00401 
00402 /*! \brief queue a frame on a to either the p->owner or p->chan
00403  *
00404  * \note the local_pvt MUST have it's ref count bumped before entering this function and
00405  * decremented after this function is called.  This is a side effect of the deadlock
00406  * avoidance that is necessary to lock 2 channels and a tech_pvt.  Without a ref counted
00407  * local_pvt, it is impossible to guarantee it will not be destroyed by another thread
00408  * during deadlock avoidance.
00409  */
00410 static int local_queue_frame(struct local_pvt *p, int isoutbound, struct ast_frame *f, 
00411    struct ast_channel *us, int us_locked)
00412 {
00413    struct ast_channel *other = NULL;
00414 
00415    /* Recalculate outbound channel */
00416    other = isoutbound ? p->owner : p->chan;
00417 
00418    if (!other) {
00419       return 0;
00420    }
00421 
00422    /* do not queue frame if generator is on both local channels */
00423    if (us && us->generator && other->generator) {
00424       return 0;
00425    }
00426 
00427    /* grab a ref on the channel before unlocking the pvt,
00428     * other can not go away from us now regardless of locking */
00429    ast_channel_ref(other);
00430    if (us && us_locked) {
00431       ast_channel_unlock(us);
00432    }
00433    ao2_unlock(p);
00434 
00435    if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_RINGING) {
00436       ast_setstate(other, AST_STATE_RINGING);
00437    }
00438    ast_queue_frame(other, f);
00439 
00440    other = ast_channel_unref(other);
00441    if (us && us_locked) {
00442       ast_channel_lock(us);
00443    }
00444    ao2_lock(p);
00445 
00446    return 0;
00447 }
00448 
00449 static int local_answer(struct ast_channel *ast)
00450 {
00451    struct local_pvt *p = ast->tech_pvt;
00452    int isoutbound;
00453    int res = -1;
00454 
00455    if (!p)
00456       return -1;
00457 
00458    ao2_lock(p);
00459    ao2_ref(p, 1);
00460    isoutbound = IS_OUTBOUND(ast, p);
00461    if (isoutbound) {
00462       /* Pass along answer since somebody answered us */
00463       struct ast_frame answer = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } };
00464       res = local_queue_frame(p, isoutbound, &answer, ast, 1);
00465    } else {
00466       ast_log(LOG_WARNING, "Huh?  Local is being asked to answer?\n");
00467    }
00468    ao2_unlock(p);
00469    ao2_ref(p, -1);
00470    return res;
00471 }
00472 
00473 /*!
00474  * \internal
00475  * \note This function assumes that we're only called from the "outbound" local channel side
00476  *
00477  * \note it is assummed p is locked and reffed before entering this function
00478  */
00479 static void check_bridge(struct ast_channel *ast, struct local_pvt *p)
00480 {
00481    struct ast_channel *owner;
00482    struct ast_channel *chan;
00483    struct ast_channel *bridged_chan;
00484    struct ast_frame *f;
00485 
00486    /* Do a few conditional checks early on just to see if this optimization is possible */
00487    if (ast_test_flag(p, LOCAL_NO_OPTIMIZATION | LOCAL_ALREADY_MASQED)
00488       || !p->chan || !p->owner) {
00489       return;
00490    }
00491 
00492    /* Safely get the channel bridged to p->chan */
00493    chan = ast_channel_ref(p->chan);
00494 
00495    ao2_unlock(p); /* don't call bridged channel with the pvt locked */
00496    bridged_chan = ast_bridged_channel(chan);
00497    ao2_lock(p);
00498 
00499    chan = ast_channel_unref(chan);
00500 
00501    /* since we had to unlock p to get the bridged chan, validate our
00502     * data once again and verify the bridged channel is what we expect
00503     * it to be in order to perform this optimization */
00504    if (ast_test_flag(p, LOCAL_NO_OPTIMIZATION | LOCAL_ALREADY_MASQED)
00505       || !p->chan || !p->owner
00506       || (p->chan->_bridge != bridged_chan)) {
00507       return;
00508    }
00509 
00510    /* only do the masquerade if we are being called on the outbound channel,
00511       if it has been bridged to another channel and if there are no pending
00512       frames on the owner channel (because they would be transferred to the
00513       outbound channel during the masquerade)
00514    */
00515    if (!p->chan->_bridge /* Not ast_bridged_channel!  Only go one step! */
00516       || !AST_LIST_EMPTY(&p->owner->readq)
00517       || ast != p->chan /* Sanity check (should always be false) */) {
00518       return;
00519    }
00520 
00521    /* Masquerade bridged channel into owner */
00522    /* Lock everything we need, one by one, and give up if
00523       we can't get everything.  Remember, we'll get another
00524       chance in just a little bit */
00525    if (ast_channel_trylock(p->chan->_bridge)) {
00526       return;
00527    }
00528    if (ast_check_hangup(p->chan->_bridge) || ast_channel_trylock(p->owner)) {
00529       ast_channel_unlock(p->chan->_bridge);
00530       return;
00531    }
00532 
00533    /*
00534     * At this point we have 4 locks:
00535     * p, p->chan (same as ast), p->chan->_bridge, p->owner
00536     *
00537     * Flush a voice or video frame on the outbound channel to make
00538     * the queue empty faster so we can get optimized out.
00539     */
00540    f = AST_LIST_FIRST(&p->chan->readq);
00541    if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) {
00542       AST_LIST_REMOVE_HEAD(&p->chan->readq, frame_list);
00543       ast_frfree(f);
00544       f = AST_LIST_FIRST(&p->chan->readq);
00545    }
00546 
00547    if (f
00548       || ast_check_hangup(p->owner)
00549       || ast_channel_masquerade(p->owner, p->chan->_bridge)) {
00550       ast_channel_unlock(p->owner);
00551       ast_channel_unlock(p->chan->_bridge);
00552       return;
00553    }
00554 
00555    /* Masquerade got setup. */
00556    ast_debug(4, "Masquerading %s <- %s\n",
00557       p->owner->name, p->chan->_bridge->name);
00558    if (p->owner->monitor && !p->chan->_bridge->monitor) {
00559       struct ast_channel_monitor *tmp;
00560 
00561       /* If a local channel is being monitored, we don't want a masquerade
00562        * to cause the monitor to go away. Since the masquerade swaps the monitors,
00563        * pre-swapping the monitors before the masquerade will ensure that the monitor
00564        * ends up where it is expected.
00565        */
00566       tmp = p->owner->monitor;
00567       p->owner->monitor = p->chan->_bridge->monitor;
00568       p->chan->_bridge->monitor = tmp;
00569    }
00570    if (p->chan->audiohooks) {
00571       struct ast_audiohook_list *audiohooks_swapper;
00572       audiohooks_swapper = p->chan->audiohooks;
00573       p->chan->audiohooks = p->owner->audiohooks;
00574       p->owner->audiohooks = audiohooks_swapper;
00575    }
00576 
00577    /* If any Caller ID was set, preserve it after masquerade like above. We must check
00578     * to see if Caller ID was set because otherwise we'll mistakingly copy info not
00579     * set from the dialplan and will overwrite the real channel Caller ID. The reason
00580     * for this whole preswapping action is because the Caller ID is set on the channel
00581     * thread (which is the to be masqueraded away local channel) before both local
00582     * channels are optimized away.
00583     */
00584    if (p->owner->caller.id.name.valid || p->owner->caller.id.number.valid
00585       || p->owner->caller.id.subaddress.valid || p->owner->caller.ani.name.valid
00586       || p->owner->caller.ani.number.valid || p->owner->caller.ani.subaddress.valid) {
00587       struct ast_party_caller tmp;
00588 
00589       tmp = p->owner->caller;
00590       p->owner->caller = p->chan->_bridge->caller;
00591       p->chan->_bridge->caller = tmp;
00592    }
00593    if (p->owner->redirecting.from.name.valid || p->owner->redirecting.from.number.valid
00594       || p->owner->redirecting.from.subaddress.valid || p->owner->redirecting.to.name.valid
00595       || p->owner->redirecting.to.number.valid || p->owner->redirecting.to.subaddress.valid) {
00596       struct ast_party_redirecting tmp;
00597 
00598       tmp = p->owner->redirecting;
00599       p->owner->redirecting = p->chan->_bridge->redirecting;
00600       p->chan->_bridge->redirecting = tmp;
00601    }
00602    if (p->owner->dialed.number.str || p->owner->dialed.subaddress.valid) {
00603       struct ast_party_dialed tmp;
00604 
00605       tmp = p->owner->dialed;
00606       p->owner->dialed = p->chan->_bridge->dialed;
00607       p->chan->_bridge->dialed = tmp;
00608    }
00609    ast_app_group_update(p->chan, p->owner);
00610    ast_set_flag(p, LOCAL_ALREADY_MASQED);
00611 
00612    ast_channel_unlock(p->owner);
00613    ast_channel_unlock(p->chan->_bridge);
00614 
00615    /* Do the masquerade now. */
00616    owner = ast_channel_ref(p->owner);
00617    ao2_unlock(p);
00618    ast_channel_unlock(ast);
00619    ast_do_masquerade(owner);
00620    ast_channel_unref(owner);
00621    ast_channel_lock(ast);
00622    ao2_lock(p);
00623 }
00624 
00625 static struct ast_frame  *local_read(struct ast_channel *ast)
00626 {
00627    return &ast_null_frame;
00628 }
00629 
00630 static int local_write(struct ast_channel *ast, struct ast_frame *f)
00631 {
00632    struct local_pvt *p = ast->tech_pvt;
00633    int res = -1;
00634    int isoutbound;
00635 
00636    if (!p) {
00637       return -1;
00638    }
00639 
00640    /* Just queue for delivery to the other side */
00641    ao2_ref(p, 1); /* ref for local_queue_frame */
00642    ao2_lock(p);
00643    isoutbound = IS_OUTBOUND(ast, p);
00644 
00645    if (isoutbound
00646       && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) {
00647       check_bridge(ast, p);
00648    }
00649 
00650    if (!ast_test_flag(p, LOCAL_ALREADY_MASQED)) {
00651       res = local_queue_frame(p, isoutbound, f, ast, 1);
00652    } else {
00653       ast_debug(1, "Not posting to '%s' queue since already masqueraded out\n",
00654          ast->name);
00655       res = 0;
00656    }
00657    ao2_unlock(p);
00658    ao2_ref(p, -1);
00659 
00660    return res;
00661 }
00662 
00663 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
00664 {
00665    struct local_pvt *p = newchan->tech_pvt;
00666 
00667    if (!p)
00668       return -1;
00669 
00670    ao2_lock(p);
00671 
00672    if ((p->owner != oldchan) && (p->chan != oldchan)) {
00673       ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
00674       ao2_unlock(p);
00675       return -1;
00676    }
00677    if (p->owner == oldchan)
00678       p->owner = newchan;
00679    else
00680       p->chan = newchan;
00681 
00682    /* Do not let a masquerade cause a Local channel to be bridged to itself! */
00683    if (!ast_check_hangup(newchan) && ((p->owner && p->owner->_bridge == p->chan) || (p->chan && p->chan->_bridge == p->owner))) {
00684       ast_log(LOG_WARNING, "You can not bridge a Local channel to itself!\n");
00685       ao2_unlock(p);
00686       ast_queue_hangup(newchan);
00687       return -1;
00688    }
00689 
00690    ao2_unlock(p);
00691    return 0;
00692 }
00693 
00694 static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
00695 {
00696    struct local_pvt *p = ast->tech_pvt;
00697    int res = 0;
00698    struct ast_frame f = { AST_FRAME_CONTROL, };
00699    int isoutbound;
00700 
00701    if (!p)
00702       return -1;
00703 
00704    ao2_ref(p, 1); /* ref for local_queue_frame */
00705 
00706    /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */
00707    if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) {
00708       ast_moh_start(ast, data, NULL);
00709    } else if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_UNHOLD) {
00710       ast_moh_stop(ast);
00711    } else if (condition == AST_CONTROL_CONNECTED_LINE || condition == AST_CONTROL_REDIRECTING) {
00712       struct ast_channel *this_channel;
00713       struct ast_channel *the_other_channel;
00714       /* A connected line update frame may only contain a partial amount of data, such
00715        * as just a source, or just a ton, and not the full amount of information. However,
00716        * the collected information is all stored in the outgoing channel's connectedline
00717        * structure, so when receiving a connected line update on an outgoing local channel,
00718        * we need to transmit the collected connected line information instead of whatever
00719        * happens to be in this control frame. The same applies for redirecting information, which
00720        * is why it is handled here as well.*/
00721       ao2_lock(p);
00722       isoutbound = IS_OUTBOUND(ast, p);
00723       if (isoutbound) {
00724          this_channel = p->chan;
00725          the_other_channel = p->owner;
00726       } else {
00727          this_channel = p->owner;
00728          the_other_channel = p->chan;
00729       }
00730       if (the_other_channel) {
00731          unsigned char frame_data[1024];
00732          if (condition == AST_CONTROL_CONNECTED_LINE) {
00733             if (isoutbound) {
00734                ast_connected_line_copy_to_caller(&the_other_channel->caller, &this_channel->connected);
00735             }
00736             f.datalen = ast_connected_line_build_data(frame_data, sizeof(frame_data), &this_channel->connected, NULL);
00737          } else {
00738             f.datalen = ast_redirecting_build_data(frame_data, sizeof(frame_data), &this_channel->redirecting, NULL);
00739          }
00740          f.subclass.integer = condition;
00741          f.data.ptr = frame_data;
00742          res = local_queue_frame(p, isoutbound, &f, ast, 1);
00743       }
00744       ao2_unlock(p);
00745    } else {
00746       /* Queue up a frame representing the indication as a control frame */
00747       ao2_lock(p);
00748       /*
00749        * Block -1 stop tones events if we are to be optimized out.  We
00750        * don't need a flurry of these events on a local channel chain
00751        * when initially connected to slow the optimization process.
00752        */
00753       if (0 <= condition || ast_test_flag(p, LOCAL_NO_OPTIMIZATION)) {
00754          isoutbound = IS_OUTBOUND(ast, p);
00755          f.subclass.integer = condition;
00756          f.data.ptr = (void *) data;
00757          f.datalen = datalen;
00758          res = local_queue_frame(p, isoutbound, &f, ast, 1);
00759       } else {
00760          ast_debug(4, "Blocked indication %d\n", condition);
00761       }
00762       ao2_unlock(p);
00763    }
00764 
00765    ao2_ref(p, -1);
00766    return res;
00767 }
00768 
00769 static int local_digit_begin(struct ast_channel *ast, char digit)
00770 {
00771    struct local_pvt *p = ast->tech_pvt;
00772    int res = -1;
00773    struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
00774    int isoutbound;
00775 
00776    if (!p)
00777       return -1;
00778 
00779    ao2_ref(p, 1); /* ref for local_queue_frame */
00780    ao2_lock(p);
00781    isoutbound = IS_OUTBOUND(ast, p);
00782    f.subclass.integer = digit;
00783    res = local_queue_frame(p, isoutbound, &f, ast, 0);
00784    ao2_unlock(p);
00785    ao2_ref(p, -1);
00786 
00787    return res;
00788 }
00789 
00790 static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
00791 {
00792    struct local_pvt *p = ast->tech_pvt;
00793    int res = -1;
00794    struct ast_frame f = { AST_FRAME_DTMF_END, };
00795    int isoutbound;
00796 
00797    if (!p)
00798       return -1;
00799 
00800    ao2_ref(p, 1); /* ref for local_queue_frame */
00801    ao2_lock(p);
00802    isoutbound = IS_OUTBOUND(ast, p);
00803    f.subclass.integer = digit;
00804    f.len = duration;
00805    res = local_queue_frame(p, isoutbound, &f, ast, 0);
00806    ao2_unlock(p);
00807    ao2_ref(p, -1);
00808 
00809    return res;
00810 }
00811 
00812 static int local_sendtext(struct ast_channel *ast, const char *text)
00813 {
00814    struct local_pvt *p = ast->tech_pvt;
00815    int res = -1;
00816    struct ast_frame f = { AST_FRAME_TEXT, };
00817    int isoutbound;
00818 
00819    if (!p)
00820       return -1;
00821 
00822    ao2_lock(p);
00823    ao2_ref(p, 1); /* ref for local_queue_frame */
00824    isoutbound = IS_OUTBOUND(ast, p);
00825    f.data.ptr = (char *) text;
00826    f.datalen = strlen(text) + 1;
00827    res = local_queue_frame(p, isoutbound, &f, ast, 0);
00828    ao2_unlock(p);
00829    ao2_ref(p, -1);
00830    return res;
00831 }
00832 
00833 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
00834 {
00835    struct local_pvt *p = ast->tech_pvt;
00836    int res = -1;
00837    struct ast_frame f = { AST_FRAME_HTML, };
00838    int isoutbound;
00839 
00840    if (!p)
00841       return -1;
00842 
00843    ao2_lock(p);
00844    ao2_ref(p, 1); /* ref for local_queue_frame */
00845    isoutbound = IS_OUTBOUND(ast, p);
00846    f.subclass.integer = subclass;
00847    f.data.ptr = (char *)data;
00848    f.datalen = datalen;
00849    res = local_queue_frame(p, isoutbound, &f, ast, 0);
00850    ao2_unlock(p);
00851    ao2_ref(p, -1);
00852 
00853    return res;
00854 }
00855 
00856 /*! \brief Initiate new call, part of PBX interface 
00857  *    dest is the dial string */
00858 static int local_call(struct ast_channel *ast, char *dest, int timeout)
00859 {
00860    struct local_pvt *p = ast->tech_pvt;
00861    int pvt_locked = 0;
00862 
00863    struct ast_channel *owner = NULL;
00864    struct ast_channel *chan = NULL;
00865    int res;
00866    struct ast_var_t *varptr = NULL, *new;
00867    size_t len, namelen;
00868    char *reduced_dest = ast_strdupa(dest);
00869    char *slash;
00870    const char *exten;
00871    const char *context;
00872 
00873    if (!p) {
00874       return -1;
00875    }
00876 
00877    /* since we are letting go of channel locks that were locked coming into
00878     * this function, then we need to give the tech pvt a ref */
00879    ao2_ref(p, 1);
00880    ast_channel_unlock(ast);
00881 
00882    awesome_locking(p, &chan, &owner);
00883    pvt_locked = 1;
00884 
00885    if (owner != ast) {
00886       res = -1;
00887       goto return_cleanup;
00888    }
00889 
00890    if (!owner || !chan) {
00891       res = -1;
00892       goto return_cleanup;
00893    }
00894 
00895    /*
00896     * Note that cid_num and cid_name aren't passed in the ast_channel_alloc
00897     * call, so it's done here instead.
00898     *
00899     * All these failure points just return -1. The individual strings will
00900     * be cleared when we destroy the channel.
00901     */
00902    ast_party_redirecting_copy(&chan->redirecting, &owner->redirecting);
00903 
00904    ast_party_dialed_copy(&chan->dialed, &owner->dialed);
00905 
00906    ast_connected_line_copy_to_caller(&chan->caller, &owner->connected);
00907    ast_connected_line_copy_from_caller(&chan->connected, &owner->caller);
00908 
00909    ast_string_field_set(chan, language, owner->language);
00910    ast_string_field_set(chan, accountcode, owner->accountcode);
00911    ast_string_field_set(chan, musicclass, owner->musicclass);
00912    ast_cdr_update(chan);
00913 
00914    ast_channel_cc_params_init(chan, ast_channel_get_cc_config_params(owner));
00915 
00916    /* Make sure we inherit the ANSWERED_ELSEWHERE flag if it's set on the queue/dial call request in the dialplan */
00917    if (ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
00918       ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE);
00919    }
00920 
00921    /* copy the channel variables from the incoming channel to the outgoing channel */
00922    /* Note that due to certain assumptions, they MUST be in the same order */
00923    AST_LIST_TRAVERSE(&owner->varshead, varptr, entries) {
00924       namelen = strlen(varptr->name);
00925       len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
00926       if ((new = ast_calloc(1, len))) {
00927          memcpy(new, varptr, len);
00928          new->value = &(new->name[0]) + namelen + 1;
00929          AST_LIST_INSERT_TAIL(&chan->varshead, new, entries);
00930       }
00931    }
00932    ast_channel_datastore_inherit(owner, chan);
00933    /* If the local channel has /n or /b on the end of it,
00934     * we need to lop that off for our argument to setting
00935     * up the CC_INTERFACES variable
00936     */
00937    if ((slash = strrchr(reduced_dest, '/'))) {
00938       *slash = '\0';
00939    }
00940    ast_set_cc_interfaces_chanvar(chan, reduced_dest);
00941 
00942    exten = ast_strdupa(chan->exten);
00943    context = ast_strdupa(chan->context);
00944 
00945    ao2_unlock(p);
00946    pvt_locked = 0;
00947 
00948    ast_channel_unlock(chan);
00949 
00950    if (!ast_exists_extension(chan, context, exten, 1,
00951       S_COR(owner->caller.id.number.valid, owner->caller.id.number.str, NULL))) {
00952       ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", exten, context);
00953       res = -1;
00954       chan = ast_channel_unref(chan); /* we already unlocked it, so clear it hear so the cleanup label won't touch it. */
00955       goto return_cleanup;
00956    }
00957 
00958    /* Start switch on sub channel */
00959    if (!(res = ast_pbx_start(chan))) {
00960       ao2_lock(p);
00961       ast_set_flag(p, LOCAL_LAUNCHED_PBX);
00962       ao2_unlock(p);
00963    }
00964    chan = ast_channel_unref(chan); /* chan is already unlocked, clear it here so the cleanup lable won't touch it. */
00965 
00966 return_cleanup:
00967    if (p) {
00968       if (pvt_locked) {
00969          ao2_unlock(p);
00970       }
00971       ao2_ref(p, -1);
00972    }
00973    if (chan) {
00974       ast_channel_unlock(chan);
00975       chan = ast_channel_unref(chan);
00976    }
00977 
00978    /* owner is supposed to be == to ast,  if it
00979     * is, don't unlock it because ast must exit locked */
00980    if (owner) {
00981       if (owner != ast) {
00982          ast_channel_unlock(owner);
00983          ast_channel_lock(ast);
00984       }
00985       owner = ast_channel_unref(owner);
00986    } else {
00987       /* we have to exit with ast locked */
00988       ast_channel_lock(ast);
00989    }
00990 
00991    return res;
00992 }
00993 
00994 /*! \brief Hangup a call through the local proxy channel */
00995 static int local_hangup(struct ast_channel *ast)
00996 {
00997    struct local_pvt *p = ast->tech_pvt;
00998    int isoutbound;
00999    int hangup_chan = 0;
01000    int res = 0;
01001    struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_HANGUP }, .data.uint32 = ast->hangupcause };
01002    struct ast_channel *owner = NULL;
01003    struct ast_channel *chan = NULL;
01004 
01005    if (!p) {
01006       return -1;
01007    }
01008 
01009    /* give the pvt a ref since we are unlocking the channel. */
01010    ao2_ref(p, 1);
01011 
01012    /* the pvt isn't going anywhere, we gave it a ref */
01013    ast_channel_unlock(ast);
01014 
01015    /* lock everything */
01016    awesome_locking(p, &chan, &owner);
01017 
01018    if (ast != chan && ast != owner) {
01019       res = -1;
01020       goto local_hangup_cleanup;
01021    }
01022 
01023    isoutbound = IS_OUTBOUND(ast, p); /* just comparing pointer of ast */
01024 
01025    if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
01026       ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE);
01027       ast_debug(2, "This local call has the ANSWERED_ELSEWHERE flag set.\n");
01028    }
01029 
01030    if (isoutbound) {
01031       const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
01032       if ((status) && (p->owner)) {
01033          p->owner->hangupcause = p->chan->hangupcause;
01034          pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
01035       }
01036 
01037       ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
01038       ast_module_user_remove(p->u_chan);
01039       p->chan = NULL;
01040    } else {
01041       ast_module_user_remove(p->u_owner);
01042       if (p->chan) {
01043          ast_queue_hangup(p->chan);
01044       }
01045       p->owner = NULL;
01046    }
01047 
01048    ast->tech_pvt = NULL; /* this is one of our locked channels, doesn't matter which */
01049 
01050    if (!p->owner && !p->chan) {
01051       ao2_unlock(p);
01052       /* Remove from list */
01053       ao2_unlink(locals, p);
01054       ao2_ref(p, -1);
01055       p = NULL;
01056       res = 0;
01057       goto local_hangup_cleanup;
01058    }
01059    if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) {
01060       /* Need to actually hangup since there is no PBX */
01061       hangup_chan = 1;
01062    } else {
01063       local_queue_frame(p, isoutbound, &f, NULL, 0);
01064    }
01065 
01066 local_hangup_cleanup:
01067    if (p) {
01068       ao2_unlock(p);
01069       ao2_ref(p, -1);
01070    }
01071    if (chan) {
01072       ast_channel_unlock(chan);
01073       if (hangup_chan) {
01074          ast_hangup(chan);
01075       }
01076       chan = ast_channel_unref(chan);
01077    }
01078    if (owner) {
01079       ast_channel_unlock(owner);
01080       owner = ast_channel_unref(owner);
01081    }
01082 
01083    /* leave with the same stupid channel locked that came in */
01084    ast_channel_lock(ast);
01085    return res;
01086 }
01087 
01088 /*! \brief Create a call structure */
01089 static struct local_pvt *local_alloc(const char *data, format_t format)
01090 {
01091    struct local_pvt *tmp = NULL;
01092    char *c = NULL, *opts = NULL;
01093 
01094    if (!(tmp = ao2_alloc(sizeof(*tmp), NULL))) {
01095       return NULL;
01096    }
01097 
01098    /* Initialize private structure information */
01099    ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
01100 
01101    memcpy(&tmp->jb_conf, &g_jb_conf, sizeof(tmp->jb_conf));
01102 
01103    /* Look for options */
01104    if ((opts = strchr(tmp->exten, '/'))) {
01105       *opts++ = '\0';
01106       if (strchr(opts, 'n'))
01107          ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
01108       if (strchr(opts, 'j')) {
01109          if (ast_test_flag(tmp, LOCAL_NO_OPTIMIZATION))
01110             ast_set_flag(&tmp->jb_conf, AST_JB_ENABLED);
01111          else {
01112             ast_log(LOG_ERROR, "You must use the 'n' option for chan_local "
01113                "to use the 'j' option to enable the jitterbuffer\n");
01114          }
01115       }
01116       if (strchr(opts, 'b')) {
01117          ast_set_flag(tmp, LOCAL_BRIDGE);
01118       }
01119       if (strchr(opts, 'm')) {
01120          ast_set_flag(tmp, LOCAL_MOH_PASSTHRU);
01121       }
01122    }
01123 
01124    /* Look for a context */
01125    if ((c = strchr(tmp->exten, '@')))
01126       *c++ = '\0';
01127 
01128    ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
01129 
01130    tmp->reqformat = format;
01131 
01132 #if 0
01133    /* We can't do this check here, because we don't know the CallerID yet, and
01134     * the CallerID could potentially affect what step is actually taken (or
01135     * even if that step exists). */
01136    if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
01137       ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
01138       tmp = local_pvt_destroy(tmp);
01139    } else {
01140 #endif
01141       /* Add to list */
01142       ao2_link(locals, tmp);
01143 #if 0
01144    }
01145 #endif
01146    return tmp; /* this is returned with a ref */
01147 }
01148 
01149 /*! \brief Start new local channel */
01150 static struct ast_channel *local_new(struct local_pvt *p, int state, const char *linkedid)
01151 {
01152    struct ast_channel *tmp = NULL, *tmp2 = NULL;
01153    int randnum = ast_random() & 0xffff, fmt = 0;
01154    const char *t;
01155    int ama;
01156 
01157    /* Allocate two new Asterisk channels */
01158    /* safe accountcode */
01159    if (p->owner && p->owner->accountcode)
01160       t = p->owner->accountcode;
01161    else
01162       t = "";
01163 
01164    if (p->owner)
01165       ama = p->owner->amaflags;
01166    else
01167       ama = 0;
01168 
01169    /* Make sure that the ;2 channel gets the same linkedid as ;1. You can't pass linkedid to both
01170     * allocations since if linkedid isn't set, then each channel will generate its own linkedid. */
01171    if (!(tmp = ast_channel_alloc(1, state, 0, 0, t, p->exten, p->context, linkedid, ama, "Local/%s@%s-%04x;1", p->exten, p->context, randnum)) 
01172       || !(tmp2 = ast_channel_alloc(1, AST_STATE_RING, 0, 0, t, p->exten, p->context, tmp->linkedid, ama, "Local/%s@%s-%04x;2", p->exten, p->context, randnum))) {
01173       if (tmp) {
01174          tmp = ast_channel_release(tmp);
01175       }
01176       ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
01177       return NULL;
01178    }
01179 
01180    tmp2->tech = tmp->tech = &local_tech;
01181 
01182    tmp->nativeformats = p->reqformat;
01183    tmp2->nativeformats = p->reqformat;
01184 
01185    /* Determine our read/write format and set it on each channel */
01186    fmt = ast_best_codec(p->reqformat);
01187    tmp->writeformat = fmt;
01188    tmp2->writeformat = fmt;
01189    tmp->rawwriteformat = fmt;
01190    tmp2->rawwriteformat = fmt;
01191    tmp->readformat = fmt;
01192    tmp2->readformat = fmt;
01193    tmp->rawreadformat = fmt;
01194    tmp2->rawreadformat = fmt;
01195 
01196    tmp->tech_pvt = p;
01197    tmp2->tech_pvt = p;
01198 
01199    p->owner = tmp;
01200    p->chan = tmp2;
01201    p->u_owner = ast_module_user_add(p->owner);
01202    p->u_chan = ast_module_user_add(p->chan);
01203 
01204    ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
01205    ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
01206    ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten));
01207    tmp->priority = 1;
01208    tmp2->priority = 1;
01209 
01210    ast_jb_configure(tmp, &p->jb_conf);
01211 
01212    return tmp;
01213 }
01214 
01215 /*! \brief Part of PBX interface */
01216 static struct ast_channel *local_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause)
01217 {
01218    struct local_pvt *p;
01219    struct ast_channel *chan;
01220 
01221    /* Allocate a new private structure and then Asterisk channels */
01222    p = local_alloc(data, format);
01223    if (!p) {
01224       return NULL;
01225    }
01226    chan = local_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL);
01227    if (!chan) {
01228       ao2_unlink(locals, p);
01229    } else if (ast_channel_cc_params_init(chan, requestor ? ast_channel_get_cc_config_params((struct ast_channel *)requestor) : NULL)) {
01230       ao2_unlink(locals, p);
01231       p->owner = ast_channel_release(p->owner);
01232       ast_module_user_remove(p->u_owner);
01233       p->chan = ast_channel_release(p->chan);
01234       ast_module_user_remove(p->u_chan);
01235       chan = NULL;
01236    }
01237    ao2_ref(p, -1); /* kill the ref from the alloc */
01238 
01239    return chan;
01240 }
01241 
01242 /*! \brief CLI command "local show channels" */
01243 static char *locals_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01244 {
01245    struct local_pvt *p = NULL;
01246    struct ao2_iterator it;
01247 
01248    switch (cmd) {
01249    case CLI_INIT:
01250       e->command = "local show channels";
01251       e->usage =
01252          "Usage: local show channels\n"
01253          "       Provides summary information on active local proxy channels.\n";
01254       return NULL;
01255    case CLI_GENERATE:
01256       return NULL;
01257    }
01258 
01259    if (a->argc != 3)
01260       return CLI_SHOWUSAGE;
01261 
01262    if (ao2_container_count(locals) == 0) {
01263       ast_cli(a->fd, "No local channels in use\n");
01264       return RESULT_SUCCESS;
01265    }
01266 
01267    it = ao2_iterator_init(locals, 0);
01268    while ((p = ao2_iterator_next(&it))) {
01269       ao2_lock(p);
01270       ast_cli(a->fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
01271       ao2_unlock(p);
01272       ao2_ref(p, -1);
01273    }
01274    ao2_iterator_destroy(&it);
01275 
01276    return CLI_SUCCESS;
01277 }
01278 
01279 static struct ast_cli_entry cli_local[] = {
01280    AST_CLI_DEFINE(locals_show, "List status of local channels"),
01281 };
01282 
01283 static int manager_optimize_away(struct mansession *s, const struct message *m)
01284 {
01285    const char *channel;
01286    struct local_pvt *p, *tmp = NULL;
01287    struct ast_channel *c;
01288    int found = 0;
01289    struct ao2_iterator it;
01290 
01291    channel = astman_get_header(m, "Channel");
01292 
01293    if (ast_strlen_zero(channel)) {
01294       astman_send_error(s, m, "'Channel' not specified.");
01295       return 0;
01296    }
01297 
01298    c = ast_channel_get_by_name(channel);
01299    if (!c) {
01300       astman_send_error(s, m, "Channel does not exist.");
01301       return 0;
01302    }
01303 
01304    p = c->tech_pvt;
01305    ast_channel_unref(c);
01306    c = NULL;
01307 
01308    it = ao2_iterator_init(locals, 0);
01309    while ((tmp = ao2_iterator_next(&it))) {
01310       if (tmp == p) {
01311          ao2_lock(tmp);
01312          found = 1;
01313          ast_clear_flag(tmp, LOCAL_NO_OPTIMIZATION);
01314          ao2_unlock(tmp);
01315          ao2_ref(tmp, -1);
01316          break;
01317       }
01318       ao2_ref(tmp, -1);
01319    }
01320    ao2_iterator_destroy(&it);
01321 
01322    if (found) {
01323       astman_send_ack(s, m, "Queued channel to be optimized away");
01324    } else {
01325       astman_send_error(s, m, "Unable to find channel");
01326    }
01327 
01328    return 0;
01329 }
01330 
01331 
01332 static int locals_cmp_cb(void *obj, void *arg, int flags)
01333 {
01334    return (obj == arg) ? CMP_MATCH : 0;
01335 }
01336 
01337 /*! \brief Load module into PBX, register channel */
01338 static int load_module(void)
01339 {
01340    if (!(locals = ao2_container_alloc(BUCKET_SIZE, NULL, locals_cmp_cb))) {
01341       return AST_MODULE_LOAD_FAILURE;
01342    }
01343 
01344    /* Make sure we can register our channel type */
01345    if (ast_channel_register(&local_tech)) {
01346       ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
01347       ao2_ref(locals, -1);
01348       return AST_MODULE_LOAD_FAILURE;
01349    }
01350    ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
01351    ast_manager_register_xml("LocalOptimizeAway", EVENT_FLAG_SYSTEM|EVENT_FLAG_CALL, manager_optimize_away);
01352 
01353    return AST_MODULE_LOAD_SUCCESS;
01354 }
01355 
01356 /*! \brief Unload the local proxy channel from Asterisk */
01357 static int unload_module(void)
01358 {
01359    struct local_pvt *p = NULL;
01360    struct ao2_iterator it;
01361 
01362    /* First, take us out of the channel loop */
01363    ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
01364    ast_manager_unregister("LocalOptimizeAway");
01365    ast_channel_unregister(&local_tech);
01366 
01367    it = ao2_iterator_init(locals, 0);
01368    while ((p = ao2_iterator_next(&it))) {
01369       if (p->owner) {
01370          ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
01371       }
01372       ao2_ref(p, -1);
01373    }
01374    ao2_iterator_destroy(&it);
01375    ao2_ref(locals, -1);
01376 
01377    return 0;
01378 }
01379 
01380 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Local Proxy Channel (Note: used internally by other modules)",
01381       .load = load_module,
01382       .unload = unload_module,
01383       .load_pri = AST_MODPRI_CHANNEL_DRIVER,
01384    );

Generated on Mon Oct 8 12:38:59 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7