Asterisk - The Open Source Telephony Project GIT-master-7e7a603
bridge_roles.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2013, Digium, Inc.
5 *
6 * Jonathan Rose <jrose@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*! \file
20 *
21 * \brief Channel Bridging Roles API
22 *
23 * \author Jonathan Rose <jrose@digium.com>
24 *
25 * \ingroup bridges
26 */
27
28/*** MODULEINFO
29 <support_level>core</support_level>
30 ***/
31
32#include "asterisk.h"
33
34#include <signal.h>
35
36#include "asterisk/logger.h"
37#include "asterisk/channel.h"
38#include "asterisk/datastore.h"
40#include "asterisk/bridge.h"
43
49 );
50};
51
56};
57
60};
61
62/*!
63 * \internal
64 * \brief Destructor function for a bridge role
65 * \since 12.0.0
66 *
67 * \param role bridge_role being destroyed
68 */
69static void bridge_role_destroy(struct bridge_role *role)
70{
71 struct bridge_role_option *role_option;
72 while ((role_option = AST_LIST_REMOVE_HEAD(&role->options, list))) {
74 ast_free(role_option);
75 }
76 ast_free(role);
77}
78
79/*!
80 * \internal
81 * \brief Destructor function for bridge role datastores
82 * \since 12.0.0
83 *
84 * \param data Pointer to the datastore being destroyed
85 */
86static void bridge_role_datastore_destroy(void *data)
87{
88 struct bridge_roles_datastore *roles_datastore = data;
89 struct bridge_role *role;
90
91 while ((role = AST_LIST_REMOVE_HEAD(&roles_datastore->role_list, list))) {
93 }
94
95 ast_free(roles_datastore);
96}
97
98static const struct ast_datastore_info bridge_role_info = {
99 .type = "bridge roles",
101};
102
103/*!
104 * \internal
105 * \brief Setup a bridge role datastore on a channel
106 * \since 12.0.0
107 *
108 * \param chan Chan the datastore is being setup on
109 *
110 * \retval NULL if failed
111 * \return pointer to the newly created datastore
112 */
114{
115 struct ast_datastore *datastore = NULL;
116 struct bridge_roles_datastore *roles_datastore = NULL;
117
118 if (!(datastore = ast_datastore_alloc(&bridge_role_info, NULL))) {
119 return NULL;
120 }
121
122 if (!(roles_datastore = ast_calloc(1, sizeof(*roles_datastore)))) {
123 ast_datastore_free(datastore);
124 return NULL;
125 }
126
127 AST_LIST_HEAD_INIT_NOLOCK(&roles_datastore->role_list);
128
129 datastore->data = roles_datastore;
130 ast_channel_datastore_add(chan, datastore);
131 return roles_datastore;
132}
133
134/*!
135 * \internal
136 * \brief Get the bridge_roles_datastore from a channel if it exists. Don't create one if it doesn't.
137 * \since 12.0.0
138 *
139 * \param chan Channel we want the bridge_roles_datastore from
140 *
141 * \retval NULL if we can't find the datastore
142 * \return pointer to the bridge_roles_datastore
143 */
145{
146 struct ast_datastore *datastore = NULL;
147
148 ast_channel_lock(chan);
149 if (!(datastore = ast_channel_datastore_find(chan, &bridge_role_info, NULL))) {
150 ast_channel_unlock(chan);
151 return NULL;
152 }
153 ast_channel_unlock(chan);
154
155 return datastore->data;
156}
157
158/*!
159 * \internal
160 * \brief Get the bridge_roles_datastore from a channel if it exists. If not, create one.
161 * \since 12.0.0
162 *
163 * \param chan Channel we want the bridge_roles_datastore from
164 *
165 * \retval NULL If we can't find and can't create the datastore
166 * \return pointer to the bridge_roles_datastore
167 */
169{
170 struct bridge_roles_datastore *roles_datastore;
171
172 ast_channel_lock(chan);
173 roles_datastore = fetch_bridge_roles_datastore(chan);
174 if (!roles_datastore) {
175 roles_datastore = setup_bridge_roles_datastore(chan);
176 }
177 ast_channel_unlock(chan);
178
179 return roles_datastore;
180}
181
182/*!
183 * \internal
184 * \brief Obtain a role from a bridge_roles_datastore if the datastore has it
185 * \since 12.0.0
186 *
187 * \param roles_datastore The bridge_roles_datastore we are looking for the role of
188 * \param role_name Name of the role being sought
189 *
190 * \retval NULL if the datastore does not have the requested role
191 * \return pointer to the requested role
192 */
193static struct bridge_role *get_role_from_datastore(struct bridge_roles_datastore *roles_datastore, const char *role_name)
194{
195 struct bridge_role *role;
196
197 AST_LIST_TRAVERSE(&roles_datastore->role_list, role, list) {
198 if (!strcmp(role->role, role_name)) {
199 return role;
200 }
201 }
202
203 return NULL;
204}
205
206/*!
207 * \internal
208 * \brief Obtain a role from a channel structure if the channel's datastore has it
209 * \since 12.0.0
210 *
211 * \param channel The channel we are checking the role of
212 * \param role_name Name of the role sought
213 *
214 * \retval NULL if the channel's datastore does not have the requested role
215 * \return pointer to the requested role
216 */
217static struct bridge_role *get_role_from_channel(struct ast_channel *channel, const char *role_name)
218{
219 struct bridge_roles_datastore *roles_datastore = fetch_bridge_roles_datastore(channel);
220 return roles_datastore ? get_role_from_datastore(roles_datastore, role_name) : NULL;
221}
222
223/*!
224 * \internal
225 * \brief Obtain a role option from a bridge role if it exists in the bridge role's option list
226 * \since 12.0.0
227 *
228 * \param role a pointer to the bridge role wea re searching for the option of
229 * \param option Name of the option sought
230 *
231 * \retval NULL if the bridge role doesn't have the requested option
232 * \return pointer to the requested option
233 */
234static struct bridge_role_option *get_role_option(struct bridge_role *role, const char *option)
235{
236 struct bridge_role_option *role_option = NULL;
237 AST_LIST_TRAVERSE(&role->options, role_option, list) {
238 if (!strcmp(role_option->option, option)) {
239 return role_option;
240 }
241 }
242 return NULL;
243}
244
245/*!
246 * \internal
247 * \brief Setup a bridge role on an existing bridge role datastore
248 * \since 12.0.0
249 *
250 * \param roles_datastore bridge_roles_datastore receiving the new role
251 * \param role_name Name of the role being received
252 *
253 * \retval 0 on success
254 * \retval -1 on failure
255 */
256static int setup_bridge_role(struct bridge_roles_datastore *roles_datastore, const char *role_name)
257{
258 struct bridge_role *role;
259 role = ast_calloc(1, sizeof(*role));
260
261 if (!role) {
262 return -1;
263 }
264
266
267 ast_copy_string(role->role, role_name, sizeof(role->role));
268
269 AST_LIST_INSERT_TAIL(&roles_datastore->role_list, role, list);
270 ast_debug(3, "Set role '%s'\n", role_name);
271
272 return 0;
273}
274
275/*!
276 * \internal
277 * \brief Setup a bridge role option on an existing bridge role
278 * \since 12.0.0
279 *
280 * \param role The role receiving the option
281 * \param option Name of the option
282 * \param value the option's value
283 *
284 * \retval 0 on success
285 * \retval -1 on failure
286 */
287static int setup_bridge_role_option(struct bridge_role *role, const char *option, const char *value)
288{
289 struct bridge_role_option *role_option;
290
291 if (!value) {
292 value = "";
293 }
294
295 role_option = ast_calloc(1, sizeof(*role_option));
296 if (!role_option) {
297 return -1;
298 }
299
300 if (ast_string_field_init(role_option, 32)) {
301 ast_free(role_option);
302 return -1;
303 }
304
305 ast_string_field_set(role_option, option, option);
306 ast_string_field_set(role_option, value, value);
307
308 AST_LIST_INSERT_TAIL(&role->options, role_option, list);
309
310 return 0;
311}
312
313int ast_channel_add_bridge_role(struct ast_channel *chan, const char *role_name)
314{
316
317 if (!roles_datastore) {
318 ast_log(LOG_WARNING, "Unable to set up bridge role datastore on channel %s\n", ast_channel_name(chan));
319 return -1;
320 }
321
322 /* Check to make sure we aren't adding a redundant role */
323 if (get_role_from_datastore(roles_datastore, role_name)) {
324 ast_debug(2, "Bridge role %s is already applied to the channel %s\n", role_name, ast_channel_name(chan));
325 return 0;
326 }
327
328 /* It wasn't already there, so we can just finish setting it up now. */
329 return setup_bridge_role(roles_datastore, role_name);
330}
331
332void ast_channel_remove_bridge_role(struct ast_channel *chan, const char *role_name)
333{
334 struct bridge_roles_datastore *roles_datastore = fetch_bridge_roles_datastore(chan);
335 struct bridge_role *role;
336
337 if (!roles_datastore) {
338 /* The roles datastore didn't already exist, so there is no need to remove a role */
339 ast_debug(2, "Role %s did not exist on channel %s\n", role_name, ast_channel_name(chan));
340 return;
341 }
342
343 AST_LIST_TRAVERSE_SAFE_BEGIN(&roles_datastore->role_list, role, list) {
344 if (!strcmp(role->role, role_name)) {
345 ast_debug(2, "Removing bridge role %s from channel %s\n", role_name, ast_channel_name(chan));
348 return;
349 }
350 }
352
353 ast_debug(2, "Role %s did not exist on channel %s\n", role_name, ast_channel_name(chan));
354}
355
357{
358 struct bridge_roles_datastore *roles_datastore = fetch_bridge_roles_datastore(chan);
359 struct bridge_role *role;
360
361 if (!roles_datastore) {
362 /* The roles datastore didn't already exist, so there is no need to remove any roles */
363 ast_debug(2, "Roles did not exist on channel %s\n", ast_channel_name(chan));
364 return;
365 }
366
367 AST_LIST_TRAVERSE_SAFE_BEGIN(&roles_datastore->role_list, role, list) {
368 ast_debug(2, "Removing bridge role %s from channel %s\n", role->role, ast_channel_name(chan));
371 }
373}
374
375int ast_channel_set_bridge_role_option(struct ast_channel *channel, const char *role_name, const char *option, const char *value)
376{
377 struct bridge_role *role = get_role_from_channel(channel, role_name);
378 struct bridge_role_option *role_option;
379
380 if (!role) {
381 return -1;
382 }
383
384 role_option = get_role_option(role, option);
385
386 if (role_option) {
387 ast_string_field_set(role_option, value, value);
388 return 0;
389 }
390
392}
393
394int ast_channel_has_role(struct ast_channel *channel, const char *role_name)
395{
396 return get_role_from_channel(channel, role_name) ? 1 : 0;
397}
398
399const char *ast_channel_get_role_option(struct ast_channel *channel, const char *role_name, const char *option)
400{
401 struct bridge_role *role;
402 struct bridge_role_option *role_option;
403
404 role = get_role_from_channel(channel, role_name);
405 if (!role) {
406 return NULL;
407 }
408
409 role_option = get_role_option(role, option);
410
411 return role_option ? role_option->value : NULL;
412}
413
414int ast_bridge_channel_has_role(struct ast_bridge_channel *bridge_channel, const char *role_name)
415{
416 if (!bridge_channel->bridge_roles) {
417 return 0;
418 }
419
420 return get_role_from_datastore(bridge_channel->bridge_roles, role_name) ? 1 : 0;
421}
422
423const char *ast_bridge_channel_get_role_option(struct ast_bridge_channel *bridge_channel, const char *role_name, const char *option)
424{
425 struct bridge_role *role;
426 struct bridge_role_option *role_option = NULL;
427
428 if (!bridge_channel->bridge_roles) {
429 return NULL;
430 }
431
432 role = get_role_from_datastore(bridge_channel->bridge_roles, role_name);
433
434 if (!role) {
435 return NULL;
436 }
437
438 role_option = get_role_option(role, option);
439
440 return role_option ? role_option->value : NULL;
441}
442
444{
445 struct bridge_roles_datastore *roles_datastore;
446 struct bridge_role *role = NULL;
447 struct bridge_role_option *role_option;
448
449 if (!bridge_channel->chan) {
450 ast_debug(2, "Attempted to set roles on a bridge channel that has no associated channel. That's a bad idea.\n");
451 return -1;
452 }
453
454 if (bridge_channel->bridge_roles) {
455 ast_debug(2, "Attempted to reset roles while roles were already established. Purge existing roles first.\n");
456 return -1;
457 }
458
459 roles_datastore = fetch_bridge_roles_datastore(bridge_channel->chan);
460 if (!roles_datastore) {
461 /* No roles to establish. */
462 return 0;
463 }
464
465 if (!(bridge_channel->bridge_roles = ast_calloc(1, sizeof(*bridge_channel->bridge_roles)))) {
466 return -1;
467 }
468
469 AST_LIST_TRAVERSE(&roles_datastore->role_list, role, list) {
470 struct bridge_role *this_role_copy;
471
472 if (setup_bridge_role(bridge_channel->bridge_roles, role->role)) {
473 /* We need to abandon the copy because we couldn't setup a role */
474 ast_bridge_channel_clear_roles(bridge_channel);
475 return -1;
476 }
477 this_role_copy = AST_LIST_LAST(&bridge_channel->bridge_roles->role_list);
478
479 AST_LIST_TRAVERSE(&role->options, role_option, list) {
480 if (setup_bridge_role_option(this_role_copy, role_option->option, role_option->value)) {
481 /* We need to abandon the copy because we couldn't setup a role option */
482 ast_bridge_channel_clear_roles(bridge_channel);
483 return -1;
484 }
485 }
486 }
487
488 return 0;
489}
490
492{
493 if (bridge_channel->bridge_roles) {
495 bridge_channel->bridge_roles = NULL;
496 }
497}
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
Bridging API.
static void bridge_role_destroy(struct bridge_role *role)
Definition: bridge_roles.c:69
static struct bridge_role * get_role_from_datastore(struct bridge_roles_datastore *roles_datastore, const char *role_name)
Definition: bridge_roles.c:193
static int setup_bridge_role_option(struct bridge_role *role, const char *option, const char *value)
Definition: bridge_roles.c:287
static void bridge_role_datastore_destroy(void *data)
Definition: bridge_roles.c:86
int ast_channel_set_bridge_role_option(struct ast_channel *channel, const char *role_name, const char *option, const char *value)
Set a role option on a channel.
Definition: bridge_roles.c:375
const char * ast_channel_get_role_option(struct ast_channel *channel, const char *role_name, const char *option)
Retrieve the value of a requested role option from a channel.
Definition: bridge_roles.c:399
int ast_channel_has_role(struct ast_channel *channel, const char *role_name)
Check if a role exists on a channel.
Definition: bridge_roles.c:394
static struct bridge_roles_datastore * setup_bridge_roles_datastore(struct ast_channel *chan)
Definition: bridge_roles.c:113
static struct bridge_role * get_role_from_channel(struct ast_channel *channel, const char *role_name)
Definition: bridge_roles.c:217
static struct bridge_roles_datastore * fetch_or_create_bridge_roles_datastore(struct ast_channel *chan)
Definition: bridge_roles.c:168
void ast_channel_remove_bridge_role(struct ast_channel *chan, const char *role_name)
Removes a bridge role from a channel.
Definition: bridge_roles.c:332
int ast_channel_add_bridge_role(struct ast_channel *chan, const char *role_name)
Adds a bridge role to a channel.
Definition: bridge_roles.c:313
static struct bridge_roles_datastore * fetch_bridge_roles_datastore(struct ast_channel *chan)
Definition: bridge_roles.c:144
void ast_channel_clear_bridge_roles(struct ast_channel *chan)
Removes all bridge roles currently on a channel.
Definition: bridge_roles.c:356
static int setup_bridge_role(struct bridge_roles_datastore *roles_datastore, const char *role_name)
Definition: bridge_roles.c:256
static struct bridge_role_option * get_role_option(struct bridge_role *role, const char *option)
Definition: bridge_roles.c:234
const char * ast_bridge_channel_get_role_option(struct ast_bridge_channel *bridge_channel, const char *role_name, const char *option)
Retrieve the value of a requested role option from a bridge channel.
Definition: bridge_roles.c:423
int ast_bridge_channel_has_role(struct ast_bridge_channel *bridge_channel, const char *role_name)
Check to see if a bridge channel inherited a specific role from its channel.
Definition: bridge_roles.c:414
int ast_bridge_channel_establish_roles(struct ast_bridge_channel *bridge_channel)
Clone the roles from a bridge_channel's attached ast_channel onto the bridge_channel's role list.
Definition: bridge_roles.c:443
void ast_bridge_channel_clear_roles(struct ast_bridge_channel *bridge_channel)
Clear all roles from a bridge_channel's role list.
Definition: bridge_roles.c:491
static const struct ast_datastore_info bridge_role_info
Definition: bridge_roles.c:98
Channel Bridging Roles API.
#define AST_ROLE_LEN
Definition: bridge_roles.h:33
General Asterisk PBX channel definitions.
const char * ast_channel_name(const struct ast_channel *chan)
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2385
#define ast_channel_lock(chan)
Definition: channel.h:2922
#define ast_channel_unlock(chan)
Definition: channel.h:2923
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2399
Asterisk datastore objects.
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:85
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
Support for logging to various files, console and syslog Configuration in file logger....
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_WARNING
A set of macros to manage forward-linked lists.
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:681
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:225
#define AST_LIST_LAST(head)
Returns the last entry contained in a list.
Definition: linkedlists.h:429
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:410
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define NULL
Definition: resample.c:96
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:341
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:303
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
Structure that contains information regarding a channel in a bridge.
struct bridge_roles_datastore * bridge_roles
struct ast_channel * chan
Main Channel structure associated with a channel.
Structure for a data store type.
Definition: datastore.h:31
const char * type
Definition: datastore.h:32
Structure for a data store object.
Definition: datastore.h:64
void * data
Definition: datastore.h:66
struct bridge_role_option::@315 list
const ast_string_field option
Definition: bridge_roles.c:49
const ast_string_field value
Definition: bridge_roles.c:49
struct bridge_role::@317 options
char role[AST_ROLE_LEN]
Definition: bridge_roles.c:55
struct bridge_role::@316 list
struct bridge_roles_datastore::@318 role_list
int value
Definition: syslog.c:37