bridge_roles.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  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(, bridge_role_option) options;
  49. char role[AST_ROLE_LEN];
  50. };
  51. struct bridge_roles_datastore {
  52. AST_LIST_HEAD(, 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. datastore->data = roles_datastore;
  116. ast_channel_datastore_add(chan, datastore);
  117. return roles_datastore;
  118. }
  119. /*!
  120. * \internal
  121. * \brief Get the bridge_roles_datastore from a channel if it exists. Don't create one if it doesn't.
  122. * \since 12.0.0
  123. *
  124. * \param chan Channel we want the bridge_roles_datastore from
  125. *
  126. * \retval NULL if we can't find the datastore
  127. * \retval pointer to the bridge_roles_datastore
  128. */
  129. static struct bridge_roles_datastore *fetch_bridge_roles_datastore(struct ast_channel *chan)
  130. {
  131. struct ast_datastore *datastore = NULL;
  132. ast_channel_lock(chan);
  133. if (!(datastore = ast_channel_datastore_find(chan, &bridge_role_info, NULL))) {
  134. ast_channel_unlock(chan);
  135. return NULL;
  136. }
  137. ast_channel_unlock(chan);
  138. return datastore->data;
  139. }
  140. /*!
  141. * \internal
  142. * \brief Get the bridge_roles_datastore from a channel if it exists. If not, create one.
  143. * \since 12.0.0
  144. *
  145. * \param chan Channel we want the bridge_roles_datastore from
  146. *
  147. * \retval NULL If we can't find and can't create the datastore
  148. * \retval pointer to the bridge_roles_datastore
  149. */
  150. static struct bridge_roles_datastore *fetch_or_create_bridge_roles_datastore(struct ast_channel *chan)
  151. {
  152. struct bridge_roles_datastore *roles_datastore;
  153. ast_channel_lock(chan);
  154. roles_datastore = fetch_bridge_roles_datastore(chan);
  155. if (!roles_datastore) {
  156. roles_datastore = setup_bridge_roles_datastore(chan);
  157. }
  158. ast_channel_unlock(chan);
  159. return roles_datastore;
  160. }
  161. /*!
  162. * \internal
  163. * \brief Obtain a role from a bridge_roles_datastore if the datastore has it
  164. * \since 12.0.0
  165. *
  166. * \param roles_datastore The bridge_roles_datastore we are looking for the role of
  167. * \param role_name Name of the role being sought
  168. *
  169. * \retval NULL if the datastore does not have the requested role
  170. * \retval pointer to the requested role
  171. */
  172. static struct bridge_role *get_role_from_datastore(struct bridge_roles_datastore *roles_datastore, const char *role_name)
  173. {
  174. struct bridge_role *role;
  175. AST_LIST_TRAVERSE(&roles_datastore->role_list, role, list) {
  176. if (!strcmp(role->role, role_name)) {
  177. return role;
  178. }
  179. }
  180. return NULL;
  181. }
  182. /*!
  183. * \internal
  184. * \brief Obtain a role from a channel structure if the channel's datastore has it
  185. * \since 12.0.0
  186. *
  187. * \param channel The channel we are checking the role of
  188. * \param role_name Name of the role sought
  189. *
  190. * \retval NULL if the channel's datastore does not have the requested role
  191. * \retval pointer to the requested role
  192. */
  193. static struct bridge_role *get_role_from_channel(struct ast_channel *channel, const char *role_name)
  194. {
  195. struct bridge_roles_datastore *roles_datastore = fetch_bridge_roles_datastore(channel);
  196. return roles_datastore ? get_role_from_datastore(roles_datastore, role_name) : NULL;
  197. }
  198. /*!
  199. * \internal
  200. * \brief Obtain a role option from a bridge role if it exists in the bridge role's option list
  201. * \since 12.0.0
  202. *
  203. * \param role a pointer to the bridge role wea re searching for the option of
  204. * \param option Name of the option sought
  205. *
  206. * \retval NULL if the bridge role doesn't have the requested option
  207. * \retval pointer to the requested option
  208. */
  209. static struct bridge_role_option *get_role_option(struct bridge_role *role, const char *option)
  210. {
  211. struct bridge_role_option *role_option = NULL;
  212. AST_LIST_TRAVERSE(&role->options, role_option, list) {
  213. if (!strcmp(role_option->option, option)) {
  214. return role_option;
  215. }
  216. }
  217. return NULL;
  218. }
  219. /*!
  220. * \internal
  221. * \brief Setup a bridge role on an existing bridge role datastore
  222. * \since 12.0.0
  223. *
  224. * \param roles_datastore bridge_roles_datastore receiving the new role
  225. * \param role_name Name of the role being received
  226. *
  227. * \retval 0 on success
  228. * \retval -1 on failure
  229. */
  230. static int setup_bridge_role(struct bridge_roles_datastore *roles_datastore, const char *role_name)
  231. {
  232. struct bridge_role *role;
  233. role = ast_calloc(1, sizeof(*role));
  234. if (!role) {
  235. return -1;
  236. }
  237. ast_copy_string(role->role, role_name, sizeof(role->role));
  238. AST_LIST_INSERT_TAIL(&roles_datastore->role_list, role, list);
  239. ast_debug(3, "Set role '%s'\n", role_name);
  240. return 0;
  241. }
  242. /*!
  243. * \internal
  244. * \brief Setup a bridge role option on an existing bridge role
  245. * \since 12.0.0
  246. *
  247. * \param role The role receiving the option
  248. * \param option Name of the option
  249. * \param value the option's value
  250. *
  251. * \retval 0 on success
  252. * \retval -1 on failure
  253. */
  254. static int setup_bridge_role_option(struct bridge_role *role, const char *option, const char *value)
  255. {
  256. struct bridge_role_option *role_option;
  257. if (!value) {
  258. value = "";
  259. }
  260. role_option = ast_calloc(1, sizeof(*role_option));
  261. if (!role_option) {
  262. return -1;
  263. }
  264. if (ast_string_field_init(role_option, 32)) {
  265. ast_free(role_option);
  266. return -1;
  267. }
  268. ast_string_field_set(role_option, option, option);
  269. ast_string_field_set(role_option, value, value);
  270. AST_LIST_INSERT_TAIL(&role->options, role_option, list);
  271. return 0;
  272. }
  273. int ast_channel_add_bridge_role(struct ast_channel *chan, const char *role_name)
  274. {
  275. struct bridge_roles_datastore *roles_datastore = fetch_or_create_bridge_roles_datastore(chan);
  276. if (!roles_datastore) {
  277. ast_log(LOG_WARNING, "Unable to set up bridge role datastore on channel %s\n", ast_channel_name(chan));
  278. return -1;
  279. }
  280. /* Check to make sure we aren't adding a redundant role */
  281. if (get_role_from_datastore(roles_datastore, role_name)) {
  282. ast_debug(2, "Bridge role %s is already applied to the channel %s\n", role_name, ast_channel_name(chan));
  283. return 0;
  284. }
  285. /* It wasn't already there, so we can just finish setting it up now. */
  286. return setup_bridge_role(roles_datastore, role_name);
  287. }
  288. void ast_channel_remove_bridge_role(struct ast_channel *chan, const char *role_name)
  289. {
  290. struct bridge_roles_datastore *roles_datastore = fetch_bridge_roles_datastore(chan);
  291. struct bridge_role *role;
  292. if (!roles_datastore) {
  293. /* The roles datastore didn't already exist, so there is no need to remove a role */
  294. ast_debug(2, "Role %s did not exist on channel %s\n", role_name, ast_channel_name(chan));
  295. return;
  296. }
  297. AST_LIST_TRAVERSE_SAFE_BEGIN(&roles_datastore->role_list, role, list) {
  298. if (!strcmp(role->role, role_name)) {
  299. ast_debug(2, "Removing bridge role %s from channel %s\n", role_name, ast_channel_name(chan));
  300. AST_LIST_REMOVE_CURRENT(list);
  301. bridge_role_destroy(role);
  302. return;
  303. }
  304. }
  305. AST_LIST_TRAVERSE_SAFE_END;
  306. ast_debug(2, "Role %s did not exist on channel %s\n", role_name, ast_channel_name(chan));
  307. }
  308. void ast_channel_clear_bridge_roles(struct ast_channel *chan)
  309. {
  310. struct bridge_roles_datastore *roles_datastore = fetch_bridge_roles_datastore(chan);
  311. struct bridge_role *role;
  312. if (!roles_datastore) {
  313. /* The roles datastore didn't already exist, so there is no need to remove any roles */
  314. ast_debug(2, "Roles did not exist on channel %s\n", ast_channel_name(chan));
  315. return;
  316. }
  317. AST_LIST_TRAVERSE_SAFE_BEGIN(&roles_datastore->role_list, role, list) {
  318. ast_debug(2, "Removing bridge role %s from channel %s\n", role->role, ast_channel_name(chan));
  319. AST_LIST_REMOVE_CURRENT(list);
  320. bridge_role_destroy(role);
  321. }
  322. AST_LIST_TRAVERSE_SAFE_END;
  323. }
  324. int ast_channel_set_bridge_role_option(struct ast_channel *channel, const char *role_name, const char *option, const char *value)
  325. {
  326. struct bridge_role *role = get_role_from_channel(channel, role_name);
  327. struct bridge_role_option *role_option;
  328. if (!role) {
  329. return -1;
  330. }
  331. role_option = get_role_option(role, option);
  332. if (role_option) {
  333. ast_string_field_set(role_option, value, value);
  334. return 0;
  335. }
  336. return setup_bridge_role_option(role, option, value);
  337. }
  338. int ast_channel_has_role(struct ast_channel *channel, const char *role_name)
  339. {
  340. return get_role_from_channel(channel, role_name) ? 1 : 0;
  341. }
  342. const char *ast_channel_get_role_option(struct ast_channel *channel, const char *role_name, const char *option)
  343. {
  344. struct bridge_role *role;
  345. struct bridge_role_option *role_option;
  346. role = get_role_from_channel(channel, role_name);
  347. if (!role) {
  348. return NULL;
  349. }
  350. role_option = get_role_option(role, option);
  351. return role_option ? role_option->value : NULL;
  352. }
  353. int ast_bridge_channel_has_role(struct ast_bridge_channel *bridge_channel, const char *role_name)
  354. {
  355. if (!bridge_channel->bridge_roles) {
  356. return 0;
  357. }
  358. return get_role_from_datastore(bridge_channel->bridge_roles, role_name) ? 1 : 0;
  359. }
  360. const char *ast_bridge_channel_get_role_option(struct ast_bridge_channel *bridge_channel, const char *role_name, const char *option)
  361. {
  362. struct bridge_role *role;
  363. struct bridge_role_option *role_option = NULL;
  364. if (!bridge_channel->bridge_roles) {
  365. return NULL;
  366. }
  367. role = get_role_from_datastore(bridge_channel->bridge_roles, role_name);
  368. if (!role) {
  369. return NULL;
  370. }
  371. role_option = get_role_option(role, option);
  372. return role_option ? role_option->value : NULL;
  373. }
  374. int ast_bridge_channel_establish_roles(struct ast_bridge_channel *bridge_channel)
  375. {
  376. struct bridge_roles_datastore *roles_datastore;
  377. struct bridge_role *role = NULL;
  378. struct bridge_role_option *role_option;
  379. if (!bridge_channel->chan) {
  380. ast_debug(2, "Attempted to set roles on a bridge channel that has no associated channel. That's a bad idea.\n");
  381. return -1;
  382. }
  383. if (bridge_channel->bridge_roles) {
  384. ast_debug(2, "Attempted to reset roles while roles were already established. Purge existing roles first.\n");
  385. return -1;
  386. }
  387. roles_datastore = fetch_bridge_roles_datastore(bridge_channel->chan);
  388. if (!roles_datastore) {
  389. /* No roles to establish. */
  390. return 0;
  391. }
  392. if (!(bridge_channel->bridge_roles = ast_calloc(1, sizeof(*bridge_channel->bridge_roles)))) {
  393. return -1;
  394. }
  395. AST_LIST_TRAVERSE(&roles_datastore->role_list, role, list) {
  396. struct bridge_role *this_role_copy;
  397. if (setup_bridge_role(bridge_channel->bridge_roles, role->role)) {
  398. /* We need to abandon the copy because we couldn't setup a role */
  399. ast_bridge_channel_clear_roles(bridge_channel);
  400. return -1;
  401. }
  402. this_role_copy = AST_LIST_LAST(&bridge_channel->bridge_roles->role_list);
  403. AST_LIST_TRAVERSE(&role->options, role_option, list) {
  404. if (setup_bridge_role_option(this_role_copy, role_option->option, role_option->value)) {
  405. /* We need to abandon the copy because we couldn't setup a role option */
  406. ast_bridge_channel_clear_roles(bridge_channel);
  407. return -1;
  408. }
  409. }
  410. }
  411. return 0;
  412. }
  413. void ast_bridge_channel_clear_roles(struct ast_bridge_channel *bridge_channel)
  414. {
  415. if (bridge_channel->bridge_roles) {
  416. bridge_role_datastore_destroy(bridge_channel->bridge_roles);
  417. bridge_channel->bridge_roles = NULL;
  418. }
  419. }