Asterisk - The Open Source Telephony Project GIT-master-f36a736
Data Structures | Macros | Functions | Variables
cdr_tds.c File Reference

FreeTDS CDR logger http://www.freetds.org/. 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>
Include dependency graph for cdr_tds.c:

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)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
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 = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CDR_DRIVER, .requires = "cdr", }
 
static const 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, 0} }
 

Detailed Description

FreeTDS CDR logger http://www.freetds.org/.

Definition in file cdr_tds.c.

Macro Definition Documentation

◆ DATE_FORMAT

#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 72 of file cdr_tds.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 636 of file cdr_tds.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 636 of file cdr_tds.c.

◆ anti_injection()

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

Definition at line 299 of file cdr_tds.c.

300{
301 /* Reference to http://www.nextgenss.com/papers/advanced_sql_injection.pdf */
302 char *buf;
303 char *buf_ptr, *srh_ptr;
304 char *known_bad[] = {"select", "insert", "update", "delete", "drop", ";", "--", "\0"};
305 int idx;
306
307 if (!(buf = ast_calloc(1, len + 1))) {
308 ast_log(LOG_ERROR, "Out of memory\n");
309 return NULL;
310 }
311
312 buf_ptr = buf;
313
314 /* Escape single quotes */
315 for (; *str && strlen(buf) < len; str++) {
316 if (*str == '\'') {
317 *buf_ptr++ = '\'';
318 }
319 *buf_ptr++ = *str;
320 }
321 *buf_ptr = '\0';
322
323 /* Erase known bad input */
324 for (idx = 0; *known_bad[idx]; idx++) {
325 while ((srh_ptr = strcasestr(buf, known_bad[idx]))) {
326 memmove(srh_ptr, srh_ptr + strlen(known_bad[idx]), strlen(srh_ptr + strlen(known_bad[idx])) + 1);
327 }
328 }
329
330 return buf;
331}
const char * str
Definition: app_jack.c:147
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
char * strcasestr(const char *, const char *)
#define LOG_ERROR
#define NULL
Definition: resample.c:96

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

Referenced by tds_log().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 636 of file cdr_tds.c.

◆ execute_and_consume()

static int execute_and_consume ( DBPROCESS *  dbproc,
const char *  fmt,
  ... 
)
static

Definition at line 345 of file cdr_tds.c.

346{
347 va_list ap;
348 char *buffer;
349
350 va_start(ap, fmt);
351 if (ast_vasprintf(&buffer, fmt, ap) < 0) {
352 va_end(ap);
353 return 1;
354 }
355 va_end(ap);
356
357 if (dbfcmd(dbproc, buffer) == FAIL) {
358 ast_free(buffer);
359 return 1;
360 }
361
362 ast_free(buffer);
363
364 if (dbsqlexec(dbproc) == FAIL) {
365 return 1;
366 }
367
368 /* Consume the result set (we don't really care about the result, though) */
369 while (dbresults(dbproc) != NO_MORE_RESULTS) {
370 while (dbnextrow(dbproc) != NO_MORE_ROWS);
371 }
372
373 return 0;
374}
#define ast_free(a)
Definition: astmm.h:180
#define ast_vasprintf(ret, fmt, ap)
A wrapper for vasprintf()
Definition: astmm.h:278

References ast_free, and ast_vasprintf.

Referenced by mssql_connect().

◆ get_date()

static void get_date ( char *  dateField,
size_t  len,
struct timeval  when 
)
static

Definition at line 333 of file cdr_tds.c.

334{
335 /* To make sure we have date variable if not insert null to SQL */
336 if (!ast_tvzero(when)) {
337 struct ast_tm tm;
338 ast_localtime(&when, &tm, NULL);
339 ast_strftime(dateField, len, "'" DATE_FORMAT "'", &tm);
340 } else {
341 ast_copy_string(dateField, "null", len);
342 }
343}
#define DATE_FORMAT
Definition: cdr_tds.c:72
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
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
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition: time.h:117

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

Referenced by tds_log().

◆ load_module()

static int load_module ( void  )
static

Definition at line 594 of file cdr_tds.c.

