Wed Jan 8 2020 09:49:59

Asterisk developer's documentation


cdr_tds.c File Reference

FreeTDS CDR logger. More...

#include "asterisk.h"
#include "asterisk/config.h"
#include "asterisk/channel.h"
#include "asterisk/cdr.h"
#include "asterisk/module.h"
#include <sqlfront.h>
#include <sybdb.h>

Go to the source code of this file.

Data Structures

struct  cdr_tds_config
 

Macros

#define DATE_FORMAT   "%Y/%m/%d %T"
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
static char * anti_injection (const char *, int)
 
static int execute_and_consume (DBPROCESS *dbproc, const char *fmt,...)
 
static void get_date (char *, size_t len, struct timeval)
 
static int load_module (void)
 
static int mssql_connect (void)
 
static int mssql_disconnect (void)
 
static int reload (void)
 
static int tds_error_handler (DBPROCESS *dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr)
 
static int tds_load_module (int reload)
 
static int tds_log (struct ast_cdr *cdr)
 
static int tds_message_handler (DBPROCESS *dbproc, DBINT msgno, int msgstate, int severity, char *msgtext, char *srvname, char *procname, int line)
 
static int tds_unload_module (void)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "FreeTDS CDR Backend" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CDR_DRIVER, }
 
static struct ast_module_infoast_module_info = &__mod_info
 
static const char config [] = "cdr_tds.conf"
 
static const char name [] = "FreeTDS (MSSQL)"
 
static struct cdr_tds_configsettings
 
static ast_mutex_t tds_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 }
 

Detailed Description

FreeTDS CDR logger.

See also

Definition in file cdr_tds.c.

Macro Definition Documentation

#define DATE_FORMAT   "%Y/%m/%d %T"
 *
 * Table Structure for `cdr`
 *
 * Created on: 05/20/2004 16:16
 * Last changed on: 07/27/2004 20:01

CREATE TABLE [dbo].[cdr] (
   [accountcode] [varchar] (20) NULL ,
   [src] [varchar] (80) NULL ,
   [dst] [varchar] (80) NULL ,
   [dcontext] [varchar] (80) NULL ,
   [clid] [varchar] (80) NULL ,
   [channel] [varchar] (80) NULL ,
   [dstchannel] [varchar] (80) NULL ,
   [lastapp] [varchar] (80) NULL ,
   [lastdata] [varchar] (80) NULL ,
   [start] [datetime] NULL ,
   [answer] [datetime] NULL ,
   [end] [datetime] NULL ,
   [duration] [int] NULL ,
   [billsec] [int] NULL ,
   [disposition] [varchar] (20) NULL ,
   [amaflags] [varchar] (16) NULL ,
   [uniqueid] [varchar] (32) NULL ,
   [userfield] [varchar] (256) NULL
) ON [PRIMARY]

Definition at line 77 of file cdr_tds.c.

Referenced by get_date().

Function Documentation

static void __reg_module ( void  )
static

Definition at line 637 of file cdr_tds.c.

static void __unreg_module ( void  )
static

Definition at line 637 of file cdr_tds.c.

static char * anti_injection ( const char *  str,
int  len 
)
static

Definition at line 304 of file cdr_tds.c.

References ast_calloc, ast_log(), len(), LOG_ERROR, str, and strcasestr().

Referenced by tds_log().

