Asterisk - The Open Source Telephony Project  18.5.0
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  *
21  * See also
22  * \arg \ref Config_cdr
23  * \arg http://www.freetds.org/
24  * \ingroup cdr_drivers
25  */
26 
27 /*!
28  * \verbatim
29  *
30  * Table Structure for `cdr`
31  *
32  * Created on: 05/20/2004 16:16
33  * Last changed on: 07/27/2004 20:01
34 
35 CREATE TABLE [dbo].[cdr] (
36  [accountcode] [varchar] (20) NULL ,
37  [src] [varchar] (80) NULL ,
38  [dst] [varchar] (80) NULL ,
39  [dcontext] [varchar] (80) NULL ,
40  [clid] [varchar] (80) NULL ,
41  [channel] [varchar] (80) NULL ,
42  [dstchannel] [varchar] (80) NULL ,
43  [lastapp] [varchar] (80) NULL ,
44  [lastdata] [varchar] (80) NULL ,
45  [start] [datetime] NULL ,
46  [answer] [datetime] NULL ,
47  [end] [datetime] NULL ,
48  [duration] [int] NULL ,
49  [billsec] [int] NULL ,
50  [disposition] [varchar] (20) NULL ,
51  [amaflags] [varchar] (16) NULL ,
52  [uniqueid] [varchar] (32) NULL ,
53  [userfield] [varchar] (256) NULL
54 ) ON [PRIMARY]
55 
56 \endverbatim
57 
58 */
59 
60 /*** MODULEINFO
61  <depend>freetds</depend>
62  <support_level>extended</support_level>
63  ***/
64 
65 #include "asterisk.h"
66 
67 #include "asterisk/config.h"
68 #include "asterisk/channel.h"
69 #include "asterisk/cdr.h"
70 #include "asterisk/module.h"
71 
72 #include <sqlfront.h>
73 #include <sybdb.h>
74 
75 #define DATE_FORMAT "%Y/%m/%d %T"
76 
77 static const char name[] = "FreeTDS (MSSQL)";
78 static const char config[] = "cdr_tds.conf";
79 
90  );
91  DBPROCESS *dbproc;
92  unsigned int connected:1;
93  unsigned int has_userfield:1;
94 };
95 
97 
98 static struct cdr_tds_config *settings;
99 
100 static char *anti_injection(const char *, int);
101 static void get_date(char *, size_t len, struct timeval);
102 
103 static int execute_and_consume(DBPROCESS *dbproc, const char *fmt, ...)
104  __attribute__((format(printf, 2, 3)));
105 
106 static int mssql_connect(void);
107 static int mssql_disconnect(void);
108 
109 static int tds_log(struct ast_cdr *cdr)
110 {
111  char start[80], answer[80], end[80];
112  char *accountcode, *src, *dst, *dcontext, *clid, *channel, *dstchannel, *lastapp, *lastdata, *uniqueid, *userfield = NULL;
113  RETCODE erc;
114  int res = -1;
115  int attempt = 1;
116 
117  accountcode = anti_injection(cdr->accountcode, 20);
118  src = anti_injection(cdr->src, 80);
119  dst = anti_injection(cdr->dst, 80);
120  dcontext = anti_injection(cdr->dcontext, 80);
121  clid = anti_injection(cdr->clid, 80);
122  channel = anti_injection(cdr->channel, 80);
123  dstchannel = anti_injection(cdr->dstchannel, 80);
124  lastapp = anti_injection(cdr->lastapp, 80);
125  lastdata = anti_injection(cdr->lastdata, 80);
126  uniqueid = anti_injection(cdr->uniqueid, 32);
127 
128  get_date(start, sizeof(start), cdr->start);
129  get_date(answer, sizeof(answer), cdr->answer);
130  get_date(end, sizeof(end), cdr->end);
131 
133 
134  if (settings->has_userfield) {
135  userfield = anti_injection(cdr->userfield, AST_MAX_USER_FIELD);
136  }
137 
138 retry:
139  /* Ensure that we are connected */
140  if (!settings->connected) {
141  ast_log(LOG_NOTICE, "Attempting to reconnect to %s (Attempt %d)\n", settings->hostname, attempt);
142  if (mssql_connect()) {
143  /* Connect failed */
144  if (attempt++ < 3) {
145  goto retry;
146  }
147  goto done;
148  }
149  }
150 
151  if (settings->has_userfield) {
152  if (settings->hrtime) {
153  double hrbillsec = 0.0;
154  double hrduration;
155 
156  if (!ast_tvzero(cdr->answer)) {
157  hrbillsec = (double)(ast_tvdiff_us(cdr->end, cdr->answer) / 1000000.0);
158  }
159  hrduration = (double)(ast_tvdiff_us(cdr->end, cdr->start) / 1000000.0);
160 
161  erc = dbfcmd(settings->dbproc,
162  "INSERT INTO %s "
163  "("
164  "accountcode, src, dst, dcontext, clid, channel, "
165  "dstchannel, lastapp, lastdata, start, answer, [end], duration, "
166  "billsec, disposition, amaflags, uniqueid, userfield"
167  ") "
168  "VALUES "
169  "("
170  "'%s', '%s', '%s', '%s', '%s', '%s', "
171  "'%s', '%s', '%s', %s, %s, %s, %lf, "
172  "%lf, '%s', '%s', '%s', '%s'"
173  ")",
174  settings->table,
175  accountcode, src, dst, dcontext, clid, channel,
176  dstchannel, lastapp, lastdata, start, answer, end, hrduration,
177  hrbillsec, ast_cdr_disp2str(cdr->disposition), ast_channel_amaflags2string(cdr->amaflags), uniqueid,
178  userfield
179  );
180  } else {
181  erc = dbfcmd(settings->dbproc,
182  "INSERT INTO %s "
183  "("
184  "accountcode, src, dst, dcontext, clid, channel, "
185  "dstchannel, lastapp, lastdata, start, answer, [end], duration, "
186  "billsec, disposition, amaflags, uniqueid, userfield"
187  ") "
188  "VALUES "
189  "("
190  "'%s', '%s', '%s', '%s', '%s', '%s', "
191  "'%s', '%s', '%s', %s, %s, %s, %ld, "
192  "%ld, '%s', '%s', '%s', '%s'"
193  ")",
194  settings->table,
195  accountcode, src, dst, dcontext, clid, channel,
196  dstchannel, lastapp, lastdata, start, answer, end, cdr->duration,
197  cdr->billsec, ast_cdr_disp2str(cdr->disposition), ast_channel_amaflags2string(cdr->amaflags), uniqueid,
198  userfield
199  );
200  }
201  } else {
202  if (settings->hrtime) {
203  double hrbillsec = 0.0;
204  double hrduration;
205 
206  if (!ast_tvzero(cdr->answer)) {
207  hrbillsec = (double)(ast_tvdiff_us(cdr->end, cdr->answer) / 1000000.0);
208  }
209  hrduration = (double)(ast_tvdiff_us(cdr->end, cdr->start) / 1000000.0);
210 
211  erc = dbfcmd(settings->dbproc,
212  "INSERT INTO %s "
213  "("
214  "accountcode, src, dst, dcontext, clid, channel, "
215  "dstchannel, lastapp, lastdata, start, answer, [end], duration, "
216  "billsec, disposition, amaflags, uniqueid"
217  ") "
218  "VALUES "
219  "("
220  "'%s', '%s', '%s', '%s', '%s', '%s', "
221  "'%s', '%s', '%s', %s, %s, %s, %lf, "
222  "%lf, '%s', '%s', '%s'"
223  ")",
224  settings->table,
225  accountcode, src, dst, dcontext, clid, channel,
226  dstchannel, lastapp, lastdata, start, answer, end, hrduration,
227  hrbillsec, ast_cdr_disp2str(cdr->disposition), ast_channel_amaflags2string(cdr->amaflags), uniqueid
228  );
229  } else {
230  erc = dbfcmd(settings->dbproc,
231  "INSERT INTO %s "
232  "("
233  "accountcode, src, dst, dcontext, clid, channel, "
234  "dstchannel, lastapp, lastdata, start, answer, [end], duration, "
235  "billsec, disposition, amaflags, uniqueid"
236  ") "
237  "VALUES "
238  "("
239  "'%s', '%s', '%s', '%s', '%s', '%s', "
240  "'%s', '%s', '%s', %s, %s, %s, %ld, "
241  "%ld, '%s', '%s', '%s'"
242  ")",
243  settings->table,
244  accountcode, src, dst, dcontext, clid, channel,
245  dstchannel, lastapp, lastdata, start, answer, end, cdr->duration,
246  cdr->billsec, ast_cdr_disp2str(cdr->disposition), ast_channel_amaflags2string(cdr->amaflags), uniqueid
247  );
248  }
249  }
250 
251  if (erc == FAIL) {
252  if (attempt++ < 3) {
253  ast_log(LOG_NOTICE, "Failed to build INSERT statement, retrying...\n");
255  goto retry;
256  } else {
257  ast_log(LOG_ERROR, "Failed to build INSERT statement, no CDR was logged.\n");
258  goto done;
259  }
260  }
261 
262  if (dbsqlexec(settings->dbproc) == FAIL) {
263  if (attempt++ < 3) {
264  ast_log(LOG_NOTICE, "Failed to execute INSERT statement, retrying...\n");
266  goto retry;
267  } else {
268  ast_log(LOG_ERROR, "Failed to execute INSERT statement, no CDR was logged.\n");
269  goto done;
270  }
271  }
272 
273  /* Consume any results we might get back (this is more of a sanity check than
274  * anything else, since an INSERT shouldn't return results). */
275  while (dbresults(settings->dbproc) != NO_MORE_RESULTS) {
276  while (dbnextrow(settings->dbproc) != NO_MORE_ROWS);
277  }
278 
279  res = 0;
280 
281 done:
283 
284  ast_free(accountcode);
285  ast_free(src);
286  ast_free(dst);
287  ast_free(dcontext);
288  ast_free(clid);
289  ast_free(channel);
290  ast_free(dstchannel);
291  ast_free(lastapp);
292  ast_free(lastdata);
293  ast_free(uniqueid);
294 
295  if (userfield) {
296  ast_free(userfield);
297  }
298 
299  return res;
300 }
301 
302 static char *anti_injection(const char *str, int len)
303 {
304  /* Reference to http://www.nextgenss.com/papers/advanced_sql_injection.pdf */
305  char *buf;
306  char *buf_ptr, *srh_ptr;
307  char *known_bad[] = {"select", "insert", "update", "delete", "drop", ";", "--", "\0"};
308  int idx;
309 
310  if (!(buf = ast_calloc(1, len + 1))) {
311  ast_log(LOG_ERROR, "Out of memory\n");
312  return NULL;
313  }
314 
315  buf_ptr = buf;
316 
317  /* Escape single quotes */
318  for (; *str && strlen(buf) < len; str++) {
319  if (*str == '\'') {
320  *buf_ptr++ = '\'';
321  }
322  *buf_ptr++ = *str;
323  }
324  *buf_ptr = '\0';
325 
326  /* Erase known bad input */
327  for (idx = 0; *known_bad[idx]; idx++) {
328  while ((srh_ptr = strcasestr(buf, known_bad[idx]))) {
329  memmove(srh_ptr, srh_ptr + strlen(known_bad[idx]), strlen(srh_ptr + strlen(known_bad[idx])) + 1);
330  }
331  }
332 
333  return buf;
334 }
335 
336 static void get_date(char *dateField, size_t len, struct timeval when)
337 {
338  /* To make sure we have date variable if not insert null to SQL */
339  if (!ast_tvzero(when)) {
340  struct ast_tm tm;
341  ast_localtime(&when, &tm, NULL);
342  ast_strftime(dateField, len, "'" DATE_FORMAT "'", &tm);
343  } else {
344  ast_copy_string(dateField, "null", len);
345  }
346 }
347 
348 static int execute_and_consume(DBPROCESS *dbproc, const char *fmt, ...)
349 {
350  va_list ap;
351  char *buffer;
352 
353  va_start(ap, fmt);
354  if (ast_vasprintf(&buffer, fmt, ap) < 0) {
355  va_end(ap);
356  return 1;
357  }
358  va_end(ap);
359 
360  if (dbfcmd(dbproc, buffer) == FAIL) {
361  ast_free(buffer);
362  return 1;
363  }
364 
365  ast_free(buffer);
366 
367  if (dbsqlexec(dbproc) == FAIL) {
368  return 1;
369  }
370 
371  /* Consume the result set (we don't really care about the result, though) */
372  while (dbresults(dbproc) != NO_MORE_RESULTS) {
373  while (dbnextrow(dbproc) != NO_MORE_ROWS);
374  }
375 
376  return 0;
377 }
378 
379 static int mssql_disconnect(void)
380 {
381  if (settings->dbproc) {
382  dbclose(settings->dbproc);
383  settings->dbproc = NULL;
384  }
385 
386  settings->connected = 0;
387 
388  return 0;
389 }
390 
391 static int mssql_connect(void)
392 {
393  LOGINREC *login;
394 
395  if ((login = dblogin()) == NULL) {
396  ast_log(LOG_ERROR, "Unable to allocate login structure for db-lib\n");
397  return -1;
398  }
399 
400  DBSETLAPP(login, "TSQL");
401  DBSETLUSER(login, (char *) settings->username);
402  DBSETLPWD(login, (char *) settings->password);
403  DBSETLCHARSET(login, (char *) settings->charset);
404  DBSETLNATLANG(login, (char *) settings->language);
405 
406  if ((settings->dbproc = dbopen(login, (char *) settings->hostname)) == NULL) {
407  ast_log(LOG_ERROR, "Unable to connect to %s\n", settings->hostname);
408  dbloginfree(login);
409  return -1;
410  }
411 
412  dbloginfree(login);
413 
414  if (dbuse(settings->dbproc, (char *) settings->database) == FAIL) {
415  ast_log(LOG_ERROR, "Unable to select database %s\n", settings->database);
416  goto failed;
417  }
418 
419  if (execute_and_consume(settings->dbproc, "SELECT 1 FROM [%s] WHERE 1 = 0", settings->table)) {
420  ast_log(LOG_ERROR, "Unable to find table '%s'\n", settings->table);
421  goto failed;
422  }
423 
424  /* Check to see if we have a userfield column in the table */
425  if (execute_and_consume(settings->dbproc, "SELECT userfield FROM [%s] WHERE 1 = 0", settings->table)) {
426  ast_log(LOG_NOTICE, "Unable to find 'userfield' column in table '%s'\n", settings->table);
427  settings->has_userfield = 0;
428  } else {
429  settings->has_userfield = 1;
430  }
431 
432  settings->connected = 1;
433 
434  return 0;
435 
436 failed:
437  dbclose(settings->dbproc);
438  settings->dbproc = NULL;
439  return -1;
440 }
441 
442 static int tds_unload_module(void)
443 {
444  if (ast_cdr_unregister(name)) {
445  return -1;
446  }
447 
448  if (settings) {
452 
454  ast_free(settings);
455  }
456 
457  dbexit();
458 
459  return 0;
460 }
461 
462 static int tds_error_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr)
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 }
472 
473 static int tds_message_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, int severity, char *msgtext, char *srvname, char *procname, int line)
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 }
480 
481 static int tds_load_module(int 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 */
503  ast_string_field_init(settings, 0);
504 
505  /* 'connection' is the new preferred configuration option */
506  ptr = ast_variable_retrieve(cfg, "global", "connection");
507  if (ptr) {
508  ast_string_field_set(settings, hostname, ptr);
509  } else {
510  /* But we keep 'hostname' for backwards compatibility */
511  ptr = ast_variable_retrieve(cfg, "global", "hostname");
512  if (ptr) {
513  ast_string_field_set(settings, hostname, 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) {
546  ast_string_field_set(settings, charset, ptr);
547  } else {
548  ast_string_field_set(settings, charset, "iso_1");
549  }
550 
551  ptr = ast_variable_retrieve(cfg, "global", "language");
552  if (ptr) {
553  ast_string_field_set(settings, language, 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) {
560  ast_string_field_set(settings, table, ptr);
561  } else {
562  ast_log(LOG_NOTICE, "Table name not specified, using 'cdr' by default.\n");
563  ast_string_field_set(settings, table, "cdr");
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 }
591 
592 static int reload(void)
593 {
594  return tds_load_module(1);
595 }
596 
597 static int load_module(void)
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 
607  settings = ast_calloc_with_stringfields(1, struct cdr_tds_config, 256);
608 
609  if (!settings) {
610  dbexit();
612  }
613 
614  if (!tds_load_module(0)) {
616  ast_free(settings);
617  settings = NULL;
618  dbexit();
620  }
621 
623 
625 }
626 
627 static int unload_module(void)
628 {
629  return tds_unload_module();
630 }
631 
633  .support_level = AST_MODULE_SUPPORT_EXTENDED,
634  .load = load_module,
635  .unload = unload_module,
636  .reload = reload,
637  .load_pri = AST_MODPRI_CDR_DRIVER,
638  .requires = "cdr",
639 );
const char * description
Definition: module.h:352
static char accountcode[AST_MAX_ACCOUNT_CODE]
Definition: chan_iax2.c:428
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
static char * anti_injection(const char *, int)
Definition: cdr_tds.c:302
static const char config[]
Definition: cdr_tds.c:78
static int tds_log(struct ast_cdr *cdr)
Definition: cdr_tds.c:109
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
const ast_string_field hostname
Definition: cdr_tds.c:90
const ast_string_field table
Definition: cdr_tds.c:90
#define CONFIG_STATUS_FILEINVALID
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
static ast_mutex_t tds_lock
Definition: cdr_tds.c:96
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition: time.h:108
#define ast_calloc_with_stringfields(n, type, size)
Allocate a structure with embedded stringfields in a single allocation.
Definition: stringfields.h:426
const char * ast_channel_amaflags2string(enum ama_flags flags)
Convert the enum representation of an AMA flag to a string representation.
Definition: channel.c:4418
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:337
DBPROCESS * dbproc
Definition: cdr_tds.c:91
const ast_string_field hrtime
Definition: cdr_tds.c:90
#define ast_mutex_lock(a)
Definition: lock.h:187
Definition: muted.c:95
#define ast_vasprintf(ret, fmt, ap)
A wrapper for vasprintf()
Definition: astmm.h:280
const char * str
Definition: app_jack.c:147
#define NULL
Definition: resample.c:96
char * end
Definition: eagi_proxy.c:73
const ast_string_field language
Definition: cdr_tds.c:90
static int mssql_connect(void)
Definition: cdr_tds.c:391
int done
Definition: test_amihooks.c:48
Call Detail Record API.
static int load_module(void)
Definition: cdr_tds.c:597
Configuration File Parser.
static int reload(void)
Definition: cdr_tds.c:592
static int mssql_disconnect(void)
Definition: cdr_tds.c:379
#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 int execute_and_consume(DBPROCESS *dbproc, const char *fmt,...)
Definition: cdr_tds.c:348
General Asterisk PBX channel definitions.
unsigned int connected
Definition: cdr_tds.c:92
unsigned int has_userfield
Definition: cdr_tds.c:93
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:353
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:299
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
static int answer(void *data)
Definition: chan_pjsip.c:682
#define CONFIG_STATUS_FILEUNCHANGED
Responsible for call detail data.
Definition: cdr.h:276
const char * ast_cdr_disp2str(int disposition)
Disposition to a string.
Definition: cdr.c:3430
#define LOG_ERROR
Definition: logger.h:285
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
static int tds_error_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr)
Definition: cdr_tds.c:462
const ast_string_field username
Definition: cdr_tds.c:90
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
const ast_string_field password
Definition: cdr_tds.c:90
#define LOG_NOTICE
Definition: logger.h:263
char * strcasestr(const char *, const char *)
const ast_string_field charset
Definition: cdr_tds.c:90
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
#define DATE_FORMAT
Definition: cdr_tds.c:75
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
const ast_string_field database
Definition: cdr_tds.c:90
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
Structure used to handle boolean flags.
Definition: utils.h:199
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",)
static int unload_module(void)
Definition: cdr_tds.c:627
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:694
static int tds_load_module(int reload)
Definition: cdr_tds.c:481
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
static const char name[]
Definition: cdr_tds.c:77
enum ast_security_event_severity severity
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
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
static snd_pcm_format_t format
Definition: chan_alsa.c:102
static struct cdr_tds_config * settings
Definition: cdr_tds.c:98
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:368
DB * dbopen(char *fname, int flags, int mode, DBTYPE type, const void *openinfo) const
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:518
static int tds_unload_module(void)
Definition: cdr_tds.c:442
#define ast_mutex_unlock(a)
Definition: lock.h:188
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:514
static void get_date(char *, size_t len, struct timeval)
Definition: cdr_tds.c:336
#define AST_MAX_USER_FIELD
Definition: channel.h:175