>From b157ca5d4a0a64a38dfba89c37625d579025568a Mon Sep 17 00:00:00 2001
From: lucian balanceanu <lucian.balanceanu@1and1.ro>
Date: Wed, 23 Jul 2014 08:17:49 +0300
Subject: [PATCH] acc: fix cdr extra2strar allocation issues

- for more than 10 string cdr_extra parameters, the addresses used
  by the new parameters overwrite the previous ones; our solution is
  to allocate memory for the cdr extra params with pkg_malloc() and
  free it once it is no longer needed.
---
 modules/acc/acc.c       |    7 ++++++-
 modules/acc/acc_cdr.c   |   35 ++++++++++++++++++++++++++++-------
 modules/acc/acc_extra.c |   36 +++++++++++++++---------------------
 modules/acc/acc_extra.h |   11 +++++++++++
 modules/acc/acc_mod.c   |    3 ---
 5 files changed, 60 insertions(+), 32 deletions(-)

diff --git a/modules/acc/acc.c b/modules/acc/acc.c
index 418e709..51dfde5 100644
--- a/modules/acc/acc.c
+++ b/modules/acc/acc.c
@@ -229,6 +229,7 @@ int acc_log_request( struct sip_msg *rq)
 	char *p;
 	int n;
 	int m;
+	int o = 0;
 	int i;
 	struct tm *t;
 
@@ -236,7 +237,9 @@ int acc_log_request( struct sip_msg *rq)
 	m = core2strar( rq, val_arr, int_arr, type_arr);
 
 	/* get extra values */
-	m += extra2strar( log_extra, rq, val_arr+m, int_arr+m, type_arr+m);
+	o += extra2strar( log_extra, rq, val_arr+m, int_arr+m, type_arr+m);
+
+	m += o;
 
 	for ( i=0,p=log_msg ; i<m ; i++ ) {
 		if (p+1+log_attrs[i].len+1+val_arr[i].len >= log_msg_end) {
@@ -314,6 +317,8 @@ int acc_log_request( struct sip_msg *rq)
 			acc_env.text.len, acc_env.text.s,(unsigned long)acc_env.ts,
 			log_msg);
 	}
+	/* free memory allocated by extra2strar */
+	free_strar_mem( &(type_arr[m-o]), &(val_arr[m-o]), o, m);
 
 	return 1;
 }
diff --git a/modules/acc/acc_cdr.c b/modules/acc/acc_cdr.c
index c8d2684..dd716c6 100644
--- a/modules/acc/acc_cdr.c
+++ b/modules/acc/acc_cdr.c
@@ -89,6 +89,14 @@ extern str cdr_duration_str;
 extern str acc_cdrs_table;
 extern int cdr_log_enable;
 