595{
596 if (dbinit() == FAIL) {
597 ast_log(LOG_ERROR, "Failed to initialize FreeTDS db-lib\n");
599 }
600
601 dberrhandle(tds_error_handler);
602 dbmsghandle(tds_message_handler);
603
605
606 if (!settings) {
607 dbexit();
609 }
610
611 if (!tds_load_module(0)) {
614 settings = NULL;
615 dbexit();
617 }
618
620
622}
int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be)
Register a CDR handling engine.
Definition: cdr.c:3009
static const char name[]
Definition: cdr_tds.c:74
static int tds_log(struct ast_cdr *cdr)
Definition: cdr_tds.c:106
static int tds_error_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr)
Definition: cdr_tds.c:459
static struct cdr_tds_config * settings
Definition: cdr_tds.c:95
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:470
static int tds_load_module(int reload)
Definition: cdr_tds.c:478
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define ast_calloc_with_stringfields(n, type, size)
Allocate a structure with embedded stringfields in a single allocation.
Definition: stringfields.h:432
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
const char * description
Definition: module.h:366

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, ast_module_info::description, LOG_ERROR, name, NULL, settings, tds_error_handler(), tds_load_module(), tds_log(), and tds_message_handler().

◆ mssql_connect()

static int mssql_connect ( void  )
static

Definition at line 388 of file cdr_tds.c.

389{
390 LOGINREC *login;
391
392 if ((login = dblogin()) == NULL) {
393 ast_log(LOG_ERROR, "Unable to allocate login structure for db-lib\n");
394 return -1;
395 }
396
397 DBSETLAPP(login, "TSQL");
398 DBSETLUSER(login, (char *) settings->username);
399 DBSETLPWD(login, (char *) settings->password);
400 DBSETLCHARSET(login, (char *) settings->charset);
401 DBSETLNATLANG(login, (char *) settings->language);
402
403 if ((settings->dbproc = dbopen(login, (char *) settings->hostname)) == NULL) {
404 ast_log(LOG_ERROR, "Unable to connect to %s\n", settings->hostname);
405 dbloginfree(login);
406 return -1;
407 }
408
409 dbloginfree(login);
410
411 if (dbuse(settings->dbproc, (char *) settings->database) == FAIL) {
412 ast_log(LOG_ERROR, "Unable to select database %s\n", settings->database);
413 goto failed;
414 }
415
416 if (execute_and_consume(settings->dbproc, "SELECT 1 FROM [%s] WHERE 1 = 0", settings->table)) {
417 ast_log(LOG_ERROR, "Unable to find table '%s'\n", settings->table);
418 goto failed;
419 }
420
421 /* Check to see if we have a userfield column in the table */
422 if (execute_and_consume(settings->dbproc, "SELECT userfield FROM [%s] WHERE 1 = 0", settings->table)) {
423 ast_log(LOG_NOTICE, "Unable to find 'userfield' column in table '%s'\n", settings->table);
425 } else {
427 }
428
429 settings->connected = 1;
430
431 return 0;
432
433failed:
434 dbclose(settings->dbproc);
436 return -1;
437}
static int execute_and_consume(DBPROCESS *dbproc, const char *fmt,...)
Definition: cdr_tds.c:345
#define LOG_NOTICE
DBPROCESS * dbproc
Definition: cdr_tds.c:88
const ast_string_field charset
Definition: cdr_tds.c:87
const ast_string_field language
Definition: cdr_tds.c:87
const ast_string_field database
Definition: cdr_tds.c:87
const ast_string_field password
Definition: cdr_tds.c:87
const ast_string_field username
Definition: cdr_tds.c:87
const ast_string_field table
Definition: cdr_tds.c:87
unsigned int connected
Definition: cdr_tds.c:89
unsigned int has_userfield
Definition: cdr_tds.c:90
const ast_string_field hostname
Definition: cdr_tds.c:87
DB * dbopen(char *fname, int flags, int mode, DBTYPE type, const void *openinfo) const

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

Referenced by tds_load_module(), and tds_log().

◆ mssql_disconnect()

static int mssql_disconnect ( void  )
static

Definition at line 376 of file cdr_tds.c.

377{
378 if (settings->dbproc) {
379 dbclose(settings->dbproc);
381 }
382
383 settings->connected = 0;
384
385 return 0;
386}

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

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

