diff --git a/modules/acc/acc.c b/modules/acc/acc.c index bbac75091c1..20115c218f1 100644 --- a/modules/acc/acc.c +++ b/modules/acc/acc.c @@ -50,16 +50,11 @@ #include "../tm/t_funcs.h" #include "../../aaa/aaa.h" -#ifdef DIAM_ACC -#include "diam_dict.h" -#include "diam_message.h" -#include "diam_tcp.h" -#endif - #include "acc.h" #include "acc_mod.h" #include "acc_extra.h" #include "acc_logic.h" +#include "acc_vars.h" #define TABLE_VERSION 7 @@ -71,61 +66,55 @@ *(p+1) = (n) >> 8; \ } while(0) +#define LEG_VALUE( leg, extra, ctx) (ctx->leg_values[leg][extra->tag_idx].value) + str created_str = str_init("accX_created"); str core_str = str_init("accX_core"); str leg_str = str_init("accX_leg"); str flags_str = str_init("accX_flags"); str table_str = str_init("accX_table"); -str db_extra_str = str_init("accX_db"); -str log_extra_str = str_init("accX_log"); -str aaa_extra_str = str_init("accX_aaa"); -str evi_extra_str = str_init("accX_evi"); - -extern struct acc_extra *log_extra; -extern struct acc_extra *log_extra_bye; -extern struct acc_extra *leg_info; -extern struct acc_extra *leg_bye_info; +str extra_str = str_init("accX_extra"); +str acc_ctx_str = str_init("accX_ctx"); + +extern struct acc_extra *log_extra_tags; +extern struct acc_extra *db_extra_tags; +extern struct acc_extra *aaa_extra_tags; +extern struct acc_extra *evi_extra_tags; + +extern tag_t* extra_tags; +extern int extra_tgs_len; + +extern struct acc_extra *log_leg_tags; +extern struct acc_extra *db_leg_tags; +extern struct acc_extra *aaa_leg_tags; +extern struct acc_extra *evi_leg_tags; + +extern tag_t* leg_tags; +extern int leg_tgs_len; + extern struct acc_enviroment acc_env; -extern struct acc_extra *aaa_extra; -extern struct acc_extra *aaa_extra_bye; +extern int acc_flags_ctx_idx; -#ifdef DIAM_ACC -extern char *diameter_client_host; -extern int diameter_client_port; -extern struct acc_extra *dia_extra; -#endif -extern struct acc_extra *evi_extra; -extern struct acc_extra *evi_extra_bye; event_id_t acc_cdr_event = EVI_ERROR; event_id_t acc_event = EVI_ERROR; event_id_t acc_missed_event = EVI_ERROR; static db_func_t acc_dbf; static db_con_t* db_handle=0; -extern struct acc_extra *db_extra; -extern struct acc_extra *db_extra_bye; extern int acc_log_facility; + /* call created avp id */ extern int acc_created_avp_id; static int build_core_dlg_values(struct dlg_cell *dlg,struct sip_msg *req); -static int build_extra_dlg_values(struct acc_extra* extra, - struct dlg_cell *dlg,struct sip_msg *req, struct sip_msg *reply); -static int build_leg_dlg_values(struct dlg_cell *dlg,struct sip_msg *req); +static int build_extra_dlg_values(extra_value_t* values); +static int build_leg_dlg_values(acc_ctx_t* ctx); static void complete_dlg_values(str *stored_values,str *val_arr,short nr_vals); /* prebuild functions */ -static time_t acc_get_created(struct dlg_cell *dlg); static int prebuild_core_arr(struct dlg_cell *dlg, str *buffer, struct timeval *start); -static int prebuild_extra_arr(struct dlg_cell *dlg, struct sip_msg *msg, - str *buffer, str *type_str, struct acc_extra * extra, int start); -static int prebuild_leg_arr(struct dlg_cell *dlg, str *buffer, short *nr_legs) -; - -static int store_extra_values(struct acc_extra* extra, str *values_str, - struct dlg_cell *dlg, struct sip_msg *req, struct sip_msg *reply); /* array used to collect the values before being * pushed to the storage backend (whatever used) */ @@ -144,24 +133,6 @@ static str val_arr[ACC_CORE_LEN+ACC_DLG_LEN+MAX_ACC_EXTRA+MAX_ACC_LEG]; c_vals[_i].len = 0; \ } while(0) -/* - * - */ -static inline int get_timestamps(unsigned int* created, unsigned int* setup_time)\ -{ - int_str _created_ts; - - if (search_first_avp( 0, acc_created_avp_id, &_created_ts, 0)==0) { - LM_ERR("cannot find created avp\n"); - return -1; - } - - *created = (unsigned int)_created_ts.n; - *setup_time = time(NULL) - *created; - - return 0; -} - /* returns: * method name * from TAG @@ -247,15 +218,11 @@ void acc_log_init(void) SET_LOG_ATTR(n,STATUS); /* init the extra db keys */ - for(extra=log_extra; extra ; extra=extra->next) - log_attrs[n++] = extra->name; - for(extra=log_extra_bye; extra ; extra=extra->next) + for(extra=log_extra_tags; extra ; extra=extra->next) log_attrs[n++] = extra->name; /* multi leg call columns */ - for( extra=leg_info ; extra ; extra=extra->next) - log_attrs[n++] = extra->name; - for( extra=leg_bye_info ; extra ; extra=extra->next) + for( extra=log_leg_tags; extra ; extra=extra->next) log_attrs[n++] = extra->name; /* cdrs columns */ @@ -264,18 +231,16 @@ void acc_log_init(void) SET_LOG_ATTR(n,CREATED); } -int acc_log_cdrs(struct dlg_cell *dlg, struct sip_msg *msg) +int acc_log_cdrs(struct dlg_cell *dlg, struct sip_msg *msg, acc_ctx_t* ctx) { static char log_msg[MAX_SYSLOG_SIZE]; static char *log_msg_end=log_msg+MAX_SYSLOG_SIZE-2; char *p; - int nr_vals, i, j, ret, res = -1, n; - time_t created; - struct timeval start_time,end; + int i, j, ret, res = -1, n; + struct timeval start_time; str core_s, leg_s, extra_s; - short nr_legs; - gettimeofday(&end,NULL); + struct acc_extra* extra; core_s.s = extra_s.s = leg_s.s = 0; @@ -285,24 +250,11 @@ int acc_log_cdrs(struct dlg_cell *dlg, struct sip_msg *msg) goto end; } - ret = prebuild_extra_arr(dlg, msg, &extra_s, - &log_extra_str, log_extra_bye, ret); - if (ret < 0) { - LM_ERR("cannot copy extra arguments\n"); - goto end; - } - /* here starts the extra leg */ - nr_vals = prebuild_leg_arr(dlg, &leg_s, &nr_legs); - if (nr_vals < 0) { - LM_ERR("cannot compute leg values\n"); - goto end; - } - - if (!(created = acc_get_created(dlg))) { - LM_ERR("cannot get created\n"); - goto end; - } + /* prevent acces for setting variable */ + accX_lock(&ctx->lock); + for (extra=log_extra_tags, i=ACC_CORE_LEN; extra; extra=extra->next, ++i, ++ret) + val_arr[i] = ctx->extra_values[extra->tag_idx].value; for ( i = 0,p = log_msg ; i= log_msg_end) { @@ -318,47 +270,29 @@ int acc_log_cdrs(struct dlg_cell *dlg, struct sip_msg *msg) memcpy(p, val_arr[i].s, val_arr[i].len); p += val_arr[i].len; } - LM_DBG("core+extra = %d - nr_legs = %d - nr_vals = %d\n", - ret, nr_legs, nr_vals); - if (leg_info || leg_bye_info) { + if (ctx->leg_values) { leg_s.len = 4; - n = legs2strar(leg_bye_info,msg,val_arr+ret+nr_vals,1); - for (j=0; j= log_msg_end) { - LM_WARN("acc message too long, truncating..\n"); - p = log_msg_end; - break; - } - *(p++) = A_SEPARATOR_CHR; - memcpy(p, log_attrs[i].s, log_attrs[i].len); - p += log_attrs[i].len; - *(p++) = A_EQ_CHR; - memcpy(p, val_arr[i].s, val_arr[i].len); - p += val_arr[i].len; - } - n = legs2strar(leg_bye_info,msg,val_arr+ret+nr_vals,0); - } - while (n) { - for (i=ret; i= log_msg_end) { + for (j=0; jlegs_no; j++) { + for (extra=log_leg_tags, n=ret; extra; extra=extra->next, n++) { + if (p+1+log_attrs[i].len+1+ + LEG_VALUE(j, extra, ctx).len >= log_msg_end) { LM_WARN("acc message too long, truncating..\n"); p = log_msg_end; break; } *(p++) = A_SEPARATOR_CHR; - memcpy(p, log_attrs[i].s, log_attrs[i].len); - p += log_attrs[i].len; + memcpy(p, log_attrs[n].s, log_attrs[n].len); + p += log_attrs[n].len; *(p++) = A_EQ_CHR; - memcpy(p, val_arr[i].s, val_arr[i].len); - p += val_arr[i].len; + memcpy(p, LEG_VALUE(j, extra, ctx).s, LEG_VALUE(j, extra, ctx).len); + p += LEG_VALUE(j, extra, ctx).len; } - n = legs2strar(leg_bye_info,msg,val_arr+ret+nr_vals,0); } - } else - LM_DBG("not entering\n"); + } else { + LM_DBG("no legs\n"); + } + accX_unlock(&ctx->lock); /* terminating line */ *(p++) = '\n'; @@ -366,11 +300,12 @@ int acc_log_cdrs(struct dlg_cell *dlg, struct sip_msg *msg) LM_GEN2(acc_log_facility, acc_log_level, "%.*screated=%lu;call_start_time=%lu;duration=%lu;ms_duration=%lu;setuptime=%lu%s", - acc_env.text.len, acc_env.text.s,(unsigned long)created, + acc_env.text.len, acc_env.text.s,(unsigned long)ctx->created, (unsigned long)start_time.tv_sec, - (unsigned long)(end.tv_sec-start_time.tv_sec), - (unsigned long)((end.tv_sec-start_time.tv_sec)*1000+(end.tv_usec-start_time.tv_usec)%1000), - (unsigned long)(start_time.tv_sec - created), log_msg); + (unsigned long)(ctx->bye_time.tv_sec-start_time.tv_sec), + (unsigned long)((ctx->bye_time.tv_sec-start_time.tv_sec)*1000 + +(ctx->bye_time.tv_usec-start_time.tv_usec)%1000), + (unsigned long)(start_time.tv_sec - ctx->created), log_msg); res = 1; end: @@ -389,22 +324,30 @@ int acc_log_request( struct sip_msg *rq, struct sip_msg *rpl, int cdr_flag) static char log_msg[MAX_SYSLOG_SIZE]; static char *log_msg_end=log_msg+MAX_SYSLOG_SIZE-2; char *p; - int n; int m; - int i; + int i, j; unsigned int _created=0; unsigned int _setup_time=0; - if (cdr_flag && get_timestamps(&_created, &_setup_time)<0) { - LM_ERR("cannot get timestamps\n"); - return -1; + struct acc_extra* extra; + acc_ctx_t* ctx = try_fetch_ctx(); + + if (ctx && cdr_flag) { + /* get created value from context */ + _created = ctx->created; + _setup_time = time(NULL) - _created; } /* get default values */ m = core2strar( rq, val_arr); /* get extra values */ - m += extra2strar( log_extra, rq, rpl, val_arr+m, 0); + if (ctx) { + /* prevent acces for setting variable */ + accX_lock(&ctx->lock); + for (extra=log_extra_tags; extra; extra=extra->next, ++m) + val_arr[m] = ctx->extra_values[extra->tag_idx].value; + } for ( i = 0,p = log_msg ; i= log_msg_end) { @@ -421,23 +364,29 @@ int acc_log_request( struct sip_msg *rq, struct sip_msg *rpl, int cdr_flag) } /* get per leg attributes */ - if ( leg_info ) { - n = legs2strar(leg_info,rq,val_arr+m,1); - do { - for (i=m; i= log_msg_end) { - LM_WARN("acc message too long, truncating..\n"); - p = log_msg_end; - break; + if (ctx) { + /* we are still under lock here */ + if (ctx->leg_values) { + for (j=0; jlegs_no; j++) { + for (extra=log_leg_tags, i=m; extra; extra=extra->next, i++) { + if (p+1+log_attrs[i].len+1+ + LEG_VALUE(j, extra, ctx).len >= log_msg_end) { + LM_WARN("acc message too long, truncating..\n"); + p = log_msg_end; + break; + } + *(p++) = A_SEPARATOR_CHR; + memcpy(p, log_attrs[i].s, log_attrs[i].len); + p += log_attrs[i].len; + *(p++) = A_EQ_CHR; + memcpy(p, LEG_VALUE(j, extra, ctx).s, LEG_VALUE(j, extra,ctx).len); + p += LEG_VALUE(j, extra, ctx).len; } - *(p++) = A_SEPARATOR_CHR; - memcpy(p, log_attrs[i].s, log_attrs[i].len); - p += log_attrs[i].len; - *(p++) = A_EQ_CHR; - memcpy(p, val_arr[i].s, val_arr[i].len); - p += val_arr[i].len; } - }while (p!=log_msg_end && (n=legs2strar(leg_info,rq,val_arr+m,0))!=0); + } else { + LM_DBG("no legs\n"); + } + accX_unlock(&ctx->lock); } /* terminating line */ @@ -445,7 +394,7 @@ int acc_log_request( struct sip_msg *rq, struct sip_msg *rpl, int cdr_flag) *(p++) = 0; - if (cdr_flag) { + if (ctx && cdr_flag) { LM_GEN2(acc_log_facility, acc_log_level, "%.*stimestamp=%lu;created=%lu;setuptime=%lu%s", acc_env.text.len, acc_env.text.s, (unsigned long) acc_env.ts.tv_sec, @@ -460,13 +409,6 @@ int acc_log_request( struct sip_msg *rq, struct sip_msg *rpl, int cdr_flag) return 1; } -int store_log_extra_values(struct dlg_cell *dlg, struct sip_msg *req, - struct sip_msg *reply) -{ - return store_extra_values(log_extra, &log_extra_str, dlg, req, reply); -} - - /******************************************** * SQL ACCOUNTING ********************************************/ @@ -500,16 +442,12 @@ static void acc_db_init_keys(void) time_idx = n-1; /* init the extra db keys */ - for(extra=db_extra; extra ; extra=extra->next) + for(extra=db_extra_tags; extra ; extra=extra->next) db_keys_cdrs[n++] = db_keys[m++] = &extra->name; - for(extra=db_extra_bye; extra ; extra=extra->next) - db_keys_cdrs[n++] = &extra->name; /* multi leg call columns */ - for( extra=leg_info ; extra ; extra=extra->next) + for( extra=db_leg_tags; extra ; extra=extra->next) db_keys_cdrs[n++] = db_keys[m++] = &extra->name; - for( extra=leg_bye_info ; extra ; extra=extra->next) - db_keys_cdrs[n++] = &extra->name; /* init the values */ for(i = 0; i < n; i++) { @@ -605,18 +543,24 @@ int acc_db_request( struct sip_msg *rq, struct sip_msg *rpl, static db_ps_t my_ps2 = NULL; int m; int n; - int i; + int i, j; unsigned int _created=0; unsigned int _setup_time=0; + unsigned int extra_start; + + + struct acc_extra* extra; + acc_ctx_t* ctx = try_fetch_ctx(); if (!acc_dbf.use_table || !acc_dbf.insert) { LM_ERR("database not loaded! Probably database url not defined!\n"); return -1; } - if (cdr_flag && get_timestamps(&_created, &_setup_time)<0) { - LM_ERR("cannot get timestamps\n"); - return -1; + if (ctx && cdr_flag) { + /* get created value from context */ + _created = ctx->created; + _setup_time = time(NULL) - _created; } /* formatted database columns */ @@ -628,64 +572,87 @@ int acc_db_request( struct sip_msg *rq, struct sip_msg *rpl, /* time value */ VAL_TIME(db_vals+(m++)) = acc_env.ts.tv_sec; - /* extra columns */ - m += extra2strar( db_extra, rq, rpl, val_arr+m, 0); - - for( i++; i < m; i++) - VAL_STR(db_vals+i) = val_arr[i]; + /* just count the values to do other ops inside lock */ + if (ctx) { + extra_start=m; + for (extra=db_extra_tags; extra; extra=extra->next, ++m); + for( extra=db_leg_tags, n=0; extra; extra=extra->next, n++); - n = legs2strar(leg_info,rq,val_arr+m,1); - if (cdr_flag) { - VAL_INT(db_vals+(m+n)) = _setup_time; - VAL_TIME(db_vals+(m+n+1)) = _created; + if (cdr_flag) { + VAL_INT(db_vals+(m+n)) = _setup_time; + VAL_TIME(db_vals+(m+n+1)) = _created; + } } acc_dbf.use_table(db_handle, &acc_env.text/*table*/); - CON_PS_REFERENCE(db_handle) = cdr_flag ? + CON_PS_REFERENCE(db_handle) = (ctx && cdr_flag) ? (ins_list? &my_ps_ins2:&my_ps2) : (ins_list? &my_ps_ins:&my_ps); + /* multi-leg columns */ - if ( !leg_info ) { - if (con_set_inslist(&acc_dbf,db_handle,ins_list,db_keys,m+(cdr_flag?2:0)) < 0 ) - CON_RESET_INSLIST(db_handle); - if (acc_dbf.insert(db_handle, db_keys, db_vals, m+(cdr_flag?2:0)) < 0) { - LM_ERR("failed to insert into database\n"); - return -1; + if (ctx) { + /* prevent acces for setting variable */ + accX_lock(&ctx->lock); + + /* extra columns */ + if (ctx->extra_values) { + for (extra=db_extra_tags, i=extra_start; extra; extra=extra->next, ++i) { + VAL_STR(db_vals+i) = ctx->extra_values[extra->tag_idx].value; + } } - } else { - do { - for ( i = m; i < m + n; i++) - VAL_STR(db_vals+i)=val_arr[i]; - if (con_set_inslist(&acc_dbf,db_handle,ins_list,db_keys,m+n+(cdr_flag?2:0)) < 0 ) + + if ( !ctx->leg_values ) { + accX_unlock(&ctx->lock); + if (con_set_inslist(&acc_dbf,db_handle,ins_list,db_keys,m+((ctx&&cdr_flag)?2:0)) < 0 ) CON_RESET_INSLIST(db_handle); - if (acc_dbf.insert(db_handle, db_keys, db_vals, m+n+(cdr_flag?2:0)) < 0) { + if (acc_dbf.insert(db_handle, db_keys, db_vals, m+((ctx&&cdr_flag)?2:0)) < 0) { LM_ERR("failed to insert into database\n"); return -1; } - }while ( (n = legs2strar(leg_info,rq,val_arr+m,0))!=0 ); + } else { + for (j=0; j < ctx->legs_no; j++) { + for (extra=db_leg_tags, i=m; extra; extra=extra->next, i++) { + VAL_STR(db_vals+i)=LEG_VALUE( j, extra, ctx); + } + if (con_set_inslist(&acc_dbf,db_handle,ins_list,db_keys,m+n+((ctx&&cdr_flag)?2:0)) < 0 ) + CON_RESET_INSLIST(db_handle); + if (acc_dbf.insert(db_handle, db_keys, db_vals, m+n+((ctx&&cdr_flag)?2:0)) < 0) { + LM_ERR("failed to insert into database\n"); + accX_unlock(&ctx->lock); + return -1; + } + } + accX_unlock(&ctx->lock); + } + } else { + if (con_set_inslist(&acc_dbf,db_handle,ins_list,db_keys,m+((ctx&&cdr_flag)?2:0)) < 0 ) + CON_RESET_INSLIST(db_handle); + if (acc_dbf.insert(db_handle, db_keys, db_vals, m+((ctx&&cdr_flag)?2:0)) < 0) { + LM_ERR("failed to insert into database\n"); + return -1; + } } return 1; } -int acc_db_cdrs(struct dlg_cell *dlg, struct sip_msg *msg) +int acc_db_cdrs(struct dlg_cell *dlg, struct sip_msg *msg, acc_ctx_t* ctx) { - int total, nr_vals, i, ret, res = -1, nr_bye_vals = 0, j; - int remaining_bye_vals = 0; - time_t created; - struct timeval start_time,end; + int total, i, ret, res = -1, j; + int nr_leg_vals=0; + struct timeval start_time; str core_s, leg_s, extra_s, table; - short nr_legs; static db_ps_t my_ps = NULL; static query_list_t *ins_list = NULL; + struct acc_extra* extra; + if (!acc_dbf.use_table || !acc_dbf.insert) { LM_ERR("database not loaded! Probably database url not defined!\n"); return -1; } core_s.s = extra_s.s = leg_s.s = 0; - gettimeofday(&end,NULL); ret = prebuild_core_arr(dlg, &core_s, &start_time); if (ret < 0) { @@ -693,85 +660,62 @@ int acc_db_cdrs(struct dlg_cell *dlg, struct sip_msg *msg) goto end; } - ret = prebuild_extra_arr(dlg, msg, &extra_s, - &db_extra_str, db_extra_bye, ret); - if (ret < 0) { - LM_ERR("cannot copy extra arguments\n"); - goto end; - } + /* count the number of extra values*/ + for (extra=db_extra_tags; extra; extra=extra->next, ++ret); + /* count the number of leg values*/ + for (extra=db_leg_tags, nr_leg_vals=0; extra; extra=extra->next, nr_leg_vals++); - /* here starts the extra leg */ - nr_vals = prebuild_leg_arr(dlg, &leg_s, &nr_legs); - if (nr_vals < 0) { - LM_ERR("cannot compute leg values\n"); - goto end; - } - - if (!(created = acc_get_created(dlg))) { - LM_ERR("cannot get created\n"); - goto end; - } - - if (dlg_api.fetch_dlg_value(dlg, &table_str, &table, 0) < 0) { - LM_ERR("error getting table name\n"); - return -1; - } + table = ctx->acc_table; for (i=0;icreated; + VAL_TIME(db_vals_cdrs+ret+nr_leg_vals+2) = ctx->created; + VAL_INT(db_vals_cdrs+ret+nr_leg_vals+3) = + ctx->bye_time.tv_sec - start_time.tv_sec; + VAL_INT(db_vals_cdrs+ret+nr_leg_vals+4) = + (ctx->bye_time.tv_sec-start_time.tv_sec)*1000+(ctx->bye_time.tv_usec-start_time.tv_usec)%1000; total = ret + 5; acc_dbf.use_table(db_handle, &table); CON_PS_REFERENCE(db_handle) = &my_ps; - if (!leg_info && !leg_bye_info) { + + /* prevent acces for setting variable */ + accX_lock(&ctx->lock); + + for (extra=db_extra_tags,i=ACC_CORE_LEN+1; extra; extra=extra->next, ++i) + VAL_STR(db_vals_cdrs+i) = ctx->extra_values[extra->tag_idx].value; + + if (!ctx->leg_values) { if (con_set_inslist(&acc_dbf,db_handle,&ins_list,db_keys_cdrs,total) < 0 ) CON_RESET_INSLIST(db_handle); if (acc_dbf.insert(db_handle, db_keys_cdrs, db_vals_cdrs, total) < 0) { LM_ERR("failed to insert into database\n"); + accX_unlock(&ctx->lock); goto end; } + accX_unlock(&ctx->lock); } else { - total += nr_vals; + total += nr_leg_vals; leg_s.len = 4; - for (i=0;ilegs_no; i++) { + for (extra=db_leg_tags, j=0; extra; extra=extra->next, j++) { + VAL_STR(db_vals_cdrs+ret+j+1) = LEG_VALUE( i, extra, ctx); } - remaining_bye_vals = legs2strar(leg_bye_info,msg,val_arr+ret+nr_vals, 0); - } - /* check if there is any other extra info */ - while (remaining_bye_vals) { - /* drain all the values */ - for (j = ret+nr_vals; jlock); goto end; } - remaining_bye_vals = legs2strar(leg_bye_info,msg,val_arr+ret+nr_vals, 0); } + accX_unlock(&ctx->lock); } res = 1; @@ -785,12 +729,6 @@ int acc_db_cdrs(struct dlg_cell *dlg, struct sip_msg *msg) return res; } -int store_db_extra_values(struct dlg_cell *dlg, struct sip_msg *req, - struct sip_msg *reply) -{ - return store_extra_values(db_extra, &db_extra_str, dlg, req, reply); -} - /************ AAA PROTOCOLS helper functions **************/ inline static uint32_t phrase2code(str *phrase) { @@ -845,11 +783,10 @@ int init_acc_aaa(char* aaa_proto_url, int srv_type) rd_vals[RV_SIP_SESSION].name = "Sip-Session"; /* add and count the extras as attributes */ - n += extra2attrs( aaa_extra, rd_attrs, n); - n += extra2attrs( aaa_extra_bye, rd_attrs, n); + n += extra2attrs( aaa_extra_tags, rd_attrs, n); + /* add and count the legs as attributes */ - n += extra2attrs( leg_info, rd_attrs, n); - n += extra2attrs( leg_bye_info, rd_attrs, n); + n += extra2attrs( aaa_leg_tags, rd_attrs, n); rd_attrs[n++].name = "Sip-Call-Duration"; rd_attrs[n++].name = "Sip-Call-Setuptime"; @@ -902,7 +839,7 @@ static inline aaa_map *aaa_status( struct sip_msg *req, int code ) int acc_aaa_request( struct sip_msg *req, struct sip_msg *rpl, int cdr_flag) { - int attr_cnt; + int attr_cnt, extra_len; aaa_message *send; int offset, i, av_type; aaa_map *r_stat; @@ -910,14 +847,17 @@ int acc_aaa_request( struct sip_msg *req, struct sip_msg *rpl, int cdr_flag) unsigned int _created=0; unsigned int _setup_time=0; + struct acc_extra* extra; + acc_ctx_t* ctx = try_fetch_ctx(); + if ((send = proto.create_aaa_message(conn, AAA_ACCT)) == NULL) { LM_ERR("failed to create new aaa message for acct\n"); return -1; } - if (cdr_flag && get_timestamps(&_created, &_setup_time)<0) { - LM_ERR("cannot get timestamps\n"); - return -1; + if (ctx &&cdr_flag) { + _created = ctx->created; + _setup_time = time(NULL) - _created; } attr_cnt = core2strar( req, val_arr); @@ -940,8 +880,8 @@ int acc_aaa_request( struct sip_msg *req, struct sip_msg *rpl, int cdr_flag) av_type = (uint32_t)acc_env.ts.tv_sec; ADD_AAA_AVPAIR( RA_TIME_STAMP, &av_type, -1); - /* add extra also */ - attr_cnt += extra2strar( aaa_extra, req, rpl, val_arr+attr_cnt, 0); + if (ctx) + for (extra=aaa_extra_tags, extra_len=0; extra; extra=extra->next, extra_len++); /* add the values for the vector - start from 1 instead of * 0 to skip the first value which is the METHOD as string */ @@ -951,19 +891,31 @@ int acc_aaa_request( struct sip_msg *req, struct sip_msg *rpl, int cdr_flag) if (cdr_flag) { av_type = (uint32_t)_setup_time; - ADD_AAA_AVPAIR( offset + attr_cnt + 1, &av_type, -1); + ADD_AAA_AVPAIR( offset + attr_cnt + extra_len + 1, &av_type, -1); av_type = (uint32_t)_created; - ADD_AAA_AVPAIR( offset + attr_cnt + 2, &av_type, -1); + ADD_AAA_AVPAIR( offset + attr_cnt + extra_len + 2, &av_type, -1); } /* call-legs attributes also get inserted */ - if (leg_info) { - offset += attr_cnt; - attr_cnt = legs2strar(leg_info,req,val_arr,1); - do { - for (i = 0; i < attr_cnt; i++) - ADD_AAA_AVPAIR( offset+i, val_arr[i].s, val_arr[i].len ); - } while ((attr_cnt = legs2strar(leg_info,req,val_arr,0)) != 0); + if (ctx) { + /* prevent acces for setting variable */ + accX_lock(&ctx->lock); + + for (extra = aaa_extra_tags, i=attr_cnt; extra; i++, extra=extra->next) { + ADD_AAA_AVPAIR(offset+i, ctx->extra_values[extra->tag_idx].value.s, + ctx->extra_values[extra->tag_idx].value.len); + } + + if (ctx->leg_values) { + offset += attr_cnt; + for (i=0; ilegs_no; i++) { + for (extra=aaa_leg_tags; extra; extra=extra->next) { + ADD_AAA_AVPAIR( offset+i, + LEG_VALUE(i, extra, ctx).s, LEG_VALUE(i, extra, ctx).len); + } + } + } + accX_unlock(&ctx->lock); } if (proto.send_aaa_request(conn, send, NULL)) { @@ -981,18 +933,18 @@ int acc_aaa_request( struct sip_msg *req, struct sip_msg *rpl, int cdr_flag) return -1; } -int acc_aaa_cdrs(struct dlg_cell *dlg, struct sip_msg *msg) +int acc_aaa_cdrs(struct dlg_cell *dlg, struct sip_msg *msg, acc_ctx_t* ctx) { - int nr_vals, i, j, ret, res = -1; - time_t created; - struct timeval start_time,end; + int i, j, ret, res = -1; + int nr_leg_vals=0; + struct timeval start_time; str core_s, leg_s, extra_s; - short nr_legs; aaa_message *send = NULL; int offset, av_type; aaa_map *r_stat; - gettimeofday(&end,NULL); + struct acc_extra* extra; + core_s.s = extra_s.s = leg_s.s = 0; ret = prebuild_core_arr(dlg, &core_s, &start_time); @@ -1001,25 +953,10 @@ int acc_aaa_cdrs(struct dlg_cell *dlg, struct sip_msg *msg) goto error; } - ret = prebuild_extra_arr(dlg, msg, &extra_s, - &aaa_extra_str, aaa_extra_bye, ret); - if (ret < 0) { - LM_ERR("cannot copy extra arguments\n"); - goto error; - } - - /* here starts the extra leg */ - nr_vals = prebuild_leg_arr(dlg, &leg_s, &nr_legs); - if (nr_vals < 0) { - LM_ERR("cannot compute leg values\n"); - goto error; - } - - if (!(created = acc_get_created(dlg))) { - LM_ERR("cannot get created\n"); - goto error; - } - + /* count the number of values in one leg */ + for (extra=aaa_leg_tags; extra; extra=extra->next, ++ret); + /* count the number of values in one leg */ + for (extra=aaa_leg_tags, nr_leg_vals=0; extra; extra=extra->next, nr_leg_vals++); if ((send = proto.create_aaa_message(conn, AAA_ACCT)) == NULL) { LM_ERR("failed to create new aaa message for acct\n"); @@ -1046,34 +983,35 @@ int acc_aaa_cdrs(struct dlg_cell *dlg, struct sip_msg *msg) offset = RA_STATIC_MAX-1; for (i = 1; i < ACC_CORE_LEN-2; i++) ADD_AAA_AVPAIR( offset + i, val_arr[i].s, val_arr[i].len ); - for (i = ACC_CORE_LEN - 2; ibye_time.tv_sec - start_time.tv_sec); + ADD_AAA_AVPAIR( offset + nr_leg_vals, &av_type, -1); + av_type = (uint32_t)((ctx->bye_time.tv_sec-start_time.tv_sec)*1000+(ctx->bye_time.tv_usec-start_time.tv_usec)%1000); + ADD_AAA_AVPAIR( offset + nr_leg_vals + 1, &av_type, -1); + av_type = (uint32_t)(start_time.tv_sec - ctx->created); + ADD_AAA_AVPAIR( offset + nr_leg_vals + 2, &av_type, -1); + + /* prevent acces for setting variable */ + accX_lock(&ctx->lock); /* call-legs attributes also get inserted */ - if (leg_info || leg_bye_info) { + for (extra=aaa_extra_tags, i=ACC_CORE_LEN+1; extra; extra=extra->next, ++i) { + ADD_AAA_AVPAIR( i, ctx->extra_values[extra->tag_idx].value.s , + ctx->extra_values[extra->tag_idx].value.len ); + } + + if (ctx->leg_values) { leg_s.len = 4; - ret = legs2strar(leg_bye_info,msg,val_arr + nr_vals,1); - for (i=0; ilegs_no; i++) { + for (extra=aaa_leg_tags,j=0; extra; extra=extra->next, j++) { + ADD_AAA_AVPAIR( offset+j, + LEG_VALUE(j, extra, ctx).s, LEG_VALUE(j, extra, ctx).len); + } } } + accX_unlock(&ctx->lock); if (proto.send_aaa_request(conn, send, NULL)) { LM_ERR("Radius accounting request failed for status: '%s' " @@ -1094,237 +1032,6 @@ int acc_aaa_cdrs(struct dlg_cell *dlg, struct sip_msg *msg) return res; } -int store_aaa_extra_values(struct dlg_cell *dlg, struct sip_msg *req, - struct sip_msg *reply) -{ - return store_extra_values(aaa_extra, &aaa_extra_str, dlg, req, reply); -} - -/******************************************** - * DIAMETER ACCOUNTING - ********************************************/ -#ifdef DIAM_ACC - -#define AA_REQUEST 265 -#define AA_ANSWER 265 - -#define ACCOUNTING_REQUEST 271 -#define ACCOUNTING_ANSWER 271 - -static int diam_attrs[ACC_CORE_LEN+MAX_ACC_EXTRA+MAX_ACC_LEG]; - -int acc_diam_init() -{ - int n; - int m; - - n = 0; - /* caution: keep these aligned to core acc output */ - diam_attrs[n++] = AVP_SIP_METHOD; - diam_attrs[n++] = AVP_SIP_FROM_TAG; - diam_attrs[n++] = AVP_SIP_TO_TAG; - diam_attrs[n++] = AVP_SIP_CALLID; - diam_attrs[n++] = AVP_SIP_STATUS; - - m = extra2int( dia_extra, diam_attrs+n); - if (m<0) { - LM_ERR("extra names for DIAMETER must be integer AVP codes\n"); - return -1; - } - n += m; - - m = extra2int( leg_info, diam_attrs+n); - if (m<0) { - LM_ERR("leg info names for DIAMTER must be integer AVP codes\n"); - return -1; - } - n += m; - - return 0; -} - - -inline unsigned long diam_status(struct sip_msg *rq, int code) -{ - if ((rq->REQ_METHOD==METHOD_INVITE || rq->REQ_METHOD==METHOD_ACK) - && code>=200 && code<300) - return AAA_ACCT_START; - - if ((rq->REQ_METHOD==METHOD_BYE || rq->REQ_METHOD==METHOD_CANCEL)) - return AAA_ACCT_STOP; - - if (code>=200 && code <=300) - return AAA_ACCT_EVENT; - - return -1; -} - - -int acc_diam_request( struct sip_msg *req, struct sip_msg *rpl) -{ - int attr_cnt; - int cnt; - AAAMessage *send = NULL; - AAA_AVP *avp; - struct sip_uri puri; - str *uri; - int ret; - int i; - int status; - char tmp[2]; - unsigned int mid; - - attr_cnt = core2strar( req, val_arr); - /* last value is not used */ - attr_cnt--; - - if ( (send=AAAInMessage(ACCOUNTING_REQUEST, AAA_APP_NASREQ))==NULL) { - LM_ERR("failed to create new AAA request\n"); - return -1; - } - - /* AVP_ACCOUNTIG_RECORD_TYPE */ - if( (status = diam_status(req, acc_env.code))<0) { - LM_ERR("status unknown\n"); - goto error; - } - tmp[0] = status+'0'; - tmp[1] = 0; - if( (avp=AAACreateAVP(AVP_Accounting_Record_Type, 0, 0, tmp, - 1, AVP_DUPLICATE_DATA)) == 0) { - LM_ERR("failed to create AVP:no more free memory!\n"); - goto error; - } - if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) { - LM_ERR("avp not added \n"); - AAAFreeAVP(&avp); - goto error; - } - /* SIP_MSGID AVP */ - mid = req->id; - if( (avp=AAACreateAVP(AVP_SIP_MSGID, 0, 0, (char*)(&mid), - sizeof(mid), AVP_DUPLICATE_DATA)) == 0) { - LM_ERR("failed to create AVP:no more free memory!\n"); - goto error; - } - if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) { - LM_ERR("avp not added \n"); - AAAFreeAVP(&avp); - goto error; - } - - /* SIP Service AVP */ - if( (avp=AAACreateAVP(AVP_Service_Type, 0, 0, SIP_ACCOUNTING, - SERVICE_LEN, AVP_DUPLICATE_DATA)) == 0) { - LM_ERR("failed to create AVP:no more free memory!\n"); - goto error; - } - if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) { - LM_ERR("avp not added \n"); - AAAFreeAVP(&avp); - goto error; - } - - /* also the extra attributes */ - attr_cnt += extra2strar( dia_extra, rpl, req, val_arr, 0); - - /* add attributes */ - for(i=0; is, uri->len, &puri) < 0) { - LM_ERR("failed to parse From/To URI\n"); - goto error; - } - - /* Destination-Realm AVP */ - if( (avp=AAACreateAVP(AVP_Destination_Realm, 0, 0, puri.host.s, - puri.host.len, AVP_DUPLICATE_DATA)) == 0) { - LM_ERR("failed to create AVP:no more free memory!\n"); - goto error; - } - - if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) { - LM_ERR("avp not added \n"); - AAAFreeAVP(&avp); - goto error; - } - - /* prepare the message to be sent over the network */ - if(AAABuildMsgBuffer(send) != AAA_ERR_SUCCESS) { - LM_ERR("message buffer not created\n"); - goto error; - } - - if(sockfd==AAA_NO_CONNECTION) { - sockfd = init_mytcp(diameter_client_host, diameter_client_port); - if(sockfd==AAA_NO_CONNECTION) { - LM_ERR("failed to reconnect to Diameter client\n"); - goto error; - } - } - - /* send the message to the DIAMETER client */ - ret = tcp_send_recv(sockfd, send->buf.s, send->buf.len, rb, req->id); - if(ret == AAA_CONN_CLOSED) { - LM_NOTICE("connection to Diameter client closed.It will be " - "reopened by the next request\n"); - close(sockfd); - sockfd = AAA_NO_CONNECTION; - goto error; - } - - if(ret != ACC_SUCCESS) { - /* a transmission error occurred */ - LM_ERR("message sending to the DIAMETER backend authorization " - "server failed\n"); - goto error; - } - - AAAFreeMessage(&send); - return 1; - -error: - AAAFreeMessage(&send); - return -1; -} - -#endif - /******************************************** * EVENT INTERFACE ACCOUNTING @@ -1399,15 +1106,11 @@ int init_acc_evi(void) EVI_CREATE_PARAM(acc_time_evi); /* init the extra db keys */ - for(extra=evi_extra; extra ; extra=extra->next) - EVI_CREATE_PARAM(extra->name); - for(extra=evi_extra_bye; extra ; extra=extra->next) + for(extra=evi_extra_tags; extra ; extra=extra->next) EVI_CREATE_PARAM(extra->name); /* multi leg call columns */ - for( extra=leg_info ; extra ; extra=extra->next) - EVI_CREATE_PARAM(extra->name); - for( extra=leg_bye_info ; extra ; extra=extra->next) + for( extra=evi_leg_tags; extra ; extra=extra->next) EVI_CREATE_PARAM(extra->name); EVI_CREATE_PARAM(acc_duration_evi); @@ -1429,11 +1132,15 @@ int acc_evi_request( struct sip_msg *rq, struct sip_msg *rpl, int cdr_flag) int m; int n; int i; - int backup_idx = -1, ret = -1; + int ret = -1; + int nr_leg_vals; unsigned int _created=0; unsigned int _setup_time=0; + struct acc_extra* extra; + acc_ctx_t* ctx = try_fetch_ctx(); + /* * if the code is not set, choose the missed calls event * otherwise, check if the code is negative @@ -1447,9 +1154,9 @@ int acc_evi_request( struct sip_msg *rq, struct sip_msg *rpl, int cdr_flag) if (!evi_probe_event(acc_env.event)) return 1; - if (cdr_flag && get_timestamps(&_created, &_setup_time)<0) { - LM_ERR("cannot get timestamps\n"); - return -1; + if (ctx && cdr_flag) { + _created = ctx->created; + _setup_time = time(NULL) - _created; } m = core2strar( rq, val_arr ); @@ -1465,77 +1172,84 @@ int acc_evi_request( struct sip_msg *rq, struct sip_msg *rpl, int cdr_flag) return -1; } - /* extra columns */ - m += extra2strar( evi_extra, rq, rpl, val_arr+m, 0); - - for( i++; i < m; i++) - if(evi_param_set_str(evi_params[i], &val_arr[i]) < 0) { - LM_ERR("cannot set acc extra parameter\n"); - return -1; - } + for (extra=evi_extra_tags; extra; extra=extra->next, ++m); - /* little hack to jump over the duration parameter*/ - m++; + for (extra=evi_leg_tags, nr_leg_vals=0; extra; extra=extra->next, nr_leg_vals++); - if (cdr_flag && evi_param_set_int(evi_params[m++], &_setup_time) < 0) { + if ((ctx&&cdr_flag) && evi_param_set_int(evi_params[m+nr_leg_vals], &_setup_time) < 0) { LM_ERR("cannot set setuptime parameter\n"); goto end; } - if (cdr_flag && evi_param_set_int(evi_params[m++], &_created) < 0) { + if ((ctx&&cdr_flag) && evi_param_set_int(evi_params[m+nr_leg_vals+1], &_created) < 0) { LM_ERR("cannot set created parameter\n"); goto end; } /* multi-leg columns */ - if ( !leg_info ) { - /* - * XXX: hack to skip adding the information that doesn't exist - * for these requests - leg info, duration, setuptime, etc. - */ - backup_idx = m - 1; - evi_params[backup_idx]->next = NULL; - - if (evi_raise_event(acc_env.event, acc_event_params) < 0) { - LM_ERR("cannot raise ACC event\n"); - goto end; - } - } else { - n = legs2strar(leg_info,rq,val_arr+m,1); - do { - for ( i = m; i < m + n; i++) - if(evi_param_set_str(evi_params[i], &val_arr[i]) < 0) { - LM_ERR("cannot set acc extra parameter\n"); - goto end; - } - /* XXX: same hack for above, but at least now we have legs */ - backup_idx = i - 1; - evi_params[backup_idx]->next = NULL; + if (ctx) { + /* prevent acces for setting variable */ + accX_lock(&ctx->lock); + + /* extra columns */ + /* i will now indicate at the first position after the core values, where + * we have to put the extras*/ + for( extra=evi_extra_tags, i++; extra; extra=extra->next, i++) + if(evi_param_set_str(evi_params[i], + &ctx->extra_values[extra->tag_idx].value) < 0) { + LM_ERR("cannot set acc extra parameter\n"); + return -1; + } + if ( !ctx->leg_values) { + accX_unlock(&ctx->lock); if (evi_raise_event(acc_env.event, acc_event_params) < 0) { LM_ERR("cannot raise ACC event\n"); goto end; } - evi_params[backup_idx]->next = evi_params[backup_idx + 1]; - }while ( (n = legs2strar(leg_info,rq,val_arr+m,0))!=0 ); + } else { + for (i=0; ilegs_no; i++) { + for (extra=evi_leg_tags, n=m; extra; extra=extra->next,n++) { + if (evi_param_set_str(evi_params[n], + &LEG_VALUE(i, extra, ctx)) < 0) { + LM_ERR("cannot set acc extra parameter\n"); + accX_unlock(&ctx->lock); + goto end; + } + } + + if (evi_raise_event(acc_env.event, acc_event_params) < 0) { + LM_ERR("cannot raise ACC event\n"); + accX_unlock(&ctx->lock); + goto end; + } + } + accX_unlock(&ctx->lock); + } + } else { + if (evi_raise_event(acc_env.event, acc_event_params) < 0) { + LM_ERR("cannot raise ACC event\n"); + goto end; + } } + + + ret = 1; end: - if (backup_idx!=-1) /* can be -1, jumped to end: label*/ - evi_params[backup_idx]->next = evi_params[backup_idx + 1]; - return ret; } -int acc_evi_cdrs(struct dlg_cell *dlg, struct sip_msg *msg) +int acc_evi_cdrs(struct dlg_cell *dlg, struct sip_msg *msg, acc_ctx_t* ctx) { - int nr_vals, i, ret, res = -1, nr_bye_vals = 0, j; + int i, ret, res = -1, j; + int nr_leg_vals; int aux_time; - time_t created; - struct timeval start_time,end; + struct timeval start_time; str core_s, leg_s, extra_s; - short nr_legs; + + struct acc_extra* extra; if (acc_cdr_event == EVI_ERROR) { LM_ERR("event not registered %d\n", acc_cdr_event); @@ -1546,7 +1260,6 @@ int acc_evi_cdrs(struct dlg_cell *dlg, struct sip_msg *msg) if (!evi_probe_event(acc_cdr_event)) return 1; - gettimeofday(&end,NULL); core_s.s = extra_s.s = leg_s.s = 0; ret = prebuild_core_arr(dlg, &core_s, &start_time); @@ -1555,68 +1268,57 @@ int acc_evi_cdrs(struct dlg_cell *dlg, struct sip_msg *msg) goto end; } + /* count extras just to avoid doing all operations below under lock */ + for (extra=evi_extra_tags; extra; extra=extra->next, ++ret); - LM_DBG("XXX: nr before extra is: %d\n", ret); - ret = prebuild_extra_arr(dlg, msg, &extra_s, - &evi_extra_str, evi_extra_bye, ret); - if (ret < 0) { - LM_ERR("cannot copy extra arguments\n"); - goto end; - } - LM_DBG("XXX: nr after extra is: %d\n", ret); - - /* here starts the extra leg */ - nr_vals = prebuild_leg_arr(dlg, &leg_s, &nr_legs); - if (nr_vals < 0) { - LM_ERR("cannot compute leg values\n"); - goto end; - } - - if (!(created = acc_get_created(dlg))) { - LM_ERR("cannot get created\n"); - goto end; - } + /* count the number of leg values */ + for (extra=evi_leg_tags, nr_leg_vals=0; extra; extra=extra->next, nr_leg_vals++); for (i=0;ibye_time.tv_sec - start_time.tv_sec; + if (evi_param_set_int(evi_params[ret+nr_leg_vals+1], &aux_time) < 0) { LM_ERR("cannot set duration parameter\n"); goto end; } - aux_time = (end.tv_sec-start_time.tv_sec)*1000+(end.tv_usec-start_time.tv_usec)%1000; - if (evi_param_set_int(evi_params[ret+nr_vals+nr_bye_vals+2], &aux_time) < 0) { + aux_time = (ctx->bye_time.tv_sec-start_time.tv_sec)*1000 + + (ctx->bye_time.tv_usec-start_time.tv_usec)%1000; + if (evi_param_set_int(evi_params[ret+nr_leg_vals+2], &aux_time) < 0) { LM_ERR("cannot set duration parameter\n"); goto end; } - aux_time = start_time.tv_sec - created; - if (evi_param_set_int(evi_params[ret+nr_vals+nr_bye_vals+3], &aux_time) < 0) { + aux_time = start_time.tv_sec - ctx->created; + if (evi_param_set_int(evi_params[ret+nr_leg_vals+3], &aux_time) < 0) { LM_ERR("cannot set setuptime parameter\n"); goto end; } - if (evi_param_set_int(evi_params[ret+nr_vals+nr_bye_vals+4], &created) < 0) { + if (evi_param_set_int(evi_params[ret+nr_leg_vals+4], &ctx->created) < 0) { LM_ERR("cannot set created parameter\n"); goto end; } - if (!leg_info && !leg_bye_info) { + /* prevent acces for setting variable */ + accX_lock(&ctx->lock); + + for (extra=evi_extra_tags, i=ACC_CORE_LEN+1; extra; extra=extra->next, i++) + if(evi_param_set_str(evi_params[i], &ctx->extra_values[extra->tag_idx].value) < 0) { + LM_ERR("cannot set acc parameter\n"); + accX_unlock(&ctx->lock); + goto end; + } + + + if (!ctx->leg_values) { + accX_unlock(&ctx->lock); /* make sure the parameters list is built */ if (evi_raise_event(acc_cdr_event, acc_event_params) < 0) { LM_ERR("cannot raise acc CDR event\n"); @@ -1624,35 +1326,22 @@ int acc_evi_cdrs(struct dlg_cell *dlg, struct sip_msg *msg) } } else { leg_s.len = 4; - for (i=0;ilegs_no;i++) { + for (extra=evi_leg_tags, j=0; extra; extra=extra->next, j++) { + if(evi_param_set_str(evi_params[ret+j+1], &LEG_VALUE(i, extra, ctx)) < 0) { LM_ERR("cannot set acc parameter\n"); + accX_unlock(&ctx->lock); goto end; } } + if (evi_raise_event(acc_cdr_event, acc_event_params) < 0) { LM_ERR("cannot raise acc CDR event\n"); + accX_unlock(&ctx->lock); goto end; } - nr_bye_vals = legs2strar(leg_bye_info,msg,val_arr+ret+nr_vals, 0); - } - /* there were no Invite legs */ - while (nr_bye_vals) { - /* drain all the values */ - for (j = 0; jlock); } res = 1; @@ -1666,14 +1355,6 @@ int acc_evi_cdrs(struct dlg_cell *dlg, struct sip_msg *msg) return res; } -int store_evi_extra_values(struct dlg_cell *dlg, struct sip_msg *req, - struct sip_msg *reply) -{ - return store_extra_values(evi_extra, &evi_extra_str, dlg, req, reply); -} - - - /* Functions used to store values into dlg */ static str cdr_buf = {NULL, 0}; @@ -1747,25 +1428,15 @@ int store_core_leg_values(struct dlg_cell *dlg, struct sip_msg *req) return -1; } - if ( build_leg_dlg_values(dlg, req) < 0) { - LM_ERR("cannot build legs value string\n"); - return -1; - } - - if (dlg_api.store_dlg_value(dlg,&leg_str,&cdr_buf) < 0) { - LM_ERR("cannot store dialog string\n"); - return -1; - } - return 1; } /* stores extra values into dlg */ -static int store_extra_values(struct acc_extra* extra, str *values_str, - struct dlg_cell *dlg, struct sip_msg *req, struct sip_msg *reply) +int store_extra_values(extra_value_t* values, str *values_str, + struct dlg_cell *dlg) { - if ( build_extra_dlg_values(extra, dlg, req, reply) < 0) { + if ( build_extra_dlg_values(values) < 0) { LM_ERR("cannot build core value string\n"); return -1; } @@ -1778,6 +1449,26 @@ static int store_extra_values(struct acc_extra* extra, str *values_str, return 1; } +int store_leg_values(acc_ctx_t* ctx, str* values_str, struct dlg_cell *dlg) +{ + if (ctx == NULL || values_str == NULL) { + LM_ERR("bad usage!\n"); + return -1; + } + + if ( build_leg_dlg_values(ctx) < 0) { + LM_ERR("cannot build legs value string\n"); + return -1; + } + + if (dlg_api.store_dlg_value(dlg, values_str,&cdr_buf) < 0) { + LM_ERR("cannot store dialog string\n"); + return -1; + } + + return 0; +} + /* builds core string */ static int build_core_dlg_values(struct dlg_cell *dlg,struct sip_msg *req) { @@ -1799,51 +1490,65 @@ static int build_core_dlg_values(struct dlg_cell *dlg,struct sip_msg *req) } /* builds extra values string */ -static int build_extra_dlg_values(struct acc_extra *extra, - struct dlg_cell *dlg,struct sip_msg *req, struct sip_msg *reply) +static int build_extra_dlg_values(extra_value_t* values) { str val_arr[MAX_ACC_EXTRA]; int nr, i; cdr_buf.len = 2; - nr = extra2strar(extra, req, reply, val_arr, 0); + nr = extra2strar(values, val_arr, 0); for (i=0; ileg_values) SET_LEN(cdr_buf.s,0); else { - nr_values = legs2strar(leg_info,req,val_arr,1); - SET_LEN(cdr_buf.s,nr_values); - do { - for (i=0;ilegs_no; i++) { + for (j=0; j < leg_tgs_len; j++) { + if (set_dlg_value(&ctx->leg_values[i][j].value) < 0) { return -1; - nr_legs++; - } while ( (nr_values = legs2strar(leg_info,req,val_arr,0)) != 0); + } + } + } } - SET_LEN(cdr_buf.s+2,nr_legs); - return 1; + + SET_LEN(cdr_buf.s+2,ctx->legs_no); + return 0; } /* create accounting dialog */ int create_acc_dlg(struct sip_msg* req) { struct dlg_cell *dlg; - str current_time; - time_t curr_time; + + if (!dlg_api.get_dlg) { + LM_ERR("dialog not loaded!\n"); + return -1; + } dlg = dlg_api.get_dlg(); if (!dlg) { @@ -1859,14 +1564,6 @@ int create_acc_dlg(struct sip_msg* req) } } - /* store the created time into dlg */ - curr_time = time(NULL); - current_time.s = (char*)&curr_time; - current_time.len = sizeof(time_t); - - if ( dlg_api.store_dlg_value(dlg,&created_str,¤t_time) < 0) - return -1; - return 1; } @@ -1894,69 +1591,154 @@ static int prebuild_core_arr(struct dlg_cell *dlg, str *buffer, struct timeval * } +/* + * @param list of tag names and their indexes + * + * + */ +static extra_value_t* restore_extra_from_str(tag_t* tags, int tags_len, + str* extra_s, int extra_len) +{ + int i; + + pv_value_t value; + extra_value_t* values; + + if (build_acc_extra_array(tags, tags_len, &values) < 0) { + LM_ERR("failed to build extra pvar list!\n"); + return NULL; + } + + value.flags = PV_VAL_STR; + for (i=0; is); + value.rs.s = extra_s->s + 2; + value.flags = value.rs.len == 0 ? PV_VAL_NULL : PV_VAL_STR; -/* gets extra values from dlg and stores them into val_arr array */ -static int prebuild_extra_arr(struct dlg_cell *dlg, struct sip_msg *msg, - str *buffer, str *type_str, struct acc_extra * extra, int start) + if (set_value_shm(&value, &values[i])< 0) { + LM_ERR("failed to set shm value!\n"); + return NULL; + } + + extra_s->s += 2 + value.rs.len; + extra_s->len -= 2 + value.rs.len; + } + + return values; +} + +static int restore_extra(struct dlg_cell* dlg, + str *type_str, acc_ctx_t* ctx) { - short extra_len; + int extra_len; + str buffer = {0, 0}; - if (!start || !type_str || !buffer) { - LM_ERR("invalid parameters\n"); + if (ctx == NULL) { + LM_ERR("bad call!\n"); return -1; } - buffer->len = 0; - buffer->s = 0; - /* fetching extra string values */ - if (dlg_api.fetch_dlg_value(dlg, type_str, buffer, 1) < 0) { - LM_ERR("cannot fetch core string value\n"); + if (dlg_api.fetch_dlg_value(dlg, type_str, &buffer, 1) < 0) { + LM_ERR("cannot fetch <%.*s> value from dialog!\n", + type_str->len, type_str->s); return -1; } - extra_len = GET_LEN(buffer->s); - buffer->len = 2; - complete_dlg_values(buffer, val_arr + start, extra_len); - start += extra_len; + /* jump over the total length */ + extra_len = GET_LEN(buffer.s); + buffer.s += 2; + buffer.len -= 2; - /* populate the extra from bye */ - return start + extra2strar(extra, msg, NULL, val_arr + start, 1); -} + if ((ctx->extra_values = + restore_extra_from_str(extra_tags, extra_tgs_len, &buffer, extra_len)) == NULL) { + LM_ERR("failed to restore extra values!\n"); + return -1; + } + return 0; +} -/* gets leg values from dlg and stores them into val_arr array */ -static int prebuild_leg_arr(struct dlg_cell *dlg, str *buffer, short *nr_legs) +static int restore_legs(struct dlg_cell* dlg, + str *type_str, acc_ctx_t* ctx) { - if (!buffer || !nr_legs) { - LM_ERR("invalid parameters\n"); + short extra_len, i; + str buffer = {0, 0}; + + if (ctx == NULL) { + LM_ERR("bad call!\n"); return -1; } - buffer->len = 0; - buffer->s = 0; - /* fetching leg string values */ - if (dlg_api.fetch_dlg_value(dlg, &leg_str, buffer, 1) < 0) { - LM_ERR("cannot fetch core string value\n"); + if (dlg_api.fetch_dlg_value(dlg, type_str, &buffer, 1) < 0) { + LM_ERR("cannot fetch <%.*s> value from dialog!\n", + type_str->len, type_str->s); + return -1; + } + + ctx->legs_no = GET_LEN(buffer.s+2); + extra_len = GET_LEN(buffer.s); + + if (extra_len != leg_tgs_len) { + LM_WARN("tags were added/removed since last run! won't restore values!\n"); + return 0; + } + + ctx->leg_values = shm_malloc(ctx->legs_no * sizeof(leg_value_p)); + if (ctx->leg_values == NULL) { + LM_ERR("no more shm!\n"); return -1; } - /* getting legs number */ - *nr_legs = GET_LEN(buffer->s+2); + buffer.s += 4; + buffer.len -=4; - return GET_LEN(buffer->s); + for (i=0; ilegs_no; i++) { + if ((ctx->leg_values[i] = + restore_extra_from_str(leg_tags, leg_tgs_len, &buffer, extra_len)) == NULL) { + LM_ERR("failed to restore leg values!\n"); + return -1; + } + } + + return 0; } -/* gets leg values from dlg and stores them into val_arr array */ -static time_t acc_get_created(struct dlg_cell *dlg) +/* + * restore extras that are held in dlg vals + */ +int restore_dlg_extra(struct dlg_cell* dlg, acc_ctx_t** ctx_p) { - time_t created; - str aux; - if (dlg_api.fetch_dlg_value(dlg, &created_str, &aux, 0) < 0) { - LM_ERR("error getting dialog creation time\n"); - return 0; + acc_ctx_t* ctx; + + if (ctx_p == NULL) { + LM_ERR("bad usage! null context!\n"); + return -1; } - memcpy(&created, aux.s, aux.len); - return created; + + ctx = shm_malloc(sizeof(acc_ctx_t)); + if (ctx == NULL) { + LM_ERR("no more shm!\n"); + return -1; + } + + memset(ctx, 0, sizeof(acc_ctx_t)); + + if (extra_tags && + restore_extra(dlg, &extra_str, ctx)) { + LM_ERR("failed to restore extra!\n"); + return -1; + } + + if (leg_tags && + restore_legs(dlg, &leg_str, ctx)) { + LM_ERR("failed to restore legs!\n"); + return -1; + } + + *ctx_p = ctx; + + return 0; + } diff --git a/modules/acc/acc.h b/modules/acc/acc.h index 878fc77f317..099b08a21ae 100644 --- a/modules/acc/acc.h +++ b/modules/acc/acc.h @@ -76,30 +76,33 @@ #define STRING_INIT_SIZE 128 #include "../dialog/dlg_load.h" +#include "acc_extra.h" +#include "acc_logic.h" extern struct dlg_binds dlg_api; + +int store_extra_values(extra_value_t* values, str *values_str, + struct dlg_cell *dlg); +int store_leg_values(acc_ctx_t* ctx, str* values_str, + struct dlg_cell *dlg); + void acc_log_init(); int acc_log_request( struct sip_msg *req, struct sip_msg *rpl, int cdr_flag); -int acc_log_cdrs(struct dlg_cell *dlg, struct sip_msg *msg); -int store_log_extra_values(struct dlg_cell *dlg, struct sip_msg *req, - struct sip_msg *reply); +int acc_log_cdrs(struct dlg_cell *dlg, struct sip_msg *msg, acc_ctx_t* ctx); int acc_db_init(const str* db_url); int acc_db_init_child(const str* db_url); void acc_db_close(); int acc_db_request( struct sip_msg *req, struct sip_msg *rpl, query_list_t **ins_list, int cdr_flag); -int acc_db_cdrs(struct dlg_cell *dlg, struct sip_msg *msg); -int store_db_extra_values(struct dlg_cell *dlg, struct sip_msg *req, - struct sip_msg *reply); +int acc_db_cdrs(struct dlg_cell *dlg, struct sip_msg *msg, acc_ctx_t* ctx); + int init_acc_aaa(char* aaa_proto_url, int srv_type); int acc_aaa_request( struct sip_msg *req, struct sip_msg *rpl, int cdr_flag); int acc_aaa_cdrs_request(struct dlg_cell *dlg); -int acc_aaa_cdrs(struct dlg_cell *dlg, struct sip_msg *msg); -int store_aaa_extra_values(struct dlg_cell *dlg, struct sip_msg *req, - struct sip_msg *reply); +int acc_aaa_cdrs(struct dlg_cell *dlg, struct sip_msg *msg, acc_ctx_t* ctx); int store_core_leg_values(struct dlg_cell *dlg, struct sip_msg *req); int store_created_dlg_time(struct dlg_cell *dlg); @@ -107,19 +110,12 @@ int create_acc_dlg(struct sip_msg* req); int init_acc_evi(void); int acc_evi_request( struct sip_msg *req, struct sip_msg *rpl, int cdr_flag); -int acc_evi_cdrs(struct dlg_cell *dlg, struct sip_msg *msg); -int store_evi_extra_values(struct dlg_cell *dlg, struct sip_msg *req, - struct sip_msg *reply); +int acc_evi_cdrs(struct dlg_cell *dlg, struct sip_msg *msg, acc_ctx_t* ctx); extern event_id_t acc_cdr_event; extern event_id_t acc_event; extern event_id_t acc_missed_event; - -#ifdef DIAM_ACC -int acc_diam_init(); -int acc_diam_request( struct sip_msg *req, struct sip_msg *rpl); -#endif - +int restore_dlg_extra(struct dlg_cell* dlg, acc_ctx_t** ctx); #endif diff --git a/modules/acc/acc_extra.c b/modules/acc/acc_extra.c index fb984786313..a67925844ad 100644 --- a/modules/acc/acc_extra.c +++ b/modules/acc/acc_extra.c @@ -39,6 +39,8 @@ #include "../../socket_info.h" #include "../../mem/mem.h" #include "acc_extra.h" +#include "acc_logic.h" +#include "acc_mod.h" #define EQUAL '=' #define SEPARATOR ';' @@ -51,11 +53,33 @@ #else #define MAX_ACC_INT_BUF MAX_ACC_EXTRA #endif + +extern struct acc_extra *log_extra_tags; +extern struct acc_extra *db_extra_tags; +extern struct acc_extra *aaa_extra_tags; +extern struct acc_extra *evi_extra_tags; + +extern int extra_tgs_len; +extern tag_t* extra_tags; + +extern struct acc_extra *log_leg_tags; +extern struct acc_extra *db_leg_tags; +extern struct acc_extra *aaa_leg_tags; +extern struct acc_extra *evi_leg_tags; + +extern int leg_tgs_len; +extern tag_t* leg_tags; + +static const str tag_delim = str_init("->"); + /* here we copy the strings returned by int2str (which uses a static buffer) */ static char int_buf[MAX_ACC_BUFS][INT2STR_MAX_LEN*MAX_ACC_INT_BUF]; static char* static_detector[2] = {NULL,NULL}; +typedef struct acc_extra** (*str2bkend)(str*); + + void init_acc_extra(void) { int i; @@ -66,149 +90,377 @@ void init_acc_extra(void) } -struct acc_extra *parse_acc_leg(char *extra_str) +/* + * insert a tag int the tags vector + * @param tag to insert(str value) + * @return inserted tag index + */ +/* add tag list param + * tag list will differ for extra/leg */ +static inline int add_tag(str* _stag, tag_t** tag_arr, int* tags_len) { - struct acc_extra *legs; - struct acc_extra *it; - int n; + int ret=-1, i; + + if (tags_len == 0) { + (*tag_arr) = pkg_malloc(TAGS_FACTOR * sizeof(tag_t)); + if ((*tag_arr) == NULL) + goto out_nomem; + } else if ((*tags_len) % TAGS_FACTOR == 0) { + (*tag_arr) = pkg_realloc((*tag_arr), + (*tags_len + TAGS_FACTOR) * sizeof(tag_t)); + if ((*tag_arr) == NULL) + goto out_nomem; + } + + /* serach whether tag has already been inserted */ + for (i=0; i < *tags_len; i++) { + if ((*tag_arr)[i].len == _stag->len && + !memcmp(_stag->s, (*tag_arr)[i].s, (*tag_arr)[i].len)) + return i; + } + + ret = (*tags_len)++; + (*tag_arr)[ret] = *_stag; + + return ret; + +out_nomem: + LM_ERR("no more pkg mem!\n"); + return ret; +} + + +/* + * insert extra into it's list after creating the element + * and adding the tag into the tag list + * @param tag + * @param value + * @param insert list + * @return 0(success)/ < 0 (error) + */ +static inline int add_extra(str* tag, str* value, + struct acc_extra** bkend_list, tag_t** tag_arr, int* tags_len) +{ + int tag_idx; + + struct acc_extra *xel, *it; + + /* first try adding the tag */ + if ((tag_idx=add_tag(tag, tag_arr, tags_len)) < 0) { + LM_ERR("failed to add tag\n"); + return -1; + } + + if ((xel=shm_malloc(sizeof(struct acc_extra))) == NULL) { + LM_ERR("no more pkg mem!\n"); + return -1; + } + + xel->tag_idx = tag_idx; + xel->name = *value; + - legs = parse_acc_extra(extra_str, 1); - if (legs==0) { - LM_ERR("failed to parse extra leg\n"); + xel->next = NULL; + + if (*bkend_list == NULL) { + *bkend_list = xel; return 0; } - /* check the type and len */ - for( it=legs,n=0 ; it ; it=it->next ) { - if (it->spec.type!=PVT_AVP) { - LM_ERR("only AVP are accepted as leg info\n"); - destroy_extras(legs); - return 0; + for ( it=*bkend_list; it; it=it->next) { + /* check if someone is trying to define same tag twice + * for the same backend*/ + if (it->tag_idx == xel->tag_idx) { + LM_WARN("Tag <%.*s> redefined for same backend!" + " Previous definition for this tag in this backend" + " will be overridden!\n", + extra_tags[xel->tag_idx].len, extra_tags[xel->tag_idx].s); + break; } - n++; - if (n>MAX_ACC_LEG) { - LM_ERR("too many leg info; MAX=%d\n", MAX_ACC_LEG); - destroy_extras(legs); - return 0; + + /* add the element at the end of the list and exit */ + if (it->next == NULL) { + it->next = xel; + break; } } - return legs; + return 0; } -struct acc_extra *parse_acc_extra(char *extra_str, int allow_reply) +static inline struct acc_extra** extra_str2bkend(str* bkend) { - struct acc_extra *head; - struct acc_extra *tail; - struct acc_extra *extra; - char *foo; - char *s; - int n; - str stmp; - - n = 0; - head = 0; - extra = 0; - tail = 0; - s = extra_str; - - if (s==0) { - LM_ERR("null string received\n"); - goto error; + static str log_bkend_s = str_init("log"); + static str db_bkend_s = str_init("db"); + static str aaa_bkend_s = str_init("aaa"); + static str evi_bkend_s = str_init("evi"); + + if (bkend->len == log_bkend_s.len && + !memcmp(bkend->s, log_bkend_s.s, log_bkend_s.len)) { + return &log_extra_tags; + } else + if (bkend->len == db_bkend_s.len && + !memcmp(bkend->s, db_bkend_s.s, db_bkend_s.len)) { + return &db_extra_tags; + } else + if (bkend->len == aaa_bkend_s.len && + !memcmp(bkend->s, aaa_bkend_s.s, aaa_bkend_s.len)) { + return &aaa_extra_tags; + } else + if (bkend->len == evi_bkend_s.len && + !memcmp(bkend->s, evi_bkend_s.s, evi_bkend_s.len)) { + return &evi_extra_tags; + } else { + return NULL; } +} - while (*s) { - /* skip white spaces */ - while (*s && isspace((int)*s)) s++; - if (*s==0) - goto parse_error; - if (n==MAX_ACC_EXTRA) { - LM_ERR("too many extras -> please increase the internal buffer\n"); - goto error; - } - extra = (struct acc_extra*)pkg_malloc(sizeof(struct acc_extra)); - if (extra==0) { - LM_ERR("no more pkg mem 1\n"); - goto error; - } - memset( extra, 0, sizeof(struct acc_extra)); +static inline struct acc_extra** leg_str2bkend(str* bkend) +{ + static str log_bkend_s = str_init("log"); + static str db_bkend_s = str_init("db"); + static str aaa_bkend_s = str_init("aaa"); + static str evi_bkend_s = str_init("evi"); + + if (bkend->len == log_bkend_s.len && + !memcmp(bkend->s, log_bkend_s.s, log_bkend_s.len)) { + return &log_leg_tags; + } else + if (bkend->len == db_bkend_s.len && + !memcmp(bkend->s, db_bkend_s.s, db_bkend_s.len)) { + return &db_leg_tags; + } else + if (bkend->len == aaa_bkend_s.len && + !memcmp(bkend->s, aaa_bkend_s.s, aaa_bkend_s.len)) { + return &aaa_leg_tags; + } else + if (bkend->len == evi_bkend_s.len && + !memcmp(bkend->s, evi_bkend_s.s, evi_bkend_s.len)) { + return &evi_leg_tags; + } else { + return NULL; + } +} - /* link the new extra at the end */ - if (tail==0) { - head = extra; + + +/* + * from a token in form of + * tag->value extract the tag and the value + * @param token + * @param tag reference + * @param value reference + * @return 0 (success) / < 0 (error) + * + * tag and value must be allocated beforehand + */ +static int parse_extra_token(str* token, str* tag, str* value) +{ + + /* insanity checks */ + if (token == NULL || token->len == 0 || token->s == NULL + || tag == NULL || value == NULL) { + LM_ERR("bad input!\n"); + return -1; + } + + /* value will not point exactly where the value is + * will point where the - character from the '->' delimiter will be */ + if ((value->s = str_strstr(token, &tag_delim)) == NULL) { + /* if not found then the value is the same as the token */ + str_trim_spaces_lr(*token); + + *value = *tag = *token; + } else { + tag->s = token->s; + tag->len = value->s - token->s; + + /* jump over '->' delimiter */ + value->s += tag_delim.len; + value->len = token->len - (value->s - token->s); + + str_trim_spaces_lr(*tag); + str_trim_spaces_lr(*value); + } + + return 0; +} + + +/* + * parse acc extra element in form of + * :=;=[;] + * last semicolon may miss + * all tags shall be added (if not present) to the tag list + * and be linked to all extra structures in acc_extra lists by + * the index in the vector + * + * @param string to be parsed(char*) + * @return 0(success) / < 0 (error) + */ +static int parse_acc_list_generic(void* val, str2bkend str2bk, + tag_t** tag_arr, int* tags_len) +{ + + str sent={(char*)val, strlen((char*)val)}; + str tok_list_s, backend_s; + + str token, tag, value; + + struct acc_extra** bkend_list; + + char* end; + + + if ((end=q_memchr(sent.s, ':', sent.len)) == NULL) { + LM_ERR("Missing backend separator ':'!\n"); + return -1; + } + + backend_s.s = sent.s; + backend_s.len = end-sent.s; + str_trim_spaces_lr(backend_s); + + if ((bkend_list = str2bk(&backend_s)) == NULL) { + LM_ERR("Invalid backend <%.*s>\n", backend_s.len, backend_s.s); + return -1; + } + + tok_list_s.s = end+1; + tok_list_s.len = sent.len - (end - sent.s + 1); + + do { + end=q_memchr(tok_list_s.s, ';', tok_list_s.len); + + /* get key=value parameter */ + token.s = tok_list_s.s; + + if (end != NULL) { + token.len = end-tok_list_s.s; + tok_list_s.len = tok_list_s.len - (end - tok_list_s.s + 1); + tok_list_s.s = end + 1; } else { - tail->next = extra; + token.len = tok_list_s.len; } - tail = extra; - n++; - - /* get name */ - foo = s; - while (*s && !isspace((int)*s) && EQUAL!=*s) s++; - if (*s==0) - goto parse_error; - if (*s==EQUAL) { - extra->name.len = (s++) - foo; - } else { - extra->name.len = (s++) - foo; - /* skip spaces */ - while (*s && isspace((int)*s)) s++; - if (*s!=EQUAL) - goto parse_error; - s++; + + /* we reached the end or there are probably some trailing spaces + * after the last ';' */ + str_trim_spaces_lr(token); + if (!token.len) + break; + + if (parse_extra_token(&token, &tag, &value) < 0) { + LM_ERR("failed to parse token!\n"); + return -1; } - extra->name.s = foo; - - /* skip spaces */ - while (*s && isspace((int)*s)) s++; - - /* get value type */ - stmp.s = s; stmp.len = strlen(s); - if ( (foo=pv_parse_spec(&stmp, &extra->spec))==0 ) - goto parse_error; - s = foo; - - /* skip spaces */ - while (*s && isspace((int)*s)) s++; - - /* type of message - request or reply ? */ - if (allow_reply && *s=='/') { - s++; - while (*s && isspace((int)*s)) s++; - if (*s==0) - goto parse_error; - foo = s; - while (*s && isalpha((int)*s)) s++; - if (s-foo==REPLY_STR_LEN && - strncasecmp(foo,REPLY_STR_S,REPLY_STR_LEN)==0 ) { - extra->use_rpl =1; - } else { - LM_ERR("unsupported marker <%.*s>\n",(unsigned int)(s-foo),foo); - goto error; - } + + if (add_extra(&tag, &value, bkend_list, tag_arr, tags_len) < 0) { + LM_ERR("failed to add extra!\n"); + return -1; } + } while (end); + + return 0; +} + +int parse_acc_extra(modparam_t type, void* val) { + return parse_acc_list_generic(val, extra_str2bkend, &extra_tags, &extra_tgs_len); +} + +int parse_acc_leg(modparam_t type, void* val) { + return parse_acc_list_generic(val, leg_str2bkend, &leg_tags, &leg_tgs_len); +} + + +/* + * starting from the given tags array build an array with + * pv_value_t type variables that will store the extra variables + * + * */ +int build_acc_extra_array(tag_t* tags, int tags_len, extra_value_t** array_p) +{ + extra_value_t* array; + + if (array_p == NULL) { + LM_ERR("bad usage!\n"); + return -1; + } + - /* skip spaces */ - while (*s && isspace((int)*s)) s++; - if (*s && (*(s++)!=SEPARATOR || *s==0)) - goto parse_error; + array = shm_malloc(tags_len * sizeof(extra_value_t)); + if (array == NULL) { + LM_ERR("no more shm!\n"); + return -1; } - /* go throught all extras and make the names null terminated */ - for( extra=head ; extra ; extra=extra->next) - extra->name.s[extra->name.len] = 0; - - return head; -parse_error: - LM_ERR("parse failed in <%s> " - "around position %d\n",extra_str, (int)(long)(s-extra_str)); -error: - LM_ERR("error\n"); - destroy_extras(head); + memset(array, 0, tags_len * sizeof(extra_value_t)); + + *array_p = array; + + return 0; + +} + +int build_acc_extra_array_pkg(tag_t* tags, int tags_len, extra_value_t** array_p) +{ + extra_value_t* array; + + if (array_p == NULL) { + LM_ERR("bad usage!\n"); + return -1; + } + + + array = pkg_malloc(tags_len * sizeof(extra_value_t)); + if (array == NULL) { + LM_ERR("no more shm!\n"); + return -1; + } + + memset(array, 0, tags_len * sizeof(extra_value_t)); + + *array_p = array; + return 0; } +/* + * create/add new row to the leg matrix + * initialize all values in current row with null + * + * */ +int expand_legs(acc_ctx_t* ctx) +{ + if (ctx == NULL) { + LM_ERR("bad usage!\n"); + return -1; + } + + if (ctx->leg_values == NULL) { + ctx->leg_values = + shm_malloc(LEG_MATRIX_ALLOC_FACTOR * sizeof(leg_value_p)); + ctx->allocated_legs = LEG_MATRIX_ALLOC_FACTOR; + } else if (ctx->legs_no + 1 == ctx->allocated_legs) { + ctx->leg_values = + shm_realloc(ctx->leg_values, + (ctx->allocated_legs + LEG_MATRIX_ALLOC_FACTOR) * + sizeof(leg_value_p)); + ctx->allocated_legs += LEG_MATRIX_ALLOC_FACTOR; + } + + if (ctx->leg_values == NULL) { + LM_ERR("no more shm!\n"); + return -1; + } + + return build_acc_extra_array(leg_tags, + leg_tgs_len, &ctx->leg_values[ctx->legs_no++]); +} + + + + void destroy_extras( struct acc_extra *extra) @@ -218,7 +470,7 @@ void destroy_extras( struct acc_extra *extra) while (extra) { foo = extra; extra = extra->next; - pkg_free(foo); + shm_free(foo); } } @@ -257,10 +509,8 @@ int extra2int( struct acc_extra *extra, int *attrs ) -int extra2strar( struct acc_extra *extra, struct sip_msg *rq, - struct sip_msg *rpl, str *val_arr, int idx) +int extra2strar( extra_value_t* values, str *val_arr, int idx) { - pv_value_t value; int n; int r; @@ -269,54 +519,28 @@ int extra2strar( struct acc_extra *extra, struct sip_msg *rq, return 0; } - if(rq == NULL) { - for (n=0; extra ; extra=extra->next,n++) { - val_arr[n].s = 0; - val_arr[n].len = 0; - } - return n; - } - memset(&value, 0, sizeof(pv_value_t)); - - for( n=0,r=0 ; extra ; extra=extra->next,n++) { + for( n=0,r=0 ; n < extra_tgs_len ; n++) { /* get the value */ - if (extra->use_rpl) { - if (rpl==NULL || rpl==FAKED_REPLY ) { - /* force a NULL value */ - value.flags |= PV_VAL_NULL; - } else if (pv_get_spec_value( rpl, &extra->spec, &value)!=0 ) { - LM_ERR("failed to get '%.*s'\n",extra->name.len,extra->name.s); - /* force a NULL value */ - value.flags |= PV_VAL_NULL; - } - } else { - if (pv_get_spec_value( rq, &extra->spec, &value)!=0) { - LM_ERR("failed to get '%.*s'\n",extra->name.len,extra->name.s); - /* force a NULL value */ - value.flags |= PV_VAL_NULL; - } - } - /* check for overflow */ if (n==MAX_ACC_EXTRA) { LM_WARN("array to short -> ommiting extras for accounting\n"); goto done; } - if(value.flags&PV_VAL_NULL) { + if(values[n].value.s == NULL) { /* convert to empty to have consistency */ val_arr[n].s = 0; val_arr[n].len = 0; } else { /* set the value into the acc buffer */ - if (value.rs.s+value.rs.len==static_detector[0] || - value.rs.s==static_detector[1]) { + if (values[n].value.s+values[n].value.len==static_detector[0] || + values[n].value.s==static_detector[1]) { val_arr[n].s = int_buf[idx] + r*INT2STR_MAX_LEN; - val_arr[n].len = value.rs.len; - memcpy(val_arr[n].s, value.rs.s, value.rs.len); + val_arr[n].len = values[n].value.len; + memcpy(val_arr[n].s, values[n].value.s, values[n].value.len); r++; } else { - val_arr[n] = value.rs; + val_arr[n] = values[n].value; } } } @@ -324,54 +548,3 @@ int extra2strar( struct acc_extra *extra, struct sip_msg *rq, done: return n; } - - -int legs2strar( struct acc_extra *legs, struct sip_msg *rq, str *val_arr, - int start) -{ - static struct usr_avp *avp[MAX_ACC_LEG]; - unsigned short name_type; - int name; - int_str value; - int n; - int found; - int r; - - found = 0; - r = 0; - - for( n=0 ; legs ; legs=legs->next,n++ ) { - /* search for the AVP */ - if (start) { - if ( pv_get_avp_name( rq, &(legs->spec.pvp), &name, &name_type)<0 ) - goto exit; - avp[n] = search_first_avp( name_type, name, &value, 0); - } else { - avp[n] = search_next_avp( avp[n], &value); - } - - /* set new leg record */ - if (avp[n]) { - found = 1; - /* get its value */ - if(avp[n]->flags & AVP_VAL_STR) { - val_arr[n] = value.s; - } else { - val_arr[n].s = int2bstr( value.n, int_buf[MAX_ACC_BUFS-1]+r*INT2STR_MAX_LEN, - &val_arr[n].len); - r++; - } - } else { - val_arr[n].s = 0; - val_arr[n].len = 0; - } - - } - - if (found || start) - return n; -exit: - return 0; -} - - diff --git a/modules/acc/acc_extra.h b/modules/acc/acc_extra.h index e91920f7e94..229686970d1 100644 --- a/modules/acc/acc_extra.h +++ b/modules/acc/acc_extra.h @@ -35,15 +35,32 @@ #include "../../str.h" #include "../../pvar.h" #include "../../parser/msg_parser.h" +#include "../../sr_module.h" +#include "acc_logic.h" + +#define ACC_INT_VALUE (1 << 0) +#define ACC_STR_VALUE (1 << 1) + + +struct acc_extra { + int tag_idx; + + str name; /* log value(column/avp etc. name) */ -struct acc_extra -{ - str name; /* name (log comment/ column name) */ - pv_spec_t spec; /* value's spec */ - unsigned int use_rpl; /* if this value should be taken from reply */ struct acc_extra *next; /* next extra value */ }; +/* + * this protects multiple processes from accessing + * acc_leg/acc_extra values + */ +#define accX_lock(__S__) lock_get(__S__) +#define accX_unlock(__S__) lock_release(__S__) + +/* the factor with which will realloc the tags array */ +#define TAGS_FACTOR 5 +typedef str tag_t; + #define MAX_ACC_EXTRA 64 #define MAX_ACC_LEG 16 @@ -52,17 +69,18 @@ struct acc_extra void init_acc_extra(); -struct acc_extra *parse_acc_extra(char *extra, int allow_reply); +int parse_acc_extra(modparam_t type, void* val); -struct acc_extra *parse_acc_leg(char *extra); +int build_acc_extra_array(tag_t* tags, int tags_len, extra_value_t** array_p); +int build_acc_extra_array_pkg(tag_t* tags, int tags_len, extra_value_t** array_p); -void destroy_extras( struct acc_extra *extra); +int expand_legs(acc_ctx_t* ctx); -int extra2strar( struct acc_extra *extra, struct sip_msg *rq, - struct sip_msg *rpl,str *val_arr, int idx); +int parse_acc_leg(modparam_t type, void* val); + +void destroy_extras( struct acc_extra *extra); -int legs2strar( struct acc_extra *legs, struct sip_msg *rq, - str *val_arr, int start); +int extra2strar( extra_value_t* values, str *val_arr, int idx); int extra2int( struct acc_extra *extra, int *attrs ); diff --git a/modules/acc/acc_logic.c b/modules/acc/acc_logic.c index 4fe8975fe39..9b94707a2a0 100644 --- a/modules/acc/acc_logic.c +++ b/modules/acc/acc_logic.c @@ -39,20 +39,21 @@ #include "../dialog/dlg_hash.h" #include "../../aaa/aaa.h" #include "../../mod_fix.h" - -#ifdef DIAM_ACC -#include "diam_dict.h" -#include "diam_tcp.h" -#endif +#include "../../dprint.h" #include "acc.h" #include "acc_mod.h" #include "acc_logic.h" +#include "acc_extra.h" extern struct tm_binds tmb; extern struct rr_binds rrb; extern str flags_str; extern str table_str; +extern str acc_ctx_str; +extern str extra_str; +extern str leg_str; +extern str created_str; extern str acc_created_avp_name; extern int acc_created_avp_id; @@ -60,6 +61,12 @@ extern int acc_created_avp_id; extern int acc_flags_ctx_idx; extern int acc_tm_flags_ctx_idx; +extern tag_t* extra_tags; +extern int extra_tgs_len; + +extern tag_t* leg_tags; +extern int leg_tgs_len; + struct acc_enviroment acc_env; static query_list_t *acc_ins_list = NULL; @@ -94,35 +101,21 @@ static int is_cdr_enabled=0; #define is_evi_failed_on(_mask) is_evi_flag_on(_mask, DO_ACC_FAILED) -#ifdef DIAM_ACC - #define is_diam_flag_on(_mask, _flag) is_acc_flag_set(_mask, DO_ACC_DIAM, _flag) - #define is_diam_acc_on(_mask) is_diam_flag_on(_mask, DO_ACC) - #define is_diam_cdr_on(_mask) is_diam_flag_on(_mask, DO_ACC_CDR) - #define is_diam_mc_on(_mask) is_diam_flag_on(_mask, DO_ACC_MISSED) - #define is_diam_failed_on(_mask) is_diam_flag_on(_mask, DO_ACC_FAILED) -#else - #define is_diam_acc_on(_mask) (0) - #define is_diam_cdr_on(_mask) (0) - #define is_diam_mc_on(_mask) (0) - #define is_diam_failed_on(_mask) (0) -#endif - #define is_acc_on(_mask) \ ( (is_log_acc_on(_mask)) || (is_db_acc_on(_mask)) \ - || (is_aaa_acc_on(_mask)) || (is_diam_acc_on(_mask)) \ - || (is_evi_acc_on(_mask)) ) + || (is_aaa_acc_on(_mask)) || (is_evi_acc_on(_mask)) ) #define is_cdr_acc_on(_mask) (is_log_cdr_on(_mask) || \ is_aaa_cdr_on(_mask) || is_db_cdr_on(_mask) || \ - is_evi_cdr_on(_mask)||is_diam_cdr_on(_mask)) + is_evi_cdr_on(_mask)) #define is_mc_acc_on(_mask) (is_log_mc_on(_mask) || \ is_aaa_mc_on(_mask) || is_db_cdr_on(_mask) || \ - is_evi_cdr_on(_mask) || is_diam_cdr_on(_mask)) + is_evi_cdr_on(_mask)) #define is_failed_acc_on(_mask) (is_log_failed_on(_mask) || \ is_aaa_failed_on(_mask) || is_db_failed_on(_mask) || \ - is_evi_failed_on(_mask) || is_diam_failed_on(_mask)) + is_evi_failed_on(_mask)) #define set_dialog_context(_mask) \ (_mask) |= ACC_DIALOG_CONTEXT; @@ -186,32 +179,101 @@ static int is_cdr_enabled=0; static void tmcb_func( struct cell* t, int type, struct tmcb_params *ps ); static void acc_dlg_callback(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params); +static void acc_dlg_onshutdown(struct dlg_cell *dlg, int type, + struct dlg_cb_params *_params); +static void acc_cdr_cb( struct cell* t, int type, struct tmcb_params *ps ); + +static inline void free_extra_array(tag_t* tags, int tags_len, + extra_value_t* array) +{ + int i; + + for (i=0; i < tags_len; i++) { + if (array[i].shm_buf_len) + shm_free(array[i].value.s); + } + shm_free(array); +} + +static inline void free_extra_array_pkg(tag_t* tags, int tags_len, + extra_value_t* array) +{ + int i; + + for (i=0; i < tags_len; i++) { + if (array[i].shm_buf_len) + shm_free(array[i].value.s); + } + pkg_free(array); +} + +static inline void free_acc_ctx(acc_ctx_t* ctx) +{ + int i; + + if (ctx->extra_values) + free_extra_array(extra_tags, extra_tgs_len, ctx->extra_values); + if (ctx->leg_values) { + for (i=0; ilegs_no; i++) { + free_extra_array(leg_tags, leg_tgs_len, ctx->leg_values[i]); + } + shm_free(ctx->leg_values); + } + if (ctx->acc_table.s) + shm_free(ctx->acc_table.s); + + shm_free(ctx); +} -void dlg_free_acc_mask(void* param) { +void dlg_free_acc_ctx(void* param) { + acc_ctx_t* ctx=param; /* * decrease the number of references to the shm memory pointer * the free functions are executed sequentially so we know that this operation * is atomic **/ - ACC_MASK_DEC_REF(*((unsigned long long*)param)); + ACC_MASK_DEC_REF(ctx->flags); LM_DBG("flags[%p] ref counter value after dereferencing[%llu]\n", param, - ACC_MASK_GET_REF(*((unsigned long long*)param))); + ACC_MASK_GET_REF(ctx->flags)); + /* * if the reference counter gets to 0 we can free * the shm pointer * */ - if (ACC_MASK_GET_REF(*((unsigned long long*)param)) == 0) - shm_free((unsigned long long *)param); + if (ACC_MASK_GET_REF(ctx->flags) == 0) { + free_acc_ctx(ctx); + } } -void tm_free_acc_mask(void* param) { - if (!is_dialog_context(*(unsigned long long*)param)) { - shm_free((unsigned long long *)param); +void tm_free_acc_ctx(void* param) { + acc_ctx_t* ctx = param; + + + if (!is_dialog_context(ctx->flags)) { + free_acc_ctx(ctx); + + /* there are some cases when this function is called on the initial + * INVITE, so we won't be able free this context from dialog; also + * this callback will be called before processing context destroy + * function, causing a double free so we need to stop the processing + * context from freeing this pointer */ + if (current_processing_ctx) + ACC_PUT_CTX(NULL); } } +/* free function for processing context + * will free only if ACC_PROCESSING_CTX_NO_FREE flag not set */ +void free_processing_acc_ctx(void* param) +{ + acc_ctx_t* ctx = param; + + if (ctx && !(ctx->flags&ACC_PROCESSING_CTX_NO_FREE)) { + free_acc_ctx(ctx); + } +} static inline struct hdr_field* get_rpl_to( struct cell *t, @@ -223,6 +285,63 @@ static inline struct hdr_field* get_rpl_to( struct cell *t, return reply->to; } +acc_ctx_t* try_fetch_ctx(void) +{ + acc_ctx_t* ret=NULL; + str ctx_s; + + struct cell* t; + struct dlg_cell* dlg; + + t = tmb.t_gett ? tmb.t_gett() : NULL; + t = t==T_UNDEFINED ? NULL : t; + + + if ((ret=ACC_GET_CTX) == NULL) { + t = tmb.t_gett ? tmb.t_gett() : NULL; + t = (t==T_UNDEFINED) ? NULL : t; + dlg = dlg_api.get_dlg ? dlg_api.get_dlg() : NULL; + + /* search the flags in transaction context */ + if (t && (ret=ACC_GET_TM_CTX(t))==NULL) { + /* try fetching the context from dialog */ + if (dlg && dlg_api.fetch_dlg_value(dlg, &acc_ctx_str, &ctx_s, 0) < 0) { + /* can't find the flags anywhere */ + return NULL; + } else { /* found them in dialog; set in the processing context + * and in the transaction */ + /* set the flags in transaction and processing context */ + memcpy(&ret, ctx_s.s, sizeof(acc_ctx_t *)); + + ACC_PUT_TM_CTX(t, ret); + ACC_PUT_CTX(ret); + } + } else if (ret) { /* we have the flags in transaction */ + /* in transaction; put them in dialog(if possible) and in processing context */ + ACC_PUT_CTX(ret); + if (dlg) { + ctx_s.s = (char *)&ret; + ctx_s.len = sizeof(acc_ctx_t *); + } + } else if (dlg) { /* no (flags in) transaction; search only in dialog*/ + if (dlg_api.fetch_dlg_value(dlg, &acc_ctx_str, &ctx_s, 0) < 0) { + /* can't find the flags anywhere */ + return NULL; + } else { + /* found them in dialog; set in processing context */ + memcpy(&ret, ctx_s.s, sizeof(acc_ctx_t *)); + + ACC_PUT_CTX(ret); + if (t) { + ACC_PUT_TM_CTX(t, ret); + } + } + } + } + + return ret; +} + static inline void env_set_to(struct hdr_field *to) { @@ -351,22 +470,6 @@ int w_acc_db_request(struct sip_msg *rq, pv_elem_t* comment, char *table) return acc_db_request( rq, NULL,NULL, 0); } -#ifdef DIAM_ACC -int w_acc_diam_request(struct sip_msg *rq, pv_elem_t* comment, char *foo) -{ - struct acc_param accp; - - if (acc_preparse_req(rq)<0) - return -1; - - acc_pvel_to_acc_param(rq, comment, &accp); - - env_set_to( rq->to ); - env_set_comment( &accp ); - return acc_diam_request( rq, NULL); -} -#endif - int w_acc_evi_request(struct sip_msg *rq, pv_elem_t* comment, char *foo) { struct acc_param accp; @@ -473,13 +576,13 @@ static inline int should_acc_reply(struct sip_msg *req,struct sip_msg *rpl, /* parse incoming replies before cloning */ static inline void acc_onreply_in(struct cell *t, struct sip_msg *req, - struct sip_msg *reply, int code, unsigned long long* flags) + struct sip_msg *reply, int code, acc_ctx_t* ctx) { /* don't parse replies in which we are not interested */ /* missed calls enabled ? */ if ( (reply && reply!=FAKED_REPLY) - && (should_acc_reply(req,reply,code, flags) - || (is_invite(t) && code>=300 && is_mc_acc_on(*flags))) ) { + && (should_acc_reply(req,reply,code, &ctx->flags) + || (is_invite(t) && code>=300 && is_mc_acc_on(ctx->flags))) ) { parse_headers(reply, HDR_TO_F, 0 ); } } @@ -488,11 +591,12 @@ static inline void acc_onreply_in(struct cell *t, struct sip_msg *req, /* initiate a report if we previously enabled MC accounting for this t */ static inline void on_missed(struct cell *t, struct sip_msg *req, - struct sip_msg *reply, int code, unsigned long long *flags) + struct sip_msg *reply, int code, acc_ctx_t *ctx) { str new_uri_bk={0,0}; str dst_uri_bk={0,0}; unsigned long long flags_to_reset=0; + unsigned long long *flags = &ctx->flags; if (t->nr_of_outgoings) { /* set as new_uri the last branch */ @@ -534,13 +638,6 @@ static inline void on_missed(struct cell *t, struct sip_msg *req, acc_db_request( req, reply,&mc_ins_list, is_db_cdr_on(*flags)); flags_to_reset |= DO_ACC_DB * DO_ACC_MISSED; } -/* DIAMETER */ -#ifdef DIAM_ACC - if (is_diam_mc_on(*flags)) { - acc_diam_request( req, reply ); - flags_to_reset |= DO_ACC_DIAM * DO_ACC_MISSED; - } -#endif /* Reset the accounting missed_flags * These can't be reset in the blocks above, because @@ -561,7 +658,8 @@ static inline void on_missed(struct cell *t, struct sip_msg *req, /* restore callbacks */ void acc_loaded_callback(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params) { - str flags_s; + str flags_s, ctx_s, table_s; + acc_ctx_t* ctx; if (!dlg) { LM_ERR("null dialog - cannot fetch message flags\n"); @@ -573,9 +671,46 @@ void acc_loaded_callback(struct dlg_cell *dlg, int type, return; } + /** + * restore acc extra context(extra and leg values) + */ + if (restore_dlg_extra(dlg, &ctx)) { + LM_ERR("failed to rebuild acc context!\n"); + return; + } + + /* copy flags value into the context */ + memcpy(&ctx->flags, flags_s.s, flags_s.len); + + /* restore accounting table if db accounting is used */ + if (is_db_acc_on(ctx->flags)) { + if (dlg_api.fetch_dlg_value(dlg, &table_str, &table_s, 0) < 0) { + LM_DBG("table was not saved in dialog\n"); + return; + } + + if ((ctx->acc_table.s=shm_malloc(table_s.len)) == NULL) { + LM_ERR("no more shm!\n"); + return; + } + + memcpy(ctx->acc_table.s, table_s.s, table_s.len); + ctx->acc_table.len = table_s.len; + } + + + + /* replace the context value with a good pointer */ + ctx_s.s = (char *)&ctx; + ctx_s.len = sizeof(acc_ctx_t *); + if (dlg_api.store_dlg_value(dlg, &acc_ctx_str, &ctx_s) < 0) { + LM_ERR("failed to set new context value!\n"); + return; + } + /* register database callbacks */ if (dlg_api.register_dlgcb(dlg, DLGCB_TERMINATED | - DLGCB_EXPIRED, acc_dlg_callback, flags_s.s, 0)){ + DLGCB_EXPIRED, acc_dlg_callback, ctx, dlg_free_acc_ctx)){ LM_ERR("cannot register callback for database accounting\n"); return; } @@ -583,21 +718,21 @@ void acc_loaded_callback(struct dlg_cell *dlg, int type, /* initiate a report if we previously enabled accounting for this t */ static inline void acc_onreply( struct cell* t, struct sip_msg *req, - struct sip_msg *reply, int code, unsigned long long *flags) + struct sip_msg *reply, int code, acc_ctx_t* ctx) { str new_uri_bk; str dst_uri_bk; struct dlg_cell *dlg = NULL; - str flags_s; - int_str table; - struct usr_avp *avp; + str ctx_s; + str table; + unsigned long long* flags = &ctx->flags; /* acc_onreply is bound to TMCB_REPLY which may be called from _reply, like when FR hits; we should not miss this event for missed calls either */ if (is_invite(t) && code>=300 && is_mc_acc_on(*flags) ) { - on_missed(t, req, reply, code, flags); + on_missed(t, req, reply, code, ctx); } if (!should_acc_reply(req, reply, code, flags)) @@ -619,22 +754,11 @@ static inline void acc_onreply( struct cell* t, struct sip_msg *req, env_set_code_status( code, reply); /* search for table avp */ - table.s = db_table_acc; - if (db_table_name != -1 && is_db_acc_on(*flags)) { - avp = search_first_avp(db_table_name_type, db_table_name, &table, 0); - if (!avp) { - LM_DBG("table not set: using default %.*s\n", - db_table_acc.len, db_table_acc.s); - } else { - if (!(avp->flags & AVP_VAL_STR)) { - LM_WARN("invalid integer table name: using default %.*s\n", - db_table_acc.len, db_table_acc.s); - table.s = db_table_acc; - } - } + if (is_db_acc_on(ctx->flags)) { + table = ctx->acc_table; } - if (is_invite(t) && !has_totag(req) && is_cdr_acc_on(*flags) && + if (is_invite(t) && !has_totag(req) && is_cdr_acc_on(ctx->flags) && code >= 200 && code < 300 && (dlg=dlg_api.get_dlg()) != NULL) { /* if dialog module loaded and INVITE and success reply */ if (store_core_leg_values(dlg, req) < 0) { @@ -642,38 +766,12 @@ static inline void acc_onreply( struct cell* t, struct sip_msg *req, return; } - if(is_log_acc_on(*flags) && store_log_extra_values(dlg,req,reply)<0){ - LM_ERR("cannot store string values\n"); - return; - } - - if(is_aaa_acc_on(*flags) && store_aaa_extra_values(dlg, req, reply)<0){ - LM_ERR("cannot store aaa extra values\n"); - return; - } - - if (is_db_acc_on(*flags) && store_db_extra_values(dlg,req,reply)<0) { - LM_ERR("cannot store database extra values\n"); - return; - } - - if (is_evi_acc_on(*flags) && store_evi_extra_values(dlg,req,reply)<0) { - LM_ERR("cannot store database extra values\n"); - return; - } - - flags_s.s = (char*)flags; - flags_s.len = sizeof(unsigned long long); - - /* store flags into dlg */ - if ( dlg_api.store_dlg_value(dlg, &flags_str, &flags_s) < 0) { - LM_ERR("cannot store flag value into dialog\n"); - return; - } + ctx_s.s = (char*)&ctx; + ctx_s.len = sizeof(acc_ctx_t *); - /* store flags into dlg */ - if ( dlg_api.store_dlg_value(dlg, &table_str, &table.s) < 0) { - LM_ERR("cannot store the table name into dialog\n"); + /* store context pointer into dialog */ + if (dlg_api.store_dlg_value(dlg, &acc_ctx_str, &ctx_s) < 0) { + LM_ERR("cannot store context pointer into dlg val!\n"); return; } @@ -681,9 +779,18 @@ static inline void acc_onreply( struct cell* t, struct sip_msg *req, * tm must never free it */ set_dialog_context(*flags); + /* register program shutdown callback + * won't register free function since TERMINATED|EXPIRED callback + * free function will be called to free */ + if (dlg_api.register_dlgcb(dlg, DLGCB_DB_WRITE_VP, + acc_dlg_onshutdown, ctx, NULL) != 0) { + LM_ERR("cannot register callback for program shutdown!\n"); + return; + } + /* register database callbacks */ - if (dlg_api.register_dlgcb(dlg, DLGCB_TERMINATED | - DLGCB_EXPIRED, acc_dlg_callback,flags, dlg_free_acc_mask) != 0) { + if (dlg_api.register_dlgcb(dlg, DLGCB_TERMINATED|DLGCB_EXPIRED, + acc_dlg_callback, ctx, dlg_free_acc_ctx) != 0) { LM_ERR("cannot register callback for database accounting\n"); return; } @@ -703,17 +810,11 @@ static inline void acc_onreply( struct cell* t, struct sip_msg *req, acc_aaa_request( req, reply, 0 ); if (is_db_acc_on(*flags)) { - env_set_text( table.s.s, table.s.len); + env_set_text( table.s, table.len); acc_db_request( req, reply, &acc_ins_list, 0); } } -/* DIAMETER */ -#ifdef DIAM_ACC - if (is_diam_acc_on(req)) - acc_diam_request( req, reply ); -#endif - if (new_uri_bk.len>=0) { req->new_uri = new_uri_bk; req->dst_uri = dst_uri_bk; @@ -724,97 +825,197 @@ static inline void acc_onreply( struct cell* t, struct sip_msg *req, static void acc_dlg_callback(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params) { - unsigned long long flags; + struct cell* t; + acc_ctx_t* ctx; if (!_params) { LM_ERR("not enough info\n"); return; } + ctx = *_params->param; + ACC_PUT_CTX(ctx); - flags = *((unsigned long long*)(*_params->param)); /** * we've read the value of the flags * increase the number of references to the shm memory pointer * we know that this operation is atomic since the dialog callbacks * are executed sequentially */ - ACC_MASK_INC_REF(*((unsigned long long *)*_params->param)); + ACC_MASK_INC_REF(ctx->flags); LM_DBG("flags[%p] ref counter value after referencing [%llu]\n", *_params->param, - ACC_MASK_GET_REF(*((unsigned long long*)*_params->param))); + ACC_MASK_GET_REF(ctx->flags)); /* * this way we "enable" the refcount * if opensips shuts down before dialog terminated then the refcount * won't be enabled */ - set_dlg_cb_used(*((unsigned long long*)*_params->param)); + set_dlg_cb_used(ctx->flags); + + /* this time will be used to set */ + gettimeofday(&ctx->bye_time, NULL); + + /* if it's not a local transaction we do the accounting on the tm callbacks */ + if (((t=tmb.t_gett()) == T_UNDEFINED) || + (t != NULL && !tmb.t_is_local(_params->msg))) { + /* normal dialogs will have to do accounting when the response for + * the bye will come since users should be able to populate extra + * vars and leg vars */ + if (tmb.register_tmcb( _params->msg, NULL, + TMCB_RESPONSE_OUT, acc_cdr_cb, ctx, 0) < 0) { + LM_ERR("failed to register cdr callback!\n"); + return; + } + /* for local transactions we do the accounting here since all the messages + * have been processed */ + } else if (t != NULL && tmb.t_is_local(_params->msg)) { + /* expired dialogs will be handled here */ + if (is_log_acc_on(ctx->flags)) { + env_set_text( ACC_ENDED, ACC_ENDED_LEN); + if (acc_log_cdrs(dlg, _params->msg, ctx) < 0) { + LM_ERR("Cannot log values\n"); + return; + } + } - if (is_evi_acc_on(flags)) { - env_set_event(acc_cdr_event); - if (acc_evi_cdrs(dlg, _params->msg) < 0) { - LM_ERR("cannot send accounting events\n"); + if (is_db_acc_on(ctx->flags)) { + env_set_text( db_table_acc.s, db_table_acc.len); + if (acc_db_cdrs(dlg, _params->msg, ctx) < 0) { + LM_ERR("Cannot insert into database\n"); + return; + } + } + + if (is_aaa_acc_on(ctx->flags) && acc_aaa_cdrs(dlg, _params->msg, ctx) < 0) { + LM_ERR("Cannot create radius accounting\n"); + return; + } + + if (is_evi_acc_on(ctx->flags)) { + env_set_event(acc_cdr_event); + if (acc_evi_cdrs(dlg, _params->msg, ctx) < 0) { + LM_ERR("cannot send accounting events\n"); + return; + } + } + } + +} + + +static void acc_dlg_onshutdown(struct dlg_cell *dlg, int type, + struct dlg_cb_params *_params) +{ + str flags_s; + acc_ctx_t* ctx; + + str created_s; + + if (!_params) { + LM_ERR("not enough info!\n"); + return; + } + + ctx = *_params->param; + + if (ctx->extra_values && + store_extra_values(ctx->extra_values, &extra_str, dlg) < 0) { + LM_ERR("cannot store extra values!\n"); + return; + } + + if (ctx->leg_values && + store_leg_values(ctx, &leg_str, dlg) < 0) { + LM_ERR("cannot store leg values!\n"); + return; + } + + flags_s.s = (char*)(&ctx->flags); + flags_s.len = sizeof(unsigned long long); + + /* store flags into dlg */ + if ( dlg_api.store_dlg_value(dlg, &flags_str, &flags_s) < 0) { + LM_ERR("cannot store flag value into dialog\n"); + return; + } + + created_s.s = (char*)(&ctx->created); + created_s.len = sizeof(time_t); + + if ( dlg_api.store_dlg_value(dlg,&created_str,&created_s) < 0) { + LM_ERR("cannot store created value!\n"); + return; + } + + if (is_db_acc_on(ctx->flags) && ctx->acc_table.s && ctx->acc_table.len) { + if ( dlg_api.store_dlg_value(dlg, &table_str, &ctx->acc_table) < 0) { + LM_ERR("cannot store table name into dialog\n"); return; } } +} + +static void acc_cdr_cb( struct cell* t, int type, struct tmcb_params *ps ) +{ + acc_ctx_t* ctx = *ps->param; + struct dlg_cell *dlg; + + dlg = dlg_api.get_dlg(); + + if (dlg == NULL) { + LM_DBG("dlg is null!\n"); + return; + } - if (is_log_acc_on(flags)) { + if (is_log_acc_on(ctx->flags)) { env_set_text( ACC_ENDED, ACC_ENDED_LEN); - if (acc_log_cdrs(dlg, _params->msg) < 0) { + if (acc_log_cdrs(dlg, ps->req, ctx) < 0) { LM_ERR("Cannot log values\n"); return; } } - if (is_db_acc_on(flags)) { + if (is_db_acc_on(ctx->flags)) { env_set_text( db_table_acc.s, db_table_acc.len); - if (acc_db_cdrs(dlg, _params->msg) < 0) { + if (acc_db_cdrs(dlg, ps->req, ctx) < 0) { LM_ERR("Cannot insert into database\n"); return; } } - if (is_aaa_acc_on(flags) && acc_aaa_cdrs(dlg, _params->msg) < 0) { + if (is_aaa_acc_on(ctx->flags) && acc_aaa_cdrs(dlg, ps->req, ctx) < 0) { LM_ERR("Cannot create radius accounting\n"); return; } + + if (is_evi_acc_on(ctx->flags)) { + env_set_event(acc_cdr_event); + if (acc_evi_cdrs(dlg, ps->req, ctx) < 0) { + LM_ERR("cannot send accounting events\n"); + return; + } + } } static void tmcb_func( struct cell* t, int type, struct tmcb_params *ps ) { - unsigned long long *flags = *ps->param; + acc_ctx_t* ctx = *ps->param; - if (ACC_GET_TM_FLAGS(t) == NULL) - ACC_PUT_TM_FLAGS(t, flags); + if (ACC_GET_TM_CTX(t) == NULL) + ACC_PUT_TM_CTX(t, ctx); if (type&TMCB_RESPONSE_OUT) { - acc_onreply( t, ps->req, ps->rpl, ps->code, flags); + acc_onreply( t, ps->req, ps->rpl, ps->code, ctx); } else if (type&TMCB_ON_FAILURE) { - on_missed( t, ps->req, ps->rpl, ps->code, flags); + on_missed( t, ps->req, ps->rpl, ps->code, ctx); } else if (type&TMCB_RESPONSE_IN) { - acc_onreply_in( t, ps->req, ps->rpl, ps->code, flags); + acc_onreply_in( t, ps->req, ps->rpl, ps->code, ctx); } } -/* - * helper function to retrieve flags from processing context or - * transaction context - */ -static inline unsigned long long* try_fetch_flags(void) -{ - unsigned long long* ret=NULL; - struct cell* t; - - if ((ret=ACC_GET_FLAGS) == NULL) - if (((t=tmb.t_gett()) != NULL) && (t!=T_UNDEFINED) - && ((ret=ACC_GET_TM_FLAGS(t)) == NULL)) - return NULL; - - return ret; -} - /* * use case * @@ -830,7 +1031,6 @@ static inline unsigned long long* try_fetch_flags(void) static str do_acc_log_s=str_init(DO_ACC_LOG_STR); static str do_acc_aaa_s=str_init(DO_ACC_AAA_STR); static str do_acc_db_s=str_init(DO_ACC_DB_STR); -static str do_acc_diam_s=str_init(DO_ACC_DIAM_STR); static str do_acc_evi_s=str_init(DO_ACC_EVI_STR); /* accounting flags strings */ @@ -840,7 +1040,7 @@ static str do_acc_failed_s=str_init(DO_ACC_FAILED_STR); /** - * types: log, aaa, db, diam, evi + * types: log, aaa, db, evi * case insesitive * */ @@ -858,10 +1058,7 @@ unsigned long long do_acc_type_parser(str* token) } else if (token->len == do_acc_db_s.len && !strncasecmp(token->s, do_acc_db_s.s, token->len)) { return DO_ACC_DB; - } else if (token->len == do_acc_diam_s.len && - !strncasecmp(token->s, do_acc_diam_s.s, token->len)) { - return DO_ACC_DIAM; - } else if (token->len == do_acc_evi_s.len && + } else if (token->len == do_acc_evi_s.len && !strncasecmp(token->s, do_acc_evi_s.s, token->len)) { return DO_ACC_EVI; } else { @@ -884,11 +1081,6 @@ unsigned long long do_acc_flags_parser(str* token) !strncasecmp(token->s, do_acc_cdr_s.s, token->len)) { if (!is_cdr_enabled) { - if (parse_avp_spec( &acc_created_avp_name, &acc_created_avp_id) < 0) { - LM_ERR("failed to register AVP name <%s>\n", acc_created_avp_name.s); - return DO_ACC_ERR; - } - if (load_dlg_api(&dlg_api)!=0) LM_DBG("failed to find dialog API - is dialog module loaded?\n"); @@ -1035,7 +1227,70 @@ int do_acc_fixup(void** param, int param_no) return 0; } +static inline int store_acc_table(acc_ctx_t* ctx, str* table) { + if (ctx == NULL || table == NULL || table->s == NULL || table->len == 0) { + LM_ERR("bad usage!\n"); + return -1; + } + + if (ctx->acc_table.s && ctx->acc_table.len) { + if (table->len > ctx->acc_table.len) { + ctx->acc_table.s = shm_realloc(ctx->acc_table.s, table->len * sizeof(char)); + if (ctx->acc_table.s == NULL) + goto memerr; + } + } else { + ctx->acc_table.s = shm_malloc(table->len * sizeof(char)); + if (ctx->acc_table.s == NULL) + goto memerr; + } + + memcpy(ctx->acc_table.s, table->s, table->len); + ctx->acc_table.len = table->len; + + return 0; + +memerr: + LM_ERR("no more shm!\n"); + return -1; +} + +int init_acc_ctx(acc_ctx_t** ctx_p) +{ + acc_ctx_t* ctx; + + if (ctx_p == NULL) { + LM_ERR("bad usage!\n"); + return -1; + } + + ctx=shm_malloc(sizeof(acc_ctx_t)); + if (ctx == NULL) { + LM_ERR("no more shm!\n"); + return -1; + } + memset(ctx, 0, sizeof(acc_ctx_t)); + lock_init(&ctx->lock); + + /* init extra s array */ + if (extra_tags != NULL && + build_acc_extra_array(extra_tags, extra_tgs_len, + &ctx->extra_values) < 0) { + LM_ERR("failed to build extra values array!\n"); + return -1; + } + + + if (leg_tags != NULL && expand_legs(ctx) < 0) { + LM_ERR("failed to build extra values array!\n"); + return -1; + } + + *ctx_p = ctx; + return 0; + +} int w_do_acc_1(struct sip_msg* msg, char* type) @@ -1051,7 +1306,9 @@ int w_do_acc_2(struct sip_msg* msg, char* type, char* flags) int w_do_acc_3(struct sip_msg* msg, char* type_p, char* flags_p, char* table_p) { unsigned long long type=0, flags=0; - unsigned long long *flag_mask_p, flag_mask; + unsigned long long flag_mask; + + acc_ctx_t* acc_ctx; acc_type_param_t* acc_param; @@ -1061,8 +1318,6 @@ int w_do_acc_3(struct sip_msg* msg, char* type_p, char* flags_p, char* table_p) int tmcb_types; int is_invite; - int_str _avp_created_value; - if (type_p == NULL) { LM_ERR("accounting type is mandatory!\n"); return -1; @@ -1083,6 +1338,13 @@ int w_do_acc_3(struct sip_msg* msg, char* type_p, char* flags_p, char* table_p) } } + if (table_p != NULL) { + if (fixup_get_svalue(msg, (gparam_p)table_p, &table_name) < 0) { + LM_ERR("failed to fetch table name!\n"); + return -1; + } + } + if (flags_p != NULL) { flags= *(unsigned long long*)flags_p; } @@ -1094,22 +1356,36 @@ int w_do_acc_3(struct sip_msg* msg, char* type_p, char* flags_p, char* table_p) set_cdr_values_registered(flag_mask); } - /* is it the first time when the function was called ? */ - if ((flag_mask_p=try_fetch_flags()) != NULL) { - /* no the first time ; check now if CDRs are requested now - * for the first time */ - if (!cdr_values_registered(*flag_mask_p) && + acc_ctx = try_fetch_ctx(); + + /* we go in here only if do_accounting function was called before; + * if accounting context is null or it's created but flags value is + * 0(meaning that context was created from somewhere else but do_accounting + * wasn't called) then we need to jump over this and register + * all the callbacks we need */ + if (acc_ctx != NULL && acc_ctx->flags != 0) { + /* do_accounting already called once */ + /* first check if the accounting table changed */ + if (is_db_acc_on(flag_mask) && + (table_p != NULL || + (acc_ctx->acc_table.s==NULL && acc_ctx->acc_table.len == 0))) { + if (table_p == NULL) { + table_name = db_table_acc; + } + + if (store_acc_table( acc_ctx, &table_name) < 0) { + LM_ERR("failed to store acc table!\n"); + return -1; + } + } + + if (!cdr_values_registered(acc_ctx->flags) && cdr_values_registered(flag_mask)) { /* CDR support requested for the first time, we need to create * the dialog support, if an initial INVITE */ if (!has_totag(msg)) { - _avp_created_value.n = time(NULL); - - if ( add_avp(0, acc_created_avp_id, _avp_created_value) != 0) { - LM_ERR("failed to add created avp value!\n"); - return -1; - } + acc_ctx->created = time(NULL); if (msg->REQ_METHOD == METHOD_INVITE && create_acc_dlg(msg) < 0) { LM_ERR("cannot use dialog accounting module\n"); @@ -1118,17 +1394,28 @@ int w_do_acc_3(struct sip_msg* msg, char* type_p, char* flags_p, char* table_p) } } - *flag_mask_p |= flag_mask; + acc_ctx->flags |= flag_mask; return 1; } - /* setting accouting for the first time, allocate the flags holder */ - flag_mask_p=shm_malloc(sizeof(unsigned long long)); - if (flag_mask_p==NULL) { - LM_ERR("No more shm mem!\n"); + /* initialize accounting context if not created before */ + if (acc_ctx == NULL && init_acc_ctx(&acc_ctx) < 0) { + LM_ERR("failed to create accounting context!\n"); return -1; } + /* move acc table in context if we have database accounting */ + if (is_db_acc_on(flag_mask)) { + if (table_p == NULL) { + table_name = db_table_acc; + } + + if (store_acc_table( acc_ctx, &table_name) < 0) { + LM_ERR("failed to store acc table!\n"); + return -1; + } + } + /* * the first bit in each byte will just tell that we want that type of @@ -1137,19 +1424,14 @@ int w_do_acc_3(struct sip_msg* msg, char* type_p, char* flags_p, char* table_p) * so we keep the first bits in each byte and on the following positions * next flags */ - *flag_mask_p = flag_mask; - ACC_PUT_FLAGS(flag_mask_p); - - if (table_p != NULL) { - if (fixup_get_svalue(msg, (gparam_p)table_p, &table_name) < 0) { - LM_ERR("failed to fetch table name!\n"); - return -1; - } - } + acc_ctx->flags = flag_mask; + /* make sure that context won't be freed by GLOBAL_CONTEXT free function */ + acc_ctx->flags |= ACC_PROCESSING_CTX_NO_FREE; + ACC_PUT_CTX(acc_ctx); if ( msg && !skip_cancel(msg) && - (is_acc_on(*flag_mask_p) || is_mc_acc_on(*flag_mask_p)) ) { + (is_acc_on(acc_ctx->flags) || is_mc_acc_on(acc_ctx->flags)) ) { /* do some parsing in advance */ if (acc_preparse_req(msg)<0) return -1; @@ -1162,16 +1444,11 @@ int w_do_acc_3(struct sip_msg* msg, char* type_p, char* flags_p, char* table_p) * get incoming replies ready for processing */ /* TMCB_RESPONSE_OUT | */ /* report on missed calls */ - ((is_invite && is_mc_acc_on(*flag_mask_p))?TMCB_ON_FAILURE:0) ; + ((is_invite && is_mc_acc_on(acc_ctx->flags))?TMCB_ON_FAILURE:0) ; /* if cdr accounting is enabled */ - if (is_cdr_acc_on(*flag_mask_p) && !has_totag(msg)) { - _avp_created_value.n = time(NULL); - - if ( add_avp(0, acc_created_avp_id, _avp_created_value) != 0) { - LM_ERR("failed to add created avp value!\n"); - return -1; - } + if (is_cdr_acc_on(acc_ctx->flags) && !has_totag(msg)) { + acc_ctx->created = time(NULL); if (is_invite && create_acc_dlg(msg) < 0) { LM_ERR("cannot use dialog accounting module\n"); @@ -1179,16 +1456,16 @@ int w_do_acc_3(struct sip_msg* msg, char* type_p, char* flags_p, char* table_p) } } - /* we do register_tmcb twice because we wan't to register the free - * fucntion only once */ + /* we do register_tmcb twice because we want to register the free + * function only once */ if (tmb.register_tmcb( msg, 0, TMCB_RESPONSE_OUT, tmcb_func, - flag_mask_p, tm_free_acc_mask)<=0) { + acc_ctx, tm_free_acc_ctx)<=0) { LM_ERR("cannot register additional callbacks\n"); return -1; } if (tmb.register_tmcb( msg, 0, tmcb_types, tmcb_func, - flag_mask_p, 0)<=0) { + acc_ctx, 0)<=0) { LM_ERR("cannot register additional callbacks\n"); return -1; } @@ -1219,14 +1496,14 @@ int w_drop_acc_2(struct sip_msg* msg, char* type_p, char* flags_p) /* if not set, we reset all flags for the type of accounting requested */ unsigned long long flags=ALL_ACC_FLAGS; unsigned long long flag_mask; - unsigned long long *context_flags_p=try_fetch_flags(); - acc_type_param_t* acc_param; + acc_ctx_t* acc_ctx=try_fetch_ctx(); + str in; - if (context_flags_p == NULL) { + if (acc_ctx == NULL) { LM_ERR("do_accounting() not used! This function resets flags in " "do_accounting()!\n"); return -1; @@ -1257,10 +1534,43 @@ int w_drop_acc_2(struct sip_msg* msg, char* type_p, char* flags_p) /* reset all flags */ if (flag_mask == 0) { - *context_flags_p = 0; + /* + * we use this flag in order make the difference between + * 0 value (do_accounting never called, callbacks never registered) and + * ACC_FLAGS_RESET (do_accounting called, callbacks registered, flag value + * changing during script execution) + */ + acc_ctx->flags = ACC_FLAGS_RESET; } else { - reset_flags(*context_flags_p, flag_mask); + reset_flags(acc_ctx->flags, flag_mask); } return 1; } + + +int w_new_leg(struct sip_msg* msg) +{ + acc_ctx_t* ctx = try_fetch_ctx(); + + if (ctx == NULL) { + if (init_acc_ctx(&ctx) < 0) { + LM_ERR("failed to create accounting context!\n"); + return -1; + } + + ACC_PUT_CTX(ctx); + } + + accX_lock(&ctx->lock); + if (expand_legs(ctx) < 0) { + LM_ERR("failed to create new leg!\n"); + accX_unlock(&ctx->lock); + return -1; + } + accX_unlock(&ctx->lock); + + return 1; + +} + diff --git a/modules/acc/acc_logic.h b/modules/acc/acc_logic.h index 1ad371a41ea..8a933dfd185 100644 --- a/modules/acc/acc_logic.h +++ b/modules/acc/acc_logic.h @@ -29,6 +29,7 @@ #define _ACC_ACC_LOGIC_H #include "../../str.h" +#include "../../context.h" #include "../tm/t_hooks.h" #include "../dialog/dlg_cb.h" @@ -36,7 +37,6 @@ #define DO_ACC_LOG (1<<(0*8)) #define DO_ACC_AAA (1<<(1*8)) #define DO_ACC_DB (1<<(2*8)) -#define DO_ACC_DIAM (1<<(3*8)) #define DO_ACC_EVI ((unsigned long long)1<<(4*8)) #define DO_ACC_ERR ((unsigned long long)-1) @@ -52,16 +52,30 @@ #define DO_ACC_LOG_STR "log" #define DO_ACC_AAA_STR "aaa" #define DO_ACC_DB_STR "db" -#define DO_ACC_DIAM_STR "diam" #define DO_ACC_EVI_STR "evi" #define DO_ACC_CDR_STR "cdr" #define DO_ACC_MISSED_STR "missed" #define DO_ACC_FAILED_STR "failed" -/* flags on the eigth byte - generic flags for all accounting types */ +/* flags on the seventh byte - generic flags for all accounting types */ +/* this flag signals to the transaction that the context was moved + * into dialog and shall be freed from there; tm should never free it */ #define ACC_DIALOG_CONTEXT (((unsigned long long)1<<(8*6)) * (1<<0)) +/* if cdr engine is used then we have some extra work to do in + * do_accounting function, and we need to do this only once; since + * it is not necessary that the user + * sets the cdr flag from first do_accounting call, we need to know + * when cdr engine is activated */ #define ACC_CDR_REGISTERED (((unsigned long long)1<<(8*6)) * (1<<1)) +/* flag to signal the processing context no to free the accounting context + * the accounting context shall be freed by upper layers(TM, DIALOG) */ +#define ACC_PROCESSING_CTX_NO_FREE (((unsigned long long)1<<(8*6)) * (1<<2)) +/* flag to help make the difference between context created, but do_accounting + * never called(flags value is 0) and do_accounting called, but value of the + * flags changed using drop_accounting meaning that all callbacks are + * registered and we don't have to register them twice */ +#define ACC_FLAGS_RESET (((unsigned long long)1<<(8*6)) * (1<<3)) /* * this flag will help to know if we entered at least once * in the dialog callbacks @@ -70,7 +84,8 @@ * dialog callbacks and value 0 in the 8th byte(ref count) * is valid */ -#define ACC_DLG_CB_USED (((unsigned long long)1<<(8*6)) * (1<<2)) +#define ACC_DLG_CB_USED (((unsigned long long)1<<(8*6)) * (1<<4)) + #define ACC_MASK_REF_BYTE (((unsigned long long)(0xFF)<<(8*7)) @@ -91,6 +106,23 @@ #define ACC_PUT_TM_FLAGS(_t, _ptr) \ tmb.t_ctx_put_ptr(_t, acc_tm_flags_ctx_idx, _ptr) +#define ACC_GET_CTX \ + (acc_ctx_t *)context_get_ptr(CONTEXT_GLOBAL, current_processing_ctx, \ + acc_flags_ctx_idx) + +#define ACC_PUT_CTX(_ptr) \ + context_put_ptr(CONTEXT_GLOBAL, current_processing_ctx, \ + acc_flags_ctx_idx, _ptr) + +#define ACC_GET_TM_CTX(_t) \ + (acc_ctx_t *)tmb.t_ctx_get_ptr(_t, acc_tm_flags_ctx_idx) + +#define ACC_PUT_TM_CTX(_t, _ptr) \ + tmb.t_ctx_put_ptr(_t, acc_tm_flags_ctx_idx, _ptr) + + +#define LEG_MATRIX_ALLOC_FACTOR 2 + typedef unsigned long long (*do_acc_parser)(str*); @@ -120,6 +152,32 @@ struct acc_param { str reason; }; +typedef struct extra_value { + int shm_buf_len; + str value; +} extra_value_t, leg_value_t, *leg_value_p; + +typedef struct acc_ctx { + gen_lock_t lock; + + /* array of values; will have the same length as tags array */ + extra_value_t* extra_values; + + unsigned short allocated_legs; + unsigned short legs_no; + /* leg matrix; each line of the matrix will hold the values + * corresponding to a certain leg */ + leg_value_p* leg_values; + + unsigned long long flags; + + str acc_table; + time_t created; + struct timeval bye_time; +} acc_ctx_t; + + +int init_acc_ctx(acc_ctx_t** ctx_p); int w_acc_log_request(struct sip_msg *rq, pv_elem_t* comment, char *foo); @@ -132,10 +190,6 @@ int acc_pvel_to_acc_param(struct sip_msg *rq, pv_elem_t* pv_el, struct acc_param void acc_loaded_callback(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params); -#ifdef DIAM_ACC -int w_acc_diam_request(struct sip_msg *rq, char *comment, char *foo); -#endif - int w_acc_evi_request(struct sip_msg *rq, pv_elem_t* comment, char *foo); @@ -150,4 +204,14 @@ int w_drop_acc_0(struct sip_msg* msg); int w_drop_acc_1(struct sip_msg* msg, char* type); int w_drop_acc_2(struct sip_msg* msg, char* type, char* flags); +int w_new_leg(struct sip_msg* msg); + +/* + * helper function to retrieve acc context from processing context or + * transaction context + */ +acc_ctx_t* try_fetch_ctx(void); +void free_global_acc_ctx(acc_ctx_t* ctx); +void free_processing_acc_ctx(void* param); + #endif diff --git a/modules/acc/acc_mod.c b/modules/acc/acc_mod.c index 8404fc53cf7..e9868831a9a 100644 --- a/modules/acc/acc_mod.c +++ b/modules/acc/acc_mod.c @@ -54,15 +54,11 @@ #include "../../aaa/aaa.h" #include "../dialog/dlg_load.h" -#ifdef DIAM_ACC -#include "diam_dict.h" -#include "diam_tcp.h" -#endif - #include "acc.h" #include "acc_mod.h" #include "acc_extra.h" #include "acc_logic.h" +#include "acc_vars.h" struct dlg_binds dlg_api; struct tm_binds tmb; @@ -74,6 +70,12 @@ static int child_init(int rank); /* ----- General purpose variables ----------- */ +/* array of extra parameter tags */ +int extra_tgs_len=0; +tag_t* extra_tags=0; +/* array of leg parameter tags */ +int leg_tgs_len=0; +tag_t* leg_tags=0; /* what would you like to report on */ /* should early media replies (183) be logged ? default==no */ @@ -82,12 +84,6 @@ int early_media = 0; int report_cancels = 0; /* detect and correct direction in the sequential requests */ int detect_direction = 0; -/* should failed replies (>=3xx) be logged ? default==no */ -/* multi call-leg support */ -static char* leg_info_str = 0; -static char* leg_bye_info_str = 0; -struct acc_extra *leg_info = 0; -struct acc_extra *leg_bye_info = 0; /* ----- SYSLOG acc variables ----------- */ @@ -97,10 +93,8 @@ int acc_log_level = L_NOTICE; int acc_log_facility = LOG_DAEMON; static char * log_facility_str = 0; /* log extra variables */ -static char *log_extra_str = 0; -struct acc_extra *log_extra = 0; -static char *log_extra_bye_str = 0; -struct acc_extra *log_extra_bye = 0; +struct acc_extra *log_extra_tags = 0; +struct acc_extra *log_leg_tags = 0; /* ----- AAA PROTOCOL acc variables ----------- */ @@ -111,30 +105,14 @@ aaa_conn *conn; /* aaa extra variables */ -static char *aaa_extra_str = 0; -struct acc_extra *aaa_extra = 0; -static char *aaa_extra_bye_str = 0; -struct acc_extra *aaa_extra_bye = 0; - -/* ----- DIAMETER acc variables ----------- */ - -#ifdef DIAM_ACC -/* diameter extra variables */ -static char *dia_extra_str = 0; -struct acc_extra *dia_extra = 0; -/* buffer used to read from TCP connection*/ -rd_buf_t *rb; -char* diameter_client_host="localhost"; -int diameter_client_port=3000; -#endif - +struct acc_extra *aaa_extra_tags = 0; +struct acc_extra *aaa_leg_tags = 0; /* ----- SQL acc variables ----------- */ /* db extra variables */ -static char *db_extra_str = 0; -struct acc_extra *db_extra = 0; -static char *db_extra_bye_str = 0; -struct acc_extra *db_extra_bye = 0; +struct acc_extra *db_extra_tags = 0; +struct acc_extra *db_leg_tags = 0; + /* Database url */ static str db_url = {NULL, 0}; /* name of database tables */ @@ -158,10 +136,8 @@ str acc_created_col = str_init("created"); /* ----- Event Interface acc variables ----------- */ /* event extra variables */ -static char *evi_extra_str = 0; -struct acc_extra *evi_extra = 0; -static char *evi_extra_bye_str = 0; -struct acc_extra *evi_extra_bye = 0; +struct acc_extra *evi_extra_tags = 0; +struct acc_extra *evi_leg_tags = 0; /* db avp variables */ str acc_created_avp_name = str_init("accX_created"); @@ -176,6 +152,21 @@ static int acc_fixup(void** param, int param_no); static int free_acc_fixup(void** param, int param_no); +/** + * pseudo-variables exported by acc module + */ +static pv_export_t mod_items[] = { + { {"acc_extra", sizeof("acc_extra") - 1}, 2001, pv_get_acc_extra, + pv_set_acc_extra, pv_parse_acc_extra_name, + 0 /* parse index(won't use here) */, 0, 0}, + { {"acc_leg", sizeof("acc_leg") - 1}, 2002, pv_get_acc_leg, + pv_set_acc_leg, pv_parse_acc_leg_name, + pv_parse_acc_leg_index, 0, 0}, + { {"acc_current_leg", sizeof("acc_current_leg") - 1}, 2003, + pv_get_acc_current_leg, 0, 0, 0, 0, 0}, + { {0, 0}, 0, 0, 0, 0, 0, 0, 0 } +}; + static cmd_export_t cmds[] = { {"acc_log_request", (cmd_function)w_acc_log_request, 1, acc_fixup, free_acc_fixup, @@ -186,11 +177,6 @@ static cmd_export_t cmds[] = { {"acc_aaa_request", (cmd_function)w_acc_aaa_request, 1, acc_fixup, free_acc_fixup, REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, -#ifdef DIAM_ACC - {"acc_diam_request",(cmd_function)w_acc_diam_request,1, - acc_fixup, free_acc_fixup, - REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, -#endif {"acc_evi_request", (cmd_function)w_acc_evi_request, 1, acc_fixup, free_acc_fixup, REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, @@ -224,6 +210,9 @@ static cmd_export_t cmds[] = { do_acc_fixup, NULL, REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, + {"acc_new_leg", (cmd_function)w_new_leg, 0, 0, 0, + REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, + {0, 0, 0, 0, 0, 0} }; @@ -232,32 +221,19 @@ static cmd_export_t cmds[] = { static param_export_t params[] = { {"early_media", INT_PARAM, &early_media }, {"report_cancels", INT_PARAM, &report_cancels }, - {"multi_leg_info", STR_PARAM, &leg_info_str }, - {"multi_leg_bye_info", STR_PARAM, &leg_bye_info_str }, {"detect_direction", INT_PARAM, &detect_direction }, /* syslog specific */ {"log_level", INT_PARAM, &acc_log_level }, {"log_facility", STR_PARAM, &log_facility_str }, - {"log_extra", STR_PARAM, &log_extra_str }, - {"log_extra_bye", STR_PARAM, &log_extra_bye_str }, /* aaa specific */ {"aaa_url", STR_PARAM, &aaa_proto_url }, {"service_type", INT_PARAM, &service_type }, - {"aaa_extra", STR_PARAM, &aaa_extra_str }, - {"aaa_extra_bye", STR_PARAM, &aaa_extra_bye_str }, /* event interface specific */ - {"evi_extra", STR_PARAM, &evi_extra_str }, - {"evi_extra_bye", STR_PARAM, &evi_extra_bye_str }, - - /* DIAMETER specific */ -#ifdef DIAM_ACC - {"diameter_client_host", STR_PARAM, &diameter_client_host }, - {"diameter_client_port", INT_PARAM, &diameter_client_port }, - {"diameter_extra", STR_PARAM, &dia_extra_str }, -#endif + + {"extra_fields", STR_PARAM|USE_FUNC_PARAM, parse_acc_extra}, + {"leg_fields", STR_PARAM|USE_FUNC_PARAM, parse_acc_leg}, + /* db-specific */ - {"db_extra", STR_PARAM, &db_extra_str }, - {"db_extra_bye", STR_PARAM, &db_extra_bye_str }, {"db_url", STR_PARAM, &db_url.s }, {"db_table_acc", STR_PARAM, &db_table_acc.s }, {"db_table_missed_calls",STR_PARAM, &db_table_mc.s }, @@ -315,7 +291,7 @@ struct module_exports exports= { params, /* exported params */ 0, /* exported statistics */ 0, /* exported MI functions */ - 0, /* exported pseudo-variables */ + mod_items, /* exported pseudo-variables */ 0, /* extra processes */ mod_init, /* initialization module */ 0, /* response function */ @@ -430,65 +406,20 @@ static int mod_init( void ) /* 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 multi_leg_info param\n"); - return -1; - } - if (leg_bye_info_str && (leg_bye_info=parse_acc_leg(leg_bye_info_str))==0 ) { - LM_ERR("failed to parse multi_leg_bye_info param\n"); - return -1; - } - /* ----------- SYSLOG INIT SECTION ----------- */ - - /* parse the extra string, if any */ - if (log_extra_str && (log_extra=parse_acc_extra(log_extra_str, 1))==0 ) { - LM_ERR("failed to parse log_extra param\n"); - return -1; - } - if (log_extra_bye_str && - (log_extra_bye=parse_acc_extra(log_extra_bye_str, 0))==0 ) { - LM_ERR("failed to parse log_extra_bye param\n"); - return -1; - } - acc_log_init(); - /* ------------ SQL INIT SECTION ----------- */ - + /* ----------- DATABASE INIT SECTION ----------- */ if (db_url.s) { - /* parse the extra string, if any */ - if (db_extra_str && (db_extra=parse_acc_extra(db_extra_str, 1))==0 ) { - LM_ERR("failed to parse db_extra param\n"); - return -1; - } - if (db_extra_bye_str && - (db_extra_bye=parse_acc_extra(db_extra_bye_str, 0))==0 ) { - LM_ERR("failed to parse db_extra_bye param\n"); - return -1; - } - if (acc_db_init(&db_url)<0){ LM_ERR("failed! bad db url / missing db module ?\n"); return -1; } } - /* ------------ AAA PROTOCOL INIT SECTION ----------- */ + /* ------------ AAA PROTOCOL INIT SECTION ----------- */ if (aaa_proto_url && aaa_proto_url[0]) { - /* parse the extra string, if any */ - if (aaa_extra_str && (aaa_extra = parse_acc_extra(aaa_extra_str, 1))==0) { - LM_ERR("failed to parse aaa_extra param\n"); - return -1; - } - if (aaa_extra_bye_str && - (aaa_extra_bye = parse_acc_extra(aaa_extra_bye_str, 0))==0) { - LM_ERR("failed to parse aaa_extra_bye param\n"); - return -1; - } - if (init_acc_aaa(aaa_proto_url, service_type)!=0 ) { LM_ERR("failed to init radius\n"); return -1; @@ -497,40 +428,14 @@ static int mod_init( void ) aaa_proto_url = NULL; } - /* ------------ DIAMETER INIT SECTION ----------- */ - -#ifdef DIAM_ACC - /* parse the extra string, if any */ - if (dia_extra_str && (dia_extra=parse_acc_extra(dia_extra_str))==0 ) { - LM_ERR("failed to parse dia_extra param\n"); - return -1; - } - - if (acc_diam_init()!=0) { - LM_ERR("failed to init diameter engine\n"); - return -1; - } - -#endif /* ----------- EVENT INTERFACE INIT SECTION ----------- */ - - if (evi_extra_str && (evi_extra = parse_acc_extra(evi_extra_str, 1))==0) { - LM_ERR("failed to parse evi_extra param\n"); - return -1; - } - if (evi_extra_bye_str && - (evi_extra_bye = parse_acc_extra(evi_extra_bye_str, 0))==0) { - LM_ERR("failed to parse evi_extra_bye param\n"); - return -1; - } - if (init_acc_evi() < 0) { LM_ERR("cannot init acc events\n"); return -1; } - acc_flags_ctx_idx = context_register_ptr(CONTEXT_GLOBAL, NULL); + acc_flags_ctx_idx = context_register_ptr(CONTEXT_GLOBAL, free_processing_acc_ctx); acc_tm_flags_ctx_idx = tmb.t_ctx_register_ptr(NULL); return 0; @@ -544,56 +449,30 @@ static int child_init(int rank) return -1; } - /* DIAMETER */ -#ifdef DIAM_ACC - /* open TCP connection */ - LM_DBG("initializing TCP connection\n"); - - sockfd = init_mytcp(diameter_client_host, diameter_client_port); - if(sockfd==-1) - { - LM_ERR("TCP connection not established\n"); - return -1; - } - - LM_DBG("a TCP connection was established on sockfd=%d\n", sockfd); - - /* every child with its buffer */ - rb = (rd_buf_t*)pkg_malloc(sizeof(rd_buf_t)); - if(!rb) - { - LM_DBG("no more pkg memory\n"); - return -1; - } - rb->buf = 0; - -#endif - return 0; } static void destroy(void) { - if (log_extra) - destroy_extras( log_extra); - if (log_extra_bye) - destroy_extras( log_extra_bye); + if (log_extra_tags) + destroy_extras( log_extra_tags); + if (log_leg_tags) + destroy_extras( log_leg_tags); acc_db_close(); - if (db_extra) - destroy_extras( db_extra); - if (db_extra_bye) - destroy_extras( db_extra_bye); - - if (aaa_extra) - destroy_extras( aaa_extra); - if (aaa_extra_bye) - destroy_extras( aaa_extra_bye); - -#ifdef DIAM_ACC - close_tcp_connection(sockfd); - if (dia_extra) - destroy_extras( dia_extra); -#endif + if (db_extra_tags) + destroy_extras( db_extra_tags); + if (db_leg_tags) + destroy_extras( db_leg_tags); + + if (aaa_extra_tags) + destroy_extras( aaa_extra_tags); + if (aaa_leg_tags) + destroy_extras( aaa_leg_tags); + + if (evi_extra_tags) + destroy_extras( evi_extra_tags); + if (evi_leg_tags) + destroy_extras( evi_leg_tags); } diff --git a/modules/acc/acc_mod.h b/modules/acc/acc_mod.h index 474101a682f..40d64a146b0 100644 --- a/modules/acc/acc_mod.h +++ b/modules/acc/acc_mod.h @@ -51,13 +51,6 @@ extern char* aaa_proto_url; extern int cdr_flag; -#ifdef DIAM_ACC -#include "diam_tcp.h" -extern rd_buf_t *rb; -extern int diameter_flag; -extern int diameter_missed_flag; -#endif - extern int db_flag; extern int db_missed_flag; @@ -86,5 +79,4 @@ extern unsigned short db_table_name_type; extern int evi_flag; extern int evi_missed_flag; - #endif diff --git a/modules/acc/acc_vars.c b/modules/acc/acc_vars.c new file mode 100644 index 00000000000..2a8e163008f --- /dev/null +++ b/modules/acc/acc_vars.c @@ -0,0 +1,509 @@ +/** + * Fraud Detection Module + * + * Copyright (C) 2016 OpenSIPS Foundation + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + * + * History + * ------- + * 2016-06-23 initial version (Ionut Ionita) +*/ +#include +#include + +#include "../../sr_module.h" +#include "../../dprint.h" +#include "../../mem/mem.h" +#include "../../ut.h" +#include "acc_extra.h" +#include "acc_logic.h" + +#define GET_EXTRA_VALUE_SAFE(val_ptr, extra) \ + do { \ + *val_ptr = extra->value; \ + } while(0); + +extern int extra_tgs_len; +extern tag_t* extra_tags; + +extern int leg_tgs_len; +extern tag_t* leg_tags; + +extern int acc_flags_ctx_idx; + +/* + * acc_extra + * VARIABLE + * ***********************/ + +/* + * parse $acc_extra variable name + */ +int pv_parse_acc_extra_name(pv_spec_p sp, str *in) +{ + int idx; + + if (sp == NULL || in == NULL || in->s == NULL || in->len == 0) { + LM_ERR("bad name!\n"); + return -1; + } + + str_trim_spaces_lr(*in); + + for (idx=0; idxlen == extra_tags[idx].len && + !memcmp(in->s, extra_tags[idx].s, extra_tags[idx].len)) { + sp->pvp.pvn.u.isname.name.n = idx; + return 0; + } + } + + LM_ERR("tag <%.*s> not declared in modparam section!\n", in->len, in->s); + + return -1; +} + + +/* + * getter function for $acc_extra + */ +int pv_get_acc_extra(struct sip_msg *msg, pv_param_t *param, + pv_value_t *val) +{ + int tag_idx; + + acc_ctx_t* ctx=try_fetch_ctx(); + + if (param == NULL || val == NULL) { + LM_ERR("bad input params!\n"); + return -1; + } + + if (ctx == NULL) { + /* if we don't have a context then create it */ + if (init_acc_ctx(&ctx) < 0) { + LM_ERR("failed to create accounting context!\n"); + return -1; + } + + ACC_PUT_CTX(ctx); + } + + tag_idx = param->pvn.u.isname.name.n; + /* sanity checks for the tag; it should be valid since + * we found it in the parse name function */ + if (tag_idx < 0 || tag_idx >= extra_tgs_len) { + LM_BUG("invalid tag value! probably a memory corruption issue!\n"); + return -1; + } + + + accX_lock(&ctx->lock); + if (ctx->extra_values[tag_idx].value.s == NULL) { + val->flags = PV_VAL_NULL; + } else { + val->rs = ctx->extra_values[tag_idx].value; + val->flags = PV_VAL_STR; + } + accX_unlock(&ctx->lock); + + return 0; +} + + +/* + * set pv_value_t in pkg to pv_value_t from extra in shm + * + * * if it's an integer then convert it to string and set the string value + * to the shm pv_value_t + * * if it's a string then try converting it to it + */ +int set_value_shm(pv_value_t* pvt, extra_value_t* extra) +{ + if (pvt->flags&PV_TYPE_INT || pvt->flags&PV_VAL_STR) { + if (pvt->flags&PV_TYPE_INT || pvt->flags&PV_VAL_INT) { + /* transform the int value into a string */ + pvt->rs.s = int2str(pvt->ri, &pvt->rs.len); + pvt->flags |= PV_VAL_STR; + } else { /* it's PV_VAL_STR; check whether it is an integer value */ + if (str2sint(&pvt->rs, &pvt->ri) == 0) { + pvt->flags |= PV_TYPE_INT|PV_VAL_INT; + } + } + + if (extra->shm_buf_len == 0) { + extra->value.s = shm_malloc(pvt->rs.len); + extra->shm_buf_len = extra->value.len = pvt->rs.len; + } else if (extra->shm_buf_len < pvt->rs.len) { + extra->value.s = shm_realloc(extra->value.s, pvt->rs.len); + extra->shm_buf_len = extra->value.len = pvt->rs.len; + } else { + extra->value.len = pvt->rs.len; + } + + if (extra->value.s == NULL) + goto memerr; + + memcpy(extra->value.s, pvt->rs.s, pvt->rs.len); + } else if (pvt->flags&PV_VAL_NULL) { + if (extra->shm_buf_len) { + shm_free(extra->value.s); + extra->shm_buf_len = 0; + } + extra->value.s = NULL; + extra->value.len = 0; + } else { + LM_ERR("invalid pvt value!\n"); + return -1; + } + + return 0; + +memerr: + LM_ERR("No more shm!\n"); + return -1; +} + +/* + * setter function for $acc_extra + */ +int pv_set_acc_extra(struct sip_msg *msg, pv_param_t *param, int op, + pv_value_t *val) +{ + int tag_idx; + + acc_ctx_t* ctx=try_fetch_ctx(); + + if (param == NULL || val == NULL) { + LM_ERR("bad params!\n"); + } + + if (ctx == NULL) { + /* if we don't have a context then create it */ + if (init_acc_ctx(&ctx) < 0) { + LM_ERR("failed to create accounting context!\n"); + return -1; + } + + ACC_PUT_CTX(ctx); + } + + + tag_idx = param->pvn.u.isname.name.n; + /* sanity checks for the tag; it should be valid since + * we found it in the parse name function */ + if (tag_idx < 0 || tag_idx >= extra_tgs_len) { + LM_BUG("invalid tag value! probably a memory corruption issue!\n"); + return -1; + } + + + /* go through all extras and fetch first value you find + * all the extras with the same tag will have the same + * value */ + accX_lock(&ctx->lock); + if (set_value_shm(val, &ctx->extra_values[tag_idx]) < 0) { + LM_ERR("failed to set extra <%.*s> value!\n", + extra_tags[tag_idx].len, extra_tags[tag_idx].s); + accX_unlock(&ctx->lock); + return -1; + } + accX_unlock(&ctx->lock); + + return 0; +} + +/* + * acc_current_leg + * VARIABLE + * ***********************/ + +int pv_get_acc_current_leg(struct sip_msg *msg, pv_param_t *param, + pv_value_t *val) +{ + acc_ctx_t* ctx=try_fetch_ctx(); + + if (ctx == NULL) { + /* if we don't have a context then create it */ + if (init_acc_ctx(&ctx) < 0) { + LM_ERR("failed to create accounting context!\n"); + return -1; + } + + ACC_PUT_CTX(ctx); + } + + if (ctx->leg_values == NULL) { + LM_ERR("no legs defined!\n"); + return -1; + } + + accX_lock(&ctx->lock); + val->ri = ctx->legs_no - 1; + val->rs.s = int2str(ctx->legs_no - 1, &val->rs.len); + accX_unlock(&ctx->lock); + + val->flags = PV_VAL_INT | PV_VAL_STR | PV_TYPE_INT; + + return 0; +} + +/* + * acc_leg + * VARIABLE + * ***********************/ + +int pv_parse_acc_leg_index(pv_spec_p sp, str* in) +{ + int idx; + pv_spec_p e; + + if (in == NULL || in->s == NULL || in->len == 0) { + LM_ERR("bad index!\n"); + return -1; + } + + if (sp == NULL) { + LM_ERR("bad pv spec!\n"); + return -1; + } + + str_trim_spaces_lr(*in); + + if (in->s[0] == PV_MARKER) { + e=pkg_malloc(sizeof(pv_spec_t)); + if (e==NULL) { + LM_ERR("no more pkg mem!\n"); + return -1; + } + memset(e, 0, sizeof(pv_spec_t)); + + if (pv_parse_spec(in, e) == NULL) { + LM_ERR("failed to parse index variable!\n"); + pv_spec_free(e); + return -1; + } + + sp->pvp.pvi.type = PV_IDX_PVAR; + sp->pvp.pvi.u.dval = (void *)e; + } else { + if (str2sint(in, &idx) < 0) { + LM_ERR("bad index! not a number! <%.*s>!\n", in->len, in->s); + return -1; + } + + sp->pvp.pvi.type = PV_IDX_INT; + sp->pvp.pvi.u.ival = idx; + } + + return 0; +} + +/* +* parse $acc_leg variable name +*/ +int pv_parse_acc_leg_name(pv_spec_p sp, str *in) +{ + int idx; + + if (sp == NULL || in == NULL || in->s == NULL || in->len == 0) { + LM_ERR("bad name!\n"); + return -1; + } + + str_trim_spaces_lr(*in); + + for (idx=0; idxlen == leg_tags[idx].len && + !memcmp(in->s, leg_tags[idx].s, leg_tags[idx].len)) { + sp->pvp.pvn.u.isname.name.n = idx; + return 0; + } + } + + LM_ERR("tag <%.*s> not declared in modparam section!\n", in->len, in->s); + + return -1; +} + + +int pv_get_acc_leg(struct sip_msg *msg, pv_param_t *param, + pv_value_t *val) +{ + int tag_idx, leg_idx; + acc_ctx_t* ctx = try_fetch_ctx(); + + pv_value_t idx_value; + + if (ctx == NULL) { + /* if we don't have a context then create it */ + if (init_acc_ctx(&ctx) < 0) { + LM_ERR("failed to create accounting context!\n"); + return -1; + } + + ACC_PUT_CTX(ctx); + } + + if (ctx->leg_values == NULL) { + LM_ERR("no legs defined!\n"); + return -1; + } + + tag_idx = param->pvn.u.isname.name.n; + + if (param->pvi.type == PV_IDX_PVAR) { + if (pv_get_spec_value(msg, param->pvi.u.dval, &idx_value) < 0) { + LM_ERR("failed to fetch index value!\n"); + return -1; + } + + if (idx_value.flags&PV_VAL_INT) { + leg_idx = idx_value.ri; + } else if (idx_value.flags&PV_VAL_STR) { + if (str2sint(&idx_value.rs, &leg_idx) < 0) { + goto invalid_leg; + } + } else { + goto invalid_leg; + } + + } else if (param->pvi.type == PV_IDX_INT) { + leg_idx = param->pvi.u.ival; + } else { + /* if not provided consider the value of the last leg */ + leg_idx = ctx->legs_no - 1; + } + + if (leg_idx >= ctx->legs_no) { + LM_ERR("there aren't that many legs!\n"); + return -1; + } + + if (leg_idx < 0) { + if (ctx->legs_no + leg_idx < -1) { + LM_ERR("invalid leg index %d!\n", leg_idx); + return -1; + } + + /* -1 will be the last element and so on */ + leg_idx += (ctx->legs_no + 1); + } + + val->flags = PV_VAL_STR; + + accX_lock(&ctx->lock); + if (ctx->leg_values[leg_idx][tag_idx].value.s == NULL) { + val->flags = PV_VAL_NULL; + } else { + val->rs = ctx->leg_values[leg_idx][tag_idx].value; + } + accX_unlock(&ctx->lock); + + return 0; + +invalid_leg: + LM_ERR("cannot fetch leg index value!\n"); + return -1; +} + +/* + * + * + */ +int pv_set_acc_leg(struct sip_msg *msg, pv_param_t *param, int flag, + pv_value_t *val) +{ + int tag_idx, leg_idx; + acc_ctx_t* ctx = try_fetch_ctx(); + + pv_value_t idx_value; + + if (ctx == NULL) { + /* if we don't have a context then create it */ + if (init_acc_ctx(&ctx) < 0) { + LM_ERR("failed to create accounting context!\n"); + return -1; + } + + ACC_PUT_CTX(ctx); + } + + if (ctx->leg_values == NULL) { + LM_ERR("no legs defined!\n"); + return -1; + } + + tag_idx = param->pvn.u.isname.name.n; + + if (param->pvi.type == PV_IDX_PVAR) { + if (pv_get_spec_value(msg, param->pvi.u.dval, &idx_value) < 0) { + LM_ERR("failed to fetch index value!\n"); + return -1; + } + + if (idx_value.flags&PV_VAL_INT) { + leg_idx = idx_value.ri; + } else if (idx_value.flags&PV_VAL_STR) { + if (str2sint(&idx_value.rs, &leg_idx) < 0) { + goto invalid_leg; + } + } else { + goto invalid_leg; + } + + } else if(param->pvi.type == PV_IDX_INT) { + leg_idx = param->pvi.u.ival; + } else { + /* if not provided consider the value of the last leg */ + leg_idx = ctx->legs_no - 1; + } + + if (leg_idx >= (int)ctx->legs_no) { + LM_ERR("there aren't that many legs!\n"); + return -1; + } + + if (leg_idx < 0) { + if ((int)ctx->legs_no + leg_idx < -1) { + LM_ERR("invalid leg index %d!\n", leg_idx); + return -1; + } + + /* -1 will be the last element */ + leg_idx = (int)ctx->legs_no + leg_idx; + } + + accX_lock(&ctx->lock); + if (set_value_shm(val, &ctx->leg_values[leg_idx][tag_idx]) < 0) { + LM_ERR("failed to set leg <%.*s> value for leg number %d!\n", + extra_tags[tag_idx].len, leg_tags[tag_idx].s, leg_idx); + accX_unlock(&ctx->lock); + return -1; + } + accX_unlock(&ctx->lock); + + return 0; + +invalid_leg: + LM_ERR("cannot fetch leg index value!\n"); + return -1; +} + + + diff --git a/modules/acc/acc_vars.h b/modules/acc/acc_vars.h new file mode 100644 index 00000000000..02d9af4be50 --- /dev/null +++ b/modules/acc/acc_vars.h @@ -0,0 +1,48 @@ +/** + * + * Copyright (C) 2016 OpenSIPS Foundation + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + * + * History + * ------- + * 2016-06-23 initial version (Ionut Ionita) +*/ + +#ifndef _ACC_VARS_H +#define _ACC_VARS_H + +/* $acc_extra */ +int pv_parse_acc_extra_name(pv_spec_p sp, str *in); +int pv_get_acc_extra(struct sip_msg *msg, pv_param_t *param, + pv_value_t *val); +int pv_set_acc_extra(struct sip_msg *msg, pv_param_t *param, int flag, + pv_value_t *val); +int set_value_shm(pv_value_t* pvt, extra_value_t* values); +/* $acc_current_leg */ +int pv_get_acc_current_leg(struct sip_msg *msg, pv_param_t *param, + pv_value_t *val); +/* $acc_leg */ +int pv_parse_acc_leg_index(pv_spec_p sp, str* in); +int pv_parse_acc_leg_name(pv_spec_p sp, str *in); +int pv_get_acc_leg(struct sip_msg *msg, pv_param_t *param, + pv_value_t *val); + +int pv_set_acc_leg(struct sip_msg *msg, pv_param_t *param, int flag, + pv_value_t *val); + +#endif diff --git a/modules/acc/diam_avp.c b/modules/acc/diam_avp.c deleted file mode 100644 index 61f2b864ca7..00000000000 --- a/modules/acc/diam_avp.c +++ /dev/null @@ -1,459 +0,0 @@ -/* - * Copyright (C) 2002-2003 FhG Fokus - * - * This file is part of disc, a free diameter server/client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * 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 - * - * History: - * -------- - * 2002-10-04 created by illya (komarov@fokus.gmd.de) - * 2003-03-12 converted to shm_malloc/free (andrei) - * - */ - -#ifdef DIAM_ACC - -#include -#include -#include -#include - -#include "../../mem/shm_mem.h" -#include "../../dprint.h" -#include "diam_message.h" - - - -/* - * each AVP type has some default set/reset flags and a proper data type. - * All this default values (for flags and data-type) are correct/set by this - * function. - */ -inline void set_avp_fields( AAA_AVPCode code, AAA_AVP *avp) -{ - switch (code) { - case 1: /*AVP_User_Name*/ - case 25: /*AVP_Class*/ - case 263: /*AVP_Session_Id*/ - case 283: /*AVP_Destination_Realm*/ - case 293: /*AVP Destination Host*/ - case 264: /*AVP_Origin_Host*/ - case 296: /*AVP Origin_Realm*/ - case 400: /* AVP_Resource */ - case 401: /* AVP_Response */ - case 402: /* AVP_Chalenge */ - case 403: /* AVP_Method */ - case 404: /* Service_Type AVP */ - case 405: /* User_Group AVP*/ - case 279: - avp->flags = 0x40|(0x20&avp->flags); - avp->type = AAA_AVP_STRING_TYPE; - break; - case 27: /*AVP_Session_Timeout*/ - case 258: /*AVP_Auth_Aplication_Id*/ - case 262: /*AVP_Redirect_Max_Cache_Time*/ - case 265: /*AVP_Supported_Vendor_Id*/ - case 266: /*AVP_Vendor_Id*/ - case 268: /*AVP_Result_Code*/ - case 270: /*AVP_Session_Binding*/ - case 276: /*AVP_Auth_Grace_Period*/ - case 278: /*AVP_Origin_State_Id*/ - case 291: /*AVP_Authorization_Lifetime*/ - avp->flags = 0x40|(0x20&avp->flags); - avp->type = AAA_AVP_INTEGER32_TYPE; - break; - case 33: /*AVP_Proxy_State*/ - avp->flags = 0x40; - avp->type = AAA_AVP_STRING_TYPE; - break; - case 257: /*AVP_Host_IP_Address*/ - avp->flags = 0x40|(0x20&avp->flags); - avp->type = AAA_AVP_ADDRESS_TYPE; - break; - case 269: /*AVP_Product_Name*/ - avp->flags = 0x00; - avp->type = AAA_AVP_STRING_TYPE; - break; - case 281: /*AVP_Error_Message*/ - avp->flags = (0x20&avp->flags); - avp->type = AAA_AVP_STRING_TYPE; - break; - default: - avp->type = AAA_AVP_DATA_TYPE; - }; -} - - - -/* This function creates an AVP and returns a pointer to it; - */ -AAA_AVP* AAACreateAVP( - AAA_AVPCode code, - AAA_AVPFlag flags, - AAAVendorId vendorId, - char *data, - size_t length, - AVPDataStatus data_status) -{ - AAA_AVP *avp; - - /* first check the params */ - if( data==0 || length==0) { - LM_ERR("null value received for param data/length !!\n"); - return 0; - } - - /* allocated a new AVP struct */ - avp = 0; - avp = (AAA_AVP*)ad_malloc(sizeof(AAA_AVP)); - if (!avp) - goto error; - memset( avp, 0, sizeof(AAA_AVP) ); - - /* set some fields */ - //avp->free_it = free_it; - avp->packetType = AAA_DIAMETER; - avp->code=code; - avp->flags=flags; - avp->vendorId=vendorId; - set_avp_fields( code, avp); - - if ( data_status==AVP_DUPLICATE_DATA ) { - /* make a duplicate for data */ - avp->data.len = length; - avp->data.s = (void*)ad_malloc(length); - if(!avp->data.s) - goto error; - memcpy( avp->data.s, data, length); - avp->free_it = 1; - } else { - avp->data.s = data; - avp->data.len = length; - avp->free_it = (data_status==AVP_FREE_DATA)?1:0; - } - - return avp; -error: - LM_ERR("no more free memoryfor a new AVP!\n"); - return 0; -} - - - -/* Insert the AVP avp into this avpList of a message after position */ -AAAReturnCode AAAAddAVPToMessage( - AAAMessage *msg, - AAA_AVP *avp, - AAA_AVP *position) -{ - AAA_AVP *avp_t; - - if ( !msg || !avp ) { - LM_ERR("param msg or avp passed null or *avpList=NULL " - "and position!=NULL !!\n"); - return AAA_ERR_PARAMETER; - } - - if (!position) { - /* insert at the beginning */ - avp->next = msg->avpList.head; - avp->prev = 0; - msg->avpList.head = avp; - if (avp->next) - avp->next->prev = avp; - else - msg->avpList.tail = avp; - } else { - /* look after avp from position */ - for(avp_t=msg->avpList.head;avp_t&&avp_t!=position;avp_t=avp_t->next); - if (!avp_t) { - LM_ERR("the \"position\" avp is not in \"msg\" message!!\n"); - return AAA_ERR_PARAMETER; - } - /* insert after position */ - avp->next = position->next; - position->next = avp; - if (avp->next) - avp->next->prev = avp; - else - msg->avpList.tail = avp; - avp->prev = position; - } - - /* update the short-cuts */ - switch (avp->code) { - case AVP_Session_Id: msg->sessionId = avp;break; - case AVP_Origin_Host: msg->orig_host = avp;break; - case AVP_Origin_Realm: msg->orig_realm = avp;break; - case AVP_Destination_Host: msg->dest_host = avp;break; - case AVP_Destination_Realm: msg->dest_realm = avp;break; - case AVP_Result_Code: msg->res_code = avp;break; - case AVP_Auth_Session_State: msg->auth_ses_state = avp;break; - } - - return AAA_ERR_SUCCESS; -} - - -/* This function finds an AVP with matching code and vendor id */ -AAA_AVP *AAAFindMatchingAVP( - AAAMessage *msg, - AAA_AVP *startAvp, - AAA_AVPCode avpCode, - AAAVendorId vendorId, - AAASearchType searchType) -{ - AAA_AVP *avp_t; - - /* param checking */ - if (!msg) { - LM_ERR("param msg passed null !!\n"); - goto error; - } - /* search the startAVP avp */ - for(avp_t=msg->avpList.head;avp_t&&avp_t!=startAvp;avp_t=avp_t->next); - if (!avp_t && startAvp) { - LM_ERR("the \"position\" avp is not in \"avpList\" list!!\n"); - goto error; - } - - /* where should I start searching from ? */ - if (!startAvp) - avp_t=(searchType==AAA_FORWARD_SEARCH)?(msg->avpList.head): - (msg->avpList.tail); - else - avp_t=startAvp; - - /* start searching */ - while(avp_t) { - if (avp_t->code==avpCode && avp_t->vendorId==vendorId) - return avp_t; - avp_t = (searchType==AAA_FORWARD_SEARCH)?(avp_t->next):(avp_t->prev); - } - -error: - return 0; -} - - - - -/* This function removes an AVP from a list of a message */ -AAAReturnCode AAARemoveAVPFromMessage( - AAAMessage *msg, - AAA_AVP *avp) -{ - AAA_AVP *avp_t; - - /* param check */ - if ( !msg || !avp ) { - LM_ERR("param AVP_LIST \"avpList\" or AVP \"avp\" passed null !!\n"); - return AAA_ERR_PARAMETER; - } - - /* search the "avp" avp */ - for(avp_t=msg->avpList.head;avp_t&&avp_t!=avp;avp_t=avp_t->next); - if (!avp_t) { - LM_ERR("the \"avp\" avp is not in \"avpList\" avp list!!\n"); - return AAA_ERR_PARAMETER; - } - - /* remove the avp from list */ - if (msg->avpList.head==avp) - msg->avpList.head = avp->next; - else - avp->prev->next = avp->next; - if (avp->next) - avp->next->prev = avp->prev; - else - msg->avpList.tail = avp->prev; - avp->next = avp->prev = 0; - - /* update short-cuts */ - switch (avp->code) { - case AVP_Session_Id: msg->sessionId = 0;break; - case AVP_Origin_Host: msg->orig_host = 0;break; - case AVP_Origin_Realm: msg->orig_realm = 0;break; - case AVP_Destination_Host: msg->dest_host = 0;break; - case AVP_Destination_Realm: msg->dest_realm = 0;break; - case AVP_Result_Code: msg->res_code = 0;break; - case AVP_Auth_Session_State: msg->auth_ses_state = 0;break; - } - - return AAA_ERR_SUCCESS; -} - - - -/* The function frees an AVP */ -AAAReturnCode AAAFreeAVP(AAA_AVP **avp) -{ - /* some checks */ - if (!avp || !(*avp)) { - LM_ERR("param avp cannot be null!!\n"); - return AAA_ERR_PARAMETER; - } - - /* free all the mem */ - if ( (*avp)->free_it && (*avp)->data.s ) - ad_free((*avp)->data.s); - - ad_free( *avp ); - *avp = 0; - - return AAA_ERR_SUCCESS; -} - - - -/* This function returns a pointer to the first AVP in the list */ -AAA_AVP* AAAGetFirstAVP(AAA_AVP_LIST *avpList){ - return avpList->head; -} - - - -/* This function returns a pointer to the last AVP in the list */ -AAA_AVP* AAAGetLastAVP(AAA_AVP_LIST *avpList) -{ - return avpList->tail; -} - - - - -/* This function returns a pointer to the next AVP in the list */ -AAA_AVP* AAAGetNextAVP(AAA_AVP *avp) -{ - return avp->next; -} - - - -/* This function returns a pointer to the previous AVP in the list */ -AAA_AVP* AAAGetPrevAVP(AAA_AVP *avp) -{ - return avp->prev; -} - - - -/* This function converts the data in the AVP to a format suitable for - * log or display functions. */ -char* AAAConvertAVPToString(AAA_AVP *avp, char *dest, unsigned int destLen) -{ - int l; - int i; - - if (!avp || !dest || !destLen) { - LM_ERR("param AVP, DEST or DESTLEN passed as null!!!\n"); - return 0; - } - l = snprintf(dest,destLen,"AVP(%p < %p >%p):packetType=%u;code=%u," - "flags=%x;\nDataType=%u;VendorID=%u;DataLen=%u;\n", - avp->prev,avp,avp->next,avp->packetType,avp->code,avp->flags, - avp->type,avp->vendorId,avp->data.len); - switch(avp->type) { - case AAA_AVP_STRING_TYPE: - l+=snprintf(dest+l,destLen-l,"String: <%.*s>",avp->data.len, - avp->data.s); - break; - case AAA_AVP_INTEGER32_TYPE: - l+=snprintf(dest+l,destLen-l,"Int32: <%u>(%x)", - htonl(*((unsigned int*)avp->data.s)), - htonl(*((unsigned int*)avp->data.s))); - break; - case AAA_AVP_ADDRESS_TYPE: - i = 1; - switch (avp->data.len) { - case 4: i=i*0; - case 6: i=i*2; - l+=snprintf(dest+l,destLen-l,"Address IPv4: <%d.%d.%d.%d>", - (unsigned char)avp->data.s[i+0], - (unsigned char)avp->data.s[i+1], - (unsigned char)avp->data.s[i+2], - (unsigned char)avp->data.s[i+3]); - break; - case 16: i=i*0; - case 18: i=i*2; - l+=snprintf(dest+l,destLen-l, - "Address IPv6: <%x.%x.%x.%x.%x.%x.%x.%x>", - ((avp->data.s[i+0]<<8)+avp->data.s[i+1]), - ((avp->data.s[i+2]<<8)+avp->data.s[i+3]), - ((avp->data.s[i+4]<<8)+avp->data.s[i+5]), - ((avp->data.s[i+6]<<8)+avp->data.s[i+7]), - ((avp->data.s[i+8]<<8)+avp->data.s[i+9]), - ((avp->data.s[i+10]<<8)+avp->data.s[i+11]), - ((avp->data.s[i+12]<<8)+avp->data.s[i+13]), - ((avp->data.s[i+14]<<8)+avp->data.s[i+15])); - break; - break; - } - break; - //case AAA_AVP_INTEGER64_TYPE: - case AAA_AVP_TIME_TYPE: - default: - LM_WARN("don't know how to print" - " this data type [%d] -> tryng hexa\n",avp->type); - case AAA_AVP_DATA_TYPE: - for (i=0;idata.len&&ldata.s)[i]); - } - return dest; -} - - - -AAA_AVP* AAACloneAVP( AAA_AVP *avp , unsigned char clone_data) -{ - AAA_AVP *n_avp; - - if (!avp || !(avp->data.s) || !(avp->data.len) ) - goto error; - - /* clone the avp structure */ - n_avp = (AAA_AVP*)ad_malloc( sizeof(AAA_AVP) ); - if (!n_avp) { - LM_ERR("cannot get free memory!!\n"); - goto error; - } - memcpy( n_avp, avp, sizeof(AAA_AVP)); - n_avp->next = n_avp->prev = 0; - - if (clone_data) { - /* clone the avp data */ - n_avp->data.s = (char*)ad_malloc( avp->data.len ); - if (!(n_avp->data.s)) { - LM_ERR("cannot get free memory!!\n"); - ad_free( n_avp ); - goto error; - } - memcpy( n_avp->data.s, avp->data.s, avp->data.len); - n_avp->free_it = 1; - } else { - /* link the clone's data to the original's data */ - n_avp->data.s = avp->data.s; - n_avp->data.len = avp->data.len; - n_avp->free_it = 0; - } - - return n_avp; -error: - return 0; -} - -#endif diff --git a/modules/acc/diam_dict.h b/modules/acc/diam_dict.h deleted file mode 100644 index cd8215b0a98..00000000000 --- a/modules/acc/diam_dict.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2002-2003 FhG Fokus - * - * This file is part of disc, a free diameter server/client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * 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 - * - * History: - * -------- - */ - -#ifdef DIAM_ACC - -#ifndef DIAM_ACC_H -#define DIAM_ACC_H - -#define SERVICE_LEN 1 -#define SIP_ACCOUNTING "9" - -#define vendorID 0 - -/* Accounting AVPs */ -enum{ - /*Accounting*/ - AVP_SIP_CALLID = 550, /* string */ - AVP_SIP_METHOD = 551, /* string */ - AVP_SIP_STATUS = 552, /* string */ - AVP_SIP_FROM_TAG = 553, /* string */ - AVP_SIP_TO_TAG = 554, /* string */ - AVP_SIP_CODE = 564 /* string */ -}; - -#endif - - -#endif - diff --git a/modules/acc/diam_message.c b/modules/acc/diam_message.c deleted file mode 100644 index 2ab9b10919e..00000000000 --- a/modules/acc/diam_message.c +++ /dev/null @@ -1,367 +0,0 @@ -/* - * Copyright (C) 2002-2003 FhG Fokus - * - * This file is part of disc, a free diameter server/client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * 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 - * - * History: - * --------- - * - * 2003-04-07 created by bogdan - */ - - -#ifdef DIAM_ACC - -#include -#include -#include - -#include "../../mem/shm_mem.h" -#include "../../dprint.h" -#include "diam_message.h" - -#define get_3bytes(_b) \ - ((((unsigned int)(_b)[0])<<16)|(((unsigned int)(_b)[1])<<8)|\ - (((unsigned int)(_b)[2]))) - -#define get_4bytes(_b) \ - ((((unsigned int)(_b)[0])<<24)|(((unsigned int)(_b)[1])<<16)|\ - (((unsigned int)(_b)[2])<<8)|(((unsigned int)(_b)[3]))) - -#define set_3bytes(_b,_v) \ - {(_b)[0]=((_v)&0x00ff0000)>>16;(_b)[1]=((_v)&0x0000ff00)>>8;\ - (_b)[2]=((_v)&0x000000ff);} - -#define set_4bytes(_b,_v) \ - {(_b)[0]=((_v)&0xff000000)>>24;(_b)[1]=((_v)&0x00ff0000)>>16;\ - (_b)[2]=((_v)&0x0000ff00)>>8;(_b)[3]=((_v)&0x000000ff);} - -#define to_32x_len( _len_ ) \ - ( (_len_)+(((_len_)&3)?4-((_len_)&3):0) ) - - -/* from a AAAMessage structure, a buffer to be send is build - */ -AAAReturnCode AAABuildMsgBuffer( AAAMessage *msg ) -{ - char *p; - AAA_AVP *avp; - - /* first let's compute the length of the buffer */ - msg->buf.len = AAA_MSG_HDR_SIZE; /* AAA message header size */ - /* count and add the avps */ - for(avp=msg->avpList.head;avp;avp=avp->next) { - msg->buf.len += AVP_HDR_SIZE(avp->flags)+ to_32x_len( avp->data.len ); - } - - /* allocate some memory */ - msg->buf.s = (char*)ad_malloc( msg->buf.len ); - if (!msg->buf.s) { - LM_ERR("no more pkg free memory!\n"); - goto error; - } - memset(msg->buf.s, 0, msg->buf.len); - - /* fill in the buffer */ - p = msg->buf.s; - /* DIAMETER HEADER */ - /* message length */ - ((unsigned int*)p)[0] =htonl(msg->buf.len); - /* Diameter Version */ - *p = 1; - p += VER_SIZE + MESSAGE_LENGTH_SIZE; - /* command code */ - ((unsigned int*)p)[0] = htonl(msg->commandCode); - /* flags */ - *p = (unsigned char)msg->flags; - p += FLAGS_SIZE + COMMAND_CODE_SIZE; - /* application-ID */ - ((unsigned int*)p)[0] = htonl(msg->applicationId); - p += APPLICATION_ID_SIZE; - /* hop by hop id */ - ((unsigned int*)p)[0] = msg->hopbyhopId; - p += HOP_BY_HOP_IDENTIFIER_SIZE; - /* end to end id */ - ((unsigned int*)p)[0] = msg->endtoendId; - p += END_TO_END_IDENTIFIER_SIZE; - - /* AVPS */ - for(avp=msg->avpList.head;avp;avp=avp->next) { - /* AVP HEADER */ - /* avp code */ - set_4bytes(p,avp->code); - p +=4; - /* flags */ - (*p++) = (unsigned char)avp->flags; - /* avp length */ - set_3bytes(p, (AVP_HDR_SIZE(avp->flags)+avp->data.len) ); - p += 3; - /* vendor id */ - if ((avp->flags&0x80)!=0) { - set_4bytes(p,avp->vendorId); - p +=4; - } - /* data */ - memcpy( p, avp->data.s, avp->data.len); - p += to_32x_len( avp->data.len ); - } - - if ((char*)p-msg->buf.s!=msg->buf.len) { - LM_ERR("mismatch between len and buf!\n"); - ad_free( msg->buf.s ); - msg->buf.s = 0; - msg->buf.len = 0; - goto error; - } - LM_DBG("Message: %.*s\n", msg->buf.len, msg->buf.s); - return AAA_ERR_SUCCESS; -error: - return -1; -} - - - -/* frees a message allocated through AAANewMessage() - */ -AAAReturnCode AAAFreeMessage(AAAMessage **msg) -{ - AAA_AVP *avp_t; - AAA_AVP *avp; - - /* param check */ - if (!msg || !(*msg)) - goto done; - - /* free the avp list */ - avp = (*msg)->avpList.head; - while (avp) { - avp_t = avp; - avp = avp->next; - /*free the avp*/ - AAAFreeAVP(&avp_t); - } - - /* free the buffer (if any) */ - if ( (*msg)->buf.s ) - ad_free( (*msg)->buf.s ); - - /* free the AAA msg */ - ad_free(*msg); - msg = 0; - -done: - return AAA_ERR_SUCCESS; -} - - - -/* Sets the proper result_code into the Result-Code AVP; thus avp must already - * exists into the reply message */ -AAAResultCode AAASetMessageResultCode( - AAAMessage *message, - AAAResultCode resultCode) -{ - if ( !is_req(message) && message->res_code) { - *((unsigned int*)(message->res_code->data.s)) = htonl(resultCode); - return AAA_ERR_SUCCESS; - } - return AAA_ERR_FAILURE; -} - - - -/* This function convert message to message structure */ -AAAMessage* AAATranslateMessage( unsigned char* source, unsigned int sourceLen, - int attach_buf) -{ - unsigned char *ptr; - AAAMessage *msg; - unsigned char version; - unsigned int msg_len; - AAA_AVP *avp; - unsigned int avp_code; - unsigned char avp_flags; - unsigned int avp_len; - unsigned int avp_vendorID; - unsigned int avp_data_len; - - /* check the params */ - if( !source || !sourceLen || sourceLensourceLen) { - LM_ERR("AAA message len [%d] bigger then buffer len [%d]\n", - msg_len,sourceLen); - goto error; - } - - /* command flags */ - msg->flags = *ptr; - ptr += FLAGS_SIZE; - - /* command code */ - msg->commandCode = get_3bytes( ptr ); - ptr += COMMAND_CODE_SIZE; - - /* application-Id */ - msg->applicationId = get_4bytes( ptr ); - ptr += APPLICATION_ID_SIZE; - - /* Hop-by-Hop-Id */ - msg->hopbyhopId = *((unsigned int*)ptr); - ptr += HOP_BY_HOP_IDENTIFIER_SIZE; - - /* End-to-End-Id */ - msg->endtoendId = *((unsigned int*)ptr); - ptr += END_TO_END_IDENTIFIER_SIZE; - - /* start decoding the AVPS */ - while (ptr < source+msg_len) { - if (ptr+AVP_HDR_SIZE(0x80)>source+msg_len){ - LM_ERR("source buffer to short!! " - "Cannot read the whole AVP header!\n"); - goto error; - } - /* avp code */ - avp_code = get_4bytes( ptr ); - ptr += AVP_CODE_SIZE; - /* avp flags */ - avp_flags = (unsigned char)*ptr; - ptr += AVP_FLAGS_SIZE; - /* avp length */ - avp_len = get_3bytes( ptr ); - ptr += AVP_LENGTH_SIZE; - if (avp_len<1) { - LM_ERR("invalid AVP len [%d]\n", avp_len); - goto error; - } - /* avp vendor-ID */ - avp_vendorID = 0; - if (avp_flags&AAA_AVP_FLAG_VENDOR_SPECIFIC) { - avp_vendorID = get_4bytes( ptr ); - ptr += AVP_VENDOR_ID_SIZE; - } - /* data length */ - avp_data_len = avp_len-AVP_HDR_SIZE(avp_flags); - /*check the data length */ - if ( source+msg_lenavpList.tail); - - ptr += to_32x_len( avp_data_len ); - } - - /* link the buffer to the message */ - if (attach_buf) { - msg->buf.s = (char*)source; - msg->buf.len = msg_len; - } - - //AAAPrintMessage( msg ); - return msg; -error: - LM_ERR("message conversion droped!!\n"); - AAAFreeMessage(&msg); - return 0; -} - - - -/* print as debug all info contained by an aaa message + AVPs - */ -void AAAPrintMessage( AAAMessage *msg) -{ - char buf[1024]; - AAA_AVP *avp; - - /* print msg info */ - LM_DBG("AAA_MESSAGE - %p\n",msg); - LM_DBG("\tCode = %u\n",msg->commandCode); - LM_DBG("\tFlags = %x\n",msg->flags); - - /*print the AVPs */ - avp = msg->avpList.head; - while (avp) { - AAAConvertAVPToString(avp,buf,1024); - LM_DBG("\n%s\n",buf); - avp=avp->next; - } -} - -AAAMessage* AAAInMessage(AAACommandCode cmdCode, - AAAApplicationId appID) -{ - AAAMessage *msg; - - /* allocated a new AAAMessage structure a set it to 0 */ - msg = (AAAMessage*)ad_malloc(sizeof(AAAMessage)); - if (!msg) { - LM_ERR("no more pkg free memory!\n"); - return NULL; - } - memset(msg, 0, sizeof(AAAMessage)); - - /* command code */ - msg->commandCode = cmdCode; - - /* application ID */ - msg->applicationId = appID; - - /* it's a new request -> set the flag */ - msg->flags = 0x80; - - return msg; -} - -#endif diff --git a/modules/acc/diam_message.h b/modules/acc/diam_message.h deleted file mode 100644 index 74b9b8f9a49..00000000000 --- a/modules/acc/diam_message.h +++ /dev/null @@ -1,393 +0,0 @@ -/* - * Copyright (C) 2002-2003 FhG Fokus - * - * This file is part of disc, a free diameter server/client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * 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 - * - * History: - * --------- - * 2003-04-07 created by bogdan - */ - -#ifdef DIAM_ACC - -#ifndef _AAA_DIAMETER_MSG_H -#define _AAA_DIAMETER_MSG_H - -#include "../../str.h" -#include "../../mem/mem.h" - -#define ad_malloc pkg_malloc -#define ad_free pkg_free - -/*********************************** AAA TYPES *******************************/ - -#define AAA_NO_VENDOR_ID 0 - -#define VER_SIZE 1 -#define MESSAGE_LENGTH_SIZE 3 -#define FLAGS_SIZE 1 -#define COMMAND_CODE_SIZE 3 -#define APPLICATION_ID_SIZE 4 -#define HOP_BY_HOP_IDENTIFIER_SIZE 4 -#define END_TO_END_IDENTIFIER_SIZE 4 -#define AVP_CODE_SIZE 4 -#define AVP_FLAGS_SIZE 1 -#define AVP_LENGTH_SIZE 3 -#define AVP_VENDOR_ID_SIZE 4 - -#define AAA_MSG_HDR_SIZE \ - (VER_SIZE + MESSAGE_LENGTH_SIZE + FLAGS_SIZE + COMMAND_CODE_SIZE +\ - APPLICATION_ID_SIZE+HOP_BY_HOP_IDENTIFIER_SIZE+END_TO_END_IDENTIFIER_SIZE) - -#define AVP_HDR_SIZE(_flags_) \ - (AVP_CODE_SIZE+AVP_FLAGS_SIZE+AVP_LENGTH_SIZE+\ - AVP_VENDOR_ID_SIZE*(((_flags_)&AAA_AVP_FLAG_VENDOR_SPECIFIC)!=0) ) - -/* message codes - */ -#ifndef WORDS_BIGENDIAN - #define AS_MSG_CODE 0x12010000 - #define AC_MSG_CODE 0x0f010000 - #define CE_MSG_CODE 0x01010000 - #define DW_MSG_CODE 0x18010000 - #define DP_MSG_CODE 0x1a010000 - #define RA_MSG_CODE 0x02010000 - #define ST_MSG_CODE 0x13010000 - #define MASK_MSG_CODE 0xffffff00 -#else - #error BIG endian detected!! - #define AS_MSG_CODE 0x00000112 - #define AC_MSG_CODE 0x0000010f - #define CE_MSG_CODE 0x00000101 - #define DW_MSG_CODE 0x00000118 - #define DP_MSG_CODE 0x0000011a - #define RA_MSG_CODE 0x00000102 - #define ST_MSG_CODE 0x00000113 - #define MASK_MSG_CODE 0x00ffffff -#endif - -typedef unsigned int AAACommandCode; -typedef unsigned int AAAVendorId; -typedef unsigned int AAAExtensionId; -typedef unsigned int AAA_AVPCode; -typedef unsigned int AAAValue; -typedef unsigned int AAAApplicationId; -typedef void* AAAApplicationRef; -typedef str AAASessionId; -typedef unsigned int AAAMsgIdentifier; -typedef unsigned char AAAMsgFlag; - - -/* Status codes returned by functions in the AAA API */ -typedef enum { - AAA_ERR_NOT_FOUND = -2, /* handle or id not found */ - AAA_ERR_FAILURE = -1, /* unspecified failure during an AAA op. */ - AAA_ERR_SUCCESS = 0, /* AAA operation succeeded */ - AAA_ERR_NOMEM, /* op. caused memory to be exhausted */ - AAA_ERR_PROTO, /* AAA protocol error */ - AAA_ERR_SECURITY, - AAA_ERR_PARAMETER, - AAA_ERR_CONFIG, - AAA_ERR_UNKNOWN_CMD, - AAA_ERR_MISSING_AVP, - AAA_ERR_ALREADY_INIT, - AAA_ERR_TIMED_OUT, - AAA_ERR_CANNOT_SEND_MSG, - AAA_ERR_ALREADY_REGISTERED, - AAA_ERR_CANNOT_REGISTER, - AAA_ERR_NOT_INITIALIZED, - AAA_ERR_NETWORK_ERROR, -} AAAReturnCode; - - -/* The following are AVP data type codes. They correspond directly to - * the AVP data types outline in the Diameter specification [1]: */ -typedef enum { - AAA_AVP_DATA_TYPE, - AAA_AVP_STRING_TYPE, - AAA_AVP_ADDRESS_TYPE, - AAA_AVP_INTEGER32_TYPE, - AAA_AVP_INTEGER64_TYPE, - AAA_AVP_TIME_TYPE, -} AAA_AVPDataType; - - -/* The following are used for AVP header flags and for flags in the AVP - * wrapper struct and AVP dictionary definitions. */ -typedef enum { - AAA_AVP_FLAG_NONE = 0x00, - AAA_AVP_FLAG_MANDATORY = 0x40, - AAA_AVP_FLAG_RESERVED = 0x1F, - AAA_AVP_FLAG_VENDOR_SPECIFIC = 0x80, - AAA_AVP_FLAG_END_TO_END_ENCRYPT = 0x20, -} AAA_AVPFlag; - - -/* List with all known application identifiers */ -typedef enum { - AAA_APP_DIAMETER_COMMON_MSG = 0, - AAA_APP_NASREQ = 1, - AAA_APP_MOBILE_IP = 2, - AAA_APP_DIAMETER_BASE_ACC = 3, - AAA_APP_RELAY = 0xffffffff, -}AAA_APP_IDS; - - -/* The following are the result codes returned from remote servers as - * part of messages */ -typedef enum { - AAA_MUTI_ROUND_AUTH = 1001, - AAA_SUCCESS = 2001, - AAA_COMMAND_UNSUPPORTED = 3001, - AAA_UNABLE_TO_DELIVER = 3002, - AAA_REALM_NOT_SERVED = 3003, - AAA_TOO_BUSY = 3004, - AAA_LOOP_DETECTED = 3005, - AAA_REDIRECT_INDICATION = 3006, - AAA_APPLICATION_UNSUPPORTED = 3007, - AAA_INVALID_HDR_BITS = 3008, - AAA_INVALID_AVP_BITS = 3009, - AAA_UNKNOWN_PEER = 3010, - AAA_AUTHENTICATION_REJECTED = 4001, - AAA_OUT_OF_SPACE = 4002, - AAA_ELECTION_LOST = 4003, - AAA_AVP_UNSUPPORTED = 5001, - AAA_UNKNOWN_SESSION_ID = 5002, - AAA_AUTHORIZATION_REJECTED = 5003, - AAA_INVALID_AVP_VALUE = 5004, - AAA_MISSING_AVP = 5005, - AAA_RESOURCES_EXCEEDED = 5006, - AAA_CONTRADICTING_AVPS = 5007, - AAA_AVP_NOT_ALLOWED = 5008, - AAA_AVP_OCCURS_TOO_MANY_TIMES = 5009, - AAA_NO_COMMON_APPLICATION = 5010, - AAA_UNSUPPORTED_VERSION = 5011, - AAA_UNABLE_TO_COMPLY = 5012, - AAA_INVALID_BIT_IN_HEADER = 5013, - AAA_INVALIS_AVP_LENGTH = 5014, - AAA_INVALID_MESSGE_LENGTH = 5015, - AAA_INVALID_AVP_BIT_COMBO = 5016, - AAA_NO_COMMON_SECURITY = 5017, -} AAAResultCode; - - -typedef enum { - AVP_User_Name = 1, - AVP_Class = 25, - AVP_Session_Timeout = 27, - AVP_Proxy_State = 33, - AVP_Host_IP_Address = 257, - AVP_Auth_Application_Id = 258, - AVP_Vendor_Specific_Application_Id= 260, - AVP_Redirect_Max_Cache_Time = 262, - AVP_Session_Id = 263, - AVP_Origin_Host = 264, - AVP_Supported_Vendor_Id = 265, - AVP_Vendor_Id = 266, - AVP_Result_Code = 268, - AVP_Product_Name = 269, - AVP_Session_Binding = 270, - AVP_Disconnect_Cause = 273, - AVP_Auth_Request_Type = 274, - AVP_Auth_Grace_Period = 276, - AVP_Auth_Session_State = 277, - AVP_Origin_State_Id = 278, - AVP_Accounting_Record_Type = 279, - AVP_Proxy_Host = 280, - AVP_Error_Message = 281, - AVP_Record_Route = 282, - AVP_Destination_Realm = 283, - AVP_Proxy_Info = 284, - AVP_Re_Auth_Request_Type = 285, - AVP_Authorization_Lifetime = 291, - AVP_Redirect_Host = 292, - AVP_Destination_Host = 293, - AVP_Termination_Cause = 295, - AVP_Origin_Realm = 296, - AVP_Resource = 400, - AVP_Response = 401, - AVP_Challenge = 402, - AVP_Method = 403, - AVP_Service_Type = 404, - AVP_User_Group = 405, - AVP_SIP_MSGID = 406 - -}AAA_AVPCodeNr; - - -/* The following type allows the client to specify which direction to - * search for an AVP in the AVP list: */ -typedef enum { - AAA_FORWARD_SEARCH = 0, - AAA_BACKWARD_SEARCH -} AAASearchType; - - - -typedef enum { - AAA_ACCT_EVENT = 1, - AAA_ACCT_START = 2, - AAA_ACCT_INTERIM = 3, - AAA_ACCT_STOP = 4 -} AAAAcctMessageType; - - -typedef enum { - AVP_DUPLICATE_DATA, - AVP_DONT_FREE_DATA, - AVP_FREE_DATA, -} AVPDataStatus; - -/* The following structure contains a message AVP in parsed format */ -typedef struct avp { - struct avp *next; - struct avp *prev; - enum { - AAA_RADIUS, - AAA_DIAMETER - } packetType; - AAA_AVPCode code; - AAA_AVPFlag flags; - AAA_AVPDataType type; - AAAVendorId vendorId; - str data; - unsigned char free_it; -} AAA_AVP; - - -/* The following structure is used for representing lists of AVPs on the - * message: */ -typedef struct _avp_list_t { - AAA_AVP *head; - AAA_AVP *tail; -} AAA_AVP_LIST; - - -/* The following structure contains the full AAA message: */ -typedef struct _message_t { - AAAMsgFlag flags; - AAACommandCode commandCode; - AAAApplicationId applicationId; - AAAMsgIdentifier endtoendId; - AAAMsgIdentifier hopbyhopId; - AAASessionId *sId; - AAA_AVP *sessionId; - AAA_AVP *orig_host; - AAA_AVP *orig_realm; - AAA_AVP *dest_host; - AAA_AVP *dest_realm; - AAA_AVP *res_code; - AAA_AVP *auth_ses_state; - AAA_AVP_LIST avpList; - str buf; - void *in_peer; -} AAAMessage; - - - - -/**************************** AAA MESSAGE FUNCTIONS **************************/ - -/* MESSAGES - */ - -#define is_req(_msg_) \ - (((_msg_)->flags)&0x80) - -AAAMessage* AAAInMessage(AAACommandCode commandCode, - AAAApplicationId applicationId); - -AAAReturnCode AAAFreeMessage( - AAAMessage **message); - -AAAResultCode AAASetMessageResultCode( - AAAMessage *message, - AAAResultCode resultCode); - -void AAAPrintMessage( - AAAMessage *msg); - -AAAReturnCode AAABuildMsgBuffer( - AAAMessage *msg ); - -AAAMessage* AAATranslateMessage( - unsigned char* source, - unsigned int sourceLen, - int attach_buf ); - - -/* AVPS - */ - -#define AAACreateAndAddAVPToMessage(_msg_,_code_,_flags_,_vdr_,_data_,_len_) \ - ( AAAAddAVPToMessage(_msg_, \ - AAACreateAVP(_code_,_flags_,_vdr_,_data_,_len_, AVP_DUPLICATE_DATA),\ - (_msg_)->avpList.tail) ) - -AAA_AVP* AAACreateAVP( - AAA_AVPCode code, - AAA_AVPFlag flags, - AAAVendorId vendorId, - char *data, - size_t length, - AVPDataStatus data_status); - -AAA_AVP* AAACloneAVP( - AAA_AVP *avp, - unsigned char duplicate_data ); - -AAAReturnCode AAAAddAVPToMessage( - AAAMessage *msg, - AAA_AVP *avp, - AAA_AVP *position); - -AAA_AVP *AAAFindMatchingAVP( - AAAMessage *msg, - AAA_AVP *startAvp, - AAA_AVPCode avpCode, - AAAVendorId vendorId, - AAASearchType searchType); - -AAAReturnCode AAARemoveAVPFromMessage( - AAAMessage *msg, - AAA_AVP *avp); - -AAAReturnCode AAAFreeAVP( - AAA_AVP **avp); - -AAA_AVP* AAAGetFirstAVP( - AAA_AVP_LIST *avpList); - -AAA_AVP* AAAGetLastAVP( - AAA_AVP_LIST *avpList); - -AAA_AVP* AAAGetNextAVP( - AAA_AVP *avp); - -AAA_AVP* AAAGetPrevAVP( - AAA_AVP *avp); - -char *AAAConvertAVPToString( - AAA_AVP *avp, - char *dest, - unsigned int destLen); - - -#endif - - -#endif diff --git a/modules/acc/diam_tcp.c b/modules/acc/diam_tcp.c deleted file mode 100644 index 98483e08e4a..00000000000 --- a/modules/acc/diam_tcp.c +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright (C) 2001-2003 FhG Fokus - * - * This file is part of opensips, a free SIP server. - * - * opensips is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version - * - * opensips is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * 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 - */ - -#ifdef DIAM_ACC - -#include -#include -#include -#include -#include -#include -#include - -#include "../../dprint.h" -#include "../../parser/msg_parser.h" -#include "../../parser/parse_to.h" -#include "../../parser/parse_from.h" -#include "../../mem/mem.h" -#include "../../resolv.h" - -#include "diam_message.h" -#include "diam_tcp.h" -#include "diam_dict.h" - -#define M_NAME "acc" - -/* TCP connection setup */ -int init_mytcp(char* host, int port) -{ - int sockfd; - struct sockaddr_in serv_addr; - struct hostent *server; - - sockfd = socket(PF_INET, SOCK_STREAM, 0); - - if (sockfd < 0) - { - LM_ERR("failed to create the socket\n"); - return -1; - } - - server = resolvehost(host,0); - if (server == NULL) - { - LM_ERR("failed to find the host\n"); - return -1; - } - - memset((char *) &serv_addr, 0, sizeof(serv_addr)); - serv_addr.sin_family = PF_INET; - memcpy((char *)&serv_addr.sin_addr.s_addr, (char *)server->h_addr, - server->h_length); - serv_addr.sin_port = htons(port); - - if (connect(sockfd, (const struct sockaddr *)&serv_addr, - sizeof(serv_addr)) < 0) - { - LM_ERR("failed to connec to the DIAMETER client\n"); - return -1; - } - - return sockfd; -} - -/* send a message over an already opened TCP connection */ -int tcp_send_recv(int sockfd, char* buf, int len, rd_buf_t* rb, - unsigned int waited_id) -{ - int n, number_of_tries; - fd_set active_fd_set, read_fd_set; - struct timeval tv; - unsigned long int result_code; - AAAMessage *msg; - AAA_AVP *avp; - char serviceType; - unsigned int m_id; - - /* try to write the message to the Diameter client */ - while( (n=write(sockfd, buf, len))==-1 ) - { - if (errno==EINTR) - continue; - LM_ERR("write returned error: %s\n", strerror(errno)); - return AAA_ERROR; - } - - if (n!=len) - { - LM_ERR("write gave no error but wrote less than asked\n"); - return AAA_ERROR; - } - /* wait for the answer a limited amount of time */ - tv.tv_sec = MAX_WAIT_SEC; - tv.tv_usec = MAX_WAIT_USEC; - - /* Initialize the set of active sockets. */ - FD_ZERO (&active_fd_set); - FD_SET (sockfd, &active_fd_set); - number_of_tries = 0; - - while(number_of_triesbuf, rb->buf_len, 0); - if(!msg) - { - LM_ERR("message structure not obtained\n"); - return AAA_ERROR; - } - avp = AAAFindMatchingAVP(msg, NULL, AVP_SIP_MSGID, - vendorID, AAA_FORWARD_SEARCH); - if(!avp) - { - LM_ERR("AVP_SIP_MSGID not found\n"); - return AAA_ERROR; - } - m_id = *((unsigned int*)(avp->data.s)); - LM_DBG("######## m_id=%d\n", m_id); - if(m_id!=waited_id) - { - number_of_tries ++; - LM_NOTICE("old message received\n"); - continue; - } - goto next; - } - - LM_ERR("too many old messages received\n"); - return AAA_TIMEOUT; -next: - - /* Finally die correct answer */ - avp = AAAFindMatchingAVP(msg, NULL, AVP_Service_Type, - vendorID, AAA_FORWARD_SEARCH); - if(!avp) - { - LM_ERR("AVP_Service_Type not found\n"); - return AAA_ERROR; - } - serviceType = avp->data.s[0]; - - result_code = ntohl(*((unsigned long int*)(msg->res_code->data.s))); - switch(result_code) - { - case AAA_SUCCESS: /* 2001 */ - return ACC_SUCCESS; - default: /* error */ - return ACC_FAILURE; - } -} - -void reset_read_buffer(rd_buf_t *rb) -{ - rb->first_4bytes = 0; - rb->buf_len = 0; - if(rb->buf) - pkg_free(rb->buf); - rb->buf = 0; -} - -/* read from a socket, an AAA message buffer */ -int do_read( int socket, rd_buf_t *p) -{ - unsigned char *ptr; - unsigned int wanted_len, len; - int n; - - if (p->buf==0) - { - wanted_len = sizeof(p->first_4bytes) - p->buf_len; - ptr = ((unsigned char*)&(p->first_4bytes)) + p->buf_len; - } - else - { - wanted_len = p->first_4bytes - p->buf_len; - ptr = p->buf + p->buf_len; - } - - while( (n=recv( socket, ptr, wanted_len, MSG_DONTWAIT ))>0 ) - { -// LM_DBG("(sock=%d) -> n=%d (expected=%d)\n", p->sock,n,wanted_len); - p->buf_len += n; - if (nbuf==0) - { - /* I just finished reading the first 4 bytes from msg */ - len = ntohl(p->first_4bytes)&0x00ffffff; - if (lenMAX_AAA_MSG_SIZE) - { - LM_ERR("(sock=%d): invalid message " - "length read %u (%x)\n", socket, len, p->first_4bytes); - goto error; - } - //LM_DBG("message length = %d(%x)\n",len,len); - if ( (p->buf=pkg_malloc(len))==0 ) - { - LM_ERR("no more pkg memory\n"); - goto error; - } - *((unsigned int*)p->buf) = p->first_4bytes; - p->buf_len = sizeof(p->first_4bytes); - p->first_4bytes = len; - /* update the reading position and len */ - ptr = p->buf + p->buf_len; - wanted_len = p->first_4bytes - p->buf_len; - } - else - { - /* I finished reading the whole message */ - LM_DBG("(sock=%d): whole message read (len=%d)!\n", - socket, p->first_4bytes); - return CONN_SUCCESS; - } - } - } - - if (n==0) - { - LM_INFO("(sock=%d): FIN received\n", socket); - return CONN_CLOSED; - } - if ( n==-1 && errno!=EINTR && errno!=EAGAIN ) - { - LM_ERR("(on sock=%d): n=%d , errno=%d (%s)\n", - socket, n, errno, strerror(errno)); - goto error; - } -error: - return CONN_ERROR; -} - - -void close_tcp_connection(int sfd) -{ - shutdown(sfd, 2); -} - -/* - * Extract URI depending on the request from To or From header - */ -int get_uri(struct sip_msg* m, str** uri) -{ - if ((REQ_LINE(m).method.len == 8) && - (memcmp(REQ_LINE(m).method.s, "REGISTER", 8) == 0)) - {/* REGISTER */ - if (!m->to && ((parse_headers(m, HDR_TO_F, 0) == -1) || !m->to )) - { - LM_ERR("the To header field was not found or malformed\n"); - return -1; - } - *uri = &(get_to(m)->uri); - } - else - { - if (parse_from_header(m)<0) - { - LM_ERR("failed to parse headers\n"); - return -2; - } - *uri = &(get_from(m)->uri); - } - return 0; -} - - -#endif diff --git a/modules/acc/diam_tcp.h b/modules/acc/diam_tcp.h deleted file mode 100644 index 1855a6ef883..00000000000 --- a/modules/acc/diam_tcp.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2001-2003 FhG Fokus - * - * This file is part of opensips, a free SIP server. - * - * opensips is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version - * - * opensips is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * 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 - */ -#ifdef DIAM_ACC - -#ifndef ACC_TCP -#define ACC_TCP - -#include "../../str.h" -#include "../../parser/msg_parser.h" - -/* information needed for reading messages from tcp connection */ -typedef struct rd_buf -{ - unsigned int first_4bytes; - unsigned int buf_len; - unsigned char *buf; -} rd_buf_t; - - -#define AAA_ERROR -1 -#define AAA_CONN_CLOSED -2 -#define AAA_TIMEOUT -3 -#define ACC_SUCCESS 0 -#define ACC_FAILURE 1 - -#define AAA_NO_CONNECTION -1 - -#define MAX_WAIT_SEC 2 -#define MAX_WAIT_USEC 0 - -#define MAX_AAA_MSG_SIZE 65536 - -#define CONN_SUCCESS 1 -#define CONN_ERROR -1 -#define CONN_CLOSED -2 - -#define MAX_TRIES 10 - -int sockfd; - -int do_read( int socket, rd_buf_t *p); -void reset_read_buffer(rd_buf_t *rb); - -/* it initializes the TCP connection */ -int init_mytcp(char* host, int port); -/* send a message over an already opened TCP connection */ -int tcp_send_recv(int sockfd, char* buf, int len, rd_buf_t* rb, - unsigned int waited_id); -void close_tcp_connection(int sfd); - -int get_uri(struct sip_msg* m, str** uri); -#endif - -#endif