305 {
306  /* Reference to http://www.nextgenss.com/papers/advanced_sql_injection.pdf */
307  char *buf;
308  char *buf_ptr, *srh_ptr;
309  char *known_bad[] = {"select", "insert", "update", "delete", "drop", ";", "--", "\0"};
310  int idx;
311 
312  if (!(buf = ast_calloc(1, len + 1))) {
313  ast_log(LOG_ERROR, "Out of memory\n");
314  return NULL;
315  }
316 
317  buf_ptr = buf;
318 
319  /* Escape single quotes */
320  for (; *str && strlen(buf) < len; str++) {
321  if (*str == '\'') {
322  *buf_ptr++ = '\'';
323  }
324  *buf_ptr++ = *str;
325  }
326  *buf_ptr = '\0';
327 
328  /* Erase known bad input */
329  for (idx = 0; *known_bad[idx]; idx++) {
330  while ((srh_ptr = strcasestr(buf, known_bad[idx]))) {
331  memmove(srh_ptr, srh_ptr + strlen(known_bad[idx]), strlen(srh_ptr + strlen(known_bad[idx])) + 1);
332  }
333  }
334 
335  return buf;
336 }
const char * str
Definition: app_jack.c:144
#define LOG_ERROR
Definition: logger.h:155
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ast_calloc(a, b)
Definition: astmm.h:82
char * strcasestr(const char *, const char *)
static int execute_and_consume ( DBPROCESS *  dbproc,
const char *  fmt,
  ... 
)
static

Definition at line 350 of file cdr_tds.c.

References ast_free, and ast_vasprintf.

Referenced by mssql_connect().

351 {
352  va_list ap;
353  char *buffer;
354 
355  va_start(ap, fmt);
356  if (ast_vasprintf(&buffer, fmt, ap) < 0) {
357  va_end(ap);
358  return 1;
359  }
360  va_end(ap);
361 
362  if (dbfcmd(dbproc, buffer) == FAIL) {
363  ast_free(buffer);
364  return 1;
365  }
366 
367  ast_free(buffer);
368 
369  if (dbsqlexec(dbproc) == FAIL) {
370  return 1;
371  }
372 
373  /* Consume the result set (we don't really care about the result, though) */
374  while (dbresults(dbproc) != NO_MORE_RESULTS) {
375  while (dbnextrow(dbproc) != NO_MORE_ROWS);
376  }
377 
378  return 0;
379 }
#define ast_vasprintf(a, b, c)
Definition: astmm.h:127
#define ast_free(a)
Definition: astmm.h:97
static void get_date ( char *  dateField,
size_t  len,
struct timeval  when 
)
static

Definition at line 338 of file cdr_tds.c.

References ast_copy_string(), ast_localtime(), ast_strftime(), ast_tvzero(), and DATE_FORMAT.

Referenced by tds_log().

339 {
340  /* To make sure we have date variable if not insert null to SQL */
341  if (!ast_tvzero(when)) {
342  struct ast_tm tm;
343  ast_localtime(&when, &tm, NULL);
344  ast_strftime(dateField, len, "'" DATE_FORMAT "'", &tm);
345  } else {
346  ast_copy_string(dateField, "null", len);
347  }
348 }
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:1570
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition: time.h:100
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define DATE_FORMAT
Definition: cdr_tds.c:77
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:2351
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
static int load_module ( void  )
static

Definition at line 597 of file cdr_tds.c.

References ast_calloc_with_stringfields, ast_cdr_register(), ast_free, ast_log(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_string_field_free_memory, dbinit(), ast_module_info::description, LOG_ERROR, tds_error_handler(), tds_load_module(), tds_log(), and tds_message_handler().

598 {
599  if (dbinit() == FAIL) {
600  ast_log(LOG_ERROR, "Failed to initialize FreeTDS db-lib\n");
602  }
603 
604  dberrhandle(tds_error_handler);
605  dbmsghandle(tds_message_handler);
606 
608 
609  if (!settings) {
610  dbexit();
612  }
613 
614  if (!tds_load_module(0)) {
617  settings = NULL;
618  dbexit();
620  }
621 
623 
625 }
const char * description
Definition: module.h:234
static int tds_log(struct ast_cdr *cdr)
Definition: cdr_tds.c:111
#define ast_calloc_with_stringfields(n, type, size)
Allocate a structure with embedded stringfields in a single allocation.
Definition: stringfields.h:275
static int dbinit(void)
Definition: db.c:118
int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be)
Register a CDR handling engine.
Definition: cdr.c:130
#define LOG_ERROR
Definition: logger.h:155
static int tds_error_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr)
Definition: cdr_tds.c:462
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static const char name[]
#define ast_free(a)
Definition: astmm.h:97
static int tds_load_module(int reload)
Definition: cdr_tds.c:481
static struct cdr_tds_config * settings
Definition: cdr_tds.c:100
static int tds_message_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, int severity, char *msgtext, char *srvname, char *procname, int line)
Definition: cdr_tds.c:473
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:253
static int mssql_connect ( void  )
static

