bridge_roles.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  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. /*! \file
  19. *
  20. * \brief Channel Bridging Roles API
  21. *
  22. * \author Jonathan Rose <jrose@digium.com>
  23. *
  24. * \ingroup bridges
  25. */
  26. /*** MODULEINFO
  27. <support_level>core</support_level>
  28. ***/
  29. #include "asterisk.h"
  30. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  31. #include <signal.h>
  32. #include "asterisk/logger.h"
  33. #include "asterisk/channel.h"
  34. #include "asterisk/datastore.h"
  35. #include "asterisk/linkedlists.h"
  36. #include "asterisk/bridge.h"
  37. #include "asterisk/bridge_roles.h"
  38. #include "asterisk/stringfields.h"
  39. struct bridge_role_option {
  40. AST_LIST_ENTRY(bridge_role_option) list;
  41. AST_DECLARE_STRING_FIELDS(
  42. AST_STRING_FIELD(option);
  43. AST_STRING_FIELD(value);
  44. );
  45. };
  46. struct bridge_role {
  47. AST_LIST_ENTRY(bridge_role) list;
  48. AST_LIST_HEAD_NOLOCK(, bridge_role_option) options;
  49. char role[AST_ROLE_LEN];
  50. };
  51. struct bridge_roles_datastore {
  52. AST_LIST_HEAD_NOLOCK(, bridge_role) role_list;
  53. };
  54. /*!
  55. * \internal
  56. * \brief Destructor function for a bridge role
  57. * \since 12.0.0
  58. *
  59. * \param role bridge_role being destroyed
  60. *
  61. * \return Nothing
  62. */
  63. static void bridge_role_destroy(struct bridge_role *role)
  64. {
  65. struct bridge_role_option *role_option;
  66. while ((role_option = AST_LIST_REMOVE_HEAD(&role->options, list))) {
  67. ast_string_field_free_memory(role_option);
  68. ast_free(role_option);
  69. }
  70. ast_free(role);
  71. }
  72. /*!
  73. * \internal
  74. * \brief Destructor function for bridge role datastores
  75. * \since 12.0.0
  76. *
  77. * \param data Pointer to the datastore being destroyed
  78. *
  79. * \return Nothing
  80. */
  81. static void bridge_role_datastore_destroy(void *data)
  82. {
  83. struct bridge_roles_datastore *roles_datastore = data;
  84. struct bridge_role *role;
  85. while ((role = AST_LIST_REMOVE_HEAD(&roles_datastore->role_list, list))) {
  86. bridge_role_destroy(role);
  87. }
  88. ast_free(roles_datastore);
  89. }
  90. static const struct ast_datastore_info bridge_role_info = {
  91. .type = "bridge roles",
  92. .destroy = bridge_role_datastore_destroy,
  93. };
  94. /*!
  95. * \internal
  96. * \brief Setup a bridge role datastore on a channel
  97. * \since 12.0.0
  98. *
  99. * \param chan Chan the datastore is being setup on
  100. *
  101. * \retval NULL if failed
  102. * \retval pointer to the newly created datastore
  103. */
  104. static struct bridge_roles_datastore *setup_bridge_roles_datastore(struct ast_channel *chan)
  105. {
  106. struct ast_datastore *datastore = NULL;
  107. struct bridge_roles_datastore *roles_datastore = NULL;
  108. if (!(datastore = ast_datastore_alloc(&bridge_role_info, NULL))) {
  109. return NULL;
  110. }
  111. if (!(roles_datastore = ast_calloc(1, sizeof(*roles_datastore)))) {
  112. ast_datastore_free(datastore);
  113. return NULL;
  114. }
  115. AST_LIST_HEAD_INIT_NOLOCK(&roles_datastore->role_list);
  116. datastore->data = roles_datastore;
  117. ast_channel_datastore_add(chan, datastore);
  118. return roles_datastore;
  119. }
  120. /*!
  121. * \internal
  122. * \brief Get the bridge_roles_datastore from a channel if it exists. Don't create one if it doesn't.
  123. * \since 12.0.0
  124. *
  125. * \param chan Channel we want the bridge_roles_datastore from
  126. *
  127. * \retval NULL if we can't find the datastore
  128. * \retval pointer to the bridge_roles_datastore
  129. */
  130. static struct bridge_roles_datastore *fetch_bridge_roles_datastore(struct ast_channel *chan)
  131. {
  132. struct ast_datastore *datastore = NULL;
  133. ast_channel_lock(chan);
  134. if (!(datastore = ast_channel_datastore_find(chan, &bridge_role_info, NULL))) {
  135. ast_channel_unlock(chan);
  136. return NULL;
  137. }
  138. ast_channel_unlock(chan);
  139. return datastore->data;
  140. }
  141. /*!
  142. * \internal
  143. * \brief Get the bridge_roles_datastore from a channel if it exists. If not, create one.
  144. * \since 12.0.0
  145. *
  146. * \param chan Channel we want the bridge_roles_datastore from
  147. *
  148. * \retval NULL If we can't find and can't create the datastore
  149. * \retval pointer to the bridge_roles_datastore
  150. */
  151. static struct bridge_roles_datastore *fetch_or_create_bridge_roles_datastore(struct ast_channel *chan)
  152. {
  153. struct bridge_roles_datastore *roles_datastore;
  154. ast_channel_lock(chan);
  155. roles_datastore = fetch_bridge_roles_datastore(chan);
  156. if (!roles_datastore) {
  157. roles_datastore = setup_bridge_roles_datastore(chan);
  158. }
  159. ast_channel_unlock(chan);
  160. return roles_datastore;
  161. }
  162. /*!
  163. * \internal
  164. * \brief Obtain a role from a bridge_roles_datastore if the datastore has it
  165. * \since 12.0.0
  166. *
  167. * \param roles_datastore The bridge_roles_datastore we are looking for the role of
  168. * \param role_name Name of the role being sought
  169. *
  170. * \retval NULL if the datastore does not have the requested role
  171. * \retval pointer to the requested role
  172. */
  173. static struct bridge_role *get_role_from_datastore(struct bridge_roles_datastore *roles_datastore, const char *role_name)
  174. {
  175. struct bridge_role *role;
  176. AST_LIST_TRAVERSE(&roles_datastore->role_list, role, list) {
  177. if (!strcmp(role->role, role_name)) {
  178. return role;
  179. }
  180. }
  181. return NULL;
  182. }
  183. /*!
  184. * \internal
  185. * \brief Obtain a role from a channel structure if the channel's datastore has it
  186. * \since 12.0.0
  187. *
  188. * \param channel The channel we are checking the role of
  189. * \param role_name Name of the role sought
  190. *
  191. * \retval NULL if the channel's datastore does not have the requested role
  192. * \retval pointer to the requested role
  193. */
  194. static struct bridge_role *get_role_from_channel(struct ast_channel *channel, const char *role_name)
  195. {
  196. struct bridge_roles_datastore *roles_datastore = fetch_bridge_roles_datastore(channel);
  197. return roles_datastore ? get_role_from_datastore(roles_datastore, role_name) : NULL;
  198. }
  199. /*!
  200. * \internal
  201. * \brief Obtain a role option from a bridge role if it exists in the bridge role's option list
  202. * \since 12.0.0
  203. *
  204. * \param role a pointer to the bridge role wea re searching for the option of
  205. * \param option Name of the option sought
  206. *
  207. * \retval NULL if the bridge role doesn't have the requested option
  208. * \retval pointer to the requested option
  209. */
  210. static struct bridge_role_option *get_role_option(struct bridge_role *role, const char *option)
  211. {
  212. struct bridge_role_option *role_option = NULL;
  213. AST_LIST_TRAVERSE(&role->options, role_option, list) {
  214. if (!strcmp(role_option->option, option)) {
  215. return role_option;
  216. }
  217. }
  218. return NULL;
  219. }
  220. /*!
  221. * \internal
  222. * \brief Setup a bridge role on an existing bridge role datastore
  223. * \since 12.0.0
  224. *
  225. * \param roles_datastore bridge_roles_datastore receiving the new role
  226. * \param role_name Name of the role being received
  227. *
  228. * \retval 0 on success
  229. * \retval -1 on failure
  230. */
  231. static int setup_bridge_role(struct bridge_roles_datastore *roles_datastore, const char *role_name)
  232. {
  233. struct bridge_role *role;
  234. role = ast_calloc(1, sizeof(*role));
  235. if (!role) {
  236. return -1;
  237. }
  238. AST_LIST_HEAD_INIT_NOLOCK(&role->options);
  239. ast_copy_string(role->role, role_name, sizeof(role->role));
  240. AST_LIST_INSERT_TAIL(&roles_datastore->role_list, role, list);
  241. ast_debug(3, "Set role '%s'\n", role_name);
  242. return 0;
  243. }
  244. /*!
  245. * \internal
  246. * \brief Setup a bridge role option on an existing bridge role
  247. * \since 12.0.0
  248. *
  249. * \param role The role receiving the option
  250. * \param option Name of the option
  251. * \param value the option's value
  252. *
  253. * \retval 0 on success
  254. * \retval -1 on failure
  255. */
  256. static int setup_bridge_role_option(struct bridge_role *role, const char *option, const char *value)
  257. {
  258. struct bridge_role_option *role_option;
  259. if (!value) {
  260. value = "";
  261. }
  262. role_option = ast_calloc(1, sizeof(*role_option));
  263. if (!role_option) {
  264. return -1;
  265. }
  266. if (ast_string_field_init(role_option, 32)) {
  267. ast_free(role_option);
  268. return -1;
  269. }
  270. ast_string_field_set(role_option, option, option);
  271. ast_string_field_set(role_option, value, value);
  272. AST_LIST_INSERT_TAIL(&role->options, role_option, list);
  273. return 0;
  274. }
  275. int ast_channel_add_bridge_role(struct ast_channel *chan, const char *role_name)
  276. {
  277. struct bridge_roles_datastore *roles_datastore = fetch_or_create_bridge_roles_datastore(chan);
  278. if (!roles_datastore) {
  279. ast_log(LOG_WARNING, "Unable to set up bridge role datastore on channel %s\n", ast_channel_name(chan));
  280. return -1;
  281. }
  282. /* Check to make sure we aren't adding a redundant role */
  283. if (get_role_from_datastore(roles_datastore, role_name)) {
  284. ast_debug(2, "Bridge role %s is already applied to the channel %s\n", role_name, ast_channel_name(chan));
  285. return 0;
  286. }
  287. /* It wasn't already there, so we can just finish setting it up now. */
  288. return setup_bridge_role(roles_datastore, role_name);
  289. }
  290. void ast_channel_remove_bridge_role(struct ast_channel *chan, const char *role_name)
  291. {
  292. struct bridge_roles_datastore *roles_datastore = fetch_bridge_roles_datastore(chan);
  293. struct bridge_role *role;
  294. if (!roles_datastore) {
  295. /* The roles datastore didn't already exist, so there is no need to remove a role */
  296. ast_debug(2, "Role %s did not exist on channel %s\n", role_name, ast_channel_name(chan));
  297. return;
  298. }
  299. AST_LIST_TRAVERSE_SAFE_BEGIN(&roles_datastore->role_list, role, list) {
  300. if (!strcmp(role->role, role_name)) {
  301. ast_debug(2, "Removing bridge role %s from channel %s\n", role_name, ast_channel_name(chan));
  302. AST_LIST_REMOVE_CURRENT(list);
  303. bridge_role_destroy(role);
  304. return;
  305. }
  306. }
  307. AST_LIST_TRAVERSE_SAFE_END;
  308. ast_debug(2, "Role %s did not exist on channel %s\n", role_name, ast_channel_name(chan));
  309. }
  310. void ast_channel_clear_bridge_roles(struct ast_channel *chan)
  311. {
  312. struct bridge_roles_datastore *roles_datastore = fetch_bridge_roles_datastore(chan);
  313. struct bridge_role *role;
  314. if (!roles_datastore) {
  315. /* The roles datastore didn't already exist, so there is no need to remove any roles */
  316. ast_debug(2, "Roles did not exist on channel %s\n", ast_channel_name(chan));
  317. return;
  318. }
  319. AST_LIST_TRAVERSE_SAFE_BEGIN(&roles_datastore->role_list, role, list) {
  320. ast_debug(2, "Removing bridge role %s from channel %s\n", role->role, ast_channel_name(chan));
  321. AST_LIST_REMOVE_CURRENT(list);
  322. bridge_role_destroy(role);
  323. }
  324. AST_LIST_TRAVERSE_SAFE_END;
  325. }
  326. int ast_channel_set_bridge_role_option(struct ast_channel *channel, const char *role_name, const char *option, const char *value)
  327. {
  328. struct bridge_role *role = get_role_from_channel(channel, role_name);
  329. struct bridge_role_option *role_option;
  330. if (!role) {
  331. return -1;
  332. }
  333. role_option = get_role_option(role, option);
  334. if (role_option) {
  335. ast_string_field_set(role_option, value, value);
  336. return 0;
  337. }
  338. return setup_bridge_role_option(role, option, value);
  339. }
  340. int ast_channel_has_role(struct ast_channel *channel, const char *role_name)
  341. {
  342. return get_role_from_channel(channel, role_name) ? 1 : 0;
  343. }
  344. const char *ast_channel_get_role_option(struct ast_channel *channel, const char *role_name, const char *option)
  345. {
  346. struct bridge_role *role;
  347. struct bridge_role_option *role_option;
  348. role = get_role_from_channel(channel, role_name);
  349. if (!role) {
  350. return NULL;
  351. }
  352. role_option = get_role_option(role, option);
  353. return role_option ? role_option->value : NULL;
  354. }
  355. int ast_bridge_channel_has_role(struct ast_bridge_channel *bridge_channel, const char *role_name)
  356. {
  357. if (!bridge_channel->bridge_roles) {
  358. return 0;
  359. }
  360. return get_role_from_datastore(bridge_channel->bridge_roles, role_name) ? 1 : 0;
  361. }
  362. const char *ast_bridge_channel_get_role_option(struct ast_bridge_channel *bridge_channel, const char *role_name, const char *option)
  363. {
  364. struct bridge_role *role;
  365. struct bridge_role_option *role_option = NULL;
  366. if (!bridge_channel->bridge_roles) {
  367. return NULL;
  368. }
  369. role = get_role_from_datastore(bridge_channel->bridge_roles, role_name);
  370. if (!role) {
  371. return NULL;
  372. }
  373. role_option = get_role_option(role, option);
  374. return role_option ? role_option->value : NULL;
  375. }
  376. int ast_bridge_channel_establish_roles(struct ast_bridge_channel *bridge_channel)
  377. {
  378. struct bridge_roles_datastore *roles_datastore;
  379. struct bridge_role *role = NULL;
  380. struct bridge_role_option *role_option;
  381. if (!bridge_channel->chan) {
  382. ast_debug(2, "Attempted to set roles on a bridge channel that has no associated channel. That's a bad idea.\n");
  383. return -1;
  384. }
  385. if (bridge_channel->bridge_roles) {
  386. ast_debug(2, "Attempted to reset roles while roles were already established. Purge existing roles first.\n");
  387. return -1;
  388. }
  389. roles_datastore = fetch_bridge_roles_datastore(bridge_channel->chan);
  390. if (!roles_datastore) {
  391. /* No roles to establish. */
  392. return 0;
  393. }
  394. if (!(bridge_channel->bridge_roles = ast_calloc(1, sizeof(*bridge_channel->bridge_roles)))) {
  395. return -1;
  396. }
  397. AST_LIST_TRAVERSE(&roles_datastore->role_list, role, list) {
  398. struct bridge_role *this_role_copy;
  399. if (setup_bridge_role(bridge_channel->bridge_roles, role->role)) {
  400. /* We need to abandon the copy because we couldn't setup a role */
  401. ast_bridge_channel_clear_roles(bridge_channel);
  402. return -1;
  403. }
  404. this_role_copy = AST_LIST_LAST(&bridge_channel->bridge_roles->role_list);
  405. AST_LIST_TRAVERSE(&role->options, role_option, list) {
  406. if (setup_bridge_role_option(this_role_copy, role_option->option, role_option->value)) {
  407. /* We need to abandon the copy because we couldn't setup a role option */
  408. ast_bridge_channel_clear_roles(bridge_channel);
  409. return -1;
  410. }
  411. }
  412. }
  413. return 0;
  414. }
  415. void ast_bridge_channel_clear_roles(struct ast_bridge_channel *bridge_channel)
  416. {
  417. if (bridge_channel->bridge_roles) {
  418. bridge_role_datastore_destroy(bridge_channel->bridge_roles);
  419. bridge_channel->bridge_roles = NULL;
  420. }
  421. }