瀏覽代碼

cnxcc: added Redis support for distributed cnxcc nodes

- works for all monitoring functions
Carlos Ruiz Diaz 11 年之前
父節點
當前提交
c587ce0b17

+ 2 - 1
modules/cnxcc/Makefile

@@ -1,6 +1,6 @@
 # $Id$
 #
-# example module makefile
+# cnxcc module makefile
 #
 # 
 # WARNING: do not run this directly, it should be run by the master Makefile
@@ -9,6 +9,7 @@ include ../../Makefile.defs
 auto_gen=
 NAME=cnxcc.so
 
+LIBS=-lhiredis -levent
 DEFS+=-DOPENSER_MOD_INTERFACE
 SERLIBPATH=../../lib
 SER_LIBS+=$(SERLIBPATH)/kmi/kmi

+ 20 - 10
modules/cnxcc/README

@@ -1,10 +1,12 @@
 cnxcc Module
 
-Carlos Ruiz Diaz
+Carlos Ruiz Díaz
 
    ConexionGroup S.A.
 
-   Copyright © 2013 Carlos Ruiz Diaz, [email protected]
+   Copyright © 2013 Carlos Ruiz Díaz, [email protected]
+
+   Copyright © 2014 Carlos Ruiz Díaz, [email protected]
      __________________________________________________________________
 
    Table of Contents
@@ -15,10 +17,11 @@ Carlos Ruiz Diaz
         2. Dependencies
 
               2.1. Modules
+              2.2. Libraries
 
         3. Parameters
 
-              3.1. dlg_flag (integer)
+              3.1. redis (integer)
               3.2. credit_check_period (integer)
 
         4. Functions
@@ -58,10 +61,11 @@ Chapter 1. Admin Guide
    2. Dependencies
 
         2.1. Modules
+        2.2. Libraries
 
    3. Parameters
 
-        3.1. dlg_flag (integer)
+        3.1. redis (integer)
         3.2. credit_check_period (integer)
 
    4. Functions
@@ -106,7 +110,7 @@ Chapter 1. Admin Guide
    that are equal to the cost per second of both calls.
 
    If your accounting program does not maintain the state of the call in
-   real time, this module can provide you that ability.
+   real time, this module can provide you with that ability.
 
    Cnxcc can also provide more common means of monitoring, i.e., by time
    limit or by maximum simultaneous calls.
@@ -114,25 +118,31 @@ Chapter 1. Admin Guide
 2. Dependencies
 
    2.1. Modules
+   2.2. Libraries
 
 2.1. Modules
 
    The following module must be loaded before this module:
      * dialog
 
+2.2. Libraries
+
+   The following module must be loaded before this module:
+     * hiredis-devel >= 0.11.0
+     * libevent-devel >= 2.0.18-2
+
 3. Parameters
 
-   3.1. dlg_flag (integer)
+   3.1. redis (integer)
    3.2. credit_check_period (integer)
 
-3.1.  dlg_flag (integer)
+3.1.  redis (integer)
 
-   Flag to indicate if the dialog must be monitored or not. Messages are
-   flagged with this value if we call one of the monitoring functions.
+   Redis datasource connection information
 
    Example 1.1. dlg_flag
 ...
-modparam("cnxcc", "dlg_flag", 29)
+modparam("cnxcc", "redis", "addr=127.0.0.1;port=6379;db=1")
 ...
 
 3.2. credit_check_period (integer)

+ 4 - 4
modules/cnxcc/cnxcc.c

@@ -18,7 +18,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  */
 #include <time.h>
@@ -28,17 +28,17 @@
 
 #include "cnxcc.h"
 
-void get_datetime(str *dest)
+inline void get_datetime(str *dest)
 {
 	timestamp2isodt(dest, get_current_timestamp());
 }
 
-unsigned int get_current_timestamp()
+inline unsigned int get_current_timestamp()
 {
 	return time(NULL);
 }
 
