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

Generated on Sat Feb 11 06:33:09 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6