bridge_roles.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  * Jonathan Rose <jrose@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  * \brief Channel Bridging Roles API
00022  *
00023  * \author Jonathan Rose <jrose@digium.com>
00024  *
00025  * \ingroup bridges
00026  */
00027 
00028 /*** MODULEINFO
00029    <support_level>core</support_level>
00030  ***/
00031 
00032 #include "asterisk.h"
00033 
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 396182 $")
00035 
00036 #include <signal.h>
00037 
00038 #include "asterisk/logger.h"
00039 #include "asterisk/channel.h"
00040 #include "asterisk/datastore.h"
00041 #include "asterisk/linkedlists.h"
00042 #include "asterisk/bridge.h"
00043 #include "asterisk/bridge_roles.h"
00044 #include "asterisk/stringfields.h"
00045 
00046 struct bridge_role_option {
00047    AST_LIST_ENTRY(bridge_role_option) list;
00048    AST_DECLARE_STRING_FIELDS(
00049       AST_STRING_FIELD(option);
00050       AST_STRING_FIELD(value);
00051    );
00052 };
00053 
00054 struct bridge_role {
00055    AST_LIST_ENTRY(bridge_role) list;
00056    AST_LIST_HEAD(, bridge_role_option) options;
00057    char role[AST_ROLE_LEN];
00058 };
00059 
00060 struct bridge_roles_datastore {
00061    AST_LIST_HEAD(, bridge_role) role_list;
00062 };
00063 
00064 /*!
00065  * \internal
00066  * \brief Destructor function for a bridge role
00067  * \since 12.0.0
00068  *
00069  * \param role bridge_role being destroyed
00070  *
00071  * \return Nothing
00072  */
00073 static void bridge_role_destroy(struct bridge_role *role)
00074 {
00075    struct bridge_role_option *role_option;
00076    while ((role_option = AST_LIST_REMOVE_HEAD(&role->options, list))) {
00077       ast_string_field_free_memory(role_option);
00078       ast_free(role_option);
00079    }
00080    ast_free(role);
00081 }
00082 
00083 /*!
00084  * \internal
00085  * \brief Destructor function for bridge role datastores
00086  * \since 12.0.0
00087  *
00088  * \param data Pointer to the datastore being destroyed
00089  *
00090  * \return Nothing
00091  */
00092 static void bridge_role_datastore_destroy(void *data)
00093 {
00094    struct bridge_roles_datastore *roles_datastore = data;
00095    struct bridge_role *role;
00096 
00097    while ((role = AST_LIST_REMOVE_HEAD(&roles_datastore->role_list, list))) {
00098       bridge_role_destroy(role);
00099    }
00100 
00101    ast_free(roles_datastore);
00102 }
00103 
00104 static const struct ast_datastore_info bridge_role_info = {
00105    .type = "bridge roles",
00106    .destroy = bridge_role_datastore_destroy,
00107 };
00108 
00109 /*!
00110  * \internal
00111  * \brief Setup a bridge role datastore on a channel
00112  * \since 12.0.0
00113  *
00114  * \param chan Chan the datastore is being setup on
00115  *
00116  * \retval NULL if failed
00117  * \retval pointer to the newly created datastore
00118  */
00119 static struct bridge_roles_datastore *setup_bridge_roles_datastore(struct ast_channel *chan)
00120 {
00121    struct ast_datastore *datastore = NULL;
00122    struct bridge_roles_datastore *roles_datastore = NULL;
00123 
00124    if (!(datastore = ast_datastore_alloc(&bridge_role_info, NULL))) {
00125       return NULL;
00126    }
00127 
00128    if (!(roles_datastore = ast_calloc(1, sizeof(*roles_datastore)))) {
00129       ast_datastore_free(datastore);
00130       return NULL;
00131    }
00132 
00133    datastore->data = roles_datastore;
00134    ast_channel_datastore_add(chan, datastore);
00135    return roles_datastore;
00136 }
00137 
00138 /*!
00139  * \internal
00140  * \brief Get the bridge_roles_datastore from a channel if it exists. Don't create one if it doesn't.
00141  * \since 12.0.0
00142  *
00143  * \param chan Channel we want the bridge_roles_datastore from
00144  *
00145  * \retval NULL if we can't find the datastore
00146  * \retval pointer to the bridge_roles_datastore
00147  */
00148 static struct bridge_roles_datastore *fetch_bridge_roles_datastore(struct ast_channel *chan)
00149 {
00150    struct ast_datastore *datastore = NULL;
00151 
00152    ast_channel_lock(chan);
00153    if (!(datastore = ast_channel_datastore_find(chan, &bridge_role_info, NULL))) {
00154       ast_channel_unlock(chan);
00155       return NULL;
00156    }
00157    ast_channel_unlock(chan);
00158 
00159    return datastore->data;
00160 }
00161 
00162 /*!
00163  * \internal
00164  * \brief Get the bridge_roles_datastore from a channel if it exists. If not, create one.
00165  * \since 12.0.0
00166  *
00167  * \param chan Channel we want the bridge_roles_datastore from
00168  *
00169  * \retval NULL If we can't find and can't create the datastore
00170  * \retval pointer to the bridge_roles_datastore
00171  */
00172 static struct bridge_roles_datastore *fetch_or_create_bridge_roles_datastore(struct ast_channel *chan)
00173 {
00174    struct bridge_roles_datastore *roles_datastore;
00175 
00176    ast_channel_lock(chan);
00177    roles_datastore = fetch_bridge_roles_datastore(chan);
00178    if (!roles_datastore) {
00179       roles_datastore = setup_bridge_roles_datastore(chan);
00180    }
00181    ast_channel_unlock(chan);
00182 
00183    return roles_datastore;
00184 }
00185 
00186 /*!
00187  * \internal
00188  * \brief Obtain a role from a bridge_roles_datastore if the datastore has it
00189  * \since 12.0.0
00190  *
00191  * \param roles_datastore The bridge_roles_datastore we are looking for the role of
00192  * \param role_name Name of the role being sought
00193  *
00194  * \retval NULL if the datastore does not have the requested role
00195  * \retval pointer to the requested role
00196  */
00197 static struct bridge_role *get_role_from_datastore(struct bridge_roles_datastore *roles_datastore, const char *role_name)
00198 {
00199    struct bridge_role *role;
00200 
00201    AST_LIST_TRAVERSE(&roles_datastore->role_list, role, list) {
00202       if (!strcmp(role->role, role_name)) {
00203          return role;
00204       }
00205    }
00206 
00207    return NULL;
00208 }
00209 
00210 /*!
00211  * \internal
00212  * \brief Obtain a role from a channel structure if the channel's datastore has it
00213  * \since 12.0.0
00214  *
00215  * \param channel The channel we are checking the role of
00216  * \param role_name Name of the role sought
00217  *
00218  * \retval NULL if the channel's datastore does not have the requested role
00219  * \retval pointer to the requested role
00220  */
00221 static struct bridge_role *get_role_from_channel(struct ast_channel *channel, const char *role_name)
00222 {
00223    struct bridge_roles_datastore *roles_datastore = fetch_bridge_roles_datastore(channel);
00224    return roles_datastore ? get_role_from_datastore(roles_datastore, role_name) : NULL;
00225 }
00226 
00227 /*!
00228  * \internal
00229  * \brief Obtain a role option from a bridge role if it exists in the bridge role's option list
00230  * \since 12.0.0
00231  *
00232  * \param role a pointer to the bridge role wea re searching for the option of
00233  * \param option Name of the option sought
00234  *
00235  * \retval NULL if the bridge role doesn't have the requested option
00236  * \retval pointer to the requested option
00237  */
00238 static struct bridge_role_option *get_role_option(struct bridge_role *role, const char *option)
00239 {
00240    struct bridge_role_option *role_option = NULL;
00241    AST_LIST_TRAVERSE(&role->options, role_option, list) {
00242       if (!strcmp(role_option->option, option)) {
00243          return role_option;
00244       }
00245    }
00246    return NULL;
00247 }
00248 
00249 /*!
00250  * \internal
00251  * \brief Setup a bridge role on an existing bridge role datastore
00252  * \since 12.0.0
00253  *
00254  * \param roles_datastore bridge_roles_datastore receiving the new role
00255  * \param role_name Name of the role being received
00256  *
00257  * \retval 0 on success
00258  * \retval -1 on failure
00259  */
00260 static int setup_bridge_role(struct bridge_roles_datastore *roles_datastore, const char *role_name)
00261 {
00262    struct bridge_role *role;
00263    role = ast_calloc(1, sizeof(*role));
00264 
00265    if (!role) {
00266       return -1;
00267    }
00268 
00269    ast_copy_string(role->role, role_name, sizeof(role->role));
00270 
00271    AST_LIST_INSERT_TAIL(&roles_datastore->role_list, role, list);
00272    ast_debug(3, "Set role '%s'\n", role_name);
00273 
00274    return 0;
00275 }
00276 
00277 /*!
00278  * \internal
00279  * \brief Setup a bridge role option on an existing bridge role
00280  * \since 12.0.0
00281  *
00282  * \param role The role receiving the option
00283  * \param option Name of the option
00284  * \param value the option's value
00285  *
00286  * \retval 0 on success
00287  * \retval -1 on failure
00288  */
00289 static int setup_bridge_role_option(struct bridge_role *role, const char *option, const char *value)
00290 {
00291    struct bridge_role_option *role_option;
00292 
00293    if (!value) {
00294       value = "";
00295    }
00296 
00297    role_option = ast_calloc(1, sizeof(*role_option));
00298    if (!role_option) {
00299       return -1;
00300    }
00301 
00302    if (ast_string_field_init(role_option, 32)) {
00303       ast_free(role_option);
00304       return -1;
00305    }
00306 
00307    ast_string_field_set(role_option, option, option);
00308    ast_string_field_set(role_option, value, value);
00309 
00310    AST_LIST_INSERT_TAIL(&role->options, role_option, list);
00311 
00312    return 0;
00313 }
00314 
00315 int ast_channel_add_bridge_role(struct ast_channel *chan, const char *role_name)
00316 {
00317    struct bridge_roles_datastore *roles_datastore = fetch_or_create_bridge_roles_datastore(chan);
00318 
00319    if (!roles_datastore) {
00320       ast_log(LOG_WARNING, "Unable to set up bridge role datastore on channel %s\n", ast_channel_name(chan));
00321       return -1;
00322    }
00323 
00324    /* Check to make sure we aren't adding a redundant role */
00325    if (get_role_from_datastore(roles_datastore, role_name)) {
00326       ast_debug(2, "Bridge role %s is already applied to the channel %s\n", role_name, ast_channel_name(chan));
00327       return 0;
00328    }
00329 
00330    /* It wasn't already there, so we can just finish setting it up now. */
00331    return setup_bridge_role(roles_datastore, role_name);
00332 }
00333 
00334 void ast_channel_remove_bridge_role(struct ast_channel *chan, const char *role_name)
00335 {
00336    struct bridge_roles_datastore *roles_datastore = fetch_bridge_roles_datastore(chan);
00337    struct bridge_role *role;
00338 
00339    if (!roles_datastore) {
00340       /* The roles datastore didn't already exist, so there is no need to remove a role */
00341       ast_debug(2, "Role %s did not exist on channel %s\n", role_name, ast_channel_name(chan));
00342       return;
00343    }
00344 
00345    AST_LIST_TRAVERSE_SAFE_BEGIN(&roles_datastore->role_list, role, list) {
00346       if (!strcmp(role->role, role_name)) {
00347          ast_debug(2, "Removing bridge role %s from channel %s\n", role_name, ast_channel_name(chan));
00348          AST_LIST_REMOVE_CURRENT(list);
00349          bridge_role_destroy(role);
00350          return;
00351       }
00352    }
00353    AST_LIST_TRAVERSE_SAFE_END;
00354 
00355    ast_debug(2, "Role %s did not exist on channel %s\n", role_name, ast_channel_name(chan));
00356 }
00357 
00358 void ast_channel_clear_bridge_roles(struct ast_channel *chan)
00359 {
00360    struct bridge_roles_datastore *roles_datastore = fetch_bridge_roles_datastore(chan);
00361    struct bridge_role *role;
00362 
00363    if (!roles_datastore) {
00364       /* The roles datastore didn't already exist, so there is no need to remove any roles */
00365       ast_debug(2, "Roles did not exist on channel %s\n", ast_channel_name(chan));
00366       return;
00367    }
00368 
00369    AST_LIST_TRAVERSE_SAFE_BEGIN(&roles_datastore->role_list, role, list) {
00370       ast_debug(2, "Removing bridge role %s from channel %s\n", role->role, ast_channel_name(chan));
00371       AST_LIST_REMOVE_CURRENT(list);
00372       bridge_role_destroy(role);
00373    }
00374    AST_LIST_TRAVERSE_SAFE_END;
00375 }
00376 
00377 int ast_channel_set_bridge_role_option(struct ast_channel *channel, const char *role_name, const char *option, const char *value)
00378 {
00379    struct bridge_role *role = get_role_from_channel(channel, role_name);
00380    struct bridge_role_option *role_option;
00381 
00382    if (!role) {
00383       return -1;
00384    }
00385 
00386    role_option = get_role_option(role, option);
00387 
00388    if (role_option) {
00389       ast_string_field_set(role_option, value, value);
00390       return 0;
00391    }
00392 
00393    return setup_bridge_role_option(role, option, value);
00394 }
00395 
00396 int ast_channel_has_role(struct ast_channel *channel, const char *role_name)
00397 {
00398    return get_role_from_channel(channel, role_name) ? 1 : 0;
00399 }
00400 
00401 const char *ast_channel_get_role_option(struct ast_channel *channel, const char *role_name, const char *option)
00402 {
00403    struct bridge_role *role;
00404    struct bridge_role_option *role_option;
00405 
00406    role = get_role_from_channel(channel, role_name);
00407    if (!role) {
00408       return NULL;
00409    }
00410 
00411    role_option = get_role_option(role, option);
00412 
00413    return role_option ? role_option->value : NULL;
00414 }
00415 
00416 int ast_bridge_channel_has_role(struct ast_bridge_channel *bridge_channel, const char *role_name)
00417 {
00418    if (!bridge_channel->bridge_roles) {
00419       return 0;
00420    }
00421 
00422    return get_role_from_datastore(bridge_channel->bridge_roles, role_name) ? 1 : 0;
00423 }
00424 
00425 const char *ast_bridge_channel_get_role_option(struct ast_bridge_channel *bridge_channel, const char *role_name, const char *option)
00426 {
00427    struct bridge_role *role;
00428    struct bridge_role_option *role_option = NULL;
00429 
00430    if (!bridge_channel->bridge_roles) {
00431       return NULL;
00432    }
00433 
00434    role = get_role_from_datastore(bridge_channel->bridge_roles, role_name);
00435 
00436    if (!role) {
00437       return NULL;
00438    }
00439 
00440    role_option = get_role_option(role, option);
00441 
00442    return role_option ? role_option->value : NULL;
00443 }
00444 
00445 int ast_bridge_channel_establish_roles(struct ast_bridge_channel *bridge_channel)
00446 {
00447    struct bridge_roles_datastore *roles_datastore;
00448    struct bridge_role *role = NULL;
00449    struct bridge_role_option *role_option;
00450 
00451    if (!bridge_channel->chan) {
00452       ast_debug(2, "Attempted to set roles on a bridge channel that has no associated channel. That's a bad idea.\n");
00453       return -1;
00454    }
00455 
00456    if (bridge_channel->bridge_roles) {
00457       ast_debug(2, "Attempted to reset roles while roles were already established. Purge existing roles first.\n");
00458       return -1;
00459    }
00460 
00461    roles_datastore = fetch_bridge_roles_datastore(bridge_channel->chan);
00462    if (!roles_datastore) {
00463       /* No roles to establish. */
00464       return 0;
00465    }
00466 
00467    if (!(bridge_channel->bridge_roles = ast_calloc(1, sizeof(*bridge_channel->bridge_roles)))) {
00468       return -1;
00469    }
00470 
00471    AST_LIST_TRAVERSE(&roles_datastore->role_list, role, list) {
00472       struct bridge_role *this_role_copy;
00473 
00474       if (setup_bridge_role(bridge_channel->bridge_roles, role->role)) {
00475          /* We need to abandon the copy because we couldn't setup a role */
00476          ast_bridge_channel_clear_roles(bridge_channel);
00477          return -1;
00478       }
00479       this_role_copy = AST_LIST_LAST(&bridge_channel->bridge_roles->role_list);
00480 
00481       AST_LIST_TRAVERSE(&role->options, role_option, list) {
00482          if (setup_bridge_role_option(this_role_copy, role_option->option, role_option->value)) {
00483             /* We need to abandon the copy because we couldn't setup a role option */
00484             ast_bridge_channel_clear_roles(bridge_channel);
00485             return -1;
00486          }
00487       }
00488    }
00489 
00490    return 0;
00491 }
00492 
00493 void ast_bridge_channel_clear_roles(struct ast_bridge_channel *bridge_channel)
00494 {
00495    if (bridge_channel->bridge_roles) {
00496       bridge_role_datastore_destroy(bridge_channel->bridge_roles);
00497       bridge_channel->bridge_roles = NULL;
00498    }
00499 }

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