res_ais.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2007 - 2008, Digium, Inc.
  5. *
  6. * Russell Bryant <russell@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. * \author Russell Bryant <russell@digium.com>
  21. *
  22. * \brief Usage of the SAForum AIS (Application Interface Specification)
  23. *
  24. * \arg http://www.openais.org/
  25. *
  26. * This file contains the common code between the uses of the different AIS
  27. * services.
  28. *
  29. * \note This module is still considered experimental, as it exposes the
  30. * internal binary format of events between Asterisk servers over a network.
  31. * However, this format is still subject to change between 1.6.X releases.
  32. */
  33. /*** MODULEINFO
  34. <depend>ais</depend>
  35. <support_level>extended</support_level>
  36. ***/
  37. #include "asterisk.h"
  38. ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
  39. #include <stdlib.h>
  40. #include <stdio.h>
  41. #include <string.h>
  42. #include <unistd.h>
  43. #include <errno.h>
  44. #include <signal.h>
  45. #include <pthread.h>
  46. #include "ais/ais.h"
  47. #include "asterisk/module.h"
  48. #include "asterisk/options.h"
  49. #include "asterisk/logger.h"
  50. #include "asterisk/channel.h"
  51. #include "asterisk/utils.h"
  52. #include "asterisk/cli.h"
  53. static struct {
  54. pthread_t id;
  55. int alert_pipe[2];
  56. unsigned int stop:1;
  57. } dispatch_thread = {
  58. .id = AST_PTHREADT_NULL,
  59. .alert_pipe = { -1, -1 },
  60. };
  61. SaVersionT ais_version = { 'B', 1, 1 };
  62. static const struct ais_error {
  63. SaAisErrorT error;
  64. const char *desc;
  65. } ais_errors[] = {
  66. { SA_AIS_OK, "OK" },
  67. { SA_AIS_ERR_LIBRARY, "Library Error" },
  68. { SA_AIS_ERR_VERSION, "Version Not Compatible" },
  69. { SA_AIS_ERR_INIT, "Callback Not Registered" },
  70. { SA_AIS_ERR_TIMEOUT, "Timeout" },
  71. { SA_AIS_ERR_TRY_AGAIN , "Try Again" },
  72. { SA_AIS_ERR_INVALID_PARAM, "Invalid Parameter" },
  73. { SA_AIS_ERR_NO_MEMORY, "No Memory" },
  74. { SA_AIS_ERR_BAD_HANDLE, "Invalid Handle" },
  75. { SA_AIS_ERR_BUSY, "Resource Already In Use" },
  76. { SA_AIS_ERR_ACCESS, "Access Denied" },
  77. { SA_AIS_ERR_NOT_EXIST, "Does Not Exist" },
  78. { SA_AIS_ERR_NAME_TOO_LONG, "Name Too Long" },
  79. { SA_AIS_ERR_EXIST, "Already Exists" },
  80. { SA_AIS_ERR_NO_SPACE, "Buffer Too Small" },
  81. { SA_AIS_ERR_INTERRUPT, "Request Interrupted" },
  82. { SA_AIS_ERR_NAME_NOT_FOUND, "Name Not Found" },
  83. { SA_AIS_ERR_NO_RESOURCES, "Not Enough Resources" },
  84. { SA_AIS_ERR_NOT_SUPPORTED, "Requested Function Not Supported" },
  85. { SA_AIS_ERR_BAD_OPERATION, "Operation Not Allowed" },
  86. { SA_AIS_ERR_FAILED_OPERATION, "Operation Failed" },
  87. { SA_AIS_ERR_MESSAGE_ERROR, "Communication Error" },
  88. { SA_AIS_ERR_QUEUE_FULL, "Destination Queue Full" },
  89. { SA_AIS_ERR_QUEUE_NOT_AVAILABLE, "Destination Queue Not Available" },
  90. { SA_AIS_ERR_BAD_FLAGS, "Invalid Flags" },
  91. { SA_AIS_ERR_TOO_BIG, "Value Too Large" },
  92. { SA_AIS_ERR_NO_SECTIONS, "No More Sections to Initialize" },
  93. };
  94. const char *ais_err2str(SaAisErrorT error)
  95. {
  96. int x;
  97. for (x = 0; x < ARRAY_LEN(ais_errors); x++) {
  98. if (ais_errors[x].error == error)
  99. return ais_errors[x].desc;
  100. }
  101. return "Unknown";
  102. }
  103. static void *dispatch_thread_handler(void *data)
  104. {
  105. SaSelectionObjectT clm_fd, evt_fd;
  106. int res;
  107. struct pollfd pfd[3] = {
  108. { .events = POLLIN, },
  109. { .events = POLLIN, },
  110. { .events = POLLIN, },
  111. };
  112. SaAisErrorT ais_res;
  113. ais_res = saClmSelectionObjectGet(clm_handle, &clm_fd);
  114. if (ais_res != SA_AIS_OK) {
  115. ast_log(LOG_ERROR, "Failed to retrieve select fd for CLM service. "
  116. "This module will not operate.\n");
  117. return NULL;
  118. }
  119. ais_res = saEvtSelectionObjectGet(evt_handle, &evt_fd);
  120. if (ais_res != SA_AIS_OK) {
  121. ast_log(LOG_ERROR, "Failed to retrieve select fd for EVT service. "
  122. "This module will not operate.\n");
  123. return NULL;
  124. }
  125. pfd[0].fd = clm_fd;
  126. pfd[1].fd = evt_fd;
  127. pfd[2].fd = dispatch_thread.alert_pipe[0];
  128. while (!dispatch_thread.stop) {
  129. pfd[0].revents = 0;
  130. pfd[1].revents = 0;
  131. pfd[2].revents = 0;
  132. res = ast_poll(pfd, ARRAY_LEN(pfd), -1);
  133. if (res == -1 && errno != EINTR && errno != EAGAIN) {
  134. ast_log(LOG_ERROR, "Select error (%s) dispatch thread going away now, "
  135. "and the module will no longer operate.\n", strerror(errno));
  136. break;
  137. }
  138. if (pfd[0].revents & POLLIN) {
  139. saClmDispatch(clm_handle, SA_DISPATCH_ALL);
  140. }
  141. if (pfd[1].revents & POLLIN) {
  142. saEvtDispatch(evt_handle, SA_DISPATCH_ALL);
  143. }
  144. if (pfd[2].revents & POLLIN) {
  145. enum ast_ais_cmd cmd;
  146. ast_debug(1, "Got a command in the poll() loop\n");
  147. if (read(dispatch_thread.alert_pipe[0], &cmd, sizeof(cmd)) != -1) {
  148. switch (cmd) {
  149. case AST_AIS_CMD_MEMBERSHIP_CHANGED:
  150. ast_ais_evt_membership_changed();
  151. break;
  152. case AST_AIS_CMD_EXIT:
  153. break;
  154. }
  155. }
  156. }
  157. }
  158. return NULL;
  159. }
  160. int ast_ais_cmd(enum ast_ais_cmd cmd)
  161. {
  162. int res;
  163. res = write(dispatch_thread.alert_pipe[1], (char *) &cmd, sizeof(cmd));
  164. ast_debug(1, "AIS cmd: %d, res: %d\n", cmd, res);
  165. return res;
  166. }
  167. static int load_module(void)
  168. {
  169. if (pipe(dispatch_thread.alert_pipe) == -1) {
  170. ast_log(LOG_ERROR, "Failed to create alert pipe: %s (%d)\n",
  171. strerror(errno), errno);
  172. goto return_error;
  173. }
  174. if (ast_ais_clm_load_module())
  175. goto clm_failed;
  176. if (ast_ais_evt_load_module())
  177. goto evt_failed;
  178. if (ast_pthread_create_background(&dispatch_thread.id, NULL,
  179. dispatch_thread_handler, NULL)) {
  180. ast_log(LOG_ERROR, "Error starting AIS dispatch thread.\n");
  181. goto dispatch_failed;
  182. }
  183. return AST_MODULE_LOAD_SUCCESS;
  184. dispatch_failed:
  185. ast_ais_evt_unload_module();
  186. evt_failed:
  187. ast_ais_clm_unload_module();
  188. clm_failed:
  189. close(dispatch_thread.alert_pipe[0]);
  190. close(dispatch_thread.alert_pipe[1]);
  191. return_error:
  192. return AST_MODULE_LOAD_DECLINE;
  193. }
  194. static int unload_module(void)
  195. {
  196. ast_ais_clm_unload_module();
  197. ast_ais_evt_unload_module();
  198. if (dispatch_thread.id != AST_PTHREADT_NULL) {
  199. dispatch_thread.stop = 1;
  200. if (ast_ais_cmd(AST_AIS_CMD_EXIT) == -1) {
  201. ast_log(LOG_ERROR, "Failed to write to pipe: %s (%d)\n",
  202. strerror(errno), errno);
  203. }
  204. pthread_join(dispatch_thread.id, NULL);
  205. }
  206. if (dispatch_thread.alert_pipe[0] != -1) {
  207. close(dispatch_thread.alert_pipe[0]);
  208. dispatch_thread.alert_pipe[0] = -1;
  209. }
  210. if (dispatch_thread.alert_pipe[1] != -1) {
  211. close(dispatch_thread.alert_pipe[1]);
  212. dispatch_thread.alert_pipe[1] = -1;
  213. }
  214. return 0;
  215. }
  216. AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "SAForum AIS");