[asterisk-commits] juggie: branch juggie/NoLossCDR r104118 - /team/juggie/NoLossCDR/cdr/
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Mon Feb 25 18:22:40 CST 2008
Author: juggie
Date: Mon Feb 25 18:22:40 2008
New Revision: 104118
URL: http://svn.digium.com/view/asterisk?view=rev&rev=104118
Log:
fix cdr backends
Modified:
team/juggie/NoLossCDR/cdr/cdr_adaptive_odbc.c
team/juggie/NoLossCDR/cdr/cdr_csv.c
team/juggie/NoLossCDR/cdr/cdr_custom.c
team/juggie/NoLossCDR/cdr/cdr_manager.c
team/juggie/NoLossCDR/cdr/cdr_odbc.c
team/juggie/NoLossCDR/cdr/cdr_pgsql.c
team/juggie/NoLossCDR/cdr/cdr_radius.c
team/juggie/NoLossCDR/cdr/cdr_sqlite.c
team/juggie/NoLossCDR/cdr/cdr_sqlite3_custom.c
team/juggie/NoLossCDR/cdr/cdr_tds.c
Modified: team/juggie/NoLossCDR/cdr/cdr_adaptive_odbc.c
URL: http://svn.digium.com/view/asterisk/team/juggie/NoLossCDR/cdr/cdr_adaptive_odbc.c?view=diff&rev=104118&r1=104117&r2=104118
==============================================================================
--- team/juggie/NoLossCDR/cdr/cdr_adaptive_odbc.c (original)
+++ team/juggie/NoLossCDR/cdr/cdr_adaptive_odbc.c Mon Feb 25 18:22:40 2008
@@ -25,7 +25,7 @@
*/
/*** MODULEINFO
- <depend>unixODBC</depend>
+ <depend>unixodbc</depend>
***/
#include "asterisk.h"
@@ -33,10 +33,6 @@
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <sys/types.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
#include <time.h>
#include <sql.h>
@@ -44,25 +40,23 @@
#include <sqltypes.h>
#include "asterisk/config.h"
-#include "asterisk/options.h"
#include "asterisk/channel.h"
#include "asterisk/lock.h"
#include "asterisk/linkedlists.h"
#include "asterisk/res_odbc.h"
#include "asterisk/cdr.h"
#include "asterisk/module.h"
-#include "asterisk/logger.h"
-
-#define CONFIG "cdr_adaptive_odbc.conf"
+
+#define CONFIG "cdr_adaptive_odbc.conf"
static char *name = "Adaptive ODBC";
-
/* Optimization to reduce number of memory allocations */
static int maxsize = 512, maxsize2 = 512;
struct columns {
char *name;
char *cdrname;
+ char *filtervalue;
SQLSMALLINT type;
SQLINTEGER size;
SQLSMALLINT decimals;
@@ -72,30 +66,21 @@
AST_LIST_ENTRY(columns) list;
};
-struct table {
+struct tables {
char *connection;
char *table;
AST_LIST_HEAD_NOLOCK(odbc_columns, columns) columns;
+ AST_RWLIST_ENTRY(tables) list;
};
-static int odbc_log(struct ast_cdr *, void *);
-
-static void free_table(void *data)
-{
- struct columns *entry;
- struct table *table = (struct table *) data;
- while ((entry = AST_LIST_REMOVE_HEAD(&(table->columns), list))) {
- ast_free(entry);
- }
- ast_free(table);
-}
+static AST_RWLIST_HEAD_STATIC(odbc_tables, tables);
static int load_config(void)
{
struct ast_config *cfg;
struct ast_variable *var;
const char *tmp, *catg;
- struct table *tableptr;
+ struct tables *tableptr;
struct columns *entry;
struct odbc_obj *obj;
char columnname[80];
@@ -168,6 +153,31 @@
ast_verb(3, "Found adaptive CDR table %s@%s.\n", tableptr->table, tableptr->connection);
+ /* Check for filters first */
+ for (var = ast_variable_browse(cfg, catg); var; var = var->next) {
+ if (strncmp(var->name, "filter", 6) == 0) {
+ char *cdrvar = ast_strdupa(var->name + 6);
+ cdrvar = ast_strip(cdrvar);
+ ast_verb(3, "Found filter %s for cdr variable %s in %s@%s\n", var->value, cdrvar, tableptr->table, tableptr->connection);
+
+ entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(cdrvar) + 1 + strlen(var->value) + 1);
+ if (!entry) {
+ ast_log(LOG_ERROR, "Out of memory creating filter entry for CDR variable '%s' in table '%s' on connection '%s'\n", cdrvar, table, connection);
+ res = -1;
+ break;
+ }
+
+ /* NULL column entry means this isn't a column in the database */
+ entry->name = NULL;
+ entry->cdrname = (char *)entry + sizeof(*entry);
+ entry->filtervalue = (char *)entry + sizeof(*entry) + strlen(cdrvar) + 1;
+ strcpy(entry->cdrname, cdrvar);
+ strcpy(entry->filtervalue, var->value);
+
+ AST_LIST_INSERT_TAIL(&(tableptr->columns), entry, list);
+ }
+ }
+
while ((res = SQLFetch(stmt)) != SQL_NO_DATA && res != SQL_ERROR) {
char *cdrvar = "";
@@ -180,13 +190,14 @@
* really don't parse this file all that often, anyway.
*/
for (var = ast_variable_browse(cfg, catg); var; var = var->next) {
- if (strcasecmp(var->value, columnname) == 0) {
+ if (strncmp(var->name, "alias", 5) == 0 && strcasecmp(var->value, columnname) == 0) {
char *tmp = ast_strdupa(var->name + 5);
cdrvar = ast_strip(tmp);
ast_verb(3, "Found alias %s for column %s in %s@%s\n", cdrvar, columnname, tableptr->table, tableptr->connection);
break;
}
}
+
entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(columnname) + 1 + strlen(cdrvar) + 1);
if (!entry) {
ast_log(LOG_ERROR, "Out of memory creating entry for column '%s' in table '%s' on connection '%s'\n", columnname, table, connection);
@@ -202,12 +213,12 @@
} else /* Point to same place as the column name */
entry->cdrname = (char *)entry + sizeof(*entry);
- SQLGetData(stmt, 5, SQL_C_SHORT, &entry->type, sizeof(entry->type), NULL);
- SQLGetData(stmt, 7, SQL_C_LONG, &entry->size, sizeof(entry->size), NULL);
+ SQLGetData(stmt, 5, SQL_C_SHORT, &entry->type, sizeof(entry->type), NULL);
+ SQLGetData(stmt, 7, SQL_C_LONG, &entry->size, sizeof(entry->size), NULL);
SQLGetData(stmt, 9, SQL_C_SHORT, &entry->decimals, sizeof(entry->decimals), NULL);
- SQLGetData(stmt, 10, SQL_C_SHORT, &entry->radix, sizeof(entry->radix), NULL);
+ SQLGetData(stmt, 10, SQL_C_SHORT, &entry->radix, sizeof(entry->radix), NULL);
SQLGetData(stmt, 11, SQL_C_SHORT, &entry->nullable, sizeof(entry->nullable), NULL);
- SQLGetData(stmt, 16, SQL_C_LONG, &entry->octetlen, sizeof(entry->octetlen), NULL);
+ SQLGetData(stmt, 16, SQL_C_LONG, &entry->octetlen, sizeof(entry->octetlen), NULL);
/* Specification states that the octenlen should be the maximum number of bytes
* returned in a char or binary column, but it seems that some drivers just set
@@ -224,17 +235,25 @@
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
ast_odbc_release_obj(obj);
- if (AST_LIST_FIRST(&(tableptr->columns))) {
- res = ast_cdr_register(name, catg, ast_module_info->description, odbc_log, free_table, tableptr);
- if (res) {
- ast_log(LOG_ERROR, "Unable to register Adaptive ODBC handler sink \"%s\"\n", catg);
- if (tableptr)
- free_table(tableptr);
- }
- } else
+ if (AST_LIST_FIRST(&(tableptr->columns)))
+ AST_RWLIST_INSERT_TAIL(&odbc_tables, tableptr, list);
+ else
ast_free(tableptr);
}
return res;
+}
+
+static int free_config(void)
+{
+ struct tables *table;
+ struct columns *entry;
+ while ((table = AST_RWLIST_REMOVE_HEAD(&odbc_tables, list))) {
+ while ((entry = AST_LIST_REMOVE_HEAD(&(table->columns), list))) {
+ ast_free(entry);
+ }
+ ast_free(table);
+ }
+ return 0;
}
static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
@@ -282,7 +301,8 @@
ast_log(LOG_ERROR, "Unable to allocate sufficient memory. Insert CDR '%s:%s' failed.\n", tableptr->connection, tableptr->table); \
ast_free(sql); \
ast_free(sql2); \
- return AST_CDR_POST_FAILED; \
+ AST_RWLIST_UNLOCK(&odbc_tables); \
+ return -1; \
} \
} \
} while (0)
@@ -297,14 +317,15 @@
ast_log(LOG_ERROR, "Unable to allocate sufficient memory. Insert CDR '%s:%s' failed.\n", tableptr->connection, tableptr->table); \
ast_free(sql); \
ast_free(sql2); \
- return AST_CDR_POST_FAILED; \
+ AST_RWLIST_UNLOCK(&odbc_tables); \
+ return -1; \
} \
} \
} while (0)
-static int odbc_log(struct ast_cdr *cdr, void *data)
+static int odbc_log(struct ast_cdr *cdr)
{
- struct table *tableptr;
+ struct tables *tableptr;
struct columns *entry;
struct odbc_obj *obj;
int lensql, lensql2, sizesql = maxsize, sizesql2 = maxsize2, newsize;
@@ -313,257 +334,285 @@
char colbuf[1024], *colptr;
SQLHSTMT stmt = NULL;
SQLLEN rows = 0;
- int res = AST_CDR_POST_OK;
-
- tableptr = (struct table *) data;
-
- lensql = snprintf(sql, sizesql, "INSERT INTO %s (", tableptr->table);
- lensql2 = snprintf(sql2, sizesql2, " VALUES (");
-
- AST_LIST_TRAVERSE(&(tableptr->columns), entry, list) {
- /* Check if we have a similarly named variable */
- ast_cdr_getvar(cdr, entry->cdrname, &colptr, colbuf, sizeof(colbuf), 0,
- (strcasecmp(entry->cdrname, "start") == 0 ||
- strcasecmp(entry->cdrname, "answer") == 0 ||
- strcasecmp(entry->cdrname, "end") == 0) ? 0 : 1);
-
- if (colptr) {
- LENGTHEN_BUF1(strlen(entry->name));
-
- switch (entry->type) {
- case SQL_CHAR:
- case SQL_VARCHAR:
- case SQL_LONGVARCHAR:
- case SQL_BINARY:
- case SQL_VARBINARY:
- case SQL_LONGVARBINARY:
- case SQL_GUID:
- /* For these two field names, get the rendered form, instead of the raw
- * form (but only when we're dealing with a character-based field).
- */
- if (strcasecmp(entry->name, "disposition") == 0)
- ast_cdr_getvar(cdr, entry->name, &colptr, colbuf, sizeof(colbuf), 0, 0);
- else if (strcasecmp(entry->name, "amaflags") == 0)
- ast_cdr_getvar(cdr, entry->name, &colptr, colbuf, sizeof(colbuf), 0, 0);
-
- /* Truncate too-long fields */
- if (entry->type != SQL_GUID) {
- if (strlen(colptr) > entry->octetlen)
- colptr[entry->octetlen] = '\0';
+
+ if (!sql || !sql2) {
+ if (sql)
+ ast_free(sql);
+ if (sql2)
+ ast_free(sql2);
+ return -1;
+ }
+
+ if (AST_RWLIST_RDLOCK(&odbc_tables)) {
+ ast_log(LOG_ERROR, "Unable to lock table list. Insert CDR(s) failed.\n");
+ ast_free(sql);
+ ast_free(sql2);
+ return -1;
+ }
+
+ AST_LIST_TRAVERSE(&odbc_tables, tableptr, list) {
+ lensql = snprintf(sql, sizesql, "INSERT INTO %s (", tableptr->table);
+ lensql2 = snprintf(sql2, sizesql2, " VALUES (");
+
+ /* No need to check the connection now; we'll handle any failure in prepare_and_execute */
+ if (!(obj = ast_odbc_request_obj(tableptr->connection, 0))) {
+ ast_log(LOG_WARNING, "cdr_adaptive_odbc: Unable to retrieve database handle for '%s:%s'. CDR failed: %s\n", tableptr->connection, tableptr->table, sql);
+ continue;
+ }
+
+ AST_LIST_TRAVERSE(&(tableptr->columns), entry, list) {
+ /* Check if we have a similarly named variable */
+ ast_cdr_getvar(cdr, entry->cdrname, &colptr, colbuf, sizeof(colbuf), 0,
+ (strcasecmp(entry->cdrname, "start") == 0 ||
+ strcasecmp(entry->cdrname, "answer") == 0 ||
+ strcasecmp(entry->cdrname, "end") == 0) ? 0 : 1);
+
+ if (colptr) {
+ /* Check first if the column filters this entry. Note that this
+ * is very specifically NOT ast_strlen_zero(), because the filter
+ * could legitimately specify that the field is blank, which is
+ * different from the field being unspecified (NULL). */
+ if (entry->filtervalue && strcasecmp(colptr, entry->filtervalue) != 0) {
+ ast_verb(4, "CDR column '%s' with value '%s' does not match filter of"
+ " '%s'. Cancelling this CDR.\n",
+ entry->cdrname, colptr, entry->filtervalue);
+ goto early_release;
}
- lensql += snprintf(sql + lensql, sizesql - lensql, "%s,", entry->name);
- LENGTHEN_BUF2(strlen(colptr));
-
- /* Encode value, with escaping */
- strcpy(sql2 + lensql2, "'");
- lensql2++;
- for (tmp = colptr; *tmp; tmp++) {
- if (*tmp == '\'') {
- strcpy(sql2 + lensql2, "''");
- lensql2 += 2;
- } else if (*tmp == '\\') {
- strcpy(sql2 + lensql2, "\\\\");
- lensql2 += 2;
- } else {
- sql2[lensql2++] = *tmp;
- sql2[lensql2] = '\0';
- }
+ /* Only a filter? */
+ if (ast_strlen_zero(entry->name))
+ continue;
+
+ LENGTHEN_BUF1(strlen(entry->name));
+
+ switch (entry->type) {
+ case SQL_CHAR:
+ case SQL_VARCHAR:
+ case SQL_LONGVARCHAR:
+ case SQL_BINARY:
+ case SQL_VARBINARY:
+ case SQL_LONGVARBINARY:
+ case SQL_GUID:
+ /* For these two field names, get the rendered form, instead of the raw
+ * form (but only when we're dealing with a character-based field).
+ */
+ if (strcasecmp(entry->name, "disposition") == 0)
+ ast_cdr_getvar(cdr, entry->name, &colptr, colbuf, sizeof(colbuf), 0, 0);
+ else if (strcasecmp(entry->name, "amaflags") == 0)
+ ast_cdr_getvar(cdr, entry->name, &colptr, colbuf, sizeof(colbuf), 0, 0);
+
+ /* Truncate too-long fields */
+ if (entry->type != SQL_GUID) {
+ if (strlen(colptr) > entry->octetlen)
+ colptr[entry->octetlen] = '\0';
+ }
+
+ lensql += snprintf(sql + lensql, sizesql - lensql, "%s,", entry->name);
+ LENGTHEN_BUF2(strlen(colptr));
+
+ /* Encode value, with escaping */
+ strcpy(sql2 + lensql2, "'");
+ lensql2++;
+ for (tmp = colptr; *tmp; tmp++) {
+ if (*tmp == '\'') {
+ strcpy(sql2 + lensql2, "''");
+ lensql2 += 2;
+ } else if (*tmp == '\\' && ast_odbc_backslash_is_escape(obj)) {
+ strcpy(sql2 + lensql2, "\\\\");
+ lensql2 += 2;
+ } else {
+ sql2[lensql2++] = *tmp;
+ sql2[lensql2] = '\0';
+ }
+ }
+ strcpy(sql2 + lensql2, "',");
+ lensql2 += 2;
+ break;
+ case SQL_TYPE_DATE:
+ {
+ int year = 0, month = 0, day = 0;
+ if (sscanf(colptr, "%d-%d-%d", &year, &month, &day) != 3 || year <= 0 ||
+ month <= 0 || month > 12 || day < 0 || day > 31 ||
+ ((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) ||
+ (month == 2 && year % 400 == 0 && day > 29) ||
+ (month == 2 && year % 100 == 0 && day > 28) ||
+ (month == 2 && year % 4 == 0 && day > 29) ||
+ (month == 2 && year % 4 != 0 && day > 28)) {
+ ast_log(LOG_WARNING, "CDR variable %s is not a valid date ('%s').\n", entry->name, colptr);
+ break;
+ }
+
+ if (year > 0 && year < 100)
+ year += 2000;
+
+ lensql += snprintf(sql + lensql, sizesql - lensql, "%s,", entry->name);
+ LENGTHEN_BUF2(17);
+ lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "{ d '%04d-%02d-%02d' },", year, month, day);
+ }
+ break;
+ case SQL_TYPE_TIME:
+ {
+ int hour = 0, minute = 0, second = 0;
+ int count = sscanf(colptr, "%d:%d:%d", &hour, &minute, &second);
+
+ if ((count != 2 && count != 3) || hour < 0 || hour > 23 || minute < 0 || minute > 59 || second < 0 || second > 59) {
+ ast_log(LOG_WARNING, "CDR variable %s is not a valid time ('%s').\n", entry->name, colptr);
+ break;
+ }
+
+ lensql += snprintf(sql + lensql, sizesql - lensql, "%s,", entry->name);
+ LENGTHEN_BUF2(15);
+ lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "{ t '%02d:%02d:%02d' },", hour, minute, second);
+ }
+ break;
+ case SQL_TYPE_TIMESTAMP:
+ case SQL_TIMESTAMP:
+ {
+ int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;
+ int count = sscanf(colptr, "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &minute, &second);
+
+ if ((count != 3 && count != 5 && count != 6) || year <= 0 ||
+ month <= 0 || month > 12 || day < 0 || day > 31 ||
+ ((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) ||
+ (month == 2 && year % 400 == 0 && day > 29) ||
+ (month == 2 && year % 100 == 0 && day > 28) ||
+ (month == 2 && year % 4 == 0 && day > 29) ||
+ (month == 2 && year % 4 != 0 && day > 28) ||
+ hour > 23 || minute > 59 || second > 59 || hour < 0 || minute < 0 || second < 0) {
+ ast_log(LOG_WARNING, "CDR variable %s is not a valid timestamp ('%s').\n", entry->name, colptr);
+ break;
+ }
+
+ if (year > 0 && year < 100)
+ year += 2000;
+
+ lensql += snprintf(sql + lensql, sizesql - lensql, "%s,", entry->name);
+ LENGTHEN_BUF2(26);
+ lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "{ ts '%04d-%02d-%02d %02d:%02d:%02d' },", year, month, day, hour, minute, second);
+ }
+ break;
+ case SQL_INTEGER:
+ {
+ int integer = 0;
+ if (sscanf(colptr, "%d", &integer) != 1) {
+ ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name);
+ break;
+ }
+
+ lensql += snprintf(sql + lensql, sizesql - lensql, "%s,", entry->name);
+ LENGTHEN_BUF2(12);
+ lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%d,", integer);
+ }
+ break;
+ case SQL_BIGINT:
+ {
+ long long integer = 0;
+ if (sscanf(colptr, "%lld", &integer) != 1) {
+ ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name);
+ break;
+ }
+
+ lensql += snprintf(sql + lensql, sizesql - lensql, "%s,", entry->name);
+ LENGTHEN_BUF2(24);
+ lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%lld,", integer);
+ }
+ break;
+ case SQL_SMALLINT:
+ {
+ short integer = 0;
+ if (sscanf(colptr, "%hd", &integer) != 1) {
+ ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name);
+ break;
+ }
+
+ lensql += snprintf(sql + lensql, sizesql - lensql, "%s,", entry->name);
+ LENGTHEN_BUF2(6);
+ lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%d,", integer);
+ }
+ break;
+ case SQL_TINYINT:
+ {
+ char integer = 0;
+ if (sscanf(colptr, "%hhd", &integer) != 1) {
+ ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name);
+ break;
+ }
+
+ lensql += snprintf(sql + lensql, sizesql - lensql, "%s,", entry->name);
+ LENGTHEN_BUF2(4);
+ lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%d,", integer);
+ }
+ break;
+ case SQL_BIT:
+ {
+ char integer = 0;
+ if (sscanf(colptr, "%hhd", &integer) != 1) {
+ ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name);
+ break;
+ }
+ if (integer != 0)
+ integer = 1;
+
+ lensql += snprintf(sql + lensql, sizesql - lensql, "%s,", entry->name);
+ LENGTHEN_BUF2(2);
+ lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%d,", integer);
+ }
+ break;
+ case SQL_NUMERIC:
+ case SQL_DECIMAL:
+ {
+ double number = 0.0;
+ if (sscanf(colptr, "%lf", &number) != 1) {
+ ast_log(LOG_WARNING, "CDR variable %s is not an numeric type.\n", entry->name);
+ break;
+ }
+
+ lensql += snprintf(sql + lensql, sizesql - lensql, "%s,", entry->name);
+ LENGTHEN_BUF2(entry->decimals);
+ lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%*.*lf,", entry->decimals, entry->radix, number);
+ }
+ break;
+ case SQL_FLOAT:
+ case SQL_REAL:
+ case SQL_DOUBLE:
+ {
+ double number = 0.0;
+ if (sscanf(colptr, "%lf", &number) != 1) {
+ ast_log(LOG_WARNING, "CDR variable %s is not an numeric type.\n", entry->name);
+ break;
+ }
+
+ lensql += snprintf(sql + lensql, sizesql - lensql, "%s,", entry->name);
+ LENGTHEN_BUF2(entry->decimals);
+ lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%lf,", number);
+ }
+ break;
+ default:
+ ast_log(LOG_WARNING, "Column type %d (field '%s:%s:%s') is unsupported at this time.\n", entry->type, tableptr->connection, tableptr->table, entry->name);
}
- strcpy(sql2 + lensql2, "',");
- lensql2 += 2;
- break;
- case SQL_TYPE_DATE:
- {
- int year = 0, month = 0, day = 0;
- if (sscanf(colptr, "%d-%d-%d", &year, &month, &day) != 3 || year <= 0 ||
- month <= 0 || month > 12 || day < 0 || day > 31 ||
- ((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) ||
- (month == 2 && year % 400 == 0 && day > 29) ||
- (month == 2 && year % 100 == 0 && day > 28) ||
- (month == 2 && year % 4 == 0 && day > 29) ||
- (month == 2 && year % 4 != 0 && day > 28)) {
- ast_log(LOG_WARNING, "CDR variable %s is not a valid date ('%s').\n", entry->name, colptr);
- break;
- }
-
- if (year > 0 && year < 100)
- year += 2000;
-
- lensql += snprintf(sql + lensql, sizesql - lensql, "%s,", entry->name);
- LENGTHEN_BUF2(10);
- lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "'%04d-%02d-%02d',", year, month, day);
- }
- break;
- case SQL_TYPE_TIME:
- {
- int hour = 0, minute = 0, second = 0;
- int count = sscanf(colptr, "%d:%d:%d", &hour, &minute, &second);
-
- if ((count != 2 && count != 3) || hour < 0 || hour > 23 || minute < 0 || minute > 59 || second < 0 || second > 59) {
- ast_log(LOG_WARNING, "CDR variable %s is not a valid time ('%s').\n", entry->name, colptr);
- break;
- }
-
- lensql += snprintf(sql + lensql, sizesql - lensql, "%s,", entry->name);
- LENGTHEN_BUF2(8);
- lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "'%02d:%02d:%02d',", hour, minute, second);
- }
- break;
- case SQL_TYPE_TIMESTAMP:
- case SQL_TIMESTAMP:
- {
- int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;
- int count = sscanf(colptr, "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &minute, &second);
-
- if ((count != 3 && count != 5 && count != 6) || year <= 0 ||
- month <= 0 || month > 12 || day < 0 || day > 31 ||
- ((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) ||
- (month == 2 && year % 400 == 0 && day > 29) ||
- (month == 2 && year % 100 == 0 && day > 28) ||
- (month == 2 && year % 4 == 0 && day > 29) ||
- (month == 2 && year % 4 != 0 && day > 28) ||
- hour > 23 || minute > 59 || second > 59 || hour < 0 || minute < 0 || second < 0) {
- ast_log(LOG_WARNING, "CDR variable %s is not a valid timestamp ('%s').\n", entry->name, colptr);
- break;
- }
-
- if (year > 0 && year < 100)
- year += 2000;
-
- lensql += snprintf(sql + lensql, sizesql - lensql, "%s,", entry->name);
- LENGTHEN_BUF2(19);
- lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "'%04d-%02d-%02d %02d:%02d:%02d',", year, month, day, hour, minute, second);
- }
- break;
- case SQL_INTEGER:
- {
- int integer = 0;
- if (sscanf(colptr, "%d", &integer) != 1) {
- ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name);
- break;
- }
-
- lensql += snprintf(sql + lensql, sizesql - lensql, "%s,", entry->name);
- LENGTHEN_BUF2(12);
- lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%d,", integer);
- }
- break;
- case SQL_BIGINT:
- {
- long long integer = 0;
- if (sscanf(colptr, "%lld", &integer) != 1) {
- ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name);
- break;
- }
-
- lensql += snprintf(sql + lensql, sizesql - lensql, "%s,", entry->name);
- LENGTHEN_BUF2(24);
- lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%lld,", integer);
- }
- break;
- case SQL_SMALLINT:
- {
- short integer = 0;
- if (sscanf(colptr, "%hd", &integer) != 1) {
- ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name);
- break;
- }
-
- lensql += snprintf(sql + lensql, sizesql - lensql, "%s,", entry->name);
- LENGTHEN_BUF2(6);
- lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%d,", integer);
- }
- break;
- case SQL_TINYINT:
- {
- char integer = 0;
- if (sscanf(colptr, "%hhd", &integer) != 1) {
- ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name);
- break;
- }
-
- lensql += snprintf(sql + lensql, sizesql - lensql, "%s,", entry->name);
- LENGTHEN_BUF2(4);
- lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%d,", integer);
- }
- break;
- case SQL_BIT:
- {
- char integer = 0;
- if (sscanf(colptr, "%hhd", &integer) != 1) {
- ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name);
- break;
- }
- if (integer != 0)
- integer = 1;
-
- lensql += snprintf(sql + lensql, sizesql - lensql, "%s,", entry->name);
- LENGTHEN_BUF2(2);
- lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%d,", integer);
- }
- break;
- case SQL_NUMERIC:
- case SQL_DECIMAL:
- {
- double number = 0.0;
- if (sscanf(colptr, "%lf", &number) != 1) {
- ast_log(LOG_WARNING, "CDR variable %s is not an numeric type.\n", entry->name);
- break;
- }
-
- lensql += snprintf(sql + lensql, sizesql - lensql, "%s,", entry->name);
- LENGTHEN_BUF2(entry->decimals);
- lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%*.*lf,", entry->decimals, entry->radix, number);
- }
- break;
- case SQL_FLOAT:
- case SQL_REAL:
- case SQL_DOUBLE:
- {
- double number = 0.0;
- if (sscanf(colptr, "%lf", &number) != 1) {
- ast_log(LOG_WARNING, "CDR variable %s is not an numeric type.\n", entry->name);
- break;
- }
-
- lensql += snprintf(sql + lensql, sizesql - lensql, "%s,", entry->name);
- LENGTHEN_BUF2(entry->decimals);
- lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%lf,", number);
- }
- break;
- default:
- ast_log(LOG_WARNING, "Column type %d (field '%s:%s:%s') is unsupported at this time.\n", entry->type, tableptr->connection, tableptr->table, entry->name);
}
}
- }
-
- /* Concatenate the two constructed buffers */
- LENGTHEN_BUF1(lensql2);
- sql[lensql - 1] = ')';
- sql2[lensql2 - 1] = ')';
- strcat(sql + lensql, sql2);
-
- ast_verb(11, "[%s]\n", sql);
-
- /* No need to check the connection now; we'll handle any failure in prepare_and_execute */
- obj = ast_odbc_request_obj(tableptr->connection, 0);
- if (obj) {
+
+ /* Concatenate the two constructed buffers */
+ LENGTHEN_BUF1(lensql2);
+ sql[lensql - 1] = ')';
+ sql2[lensql2 - 1] = ')';
+ strcat(sql + lensql, sql2);
+
+ ast_verb(11, "[%s]\n", sql);
+
stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, sql);
if (stmt) {
SQLRowCount(stmt, &rows);
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
}
if (rows == 0) {
- ast_log(LOG_WARNING, "Insert failed on '%s:%s'. CDR failed: %s\n", tableptr->connection, tableptr->table, sql);
- /* We have to assume SQL error here I think, so don't retry. */
- res = AST_CDR_POST_FAILED;
- }
+ ast_log(LOG_WARNING, "cdr_adaptive_odbc: Insert failed on '%s:%s'. CDR failed: %s\n", tableptr->connection, tableptr->table, sql);
+ }
+early_release:
ast_odbc_release_obj(obj);
- } else {
- ast_log(LOG_WARNING, "Unable to retrieve database handle for '%s:%s'. CDR failed: %s\n", tableptr->connection, tableptr->table, sql);
- res = AST_CDR_POST_FAILED;
- }
+ }
+ AST_RWLIST_UNLOCK(&odbc_tables);
/* Next time, just allocate buffers that are that big to start with. */
if (sizesql > maxsize)
@@ -573,34 +622,53 @@
ast_free(sql);
ast_free(sql2);
-
- return res;
+ return 0;
}
static int unload_module(void)
{
- ast_cdr_unregister(name, NULL);
-
+ ast_cdr_unregister(name);
+ usleep(1);
+ if (AST_RWLIST_WRLOCK(&odbc_tables)) {
+ ast_cdr_register(name, ast_module_info->description, odbc_log);
+ ast_log(LOG_ERROR, "Unable to lock column list. Unload failed.\n");
+ return -1;
+ }
+
+ free_config();
+ AST_RWLIST_UNLOCK(&odbc_tables);
return 0;
}
static int load_module(void)
{
+ if (AST_RWLIST_WRLOCK(&odbc_tables)) {
+ ast_log(LOG_ERROR, "Unable to lock column list. Load failed.\n");
+ return 0;
+ }
+
load_config();
-
+ AST_RWLIST_UNLOCK(&odbc_tables);
+ ast_cdr_register(name, ast_module_info->description, odbc_log);
return 0;
}
static int reload(void)
{
- unload_module();
- load_module();
-
+ if (AST_RWLIST_WRLOCK(&odbc_tables)) {
+ ast_log(LOG_ERROR, "Unable to lock column list. Reload failed.\n");
+ return -1;
+ }
+
+ free_config();
+ load_config();
+ AST_RWLIST_UNLOCK(&odbc_tables);
return 0;
}
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Adaptive ODBC CDR Backend",
- .load = load_module,
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Adaptive ODBC CDR backend",
+ .load = load_module,
.unload = unload_module,
.reload = reload,
);
+
Modified: team/juggie/NoLossCDR/cdr/cdr_csv.c
URL: http://svn.digium.com/view/asterisk/team/juggie/NoLossCDR/cdr/cdr_csv.c?view=diff&rev=104118&r1=104117&r2=104118
==============================================================================
--- team/juggie/NoLossCDR/cdr/cdr_csv.c (original)
+++ team/juggie/NoLossCDR/cdr/cdr_csv.c Mon Feb 25 18:22:40 2008
@@ -32,21 +32,13 @@
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-#include <sys/types.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-
-#include <stdlib.h>
-#include <unistd.h>
#include <time.h>
+#include "asterisk/paths.h" /* use ast_config_AST_LOG_DIR */
#include "asterisk/config.h"
#include "asterisk/channel.h"
#include "asterisk/cdr.h"
#include "asterisk/module.h"
-#include "asterisk/options.h"
-#include "asterisk/logger.h"
#include "asterisk/utils.h"
#include "asterisk/lock.h"
@@ -266,7 +258,7 @@
return -1;
}
- snprintf(tmp, sizeof(tmp), "%s/%s/%s.csv", (char *)ast_config_AST_LOG_DIR,CSV_LOG_DIR, acc);
+ snprintf(tmp, sizeof(tmp), "%s/%s/%s.csv", ast_config_AST_LOG_DIR,CSV_LOG_DIR, acc);
ast_mutex_lock(&acf_lock);
if (!(f = fopen(tmp, "a"))) {
@@ -283,7 +275,7 @@
}
-static int csv_log(struct ast_cdr *cdr, void *data)
+static int csv_log(struct ast_cdr *cdr)
{
FILE *mf = NULL;
/* Make sure we have a big enough buf */
@@ -295,7 +287,7 @@
#endif
if (build_csv_record(buf, sizeof(buf), cdr)) {
ast_log(LOG_WARNING, "Unable to create CSV record in %d bytes. CDR not recorded!\n", (int)sizeof(buf));
- return AST_CDR_POST_FAILED;
+ return 0;
}
/* because of the absolutely unconditional need for the
@@ -311,21 +303,19 @@
} else {
ast_mutex_unlock(&mf_lock);
ast_log(LOG_ERROR, "Unable to re-open master file %s : %s\n", csvmaster, strerror(errno));
- return AST_CDR_POST_FAILED;
}
if (!ast_strlen_zero(cdr->accountcode)) {
if (writefile(buf, cdr->accountcode))
ast_log(LOG_WARNING, "Unable to write CSV record to account file '%s' : %s\n", cdr->accountcode, strerror(errno));
- return AST_CDR_POST_FAILED;
- }
-
- return AST_CDR_POST_OK;
+ }
+
+ return 0;
}
static int unload_module(void)
{
- ast_cdr_unregister(name, NULL);
+ ast_cdr_unregister(name);
return 0;
}
@@ -336,7 +326,7 @@
if(!load_config(0))
return AST_MODULE_LOAD_DECLINE;
- if ((res = ast_cdr_register(name, NULL, ast_module_info->description, csv_log, NULL, NULL)))
+ if ((res = ast_cdr_register(name, ast_module_info->description, csv_log)))
ast_log(LOG_ERROR, "Unable to register CSV CDR handling\n");
return res;
Modified: team/juggie/NoLossCDR/cdr/cdr_custom.c
URL: http://svn.digium.com/view/asterisk/team/juggie/NoLossCDR/cdr/cdr_custom.c?view=diff&rev=104118&r1=104117&r2=104118
==============================================================================
--- team/juggie/NoLossCDR/cdr/cdr_custom.c (original)
+++ team/juggie/NoLossCDR/cdr/cdr_custom.c Mon Feb 25 18:22:40 2008
@@ -34,99 +34,54 @@
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-#include <sys/types.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-
-#include <stdlib.h>
-#include <unistd.h>
#include <time.h>
+#include "asterisk/paths.h" /* use ast_config_AST_LOG_DIR */
#include "asterisk/channel.h"
#include "asterisk/cdr.h"
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/pbx.h"
-#include "asterisk/logger.h"
#include "asterisk/utils.h"
-#define CUSTOM_LOG_DIR "cdr-custom"
+#define CUSTOM_LOG_DIR "/cdr_custom"
-#define DATE_FORMAT "%Y-%m-%d %T"
-#define FORMAT_MAX 1024
-#define DEFAULT_BUFFER_SIZE 2048
+#define DATE_FORMAT "%Y-%m-%d %T"
AST_MUTEX_DEFINE_STATIC(lock);
static char *name = "cdr-custom";
-struct cdr_custom_sink
-{
- char filename[PATH_MAX];
- char format[FORMAT_MAX];
+static FILE *mf = NULL;
- FILE *output;
-};
-
-/* Prototypes */
-static int custom_log(struct ast_cdr *cdr, void *data);
-
-static void free_config(void *data)
-{
- struct cdr_custom_sink *sink = (struct cdr_custom_sink *) data;
-
- if (!sink)
- return;
-
- if (sink->output)
- fclose(sink->output);
-
- ast_free(sink);
-}
+static char master[PATH_MAX];
+static char format[1024]="";
static int load_config(int reload)
{
struct ast_config *cfg;
struct ast_variable *var;
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
- struct cdr_custom_sink *sink = NULL;
int res = -1;
if ((cfg = ast_config_load("cdr_custom.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
return 0;
- if (reload)
- ast_cdr_unregister(name, NULL);
-
+ strcpy(format, "");
+ strcpy(master, "");
ast_mutex_lock(&lock);
if (cfg) {
var = ast_variable_browse(cfg, "mappings");
while(var) {
if (!ast_strlen_zero(var->name) && !ast_strlen_zero(var->value)) {
- if (strlen(var->value) > (FORMAT_MAX - 1))
+ if (strlen(var->value) > (sizeof(format) - 1))
ast_log(LOG_WARNING, "Format string too long, will be truncated, at line %d\n", var->lineno);
- sink = (struct cdr_custom_sink *) ast_calloc(1, sizeof(struct cdr_custom_sink));
- if (!sink) {
- ast_log(LOG_ERROR, "Unable to allocate CDR custom configuration.\n");
+ ast_copy_string(format, var->value, sizeof(format) - 1);
+ strcat(format,"\n");
+ snprintf(master, sizeof(master),"%s/%s/%s", ast_config_AST_LOG_DIR, name, var->name);
+ if (var->next) {
+ ast_log(LOG_NOTICE, "Sorry, only one mapping is supported at this time, mapping '%s' will be ignored at line %d.\n", var->next->name, var->next->lineno);
break;
- }
- ast_copy_string(sink->format, var->value, FORMAT_MAX - 1);
- strcat(sink->format, "\n");
- snprintf(sink->filename, PATH_MAX, "%s/%s/%s", ast_config_AST_LOG_DIR, CUSTOM_LOG_DIR, var->name);
- /* Try to open the file */
- sink->output = fopen(sink->filename, "a");
- if (!sink->output) {
- ast_log(LOG_ERROR, "Unable to open CDR log file \"%s\": %s\n", sink->filename, strerror(errno));
- ast_free(sink);
- } else {
- fclose(sink->output);
- sink->output = NULL;
- res = ast_cdr_register(name, var->name, ast_module_info->description, custom_log, free_config, sink);
- if (res) {
- ast_log(LOG_ERROR, "Failed to register CDR custom handler sink \"%s\" at line %d\n", var->name, var->lineno);
- ast_free(sink);
- }
}
} else
ast_log(LOG_NOTICE, "Mapping must have both filename and format at line %d\n", var->lineno);
@@ -145,53 +100,60 @@
return res;
}
-static int custom_log(struct ast_cdr *cdr, void *data)
+
+
+static int custom_log(struct ast_cdr *cdr)
{
/* Make sure we have a big enough buf */
- char buf[DEFAULT_BUFFER_SIZE];
+ char buf[2048];
struct ast_channel dummy;
- struct cdr_custom_sink *sink = (struct cdr_custom_sink *) data;
/* Abort if no master file is specified */
- if (ast_strlen_zero(sink->filename))
- return AST_CDR_POST_DISABLED;
+ if (ast_strlen_zero(master))
+ return 0;
- memset(buf, 0 , DEFAULT_BUFFER_SIZE);
/* Quite possibly the first use of a static struct ast_channel, we need it so the var funcs will work */
memset(&dummy, 0, sizeof(dummy));
dummy.cdr = cdr;
- pbx_substitute_variables_helper(&dummy, sink->format, buf, DEFAULT_BUFFER_SIZE - 1);
+ pbx_substitute_variables_helper(&dummy, format, buf, sizeof(buf) - 1);
/* because of the absolutely unconditional need for the
highest reliability possible in writing billing records,
we open write and close the log file each time */
- sink->output = fopen(sink->filename, "a");
- if (!sink->output) {
- ast_log(LOG_ERROR, "Unable to re-open CDR custom file %s : %s\n", sink->filename, strerror(errno));
- return AST_CDR_POST_FAILED;
- } else {
- fputs(buf, sink->output);
- fflush(sink->output); /* be particularly anal here */
- fclose(sink->output);
- sink->output = NULL;
+ mf = fopen(master, "a");
+ if (!mf) {
+ ast_log(LOG_ERROR, "Unable to re-open master file %s : %s\n", master, strerror(errno));
}
-
- return AST_CDR_POST_OK;
+ if (mf) {
+ fputs(buf, mf);
+ fflush(mf); /* be particularly anal here */
+ fclose(mf);
+ mf = NULL;
+ }
+ return 0;
}
static int unload_module(void)
{
- ast_cdr_unregister(name, NULL);
-
+ if (mf)
+ fclose(mf);
+ ast_cdr_unregister(name);
return 0;
}
static int load_module(void)
{
- if (!load_config(0))
- return AST_MODULE_LOAD_SUCCESS;
+ int res = 0;
- return AST_MODULE_LOAD_DECLINE;
+ if (!load_config(0)) {
+ res = ast_cdr_register(name, ast_module_info->description, custom_log);
+ if (res)
+ ast_log(LOG_ERROR, "Unable to register custom CDR handling\n");
+ if (mf)
+ fclose(mf);
+ return res;
+ } else
+ return AST_MODULE_LOAD_DECLINE;
}
static int reload(void)
@@ -203,5 +165,5 @@
.load = load_module,
.unload = unload_module,
.reload = reload,
- );
+ );
Modified: team/juggie/NoLossCDR/cdr/cdr_manager.c
URL: http://svn.digium.com/view/asterisk/team/juggie/NoLossCDR/cdr/cdr_manager.c?view=diff&rev=104118&r1=104117&r2=104118
==============================================================================
--- team/juggie/NoLossCDR/cdr/cdr_manager.c (original)
+++ team/juggie/NoLossCDR/cdr/cdr_manager.c Mon Feb 25 18:22:40 2008
@@ -29,15 +29,11 @@
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-#include <sys/types.h>
-#include <strings.h>
-#include <unistd.h>
#include <time.h>
#include "asterisk/channel.h"
#include "asterisk/cdr.h"
#include "asterisk/module.h"
-#include "asterisk/logger.h"
#include "asterisk/utils.h"
#include "asterisk/manager.h"
#include "asterisk/config.h"
@@ -52,7 +48,7 @@
static int enablecdr = 0;
struct ast_str *customfields;
-static int manager_log(struct ast_cdr *cdr, void * data);
+static int manager_log(struct ast_cdr *cdr);
static int load_config(int reload)
{
@@ -75,7 +71,7 @@
/* Standard configuration */
ast_log(LOG_WARNING, "Failed to load configuration file. Module not activated.\n");
if (enablecdr)
- ast_cdr_unregister(name, NULL);
+ ast_cdr_unregister(name);
enablecdr = 0;
return 0;
}
@@ -111,15 +107,15 @@
ast_config_destroy(cfg);
if (enablecdr && !newenablecdr)
- ast_cdr_unregister(name, NULL);
+ ast_cdr_unregister(name);
else if (!enablecdr && newenablecdr)
- ast_cdr_register(name, NULL, "Asterisk Manager Interface CDR Backend", manager_log, NULL, NULL);
+ ast_cdr_register(name, "Asterisk Manager Interface CDR Backend", manager_log);
enablecdr = newenablecdr;
return 1;
}
-static int manager_log(struct ast_cdr *cdr, void *data)
+static int manager_log(struct ast_cdr *cdr)
{
struct ast_tm timeresult;
char strStartTime[80] = "";
@@ -129,7 +125,7 @@
struct ast_channel dummy;
if (!enablecdr)
- return AST_CDR_POST_DISABLED;
+ return 0;
ast_localtime(&cdr->start, &timeresult, NULL);
ast_strftime(strStartTime, sizeof(strStartTime), DATE_FORMAT, &timeresult);
@@ -142,15 +138,15 @@
ast_localtime(&cdr->end, &timeresult, NULL);
ast_strftime(strEndTime, sizeof(strEndTime), DATE_FORMAT, &timeresult);
+ buf[0] = 0;
/* Custom fields handling */
- memset(buf, 0 , sizeof(buf));
if (customfields != NULL && customfields->used > 0) {
memset(&dummy, 0, sizeof(dummy));
dummy.cdr = cdr;
pbx_substitute_variables_helper(&dummy, customfields->str, buf, sizeof(buf) - 1);
}
- manager_event(EVENT_FLAG_CALL, "Cdr",
+ manager_event(EVENT_FLAG_CDR, "Cdr",
"AccountCode: %s\r\n"
"Source: %s\r\n"
"Destination: %s\r\n"
@@ -175,12 +171,12 @@
cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition),
ast_cdr_flags2str(cdr->amaflags), cdr->uniqueid, cdr->userfield,buf);
- return AST_CDR_POST_OK;
+ return 0;
}
static int unload_module(void)
{
- ast_cdr_unregister(name, NULL);
[... 1329 lines stripped ...]
More information about the asterisk-commits
mailing list