-int timestamp2isodt(str *dest, unsigned int timestamp)
+inline int timestamp2isodt(str *dest, unsigned int timestamp)
 {
 	time_t  		tim;
 	struct tm 		*tmPtr;

+ 4 - 4
modules/cnxcc/cnxcc.h

@@ -18,7 +18,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  */
 
@@ -31,9 +31,9 @@
 #define DATETIME_LENGTH		DATETIME_SIZE - 1
 
 
-void get_datetime(str *dest);
-unsigned int get_current_timestamp();
-int timestamp2isodt(str *dest, unsigned int timestamp);
+inline void get_datetime(str *dest);
+inline unsigned int get_current_timestamp();
+inline int timestamp2isodt(str *dest, unsigned int timestamp);
 double str2double(str *string);
 
 #endif /* _CNXCC_H */

+ 68 - 59
modules/cnxcc/cnxcc_check.c

@@ -18,7 +18,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  */
 
@@ -30,43 +30,41 @@
 #include "cnxcc_mod.h"
 #include "cnxcc.h"
 #include "cnxcc_check.h"
+#include "cnxcc_redis.h"
 
 extern data_t _data;
 
-void check_calls_by_money(unsigned int ticks, void *param)
-{
-	struct str_hash_entry *h_entry 	= NULL,
-			  *tmp		= NULL;
-	call_t *tmp_call		= NULL;
+void check_calls_by_money(unsigned int ticks, void *param) {
+	struct str_hash_entry *h_entry = NULL,
+	                      *tmp = NULL;
+	call_t *tmp_call = NULL;
 	int i;
 
 	lock_get(&_data.money.lock);
+
 	if (_data.money.credit_data_by_client->table)
 		for(i = 0; i < _data.money.credit_data_by_client->size; i++)
-			clist_foreach_safe(&_data.money.credit_data_by_client->table[i], h_entry, tmp, next)
-			{
-				credit_data_t *credit_data	= (credit_data_t *) h_entry->u.p;
-				call_t *call			= NULL;
-				double total_consumed_money	= 0;
+			clist_foreach_safe(&_data.money.credit_data_by_client->table[i], h_entry, tmp, next) {
+				credit_data_t *credit_data = (credit_data_t *) h_entry->u.p;
+				call_t *call = NULL;
+				double total_consumed_money = 0, consumption_diff = 0/*, distributed_consumption = 0*/;
 
-				if (i > SAFE_ITERATION_THRESHOLD)
-				{
+/*				if (i > SAFE_ITERATION_THRESHOLD) {
 					LM_ERR("Too many iterations for this loop: %d\n", i);
 					break;
-				}
+				}*/
+
 				lock_get(&credit_data->lock);
 
-				clist_foreach_safe(credit_data->call_list, call, tmp_call, next)
-				{
+				clist_foreach_safe(credit_data->call_list, call, tmp_call, next) {
 					int consumed_time = 0;
 
 					if (!call->confirmed)
 						continue;
 
-					consumed_time 		= get_current_timestamp() - call->start_timestamp;
+					consumed_time = get_current_timestamp() - call->start_timestamp;
 
-					if (consumed_time > call->money_based.initial_pulse)
-					{
+					if (consumed_time > call->money_based.initial_pulse) {
 						call->consumed_amount = (call->money_based.cost_per_second * call->money_based.initial_pulse)
 												+
 												call->money_based.cost_per_second *
@@ -74,10 +72,9 @@ void check_calls_by_money(unsigned int ticks, void *param)
 												call->money_based.final_pulse;
 					}
 
-					total_consumed_money	+= call->consumed_amount;
+					total_consumed_money += call->consumed_amount;
 
-					if (call->consumed_amount > call->max_amount)
-					{
+					if (call->consumed_amount > call->max_amount) {
 						LM_ALERT("[%.*s] call has exhausted its credit. Breaking the loop\n", call->sip_data.callid.len, call->sip_data.callid.s);
 						break;
 					}
@@ -89,26 +86,35 @@ void check_calls_by_money(unsigned int ticks, void *param)
 																			call->consumed_amount
 																			);
 				}
-				
-				if (credit_data->concurrent_calls == 0)
-				{
+
+				if (credit_data->concurrent_calls == 0) {
 					lock_release(&credit_data->lock);
 					continue;
 				}
 
-				credit_data->consumed_amount	= credit_data->ended_calls_consumed_amount + total_consumed_money;
+				if (_data.redis) {
+					LM_INFO("ec=%f, ca=%f, ca2=%f", credit_data->ended_calls_consumed_amount, total_consumed_money, credit_data->consumed_amount);
 
-				LM_DBG("Client [%.*s] | Ended-Calls-Credit-Spent: %f  TotalCredit/MaxCredit: %f/%f\n", credit_data->call_list->client_id.len, credit_data->call_list->client_id.s,
-																									credit_data->ended_calls_consumed_amount,
-																									credit_data->consumed_amount,
-																									credit_data->max_amount);
+					consumption_diff = credit_data->ended_calls_consumed_amount + total_consumed_money - credit_data->consumed_amount;
+					if (consumption_diff > 0)
+						redis_incr_by_double(credit_data, "consumed_amount", consumption_diff);
+				}
 
-				if (credit_data->consumed_amount >= credit_data->max_amount)
-				{
-					lock_release(&_data.money.lock);
+				credit_data->consumed_amount = credit_data->ended_calls_consumed_amount + total_consumed_money /* + distributed_consumption */;
+
+				LM_DBG("Client [%.*s] | Ended-Calls-Credit-Spent: %f  TotalCredit/MaxCredit: %f/%f\n",
+							credit_data->call_list->client_id.len, credit_data->call_list->client_id.s,
+							credit_data->ended_calls_consumed_amount,
+							credit_data->consumed_amount,
+							credit_data->max_amount);
+
+				if (credit_data->consumed_amount >= credit_data->max_amount) {
 					terminate_all_calls(credit_data);
+
+					// make sure the rest of the servers kill the calls belonging to this customer
+					redis_publish_to_kill_list(credit_data);
 					lock_release(&credit_data->lock);
-					return;
+					break;
 				}
 
 				lock_release(&credit_data->lock);
@@ -117,43 +123,40 @@ void check_calls_by_money(unsigned int ticks, void *param)
 	lock_release(&_data.money.lock);
 }
 
-void check_calls_by_time(unsigned int ticks, void *param)
-{
-	struct str_hash_entry *h_entry 	= NULL,
-			*tmp		= NULL;
-	call_t *tmp_call		= NULL;
+void check_calls_by_time(unsigned int ticks, void *param) {
+	struct str_hash_entry *h_entry = NULL;
+	struct str_hash_entry *tmp = NULL;
+	call_t *tmp_call = NULL;
 	int i;
 
 	lock_get(&_data.time.lock);
 
 	if (_data.time.credit_data_by_client->table)
 		for(i = 0; i < _data.time.credit_data_by_client->size; i++)
-			clist_foreach_safe(&_data.time.credit_data_by_client->table[i], h_entry, tmp, next)
-			{
-				credit_data_t *credit_data	= (credit_data_t *) h_entry->u.p;
-				call_t *call			= NULL;
-				int total_consumed_secs		= 0;
+			clist_foreach_safe(&_data.time.credit_data_by_client->table[i], h_entry, tmp, next) {
+				credit_data_t *credit_data = (credit_data_t *) h_entry->u.p;
+				call_t *call = NULL;
+				int total_consumed_secs = 0;
+				double consumption_diff = 0/*, distributed_consumption = 0*/;
 
 				lock_get(&credit_data->lock);
 
-				if (i > SAFE_ITERATION_THRESHOLD)
+				/*if (i > SAFE_ITERATION_THRESHOLD)
 				{
-					LM_ERR("Too many iterations for this loop: %d\n", i);
+					LM_ERR("Too many iterations for this loop: %d", i);
 					break;
-				}
+				} */
 
 				LM_DBG("Iterating through calls of client [%.*s]\n", credit_data->call_list->client_id.len, credit_data->call_list->client_id.s);
 
-				clist_foreach_safe(credit_data->call_list, call, tmp_call, next)
-				{
+				clist_foreach_safe(credit_data->call_list, call, tmp_call, next) {
 					if (!call->confirmed)
 						continue;
 
-					call->consumed_amount	= get_current_timestamp() - call->start_timestamp;
+					call->consumed_amount = get_current_timestamp() - call->start_timestamp;
 					total_consumed_secs	+= call->consumed_amount;
 
-					if (call->consumed_amount > call->max_amount)
-					{
+					if (call->consumed_amount > call->max_amount) {
 						LM_ALERT("[%.*s] call has exhausted its time. Breaking the loop\n", call->sip_data.callid.len, call->sip_data.callid.s);
 						break;
 					}
@@ -165,25 +168,31 @@ void check_calls_by_time(unsigned int ticks, void *param)
 																			);
 				}
 
-				if (credit_data->concurrent_calls == 0)
-				{
+				if (credit_data->concurrent_calls == 0) {
 					lock_release(&credit_data->lock);
 					continue;
 				}
 
-				credit_data->consumed_amount	= credit_data->ended_calls_consumed_amount + total_consumed_secs;
+				if (_data.redis) {
+					consumption_diff = credit_data->ended_calls_consumed_amount + total_consumed_secs - credit_data->consumed_amount;
+					if (consumption_diff > 0)
+						redis_incr_by_double(credit_data, "consumed_amount", consumption_diff);
+				}
+
+				credit_data->consumed_amount = credit_data->ended_calls_consumed_amount + total_consumed_secs /*+ distributed_consumption*/;
 
 				LM_DBG("Client [%.*s] | Ended-Calls-Time: %d  TotalTime/MaxTime: %d/%d\n", credit_data->call_list->client_id.len, credit_data->call_list->client_id.s,
 																									(int) credit_data->ended_calls_consumed_amount,
 																									(int) credit_data->consumed_amount,
 																									(int) credit_data->max_amount);
 
-				if (credit_data->consumed_amount >= credit_data->max_amount)
-				{				
-					lock_release(&_data.time.lock);
+				if (credit_data->consumed_amount >= credit_data->max_amount) {
 					terminate_all_calls(credit_data);
+
+					// make sure the rest of the servers kill the calls belonging to this customer
+					redis_publish_to_kill_list(credit_data);
 					lock_release(&credit_data->lock);
-					return;
+					break;
 				}
 
 				lock_release(&credit_data->lock);

+ 1 - 1
modules/cnxcc/cnxcc_check.h

@@ -18,7 +18,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  */
 

文件差異過大導致無法顯示
+ 305 - 258
modules/cnxcc/cnxcc_mod.c


+ 24 - 21
modules/cnxcc/cnxcc_mod.h

@@ -18,7 +18,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  */
 #ifndef _CNXCC_MOD_H
@@ -30,37 +30,34 @@
 
 #define str_shm_free_if_not_null(_var_) if (_var_.s != NULL)  { shm_free(_var_.s); _var_.s = NULL; _var_.len = 0; }
 
-typedef struct stats
-{
+typedef struct stats {
 	unsigned int total;
 	unsigned int active;
 	unsigned int dropped;
 } stats_t;
 
-typedef enum cnxpvtypes
-{
+typedef enum cnxpvtypes {
 	CNX_PV_ACTIVE = 1,
 	CNX_PV_TOTAL,
 	CNX_PV_DROPPED
 } cnxpvtypes_t;
 
-typedef enum credit_type
-{
+typedef enum credit_type {
 	CREDIT_TIME,
 	CREDIT_MONEY,
 	CREDIT_CHANNEL
 } credit_type_t;
 
-typedef struct hash_tables
-{
+typedef struct hash_tables {
 	struct str_hash_table *credit_data_by_client;
 	struct str_hash_table *call_data_by_cid;
 
 	gen_lock_t lock;
 } hash_tables_t;
 
-typedef struct data
-{
+struct redis;
+
+typedef struct data {
 	gen_lock_t lock;
 
 	hash_tables_t time;
@@ -84,10 +81,17 @@ typedef struct data
 
 	int check_period;
 
+	str redis_cnn_str;
+	struct {
+		char host[40];
+		int port;
+		int db;
+	} redis_cnn_info;
+	struct redis *redis;
+
 } data_t;
 
-typedef struct sip_data
-{
+typedef struct sip_data {
 	str callid;
 	str from_uri;
 	str from_tag;
@@ -95,8 +99,7 @@ typedef struct sip_data
 	str to_tag;
 } sip_data_t;
 
-typedef struct money_spec_data
-{
+typedef struct money_spec_data {
 	double cost_per_second;
 	int initial_pulse;
 	int final_pulse;
@@ -104,8 +107,7 @@ typedef struct money_spec_data
 } money_spec_data_t;
 
 struct call;
-typedef struct call
-{
+typedef struct call {
 	struct call *prev;
 	struct call *next;
 
@@ -126,15 +128,13 @@ typedef struct call
 	sip_data_t sip_data;
 } call_t;
 
-typedef struct call_array
-{
+typedef struct call_array {
 	call_t *array;
 	int length;
 
 } call_array_t;
 
-typedef struct credit_data
-{
+typedef struct credit_data {
 	gen_lock_t lock;
 
 	double max_amount;
@@ -147,6 +147,9 @@ typedef struct credit_data
 
 	call_t *call_list;
 
+	char *str_id;
+	// flag to mark this instance in the process of being eliminated
+	int deallocating:1;
 } credit_data_t;
 
 

+ 65 - 86
modules/cnxcc/cnxcc_rpc.c

@@ -18,7 +18,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  */
 
@@ -33,27 +33,23 @@
 
 extern data_t _data;
 
-void rpc_kill_call(rpc_t* rpc, void* ctx)
-{
+void rpc_kill_call(rpc_t* rpc, void* ctx) {
 	call_t *call;
 	hash_tables_t *hts;
 	str callid;
 
-	if (!rpc->scan(ctx, "S", &callid))
-	{
+	if (!rpc->scan(ctx, "S", &callid)) {
 		LM_ERR("%s: error reading RPC param\n", __FUNCTION__);
 		return;
 	}
 
-	if (try_get_call_entry(&callid, &call, &hts) != 0)
-	{
+	if (try_get_call_entry(&callid, &call, &hts) != 0) {
 		LM_ERR("%s: call [%.*s] not found\n", __FUNCTION__, callid.len, callid.s);
 		rpc->fault(ctx, 404, "CallID Not Found");
 		return;
 	}
 
-	if (call == NULL)
-	{
+	if (call == NULL) {
 		LM_ERR("%s: call [%.*s] is in null state\n", __FUNCTION__, callid.len, callid.s);
 		rpc->fault(ctx, 500, "Call is NULL");
 		return;
@@ -68,29 +64,25 @@ void rpc_kill_call(rpc_t* rpc, void* ctx)
 	lock_release(&call->lock);
 }
 
-void rpc_check_client_stats(rpc_t* rpc, void* ctx)
-{
+void rpc_check_client_stats(rpc_t* rpc, void* ctx) {
 	call_t *call, *tmp;
 	int index	= 0;
 	str client_id, rows;
 	char row_buffer[512];
 	credit_data_t *credit_data;
 
-	if (!rpc->scan(ctx, "S", &client_id))
-	{
+	if (!rpc->scan(ctx, "S", &client_id)) {
 		LM_ERR("%s: error reading RPC param\n", __FUNCTION__);
 		return;
 	}
 
-	if (try_get_credit_data_entry(&client_id, &credit_data) != 0)
-	{
+	if (try_get_credit_data_entry(&client_id, &credit_data) != 0) {
 		LM_ERR("%s: client [%.*s] not found\n", __FUNCTION__, client_id.len, client_id.s);
 		rpc->fault(ctx, 404, "Not Found");
 		return;
 	}
 
-	if (credit_data == NULL)
-	{
+	if (credit_data == NULL) {
 		LM_ERR("%s: credit data for client [%.*s] is NULL\n", __FUNCTION__, client_id.len, client_id.s);
 		rpc->fault(ctx, 500, "Internal Server Error");
 		return;
@@ -98,8 +90,7 @@ void rpc_check_client_stats(rpc_t* rpc, void* ctx)
 
 	lock_get(&credit_data->lock);
 
-	if (credit_data->number_of_calls <= 0)
-	{
+	if (credit_data->number_of_calls <= 0) {
 		lock_release(&credit_data->lock);
 		LM_INFO("No calls for current client\n");
 		return;
@@ -111,43 +102,40 @@ void rpc_check_client_stats(rpc_t* rpc, void* ctx)
 	if (rows.s == NULL)
 		goto nomem;
 
-	clist_foreach_safe(credit_data->call_list, call, tmp, next)
-	{
+	clist_foreach_safe(credit_data->call_list, call, tmp, next) {
 		int row_len = 0;
 
 		memset(row_buffer, 0, sizeof(row_buffer));
 
 		if (credit_data->type == CREDIT_MONEY)
 			snprintf(row_buffer, sizeof(row_buffer), "id:%d,confirmed:%s,local_consumed_amount:%f,global_consumed_amount:%f,local_max_amount:%f,global_max_amount:%f,call_id:%.*s,start_timestamp:%d"
-																",inip:%d,finp:%d,cps:%f;",
-																 index,
-																 call->confirmed ? "yes" : "no",
-																 call->consumed_amount,
-																 credit_data->consumed_amount,
-																 call->max_amount,
-																 credit_data->max_amount,
-																 call->sip_data.callid.len, call->sip_data.callid.s,
-																 call->start_timestamp,
-																 call->money_based.initial_pulse,
-																 call->money_based.final_pulse,
-																 call->money_based.cost_per_second
-																 );
+								",inip:%d,finp:%d,cps:%f;",
+								index,
+								call->confirmed ? "yes" : "no",
+								call->consumed_amount,
+								credit_data->consumed_amount,
+								call->max_amount,
+								credit_data->max_amount,
+								call->sip_data.callid.len, call->sip_data.callid.s,
+								call->start_timestamp,
+								call->money_based.initial_pulse,
+								call->money_based.final_pulse,
+								call->money_based.cost_per_second);
 		else
 			snprintf(row_buffer, sizeof(row_buffer), "id:%d,confirmed:%s,local_consumed_amount:%d,global_consumed_amount:%d,local_max_amount:%d,global_max_amount:%d,call_id:%.*s,start_timestamp:%d;",
-					 	 	 	 	 	 	 	 	 	 	 	 index,
-																 call->confirmed ? "yes" : "no",
-																 (int) call->consumed_amount,
-																 (int) credit_data->consumed_amount,
-																 (int) call->max_amount,
-																 (int) credit_data->max_amount,
-																 call->sip_data.callid.len, call->sip_data.callid.s,
-																 call->start_timestamp);
+								index,
+								call->confirmed ? "yes" : "no",
+								(int) call->consumed_amount,
+								(int) credit_data->consumed_amount,
+								(int) call->max_amount,
+								(int) credit_data->max_amount,
+								call->sip_data.callid.len, call->sip_data.callid.s,
+								call->start_timestamp);
 
 		row_len 	= strlen(row_buffer);
 		rows.s		= pkg_realloc(rows.s, rows.len + row_len);
 
-		if (rows.s == NULL)
-		{
+		if (rows.s == NULL) {
 			lock_release(&credit_data->lock);
 			goto nomem;
 		}
@@ -160,8 +148,7 @@ void rpc_check_client_stats(rpc_t* rpc, void* ctx)
 
 	lock_release(&credit_data->lock);
 
-	if (rpc->add(ctx, "S", &rows) < 0)
-	{
+	if (rpc->add(ctx, "S", &rows) < 0) {
 		LM_ERR("%s: error creating RPC struct\n", __FUNCTION__);
 	}
 
@@ -175,8 +162,7 @@ nomem:
 	rpc->fault(ctx, 500, "No more memory\n");
 }
 
-static int iterate_over_table(hash_tables_t *hts, str *result, credit_type_t type)
-{
+static int iterate_over_table(hash_tables_t *hts, str *result, credit_type_t type) {
 	struct str_hash_entry *h_entry, *tmp;
 	char row_buffer[512];
 	int index = 0;
@@ -185,8 +171,7 @@ static int iterate_over_table(hash_tables_t *hts, str *result, credit_type_t typ
 
 	if (hts->credit_data_by_client->table)
 		for(index = 0; index < hts->credit_data_by_client->size; index++)
-			clist_foreach_safe(&hts->credit_data_by_client->table[index], h_entry, tmp, next)
-			{
+			clist_foreach_safe(&hts->credit_data_by_client->table[index], h_entry, tmp, next) {
 				credit_data_t *credit_data	= (credit_data_t *) h_entry->u.p;
 				lock_get(&credit_data->lock);
 
@@ -194,39 +179,36 @@ static int iterate_over_table(hash_tables_t *hts, str *result, credit_type_t typ
 
 				memset(row_buffer, 0, sizeof(row_buffer));
 
-				if (type == CREDIT_TIME)
-				{
+				if (type == CREDIT_TIME) {
 					snprintf(row_buffer, sizeof(row_buffer), "client_id:%.*s,"
-															 "number_of_calls:%d,"
-															 "concurrent_calls:%d,"
-															 "type:%d,"
-															 "max_amount:%d,"
-															 "consumed_amount:%d;",
-															 credit_data->call_list->client_id.len, credit_data->call_list->client_id.s,
-															 credit_data->number_of_calls,
-															 credit_data->concurrent_calls,
-															 type,
-															 (int) credit_data->max_amount,
-															 (int) credit_data->consumed_amount);
+											"number_of_calls:%d,"
+											"concurrent_calls:%d,"
+											"type:%d,"
+											"max_amount:%d,"
+											"consumed_amount:%d;",
+											credit_data->call_list->client_id.len, credit_data->call_list->client_id.s,
+											credit_data->number_of_calls,
+											credit_data->concurrent_calls,
+											type,
+											(int) credit_data->max_amount,
+											(int) credit_data->consumed_amount);
 				}
-				else if (type == CREDIT_MONEY)
-				{
+				else if (type == CREDIT_MONEY) {
 					snprintf(row_buffer, sizeof(row_buffer), "client_id:%.*s,"
-															 "number_of_calls:%d,"
-															 "concurrent_calls:%d,"
-															 "type:%d,"
-															 "max_amount:%f,"
-															 "consumed_amount:%f;",
-															 credit_data->call_list->client_id.len, credit_data->call_list->client_id.s,
-															 credit_data->number_of_calls,
-															 credit_data->concurrent_calls,
-															 type,
-															 credit_data->max_amount,
-															 credit_data->consumed_amount);
+											"number_of_calls:%d,"
+											"concurrent_calls:%d,"
+											"type:%d,"
+											"max_amount:%f,"
+											"consumed_amount:%f;",
+											credit_data->call_list->client_id.len, credit_data->call_list->client_id.s,
+											credit_data->number_of_calls,
+											credit_data->concurrent_calls,
+											type,
+											credit_data->max_amount,
+											credit_data->consumed_amount);
 				}
-				else
-				{
-					LM_ERR("Unknown credit type: %d", type);
+				else {
+					LM_ERR("Unknown credit type: %d\n", type);
 					return -1;
 				}
 
@@ -235,8 +217,7 @@ static int iterate_over_table(hash_tables_t *hts, str *result, credit_type_t typ
 				row_len 	= strlen(row_buffer);
 				result->s	= pkg_realloc(result->s, result->len + row_len);
 
-				if (result->s == NULL)
-				{
+				if (result->s == NULL) {
 					lock_release(&hts->lock);
 					goto nomem;
 				}
@@ -255,8 +236,7 @@ nomem:
 	return -1;
 }
 
-void rpc_active_clients(rpc_t* rpc, void* ctx)
-{
+void rpc_active_clients(rpc_t* rpc, void* ctx) {
 	str rows;
 
 	rows.s	 = pkg_malloc(10);
@@ -269,8 +249,7 @@ void rpc_active_clients(rpc_t* rpc, void* ctx)
 	iterate_over_table(&_data.time, &rows, CREDIT_TIME);
 	iterate_over_table(&_data.money, &rows, CREDIT_MONEY);
 
-	if (!rpc->add(ctx, "S", &rows) < 0)
-	{
+	if (!rpc->add(ctx, "S", &rows) < 0) {
 		LM_ERR("%s: error creating RPC struct\n", __FUNCTION__);
 	}
 
@@ -280,7 +259,7 @@ void rpc_active_clients(rpc_t* rpc, void* ctx)
 	return;
 
 nomem:
-	LM_ERR("No more pkg memory");
+	LM_ERR("No more pkg memory\n");
 	rpc->fault(ctx, 500, "No more memory\n");
 }
 

+ 1 - 1
modules/cnxcc/cnxcc_rpc.h

@@ -18,7 +18,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  */
 

+ 7 - 7
modules/cnxcc/cnxcc_select.c

@@ -18,7 +18,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  */
 
@@ -36,28 +36,28 @@ int sel_root(str* res, select_t* s, struct sip_msg* msg)  /* dummy */
 
 int sel_channels(str* res, select_t* s, struct sip_msg* msg)
 {
-	LM_DBG("sel_channels\n");
+	LM_DBG("sel_channels");
 
 	return 0;
 }
 
 int sel_channels_count(str* res, select_t* s, struct sip_msg* msg)
 {
-	LM_DBG("sel_channels_count for [%.*s]\n",  s->params[2].v.s.len, s->params[2].v.s.s);
+	LM_DBG("sel_channels_count for [%.*s]",  s->params[2].v.s.len, s->params[2].v.s.s);
 
 	credit_data_t *credit_data	= NULL;
-	int value			= 0;
+	int value					= 0;
 
 	if (s->params[2].v.s.len <= 0)
 	{
-		LM_ERR("Client must be specified\n");
+		LM_ERR("Client must be specified");
 		return -1;
 	}
 
-	if (try_get_credit_data_entry(&s->params[2].v.s, &credit_data) == 0)
+	if (try_get_credit_data_entry(&s->params[2].v.s, &credit_data) >= 0)
 		value = credit_data->number_of_calls;
 	else
-		LM_DBG("Client [%.*s] not found\n", s->params[2].v.s.len, s->params[2].v.s.s);
+		LM_DBG("Client [%.*s] not found", s->params[2].v.s.len, s->params[2].v.s.s);
 
 	res->s 	= int2str(value, &res->len);
 

+ 1 - 1
modules/cnxcc/cnxcc_select.h

@@ -18,7 +18,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  */
 

+ 5 - 8
modules/cnxcc/cnxcc_sip_msg_faker.c

@@ -18,7 +18,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  */
 
@@ -34,26 +34,23 @@ char _faked_sip_msg_buf[FAKED_SIP_MSG_BUF_LEN];
 
 static struct sip_msg _faked_msg;
 
-int faked_msg_init_with_dlg_info(str *callid, str *from_uri, str *from_tag, str *to_uri, str *to_tag, struct sip_msg **msg)
-{
+int faked_msg_init_with_dlg_info(str *callid, str *from_uri, str *from_tag, str *to_uri, str *to_tag, struct sip_msg **msg) {
 	memset(_faked_sip_msg_buf, 0, FAKED_SIP_MSG_BUF_LEN);
 
 	sprintf(_faked_sip_msg_buf, FAKED_SIP_MSG_FORMAT,
 				from_uri->len, from_uri->s, from_tag->len, from_tag->s,
 				to_uri->len, to_uri->s, to_tag->len, to_tag->s,
 				callid->len, callid->s);
-
+ 
 	LM_DBG("fake msg:\n%s\n", _faked_sip_msg_buf);
-	memset(&_faked_msg, 0, sizeof(struct sip_msg));
 
 	_faked_msg.buf = _faked_sip_msg_buf;
 	_faked_msg.len = strlen(_faked_sip_msg_buf);
 
 	_faked_msg.set_global_address	= default_global_address;
-	_faked_msg.set_global_port		= default_global_port;
+	_faked_msg.set_global_port	= default_global_port;
 
-	if (parse_msg(_faked_msg.buf, _faked_msg.len, &_faked_msg) != 0)
-	{
+	if (parse_msg(_faked_msg.buf, _faked_msg.len, &_faked_msg) != 0) {
 		LM_ERR("parse_msg failed\n");
 		return -1;
 	}

+ 1 - 1
modules/cnxcc/cnxcc_sip_msg_faker.h

@@ -18,7 +18,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  */
 #ifndef CNXCC_SIP_MSG_FAKER_H_

+ 7 - 2
modules/cnxcc/doc/cnxcc.xml

@@ -15,7 +15,7 @@
     <authorgroup>
 	<author>
 	<firstname>Carlos</firstname>
-	<surname>Ruiz Diaz</surname>
+	<surname>Ruiz Díaz</surname>
 	<affiliation>
 	    <orgname>ConexionGroup S.A.</orgname>
 	</affiliation>
@@ -26,8 +26,13 @@
     </authorgroup>
     <copyright>
 	<year>2013</year>
-	<holder>Carlos Ruiz Diaz, [email protected]</holder>
+	<holder>Carlos Ruiz Díaz, [email protected]</holder>
     </copyright>
+    <copyright>
+	<year>2014</year>
+	<holder>Carlos Ruiz Díaz, [email protected]</holder>
+    </copyright>
+
     </bookinfo>
 
     <toc></toc>

+ 37 - 18
modules/cnxcc/doc/cnxcc_admin.xml

@@ -35,7 +35,7 @@
 	</para>
 	<para>
 		If your accounting program does not maintain the state of the call in real time, this module can provide you
-		that ability.
+		with that ability.
 	</para>
 	<para>
 		Cnxcc can also provide more common means of monitoring, i.e., by time limit or by maximum simultaneous calls.
@@ -59,22 +59,41 @@
 		</itemizedlist>
 	    </para>
 	</section>
+	<section>
+	    <title>Libraries</title>
+	    <para>
+		The following module must be loaded before this module: 
+		<itemizedlist>
+		    <listitem>
+		    <para>
+			<emphasis> hiredis-devel >= 0.11.0 </emphasis>
+		    </para>
+		    </listitem>
+		    <listitem>
+		    <para>
+			<emphasis> libevent-devel >= 2.0.18-2 </emphasis>
+		    </para>
+		    </listitem>
+
+		</itemizedlist>
+	    </para>
+	</section>
+
     </section>
 
     <section>
 	<title>Parameters</title>
 	<section>
-		<title><varname> dlg_flag </varname> (integer)</title>
+		<title><varname> redis </varname> (integer)</title>
 	    <para>
-		Flag to indicate if the dialog must be monitored or not. Messages are flagged with this value if we call one of
-		the monitoring functions.
+		Redis datasource connection information
 	    </para>
 	    <example>
 
 		<title>dlg_flag</title>
 		<programlisting format="linespecific">
 ...
-modparam("cnxcc", "dlg_flag", 29)
+modparam("cnxcc", "redis", "addr=127.0.0.1;port=6379;db=1")
 ...		
 		</programlisting>
 	    </example>
@@ -144,8 +163,7 @@ $var(cps)   = "2.00";         # cost per second
 $var(initial_p)   = "030";    # intial pulse
 $var(final_p)   = "006";      # final pulse
 
-cnxcc_set_max_credit("$var(customer)", "$var(credit)", "$var(cps)",
-                     "$var(initial_p)", "$var(final_p)");
+cnxcc_set_max_credit("$var(customer)", "$var(credit)", "$var(cps)", "$var(initial_p)", "$var(final_p)");
 ...		
 		</programlisting>
 	    </example>
@@ -275,17 +293,17 @@ $var(max_chan)  = 2;
 $var(retcode)   = cnxcc_set_max_channels("$var(customer)", "$var(max_chan)");
 
 if ($var(retcode) == -1) {
-    xlog("Error setting up credit control");
-    return;
+	xlog("Error setting up credit control");
+	return;
 }
 
 if ($var(retcode) &lt; -1) {
-    xlog("Too many channels for customer");
-    sl_send_reply(403, "Forbidden");
+        xlog("Too many channels for customer");
+        sl_send_reply(403, "Forbidden");
 
-    if (!cnxcc_terminate_all("$var(customer)")) {
-        xlog("Error terminating customer's calls");
-    }
+        if (!cnxcc_terminate_all("$var(customer)")) {
+		xlog("Error terminating customer's calls");
+	}
 
 	exit;
 }
@@ -325,7 +343,7 @@ if ($var(retcode) &lt; -1) {
 $var(customer)  = "john-doe-123-basic";
 
 if (!cnxcc_terminate_all("$var(customer)")) {
-    xlog("Error terminating customer's calls");
+	xlog("Error terminating customer's calls");
 }
 ...
 		</programlisting>
@@ -400,9 +418,9 @@ if (!cnxcc_terminate_all("$var(customer)")) {
 ...
 event_route[cnxcc:call-shutdown]
 {
-    xlog("L_INFO", "[$ci]: call killed");
+	xlog("L_INFO", "[$ci]: call killed");
 
-    # perform some kind of notification, database update, email sending, etc.
+        # perform some kind of notification, database update, email sending, etc.
 }
 ...
 		</programlisting>
@@ -439,7 +457,7 @@ route[CNXCC]
                           "$var(cost_per_sec)",
                           "$var(i_pulse)",
                           "$var(f_pulse)")) {
-             xlog("Error setting up credit control");
+		 xlog("Error setting up credit control");
       	}
 }
 
@@ -447,6 +465,7 @@ event_route[cnxcc:call-shutdown]
 {
 	xlog("L_INFO", "[$ci]: call killed");
 
+
 }	    
 ...
 	    </programlisting>

部分文件因文件數量過多而無法顯示