core_local.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2013 Digium, Inc.
00005  *
00006  * Richard Mudgett <rmudgett@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 /*!
00020  * \file
00021  * \brief Local proxy channel driver.
00022  *
00023  * \author Richard Mudgett <rmudgett@digium.com>
00024  *
00025  * See Also:
00026  * \arg \ref AstCREDITS
00027  */
00028 
00029 /*** MODULEINFO
00030    <support_level>core</support_level>
00031  ***/
00032 
00033 
00034 #include "asterisk.h"
00035 
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 433501 $")
00037 
00038 /* ------------------------------------------------------------------- */
00039 
00040 #include "asterisk/channel.h"
00041 #include "asterisk/pbx.h"
00042 #include "asterisk/cli.h"
00043 #include "asterisk/manager.h"
00044 #include "asterisk/devicestate.h"
00045 #include "asterisk/astobj2.h"
00046 #include "asterisk/bridge.h"
00047 #include "asterisk/core_unreal.h"
00048 #include "asterisk/core_local.h"
00049 #include "asterisk/stasis.h"
00050 #include "asterisk/stasis_channels.h"
00051 #include "asterisk/_private.h"
00052 #include "asterisk/stasis_channels.h"
00053 
00054 /*** DOCUMENTATION
00055    <manager name="LocalOptimizeAway" language="en_US">
00056       <synopsis>
00057          Optimize away a local channel when possible.
00058       </synopsis>
00059       <syntax>
00060          <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
00061          <parameter name="Channel" required="true">
00062             <para>The channel name to optimize away.</para>
00063          </parameter>
00064       </syntax>
00065       <description>
00066          <para>A local channel created with "/n" will not automatically optimize away.
00067          Calling this command on the local channel will clear that flag and allow
00068          it to optimize away if it's bridged or when it becomes bridged.</para>
00069       </description>
00070    </manager>
00071    <managerEvent language="en_US" name="LocalBridge">
00072       <managerEventInstance class="EVENT_FLAG_CALL">
00073          <synopsis>Raised when two halves of a Local Channel form a bridge.</synopsis>
00074          <syntax>
00075             <channel_snapshot prefix="LocalOne"/>
00076             <channel_snapshot prefix="LocalTwo"/>
00077             <parameter name="Context">
00078                <para>The context in the dialplan that Channel2 starts in.</para>
00079             </parameter>
00080             <parameter name="Exten">
00081                <para>The extension in the dialplan that Channel2 starts in.</para>
00082             </parameter>
00083             <parameter name="LocalOptimization">
00084                <enumlist>
00085                   <enum name="Yes"/>
00086                   <enum name="No"/>
00087                </enumlist>
00088             </parameter>
00089          </syntax>
00090       </managerEventInstance>
00091    </managerEvent>
00092    <managerEvent language="en_US" name="LocalOptimizationBegin">
00093       <managerEventInstance class="EVENT_FLAG_CALL">
00094          <synopsis>Raised when two halves of a Local Channel begin to optimize
00095          themselves out of the media path.</synopsis>
00096          <syntax>
00097             <channel_snapshot prefix="LocalOne"/>
00098             <channel_snapshot prefix="LocalTwo"/>
00099             <channel_snapshot prefix="Source"/>
00100             <parameter name="DestUniqueId">
00101                <para>The unique ID of the bridge into which the local channel is optimizing.</para>
00102             </parameter>
00103             <parameter name="Id">
00104                <para>Identification for the optimization operation.</para>
00105             </parameter>
00106          </syntax>
00107          <see-also>
00108             <ref type="managerEvent">LocalOptimizationEnd</ref>
00109             <ref type="manager">LocalOptimizeAway</ref>
00110          </see-also>
00111       </managerEventInstance>
00112    </managerEvent>
00113    <managerEvent language="en_US" name="LocalOptimizationEnd">
00114       <managerEventInstance class="EVENT_FLAG_CALL">
00115          <synopsis>Raised when two halves of a Local Channel have finished optimizing
00116          themselves out of the media path.</synopsis>
00117          <syntax>
00118             <channel_snapshot prefix="LocalOne"/>
00119             <channel_snapshot prefix="LocalTwo"/>
00120             <parameter name="Success">
00121                <para>Indicates whether the local optimization succeeded.</para>
00122             </parameter>
00123             <parameter name="Id">
00124                <para>Identification for the optimization operation. Matches the <replaceable>Id</replaceable>
00125                from a previous <literal>LocalOptimizationBegin</literal></para>
00126             </parameter>
00127          </syntax>
00128          <see-also>
00129             <ref type="managerEvent">LocalOptimizationBegin</ref>
00130             <ref type="manager">LocalOptimizeAway</ref>
00131          </see-also>
00132       </managerEventInstance>
00133    </managerEvent>
00134  ***/
00135 
00136 static const char tdesc[] = "Local Proxy Channel Driver";
00137 
00138 static struct ao2_container *locals;
00139 
00140 static struct ast_channel *local_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
00141 static int local_call(struct ast_channel *ast, const char *dest, int timeout);
00142 static int local_hangup(struct ast_channel *ast);
00143 static int local_devicestate(const char *data);
00144 static void local_optimization_started_cb(struct ast_unreal_pvt *base, struct ast_channel *source,
00145       enum ast_unreal_channel_indicator dest, unsigned int id);
00146 static void local_optimization_finished_cb(struct ast_unreal_pvt *base, int success, unsigned int id);
00147 
00148 static struct ast_manager_event_blob *local_message_to_ami(struct stasis_message *msg);
00149 
00150 /*!
00151  * @{ \brief Define local channel message types.
00152  */
00153 STASIS_MESSAGE_TYPE_DEFN(ast_local_bridge_type,
00154    .to_ami = local_message_to_ami,
00155    );
00156 STASIS_MESSAGE_TYPE_DEFN(ast_local_optimization_begin_type,
00157    .to_ami = local_message_to_ami,
00158    );
00159 STASIS_MESSAGE_TYPE_DEFN(ast_local_optimization_end_type,
00160    .to_ami = local_message_to_ami,
00161    );
00162 /*! @} */
00163 
00164 /*! \brief Callbacks from the unreal core when channel optimization occurs */
00165 struct ast_unreal_pvt_callbacks local_unreal_callbacks = {
00166    .optimization_started = local_optimization_started_cb,
00167    .optimization_finished = local_optimization_finished_cb,
00168 };
00169 
00170 /* PBX interface structure for channel registration */
00171 static struct ast_channel_tech local_tech = {
00172    .type = "Local",
00173    .description = tdesc,
00174    .requester = local_request,
00175    .send_digit_begin = ast_unreal_digit_begin,
00176    .send_digit_end = ast_unreal_digit_end,
00177    .call = local_call,
00178    .hangup = local_hangup,
00179    .answer = ast_unreal_answer,
00180    .read = ast_unreal_read,
00181    .write = ast_unreal_write,
00182    .write_video = ast_unreal_write,
00183    .exception = ast_unreal_read,
00184    .indicate = ast_unreal_indicate,
00185    .fixup = ast_unreal_fixup,
00186    .send_html = ast_unreal_sendhtml,
00187    .send_text = ast_unreal_sendtext,
00188    .devicestate = local_devicestate,
00189    .queryoption = ast_unreal_queryoption,
00190    .setoption = ast_unreal_setoption,
00191 };
00192 
00193 /*! What to do with the ;2 channel when ast_call() happens. */
00194 enum local_call_action {
00195    /* The ast_call() will run dialplan on the ;2 channel. */
00196    LOCAL_CALL_ACTION_DIALPLAN,
00197    /* The ast_call() will impart the ;2 channel into a bridge. */
00198    LOCAL_CALL_ACTION_BRIDGE,
00199    /* The ast_call() will masquerade the ;2 channel into a channel. */
00200    LOCAL_CALL_ACTION_MASQUERADE,
00201 };
00202 
00203 /*! Join a bridge on ast_call() parameters. */
00204 struct local_bridge {
00205    /*! Bridge to join. */
00206    struct ast_bridge *join;
00207    /*! Channel to swap with when joining bridge. */
00208    struct ast_channel *swap;
00209    /*! Features that are specific to this channel when pushed into the bridge. */
00210    struct ast_bridge_features *features;
00211 };
00212 
00213 /*!
00214  * \brief the local pvt structure for all channels
00215  *
00216  * The local channel pvt has two ast_chan objects - the "owner" and the "next channel", the outbound channel
00217  *
00218  * ast_chan owner -> local_pvt -> ast_chan chan
00219  */
00220 struct local_pvt {
00221    /*! Unreal channel driver base class values. */
00222    struct ast_unreal_pvt base;
00223    /*! Additional action arguments */
00224    union {
00225       /*! Make ;2 join a bridge on ast_call(). */
00226       struct local_bridge bridge;
00227       /*! Make ;2 masquerade into this channel on ast_call(). */
00228       struct ast_channel *masq;
00229    } action;
00230    /*! What to do with the ;2 channel on ast_call(). */
00231    enum local_call_action type;
00232    /*! Context to call */
00233    char context[AST_MAX_CONTEXT];
00234    /*! Extension to call */
00235    char exten[AST_MAX_EXTENSION];
00236 };
00237 
00238 struct ast_channel *ast_local_get_peer(struct ast_channel *ast)
00239 {
00240    struct local_pvt *p = ast_channel_tech_pvt(ast);
00241    struct local_pvt *found;
00242    struct ast_channel *peer;
00243 
00244    if (!p) {
00245       return NULL;
00246    }
00247 
00248    found = p ? ao2_find(locals, p, 0) : NULL;
00249    if (!found) {
00250       /* ast is either not a local channel or it has alredy been hungup */
00251       return NULL;
00252    }
00253    ao2_lock(found);
00254    if (ast == p->base.owner) {
00255       peer = p->base.chan;
00256    } else if (ast == p->base.chan) {
00257       peer = p->base.owner;
00258    } else {
00259       peer = NULL;
00260    }
00261    if (peer) {
00262       ast_channel_ref(peer);
00263    }
00264    ao2_unlock(found);
00265    ao2_ref(found, -1);
00266    return peer;
00267 }
00268 
00269 /*! \brief Adds devicestate to local channels */
00270 static int local_devicestate(const char *data)
00271 {
00272    int is_inuse = 0;
00273    int res = AST_DEVICE_INVALID;
00274    char *exten = ast_strdupa(data);
00275    char *context;
00276    char *opts;
00277    struct local_pvt *lp;
00278    struct ao2_iterator it;
00279 
00280    /* Strip options if they exist */
00281    opts = strchr(exten, '/');
00282    if (opts) {
00283       *opts = '\0';
00284    }
00285 
00286    context = strchr(exten, '@');
00287    if (!context) {
00288       ast_log(LOG_WARNING,
00289          "Someone used Local/%s somewhere without a @context. This is bad.\n", data);
00290       return AST_DEVICE_INVALID;
00291    }
00292    *context++ = '\0';
00293 
00294    it = ao2_iterator_init(locals, 0);
00295    for (; (lp = ao2_iterator_next(&it)); ao2_ref(lp, -1)) {
00296       ao2_lock(lp);
00297       if (!strcmp(exten, lp->exten)
00298          && !strcmp(context, lp->context)) {
00299          res = AST_DEVICE_NOT_INUSE;
00300          if (lp->base.owner
00301             && ast_test_flag(&lp->base, AST_UNREAL_CARETAKER_THREAD)) {
00302             is_inuse = 1;
00303          }
00304       }
00305       ao2_unlock(lp);
00306       if (is_inuse) {
00307          res = AST_DEVICE_INUSE;
00308          ao2_ref(lp, -1);
00309          break;
00310       }
00311    }
00312    ao2_iterator_destroy(&it);
00313 
00314    if (res == AST_DEVICE_INVALID) {
00315       ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
00316       if (ast_exists_extension(NULL, context, exten, 1, NULL)) {
00317          res = AST_DEVICE_NOT_INUSE;
00318       }
00319    }
00320 
00321    return res;
00322 }
00323 
00324 static struct ast_multi_channel_blob *local_channel_optimization_blob(struct local_pvt *p,
00325       struct ast_json *json_object)
00326 {
00327    struct ast_multi_channel_blob *payload;
00328    RAII_VAR(struct ast_channel_snapshot *, local_one_snapshot, NULL, ao2_cleanup);
00329    RAII_VAR(struct ast_channel_snapshot *, local_two_snapshot, NULL, ao2_cleanup);
00330 
00331    local_one_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(p->base.owner));
00332    if (!local_one_snapshot) {
00333       return NULL;
00334    }
00335 
00336    local_two_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(p->base.chan));
00337    if (!local_two_snapshot) {
00338       return NULL;
00339    }
00340 
00341    payload = ast_multi_channel_blob_create(json_object);
00342    if (!payload) {
00343       return NULL;
00344    }
00345    ast_multi_channel_blob_add_channel(payload, "1", local_one_snapshot);
00346    ast_multi_channel_blob_add_channel(payload, "2", local_two_snapshot);
00347 
00348    return payload;
00349 }
00350 
00351 /*! \brief Callback for \ref ast_unreal_pvt_callbacks \ref optimization_started_cb */
00352 static void local_optimization_started_cb(struct ast_unreal_pvt *base, struct ast_channel *source,
00353       enum ast_unreal_channel_indicator dest, unsigned int id)
00354 {
00355    RAII_VAR(struct ast_json *, json_object, ast_json_null(), ast_json_unref);
00356    RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
00357    RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
00358    struct local_pvt *p = (struct local_pvt *)base;
00359 
00360    if (!ast_local_optimization_begin_type()) {
00361       return;
00362    }
00363 
00364    json_object = ast_json_pack("{s: i, s: i}",
00365          "dest", dest, "id", id);
00366 
00367    if (!json_object) {
00368       return;
00369    }
00370 
00371    payload = local_channel_optimization_blob(p, json_object);
00372    if (!payload) {
00373       return;
00374    }
00375 
00376    if (source) {
00377       RAII_VAR(struct ast_channel_snapshot *, source_snapshot, NULL, ao2_cleanup);
00378       source_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(source));
00379       if (!source_snapshot) {
00380          return;
00381       }
00382 
00383       ast_multi_channel_blob_add_channel(payload, "source", source_snapshot);
00384    }
00385 
00386    msg = stasis_message_create(ast_local_optimization_begin_type(), payload);
00387    if (!msg) {
00388       return;
00389    }
00390 
00391    stasis_publish(ast_channel_topic(p->base.owner), msg);
00392 }
00393 
00394 /*! \brief Callback for \ref ast_unreal_pvt_callbacks \ref optimization_finished_cb */
00395 static void local_optimization_finished_cb(struct ast_unreal_pvt *base, int success, unsigned int id)
00396 {
00397    RAII_VAR(struct ast_json *, json_object, ast_json_null(), ast_json_unref);
00398    RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
00399    RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
00400    struct local_pvt *p = (struct local_pvt *)base;
00401 
00402    if (!ast_local_optimization_end_type()) {
00403       return;
00404    }
00405 
00406    json_object = ast_json_pack("{s: i, s: i}", "success", success, "id", id);
00407 
00408    if (!json_object) {
00409       return;
00410    }
00411 
00412    payload = local_channel_optimization_blob(p, json_object);
00413    if (!payload) {
00414       return;
00415    }
00416 
00417    msg = stasis_message_create(ast_local_optimization_end_type(), payload);
00418    if (!msg) {
00419       return;
00420    }
00421 
00422    stasis_publish(ast_channel_topic(p->base.owner), msg);
00423 }
00424 
00425 static struct ast_manager_event_blob *local_message_to_ami(struct stasis_message *message)
00426 {
00427    struct ast_multi_channel_blob *obj = stasis_message_data(message);
00428    struct ast_json *blob = ast_multi_channel_blob_get_json(obj);
00429    struct ast_channel_snapshot *local_snapshot_one;
00430    struct ast_channel_snapshot *local_snapshot_two;
00431    RAII_VAR(struct ast_str *, local_channel_one, NULL, ast_free);
00432    RAII_VAR(struct ast_str *, local_channel_two, NULL, ast_free);
00433    RAII_VAR(struct ast_str *, event_buffer, NULL, ast_free);
00434    const char *event;
00435 
00436    local_snapshot_one = ast_multi_channel_blob_get_channel(obj, "1");
00437    local_snapshot_two = ast_multi_channel_blob_get_channel(obj, "2");
00438    if (!local_snapshot_one || !local_snapshot_two) {
00439       return NULL;
00440    }
00441 
00442    event_buffer = ast_str_create(1024);
00443    local_channel_one = ast_manager_build_channel_state_string_prefix(local_snapshot_one, "LocalOne");
00444    local_channel_two = ast_manager_build_channel_state_string_prefix(local_snapshot_two, "LocalTwo");
00445    if (!event_buffer || !local_channel_one || !local_channel_two) {
00446       return NULL;
00447    }
00448 
00449    if (stasis_message_type(message) == ast_local_optimization_begin_type()) {
00450       struct ast_channel_snapshot *source_snapshot;
00451       RAII_VAR(struct ast_str *, source_str, NULL, ast_free);
00452       const char *dest_uniqueid;
00453 
00454       source_snapshot = ast_multi_channel_blob_get_channel(obj, "source");
00455       if (source_snapshot) {
00456          source_str = ast_manager_build_channel_state_string_prefix(source_snapshot, "Source");
00457          if (!source_str) {
00458             return NULL;
00459          }
00460       }
00461 
00462       dest_uniqueid = ast_json_object_get(blob, "dest") == AST_UNREAL_OWNER ?
00463             local_snapshot_one->uniqueid : local_snapshot_two->uniqueid;
00464 
00465       event = "LocalOptimizationBegin";
00466       if (source_str) {
00467          ast_str_append(&event_buffer, 0, "%s", ast_str_buffer(source_str));
00468       }
00469       ast_str_append(&event_buffer, 0, "DestUniqueId: %s\r\n", dest_uniqueid);
00470       ast_str_append(&event_buffer, 0, "Id: %u\r\n", (unsigned int) ast_json_integer_get(ast_json_object_get(blob, "id")));
00471    } else if (stasis_message_type(message) == ast_local_optimization_end_type()) {
00472       event = "LocalOptimizationEnd";
00473       ast_str_append(&event_buffer, 0, "Success: %s\r\n", ast_json_integer_get(ast_json_object_get(blob, "success")) ? "Yes" : "No");
00474       ast_str_append(&event_buffer, 0, "Id: %u\r\n", (unsigned int) ast_json_integer_get(ast_json_object_get(blob, "id")));
00475    } else if (stasis_message_type(message) == ast_local_bridge_type()) {
00476       event = "LocalBridge";
00477       ast_str_append(&event_buffer, 0, "Context: %s\r\n", ast_json_string_get(ast_json_object_get(blob, "context")));
00478       ast_str_append(&event_buffer, 0, "Exten: %s\r\n", ast_json_string_get(ast_json_object_get(blob, "exten")));
00479       ast_str_append(&event_buffer, 0, "LocalOptimization: %s\r\n", ast_json_is_true(ast_json_object_get(blob, "can_optimize")) ? "Yes" : "No");
00480    } else {
00481       return NULL;
00482    }
00483 
00484    return ast_manager_event_blob_create(EVENT_FLAG_CALL, event,
00485       "%s"
00486       "%s"
00487       "%s",
00488       ast_str_buffer(local_channel_one),
00489       ast_str_buffer(local_channel_two),
00490       ast_str_buffer(event_buffer));
00491 }
00492 
00493 /*!
00494  * \internal
00495  * \brief Post the \ref ast_local_bridge_type \ref stasis message
00496  * \since 12.0.0
00497  *
00498  * \param p local_pvt to raise the local bridge message
00499  *
00500  * \return Nothing
00501  */
00502 static void publish_local_bridge_message(struct local_pvt *p)
00503 {
00504    RAII_VAR(struct ast_multi_channel_blob *, multi_blob, NULL, ao2_cleanup);
00505    RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
00506    RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
00507    RAII_VAR(struct ast_channel_snapshot *, one_snapshot, NULL, ao2_cleanup);
00508    RAII_VAR(struct ast_channel_snapshot *, two_snapshot, NULL, ao2_cleanup);
00509    struct ast_channel *owner;
00510    struct ast_channel *chan;
00511 
00512    if (!ast_local_bridge_type()) {
00513       return;
00514    }
00515 
00516    ast_unreal_lock_all(&p->base, &chan, &owner);
00517 
00518    blob = ast_json_pack("{s: s, s: s, s: b}",
00519       "context", p->context,
00520       "exten", p->exten,
00521       "can_optimize", !ast_test_flag(&p->base, AST_UNREAL_NO_OPTIMIZATION));
00522    if (!blob) {
00523       goto end;
00524    }
00525 
00526    multi_blob = ast_multi_channel_blob_create(blob);
00527    if (!multi_blob) {
00528       goto end;
00529    }
00530 
00531    one_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(owner));
00532    if (!one_snapshot) {
00533       goto end;
00534    }
00535 
00536    two_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan));
00537    if (!two_snapshot) {
00538       goto end;
00539    }
00540 
00541    ast_multi_channel_blob_add_channel(multi_blob, "1", one_snapshot);
00542    ast_multi_channel_blob_add_channel(multi_blob, "2", two_snapshot);
00543 
00544    msg = stasis_message_create(ast_local_bridge_type(), multi_blob);
00545    if (!msg) {
00546       goto end;
00547    }
00548 
00549    stasis_publish(ast_channel_topic(owner), msg);
00550 
00551 end:
00552    ast_channel_unlock(owner);
00553    ast_channel_unref(owner);
00554 
00555    ast_channel_unlock(chan);
00556    ast_channel_unref(chan);
00557 
00558    ao2_unlock(&p->base);
00559 }
00560 
00561 int ast_local_setup_bridge(struct ast_channel *ast, struct ast_bridge *bridge, struct ast_channel *swap, struct ast_bridge_features *features)
00562 {
00563    struct local_pvt *p;
00564    struct local_pvt *found;
00565    int res = -1;
00566 
00567    /* Sanity checks. */
00568    if (!ast || !bridge) {
00569       ast_bridge_features_destroy(features);
00570       return -1;
00571    }
00572 
00573    ast_channel_lock(ast);
00574    p = ast_channel_tech_pvt(ast);
00575    ast_channel_unlock(ast);
00576 
00577    found = p ? ao2_find(locals, p, 0) : NULL;
00578    if (found) {
00579       ao2_lock(found);
00580       if (found->type == LOCAL_CALL_ACTION_DIALPLAN
00581          && found->base.owner
00582          && found->base.chan
00583          && !ast_test_flag(&found->base, AST_UNREAL_CARETAKER_THREAD)) {
00584          ao2_ref(bridge, +1);
00585          if (swap) {
00586             ast_channel_ref(swap);
00587          }
00588          found->type = LOCAL_CALL_ACTION_BRIDGE;
00589          found->action.bridge.join = bridge;
00590          found->action.bridge.swap = swap;
00591          found->action.bridge.features = features;
00592          res = 0;
00593       } else {
00594          ast_bridge_features_destroy(features);
00595       }
00596       ao2_unlock(found);
00597       ao2_ref(found, -1);
00598    }
00599 
00600    return res;
00601 }
00602 
00603 int ast_local_setup_masquerade(struct ast_channel *ast, struct ast_channel *masq)
00604 {
00605    struct local_pvt *p;
00606    struct local_pvt *found;
00607    int res = -1;
00608 
00609    /* Sanity checks. */
00610    if (!ast || !masq) {
00611       return -1;
00612    }
00613 
00614    ast_channel_lock(ast);
00615    p = ast_channel_tech_pvt(ast);
00616    ast_channel_unlock(ast);
00617 
00618    found = p ? ao2_find(locals, p, 0) : NULL;
00619    if (found) {
00620       ao2_lock(found);
00621       if (found->type == LOCAL_CALL_ACTION_DIALPLAN
00622          && found->base.owner
00623          && found->base.chan
00624          && !ast_test_flag(&found->base, AST_UNREAL_CARETAKER_THREAD)) {
00625          ast_channel_ref(masq);
00626          found->type = LOCAL_CALL_ACTION_MASQUERADE;
00627          found->action.masq = masq;
00628          res = 0;
00629       }
00630       ao2_unlock(found);
00631       ao2_ref(found, -1);
00632    }
00633 
00634    return res;
00635 }
00636 
00637 /*! \brief Initiate new call, part of PBX interface
00638  *         dest is the dial string */
00639 static int local_call(struct ast_channel *ast, const char *dest, int timeout)
00640 {
00641    struct local_pvt *p = ast_channel_tech_pvt(ast);
00642    int pvt_locked = 0;
00643 
00644    struct ast_channel *owner = NULL;
00645    struct ast_channel *chan = NULL;
00646    int res;
00647    char *reduced_dest = ast_strdupa(dest);
00648    char *slash;
00649    const char *chan_cid;
00650 
00651    if (!p) {
00652       return -1;
00653    }
00654 
00655    /* since we are letting go of channel locks that were locked coming into
00656     * this function, then we need to give the tech pvt a ref */
00657    ao2_ref(p, 1);
00658    ast_channel_unlock(ast);
00659 
00660    ast_unreal_lock_all(&p->base, &chan, &owner);
00661    pvt_locked = 1;
00662 
00663    if (owner != ast) {
00664       res = -1;
00665       goto return_cleanup;
00666    }
00667 
00668    if (!owner || !chan) {
00669       res = -1;
00670       goto return_cleanup;
00671    }
00672 
00673    ast_unreal_call_setup(owner, chan);
00674 
00675    /*
00676     * If the local channel has /n on the end of it, we need to lop
00677     * that off for our argument to setting up the CC_INTERFACES
00678     * variable.
00679     */
00680    if ((slash = strrchr(reduced_dest, '/'))) {
00681       *slash = '\0';
00682    }
00683    ast_set_cc_interfaces_chanvar(chan, reduced_dest);
00684 
00685    ao2_unlock(p);
00686    pvt_locked = 0;
00687 
00688    ast_channel_unlock(owner);
00689 
00690    chan_cid = S_COR(ast_channel_caller(chan)->id.number.valid,
00691       ast_channel_caller(chan)->id.number.str, NULL);
00692    if (chan_cid) {
00693       chan_cid = ast_strdupa(chan_cid);
00694    }
00695    ast_channel_unlock(chan);
00696 
00697    res = -1;
00698    switch (p->type) {
00699    case LOCAL_CALL_ACTION_DIALPLAN:
00700       if (!ast_exists_extension(NULL, p->context, p->exten, 1, chan_cid)) {
00701          ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n",
00702             p->exten, p->context);
00703       } else {
00704          publish_local_bridge_message(p);
00705 
00706          /* Start switch on sub channel */
00707          res = ast_pbx_start(chan);
00708       }
00709       break;
00710    case LOCAL_CALL_ACTION_BRIDGE:
00711       publish_local_bridge_message(p);
00712       ast_answer(chan);
00713       res = ast_bridge_impart(p->action.bridge.join, chan, p->action.bridge.swap,
00714          p->action.bridge.features, AST_BRIDGE_IMPART_CHAN_INDEPENDENT);
00715       ao2_ref(p->action.bridge.join, -1);
00716       p->action.bridge.join = NULL;
00717       ao2_cleanup(p->action.bridge.swap);
00718       p->action.bridge.swap = NULL;
00719       p->action.bridge.features = NULL;
00720       break;
00721    case LOCAL_CALL_ACTION_MASQUERADE:
00722       publish_local_bridge_message(p);
00723       ast_answer(chan);
00724       res = ast_channel_move(p->action.masq, chan);
00725       if (!res) {
00726          /* Chan is now an orphaned zombie.  Destroy it. */
00727          ast_hangup(chan);
00728       }
00729       p->action.masq = ast_channel_unref(p->action.masq);
00730       break;
00731    }
00732    if (!res) {
00733       ao2_lock(p);
00734       ast_set_flag(&p->base, AST_UNREAL_CARETAKER_THREAD);
00735       ao2_unlock(p);
00736    }
00737 
00738    /* we already unlocked them, clear them here so the cleanup label won't touch them. */
00739    owner = ast_channel_unref(owner);
00740    chan = ast_channel_unref(chan);
00741 
00742 return_cleanup:
00743    if (p) {
00744       if (pvt_locked) {
00745          ao2_unlock(p);
00746       }
00747       ao2_ref(p, -1);
00748    }
00749    if (chan) {
00750       ast_channel_unlock(chan);
00751       ast_channel_unref(chan);
00752    }
00753 
00754    /*
00755     * owner is supposed to be == to ast, if it is, don't unlock it
00756     * because ast must exit locked
00757     */
00758    if (owner) {
00759       if (owner != ast) {
00760          ast_channel_unlock(owner);
00761          ast_channel_lock(ast);
00762       }
00763       ast_channel_unref(owner);
00764    } else {
00765       /* we have to exit with ast locked */
00766       ast_channel_lock(ast);
00767    }
00768 
00769    return res;
00770 }
00771 
00772 /*! \brief Hangup a call through the local proxy channel */
00773 static int local_hangup(struct ast_channel *ast)
00774 {
00775    struct local_pvt *p = ast_channel_tech_pvt(ast);
00776    int res;
00777 
00778    if (!p) {
00779       return -1;
00780    }
00781 
00782    /* give the pvt a ref to fulfill calling requirements. */
00783    ao2_ref(p, +1);
00784    res = ast_unreal_hangup(&p->base, ast);
00785    if (!res) {
00786       int unlink;
00787 
00788       ao2_lock(p);
00789       unlink = !p->base.owner && !p->base.chan;
00790       ao2_unlock(p);
00791       if (unlink) {
00792          ao2_unlink(locals, p);
00793       }
00794    }
00795    ao2_ref(p, -1);
00796 
00797    return res;
00798 }
00799 
00800 /*!
00801  * \internal
00802  * \brief struct local_pvt destructor.
00803  *
00804  * \param vdoomed Object to destroy.
00805  *
00806  * \return Nothing
00807  */
00808 static void local_pvt_destructor(void *vdoomed)
00809 {
00810    struct local_pvt *doomed = vdoomed;
00811 
00812    switch (doomed->type) {
00813    case LOCAL_CALL_ACTION_DIALPLAN:
00814       break;
00815    case LOCAL_CALL_ACTION_BRIDGE:
00816       ao2_cleanup(doomed->action.bridge.join);
00817       ao2_cleanup(doomed->action.bridge.swap);
00818       ast_bridge_features_destroy(doomed->action.bridge.features);
00819       break;
00820    case LOCAL_CALL_ACTION_MASQUERADE:
00821       ao2_cleanup(doomed->action.masq);
00822       break;
00823    }
00824    ast_unreal_destructor(&doomed->base);
00825 }
00826 
00827 /*! \brief Create a call structure */
00828 static struct local_pvt *local_alloc(const char *data, struct ast_format_cap *cap)
00829 {
00830    struct local_pvt *pvt;
00831    char *parse;
00832    char *context;
00833    char *opts;
00834 
00835    pvt = (struct local_pvt *) ast_unreal_alloc(sizeof(*pvt), local_pvt_destructor, cap);
00836    if (!pvt) {
00837       return NULL;
00838    }
00839    pvt->base.callbacks = &local_unreal_callbacks;
00840 
00841    parse = ast_strdupa(data);
00842 
00843    /*
00844     * Local channels intercept MOH by default.
00845     *
00846     * This is a silly default because it represents state held by
00847     * the local channels.  Unless local channel optimization is
00848     * disabled, the state will dissapear when the local channels
00849     * optimize out.
00850     */
00851    ast_set_flag(&pvt->base, AST_UNREAL_MOH_INTERCEPT);
00852 
00853    /* Look for options */
00854    if ((opts = strchr(parse, '/'))) {
00855       *opts++ = '\0';
00856       if (strchr(opts, 'n')) {
00857          ast_set_flag(&pvt->base, AST_UNREAL_NO_OPTIMIZATION);
00858       }
00859       if (strchr(opts, 'j')) {
00860          if (ast_test_flag(&pvt->base, AST_UNREAL_NO_OPTIMIZATION)) {
00861             ast_set_flag(&pvt->base.jb_conf, AST_JB_ENABLED);
00862          } else {
00863             ast_log(LOG_ERROR, "You must use the 'n' option with the 'j' option to enable the jitter buffer\n");
00864          }
00865       }
00866       if (strchr(opts, 'm')) {
00867          ast_clear_flag(&pvt->base, AST_UNREAL_MOH_INTERCEPT);
00868       }
00869    }
00870 
00871    /* Look for a context */
00872    if ((context = strchr(parse, '@'))) {
00873       *context++ = '\0';
00874    }
00875 
00876    ast_copy_string(pvt->context, S_OR(context, "default"), sizeof(pvt->context));
00877    ast_copy_string(pvt->exten, parse, sizeof(pvt->exten));
00878    snprintf(pvt->base.name, sizeof(pvt->base.name), "%s@%s", pvt->exten, pvt->context);
00879 
00880    return pvt; /* this is returned with a ref */
00881 }
00882 
00883 /*! \brief Part of PBX interface */
00884 static struct ast_channel *local_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
00885 {
00886    struct local_pvt *p;
00887    struct ast_channel *chan;
00888    ast_callid callid;
00889 
00890    /* Allocate a new private structure and then Asterisk channels */
00891    p = local_alloc(data, cap);
00892    if (!p) {
00893       return NULL;
00894    }
00895    callid = ast_read_threadstorage_callid();
00896    chan = ast_unreal_new_channels(&p->base, &local_tech, AST_STATE_DOWN, AST_STATE_RING,
00897       p->exten, p->context, assignedids, requestor, callid);
00898    if (chan) {
00899       ao2_link(locals, p);
00900    }
00901    ao2_ref(p, -1); /* kill the ref from the alloc */
00902 
00903    return chan;
00904 }
00905 
00906 /*! \brief CLI command "local show channels" */
00907 static char *locals_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00908 {
00909    struct local_pvt *p;
00910    struct ao2_iterator it;
00911 
00912    switch (cmd) {
00913    case CLI_INIT:
00914       e->command = "local show channels";
00915       e->usage =
00916          "Usage: local show channels\n"
00917          "       Provides summary information on active local proxy channels.\n";
00918       return NULL;
00919    case CLI_GENERATE:
00920       return NULL;
00921    }
00922 
00923    if (a->argc != 3) {
00924       return CLI_SHOWUSAGE;
00925    }
00926 
00927    if (ao2_container_count(locals) == 0) {
00928       ast_cli(a->fd, "No local channels in use\n");
00929       return RESULT_SUCCESS;
00930    }
00931 
00932    it = ao2_iterator_init(locals, 0);
00933    while ((p = ao2_iterator_next(&it))) {
00934       ao2_lock(p);
00935       ast_cli(a->fd, "%s -- %s\n",
00936          p->base.owner ? ast_channel_name(p->base.owner) : "<unowned>",
00937          p->base.name);
00938       ao2_unlock(p);
00939       ao2_ref(p, -1);
00940    }
00941    ao2_iterator_destroy(&it);
00942 
00943    return CLI_SUCCESS;
00944 }
00945 
00946 static struct ast_cli_entry cli_local[] = {
00947    AST_CLI_DEFINE(locals_show, "List status of local channels"),
00948 };
00949 
00950 static int manager_optimize_away(struct mansession *s, const struct message *m)
00951 {
00952    const char *channel;
00953    struct local_pvt *p;
00954    struct local_pvt *found;
00955    struct ast_channel *chan;
00956 
00957    channel = astman_get_header(m, "Channel");
00958    if (ast_strlen_zero(channel)) {
00959       astman_send_error(s, m, "'Channel' not specified.");
00960       return 0;
00961    }
00962 
00963    chan = ast_channel_get_by_name(channel);
00964    if (!chan) {
00965       astman_send_error(s, m, "Channel does not exist.");
00966       return 0;
00967    }
00968 
00969    p = ast_channel_tech_pvt(chan);
00970    ast_channel_unref(chan);
00971 
00972    found = p ? ao2_find(locals, p, 0) : NULL;
00973    if (found) {
00974       ao2_lock(found);
00975       ast_clear_flag(&found->base, AST_UNREAL_NO_OPTIMIZATION);
00976       ao2_unlock(found);
00977       ao2_ref(found, -1);
00978       astman_send_ack(s, m, "Queued channel to be optimized away");
00979    } else {
00980       astman_send_error(s, m, "Unable to find channel");
00981    }
00982 
00983    return 0;
00984 }
00985 
00986 
00987 static int locals_cmp_cb(void *obj, void *arg, int flags)
00988 {
00989    return (obj == arg) ? CMP_MATCH : 0;
00990 }
00991 
00992 /*!
00993  * \internal
00994  * \brief Shutdown the local proxy channel.
00995  * \since 12.0.0
00996  *
00997  * \return Nothing
00998  */
00999 static void local_shutdown(void)
01000 {
01001    /* First, take us out of the channel loop */
01002    ast_cli_unregister_multiple(cli_local, ARRAY_LEN(cli_local));
01003    ast_manager_unregister("LocalOptimizeAway");
01004    ast_channel_unregister(&local_tech);
01005 
01006    ao2_ref(locals, -1);
01007    locals = NULL;
01008 
01009    ao2_cleanup(local_tech.capabilities);
01010    local_tech.capabilities = NULL;
01011 
01012    STASIS_MESSAGE_TYPE_CLEANUP(ast_local_optimization_begin_type);
01013    STASIS_MESSAGE_TYPE_CLEANUP(ast_local_optimization_end_type);
01014    STASIS_MESSAGE_TYPE_CLEANUP(ast_local_bridge_type);
01015 }
01016 
01017 int ast_local_init(void)
01018 {
01019 
01020    if (STASIS_MESSAGE_TYPE_INIT(ast_local_optimization_begin_type)) {
01021       return -1;
01022    }
01023 
01024    if (STASIS_MESSAGE_TYPE_INIT(ast_local_optimization_end_type)) {
01025       return -1;
01026    }
01027 
01028    if (STASIS_MESSAGE_TYPE_INIT(ast_local_bridge_type)) {
01029       return -1;
01030    }
01031 
01032    if (!(local_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
01033       return -1;
01034    }
01035    ast_format_cap_append_by_type(local_tech.capabilities, AST_MEDIA_TYPE_UNKNOWN);
01036 
01037    locals = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, locals_cmp_cb);
01038    if (!locals) {
01039       ao2_cleanup(local_tech.capabilities);
01040       local_tech.capabilities = NULL;
01041       return -1;
01042    }
01043 
01044    /* Make sure we can register our channel type */
01045    if (ast_channel_register(&local_tech)) {
01046       ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
01047       ao2_ref(locals, -1);
01048       ao2_cleanup(local_tech.capabilities);
01049       local_tech.capabilities = NULL;
01050       return -1;
01051    }
01052    ast_cli_register_multiple(cli_local, ARRAY_LEN(cli_local));
01053    ast_manager_register_xml_core("LocalOptimizeAway", EVENT_FLAG_SYSTEM|EVENT_FLAG_CALL, manager_optimize_away);
01054 
01055    ast_register_cleanup(local_shutdown);
01056    return 0;
01057 }

Generated on Thu Apr 16 06:27:32 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6