+#define FREE_EXTRA_MEM ( type_arr, alloc_arr, dim_arr, dim_ext) \
+	for ( int i = 0; i < dim_arr; i ++ ) { \
+		if (type_arr[i] != TYPE_NULL ) { \
+			LM_DBG("Freeing memory, type is %d, message_index %d, index i %d\n", type_arr[i], dim_ext - dim_arr, i); \
+			pkg_free( alloc_arr[i].s); \
+		} \
+	} \
+
 /* write all basic information to buffers(e.g. start-time ...) */
 static int cdr_core2strar( struct dlg_cell* dlg,
                            str* values,
@@ -131,6 +139,7 @@ static int db_write_cdr( struct dlg_cell* dialog,
                       struct sip_msg* message)
 {
 	int m = 0;
+	int n = 0;
 	int i;
 	db_func_t *df=NULL;
 	db1_con_t *dh=NULL;
@@ -163,11 +172,12 @@ static int db_write_cdr( struct dlg_cell* dialog,
     /* get extra values */
     if (message)
     {
-		m += extra2strar( cdr_extra,
+		n += extra2strar( cdr_extra,
 							message,
 							cdr_value_array + m,
 							cdr_int_array + m,
 							cdr_type_array + m);
+		m += n;
     } else if (cdr_expired_dlg_enable){
         LM_WARN( "fallback to dlg_only search because of message doesn't exist.\n");
         m += extra2strar_dlg_only( cdr_extra,
@@ -187,27 +197,34 @@ static int db_write_cdr( struct dlg_cell* dialog,
 
 	if (df->use_table(dh, &acc_cdrs_table /*table*/) < 0) {
 		LM_ERR("error in use_table\n");
-		return -1;
+		goto error;
 	}
 
 	if(acc_db_insert_mode==1 && df->insert_delayed!=NULL) {
 		if (df->insert_delayed(dh, db_cdr_keys, db_cdr_vals, m) < 0) {
 			LM_ERR("failed to insert delayed into database\n");
-			return -1;
+			goto error;
 		}
 	} else if(acc_db_insert_mode==2 && df->insert_async!=NULL) {
 		if (df->insert_async(dh, db_cdr_keys, db_cdr_vals, m) < 0) {
 			LM_ERR("failed to insert async into database\n");
-			return -1;
+			goto error;
 		}
 	} else {
 		if (df->insert(dh, db_cdr_keys, db_cdr_vals, m) < 0) {
 			LM_ERR("failed to insert into database\n");
-			return -1;
+			goto error;
 		}
 	}
 
+	/* Free memory allocated by acc_extra.c/extra2strar */
+	free_strar_mem( &(cdr_type_array[m-n]), &(cdr_value_array[m-n]), n, m);
 	return 0;
+
+error:
+    /* Free memory allocated by acc_extra.c/extra2strar */
+	free_strar_mem( &(cdr_type_array[m-n]), &(cdr_value_array[m-n]), n, m);
+    return -1;
 }
 #endif
 
@@ -221,6 +238,7 @@ static int log_write_cdr( struct dlg_cell* dialog,
                                          2;// -2 because of the string ending '\n\0'
     char* message_position = NULL;
     int message_index = 0;
+	int extra_index = 0;
     int counter = 0;
 
 	if(cdr_log_enable==0)
@@ -235,7 +253,7 @@ static int log_write_cdr( struct dlg_cell* dialog,
     /* get extra values */
     if (message)
     {
-        message_index += extra2strar( cdr_extra,
+        extra_index += extra2strar( cdr_extra,
                                       message,
                                       cdr_value_array + message_index,
                                       cdr_int_array + message_index,
@@ -249,7 +267,7 @@ static int log_write_cdr( struct dlg_cell* dialog,
                                                cdr_type_array + message_index,
                                                &dlgb);
     }
-
+	message_index += extra_index;
 
     for( counter = 0, message_position = cdr_message;
          counter < message_index ;
@@ -296,6 +314,9 @@ static int log_write_cdr( struct dlg_cell* dialog,
 
     LM_GEN2( cdr_facility, log_level, "%s", cdr_message);
 
+	/* free memory allocated by extra2strar, nothing is done in case no extra strings were found by extra2strar */
+    free_strar_mem( &(cdr_type_array[message_index-extra_index]), &(cdr_value_array[message_index-extra_index]),
+				   extra_index, message_index);
     return 0;
 }
 
diff --git a/modules/acc/acc_extra.c b/modules/acc/acc_extra.c
index 4847109..1b6c48d 100644
--- a/modules/acc/acc_extra.c
+++ b/modules/acc/acc_extra.c
@@ -63,16 +63,6 @@
 /* here we copy the strings returned by int2str (which uses a static buffer) */
 static char int_buf[INT2STR_MAX_LEN*MAX_ACC_INT_BUF];
 
-static char *static_detector = 0;
-
-void init_acc_extra(void)
-{
-	int i;
-	/* ugly trick to get the address of the static buffer */
-	static_detector = int2str( (unsigned long)3, &i) + i;
-}
-
-
 struct acc_extra *parse_acc_leg(char *extra_str)
 {
 	struct acc_extra *legs;
@@ -249,10 +239,10 @@ int extra2strar(struct acc_extra *extra, struct sip_msg *rq, str *val_arr,
 {
 	pv_value_t value;
 	int n;
-	int r;
+	int i;
 
 	n = 0;
-	r = 0;
+	i = 0;
 	
 	while (extra) {
 		/* get the value */
@@ -272,15 +262,19 @@ int extra2strar(struct acc_extra *extra, struct sip_msg *rq, str *val_arr,
 			val_arr[n].len = 0;
 			type_arr[n] = TYPE_NULL;
 		} else {
-			/* set the value into the acc buffer */
-			if (value.rs.s+value.rs.len==static_detector) {
-				val_arr[n].s = int_buf + r*INT2STR_MAX_LEN;
-				val_arr[n].len = value.rs.len;
-				memcpy(val_arr[n].s, value.rs.s, value.rs.len);
-				r++;
-			} else {
-				val_arr[n] = value.rs;
-			}
+		    val_arr[n].s = (char *)pkg_malloc(value.rs.len);
+		    if (val_arr[n].s == NULL ) {
+		        LM_ERR("extra2strar: out of memory.\n");
+		        /* Cleanup already allocated memory and
+                   return that we didn't do anything */
+                for (i = 0; i < n ; i++) {
+                    pkg_free(val_arr[i].s);
+                }
+                n = 0;
+                goto done;
+            }
+            memcpy(val_arr[n].s, value.rs.s, value.rs.len);
+            val_arr[n].len = value.rs.len;
 			if (value.flags&PV_VAL_INT) {
 			    int_arr[n] = value.ri;
 			    type_arr[n] = TYPE_INT;
diff --git a/modules/acc/acc_extra.h b/modules/acc/acc_extra.h
index 13112b9..2d95810 100644
--- a/modules/acc/acc_extra.h
+++ b/modules/acc/acc_extra.h
@@ -43,6 +43,7 @@
 #ifndef _ACC_EXTRA_H_
 #define _ACC_EXTRA_H_
 
+#include "acc_api.h"
 #include "../../str.h"
 #include "../../pvar.h"
 #include "../../parser/msg_parser.h"
@@ -72,5 +73,15 @@ int extra2int( struct acc_extra *extra, int *attrs );
 int extra2attrs( struct acc_extra *extra, struct attr *attrs, int offset);
 #endif
 
+static inline void free_strar_mem( char* type_arr, str* alloc_arr, int dim_arr, int dim_ext){
+	int i = 0;
+	for ( i = 0; i < dim_arr; i ++ ) {
+		if (type_arr[i] != TYPE_NULL ) {
+			LM_DBG("Freeing memory, type is %d, message_index %d, index i %d\n",
+					type_arr[i], dim_ext - dim_arr, i);
+			pkg_free( alloc_arr[i].s) ;
+		}
+	}
+}
 #endif
 
diff --git a/modules/acc/acc_mod.c b/modules/acc/acc_mod.c
index 06f859a..2f046d1 100644
--- a/modules/acc/acc_mod.c
+++ b/modules/acc/acc_mod.c
@@ -538,9 +538,6 @@ static int mod_init( void )
 		return -1;
 	}
 
-	/* init the extra engine */
-	init_acc_extra();
-
 	/* configure multi-leg accounting */
 	if (leg_info_str && (leg_info=parse_acc_leg(leg_info_str))==0 ) {
 		LM_ERR("failed to parse multileg_info param\n");
-- 
1.7.4.1

