Asterisk - The Open Source Telephony Project GIT-master-7e7a603
cdr_tds.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2004 - 2006, Digium, Inc.
5 *
6 * See http://www.asterisk.org for more information about
7 * the Asterisk project. Please do not directly contact
8 * any of the maintainers of this project for assistance;
9 * the project provides a web site, mailing lists and IRC
10 * channels for your use.
11 *
12 * This program is free software, distributed under the terms of
13 * the GNU General Public License Version 2. See the LICENSE file
14 * at the top of the source tree.
15 */
16
17/*!
18 * \file
19 * \brief FreeTDS CDR logger
20 * http://www.freetds.org/
21 * \ingroup cdr_drivers
22 */
23
24/*!
25 * \verbatim
26 *
27 * Table Structure for `cdr`
28 *
29 * Created on: 05/20/2004 16:16
30 * Last changed on: 07/27/2004 20:01
31
32CREATE TABLE [dbo].[cdr] (
33 [accountcode] [varchar] (20) NULL ,
34 [src] [varchar] (80) NULL ,
35 [dst] [varchar] (80) NULL ,
36 [dcontext] [varchar] (80) NULL ,
37 [clid] [varchar] (80) NULL ,
38 [channel] [varchar] (80) NULL ,
39 [dstchannel] [varchar] (80) NULL ,
40 [lastapp] [varchar] (80) NULL ,
41 [lastdata] [varchar] (80) NULL ,
42 [start] [datetime] NULL ,
43 [answer] [datetime] NULL ,
44 [end] [datetime] NULL ,
45 [duration] [int] NULL ,
46 [billsec] [int] NULL ,
47 [disposition] [varchar] (20) NULL ,
48 [amaflags] [varchar] (16) NULL ,
49 [uniqueid] [varchar] (32) NULL ,
50 [userfield] [varchar] (256) NULL
51) ON [PRIMARY]
52
53\endverbatim
54
55*/
56
57/*** MODULEINFO
58 <depend>freetds</depend>
59 <support_level>extended</support_level>
60 ***/
61
62#include "asterisk.h"
63
64#include "asterisk/config.h"
65#include "asterisk/channel.h"
66#include "asterisk/cdr.h"
67#include "asterisk/module.h"
68
69#include <sqlfront.h>
70#include <sybdb.h>
71
72#define DATE_FORMAT "%Y/%m/%d %T"
73
74static const char name[] = "FreeTDS (MSSQL)";
75static const char config[] = "cdr_tds.conf";
76
87 );
88 DBPROCESS *dbproc;
89 unsigned int connected:1;
90 unsigned int has_userfield:1;
91};
92
94
95static struct cdr_tds_config *settings;
96
97static char *anti_injection(const char *, int);
98static void get_date(char *, size_t len, struct timeval);
99
100static int execute_and_consume(DBPROCESS *dbproc, const char *fmt, ...)
101 __attribute__((format(printf, 2, 3)));
102
103static int mssql_connect(void);
104static int mssql_disconnect(void);
105
106static int tds_log(struct ast_cdr *cdr)
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
114 accountcode = anti_injection(cdr->accountcode, 20);
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) {
132 userfield = anti_injection(cdr->userfield, AST_MAX_USER_FIELD);
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,
194 cdr->billsec, ast_cdr_disp2str(cdr->disposition), ast_channel_amaflags2string(cdr->amaflags), uniqueid,
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,
243 cdr->billsec, ast_cdr_disp2str(cdr->disposition), ast_channel_amaflags2string(cdr->amaflags), uniqueid
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}
298
299static char *anti_injection(const char *str, int len)
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}
332
333static void get_date(char *dateField, size_t len, struct timeval when)
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}
344
345static int execute_and_consume(DBPROCESS *dbproc, const char *fmt, ...)
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}
375
376static int mssql_disconnect(void)
377{
378 if (settings->dbproc) {
379 dbclose(settings->dbproc);
381 }
382
383 settings->connected = 0;
384
385 return 0;
386}
387
388static int mssql_connect(void)
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}
438
439static int tds_unload_module(void)
440{
442 return -1;
443 }
444
445 if (settings) {
449
452 }
453
454 dbexit();
455
456 return 0;
457}
458
459static int tds_error_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr)
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}
469
470static int tds_message_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, int severity, char *msgtext, char *srvname, char *procname, int line)
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}
477
478static int tds_load_module(int reload)
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}
588
589static int reload(void)
590{
591 return tds_load_module(1);
592}
593
594static int load_module(void)
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}
623
624static int unload_module(void)
625{
626 return tds_unload_module();
627}
628
630 .support_level = AST_MODULE_SUPPORT_EXTENDED,
631 .load = load_module,
632 .unload = unload_module,
633 .reload = reload,
634 .load_pri = AST_MODPRI_CDR_DRIVER,
635 .requires = "cdr",
const char * str
Definition: app_jack.c:147
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_vasprintf(ret, fmt, ap)
A wrapper for vasprintf()
Definition: astmm.h:278
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
Call Detail Record API.
int ast_cdr_unregister(const char *name)
Unregister a CDR handling engine.
Definition: cdr.c:3050
const char * ast_cdr_disp2str(int disposition)
Disposition to a string.
Definition: cdr.c:3492
int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be)
Register a CDR handling engine.
Definition: cdr.c:3005
static char * table
Definition: cdr_odbc.c:55
static const char name[]
Definition: cdr_tds.c:74
static char * anti_injection(const char *, int)
Definition: cdr_tds.c:299
static int mssql_connect(void)
Definition: cdr_tds.c:388
static int tds_log(struct ast_cdr *cdr)
Definition: cdr_tds.c:106
static void get_date(char *, size_t len, struct timeval)
Definition: cdr_tds.c:333
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 execute_and_consume(DBPROCESS *dbproc, const char *fmt,...)
Definition: cdr_tds.c:345
static const char config[]
Definition: cdr_tds.c:75
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 ast_mutex_t tds_lock
Definition: cdr_tds.c:93
static int mssql_disconnect(void)
Definition: cdr_tds.c:376
static int tds_unload_module(void)
Definition: cdr_tds.c:439
static int load_module(void)
Definition: cdr_tds.c:594
static int unload_module(void)
Definition: cdr_tds.c:624
static int reload(void)
Definition: cdr_tds.c:589
static int tds_load_module(int reload)
Definition: cdr_tds.c:478
#define DATE_FORMAT
Definition: cdr_tds.c:72
static char language[MAX_LANGUAGE]
Definition: chan_iax2.c:324
static char accountcode[AST_MAX_ACCOUNT_CODE]
Definition: chan_iax2.c:473
static int answer(void *data)
Definition: chan_pjsip.c:683
charset
Definition: chan_unistim.c:336
General Asterisk PBX channel definitions.
const char * ast_channel_amaflags2string(enum ama_flags flags)
Convert the enum representation of an AMA flag to a string representation.
Definition: channel.c:4373
#define AST_MAX_USER_FIELD
Definition: channel.h:174
char * end
Definition: eagi_proxy.c:73
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 *)
Configuration File Parser.
#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:783
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1215
@ CONFIG_FLAG_FILEUNCHANGED
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_NOTICE
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
#define ast_mutex_unlock(a)
Definition: lock.h:190
#define ast_mutex_lock(a)
Definition: lock.h:189
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:520
static char hostname[MAXHOSTNAMELEN]
Definition: logger.c:119
enum ast_security_event_severity severity
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:317
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:543
@ AST_MODPRI_CDR_DRIVER
Definition: module.h:331
@ AST_MODULE_SUPPORT_EXTENDED
Definition: module.h:122
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ 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 NULL
Definition: resample.c:96
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:341
#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(name)
Declare a string field.
Definition: stringfields.h:303
#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
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
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
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
Responsible for call detail data.
Definition: cdr.h:279
Structure used to handle boolean flags.
Definition: utils.h:199
const char * description
Definition: module.h:352
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 hrtime
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
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
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition: time.h:117
DB * dbopen(char *fname, int flags, int mode, DBTYPE type, const void *openinfo) const