diff --git a/config.c b/config.c index 07223a6..ee2b476 100644 --- a/config.c +++ b/config.c @@ -26,6 +26,9 @@ char *config_prov_pass = MEDIATOR_DEFAULT_PROVPASS; char *config_prov_db = MEDIATOR_DEFAULT_PROVDB; unsigned int config_prov_port = MEDIATOR_DEFAULT_PROVPORT; +char *config_stats_db = MEDIATOR_DEFAULT_STATSDB; +med_stats_period_t config_stats_period = MEDIATOR_DEFAULT_STATS_PERIOD; + static u_int8_t config_pid_path_free = 0; static u_int8_t config_med_host_free = 0; @@ -43,6 +46,7 @@ static u_int8_t config_prov_user_free = 0; static u_int8_t config_prov_pass_free = 0; static u_int8_t config_prov_db_free = 0; +static u_int8_t config_stats_db_free = 0; static void config_help(const char *self) { @@ -67,18 +71,21 @@ static void config_help(const char *self) " -R\tThe prov db user (default = '%s').\n" \ " -A\tThe prov db pass (default = '%s').\n" \ " -N\tThe prov db name (default = '%s').\n" \ + " -X\tThe stats db name (default = '%s').\n" \ + " -x\tThe stats db period (default = '%d', 1=hour, 2=day, 3=month).\n" \ " -?\tDisplays this message.\n", self, config_pid_path, config_interval, config_med_host, config_med_port, config_med_user, config_med_pass, config_med_db, config_cdr_host, config_cdr_port, config_cdr_user, config_cdr_pass, config_cdr_db, - config_prov_host, config_prov_port, config_prov_user, config_prov_pass, config_prov_db); + config_prov_host, config_prov_port, config_prov_user, config_prov_pass, config_prov_db, + config_stats_db, config_stats_period); } int config_parse_cmdopts(int argc, char **argv) { int c; - while((c = getopt(argc, argv, "D:i:dl?h:u:p:b:o:H:U:P:B:O:S:T:R:A:N:")) != -1) + while((c = getopt(argc, argv, "D:i:dl?h:u:p:b:o:H:U:P:B:O:S:T:R:A:N:X:x:")) != -1) { if(c == '?') { @@ -174,6 +181,15 @@ int config_parse_cmdopts(int argc, char **argv) { config_prov_port = atoi(optarg); } + else if(c == 'X') + { + config_stats_db = (char*)strdup(optarg); + config_stats_db_free = 1; + } + else if(c == 'x') + { + config_stats_period = (med_stats_period_t)atoi(optarg); + } } return 0; @@ -233,4 +249,8 @@ void config_cleanup() { free(config_prov_db); } + if(config_stats_db_free) + { + free(config_stats_db); + } } diff --git a/config.h b/config.h index 5a2e0ed..4569826 100644 --- a/config.h +++ b/config.h @@ -26,6 +26,9 @@ extern char *config_prov_user; extern char *config_prov_pass; extern char *config_prov_db; +extern char *config_stats_db; +extern med_stats_period_t config_stats_period; + extern unsigned int config_interval; extern u_int8_t config_dumpcdr; diff --git a/debian/mediator.default b/debian/mediator.default index 19e1286..2788b61 100644 --- a/debian/mediator.default +++ b/debian/mediator.default @@ -17,3 +17,5 @@ PROV_PORT="3306" PROV_USER="mediator" PROV_PASS='GimmeAllUr$$$' PROV_DB="provisioning" +STATS_DB="stats" +STATS_PERIOD=1 diff --git a/debian/mediator.init b/debian/mediator.init index 4d0845c..3a43075 100755 --- a/debian/mediator.init +++ b/debian/mediator.init @@ -59,6 +59,8 @@ OPTIONS="" [ -z "$PROV_USER" ] || OPTIONS="$OPTIONS -R $PROV_USER" [ -z "$PROV_PASS" ] || OPTIONS="$OPTIONS -A $PROV_PASS" [ -z "$PROV_DB" ] || OPTIONS="$OPTIONS -N $PROV_DB" +[ -z "$STATS_DB" ] || OPTIONS="$OPTIONS -X $STATS_DB" +[ -z "$STATS_PERIOD" ] || OPTIONS="$OPTIONS -x $STATS_PERIOD" if test "$FORK" = "yes" ; then OPTIONS="$OPTIONS -d" fi diff --git a/mediator.c b/mediator.c index d573d50..1c7c96e 100644 --- a/mediator.c +++ b/mediator.c @@ -25,7 +25,7 @@ GHashTable *med_peer_ip_table = NULL; GHashTable *med_peer_host_table = NULL; GHashTable *med_peer_id_table = NULL; GHashTable *med_uuid_table = NULL; - +GHashTable *med_call_stat_info_table = NULL; /**********************************************************************/ static int mediator_load_maps() @@ -60,11 +60,14 @@ static void mediator_destroy_maps() g_hash_table_destroy(med_peer_id_table); if(med_uuid_table) g_hash_table_destroy(med_uuid_table); + if(med_call_stat_info_table) + g_hash_table_destroy(med_call_stat_info_table); med_peer_ip_table = NULL; med_peer_host_table = NULL; med_peer_id_table = NULL; med_uuid_table = NULL; + med_call_stat_info_table = NULL; } /**********************************************************************/ diff --git a/mediator.h b/mediator.h index 306eab2..27ed394 100644 --- a/mediator.h +++ b/mediator.h @@ -38,6 +38,9 @@ #define MEDIATOR_DEFAULT_PROVDB "provisioning" #define MEDIATOR_DEFAULT_PROVPORT 0 +#define MEDIATOR_DEFAULT_STATSDB "stats" +#define MEDIATOR_DEFAULT_STATS_PERIOD MED_STATS_HOUR + #define MED_GW_STRING "gw" #define MED_AS_STRING "as" #define MED_PEER_STRING "peer" @@ -77,6 +80,7 @@ extern GHashTable *med_peer_host_table; extern GHashTable *med_peer_ip_table; extern GHashTable *med_peer_id_table; extern GHashTable *med_uuid_table; +extern GHashTable *med_call_stat_info_table; void critical(const char *); @@ -89,5 +93,10 @@ static inline int check_shutdown(void) { return 0; } +typedef enum { + MED_STATS_HOUR = 1, + MED_STATS_DAY = 2, + MED_STATS_MONTH = 3 +} med_stats_period_t; #endif /* _MEDIATOR_H */ diff --git a/medmysql.c b/medmysql.c index 0462e71..6d0d917 100644 --- a/medmysql.c +++ b/medmysql.c @@ -26,6 +26,7 @@ static MYSQL *prov_handler = NULL; static int medmysql_flush_cdr(struct medmysql_batches *); static int medmysql_flush_medlist(struct medmysql_str *); +static int medmysql_flush_call_stat_info(); static int mysql_query_wrapper(MYSQL *mysql, const char *stmt_str, unsigned long length) { @@ -474,6 +475,9 @@ int medmysql_insert_cdrs(cdr_entry_t *entries, u_int64_t count, struct medmysql_ CDRPRINT("),"); + // no check for return codes here we should keep on nevertheless + medmysql_update_call_stat_info(e->call_code, e->start_time, batches); + if (check_shutdown()) return -1; } @@ -484,6 +488,49 @@ int medmysql_insert_cdrs(cdr_entry_t *entries, u_int64_t count, struct medmysql_ return 0; } +/**********************************************************************/ +int medmysql_update_call_stat_info(const char *call_code, const double start_time, struct medmysql_batches *batches) +{ + if (!med_call_stat_info_table) + return -1; + + char period[STAT_PERIOD_SIZE]; + time_t etime = (time_t)start_time; + char period_key[STAT_PERIOD_SIZE+4]; + struct medmysql_call_stat_info_t * period_t; + + switch (config_stats_period) + { + case MED_STATS_HOUR: + strftime(period, STAT_PERIOD_SIZE, "%Y-%m-%d %H:00:00", localtime(&etime)); + break; + case MED_STATS_DAY: + strftime(period, STAT_PERIOD_SIZE, "%Y-%m-%d 00:00:00", localtime(&etime)); + break; + case MED_STATS_MONTH: + strftime(period, STAT_PERIOD_SIZE, "%Y-%m-01 00:00:00", localtime(&etime)); + break; + default: + syslog(LOG_CRIT, "Undefinied or wrong config_stats_period %d", + config_stats_period); + return -1; + } + + sprintf(period_key, "%s-%s", period, call_code); + + if ((period_t = g_hash_table_lookup(med_call_stat_info_table, &period_key)) == NULL) { + period_t = malloc(sizeof(struct medmysql_call_stat_info_t)); + strcpy(period_t->period, period); + strcpy(period_t->call_code, call_code); + period_t->amount = 1; + g_hash_table_insert(med_call_stat_info_table, strdup(period_key), period_t); + } else { + period_t->amount += 1; + } + + return 0; +} + /**********************************************************************/ int medmysql_load_maps(GHashTable *ip_table, GHashTable *host_table, GHashTable *id_table) { @@ -591,6 +638,9 @@ int medmysql_batch_start(struct medmysql_batches *batches) { if (mysql_query_wrapper(med_handler, "start transaction", 17)) return -1; + if (!med_call_stat_info_table) + med_call_stat_info_table = g_hash_table_new_full(g_str_hash, g_str_equal, free, free); + batches->cdrs.len = 0; batches->acc_backup.len = 0; batches->acc_trash.len = 0; @@ -660,6 +710,53 @@ static int medmysql_flush_medlist(struct medmysql_str *str) { return 0; } +static int medmysql_flush_call_stat_info() { + if (!med_handler) + return 0; + if (!med_call_stat_info_table) + return 0; + + GHashTable * call_stat_info = med_call_stat_info_table; + struct medmysql_str query; + struct medmysql_call_stat_info_t * period_t; + + GList * keys = g_hash_table_get_keys(call_stat_info); + GList * iter; + for (iter = keys; iter != NULL; iter = iter->next) { + char * period_key = iter->data; + if ((period_t = g_hash_table_lookup(call_stat_info, period_key)) == NULL) { + syslog(LOG_CRIT, + "Error dumping call stats info: no data for period_key %s\n", + period_key + ); + return -1; + } + + query.len = sprintf(query.str, + "insert into %s.call_info set period='%s', sip_code='%s', amount=%" PRIu64 " on duplicate key update period='%s', sip_code='%s', amount=(amount+%" PRIu64 ");", + config_stats_db, + period_t->period, period_t->call_code, period_t->amount, + period_t->period, period_t->call_code, period_t->amount + ); + + //syslog(LOG_DEBUG, "updating call stats info: %s -- %s", period_t->call_code, period_t->period); + //syslog(LOG_DEBUG, "sql: %s", query.str); + + if(mysql_query_wrapper(med_handler, query.str, query.len) != 0) + { + syslog(LOG_CRIT, "Error executing call info stats query: %s", + mysql_error(med_handler)); + critical("Failed to execute potentially crucial SQL query, check syslog for details"); + return -1; + } + period_t->amount = 0; // reset code counter on success + } + g_list_free(keys); + g_list_free(iter); + + return 0; +} + int medmysql_batch_end(struct medmysql_batches *batches) { if (medmysql_flush_cdr(batches) || check_shutdown()) return -1; @@ -669,6 +766,8 @@ int medmysql_batch_end(struct medmysql_batches *batches) { return -1; if (medmysql_flush_medlist(&batches->to_delete) || check_shutdown()) return -1; + if (medmysql_flush_call_stat_info() || check_shutdown()) + return -1; if (mysql_query_wrapper(cdr_handler, "commit", 6)) return -1; diff --git a/medmysql.h b/medmysql.h index cf793c5..7b43e54 100644 --- a/medmysql.h +++ b/medmysql.h @@ -8,6 +8,8 @@ #define PACKET_SIZE (1024*1024) +#define STAT_PERIOD_SIZE 30 + struct medmysql_str { char str[PACKET_SIZE]; unsigned int len; @@ -20,6 +22,12 @@ struct medmysql_batches { struct medmysql_str to_delete; }; +struct medmysql_call_stat_info_t { + char period[STAT_PERIOD_SIZE]; + char call_code[4]; + u_int64_t amount; +}; + int medmysql_init(); void medmysql_cleanup(); int medmysql_fetch_callids(med_callid_t **callids, u_int64_t *count); @@ -32,5 +40,6 @@ int medmysql_load_maps(GHashTable *ip_table, GHashTable *host_table, GHashTable int medmysql_load_uuids(GHashTable *uuid_table); int medmysql_batch_start(struct medmysql_batches *); int medmysql_batch_end(struct medmysql_batches *); +int medmysql_update_call_stat_info(const char *call_code, const double start_time, struct medmysql_batches *batches); #endif /* _MED_MYSQL_H */