Definition at line 393 of file cdr_tds.c.

References ast_log(), cdr_tds_config::charset, cdr_tds_config::connected, cdr_tds_config::database, cdr_tds_config::dbproc, execute_and_consume(), cdr_tds_config::has_userfield, cdr_tds_config::hostname, cdr_tds_config::language, LOG_ERROR, LOG_NOTICE, cdr_tds_config::password, cdr_tds_config::table, and cdr_tds_config::username.

Referenced by tds_load_module(), and tds_log().

394 {
395  LOGINREC *login;
396 
397  if ((login = dblogin()) == NULL) {
398  ast_log(LOG_ERROR, "Unable to allocate login structure for db-lib\n");
399  return -1;
400  }
401 
402  DBSETLAPP(login, "TSQL");
403  DBSETLUSER(login, (char *) settings->username);
404  DBSETLPWD(login, (char *) settings->password);
405  DBSETLCHARSET(login, (char *) settings->charset);
406  DBSETLNATLANG(login, (char *) settings->language);
407 
408  if ((settings->dbproc = dbopen(login, (char *) settings->hostname)) == NULL) {
409  ast_log(LOG_ERROR, "Unable to connect to %s\n", settings->hostname);
410  dbloginfree(login);
411  return -1;
412  }
413 
414  dbloginfree(login);
415 
416  if (dbuse(settings->dbproc, (char *) settings->database) == FAIL) {
417  ast_log(LOG_ERROR, "Unable to select database %s\n", settings->database);
418  goto failed;
419  }
420 
421  if (execute_and_consume(settings->dbproc, "SELECT 1 FROM [%s] WHERE 1 = 0", settings->table)) {
422  ast_log(LOG_ERROR, "Unable to find table '%s'\n", settings->table);
423  goto failed;
424  }
425 
426  /* Check to see if we have a userfield column in the table */
427  if (execute_and_consume(settings->dbproc, "SELECT userfield FROM [%s] WHERE 1 = 0", settings->table)) {
428  ast_log(LOG_NOTICE, "Unable to find 'userfield' column in table '%s'\n", settings->table);
429  settings->has_userfield = 0;
430  } else {
431  settings->has_userfield = 1;
432  }
433 
434  settings->connected = 1;
435 
436  return 0;
437 
438 failed:
439  dbclose(settings->dbproc);
440  settings->dbproc = NULL;
441  return -1;
442 }
const ast_string_field hostname
Definition: cdr_tds.c:92
const ast_string_field table
Definition: cdr_tds.c:92
DBPROCESS * dbproc
Definition: cdr_tds.c:93
const ast_string_field language
Definition: cdr_tds.c:92
static int execute_and_consume(DBPROCESS *dbproc, const char *fmt,...)
Definition: cdr_tds.c:350
unsigned int connected
Definition: cdr_tds.c:94
unsigned int has_userfield
Definition: cdr_tds.c:95
#define LOG_ERROR
Definition: logger.h:155
const ast_string_field username
Definition: cdr_tds.c:92
const ast_string_field password
Definition: cdr_tds.c:92
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define LOG_NOTICE
Definition: logger.h:133
const ast_string_field charset
Definition: cdr_tds.c:92
const ast_string_field database
Definition: cdr_tds.c:92
static struct cdr_tds_config * settings
Definition: cdr_tds.c:100
static int mssql_disconnect ( void  )
static

Definition at line 381 of file cdr_tds.c.

References cdr_tds_config::connected, and cdr_tds_config::dbproc.

Referenced by tds_load_module(), tds_log(), and tds_unload_module().

