bridge_after.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2007 - 2009, 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 After Bridge Execution API
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 #include "asterisk.h"
00034 
00035 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 431469 $")
00036 
00037 #include "asterisk/logger.h"
00038 #include "asterisk/channel.h"
00039 #include "asterisk/pbx.h"
00040 #include "asterisk/bridge_after.h"
00041 
00042 struct after_bridge_cb_node {
00043    /*! Next list node. */
00044    AST_LIST_ENTRY(after_bridge_cb_node) list;
00045    /*! Desired callback function. */
00046    ast_bridge_after_cb callback;
00047    /*! After bridge callback will not be called and destroy any resources data may contain. */
00048    ast_bridge_after_cb_failed failed;
00049    /*! Extra data to pass to the callback. */
00050    void *data;
00051    /*! Reason the after bridge callback failed. */
00052    enum ast_bridge_after_cb_reason reason;
00053 };
00054 
00055 struct after_bridge_cb_ds {
00056    /*! After bridge callbacks container. */
00057    AST_LIST_HEAD(, after_bridge_cb_node) callbacks;
00058 };
00059 
00060 /*!
00061  * \internal
00062  * \brief Indicate after bridge callback failed.
00063  * \since 12.0.0
00064  *
00065  * \param node After bridge callback node.
00066  *
00067  * \return Nothing
00068  */
00069 static void after_bridge_cb_failed(struct after_bridge_cb_node *node)
00070 {
00071    if (node->failed) {
00072       node->failed(node->reason, node->data);
00073       node->failed = NULL;
00074    }
00075 }
00076 
00077 /*!
00078  * \internal
00079  * \brief Run discarding any after bridge callbacks.
00080  * \since 12.0.0
00081  *
00082  * \param after_bridge After bridge callback container process.
00083  * \param reason Why are we doing this.
00084  *
00085  * \return Nothing
00086  */
00087 static void after_bridge_cb_run_discard(struct after_bridge_cb_ds *after_bridge, enum ast_bridge_after_cb_reason reason)
00088 {
00089    struct after_bridge_cb_node *node;
00090 
00091    for (;;) {
00092       AST_LIST_LOCK(&after_bridge->callbacks);
00093       node = AST_LIST_REMOVE_HEAD(&after_bridge->callbacks, list);
00094       AST_LIST_UNLOCK(&after_bridge->callbacks);
00095       if (!node) {
00096          break;
00097       }
00098       if (!node->reason) {
00099          node->reason = reason;
00100       }
00101       after_bridge_cb_failed(node);
00102       ast_free(node);
00103    }
00104 }
00105 
00106 /*!
00107  * \internal
00108  * \brief Destroy the after bridge callback datastore.
00109  * \since 12.0.0
00110  *
00111  * \param data After bridge callback data to destroy.
00112  *
00113  * \return Nothing
00114  */
00115 static void after_bridge_cb_destroy(void *data)
00116 {
00117    struct after_bridge_cb_ds *after_bridge = data;
00118 
00119    after_bridge_cb_run_discard(after_bridge, AST_BRIDGE_AFTER_CB_REASON_DESTROY);
00120 
00121    AST_LIST_HEAD_DESTROY(&after_bridge->callbacks);
00122    ast_free(after_bridge);
00123 }
00124 
00125 static struct after_bridge_cb_ds *after_bridge_cb_find(struct ast_channel *chan);
00126 
00127 /*!
00128  * \internal
00129  * \brief Fixup the after bridge callback datastore.
00130  * \since 12.0.0
00131  *
00132  * \param data After bridge callback data to fixup.
00133  * \param old_chan The datastore is moving from this channel.
00134  * \param new_chan The datastore is moving to this channel.
00135  *
00136  * \return Nothing
00137  */
00138 static void after_bridge_cb_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
00139 {
00140    struct after_bridge_cb_ds *after_bridge;
00141    struct after_bridge_cb_node *node;
00142 
00143    after_bridge = after_bridge_cb_find(new_chan);
00144    if (!after_bridge) {
00145       return;
00146    }
00147 
00148    AST_LIST_LOCK(&after_bridge->callbacks);
00149    node = AST_LIST_LAST(&after_bridge->callbacks);
00150    if (node && !node->reason) {
00151       node->reason = AST_BRIDGE_AFTER_CB_REASON_MASQUERADE;
00152    }
00153    AST_LIST_UNLOCK(&after_bridge->callbacks);
00154 }
00155 
00156 static const struct ast_datastore_info after_bridge_cb_info = {
00157    .type = "after-bridge-cb",
00158    .destroy = after_bridge_cb_destroy,
00159    .chan_fixup = after_bridge_cb_fixup,
00160 };
00161 
00162 /*!
00163  * \internal
00164  * \brief Find an after bridge callback datastore container.
00165  * \since 12.0.0
00166  *
00167  * \param chan Channel to find the after bridge callback container on.
00168  *
00169  * \retval after_bridge datastore container on success.
00170  * \retval NULL on error.
00171  */
00172 static struct after_bridge_cb_ds *after_bridge_cb_find(struct ast_channel *chan)
00173 {
00174    struct ast_datastore *datastore;
00175    SCOPED_CHANNELLOCK(lock, chan);
00176 
00177    datastore = ast_channel_datastore_find(chan, &after_bridge_cb_info, NULL);
00178    if (!datastore) {
00179       return NULL;
00180    }
00181    return datastore->data;
00182 }
00183 
00184 /*!
00185  * \internal
00186  * \brief Setup/create an after bridge callback datastore container.
00187  * \since 12.0.0
00188  *
00189  * \param chan Channel to setup/create the after bridge callback container on.
00190  *
00191  * \retval after_bridge datastore container on success.
00192  * \retval NULL on error.
00193  */
00194 static struct after_bridge_cb_ds *after_bridge_cb_setup(struct ast_channel *chan)
00195 {
00196    struct ast_datastore *datastore;
00197    struct after_bridge_cb_ds *after_bridge;
00198    SCOPED_CHANNELLOCK(lock, chan);
00199 
00200    datastore = ast_channel_datastore_find(chan, &after_bridge_cb_info, NULL);
00201    if (datastore) {
00202       return datastore->data;
00203    }
00204 
00205    /* Create a new datastore. */
00206    datastore = ast_datastore_alloc(&after_bridge_cb_info, NULL);
00207    if (!datastore) {
00208       return NULL;
00209    }
00210    after_bridge = ast_calloc(1, sizeof(*after_bridge));
00211    if (!after_bridge) {
00212       ast_datastore_free(datastore);
00213       return NULL;
00214    }
00215    AST_LIST_HEAD_INIT(&after_bridge->callbacks);
00216    datastore->data = after_bridge;
00217    ast_channel_datastore_add(chan, datastore);
00218 
00219    return datastore->data;
00220 }
00221 
00222 void ast_bridge_run_after_callback(struct ast_channel *chan)
00223 {
00224    struct after_bridge_cb_ds *after_bridge;
00225    struct after_bridge_cb_node *node;
00226 
00227    after_bridge = after_bridge_cb_find(chan);
00228    if (!after_bridge) {
00229       return;
00230    }
00231 
00232    for (;;) {
00233       AST_LIST_LOCK(&after_bridge->callbacks);
00234       node = AST_LIST_REMOVE_HEAD(&after_bridge->callbacks, list);
00235       AST_LIST_UNLOCK(&after_bridge->callbacks);
00236       if (!node) {
00237          break;
00238       }
00239       if (node->reason) {
00240          after_bridge_cb_failed(node);
00241       } else {
00242          node->failed = NULL;
00243          node->callback(chan, node->data);
00244       }
00245       ast_free(node);
00246    }
00247 }
00248 
00249 void ast_bridge_discard_after_callback(struct ast_channel *chan, enum ast_bridge_after_cb_reason reason)
00250 {
00251    struct after_bridge_cb_ds *after_bridge;
00252 
00253    after_bridge = after_bridge_cb_find(chan);
00254    if (!after_bridge) {
00255       return;
00256    }
00257 
00258    after_bridge_cb_run_discard(after_bridge, reason);
00259 }
00260 
00261 int ast_bridge_set_after_callback(struct ast_channel *chan, ast_bridge_after_cb callback, ast_bridge_after_cb_failed failed, void *data)
00262 {
00263    struct after_bridge_cb_ds *after_bridge;
00264    struct after_bridge_cb_node *new_node;
00265    struct after_bridge_cb_node *last_node;
00266 
00267    /* Sanity checks. */
00268    ast_assert(chan != NULL);
00269    if (!chan || !callback) {
00270       return -1;
00271    }
00272 
00273    after_bridge = after_bridge_cb_setup(chan);
00274    if (!after_bridge) {
00275       return -1;
00276    }
00277 
00278    /* Create a new callback node. */
00279    new_node = ast_calloc(1, sizeof(*new_node));
00280    if (!new_node) {
00281       return -1;
00282    }
00283    new_node->callback = callback;
00284    new_node->failed = failed;
00285    new_node->data = data;
00286 
00287    /* Put it in the container disabling any previously active one. */
00288    AST_LIST_LOCK(&after_bridge->callbacks);
00289    last_node = AST_LIST_LAST(&after_bridge->callbacks);
00290    if (last_node && !last_node->reason) {
00291       last_node->reason = AST_BRIDGE_AFTER_CB_REASON_REPLACED;
00292    }
00293    AST_LIST_INSERT_TAIL(&after_bridge->callbacks, new_node, list);
00294    AST_LIST_UNLOCK(&after_bridge->callbacks);
00295    return 0;
00296 }
00297 
00298 const char *reason_strings[] = {
00299    [AST_BRIDGE_AFTER_CB_REASON_DESTROY] = "Channel destroyed (hungup)",
00300    [AST_BRIDGE_AFTER_CB_REASON_REPLACED] = "Callback was replaced",
00301    [AST_BRIDGE_AFTER_CB_REASON_MASQUERADE] = "Channel masqueraded",
00302    [AST_BRIDGE_AFTER_CB_REASON_DEPART] = "Channel was departed from bridge",
00303    [AST_BRIDGE_AFTER_CB_REASON_REMOVED] = "Callback was removed",
00304 };
00305 
00306 const char *ast_bridge_after_cb_reason_string(enum ast_bridge_after_cb_reason reason)
00307 {
00308    if (reason < AST_BRIDGE_AFTER_CB_REASON_DESTROY
00309       || AST_BRIDGE_AFTER_CB_REASON_REMOVED < reason
00310       || !reason_strings[reason]) {
00311       return "Unknown";
00312    }
00313 
00314    return reason_strings[reason];
00315 }
00316 
00317 struct after_bridge_goto_ds {
00318    /*! Goto string that can be parsed by ast_parseable_goto(). */
00319    const char *parseable_goto;
00320    /*! Specific goto context or default context for parseable_goto. */
00321    const char *context;
00322    /*! Specific goto exten or default exten for parseable_goto. */
00323    const char *exten;
00324    /*! Specific goto priority or default priority for parseable_goto. */
00325    int priority;
00326    /*! TRUE if the peer should run the h exten. */
00327    unsigned int run_h_exten:1;
00328    /*! Specific goto location */
00329    unsigned int specific:1;
00330 };
00331 
00332 /*!
00333  * \internal
00334  * \brief Destroy the after bridge goto datastore.
00335  * \since 12.0.0
00336  *
00337  * \param data After bridge goto data to destroy.
00338  *
00339  * \return Nothing
00340  */
00341 static void after_bridge_goto_destroy(void *data)
00342 {
00343    struct after_bridge_goto_ds *after_bridge = data;
00344 
00345    ast_free((char *) after_bridge->parseable_goto);
00346    ast_free((char *) after_bridge->context);
00347    ast_free((char *) after_bridge->exten);
00348    ast_free((char *) after_bridge);
00349 }
00350 
00351 /*!
00352  * \internal
00353  * \brief Fixup the after bridge goto datastore.
00354  * \since 12.0.0
00355  *
00356  * \param data After bridge goto data to fixup.
00357  * \param old_chan The datastore is moving from this channel.
00358  * \param new_chan The datastore is moving to this channel.
00359  *
00360  * \return Nothing
00361  */
00362 static void after_bridge_goto_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
00363 {
00364    /* There can be only one.  Discard any already on the new channel. */
00365    ast_bridge_discard_after_goto(new_chan);
00366 }
00367 
00368 static const struct ast_datastore_info after_bridge_goto_info = {
00369    .type = "after-bridge-goto",
00370    .destroy = after_bridge_goto_destroy,
00371    .chan_fixup = after_bridge_goto_fixup,
00372 };
00373 
00374 /*!
00375  * \internal
00376  * \brief Remove channel goto location after the bridge and return it.
00377  * \since 12.0.0
00378  *
00379  * \param chan Channel to remove after bridge goto location.
00380  *
00381  * \retval datastore on success.
00382  * \retval NULL on error or not found.
00383  */
00384 static struct ast_datastore *after_bridge_goto_remove(struct ast_channel *chan)
00385 {
00386    struct ast_datastore *datastore;
00387 
00388    ast_channel_lock(chan);
00389    datastore = ast_channel_datastore_find(chan, &after_bridge_goto_info, NULL);
00390    if (datastore && ast_channel_datastore_remove(chan, datastore)) {
00391       datastore = NULL;
00392    }
00393    ast_channel_unlock(chan);
00394 
00395    return datastore;
00396 }
00397 
00398 void ast_bridge_discard_after_goto(struct ast_channel *chan)
00399 {
00400    struct ast_datastore *datastore;
00401 
00402    datastore = after_bridge_goto_remove(chan);
00403    if (datastore) {
00404       ast_datastore_free(datastore);
00405    }
00406 }
00407 
00408 void ast_bridge_read_after_goto(struct ast_channel *chan, char *buffer, size_t buf_size)
00409 {
00410    struct ast_datastore *datastore;
00411    struct after_bridge_goto_ds *after_bridge;
00412    char *current_pos = buffer;
00413    size_t remaining_size = buf_size;
00414 
00415    SCOPED_CHANNELLOCK(lock, chan);
00416 
00417    datastore = ast_channel_datastore_find(chan, &after_bridge_goto_info, NULL);
00418    if (!datastore) {
00419       buffer[0] = '\0';
00420       return;
00421    }
00422 
00423    after_bridge = datastore->data;
00424 
00425    if (after_bridge->parseable_goto) {
00426       snprintf(buffer, buf_size, "%s", after_bridge->parseable_goto);
00427       return;
00428    }
00429 
00430    if (!ast_strlen_zero(after_bridge->context)) {
00431       snprintf(current_pos, remaining_size, "%s,", after_bridge->context);
00432       remaining_size = remaining_size - strlen(current_pos);
00433       current_pos += strlen(current_pos);
00434    }
00435 
00436    if (after_bridge->run_h_exten) {
00437       snprintf(current_pos, remaining_size, "h,");
00438       remaining_size = remaining_size - strlen(current_pos);
00439       current_pos += strlen(current_pos);
00440    } else if (!ast_strlen_zero(after_bridge->exten)) {
00441       snprintf(current_pos, remaining_size, "%s,", after_bridge->exten);
00442       remaining_size = remaining_size - strlen(current_pos);
00443       current_pos += strlen(current_pos);
00444    }
00445 
00446    snprintf(current_pos, remaining_size, "%d", after_bridge->priority);
00447 }
00448 
00449 int ast_bridge_setup_after_goto(struct ast_channel *chan)
00450 {
00451    struct ast_datastore *datastore;
00452    struct after_bridge_goto_ds *after_bridge;
00453    int goto_failed = -1;
00454 
00455    /* We are going to be leaving the bridging system now;
00456     * clear any pending unbridge flags
00457     */
00458    ast_channel_set_unbridged(chan, 0);
00459 
00460    /* Determine if we are going to setup a dialplan location and where. */
00461    if (ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO) {
00462       /* An async goto has already setup a location. */
00463       ast_channel_clear_softhangup(chan, AST_SOFTHANGUP_ASYNCGOTO);
00464       if (!ast_check_hangup(chan)) {
00465          goto_failed = 0;
00466       }
00467       return goto_failed;
00468    }
00469 
00470    /* Get after bridge goto datastore. */
00471    datastore = after_bridge_goto_remove(chan);
00472    if (!datastore) {
00473       return goto_failed;
00474    }
00475 
00476    after_bridge = datastore->data;
00477    if (after_bridge->run_h_exten) {
00478       if (ast_exists_extension(chan, after_bridge->context, "h", 1,
00479          S_COR(ast_channel_caller(chan)->id.number.valid,
00480             ast_channel_caller(chan)->id.number.str, NULL))) {
00481          ast_debug(1, "Running after bridge goto h exten %s,h,1\n",
00482             ast_channel_context(chan));
00483          ast_pbx_h_exten_run(chan, after_bridge->context);
00484       }
00485    } else if (!ast_check_hangup(chan)) {
00486       /* Clear the outgoing flag */
00487       ast_clear_flag(ast_channel_flags(chan), AST_FLAG_OUTGOING);
00488 
00489       if (after_bridge->specific) {
00490          goto_failed = ast_explicit_goto(chan, after_bridge->context,
00491             after_bridge->exten, after_bridge->priority);
00492       } else if (!ast_strlen_zero(after_bridge->parseable_goto)) {
00493          char *context;
00494          char *exten;
00495          int priority;
00496 
00497          /* Option F(x) for Bridge(), Dial(), and Queue() */
00498 
00499          /* Save current dialplan location in case of failure. */
00500          context = ast_strdupa(ast_channel_context(chan));
00501          exten = ast_strdupa(ast_channel_exten(chan));
00502          priority = ast_channel_priority(chan);
00503 
00504          /* Set current dialplan position to default dialplan position */
00505          ast_explicit_goto(chan, after_bridge->context, after_bridge->exten,
00506             after_bridge->priority);
00507 
00508          /* Then perform the goto */
00509          goto_failed = ast_parseable_goto(chan, after_bridge->parseable_goto);
00510          if (goto_failed) {
00511             /* Restore original dialplan location. */
00512             ast_channel_context_set(chan, context);
00513             ast_channel_exten_set(chan, exten);
00514             ast_channel_priority_set(chan, priority);
00515          }
00516       } else {
00517          /* Option F() for Bridge(), Dial(), and Queue() */
00518          goto_failed = ast_goto_if_exists(chan, after_bridge->context,
00519             after_bridge->exten, after_bridge->priority + 1);
00520       }
00521       if (!goto_failed) {
00522          if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP)) {
00523             ast_channel_priority_set(chan, ast_channel_priority(chan) + 1);
00524          }
00525 
00526          ast_debug(1, "Setup after bridge goto location to %s,%s,%d.\n",
00527             ast_channel_context(chan),
00528             ast_channel_exten(chan),
00529             ast_channel_priority(chan));
00530       }
00531    }
00532 
00533    /* Discard after bridge goto datastore. */
00534    ast_datastore_free(datastore);
00535 
00536    return goto_failed;
00537 }
00538 
00539 void ast_bridge_run_after_goto(struct ast_channel *chan)
00540 {
00541    int goto_failed;
00542 
00543    goto_failed = ast_bridge_setup_after_goto(chan);
00544    if (goto_failed || ast_pbx_run(chan)) {
00545       ast_hangup(chan);
00546    }
00547 }
00548 
00549 /*!
00550  * \internal
00551  * \brief Set after bridge goto location of channel.
00552  * \since 12.0.0
00553  *
00554  * \param chan Channel to setup after bridge goto location.
00555  * \param run_h_exten TRUE if the h exten should be run.
00556  * \param specific TRUE if the context/exten/priority is exactly specified.
00557  * \param context Context to goto after bridge.
00558  * \param exten Exten to goto after bridge. (Could be NULL if run_h_exten)
00559  * \param priority Priority to goto after bridge.
00560  * \param parseable_goto User specified goto string. (Could be NULL)
00561  *
00562  * \details Add a channel datastore to setup the goto location
00563  * when the channel leaves the bridge and run a PBX from there.
00564  *
00565  * If run_h_exten then execute the h exten found in the given context.
00566  * Else if specific then goto the given context/exten/priority.
00567  * Else if parseable_goto then use the given context/exten/priority
00568  *   as the relative position for the parseable_goto.
00569  * Else goto the given context/exten/priority+1.
00570  *
00571  * \return Nothing
00572  */
00573 static void __after_bridge_set_goto(struct ast_channel *chan, int run_h_exten, int specific, const char *context, const char *exten, int priority, const char *parseable_goto)
00574 {
00575    struct ast_datastore *datastore;
00576    struct after_bridge_goto_ds *after_bridge;
00577 
00578    /* Sanity checks. */
00579    ast_assert(chan != NULL);
00580    if (!chan) {
00581       return;
00582    }
00583    if (run_h_exten) {
00584       ast_assert(run_h_exten && context);
00585       if (!context) {
00586          return;
00587       }
00588    } else {
00589       ast_assert(context && exten && 0 < priority);
00590       if (!context || !exten || priority < 1) {
00591          return;
00592       }
00593    }
00594 
00595    /* Create a new datastore. */
00596    datastore = ast_datastore_alloc(&after_bridge_goto_info, NULL);
00597    if (!datastore) {
00598       return;
00599    }
00600    after_bridge = ast_calloc(1, sizeof(*after_bridge));
00601    if (!after_bridge) {
00602       ast_datastore_free(datastore);
00603       return;
00604    }
00605 
00606    /* Initialize it. */
00607    after_bridge->parseable_goto = ast_strdup(parseable_goto);
00608    after_bridge->context = ast_strdup(context);
00609    after_bridge->exten = ast_strdup(exten);
00610    after_bridge->priority = priority;
00611    after_bridge->run_h_exten = run_h_exten ? 1 : 0;
00612    after_bridge->specific = specific ? 1 : 0;
00613    datastore->data = after_bridge;
00614    if ((parseable_goto && !after_bridge->parseable_goto)
00615       || (context && !after_bridge->context)
00616       || (exten && !after_bridge->exten)) {
00617       ast_datastore_free(datastore);
00618       return;
00619    }
00620 
00621    /* Put it on the channel replacing any existing one. */
00622    ast_channel_lock(chan);
00623    ast_bridge_discard_after_goto(chan);
00624    ast_channel_datastore_add(chan, datastore);
00625    ast_channel_unlock(chan);
00626 }
00627 
00628 void ast_bridge_set_after_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
00629 {
00630    __after_bridge_set_goto(chan, 0, 1, context, exten, priority, NULL);
00631 }
00632 
00633 void ast_bridge_set_after_h(struct ast_channel *chan, const char *context)
00634 {
00635    __after_bridge_set_goto(chan, 1, 0, context, NULL, 1, NULL);
00636 }
00637 
00638 void ast_bridge_set_after_go_on(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *parseable_goto)
00639 {
00640    char *p_goto;
00641 
00642    if (!ast_strlen_zero(parseable_goto)) {
00643       p_goto = ast_strdupa(parseable_goto);
00644       ast_replace_subargument_delimiter(p_goto);
00645    } else {
00646       p_goto = NULL;
00647    }
00648    __after_bridge_set_goto(chan, 0, 0, context, exten, priority, p_goto);
00649 }

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