◆ reload()

static int reload ( void  )
static

Definition at line 589 of file cdr_tds.c.

590{
591 return tds_load_module(1);
592}

References tds_load_module().

Referenced by tds_load_module().

◆ tds_error_handler()

static int tds_error_handler ( DBPROCESS *  dbproc,
int  severity,
int  dberr,
int  oserr,
char *  dberrstr,
char *  oserrstr 
)
static

Definition at line 459 of file cdr_tds.c.

460{
461 ast_log(LOG_ERROR, "%s (%d)\n", dberrstr, dberr);
462
463 if (oserr != DBNOERR) {
464 ast_log(LOG_ERROR, "%s (%d)\n", oserrstr, oserr);
465 }
466
467 return INT_CANCEL;
468}

References ast_log, and LOG_ERROR.

Referenced by load_module().

◆ tds_load_module()

static int tds_load_module ( int  reload)
static

Definition at line 478 of file cdr_tds.c.

479{
480 struct ast_config *cfg;
481 const char *ptr = NULL;
482 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
483
484 cfg = ast_config_load(config, config_flags);
485 if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
486 ast_log(LOG_NOTICE, "Unable to load TDS config for CDRs: %s\n", config);
487 return 0;
488 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
489 return 0;
490
491 if (!ast_variable_browse(cfg, "global")) {
492 /* nothing configured */
494 return 0;
495 }
496
498
499 /* Clear out any existing settings */
501
502 /* 'connection' is the new preferred configuration option */
503 ptr = ast_variable_retrieve(cfg, "global", "connection");
504 if (ptr) {
506 } else {
507 /* But we keep 'hostname' for backwards compatibility */
508 ptr = ast_variable_retrieve(cfg, "global", "hostname");
509 if (ptr) {
511 } else {
512 ast_log(LOG_ERROR, "Failed to connect: Database server connection not specified.\n");
513 goto failed;
514 }
515 }
516
517 ptr = ast_variable_retrieve(cfg, "global", "dbname");
518 if (ptr) {
519 ast_string_field_set(settings, database, ptr);
520 } else {
521 ast_log(LOG_ERROR, "Failed to connect: Database dbname not specified.\n");
522 goto failed;
523 }
524
525 ptr = ast_variable_retrieve(cfg, "global", "user");
526 if (ptr) {
527 ast_string_field_set(settings, username, ptr);
528 } else {
529 ast_log(LOG_ERROR, "Failed to connect: Database dbuser not specified.\n");
530 goto failed;
531 }
532
533 ptr = ast_variable_retrieve(cfg, "global", "password");
534 if (ptr) {
535 ast_string_field_set(settings, password, ptr);
536 } else {
537 ast_log(LOG_ERROR, "Failed to connect: Database password not specified.\n");
538 goto failed;
539 }
540
541 ptr = ast_variable_retrieve(cfg, "global", "charset");
542 if (ptr) {
544 } else {
546 }
547
548 ptr = ast_variable_retrieve(cfg, "global", "language");
549 if (ptr) {
551 } else {
552 ast_string_field_set(settings, language, "us_english");
553 }
554
555 ptr = ast_variable_retrieve(cfg, "global", "table");
556 if (ptr) {
558 } else {
559 ast_log(LOG_NOTICE, "Table name not specified, using 'cdr' by default.\n");
561 }
562
563 ptr = ast_variable_retrieve(cfg, "global", "hrtime");
564 if (ptr && ast_true(ptr)) {
565 ast_string_field_set(settings, hrtime, ptr);
566 } else {
567 ast_log(LOG_NOTICE, "High Resolution Time not found, using integers for billsec and duration fields by default.\n");
568 }
569
571
572 if (mssql_connect()) {
573 /* We failed to connect (mssql_connect takes care of logging it) */
574 goto failed;
575 }
576
579
580 return 1;
581
582failed:
585
586 return 0;
587}
static char * table
Definition: cdr_odbc.c:55
static int mssql_connect(void)
Definition: cdr_tds.c:388
static const char config[]
Definition: cdr_tds.c:75
static ast_mutex_t tds_lock
Definition: cdr_tds.c:93
static int mssql_disconnect(void)
Definition: cdr_tds.c:376
static int reload(void)
Definition: cdr_tds.c:589
static char language[MAX_LANGUAGE]
Definition: chan_iax2.c:324
charset
Definition: chan_unistim.c:336
#define ast_config_load(filename, flags)
Load a config file.
#define CONFIG_STATUS_FILEUNCHANGED
#define CONFIG_STATUS_FILEINVALID
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:784
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1215
@ CONFIG_FLAG_FILEUNCHANGED
#define ast_mutex_unlock(a)
Definition: lock.h:190
#define ast_mutex_lock(a)
Definition: lock.h:189
static char hostname[MAXHOSTNAMELEN]
Definition: logger.c:119
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199
Structure used to handle boolean flags.
Definition: utils.h:199

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(), config, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, hostname, language, LOG_ERROR, LOG_NOTICE, mssql_connect(), mssql_disconnect(), NULL, reload(), settings, table, and tds_lock.

