Asterisk - The Open Source Telephony Project  18.5.0
cdr_mysql.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * James Sharp <[email protected]>
5  *
6  * Modified August 2003
7  * Tilghman Lesher <[email protected]>
8  *
9  * Modified August 6, 2005
10  * Joseph Benden <[email protected]>
11  * Added mysql connection timeout parameter
12  * Added an automatic reconnect as to not lose a cdr record
13  * Cleaned up the original code to match the coding guidelines
14  *
15  * Modified Juli 2006
16  * Martin Portmann <[email protected]>
17  * Added mysql ssl support
18  *
19  * See http://www.asterisk.org for more information about
20  * the Asterisk project. Please do not directly contact
21  * any of the maintainers of this project for assistance;
22  * the project provides a web site, mailing lists and IRC
23  * channels for your use.
24  *
25  * This program is free software, distributed under the terms of
26  * the GNU General Public License Version 2. See the LICENSE file
27  * at the top of the source tree.
28  */
29 
30 /*!
31  * \file
32  * \brief MySQL CDR backend
33  * \ingroup cdr_drivers
34  */
35 
36 /*** MODULEINFO
37  <depend>mysqlclient</depend>
38  <defaultenabled>no</defaultenabled>
39  <support_level>deprecated</support_level>
40  <replacement>cdr_adaptive_odbc</replacement>
41  ***/
42 
43 #include "asterisk.h"
44 
45 #include <mysql/mysql.h>
46 #include <mysql/errmsg.h>
47 
48 #include "asterisk/config.h"
49 #include "asterisk/options.h"
50 #include "asterisk/channel.h"
51 #include "asterisk/cdr.h"
52 #include "asterisk/module.h"
53 #include "asterisk/logger.h"
54 #include "asterisk/cli.h"
55 #include "asterisk/strings.h"
56 #include "asterisk/linkedlists.h"
57 #include "asterisk/threadstorage.h"
58 
59 #define DATE_FORMAT "%Y-%m-%d %T"
60 
61 #ifndef MYSQL_PORT
62 # ifdef MARIADB_PORT
63 # define MYSQL_PORT MARIADB_PORT
64 # else
65 # define MYSQL_PORT 3306
66 # endif
67 #endif
68 
72 
73 static const char desc[] = "MySQL CDR Backend";
74 static const char name[] = "mysql";
75 static const char config[] = "cdr_mysql.conf";
76 
78 
79 static struct ast_str *ssl_ca = NULL, *ssl_cert = NULL, *ssl_key = NULL;
80 
81 static int dbport = 0;
82 static int connected = 0;
83 static time_t connect_time = 0;
84 static int records = 0;
85 static int totalrecords = 0;
86 static int timeout = 0;
87 static int calldate_compat = 0;
88 
90 
91 struct unload_string {
93  struct ast_str *str;
94 };
95 
97 
98 struct column {
99  char *name;
100  char *cdrname;
101  char *staticvalue;
102  char *type;
104 };
105 
106 /* Protected with mysql_lock */
108 
109 static MYSQL mysql = { { NULL }, };
110 
111 static char *handle_cli_cdr_mysql_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
112 {
113  switch (cmd) {
114  case CLI_INIT:
115  e->command = "cdr mysql status";
116  e->usage =
117  "Usage: cdr mysql status\n"
118  " Shows current connection status for cdr_mysql\n";
119  return NULL;
120  case CLI_GENERATE:
121  return NULL;
122  }
123 
124  if (a->argc != 3)
125  return CLI_SHOWUSAGE;
126 
127  if (connected) {
128  char status[256];
129  char status2[100] = "";
130  char buf[362]; /* 256+100+" for "+NULL */
131  int ctime = time(NULL) - connect_time;
132  if (dbport)
133  snprintf(status, 255, "Connected to %s@%s, port %d", ast_str_buffer(dbname), ast_str_buffer(hostname), dbport);
134  else if (dbsock)
135  snprintf(status, 255, "Connected to %s on socket file %s", ast_str_buffer(dbname), S_OR(ast_str_buffer(dbsock), "default"));
136  else
137  snprintf(status, 255, "Connected to %s@%s", ast_str_buffer(dbname), ast_str_buffer(hostname));
138 
139  if (ast_str_strlen(dbuser))
140  snprintf(status2, 99, " with username %s", ast_str_buffer(dbuser));
141  if (ast_str_strlen(dbtable))
142  snprintf(status2, 99, " using table %s", ast_str_buffer(dbtable));
143 
144  snprintf(buf, sizeof(buf), "%s%s for ", status, status2);
145  ast_cli_print_timestr_fromseconds(a->fd, ctime, buf);
146 
147  if (records == totalrecords)
148  ast_cli(a->fd, " Wrote %d records since last restart.\n", totalrecords);
149  else
150  ast_cli(a->fd, " Wrote %d records since last restart and %d records since last reconnect.\n", totalrecords, records);
151  } else {
152  ast_cli(a->fd, "Not currently connected to a MySQL server.\n");
153  }
154 
155  return CLI_SUCCESS;
156 }
157 
159  AST_CLI_DEFINE(handle_cli_cdr_mysql_status, "Show connection status of cdr_mysql"),
160 };
161 
163 {
164  if (ast_str_strlen(dbcharset)) {
165  const char *charset = ast_str_buffer(dbcharset);
166  if (mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, charset)) {
167  ast_log(LOG_WARNING, "Failed to set connection charset. Data inserted might be invalid.\n");
168  }
169  }
170 }
171 
172 static int mysql_log(struct ast_cdr *cdr)
173 {
174  struct ast_str *sql1 = ast_str_thread_get(&sql1_buf, 1024), *sql2 = ast_str_thread_get(&sql2_buf, 1024);
175  int retries = 5;
176 #ifdef HAVE_MYSQLCLIENT_BOOL
177  bool my_bool_true = 1;
178 #elif HAVE_MYSQLCLIENT_MY_BOOL
179  my_bool my_bool_true = 1;
180 #endif
181 
182  if (!sql1 || !sql2) {
183  ast_log(LOG_ERROR, "Memory error\n");
184  return -1;
185  }
186 
188 
189 db_reconnect:
190  if ((!connected) && (hostname || dbsock) && dbuser && password && dbname && dbtable ) {
191  /* Attempt to connect */
192  mysql_init(&mysql);
193  /* Add option to quickly timeout the connection */
194  if (timeout && mysql_options(&mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *)&timeout) != 0) {
195  ast_log(LOG_ERROR, "mysql_options returned (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql));
196  }
197 #if MYSQL_VERSION_ID >= 50013
198  /* Add option for automatic reconnection */
199  if (mysql_options(&mysql, MYSQL_OPT_RECONNECT, &my_bool_true) != 0) {
200  ast_log(LOG_ERROR, "mysql_options returned (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql));
201  }
202 #endif
203  if (ssl_ca || ssl_cert || ssl_key) {
204  mysql_ssl_set(&mysql, ssl_key ? ast_str_buffer(ssl_key) : NULL, ssl_cert ? ast_str_buffer(ssl_cert) : NULL, ssl_ca ? ast_str_buffer(ssl_ca) : NULL, NULL, NULL);
205  }
206 
208 
209  if (mysql_real_connect(&mysql, ast_str_buffer(hostname), ast_str_buffer(dbuser), ast_str_buffer(password), ast_str_buffer(dbname), dbport, dbsock && ast_str_strlen(dbsock) ? ast_str_buffer(dbsock) : NULL, ssl_ca ? CLIENT_SSL : 0)) {
210  connected = 1;
211  connect_time = time(NULL);
212  records = 0;
213  } else {
214  ast_log(LOG_ERROR, "Cannot connect to database server %s: (%d) %s\n", ast_str_buffer(hostname), mysql_errno(&mysql), mysql_error(&mysql));
215  connected = 0;
216  }
217  } else {
218  /* Long connection - ping the server */
219  int error;
220  if ((error = mysql_ping(&mysql))) {
221  connected = 0;
222  records = 0;
223  switch (mysql_errno(&mysql)) {
224  case CR_SERVER_GONE_ERROR:
225  case CR_SERVER_LOST:
226  ast_log(LOG_ERROR, "Server has gone away. Attempting to reconnect.\n");
227  break;
228  default:
229  ast_log(LOG_ERROR, "Unknown connection error: (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql));
230  }
231  retries--;
232  if (retries) {
233  goto db_reconnect;
234  } else {
235  ast_log(LOG_ERROR, "Retried to connect five times, giving up.\n");
236  }
237  }
238  }
239 
240  if (connected) {
241  int column_count = 0;
242  char *cdrname;
243  char workspace[2048], *value = NULL;
244  struct column *entry;
245  struct ast_str *escape = ast_str_thread_get(&escape_buf, 16);
246 
247  ast_str_set(&sql1, 0, "INSERT INTO %s (", AS_OR(dbtable, "cdr"));
248  ast_str_set(&sql2, 0, ") VALUES (");
249 
251  AST_RWLIST_TRAVERSE(&columns, entry, list) {
252  if (!strcmp(entry->name, "calldate")) {
253  /*!\note
254  * For some dumb reason, "calldate" used to be formulated using
255  * the datetime the record was posted, rather than the start
256  * time of the call. If someone really wants the old compatible
257  * behavior, it's provided here.
258  */
259  if (calldate_compat) {
260  struct timeval tv = ast_tvnow();
261  struct ast_tm tm;
262  char timestr[128];
264  ast_strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);
265  value = ast_strdupa(timestr);
266  cdrname = "calldate";
267  } else {
268  cdrname = "start";
269  }
270  } else {
271  cdrname = entry->cdrname;
272  }
273 
274  /* Construct SQL */
275 
276  /* Need the type and value to determine if we want the raw value or not */
277  if (entry->staticvalue) {
278  value = ast_strdupa(entry->staticvalue);
279  } else if ((!strcmp(cdrname, "disposition") ||
280  !strcmp(cdrname, "amaflags")) &&
281  (strstr(entry->type, "int") ||
282  strstr(entry->type, "dec") ||
283  strstr(entry->type, "float") ||
284  strstr(entry->type, "double") ||
285  strstr(entry->type, "real") ||
286  strstr(entry->type, "numeric") ||
287  strstr(entry->type, "fixed"))) {
288  ast_cdr_format_var(cdr, cdrname, &value, workspace, sizeof(workspace), 1);
289  } else if (!strcmp(cdrname, "start") || !strcmp(cdrname, "answer") ||
290  !strcmp(cdrname, "end")) {
291  struct ast_tm tm;
292  char timestr[128];
294  ast_strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);
295  value = ast_strdupa(timestr);
296  } else if (!strcmp(cdrname, "calldate")) {
297  /* Skip calldate - the value has already been dup'd */
298  } else {
299  ast_cdr_format_var(cdr, cdrname, &value, workspace, sizeof(workspace), 0);
300  }
301 
302  if (value) {
303  size_t valsz;
304 
305  if (column_count++) {
306  ast_str_append(&sql1, 0, ",");
307  ast_str_append(&sql2, 0, ",");
308  }
309 
310  if (!strcasecmp(cdrname, "billsec") &&
311  (strstr(entry->type, "float") ||
312  strstr(entry->type, "double") ||
313  strstr(entry->type, "decimal") ||
314  strstr(entry->type, "numeric") ||
315  strstr(entry->type, "real"))) {
316 
317  if (!ast_tvzero(cdr->answer)) {
318  snprintf(workspace, sizeof(workspace), "%lf",
319  (double) (ast_tvdiff_us(cdr->end, cdr->answer) / 1000000.0));
320  } else {
321  ast_copy_string(workspace, "0", sizeof(workspace));
322  }
323 
324  if (!ast_strlen_zero(workspace)) {
325  value = workspace;
326  }
327  }
328 
329  if (!strcasecmp(cdrname, "duration") &&
330  (strstr(entry->type, "float") ||
331  strstr(entry->type, "double") ||
332  strstr(entry->type, "decimal") ||
333  strstr(entry->type, "numeric") ||
334  strstr(entry->type, "real"))) {
335 
336  snprintf(workspace, sizeof(workspace), "%lf",
337  (double) (ast_tvdiff_us(cdr->end, cdr->start) / 1000000.0));
338 
339  if (!ast_strlen_zero(workspace)) {
340  value = workspace;
341  }
342  }
343 
344  ast_str_make_space(&escape, (valsz = strlen(value)) * 2 + 1);
345  mysql_real_escape_string(&mysql, ast_str_buffer(escape), value, valsz);
346 
347  ast_str_append(&sql1, 0, "`%s`", entry->name);
348  ast_str_append(&sql2, 0, "'%s'", ast_str_buffer(escape));
349  }
350  }
352 
353  ast_debug(1, "Inserting a CDR record.\n");
354  ast_str_append(&sql1, 0, "%s)", ast_str_buffer(sql2));
355 
356  ast_debug(1, "SQL command as follows: %s\n", ast_str_buffer(sql1));
357 
358  if (mysql_real_query(&mysql, ast_str_buffer(sql1), ast_str_strlen(sql1))) {
359  ast_log(LOG_ERROR, "Failed to insert into database: (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql));
360  mysql_close(&mysql);
361  connected = 0;
362  } else {
363  records++;
364  totalrecords++;
365  }
366  }
368  return 0;
369 }
370 
371 static void free_strings(void)
372 {
373  struct unload_string *us;
374 
376  while ((us = AST_LIST_REMOVE_HEAD(&unload_strings, entry))) {
377  ast_free(us->str);
378  ast_free(us);
379  }
381 }
382 
383 static int my_unload_module(int reload)
384 {
385  struct column *entry;
386 
387  if (!reload) {
388  if (ast_cdr_unregister(name)) {
389  /* If we can't unregister the backend, we can't unload the module */
390  return -1;
391  }
392  }
393 
394  ast_cli_unregister_multiple(cdr_mysql_status_cli, sizeof(cdr_mysql_status_cli) / sizeof(struct ast_cli_entry));
395 
396  if (connected) {
397  mysql_close(&mysql);
398  connected = 0;
399  records = 0;
400  }
401 
402  free_strings();
403 
404  if (!reload) {
406  }
407  while ((entry = AST_RWLIST_REMOVE_HEAD(&columns, list))) {
408  ast_free(entry);
409  }
410  if (!reload) {
412  }
413 
414  dbport = 0;
415  if (reload) {
417  } else {
418  /* We unregistered earlier */
419  return 0;
420  }
421 }
422 
423 static int my_load_config_string(struct ast_config *cfg, const char *category, const char *variable, struct ast_str **field, const char *def)
424 {
425  struct unload_string *us;
426  const char *tmp;
427 
428  if (!(us = ast_calloc(1, sizeof(*us))))
429  return -1;
430 
431  if (!(*field = ast_str_create(16))) {
432  ast_free(us);
433  return -1;
434  }
435 
436  tmp = ast_variable_retrieve(cfg, category, variable);
437 
438  ast_str_set(field, 0, "%s", tmp ? tmp : def);
439 
440  us->str = *field;
441 
445 
446  return 0;
447 }
448 
449 static int my_load_config_number(struct ast_config *cfg, const char *category, const char *variable, int *field, int def)
450 {
451  const char *tmp;
452 
453  tmp = ast_variable_retrieve(cfg, category, variable);
454 
455  if (!tmp || sscanf(tmp, "%30d", field) < 1)
456  *field = def;
457 
458  return 0;
459 }
460 
461 /** Connect to MySQL. Initializes the connection.
462  *
463  * * Assumes the read-write lock for columns is held.
464  * * Caller should allocate and free cfg
465  * */
466 static int my_connect_db(struct ast_config *cfg)
467 {
468  struct ast_variable *var;
469  char *temp;
470  MYSQL_ROW row;
471  MYSQL_RES *result;
472  char sqldesc[128];
473 #ifdef HAVE_MYSQLCLIENT_BOOL
474  bool my_bool_true = 1;
475 #elif HAVE_MYSQLCLIENT_MY_BOOL
476  my_bool my_bool_true = 1;
477 #endif
478 
479  mysql_init(&mysql);
480 
481  if (timeout && mysql_options(&mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *)&timeout) != 0) {
482  ast_log(LOG_ERROR, "cdr_mysql: mysql_options returned (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql));
483  }
484 
485 #if MYSQL_VERSION_ID >= 50013
486  /* Add option for automatic reconnection */
487  if (mysql_options(&mysql, MYSQL_OPT_RECONNECT, &my_bool_true) != 0) {
488  ast_log(LOG_ERROR, "cdr_mysql: mysql_options returned (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql));
489  }
490 #endif
491 
492  if ((ssl_ca && ast_str_strlen(ssl_ca)) || (ssl_cert && ast_str_strlen(ssl_cert)) || (ssl_key && ast_str_strlen(ssl_key))) {
493  mysql_ssl_set(&mysql,
495  ssl_cert ? ast_str_buffer(ssl_cert) : NULL,
496  ssl_ca ? ast_str_buffer(ssl_ca) : NULL,
497  NULL, NULL);
498  }
500 
502 
503  if (!mysql_real_connect(&mysql, ast_str_buffer(hostname), ast_str_buffer(dbuser), ast_str_buffer(password), ast_str_buffer(dbname), dbport, temp, ssl_ca && ast_str_strlen(ssl_ca) ? CLIENT_SSL : 0)) {
504  ast_log(LOG_ERROR, "Failed to connect to mysql database %s on %s.\n", ast_str_buffer(dbname), ast_str_buffer(hostname));
505  connected = 0;
506  records = 0;
507 
508  return AST_MODULE_LOAD_SUCCESS; /* May be reconnected later */
509  }
510 
511  ast_debug(1, "Successfully connected to MySQL database.\n");
512  connected = 1;
513  records = 0;
514  connect_time = time(NULL);
515 
516  /* Get table description */
517  snprintf(sqldesc, sizeof(sqldesc), "DESC %s", dbtable ? ast_str_buffer(dbtable) : "cdr");
518  if (mysql_query(&mysql, sqldesc)) {
519  ast_log(LOG_ERROR, "Unable to query table description!! Logging disabled.\n");
520  mysql_close(&mysql);
521  connected = 0;
522 
524  }
525 
526  if (!(result = mysql_store_result(&mysql))) {
527  ast_log(LOG_ERROR, "Unable to query table description!! Logging disabled.\n");
528  mysql_close(&mysql);
529  connected = 0;
530 
532  }
533 
534  while ((row = mysql_fetch_row(result))) {
535  struct column *entry;
536  char *cdrvar = "", *staticvalue = "";
537 
538  ast_debug(1, "Got a field '%s' of type '%s'\n", row[0], row[1]);
539  /* Check for an alias or a static value */
540  for (var = ast_variable_browse(cfg, "columns"); var; var = var->next) {
541  if (strncmp(var->name, "alias", 5) == 0 && strcasecmp(var->value, row[0]) == 0 ) {
542  char *alias = ast_strdupa(var->name + 5);
543  cdrvar = ast_strip(alias);
544  ast_verb(3, "Found alias %s for column %s\n", cdrvar, row[0]);
545  break;
546  } else if (strncmp(var->name, "static", 6) == 0 && strcasecmp(var->value, row[0]) == 0) {
547  char *item = ast_strdupa(var->name + 6);
548  item = ast_strip(item);
549  if (item[0] == '"' && item[strlen(item) - 1] == '"') {
550  /* Remove surrounding quotes */
551  item[strlen(item) - 1] = '\0';
552  item++;
553  }
554  staticvalue = item;
555  }
556  }
557 
558  entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(row[0]) + 1 + strlen(cdrvar) + 1 + strlen(staticvalue) + 1 + strlen(row[1]) + 1);
559  if (!entry) {
560  ast_log(LOG_ERROR, "Out of memory creating entry for column '%s'\n", row[0]);
561  mysql_free_result(result);
563  }
564 
565  entry->name = (char *)entry + sizeof(*entry);
566  strcpy(entry->name, row[0]);
567 
568  if (!ast_strlen_zero(cdrvar)) {
569  entry->cdrname = entry->name + strlen(row[0]) + 1;
570  strcpy(entry->cdrname, cdrvar);
571  } else { /* Point to same place as the column name */
572  entry->cdrname = (char *)entry + sizeof(*entry);
573  }
574 
576  entry->staticvalue = entry->cdrname + strlen(entry->cdrname) + 1;
577  strcpy(entry->staticvalue, staticvalue);
578  ast_debug(1, "staticvalue length: %d\n", (int) strlen(staticvalue) );
579  entry->type = entry->staticvalue + strlen(entry->staticvalue) + 1;
580  } else {
581  entry->type = entry->cdrname + strlen(entry->cdrname) + 1;
582  }
583  strcpy(entry->type, row[1]);
584 
585  ast_debug(1, "Entry name '%s'\n", entry->name);
586  ast_debug(1, " cdrname '%s'\n", entry->cdrname);
587  ast_debug(1, " static '%s'\n", entry->staticvalue);
588  ast_debug(1, " type '%s'\n", entry->type);
589 
591  }
592  mysql_free_result(result);
593 
595 }
596 
597 static int my_load_module(int reload)
598 {
599  int res;
600  struct ast_config *cfg;
601  struct ast_variable *var;
602  /* CONFIG_STATUS_FILEUNCHANGED is impossible when config_flags is always 0,
603  * and it has to be zero, so a reload can be sent to tell the driver to
604  * rescan the table layout. */
605  struct ast_flags config_flags = { 0 };
606  struct column *entry;
607  struct ast_str *compat;
608 
609  /* Cannot use a conditionally different flag, because the table layout may
610  * have changed, which is not detectable by config file change detection,
611  * but should still cause the configuration to be re-parsed. */
612  cfg = ast_config_load(config, config_flags);
613  if (cfg == CONFIG_STATUS_FILEMISSING) {
614  ast_log(LOG_WARNING, "Unable to load config for mysql CDR's: %s\n", config);
616  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
617  ast_log(LOG_ERROR, "Unable to load configuration file '%s'\n", config);
619  }
620 
621  if (reload) {
623  my_unload_module(1);
624  }
625 
626  var = ast_variable_browse(cfg, "global");
627  if (!var) {
628  /* nothing configured */
629  if (reload) {
631  }
632  ast_config_destroy(cfg);
634  }
635 
636  res = 0;
637 
638  res |= my_load_config_string(cfg, "global", "hostname", &hostname, "localhost");
639  res |= my_load_config_string(cfg, "global", "dbname", &dbname, "astriskcdrdb");
640  res |= my_load_config_string(cfg, "global", "user", &dbuser, "root");
641  res |= my_load_config_string(cfg, "global", "sock", &dbsock, "");
642  res |= my_load_config_string(cfg, "global", "table", &dbtable, "cdr");
643  res |= my_load_config_string(cfg, "global", "password", &password, "");
644 
645  res |= my_load_config_string(cfg, "global", "charset", &dbcharset, "");
646 
647  res |= my_load_config_string(cfg, "global", "ssl_ca", &ssl_ca, "");
648  res |= my_load_config_string(cfg, "global", "ssl_cert", &ssl_cert, "");
649  res |= my_load_config_string(cfg, "global", "ssl_key", &ssl_key, "");
650 
651  res |= my_load_config_number(cfg, "global", "port", &dbport, MYSQL_PORT);
652  res |= my_load_config_number(cfg, "global", "timeout", &timeout, 0);
653  res |= my_load_config_string(cfg, "global", "compat", &compat, "no");
654  res |= my_load_config_string(cfg, "global", "cdrzone", &cdrzone, "");
655  if (ast_str_strlen(cdrzone) == 0) {
656  for (; var; var = var->next) {
657  if (!strcasecmp(var->name, "usegmtime") && ast_true(var->value)) {
658  ast_str_set(&cdrzone, 0, "UTC");
659  }
660  }
661  }
662 
663  if (ast_true(ast_str_buffer(compat))) {
664  calldate_compat = 1;
665  } else {
666  calldate_compat = 0;
667  }
668 
669  if (res < 0) {
670  if (reload) {
672  }
673  ast_config_destroy(cfg);
674  free_strings();
675 
677  }
678 
679  /* Check for any aliases */
680  if (!reload) {
681  /* Lock, if not already */
683  }
684  while ((entry = AST_LIST_REMOVE_HEAD(&columns, list))) {
685  ast_free(entry);
686  }
687 
688  ast_debug(1, "Got hostname of %s\n", ast_str_buffer(hostname));
689  ast_debug(1, "Got port of %d\n", dbport);
690  ast_debug(1, "Got a timeout of %d\n", timeout);
691  if (ast_str_strlen(dbsock)) {
692  ast_debug(1, "Got sock file of %s\n", ast_str_buffer(dbsock));
693  }
694  ast_debug(1, "Got user of %s\n", ast_str_buffer(dbuser));
695  ast_debug(1, "Got dbname of %s\n", ast_str_buffer(dbname));
696  ast_debug(1, "Got password of %s\n", ast_str_buffer(password));
697  ast_debug(1, "%sunning in calldate compatibility mode\n", calldate_compat ? "R" : "Not r");
698  ast_debug(1, "Dates and times are localized to %s\n", S_OR(ast_str_buffer(cdrzone), "local timezone"));
699 
700  if (ast_str_strlen(dbcharset)) {
701  ast_debug(1, "Got DB charset of %s\n", ast_str_buffer(dbcharset));
702  }
703 
704  res = my_connect_db(cfg);
706  ast_config_destroy(cfg);
707  if (res != AST_MODULE_LOAD_SUCCESS) {
708  my_unload_module(0);
709  return res;
710  }
711 
712  if (!reload) {
714  } else {
716  }
717  if (res) {
718  ast_log(LOG_ERROR, "Unable to register MySQL CDR handling\n");
719  } else {
720  res = ast_cli_register_multiple(cdr_mysql_status_cli, sizeof(cdr_mysql_status_cli) / sizeof(struct ast_cli_entry));
721  }
722 
723  if (res) {
724  my_unload_module(0);
726  }
727 
729 }
730 
731 static int load_module(void)
732 {
733  return my_load_module(0);
734 }
735 
736 static int unload_module(void)
737 {
738  return my_unload_module(0);
739 }
740 
741 static int reload(void)
742 {
743  int ret;
744 
746  ret = my_load_module(1);
748 
749  return ret;
750 }
751 
753  .support_level = AST_MODULE_SUPPORT_DEPRECATED,
754  .load = load_module,
755  .unload = unload_module,
756  .reload = reload,
757  .requires = "cdr",
758 );
struct ast_variable * next
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
Definition: threadstorage.h:84
int ast_cdr_backend_suspend(const char *name)
Suspend a CDR backend temporarily.
Definition: cdr.c:2866
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
static int records
Definition: cdr_mysql.c:84
static struct ast_str * ssl_cert
Definition: cdr_mysql.c:79
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
char * cdrname
Definition: cdr_mysql.c:100
Asterisk main include file. File version handling, generic pbx functions.
int ast_cdr_unregister(const char *name)
Unregister a CDR handling engine.
Definition: cdr.c:2988
#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
static int my_load_config_number(struct ast_config *cfg, const char *category, const char *variable, int *field, int def)
Definition: cdr_mysql.c:449
String manipulation functions.
struct ast_str * str
Definition: cdr_mysql.c:93
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
static int calldate_compat
Definition: cdr_mysql.c:87
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1216
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
descriptor for a cli entry.
Definition: cli.h:171
const int argc
Definition: cli.h:160
#define LOG_WARNING
Definition: logger.h:274
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
#define ast_str_make_space(buf, new_len)
Definition: strings.h:780
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
int ast_cdr_backend_unsuspend(const char *name)
Unsuspend a CDR backend.
Definition: cdr.c:2884
#define CONFIG_STATUS_FILEINVALID
static int timeout
Definition: cdr_mysql.c:86
static int tmp()
Definition: bt_open.c:389
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
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
Structure for variables, used for configurations and for channel variables.
#define var
Definition: ast_expr2f.c:614
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition: time.h:108
#define DATE_FORMAT
Definition: cdr_mysql.c:59
static ast_mutex_t mysql_lock
Definition: cdr_mysql.c:89
Definition: cli.h:152
static const char desc[]
Definition: cdr_mysql.c:73
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1091
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
static struct aco_type item
Definition: test_config.c:1463
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
#define MYSQL_PORT
Definition: cdr_mysql.c:65
#define ast_mutex_lock(a)
Definition: lock.h:187
#define NULL
Definition: resample.c:96
Definitions to aid in the use of thread local storage.
int value
Definition: syslog.c:37
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
char * staticvalue
Definition: cdr_mysql.c:101
static struct ast_str * ssl_ca
Definition: cdr_mysql.c:79
static struct ast_str * password
Definition: cdr_mysql.c:77
#define ast_verb(level,...)
Definition: logger.h:463
static struct ast_str * dbtable
Definition: cdr_mysql.c:77
static struct ast_str * dbcharset
Definition: cdr_mysql.c:77
#define ast_strlen_zero(foo)
Definition: strings.h:52
static struct ast_threadstorage sql2_buf
Definition: cdr_mysql.c:70
Call Detail Record API.
void ast_cdr_format_var(struct ast_cdr *cdr, const char *name, char **ret, char *workspace, int workspacelen, int raw)
Format a CDR variable from an already posted CDR.
Definition: cdr.c:3050
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1065
Configuration File Parser.
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
char * type
Definition: cdr_mysql.c:102
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
#define ast_config_load(filename, flags)
Load a config file.
int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be)
Register a CDR handling engine.
Definition: cdr.c:2943
static struct ast_cli_entry cdr_mysql_status_cli[]
Definition: cdr_mysql.c:158
General Asterisk PBX channel definitions.
struct column::@3 list
const int fd
Definition: cli.h:159
static char * handle_cli_cdr_mysql_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: cdr_mysql.c:111
static int my_load_config_string(struct ast_config *cfg, const char *category, const char *variable, struct ast_str **field, const char *def)
Definition: cdr_mysql.c:423
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:219
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static int load_module(void)
Definition: cdr_mysql.c:731
A set of macros to manage forward-linked lists.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
#define AST_LIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
Definition: linkedlists.h:290
struct timeval answer
Definition: cdr.h:296
Responsible for call detail data.
Definition: cdr.h:276
static time_t connect_time
Definition: cdr_mysql.c:83
#define LOG_ERROR
Definition: logger.h:285
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
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
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
#define CLI_SHOWUSAGE
Definition: cli.h:45
static struct ast_str * ssl_key
Definition: cdr_mysql.c:79
static void configure_connection_charset(void)
Definition: cdr_mysql.c:162
static struct ast_threadstorage sql1_buf
Definition: cdr_mysql.c:69
static int totalrecords
Definition: cdr_mysql.c:85
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:409
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:710
struct timeval start
Definition: cdr.h:294
static struct ast_str * dbname
Definition: cdr_mysql.c:77
static const char name[]
Definition: cdr_mysql.c:74
#define ast_free(a)
Definition: astmm.h:182
char * command
Definition: cli.h:186
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
static int reload(void)
Definition: cdr_mysql.c:741
static int mysql_log(struct ast_cdr *cdr)
Definition: cdr_mysql.c:172
static int my_unload_module(int reload)
Definition: cdr_mysql.c:383
#define AST_RWLIST_REMOVE_HEAD
Definition: linkedlists.h:843
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
charset
Definition: chan_unistim.c:336
struct unload_string::@2 entry
Structure used to handle boolean flags.
Definition: utils.h:199
static int my_connect_db(struct ast_config *cfg)
Definition: cdr_mysql.c:466
static struct ast_threadstorage escape_buf
Definition: cdr_mysql.c:71
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",)
const char * usage
Definition: cli.h:177
void ast_cli_print_timestr_fromseconds(int fd, int seconds, const char *prefix)
Print on cli a duration in seconds in format s year(s), s week(s), s day(s), s hour(s), s second(s)
Definition: main/cli.c:3021
#define CONFIG_STATUS_FILEMISSING
#define CLI_SUCCESS
Definition: cli.h:44
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:694
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:688
static int connected
Definition: cdr_mysql.c:82
struct timeval end
Definition: cdr.h:298
static struct ast_str * dbsock
Definition: cdr_mysql.c:77
#define AS_OR(a, b)
Definition: strings.h:49
Standard Command Line Interface.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
#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
static const char config[]
Definition: cdr_mysql.c:75
static struct ast_str * dbuser
Definition: cdr_mysql.c:77
char * name
Definition: cdr_mysql.c:99
static struct ast_str * cdrzone
Definition: cdr_mysql.c:77
static PGresult * result
Definition: cel_pgsql.c:88
static struct ast_str * hostname
Definition: cdr_mysql.c:77
static int dbport
Definition: cdr_mysql.c:81
Options provided by main asterisk program.
Definition: search.h:40
int error(const char *format,...)
Definition: utils/frame.c:999
int64_t ast_tvdiff_us(struct timeval end, struct timeval start)
Computes the difference (in microseconds) between two struct timeval instances.
Definition: time.h:78
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 ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
static MYSQL mysql
Definition: cdr_mysql.c:109
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:518
static int unload_module(void)
Definition: cdr_mysql.c:736
jack_status_t status
Definition: app_jack.c:146
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620
#define ast_mutex_unlock(a)
Definition: lock.h:188
static void free_strings(void)
Definition: cdr_mysql.c:371
static struct test_val a
static int my_load_module(int reload)
Definition: cdr_mysql.c:597