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