Asterisk - The Open Source Telephony Project  GIT-master-b7027de
cel_beanstalkd.c
Go to the documentation of this file.
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 
21 /*! \file
22  *
23  * \brief Asterisk Channel Event Beanstalkd backend
24  *
25  * This module requires the beanstalk-client library, avaialble from
26  * https://github.com/deepfryed/beanstalk-client
27  *
28  * See also
29  * \arg \ref AstCEL
30  * \ingroup cel_drivers
31  */
32 
33 /*! \li \ref cek_beanstalkd.c uses the configuration file \ref cel.conf
34  * \addtogroup configuration_file Configuration Files
35  */
36 
37 /*!
38  * \page cel.conf cel.conf
39  * \verbinclude cel.conf.sample
40  */
41 
42 /*** MODULEINFO
43  <depend>beanstalk</depend>
44  <support_level>extended</support_level>
45  ***/
46 
47 #include "asterisk.h"
48 
49 #include "asterisk/channel.h"
50 #include "asterisk/cel.h"
51 #include "asterisk/module.h"
52 #include "asterisk/logger.h"
53 #include "asterisk/utils.h"
54 #include "asterisk/manager.h"
55 #include "asterisk/config.h"
56 #include "asterisk/json.h"
57 
58 #include "beanstalk.h"
59 
60 static const char DATE_FORMAT[] = "%Y-%m-%d %T";
61 
62 static const char CONF_FILE[] = "cel_beanstalkd.conf";
63 
64 /*! \brief Beanstalk CEL is off by default */
65 #define CEL_BEANSTALK_ENABLED_DEFAULT 0
66 
67 static int enablecel;
68 
69 /*! \brief show_user_def is off by default */
70 #define CEL_SHOW_USERDEF_DEFAULT 0
71 
72 #define CEL_BACKEND_NAME "Beanstalk Event Logging"
73 
74 #define BEANSTALK_JOB_SIZE 4096
75 #define BEANSTALK_JOB_PRIORITY 99
76 #define BEANSTALK_JOB_TTR 60
77 #define BEANSTALK_JOB_DELAY 0
78 #define DEFAULT_BEANSTALK_HOST "127.0.0.1"
79 #define DEFAULT_BEANSTALK_PORT 11300
80 #define DEFAULT_BEANSTALK_TUBE "asterisk-cel"
81 
82 static char *bs_host;
83 static int bs_port;
84 static char *bs_tube;
85 static int priority;
86 
88 
89 static void cel_bs_put(struct ast_event *event)
90 {
91  struct ast_tm timeresult;
92  char start_time[80];
93  char *cel_buffer;
94  int bs_id;
95  int bs_socket;
96  struct ast_json *t_cel_json;
97 
98  struct ast_cel_event_record record = {
100  };
101 
102  if (!enablecel) {
103  return;
104  }
105 
106  if (ast_cel_fill_record(event, &record)) {
107  return;
108  }
109 
111  bs_socket = bs_connect(bs_host, bs_port);
112 
113  if (bs_use(bs_socket, bs_tube) != BS_STATUS_OK) {
114  ast_log(LOG_ERROR, "Connection to Beanstalk tube %s @ %s:%d had failed", bs_tube, bs_host, bs_port);
116  return;
117  }
118 
119  ast_localtime(&record.event_time, &timeresult, NULL);
120  ast_strftime(start_time, sizeof(start_time), DATE_FORMAT, &timeresult);
121 
123 
124  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}",
125  "EventName", S_OR(record.event_name, ""),
126  "AccountCode", S_OR(record.account_code, ""),
127  "CallerIDnum", S_OR(record.caller_id_num, ""),
128  "CallerIDname", S_OR(record.caller_id_name, ""),
129  "CallerIDani", S_OR(record.caller_id_ani, ""),
130  "CallerIDrdnis", S_OR(record.caller_id_rdnis, ""),
131  "CallerIDdnid", S_OR(record.caller_id_dnid, ""),
132  "Exten", S_OR(record.extension, ""),
133  "Context", S_OR(record.context, ""),
134  "Channel", S_OR(record.channel_name, ""),
135  "Application", S_OR(record.application_name, ""),
136  "AppData", S_OR(record.application_data, ""),
137  "EventTime", S_OR(start_time, ""),
138  "AMAFlags", S_OR(ast_channel_amaflags2string(record.amaflag), ""),
139  "UniqueID", S_OR(record.unique_id, ""),
140  "LinkedID", S_OR(record.linked_id, ""),
141  "Userfield", S_OR(record.user_field, ""),
142  "Peer", S_OR(record.peer_account, ""),
143  "PeerAccount", S_OR(record.peer_account, ""),
144  "Extra", S_OR(record.extra, "")
145 
146  );
147 
148  cel_buffer = ast_json_dump_string(t_cel_json);
149 
150  ast_json_unref(t_cel_json);
151 
152  bs_id = bs_put(bs_socket, priority, BEANSTALK_JOB_DELAY, BEANSTALK_JOB_TTR, cel_buffer, strlen(cel_buffer));
153 
154  if (bs_id > 0) {
155  ast_log(LOG_DEBUG, "Successfully created job %d with %s\n", bs_id, cel_buffer);
156  } else {
157  ast_log(LOG_ERROR, "CDR job creation failed for %s\n", cel_buffer);
158  }
159 
160  bs_disconnect(bs_socket);
161  ast_json_free(cel_buffer);
162 }
163 
164 static int load_config(int reload)
165 {
166  const char *cat = NULL;
167  struct ast_config *cfg;
168  struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
169  struct ast_variable *v;
170  int newenablecel = CEL_BEANSTALK_ENABLED_DEFAULT;
171 
172  cfg = ast_config_load(CONF_FILE, config_flags);
173  if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
174  return 0;
175  }
176 
177  if (cfg == CONFIG_STATUS_FILEINVALID) {
178  ast_log(LOG_WARNING, "Configuration file '%s' is invalid. CEL Beanstalkd Module not activated.\n",
179  CONF_FILE);
180  return -1;
181  } else if (!cfg) {
182  ast_log(LOG_WARNING, "Failed to load configuration file. CEL Beanstalkd Module not activated.\n");
183  if (enablecel) {
185  }
186  enablecel = 0;
187  return -1;
188  }
189 
190  if (reload) {
192  ast_free(bs_host);
193  ast_free(bs_tube);
194  }
195 
196  /* Bootstrap the default configuration */
201 
202  while ((cat = ast_category_browse(cfg, cat))) {
203 
204  if (strcasecmp(cat, "general")) {
205  continue;
206  }
207 
208  for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
209  if (!strcasecmp(v->name, "enabled")) {
210  newenablecel = ast_true(v->value) ? 1 : 0;
211  } else if (!strcasecmp(v->name, "host")) {
212  ast_free(bs_host);
213  bs_host = ast_strdup(v->value);
214  } else if (!strcasecmp(v->name, "port")) {
215  bs_port = atoi(v->value);
216  } else if (!strcasecmp(v->name, "tube")) {
217  ast_free(bs_tube);
218  bs_tube = ast_strdup(v->value);
219  } else if (!strcasecmp(v->name, "priority")) {
220  priority = atoi(v->value);
221  } else {
222  ast_log(LOG_NOTICE, "Unknown option '%s' specified "
223  "for CEL beanstalk backend.\n", v->name);
224  }
225  }
226  }
227 
228  if (reload) {
230  }
231 
232  ast_config_destroy(cfg);
233 
234  if (enablecel && !newenablecel) {
236  } else if (!enablecel && newenablecel) {
238  ast_log(LOG_ERROR, "Unable to register Beanstalkd CEL handling\n");
239  }
240  }
241 
242  enablecel = newenablecel;
243 
244  return 0;
245 }
246 
247 static int unload_module(void)
248 {
250  ast_free(bs_host);
251  ast_free(bs_tube);
252  return 0;
253 }
254 
255 static int load_module(void)
256 {
257  if (load_config(0)) {
259  }
260 
262 }
263 
264 static int reload(void)
265 {
266  return load_config(1);
267 }
268 
269 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Beanstalkd CEL Backend",
270  .support_level = AST_MODULE_SUPPORT_EXTENDED,
271  .load = load_module,
272  .unload = unload_module,
273  .reload = reload,
274  .load_pri = AST_MODPRI_CDR_DRIVER,
275  .requires = "cel",
276 );
const char * account_code
Definition: cel.h:161
struct ast_variable * next
const char * caller_id_name
Definition: cel.h:151
Helper struct for getting the fields out of a CEL event.
Definition: cel.h:136
#define ast_rwlock_rdlock(a)
Definition: lock.h:233
const char * linked_id
Definition: cel.h:164
An event.
Definition: event.c:81
Asterisk main include file. File version handling, generic pbx functions.
#define AST_RWLOCK_DEFINE_STATIC(rwlock)
Definition: lock.h:541
static int reload(void)
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:591
static const char CONF_FILE[]
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1216
Call Event Logging API.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
int ast_cel_backend_register(const char *name, ast_cel_backend_cb backend_callback)
Register a CEL backend.
Definition: cel.c:1740
static char * bs_host
#define CEL_BEANSTALK_ENABLED_DEFAULT
Beanstalk CEL is off by default.
#define LOG_WARNING
Definition: logger.h:274
const char * application_data
Definition: cel.h:160
const char * application_name
Definition: cel.h:159
#define CONFIG_STATUS_FILEINVALID
void ast_json_free(void *p)
Asterisk&#39;s custom JSON allocator. Exposed for use by unit tests.
Definition: json.c:52
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Definition: localtime.c:1739
#define CEL_BACKEND_NAME
Structure for variables, used for configurations and for channel variables.
const char * extension
Definition: cel.h:156
#define ast_json_dump_string(root)
Encode a JSON value to a compact string.
Definition: json.h:763
Definition: astman.c:222
const char * ast_channel_amaflags2string(enum ama_flags flags)
Convert the enum representation of an AMA flag to a string representation.
Definition: channel.c:4395
const char * caller_id_num
Definition: cel.h:152
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3328
#define NULL
Definition: resample.c:96
#define LOG_DEBUG
Definition: logger.h:241
#define ast_rwlock_unlock(a)
Definition: lock.h:232
const char * extra
Definition: cel.h:168
static int bs_port
#define DEFAULT_BEANSTALK_PORT
Utility functions.
Configuration File Parser.
static int priority
#define ast_log
Definition: astobj2.c:42
#define ast_config_load(filename, flags)
Load a config file.
General Asterisk PBX channel definitions.
Asterisk JSON abstraction layer.
const char * context
Definition: cel.h:157
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
uint32_t version
struct ABI version
Definition: cel.h:146
static char * bs_tube
int ast_cel_backend_unregister(const char *name)
Unregister a CEL backend.
Definition: cel.c:1728
#define CONFIG_STATUS_FILEUNCHANGED
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define LOG_ERROR
Definition: logger.h:285
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
const char * caller_id_rdnis
Definition: cel.h:154
#define LOG_NOTICE
Definition: logger.h:263
#define ast_free(a)
Definition: astmm.h:182
#define BEANSTALK_JOB_PRIORITY
static ast_rwlock_t config_lock
#define BEANSTALK_JOB_DELAY
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
Definition: localtime.c:2524
const char * caller_id_ani
Definition: cel.h:153
const char * user_field
Definition: cel.h:166
#define AST_CEL_EVENT_RECORD_VERSION
struct ABI version
Definition: cel.h:141
Structure used to handle boolean flags.
Definition: utils.h:199
static int enablecel
static int load_config(int reload)
Support for logging to various files, console and syslog Configuration in file logger.conf.
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
#define ast_rwlock_wrlock(a)
Definition: lock.h:234
const char * peer_account
Definition: cel.h:162
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
const char * unique_id
Definition: cel.h:163
#define BEANSTALK_JOB_TTR
Abstract JSON element (object, array, string, int, ...).
const char * caller_id_dnid
Definition: cel.h:155
const char * channel_name
Definition: cel.h:158
const char * event_name
Definition: cel.h:149
static int unload_module(void)
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
#define DEFAULT_BEANSTALK_HOST
Asterisk module definitions.
#define DEFAULT_BEANSTALK_TUBE
struct timeval event_time
Definition: cel.h:148
int ast_cel_fill_record(const struct ast_event *event, struct ast_cel_event_record *r)
Fill in an ast_cel_event_record from a CEL event.
Definition: cel.c:819
static int load_module(void)
static void cel_bs_put(struct ast_event *event)
static const char DATE_FORMAT[]