Referenced by load_module(), and reload().

◆ tds_log()

static int tds_log ( struct ast_cdr cdr)
static

Definition at line 106 of file cdr_tds.c.

107{
108 char start[80], answer[80], end[80];
109 char *accountcode, *src, *dst, *dcontext, *clid, *channel, *dstchannel, *lastapp, *lastdata, *uniqueid, *userfield = NULL;
110 RETCODE erc;
111 int res = -1;
112 int attempt = 1;
113
115 src = anti_injection(cdr->src, 80);
116 dst = anti_injection(cdr->dst, 80);
117 dcontext = anti_injection(cdr->dcontext, 80);
118 clid = anti_injection(cdr->clid, 80);
119 channel = anti_injection(cdr->channel, 80);
120 dstchannel = anti_injection(cdr->dstchannel, 80);
121 lastapp = anti_injection(cdr->lastapp, 80);
122 lastdata = anti_injection(cdr->lastdata, 80);
123 uniqueid = anti_injection(cdr->uniqueid, 32);
124
125 get_date(start, sizeof(start), cdr->start);
126 get_date(answer, sizeof(answer), cdr->answer);
127 get_date(end, sizeof(end), cdr->end);
128
130
131 if (settings->has_userfield) {
133 }
134
135retry:
136 /* Ensure that we are connected */
137 if (!settings->connected) {
138 ast_log(LOG_NOTICE, "Attempting to reconnect to %s (Attempt %d)\n", settings->hostname, attempt);
139 if (mssql_connect()) {
140 /* Connect failed */
141 if (attempt++ < 3) {
142 goto retry;
143 }
144 goto done;
145 }
146 }
147
148 if (settings->has_userfield) {
149 if (settings->hrtime) {
150 double hrbillsec = 0.0;
151 double hrduration;
152
153 if (!ast_tvzero(cdr->answer)) {
154 hrbillsec = (double)(ast_tvdiff_us(cdr->end, cdr->answer) / 1000000.0);
155 }
156 hrduration = (double)(ast_tvdiff_us(cdr->end, cdr->start) / 1000000.0);
157
158 erc = dbfcmd(settings->dbproc,
159 "INSERT INTO %s "
160 "("
161 "accountcode, src, dst, dcontext, clid, channel, "
162 "dstchannel, lastapp, lastdata, start, answer, [end], duration, "
163 "billsec, disposition, amaflags, uniqueid, userfield"
164 ") "
165 "VALUES "
166 "("
167 "'%s', '%s', '%s', '%s', '%s', '%s', "
168 "'%s', '%s', '%s', %s, %s, %s, %lf, "
169 "%lf, '%s', '%s', '%s', '%s'"
170 ")",
172 accountcode, src, dst, dcontext, clid, channel,
173 dstchannel, lastapp, lastdata, start, answer, end, hrduration,
174 hrbillsec, ast_cdr_disp2str(cdr->disposition), ast_channel_amaflags2string(cdr->amaflags), uniqueid,
175 userfield
176 );
177 } else {
178 erc = dbfcmd(settings->dbproc,
179 "INSERT INTO %s "
180 "("
181 "accountcode, src, dst, dcontext, clid, channel, "
182 "dstchannel, lastapp, lastdata, start, answer, [end], duration, "
183 "billsec, disposition, amaflags, uniqueid, userfield"
184 ") "
185 "VALUES "
186 "("
187 "'%s', '%s', '%s', '%s', '%s', '%s', "
188 "'%s', '%s', '%s', %s, %s, %s, %ld, "
189 "%ld, '%s', '%s', '%s', '%s'"
190 ")",
192 accountcode, src, dst, dcontext, clid, channel,
193 dstchannel, lastapp, lastdata, start, answer, end, cdr->duration,
195 userfield
196 );
197 }
198 } else {
199 if (settings->hrtime) {
200 double hrbillsec = 0.0;
201 double hrduration;
202
203 if (!ast_tvzero(cdr->answer)) {
204 hrbillsec = (double)(ast_tvdiff_us(cdr->end, cdr->answer) / 1000000.0);
205 }
206 hrduration = (double)(ast_tvdiff_us(cdr->end, cdr->start) / 1000000.0);
207
208 erc = dbfcmd(settings->dbproc,
209 "INSERT INTO %s "
210 "("
211 "accountcode, src, dst, dcontext, clid, channel, "
212 "dstchannel, lastapp, lastdata, start, answer, [end], duration, "
213 "billsec, disposition, amaflags, uniqueid"
214 ") "
215 "VALUES "
216 "("
217 "'%s', '%s', '%s', '%s', '%s', '%s', "
218 "'%s', '%s', '%s', %s, %s, %s, %lf, "
219 "%lf, '%s', '%s', '%s'"
220 ")",
222 accountcode, src, dst, dcontext, clid, channel,
223 dstchannel, lastapp, lastdata, start, answer, end, hrduration,
224 hrbillsec, ast_cdr_disp2str(cdr->disposition), ast_channel_amaflags2string(cdr->amaflags), uniqueid
225 );
226 } else {
227 erc = dbfcmd(settings->dbproc,
228 "INSERT INTO %s "
229 "("
230 "accountcode, src, dst, dcontext, clid, channel, "
231 "dstchannel, lastapp, lastdata, start, answer, [end], duration, "
232 "billsec, disposition, amaflags, uniqueid"
233 ") "
234 "VALUES "
235 "("
236 "'%s', '%s', '%s', '%s', '%s', '%s', "
237 "'%s', '%s', '%s', %s, %s, %s, %ld, "
238 "%ld, '%s', '%s', '%s'"
239 ")",
241 accountcode, src, dst, dcontext, clid, channel,
242 dstchannel, lastapp, lastdata, start, answer, end, cdr->duration,
244 );
245 }
246 }
247
248 if (erc == FAIL) {
249 if (attempt++ < 3) {
250 ast_log(LOG_NOTICE, "Failed to build INSERT statement, retrying...\n");
252 goto retry;
253 } else {
254 ast_log(LOG_ERROR, "Failed to build INSERT statement, no CDR was logged.\n");
255 goto done;
256 }
257 }
258
259 if (dbsqlexec(settings->dbproc) == FAIL) {
260 if (attempt++ < 3) {
261 ast_log(LOG_NOTICE, "Failed to execute INSERT statement, retrying...\n");
263 goto retry;
264 } else {
265 ast_log(LOG_ERROR, "Failed to execute INSERT statement, no CDR was logged.\n");
266 goto done;
267 }
268 }
269
270 /* Consume any results we might get back (this is more of a sanity check than
271 * anything else, since an INSERT shouldn't return results). */
272 while (dbresults(settings->dbproc) != NO_MORE_RESULTS) {
273 while (dbnextrow(settings->dbproc) != NO_MORE_ROWS);
274 }
275
276 res = 0;
277
278done:
280
282 ast_free(src);
283 ast_free(dst);
284 ast_free(dcontext);
285 ast_free(clid);
286 ast_free(channel);
287 ast_free(dstchannel);
288 ast_free(lastapp);
289 ast_free(lastdata);
290 ast_free(uniqueid);
291
292 if (userfield) {
293 ast_free(userfield);
294 }
295
296 return res;
297}
const char * ast_cdr_disp2str(int disposition)
Disposition to a string.
Definition: cdr.c:3509
static char * anti_injection(const char *, int)
Definition: cdr_tds.c:299
static void get_date(char *, size_t len, struct timeval)
Definition: cdr_tds.c:333
static char accountcode[AST_MAX_ACCOUNT_CODE]
Definition: chan_iax2.c:473
static int answer(void *data)
Definition: chan_pjsip.c:687
const char * ast_channel_amaflags2string(enum ama_flags flags)
Convert the enum representation of an AMA flag to a string representation.
Definition: channel.c:4392
#define AST_MAX_USER_FIELD
Definition: channel.h:176
char * end
Definition: eagi_proxy.c:73
char dstchannel[AST_MAX_EXTENSION]
Definition: cdr.h:291
long int disposition
Definition: cdr.h:307
char lastdata[AST_MAX_EXTENSION]
Definition: cdr.h:295
char userfield[AST_MAX_USER_FIELD]
Definition: cdr.h:325
long int billsec
Definition: cdr.h:305
struct timeval answer
Definition: cdr.h:299
char channel[AST_MAX_EXTENSION]
Definition: cdr.h:289
long int duration
Definition: cdr.h:303
long int amaflags
Definition: cdr.h:309
char src[AST_MAX_EXTENSION]
Definition: cdr.h:283
char dst[AST_MAX_EXTENSION]
Definition: cdr.h:285
char clid[AST_MAX_EXTENSION]
Definition: cdr.h:281
char uniqueid[AST_MAX_UNIQUEID]
Definition: cdr.h:317
struct timeval start
Definition: cdr.h:297
char accountcode[AST_MAX_ACCOUNT_CODE]
Definition: cdr.h:311
char lastapp[AST_MAX_EXTENSION]
Definition: cdr.h:293
char dcontext[AST_MAX_EXTENSION]
Definition: cdr.h:287
struct timeval end
Definition: cdr.h:301
const ast_string_field hrtime
Definition: cdr_tds.c:87
int done
Definition: test_amihooks.c:48
int64_t ast_tvdiff_us(struct timeval end, struct timeval start)
Computes the difference (in microseconds) between two struct timeval instances.
Definition: time.h:87

