cel_beanstalkd.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2017, Greenfield Technologies Ltd.
  5. *
  6. * Nir Simionovich <nirs@greenfieldtech.net>
  7. * who freely borrowed code from the cel manager equivalents
  8. * (see cel/cel_manager.c)
  9. *
  10. * See http://www.asterisk.org for more information about
  11. * the Asterisk project. Please do not directly contact
  12. * any of the maintainers of this project for assistance;
  13. * the project provides a web site, mailing lists and IRC
  14. * channels for your use.
  15. *
  16. * This program is free software, distributed under the terms of
  17. * the GNU General Public License Version 2. See the LICENSE file
  18. * at the top of the source tree.
  19. */
  20. /*! \file
  21. *
  22. * \brief Asterisk Channel Event Beanstalkd backend
  23. *
  24. * This module requires the beanstalk-client library, avaialble from
  25. * https://github.com/deepfryed/beanstalk-client
  26. * \ingroup cel_drivers
  27. */
  28. /*! \li \ref cek_beanstalkd.c uses the configuration file \ref cel.conf
  29. * \addtogroup configuration_file Configuration Files
  30. */
  31. /*!
  32. * \page cel.conf cel.conf
  33. * \verbinclude cel.conf.sample
  34. */
  35. /*** MODULEINFO
  36. <depend>beanstalk</depend>
  37. <support_level>extended</support_level>
  38. ***/
  39. #include "asterisk.h"
  40. #include "asterisk/channel.h"
  41. #include "asterisk/cel.h"
  42. #include "asterisk/module.h"
  43. #include "asterisk/logger.h"
  44. #include "asterisk/utils.h"
  45. #include "asterisk/manager.h"
  46. #include "asterisk/config.h"
  47. #include "asterisk/json.h"
  48. #include "beanstalk.h"
  49. static const char DATE_FORMAT[] = "%Y-%m-%d %T";
  50. static const char CONF_FILE[] = "cel_beanstalkd.conf";
  51. /*! \brief Beanstalk CEL is off by default */
  52. #define CEL_BEANSTALK_ENABLED_DEFAULT 0
  53. static int enablecel;
  54. /*! \brief show_user_def is off by default */
  55. #define CEL_SHOW_USERDEF_DEFAULT 0
  56. #define CEL_BACKEND_NAME "Beanstalk Event Logging"
  57. #define BEANSTALK_JOB_SIZE 4096
  58. #define BEANSTALK_JOB_PRIORITY 99
  59. #define BEANSTALK_JOB_TTR 60
  60. #define BEANSTALK_JOB_DELAY 0
  61. #define DEFAULT_BEANSTALK_HOST "127.0.0.1"
  62. #define DEFAULT_BEANSTALK_PORT 11300
  63. #define DEFAULT_BEANSTALK_TUBE "asterisk-cel"
  64. static char *bs_host;
  65. static int bs_port;
  66. static char *bs_tube;
  67. static int priority;
  68. AST_RWLOCK_DEFINE_STATIC(config_lock);
  69. static void cel_bs_put(struct ast_event *event)
  70. {
  71. struct ast_tm timeresult;
  72. char start_time[80];
  73. char *cel_buffer;
  74. int bs_id;
  75. int bs_socket;
  76. struct ast_json *t_cel_json;
  77. struct ast_cel_event_record record = {
  78. .version = AST_CEL_EVENT_RECORD_VERSION,
  79. };
  80. if (!enablecel) {
  81. return;
  82. }
  83. if (ast_cel_fill_record(event, &record)) {
  84. return;
  85. }
  86. ast_rwlock_rdlock(&config_lock);
  87. bs_socket = bs_connect(bs_host, bs_port);
  88. if (bs_use(bs_socket, bs_tube) != BS_STATUS_OK) {
  89. ast_log(LOG_ERROR, "Connection to Beanstalk tube %s @ %s:%d had failed", bs_tube, bs_host, bs_port);
  90. ast_rwlock_unlock(&config_lock);
  91. return;
  92. }
  93. ast_localtime(&record.event_time, &timeresult, NULL);
  94. ast_strftime(start_time, sizeof(start_time), DATE_FORMAT, &timeresult);
  95. ast_rwlock_unlock(&config_lock);
  96. t_cel_json = ast_json_pack("{s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s}",
  97. "EventName", S_OR(record.event_name, ""),
  98. "AccountCode", S_OR(record.account_code, ""),
  99. "CallerIDnum", S_OR(record.caller_id_num, ""),
  100. "CallerIDname", S_OR(record.caller_id_name, ""),
  101. "CallerIDani", S_OR(record.caller_id_ani, ""),
  102. "CallerIDrdnis", S_OR(record.caller_id_rdnis, ""),
  103. "CallerIDdnid", S_OR(record.caller_id_dnid, ""),
  104. "Exten", S_OR(record.extension, ""),
  105. "Context", S_OR(record.context, ""),
  106. "Channel", S_OR(record.channel_name, ""),
  107. "Application", S_OR(record.application_name, ""),
  108. "AppData", S_OR(record.application_data, ""),
  109. "EventTime", S_OR(start_time, ""),
  110. "AMAFlags", S_OR(ast_channel_amaflags2string(record.amaflag), ""),
  111. "UniqueID", S_OR(record.unique_id, ""),
  112. "LinkedID", S_OR(record.linked_id, ""),
  113. "Userfield", S_OR(record.user_field, ""),
  114. "Peer", S_OR(record.peer_account, ""),
  115. "PeerAccount", S_OR(record.peer_account, ""),
  116. "Extra", S_OR(record.extra, "")
  117. );
  118. cel_buffer = ast_json_dump_string(t_cel_json);
  119. ast_json_unref(t_cel_json);
  120. bs_id = bs_put(bs_socket, priority, BEANSTALK_JOB_DELAY, BEANSTALK_JOB_TTR, cel_buffer, strlen(cel_buffer));
  121. if (bs_id > 0) {
  122. ast_log(LOG_DEBUG, "Successfully created job %d with %s\n", bs_id, cel_buffer);
  123. } else {
  124. ast_log(LOG_ERROR, "CDR job creation failed for %s\n", cel_buffer);
  125. }
  126. bs_disconnect(bs_socket);
  127. ast_json_free(cel_buffer);
  128. }
  129. static int load_config(int reload)
  130. {
  131. const char *cat = NULL;
  132. struct ast_config *cfg;
  133. struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
  134. struct ast_variable *v;
  135. int newenablecel = CEL_BEANSTALK_ENABLED_DEFAULT;
  136. cfg = ast_config_load(CONF_FILE, config_flags);
  137. if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
  138. return 0;
  139. }
  140. if (cfg == CONFIG_STATUS_FILEINVALID) {
  141. ast_log(LOG_WARNING, "Configuration file '%s' is invalid. CEL Beanstalkd Module not activated.\n",
  142. CONF_FILE);
  143. return -1;
  144. } else if (!cfg) {
  145. ast_log(LOG_WARNING, "Failed to load configuration file. CEL Beanstalkd Module not activated.\n");
  146. if (enablecel) {
  147. ast_cel_backend_unregister(CEL_BACKEND_NAME);
  148. }
  149. enablecel = 0;
  150. return -1;
  151. }
  152. if (reload) {
  153. ast_rwlock_wrlock(&config_lock);
  154. ast_free(bs_host);
  155. ast_free(bs_tube);
  156. }
  157. /* Bootstrap the default configuration */
  158. bs_host = ast_strdup(DEFAULT_BEANSTALK_HOST);
  159. bs_port = DEFAULT_BEANSTALK_PORT;
  160. bs_tube = ast_strdup(DEFAULT_BEANSTALK_TUBE);
  161. priority = BEANSTALK_JOB_PRIORITY;
  162. while ((cat = ast_category_browse(cfg, cat))) {
  163. if (strcasecmp(cat, "general")) {
  164. continue;
  165. }
  166. for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
  167. if (!strcasecmp(v->name, "enabled")) {
  168. newenablecel = ast_true(v->value) ? 1 : 0;
  169. } else if (!strcasecmp(v->name, "host")) {
  170. ast_free(bs_host);
  171. bs_host = ast_strdup(v->value);
  172. } else if (!strcasecmp(v->name, "port")) {
  173. bs_port = atoi(v->value);
  174. } else if (!strcasecmp(v->name, "tube")) {
  175. ast_free(bs_tube);
  176. bs_tube = ast_strdup(v->value);
  177. } else if (!strcasecmp(v->name, "priority")) {
  178. priority = atoi(v->value);
  179. } else {
  180. ast_log(LOG_NOTICE, "Unknown option '%s' specified "
  181. "for CEL beanstalk backend.\n", v->name);
  182. }
  183. }
  184. }
  185. if (reload) {
  186. ast_rwlock_unlock(&config_lock);
  187. }
  188. ast_config_destroy(cfg);
  189. if (enablecel && !newenablecel) {
  190. ast_cel_backend_unregister(CEL_BACKEND_NAME);
  191. } else if (!enablecel && newenablecel) {
  192. if (ast_cel_backend_register(CEL_BACKEND_NAME, cel_bs_put)) {
  193. ast_log(LOG_ERROR, "Unable to register Beanstalkd CEL handling\n");
  194. }
  195. }
  196. enablecel = newenablecel;
  197. return 0;
  198. }
  199. static int unload_module(void)
  200. {
  201. ast_cel_backend_unregister(CEL_BACKEND_NAME);
  202. ast_free(bs_host);
  203. ast_free(bs_tube);
  204. return 0;
  205. }
  206. static int load_module(void)
  207. {
  208. if (load_config(0)) {
  209. return AST_MODULE_LOAD_DECLINE;
  210. }
  211. return AST_MODULE_LOAD_SUCCESS;
  212. }
  213. static int reload(void)
  214. {
  215. return load_config(1);
  216. }
  217. AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Beanstalkd CEL Backend",
  218. .support_level = AST_MODULE_SUPPORT_EXTENDED,
  219. .load = load_module,
  220. .unload = unload_module,
  221. .reload = reload,
  222. .load_pri = AST_MODPRI_CDR_DRIVER,
  223. .requires = "cel",
  224. );