Mon Mar 19 11:30:24 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: 328209 $")
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 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->name);
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    ao2_lock(p);
00627 
00628    if ((p->owner != oldchan) && (p->chan != oldchan)) {
00629       ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
00630       ao2_unlock(p);
00631       return -1;
00632    }
00633    if (p->owner == oldchan)
00634       p->owner = newchan;
00635    else
00636       p->chan = newchan;
00637 
00638    /* Do not let a masquerade cause a Local channel to be bridged to itself! */
00639    if (!ast_check_hangup(newchan) && ((p->owner && p->owner->_bridge == p->chan) || (p->chan && p->chan->_bridge == p->owner))) {
00640       ast_log(LOG_WARNING, "You can not bridge a Local channel to itself!\n");
00641       ao2_unlock(p);
00642       ast_queue_hangup(newchan);
00643       return -1;
00644    }
00645 
00646    ao2_unlock(p);
00647    return 0;
00648 }
00649 
00650 static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
00651 {
00652    struct local_pvt *p = ast->tech_pvt;
00653    int res = 0;
00654    struct ast_frame f = { AST_FRAME_CONTROL, };
00655    int isoutbound;
00656 
00657    if (!p)
00658       return -1;
00659 
00660    ao2_ref(p, 1); /* ref for local_queue_frame */
00661 
00662    /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */
00663    if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) {
00664       ast_moh_start(ast, data, NULL);
00665    } else if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_UNHOLD) {
00666       ast_moh_stop(ast);
00667    } else if (condition == AST_CONTROL_CONNECTED_LINE || condition == AST_CONTROL_REDIRECTING) {
00668       struct ast_channel *this_channel;
00669       struct ast_channel *the_other_channel;
00670       /* A connected line update frame may only contain a partial amount of data, such
00671        * as just a source, or just a ton, and not the full amount of information. However,
00672        * the collected information is all stored in the outgoing channel's connectedline
00673        * structure, so when receiving a connected line update on an outgoing local channel,
00674        * we need to transmit the collected connected line information instead of whatever
00675        * happens to be in this control frame. The same applies for redirecting information, which
00676        * is why it is handled here as well.*/
00677       ao2_lock(p);
00678       isoutbound = IS_OUTBOUND(ast, p);
00679       if (isoutbound) {
00680          this_channel = p->chan;
00681          the_other_channel = p->owner;
00682       } else {
00683          this_channel = p->owner;
00684          the_other_channel = p->chan;
00685       }
00686       if (the_other_channel) {
00687          unsigned char frame_data[1024];
00688          if (condition == AST_CONTROL_CONNECTED_LINE) {
00689             if (isoutbound) {
00690                ast_connected_line_copy_to_caller(&the_other_channel->caller, &this_channel->connected);
00691             }
00692             f.datalen = ast_connected_line_build_data(frame_data, sizeof(frame_data), &this_channel->connected, NULL);
00693          } else {
00694             f.datalen = ast_redirecting_build_data(frame_data, sizeof(frame_data), &this_channel->redirecting, NULL);
00695          }
00696          f.subclass.integer = condition;
00697          f.data.ptr = frame_data;
00698          res = local_queue_frame(p, isoutbound, &f, ast, 1);
00699       }
00700       ao2_unlock(p);
00701    } else {
00702       /* Queue up a frame representing the indication as a control frame */
00703       ao2_lock(p);
00704       isoutbound = IS_OUTBOUND(ast, p);
00705       f.subclass.integer = condition;
00706       f.data.ptr = (void*)data;
00707       f.datalen = datalen;
00708       res = local_queue_frame(p, isoutbound, &f, ast, 1);
00709       ao2_unlock(p);
00710    }
00711 
00712    ao2_ref(p, -1);
00713    return res;
00714 }
00715 
00716 static int local_digit_begin(struct ast_channel *ast, char digit)
00717 {
00718    struct local_pvt *p = ast->tech_pvt;
00719    int res = -1;
00720    struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
00721    int isoutbound;
00722 
00723    if (!p)
00724       return -1;
00725 
00726    ao2_ref(p, 1); /* ref for local_queue_frame */
00727    ao2_lock(p);
00728    isoutbound = IS_OUTBOUND(ast, p);
00729    f.subclass.integer = digit;
00730    res = local_queue_frame(p, isoutbound, &f, ast, 0);
00731    ao2_unlock(p);
00732    ao2_ref(p, -1);
00733 
00734    return res;
00735 }
00736 
00737 static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
00738 {
00739    struct local_pvt *p = ast->tech_pvt;
00740    int res = -1;
00741    struct ast_frame f = { AST_FRAME_DTMF_END, };
00742    int isoutbound;
00743 
00744    if (!p)
00745       return -1;
00746 
00747    ao2_ref(p, 1); /* ref for local_queue_frame */
00748    ao2_lock(p);
00749    isoutbound = IS_OUTBOUND(ast, p);
00750    f.subclass.integer = digit;
00751    f.len = duration;
00752    res = local_queue_frame(p, isoutbound, &f, ast, 0);
00753    ao2_unlock(p);
00754    ao2_ref(p, -1);
00755 
00756    return res;
00757 }
00758 
00759 static int local_sendtext(struct ast_channel *ast, const char *text)
00760 {
00761    struct local_pvt *p = ast->tech_pvt;
00762    int res = -1;
00763    struct ast_frame f = { AST_FRAME_TEXT, };
00764    int isoutbound;
00765 
00766    if (!p)
00767       return -1;
00768 
00769    ao2_lock(p);
00770    ao2_ref(p, 1); /* ref for local_queue_frame */
00771    isoutbound = IS_OUTBOUND(ast, p);
00772    f.data.ptr = (char *) text;
00773    f.datalen = strlen(text) + 1;
00774    res = local_queue_frame(p, isoutbound, &f, ast, 0);
00775    ao2_unlock(p);
00776    ao2_ref(p, -1);
00777    return res;
00778 }
00779 
00780 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
00781 {
00782    struct local_pvt *p = ast->tech_pvt;
00783    int res = -1;
00784    struct ast_frame f = { AST_FRAME_HTML, };
00785    int isoutbound;
00786 
00787    if (!p)
00788       return -1;
00789 
00790    ao2_lock(p);
00791    ao2_ref(p, 1); /* ref for local_queue_frame */
00792    isoutbound = IS_OUTBOUND(ast, p);
00793    f.subclass.integer = subclass;
00794    f.data.ptr = (char *)data;
00795    f.datalen = datalen;
00796    res = local_queue_frame(p, isoutbound, &f, ast, 0);
00797    ao2_unlock(p);
00798    ao2_ref(p, -1);
00799 
00800    return res;
00801 }
00802 
00803 /*! \brief Initiate new call, part of PBX interface 
00804  *    dest is the dial string */
00805 static int local_call(struct ast_channel *ast, char *dest, int timeout)
00806 {
00807    struct local_pvt *p = ast->tech_pvt;
00808    int pvt_locked = 0;
00809 
00810    struct ast_channel *owner = NULL;
00811    struct ast_channel *chan = NULL;
00812    int res;
00813    struct ast_var_t *varptr = NULL, *new;
00814    size_t len, namelen;
00815    char *reduced_dest = ast_strdupa(dest);
00816    char *slash;
00817    const char *exten;
00818    const char *context;
00819 
00820    if (!p) {
00821       return -1;
00822    }
00823 
00824    /* since we are letting go of channel locks that were locked coming into
00825     * this function, then we need to give the tech pvt a ref */
00826    ao2_ref(p, 1);
00827    ast_channel_unlock(ast);
00828 
00829    awesome_locking(p, &chan, &owner);
00830    pvt_locked = 1;
00831 
00832    if (owner != ast) {
00833       res = -1;
00834       goto return_cleanup;
00835    }
00836 
00837    if (!owner || !chan) {
00838       res = -1;
00839       goto return_cleanup;
00840    }
00841 
00842    /*
00843     * Note that cid_num and cid_name aren't passed in the ast_channel_alloc
00844     * call, so it's done here instead.
00845     *
00846     * All these failure points just return -1. The individual strings will
00847     * be cleared when we destroy the channel.
00848     */
00849    ast_party_redirecting_copy(&chan->redirecting, &owner->redirecting);
00850 
00851    ast_party_dialed_copy(&chan->dialed, &owner->dialed);
00852 
00853    ast_connected_line_copy_to_caller(&chan->caller, &owner->connected);
00854    ast_connected_line_copy_from_caller(&chan->connected, &owner->caller);
00855 
00856    ast_string_field_set(chan, language, owner->language);
00857    ast_string_field_set(chan, accountcode, owner->accountcode);
00858    ast_string_field_set(chan, musicclass, owner->musicclass);
00859    ast_cdr_update(chan);
00860 
00861    ast_channel_cc_params_init(chan, ast_channel_get_cc_config_params(owner));
00862 
00863    /* Make sure we inherit the ANSWERED_ELSEWHERE flag if it's set on the queue/dial call request in the dialplan */
00864    if (ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
00865       ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE);
00866    }
00867 
00868    /* copy the channel variables from the incoming channel to the outgoing channel */
00869    /* Note that due to certain assumptions, they MUST be in the same order */
00870    AST_LIST_TRAVERSE(&owner->varshead, varptr, entries) {
00871       namelen = strlen(varptr->name);
00872       len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
00873       if ((new = ast_calloc(1, len))) {
00874          memcpy(new, varptr, len);
00875          new->value = &(new->name[0]) + namelen + 1;
00876          AST_LIST_INSERT_TAIL(&chan->varshead, new, entries);
00877       }
00878    }
00879    ast_channel_datastore_inherit(owner, chan);
00880    /* If the local channel has /n or /b on the end of it,
00881     * we need to lop that off for our argument to setting
00882     * up the CC_INTERFACES variable
00883     */
00884    if ((slash = strrchr(reduced_dest, '/'))) {
00885       *slash = '\0';
00886    }
00887    ast_set_cc_interfaces_chanvar(chan, reduced_dest);
00888 
00889    exten = ast_strdupa(chan->exten);
00890    context = ast_strdupa(chan->context);
00891 
00892    ao2_unlock(p);
00893    pvt_locked = 0;
00894 
00895    ast_channel_unlock(chan);
00896 
00897    if (!ast_exists_extension(chan, context, exten, 1,
00898       S_COR(owner->caller.id.number.valid, owner->caller.id.number.str, NULL))) {
00899       ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", exten, context);
00900       res = -1;
00901       chan = ast_channel_unref(chan); /* we already unlocked it, so clear it hear so the cleanup label won't touch it. */
00902       goto return_cleanup;
00903    }
00904 
00905    /* Start switch on sub channel */
00906    if (!(res = ast_pbx_start(chan))) {
00907       ao2_lock(p);
00908       ast_set_flag(p, LOCAL_LAUNCHED_PBX);
00909       ao2_unlock(p);
00910    }
00911    chan = ast_channel_unref(chan); /* chan is already unlocked, clear it here so the cleanup lable won't touch it. */
00912 
00913 return_cleanup:
00914    if (p) {
00915       if (pvt_locked) {
00916          ao2_unlock(p);
00917       }
00918       ao2_ref(p, -1);
00919    }
00920    if (chan) {
00921       ast_channel_unlock(chan);
00922       chan = ast_channel_unref(chan);
00923    }
00924 
00925    /* owner is supposed to be == to ast,  if it
00926     * is, don't unlock it because ast must exit locked */
00927    if (owner) {
00928       if (owner != ast) {
00929          ast_channel_unlock(owner);
00930          ast_channel_lock(ast);
00931       }
00932       owner = ast_channel_unref(owner);
00933    } else {
00934       /* we have to exit with ast locked */
00935       ast_channel_lock(ast);
00936    }
00937 
00938    return res;
00939 }
00940 
00941 /*! \brief Hangup a call through the local proxy channel */
00942 static int local_hangup(struct ast_channel *ast)
00943 {
00944    struct local_pvt *p = ast->tech_pvt;
00945    int isoutbound;
00946    int hangup_chan = 0;
00947    int res = 0;
00948    struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_HANGUP }, .data.uint32 = ast->hangupcause };
00949    struct ast_channel *owner = NULL;
00950    struct ast_channel *chan = NULL;
00951 
00952    if (!p) {
00953       return -1;
00954    }
00955 
00956    /* give the pvt a ref since we are unlocking the channel. */
00957    ao2_ref(p, 1);
00958 
00959    /* the pvt isn't going anywhere, we gave it a ref */
00960    ast_channel_unlock(ast);
00961 
00962    /* lock everything */
00963    awesome_locking(p, &chan, &owner);
00964 
00965    if (ast != chan && ast != owner) {
00966       res = -1;
00967       goto local_hangup_cleanup;
00968    }
00969 
00970    isoutbound = IS_OUTBOUND(ast, p); /* just comparing pointer of ast */
00971 
00972    if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
00973       ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE);
00974       ast_debug(2, "This local call has the ANSWERED_ELSEWHERE flag set.\n");
00975    }
00976 
00977    if (isoutbound) {
00978       const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
00979       if ((status) && (p->owner)) {
00980          p->owner->hangupcause = p->chan->hangupcause;
00981          pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
00982       }
00983 
00984       ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
00985       ast_module_user_remove(p->u_chan);
00986       p->chan = NULL;
00987    } else {
00988       ast_module_user_remove(p->u_owner);
00989       if (p->chan) {
00990          ast_queue_hangup(p->chan);
00991       }
00992       p->owner = NULL;
00993    }
00994 
00995    ast->tech_pvt = NULL; /* this is one of our locked channels, doesn't matter which */
00996 
00997    if (!p->owner && !p->chan) {
00998       ao2_unlock(p);
00999       /* Remove from list */
01000       ao2_unlink(locals, p);
01001       ao2_ref(p, -1);
01002       p = NULL;
01003       res = 0;
01004       goto local_hangup_cleanup;
01005    }
01006    if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) {
01007       /* Need to actually hangup since there is no PBX */
01008       hangup_chan = 1;
01009    } else {
01010       local_queue_frame(p, isoutbound, &f, NULL, 0);
01011    }
01012 
01013 local_hangup_cleanup:
01014    if (p) {
01015       ao2_unlock(p);
01016       ao2_ref(p, -1);
01017    }
01018    if (chan) {
01019       ast_channel_unlock(chan);
01020       if (hangup_chan) {
01021          ast_hangup(chan);
01022       }
01023       chan = ast_channel_unref(chan);
01024    }
01025    if (owner) {
01026       ast_channel_unlock(owner);
01027       owner = ast_channel_unref(owner);
01028    }
01029 
01030    /* leave with the same stupid channel locked that came in */
01031    ast_channel_lock(ast);
01032    return res;
01033 }
01034 
01035 /*! \brief Create a call structure */
01036 static struct local_pvt *local_alloc(const char *data, format_t format)
01037 {
01038    struct local_pvt *tmp = NULL;
01039    char *c = NULL, *opts = NULL;
01040 
01041    if (!(tmp = ao2_alloc(sizeof(*tmp), NULL))) {
01042       return NULL;
01043    }
01044 
01045    /* Initialize private structure information */
01046    ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
01047 
01048    memcpy(&tmp->jb_conf, &g_jb_conf, sizeof(tmp->jb_conf));
01049 
01050    /* Look for options */
01051    if ((opts = strchr(tmp->exten, '/'))) {
01052       *opts++ = '\0';
01053       if (strchr(opts, 'n'))
01054          ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
01055       if (strchr(opts, 'j')) {
01056          if (ast_test_flag(tmp, LOCAL_NO_OPTIMIZATION))
01057             ast_set_flag(&tmp->jb_conf, AST_JB_ENABLED);
01058          else {
01059             ast_log(LOG_ERROR, "You must use the 'n' option for chan_local "
01060                "to use the 'j' option to enable the jitterbuffer\n");
01061          }
01062       }
01063       if (strchr(opts, 'b')) {
01064          ast_set_flag(tmp, LOCAL_BRIDGE);
01065       }
01066       if (strchr(opts, 'm')) {
01067          ast_set_flag(tmp, LOCAL_MOH_PASSTHRU);
01068       }
01069    }
01070 
01071    /* Look for a context */
01072    if ((c = strchr(tmp->exten, '@')))
01073       *c++ = '\0';
01074 
01075    ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
01076 
01077    tmp->reqformat = format;
01078 
01079 #if 0
01080    /* We can't do this check here, because we don't know the CallerID yet, and
01081     * the CallerID could potentially affect what step is actually taken (or
01082     * even if that step exists). */
01083    if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
01084       ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
01085       tmp = local_pvt_destroy(tmp);
01086    } else {
01087 #endif
01088       /* Add to list */
01089       ao2_link(locals, tmp);
01090 #if 0
01091    }
01092 #endif
01093    return tmp; /* this is returned with a ref */
01094 }
01095 
01096 /*! \brief Start new local channel */
01097 static struct ast_channel *local_new(struct local_pvt *p, int state, const char *linkedid)
01098 {
01099    struct ast_channel *tmp = NULL, *tmp2 = NULL;
01100    int randnum = ast_random() & 0xffff, fmt = 0;
01101    const char *t;
01102    int ama;
01103 
01104    /* Allocate two new Asterisk channels */
01105    /* safe accountcode */
01106    if (p->owner && p->owner->accountcode)
01107       t = p->owner->accountcode;
01108    else
01109       t = "";
01110 
01111    if (p->owner)
01112       ama = p->owner->amaflags;
01113    else
01114       ama = 0;
01115    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)) 
01116       || !(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))) {
01117       if (tmp) {
01118          tmp = ast_channel_release(tmp);
01119       }
01120       ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
01121       return NULL;
01122    }
01123 
01124    tmp2->tech = tmp->tech = &local_tech;
01125 
01126    tmp->nativeformats = p->reqformat;
01127    tmp2->nativeformats = p->reqformat;
01128 
01129    /* Determine our read/write format and set it on each channel */
01130    fmt = ast_best_codec(p->reqformat);
01131    tmp->writeformat = fmt;
01132    tmp2->writeformat = fmt;
01133    tmp->rawwriteformat = fmt;
01134    tmp2->rawwriteformat = fmt;
01135    tmp->readformat = fmt;
01136    tmp2->readformat = fmt;
01137    tmp->rawreadformat = fmt;
01138    tmp2->rawreadformat = fmt;
01139 
01140    tmp->tech_pvt = p;
01141    tmp2->tech_pvt = p;
01142 
01143    p->owner = tmp;
01144    p->chan = tmp2;
01145    p->u_owner = ast_module_user_add(p->owner);
01146    p->u_chan = ast_module_user_add(p->chan);
01147 
01148    ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
01149    ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
01150    ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten));
01151    tmp->priority = 1;
01152    tmp2->priority = 1;
01153 
01154    ast_jb_configure(tmp, &p->jb_conf);
01155 
01156    return tmp;
01157 }
01158 
01159 /*! \brief Part of PBX interface */
01160 static struct ast_channel *local_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause)
01161 {
01162    struct local_pvt *p = NULL;
01163    struct ast_channel *chan = NULL;
01164 
01165    /* Allocate a new private structure and then Asterisk channel */
01166    if ((p = local_alloc(data, format))) {
01167       if (!(chan = local_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL))) {
01168          ao2_unlink(locals, p);
01169       }
01170       if (chan && ast_channel_cc_params_init(chan, requestor ? ast_channel_get_cc_config_params((struct ast_channel *)requestor) : NULL)) {
01171          chan = ast_channel_release(chan);
01172          ao2_unlink(locals, p);
01173       }
01174       ao2_ref(p, -1); /* kill the ref from the alloc */
01175    }
01176 
01177    return chan;
01178 }
01179 
01180 /*! \brief CLI command "local show channels" */
01181 static char *locals_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01182 {
01183    struct local_pvt *p = NULL;
01184    struct ao2_iterator it;
01185 
01186    switch (cmd) {
01187    case CLI_INIT:
01188       e->command = "local show channels";
01189       e->usage =
01190          "Usage: local show channels\n"
01191          "       Provides summary information on active local proxy channels.\n";
01192       return NULL;
01193    case CLI_GENERATE:
01194       return NULL;
01195    }
01196 
01197    if (a->argc != 3)
01198       return CLI_SHOWUSAGE;
01199 
01200    if (ao2_container_count(locals) == 0) {
01201       ast_cli(a->fd, "No local channels in use\n");
01202       return RESULT_SUCCESS;
01203    }
01204 
01205    it = ao2_iterator_init(locals, 0);
01206    while ((p = ao2_iterator_next(&it))) {
01207       ao2_lock(p);
01208       ast_cli(a->fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
01209       ao2_unlock(p);
01210       ao2_ref(p, -1);
01211    }
01212    ao2_iterator_destroy(&it);
01213 
01214    return CLI_SUCCESS;
01215 }
01216 
01217 static struct ast_cli_entry cli_local[] = {
01218    AST_CLI_DEFINE(locals_show, "List status of local channels"),
01219 };
01220 
01221 static int manager_optimize_away(struct mansession *s, const struct message *m)
01222 {
01223    const char *channel;
01224    struct local_pvt *p, *tmp = NULL;
01225    struct ast_channel *c;
01226    int found = 0;
01227    struct ao2_iterator it;
01228 
01229    channel = astman_get_header(m, "Channel");
01230 
01231    if (ast_strlen_zero(channel)) {
01232       astman_send_error(s, m, "'Channel' not specified.");
01233       return 0;
01234    }
01235 
01236    c = ast_channel_get_by_name(channel);
01237    if (!c) {
01238       astman_send_error(s, m, "Channel does not exist.");
01239       return 0;
01240    }
01241 
01242    p = c->tech_pvt;
01243    ast_channel_unref(c);
01244    c = NULL;
01245 
01246    it = ao2_iterator_init(locals, 0);
01247    while ((tmp = ao2_iterator_next(&it))) {
01248       if (tmp == p) {
01249          ao2_lock(tmp);
01250          found = 1;
01251          ast_clear_flag(tmp, LOCAL_NO_OPTIMIZATION);
01252          ao2_unlock(tmp);
01253          ao2_ref(tmp, -1);
01254          break;
01255       }
01256       ao2_ref(tmp, -1);
01257    }
01258    ao2_iterator_destroy(&it);
01259 
01260    if (found) {
01261       astman_send_ack(s, m, "Queued channel to be optimized away");
01262    } else {
01263       astman_send_error(s, m, "Unable to find channel");
01264    }
01265 
01266    return 0;
01267 }
01268 
01269 
01270 static int locals_cmp_cb(void *obj, void *arg, int flags)
01271 {
01272    return (obj == arg) ? CMP_MATCH : 0;
01273 }
01274 
01275 /*! \brief Load module into PBX, register channel */
01276 static int load_module(void)
01277 {
01278    if (!(locals = ao2_container_alloc(BUCKET_SIZE, NULL, locals_cmp_cb))) {
01279       return AST_MODULE_LOAD_FAILURE;
01280    }
01281 
01282    /* Make sure we can register our channel type */
01283    if (ast_channel_register(&local_tech)) {
01284       ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
01285       ao2_ref(locals, -1);
01286       return AST_MODULE_LOAD_FAILURE;
01287    }
01288    ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
01289    ast_manager_register_xml("LocalOptimizeAway", EVENT_FLAG_SYSTEM|EVENT_FLAG_CALL, manager_optimize_away);
01290 
01291    return AST_MODULE_LOAD_SUCCESS;
01292 }
01293 
01294 /*! \brief Unload the local proxy channel from Asterisk */
01295 static int unload_module(void)
01296 {
01297    struct local_pvt *p = NULL;
01298    struct ao2_iterator it;
01299 
01300    /* First, take us out of the channel loop */
01301    ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
01302    ast_manager_unregister("LocalOptimizeAway");
01303    ast_channel_unregister(&local_tech);
01304 
01305    it = ao2_iterator_init(locals, 0);
01306    while ((p = ao2_iterator_next(&it))) {
01307       if (p->owner) {
01308          ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
01309       }
01310       ao2_ref(p, -1);
01311    }
01312    ao2_iterator_destroy(&it);
01313    ao2_ref(locals, -1);
01314 
01315    return 0;
01316 }
01317 
01318 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Local Proxy Channel (Note: used internally by other modules)",
01319       .load = load_module,
01320       .unload = unload_module,
01321       .load_pri = AST_MODPRI_CHANNEL_DRIVER,
01322    );

Generated on Mon Mar 19 11:30:24 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7