References accountcode, answer(), anti_injection(), ast_cdr_disp2str(), ast_channel_amaflags2string(), 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, done, end, get_date(), cdr_tds_config::has_userfield, cdr_tds_config::hostname, cdr_tds_config::hrtime, LOG_ERROR, LOG_NOTICE, mssql_connect(), mssql_disconnect(), NULL, settings, cdr_tds_config::table, and tds_lock.

Referenced by load_module().

◆ tds_message_handler()

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 470 of file cdr_tds.c.

471{
472 ast_debug(1, "Msg %d, Level %d, State %d, Line %d\n", msgno, severity, msgstate, line);
473 ast_log(LOG_NOTICE, "%s\n", msgtext);
474
475 return 0;
476}
#define ast_debug(level,...)
Log a DEBUG message.
enum ast_security_event_severity severity

References ast_debug, ast_log, LOG_NOTICE, and severity.

Referenced by load_module().

◆ tds_unload_module()

static int tds_unload_module ( void  )
static

Definition at line 439 of file cdr_tds.c.

440{
442 return -1;
443 }
444
445 if (settings) {
449
452 }
453
454 dbexit();
455
456 return 0;
457}
int ast_cdr_unregister(const char *name)
Unregister a CDR handling engine.
Definition: cdr.c:3054

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

Referenced by unload_module().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 624 of file cdr_tds.c.

625{
626 return tds_unload_module();
627}
static int tds_unload_module(void)
Definition: cdr_tds.c:439

References tds_unload_module().

Variable Documentation

◆ __mod_info

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 = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CDR_DRIVER, .requires = "cdr", }
static

Definition at line 636 of file cdr_tds.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 636 of file cdr_tds.c.

◆ config

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

Definition at line 75 of file cdr_tds.c.

Referenced by tds_load_module().

◆ name

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

Definition at line 74 of file cdr_tds.c.

Referenced by load_module(), and tds_unload_module().

◆ settings

struct cdr_tds_config* settings
static

◆ tds_lock

ast_mutex_t tds_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} }
static

Definition at line 93 of file cdr_tds.c.

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