382 {
383  if (settings->dbproc) {
384  dbclose(settings->dbproc);
385  settings->dbproc = NULL;
386  }
387 
388  settings->connected = 0;
389 
390  return 0;
391 }
DBPROCESS * dbproc
Definition: cdr_tds.c:93
unsigned int connected
Definition: cdr_tds.c:94
static struct cdr_tds_config * settings
Definition: cdr_tds.c:100
static int reload ( void  )
static

Definition at line 592 of file cdr_tds.c.

References tds_load_module().

593 {
594  return tds_load_module(1);
595 }
static int tds_load_module(int reload)
Definition: cdr_tds.c:481
static int tds_error_handler ( DBPROCESS *  dbproc,
int  severity,
int  dberr,
int  oserr,
char *  dberrstr,
char *  oserrstr 
)
static

Definition at line 462 of file cdr_tds.c.

References ast_log(), and LOG_ERROR.

Referenced by load_module().

463 {
464  ast_log(LOG_ERROR, "%s (%d)\n", dberrstr, dberr);
465 
466  if (oserr != DBNOERR) {
467  ast_log(LOG_ERROR, "%s (%d)\n", oserrstr, oserr);
468  }
469 
470  return INT_CANCEL;
471 }
#define LOG_ERROR
Definition: logger.h:155
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static int tds_load_module ( int  reload)
static

Definition at line 481 of file cdr_tds.c.

References ast_config_destroy(), ast_config_load, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_string_field_init, ast_string_field_set, ast_true(), ast_variable_browse(), ast_variable_retrieve(), charset, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, hostname, language, LOG_ERROR, LOG_NOTICE, mssql_connect(), mssql_disconnect(), table, and tds_lock.

Referenced by load_module(), and reload().

482 {
483  struct ast_config *cfg;
484  const char *ptr = NULL;
485  struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
486 
487  cfg = ast_config_load(config, config_flags);
488  if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
489  ast_log(LOG_NOTICE, "Unable to load TDS config for CDRs: %s\n", config);
490  return 0;
491  } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
492  return 0;
493 
494  if (!ast_variable_browse(cfg, "global")) {
495  /* nothing configured */
496  ast_config_destroy(cfg);
497  return 0;
498  }
499 
501 
502  /* Clear out any existing settings */
504 
505  /* 'connection' is the new preferred configuration option */
506  ptr = ast_variable_retrieve(cfg, "global", "connection");
507  if (ptr) {
509  } else {
510  /* But we keep 'hostname' for backwards compatibility */
511  ptr = ast_variable_retrieve(cfg, "global", "hostname");
512  if (ptr) {
514  } else {
515  ast_log(LOG_ERROR, "Failed to connect: Database server connection not specified.\n");
516  goto failed;
517  }
518  }
519 
520  ptr = ast_variable_retrieve(cfg, "global", "dbname");
521  if (ptr) {
522  ast_string_field_set(settings, database, ptr);
523  } else {
524  ast_log(LOG_ERROR, "Failed to connect: Database dbname not specified.\n");
525  goto failed;
526  }
527 
528  ptr = ast_variable_retrieve(cfg, "global", "user");
529  if (ptr) {
530  ast_string_field_set(settings, username, ptr);
531  } else {
532  ast_log(LOG_ERROR, "Failed to connect: Database dbuser not specified.\n");
533  goto failed;
534  }
535 
536  ptr = ast_variable_retrieve(cfg, "global", "password");
537  if (ptr) {
538  ast_string_field_set(settings, password, ptr);
539  } else {
540  ast_log(LOG_ERROR, "Failed to connect: Database password not specified.\n");
541  goto failed;
542  }
543 
544  ptr = ast_variable_retrieve(cfg, "global", "charset");
545  if (ptr) {
547  } else {
549  }
550 
551  ptr = ast_variable_retrieve(cfg, "global", "language");
552  if (ptr) {
554  } else {
555  ast_string_field_set(settings, language, "us_english");
556  }
557 
558  ptr = ast_variable_retrieve(cfg, "global", "table");
559  if (ptr) {
561  } else {
562  ast_log(LOG_NOTICE, "Table name not specified, using 'cdr' by default.\n");
564  }
565 
566  ptr = ast_variable_retrieve(cfg, "global", "hrtime");
567  if (ptr && ast_true(ptr)) {
568  ast_string_field_set(settings, hrtime, ptr);
569  } else {
570  ast_log(LOG_NOTICE, "High Resolution Time not found, using integers for billsec and duration fields by default.\n");
571  }
572 
574 
575  if (mssql_connect()) {
576  /* We failed to connect (mssql_connect takes care of logging it) */
577  goto failed;
578  }
579 
581  ast_config_destroy(cfg);
582 
583  return 1;
584 
585 failed:
587  ast_config_destroy(cfg);
588 
589  return 0;
590 }
const char * ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
Gets a variable.
Definition: config.c:625
static const char config[]
Definition: cdr_tds.c:80
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category)
Goes through variables.
Definition: config.c:597
static ast_mutex_t tds_lock
Definition: cdr_tds.c:98
#define ast_mutex_lock(a)
Definition: lock.h:155
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: config.c:1037
static int mssql_connect(void)
Definition: cdr_tds.c:393
static char * table
Definition: cdr_odbc.c:50
static int reload(void)
Definition: cdr_tds.c:592
static int mssql_disconnect(void)
Definition: cdr_tds.c:381
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:249
#define ast_config_load(filename, flags)
Load a config file.
Definition: config.h:170
static char language[MAX_LANGUAGE]
Definition: chan_alsa.c:108
#define LOG_ERROR
Definition: logger.h:155
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is &quot;true&quot;. This function checks to see whether a string passed to it is an indication of an &quot;true&quot; value. It checks to see if the string is &quot;yes&quot;, &quot;true&quot;, &quot;y&quot;, &quot;t&quot;, &quot;on&quot; or &quot;1&quot;.
Definition: utils.c:1533
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define LOG_NOTICE
Definition: logger.h:133
Structure used to handle boolean flags.
Definition: utils.h:200
static char charset[32]
#define CONFIG_STATUS_FILEINVALID
Definition: config.h:52
static struct cdr_tds_config * settings
Definition: cdr_tds.c:100
#define CONFIG_STATUS_FILEUNCHANGED
Definition: config.h:51
#define ast_mutex_unlock(a)
Definition: lock.h:156
static char hostname[MAXHOSTNAMELEN]
Definition: logger.c:91
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:344
static int tds_log ( struct ast_cdr cdr)
static

