Asterisk - The Open Source Telephony Project  18.5.0
cel_custom.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2009, Digium, Inc.
5  *
6  * Steve Murphy <[email protected]>
7  * much borrowed from cdr code (cdr_custom.c), author Mark Spencer
8  *
9  * See http://www.asterisk.org for more information about
10  * the Asterisk project. Please do not directly contact
11  * any of the maintainers of this project for assistance;
12  * the project provides a web site, mailing lists and IRC
13  * channels for your use.
14  *
15  * This program is free software, distributed under the terms of
16  * the GNU General Public License Version 2. See the LICENSE file
17  * at the top of the source tree.
18  */
19 
20 /*! \file
21  *
22  * \brief Custom Comma Separated Value CEL records.
23  *
24  * \author Steve Murphy <[email protected]>
25  *
26  * \arg See also \ref AstCEL
27  *
28  * Logs in LOG_DIR/cel_custom
29  * \ingroup cel_drivers
30  */
31 
32 /*** MODULEINFO
33  <support_level>core</support_level>
34  ***/
35 
36 #include "asterisk.h"
37 
38 #include "asterisk/paths.h"
39 #include "asterisk/channel.h"
40 #include "asterisk/cel.h"
41 #include "asterisk/module.h"
42 #include "asterisk/config.h"
43 #include "asterisk/pbx.h"
44 #include "asterisk/utils.h"
45 #include "asterisk/lock.h"
46 #include "asterisk/threadstorage.h"
47 #include "asterisk/strings.h"
48 
49 #define CUSTOM_LOG_DIR "/cel_custom"
50 #define CONFIG "cel_custom.conf"
51 
53 
54 static const char name[] = "cel-custom";
55 
56 struct cel_config {
60  );
63 };
64 
65 #define CUSTOM_BACKEND_NAME "CEL Custom CSV Logging"
66 
68 
69 static void free_config(void)
70 {
71  struct cel_config *sink;
72 
73  while ((sink = AST_RWLIST_REMOVE_HEAD(&sinks, list))) {
74  ast_mutex_destroy(&sink->lock);
76  ast_free(sink);
77  }
78 }
79 
80 static int load_config(void)
81 {
82  struct ast_config *cfg;
83  struct ast_variable *var;
84  struct ast_flags config_flags = { 0 };
85  int mappings = 0;
86  int res = 0;
87 
88  cfg = ast_config_load(CONFIG, config_flags);
89  if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
90  ast_log(LOG_ERROR, "Unable to load " CONFIG ". Not logging CEL to custom CSVs.\n");
91  return -1;
92  }
93 
94  if (!(var = ast_variable_browse(cfg, "mappings"))) {
95  ast_log(LOG_NOTICE, "No mappings found in " CONFIG ". Not logging CEL to custom CSVs.\n");
96  }
97 
98  while (var) {
99  if (!ast_strlen_zero(var->name) && !ast_strlen_zero(var->value)) {
100  struct cel_config *sink = ast_calloc_with_stringfields(1, struct cel_config, 1024);
101 
102  if (!sink) {
103  ast_log(LOG_ERROR, "Unable to allocate memory for configuration settings.\n");
104  res = -2;
105  break;
106  }
107 
108  ast_string_field_build(sink, format, "%s\n", var->value);
110  ast_mutex_init(&sink->lock);
111 
112  ast_verb(3, "Added CEL CSV mapping for '%s'.\n", sink->filename);
113  mappings += 1;
114  AST_RWLIST_INSERT_TAIL(&sinks, sink, list);
115  } else {
116  ast_log(LOG_NOTICE, "Mapping must have both a filename and a format at line %d\n", var->lineno);
117  }
118  var = var->next;
119  }
120  ast_config_destroy(cfg);
121 
122  ast_verb(1, "Added CEL CSV mapping for %d files.\n", mappings);
123 
124  return res;
125 }
126 
127 static void custom_log(struct ast_event *event)
128 {
129  struct ast_channel *dummy;
130  struct ast_str *str;
131  struct cel_config *config;
132 
133  /* Batching saves memory management here. Otherwise, it's the same as doing an allocation and free each time. */
134  if (!(str = ast_str_thread_get(&custom_buf, 16))) {
135  return;
136  }
137 
139  if (!dummy) {
140  ast_log(LOG_ERROR, "Unable to fabricate channel from CEL event.\n");
141  return;
142  }
143 
145 
146  AST_LIST_TRAVERSE(&sinks, config, list) {
147  FILE *out;
148 
149  ast_str_substitute_variables(&str, 0, dummy, config->format);
150 
151  /* Even though we have a lock on the list, we could be being chased by
152  another thread and this lock ensures that we won't step on anyone's
153  toes. Once each CEL backend gets it's own thread, this lock can be
154  removed. */
155  ast_mutex_lock(&config->lock);
156 
157  /* Because of the absolutely unconditional need for the
158  highest reliability possible in writing billing records,
159  we open write and close the log file each time */
160  if ((out = fopen(config->filename, "a"))) {
161  fputs(ast_str_buffer(str), out);
162  fflush(out); /* be particularly anal here */
163  fclose(out);
164  } else {
165  ast_log(LOG_ERROR, "Unable to re-open master file %s : %s\n", config->filename, strerror(errno));
166  }
167 
168  ast_mutex_unlock(&config->lock);
169  }
170 
172 
173  ast_channel_unref(dummy);
174 }
175 
176 static int unload_module(void)
177 {
178 
179  if (AST_RWLIST_WRLOCK(&sinks)) {
180  ast_log(LOG_ERROR, "Unable to lock sink list. Unload failed.\n");
181  return -1;
182  }
183 
184  free_config();
187  return 0;
188 }
189 
191 {
192  if (AST_RWLIST_WRLOCK(&sinks)) {
193  ast_log(LOG_ERROR, "Unable to lock sink list. Load failed.\n");
195  }
196 
197  load_config();
199 
201  free_config();
203  }
205 }
206 
207 static int reload(void)
208 {
209  if (AST_RWLIST_WRLOCK(&sinks)) {
210  ast_log(LOG_ERROR, "Unable to lock sink list. Load failed.\n");
212  }
213 
214  free_config();
215  load_config();
218 }
219 
220 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Customizable Comma Separated Values CEL Backend",
221  .support_level = AST_MODULE_SUPPORT_CORE,
222  .load = load_module,
223  .unload = unload_module,
224  .reload = reload,
225  .load_pri = AST_MODPRI_CDR_DRIVER,
226  .requires = "cel",
227 );
struct ast_variable * next
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
Definition: threadstorage.h:84
ast_module_load_result
Definition: module.h:68
Main Channel structure associated with a channel.
static int reload(void)
Definition: cel_custom.c:207
An event.
Definition: event.c:81
A container that holds all config-related information.
Definition: cel_custom.c:56
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized...
Definition: linkedlists.h:332
String manipulation functions.
char * config
Definition: conf2ael.c:66
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2981
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1216
Call Event Logging API.
int ast_cel_backend_register(const char *name, ast_cel_backend_cb backend_callback)
Register a CEL backend.
Definition: cel.c:1740
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
#define CONFIG
Definition: cel_custom.c:50
static struct ast_threadstorage custom_buf
Definition: cel_custom.c:52
static enum ast_module_load_result load_module(void)
Definition: cel_custom.c:190
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
static void dummy(char *unused,...)
Definition: chan_unistim.c:220
#define CONFIG_STATUS_FILEINVALID
const ast_string_field filename
Definition: cel_custom.c:60
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
Structure for variables, used for configurations and for channel variables.
#define var
Definition: ast_expr2f.c:614
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
#define ast_calloc_with_stringfields(n, type, size)
Allocate a structure with embedded stringfields in a single allocation.
Definition: stringfields.h:426
Definition: astman.c:222
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:337
#define ast_mutex_lock(a)
Definition: lock.h:187
const char * str
Definition: app_jack.c:147
static const char name[]
Definition: cel_custom.c:54
Definitions to aid in the use of thread local storage.
#define ast_verb(level,...)
Definition: logger.h:463
Utility functions.
#define ast_strlen_zero(foo)
Definition: strings.h:52
Configuration File Parser.
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
#define ast_log
Definition: astobj2.c:42
#define ast_config_load(filename, flags)
Load a config file.
General Asterisk PBX channel definitions.
Asterisk file paths, configured in asterisk.conf.
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:299
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
Core PBX routines and definitions.
int ast_cel_backend_unregister(const char *name)
Unregister a CEL backend.
Definition: cel.c:1728
static int unload_module(void)
Definition: cel_custom.c:176
#define LOG_ERROR
Definition: logger.h:285
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
int errno
#define LOG_NOTICE
Definition: logger.h:263
const char * ast_config_AST_LOG_DIR
Definition: options.c:159
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define ast_free(a)
Definition: astmm.h:182
struct ast_channel * ast_cel_fabricate_channel_from_event(const struct ast_event *event)
Create a fake channel from data in a CEL event.
Definition: cel.c:660
#define CUSTOM_BACKEND_NAME
Definition: cel_custom.c:65
static void custom_log(struct ast_event *event)
Definition: cel_custom.c:127
static int load_config(void)
Definition: cel_custom.c:80
#define AST_RWLIST_REMOVE_HEAD
Definition: linkedlists.h:843
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
Definition: stringfields.h:550
Structure used to handle boolean flags.
Definition: utils.h:199
#define AST_RWLIST_ENTRY
Definition: linkedlists.h:414
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_RWLIST_INSERT_TAIL
Definition: linkedlists.h:740
FILE * out
Definition: utils/frame.c:33
#define ast_mutex_init(pmutex)
Definition: lock.h:184
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:861
#define ast_mutex_destroy(a)
Definition: lock.h:186
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:368
Structure for mutex and tracking information.
Definition: lock.h:135
const ast_string_field format
Definition: cel_custom.c:60
ast_mutex_t lock
Definition: cel_custom.c:61
static void free_config(void)
Definition: cel_custom.c:69
#define ast_mutex_unlock(a)
Definition: lock.h:188