Definition at line 111 of file cdr_tds.c.

References accountcode, anti_injection(), ast_cdr_disp2str(), ast_cdr_flags2str(), ast_free, ast_log(), AST_MAX_USER_FIELD, ast_mutex_lock, ast_mutex_unlock, ast_tvdiff_us(), ast_tvzero(), cdr_tds_config::connected, cdr_tds_config::dbproc, get_date(), cdr_tds_config::has_userfield, cdr_tds_config::hostname, cdr_tds_config::hrtime, LOG_ERROR, LOG_NOTICE, mssql_connect(), mssql_disconnect(), cdr_tds_config::table, and tds_lock.

Referenced by load_module().

112 {
113  char start[80], answer[80], end[80];
114  char *accountcode, *src, *dst, *dcontext, *clid, *channel, *dstchannel, *lastapp, *lastdata, *uniqueid, *userfield = NULL;
115  RETCODE erc;
116  int res = -1;
117  int attempt = 1;
118 
119  accountcode = anti_injection(cdr->accountcode, 20);
120  src = anti_injection(cdr->src, 80);
121  dst = anti_injection(cdr->dst, 80);
122  dcontext = anti_injection(cdr->dcontext, 80);
123  clid = anti_injection(cdr->clid, 80);
124  channel = anti_injection(cdr->channel, 80);
125  dstchannel = anti_injection(cdr->dstchannel, 80);
126  lastapp = anti_injection(cdr->lastapp, 80);
127  lastdata = anti_injection(cdr->lastdata, 80);
128  uniqueid = anti_injection(cdr->uniqueid, 32);
129 
130  get_date(start, sizeof(start), cdr->start);
131  get_date(answer, sizeof(answer), cdr->answer);
132  get_date(end, sizeof(end), cdr->end);
133 
135 
136  if (settings->has_userfield) {
137  userfield = anti_injection(cdr->userfield, AST_MAX_USER_FIELD);
138  }
139 
140 retry:
141  /* Ensure that we are connected */
142  if (!settings->connected) {
143  ast_log(LOG_NOTICE, "Attempting to reconnect to %s (Attempt %d)\n", settings->hostname, attempt);
144  if (mssql_connect()) {
145  /* Connect failed */
146  if (attempt++ < 3) {
147  goto retry;
148  }
149  goto done;
150  }
151  }
152 
153  if (settings->has_userfield) {
154  if (settings->hrtime) {
155  double hrbillsec = 0.0;
156  double hrduration;
157 
158  if (!ast_tvzero(cdr->answer)) {
159  hrbillsec = (double)(ast_tvdiff_us(cdr->end, cdr->answer) / 1000000.0);
160  }
161  hrduration = (double)(ast_tvdiff_us(cdr->end, cdr->start) / 1000000.0);
162 
163  erc = dbfcmd(settings->dbproc,
164  "INSERT INTO %s "
165  "("
166  "accountcode, src, dst, dcontext, clid, channel, "
167  "dstchannel, lastapp, lastdata, start, answer, [end], duration, "
168  "billsec, disposition, amaflags, uniqueid, userfield"
169  ") "
170  "VALUES "
171  "("
172  "'%s', '%s', '%s', '%s', '%s', '%s', "
173  "'%s', '%s', '%s', %s, %s, %s, %lf, "
174  "%lf, '%s', '%s', '%s', '%s'"
175  ")",
176  settings->table,
177  accountcode, src, dst, dcontext, clid, channel,
178  dstchannel, lastapp, lastdata, start, answer, end, hrduration,
179  hrbillsec, ast_cdr_disp2str(cdr->disposition), ast_cdr_flags2str(cdr->amaflags), uniqueid,
180  userfield
181  );
182  } else {
183  erc = dbfcmd(settings->dbproc,
184  "INSERT INTO %s "
185  "("
186  "accountcode, src, dst, dcontext, clid, channel, "
187  "dstchannel, lastapp, lastdata, start, answer, [end], duration, "
188  "billsec, disposition, amaflags, uniqueid, userfield"
189  ") "
190  "VALUES "
191  "("
192  "'%s', '%s', '%s', '%s', '%s', '%s', "
193  "'%s', '%s', '%s', %s, %s, %s, %ld, "
194  "%ld, '%s', '%s', '%s', '%s'"
195  ")",
196  settings->table,
197  accountcode, src, dst, dcontext, clid, channel,
198  dstchannel, lastapp, lastdata, start, answer, end, cdr->duration,
199  cdr->billsec, ast_cdr_disp2str(cdr->disposition), ast_cdr_flags2str(cdr->amaflags), uniqueid,
200  userfield
201  );
202  }
203  } else {
204  if (settings->hrtime) {
205  double hrbillsec = 0.0;
206  double hrduration;
207 
208  if (!ast_tvzero(cdr->answer)) {
209  hrbillsec = (double)(ast_tvdiff_us(cdr->end, cdr->answer) / 1000000.0);
210  }
211  hrduration = (double)(ast_tvdiff_us(cdr->end, cdr->start) / 1000000.0);
212 
213  erc = dbfcmd(settings->dbproc,
214  "INSERT INTO %s "
215  "("
216  "accountcode, src, dst, dcontext, clid, channel, "
217  "dstchannel, lastapp, lastdata, start, answer, [end], duration, "
218  "billsec, disposition, amaflags, uniqueid"
219  ") "
220  "VALUES "
221  "("
222  "'%s', '%s', '%s', '%s', '%s', '%s', "
223  "'%s', '%s', '%s', %s, %s, %s, %lf, "
224  "%lf, '%s', '%s', '%s'"
225  ")",
226  settings->table,
227  accountcode, src, dst, dcontext, clid, channel,
228  dstchannel, lastapp, lastdata, start, answer, end, hrduration,
229  hrbillsec, ast_cdr_disp2str(cdr->disposition), ast_cdr_flags2str(cdr->amaflags), uniqueid
230  );
231  } else {
232  erc = dbfcmd(settings->dbproc,
233  "INSERT INTO %s "
234  "("
235  "accountcode, src, dst, dcontext, clid, channel, "
236  "dstchannel, lastapp, lastdata, start, answer, [end], duration, "
237  "billsec, disposition, amaflags, uniqueid"
238  ") "
239  "VALUES "
240  "("
241  "'%s', '%s', '%s', '%s', '%s', '%s', "
242  "'%s', '%s', '%s', %s, %s, %s, %ld, "
243  "%ld, '%s', '%s', '%s'"
244  ")",
245  settings->table,
246  accountcode, src, dst, dcontext, clid, channel,
247  dstchannel, lastapp, lastdata, start, answer, end, cdr->duration,
248  cdr->billsec, ast_cdr_disp2str(cdr->disposition), ast_cdr_flags2str(cdr->amaflags), uniqueid
249  );
250  }
251  }
252 
253  if (erc == FAIL) {
254  if (attempt++ < 3) {
255  ast_log(LOG_NOTICE, "Failed to build INSERT statement, retrying...\n");
257  goto retry;
258  } else {
259  ast_log(LOG_ERROR, "Failed to build INSERT statement, no CDR was logged.\n");
260  goto done;
261  }
262  }
263 
264  if (dbsqlexec(settings->dbproc) == FAIL) {
265  if (attempt++ < 3) {
266  ast_log(LOG_NOTICE, "Failed to execute INSERT statement, retrying...\n");
268  goto retry;
269  } else {
270  ast_log(LOG_ERROR, "Failed to execute INSERT statement, no CDR was logged.\n");
271  goto done;
272  }
273  }
274 
275  /* Consume any results we might get back (this is more of a sanity check than
276  * anything else, since an INSERT shouldn't return results). */
277  while (dbresults(settings->dbproc) != NO_MORE_RESULTS) {
278  while (dbnextrow(settings->dbproc) != NO_MORE_ROWS);
279  }
280 
281  res = 0;
282 
283 done:
285 
286  ast_free(accountcode);
287  ast_free(src);
288  ast_free(dst);
289  ast_free(dcontext);
290  ast_free(clid);
291  ast_free(channel);
292  ast_free(dstchannel);
293  ast_free(lastapp);
294  ast_free(lastdata);
295  ast_free(uniqueid);
296 
297  if (userfield) {
298  ast_free(userfield);
299  }
300 
301  return res;
302 }
static char accountcode[AST_MAX_ACCOUNT_CODE]
Definition: chan_iax2.c:383
char accountcode[AST_MAX_ACCOUNT_CODE]
Definition: cdr.h:114
static char * anti_injection(const char *, int)
Definition: cdr_tds.c:304
#define AST_MAX_USER_FIELD
Definition: cdr.h:72
char dstchannel[AST_MAX_EXTENSION]
Definition: cdr.h:94
const ast_string_field hostname
Definition: cdr_tds.c:92
const ast_string_field table
Definition: cdr_tds.c:92
long int billsec
Definition: cdr.h:108
char dcontext[AST_MAX_EXTENSION]
Definition: cdr.h:90
static ast_mutex_t tds_lock
Definition: cdr_tds.c:98
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition: time.h:100
char uniqueid[150]
Definition: cdr.h:121
DBPROCESS * dbproc
Definition: cdr_tds.c:93
const ast_string_field hrtime
Definition: cdr_tds.c:92
#define ast_mutex_lock(a)
Definition: lock.h:155
char * ast_cdr_flags2str(int flags)
Definition: cdr.c:977
static int mssql_connect(void)
Definition: cdr_tds.c:393
char lastdata[AST_MAX_EXTENSION]
Definition: cdr.h:98
long int amaflags
Definition: cdr.h:112
static int mssql_disconnect(void)
Definition: cdr_tds.c:381
unsigned int connected
Definition: cdr_tds.c:94
unsigned int has_userfield
Definition: cdr_tds.c:95
char dst[AST_MAX_EXTENSION]
Definition: cdr.h:88
char channel[AST_MAX_EXTENSION]
Definition: cdr.h:92
struct timeval answer
Definition: cdr.h:102
char lastapp[AST_MAX_EXTENSION]
Definition: cdr.h:96
#define LOG_ERROR
Definition: logger.h:155
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define LOG_NOTICE
Definition: logger.h:133
struct timeval start
Definition: cdr.h:100
#define ast_free(a)
Definition: astmm.h:97
long int duration
Definition: cdr.h:106
char src[AST_MAX_EXTENSION]
Definition: cdr.h:86
struct timeval end
Definition: cdr.h:104
int64_t ast_tvdiff_us(struct timeval end, struct timeval start)
Computes the difference (in microseconds) between two struct timeval instances.
Definition: time.h:70
long int disposition
Definition: cdr.h:110
char clid[AST_MAX_EXTENSION]
Definition: cdr.h:84
static struct cdr_tds_config * settings
Definition: cdr_tds.c:100
char * ast_cdr_disp2str(int disposition)
Disposition to a string.
Definition: cdr.c:959
char userfield[AST_MAX_USER_FIELD]
Definition: cdr.h:125
#define ast_mutex_unlock(a)
Definition: lock.h:156
static void get_date(char *, size_t len, struct timeval)
Definition: cdr_tds.c:338
static int tds_message_handler ( DBPROCESS *  dbproc,
DBINT  msgno,
int  msgstate,
int  severity,
char *  msgtext,
char *  srvname,
char *  procname,
int  line 
)
static

Definition at line 473 of file cdr_tds.c.

References ast_debug, ast_log(), and LOG_NOTICE.

Referenced by load_module().

474 {
475  ast_debug(1, "Msg %d, Level %d, State %d, Line %d\n", msgno, severity, msgstate, line);
476  ast_log(LOG_NOTICE, "%s\n", msgtext);
477 
478  return 0;
479 }
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define LOG_NOTICE
Definition: logger.h:133
enum ast_security_event_severity severity
static int tds_unload_module ( void  )
static

Definition at line 444 of file cdr_tds.c.

References ast_cdr_unregister(), ast_free, ast_mutex_lock, ast_mutex_unlock, ast_string_field_free_memory, mssql_disconnect(), and tds_lock.

Referenced by unload_module().

445 {
446  if (settings) {
450 
453  }
454 
456 
457  dbexit();
458 
459  return 0;
460 }
static ast_mutex_t tds_lock
Definition: cdr_tds.c:98
#define ast_mutex_lock(a)
Definition: lock.h:155
static int mssql_disconnect(void)
Definition: cdr_tds.c:381
static const char name[]
#define ast_free(a)
Definition: astmm.h:97
static struct cdr_tds_config * settings
Definition: cdr_tds.c:100
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:253
void ast_cdr_unregister(const char *name)
Unregister a CDR handling engine.
Definition: cdr.c:165
#define ast_mutex_unlock(a)
Definition: lock.h:156
static int unload_module ( void  )
static

Definition at line 627 of file cdr_tds.c.

References tds_unload_module().

628 {
629  return tds_unload_module();
630 }
static int tds_unload_module(void)
Definition: cdr_tds.c:444

Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "FreeTDS CDR Backend" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CDR_DRIVER, }
static

Definition at line 637 of file cdr_tds.c.

Definition at line 637 of file cdr_tds.c.

const char config[] = "cdr_tds.conf"
static

Definition at line 80 of file cdr_tds.c.

const char name[] = "FreeTDS (MSSQL)"
static

Definition at line 79 of file cdr_tds.c.

struct cdr_tds_config* settings
static

Definition at line 100 of file cdr_tds.c.

ast_mutex_t tds_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 }
static

Definition at line 98 of file cdr_tds.c.

Referenced by tds_load_module(), tds_log(), and tds_unload_module().