diff --git a/modules/cnxcc/cnxcc_mod.c b/modules/cnxcc/cnxcc_mod.c index 456d497d385..e238b4475db 100644 --- a/modules/cnxcc/cnxcc_mod.c +++ b/modules/cnxcc/cnxcc_mod.c @@ -265,6 +265,13 @@ static int __mod_init(void) { _data.channel.credit_data_by_client = shm_malloc(sizeof(struct str_hash_table)); _data.channel.call_data_by_cid = shm_malloc(sizeof(struct str_hash_table)); + memset(_data.time.credit_data_by_client, 0, sizeof(struct str_hash_table)); + memset(_data.time.call_data_by_cid, 0, sizeof(struct str_hash_table)); + memset(_data.money.credit_data_by_client, 0, sizeof(struct str_hash_table)); + memset(_data.money.call_data_by_cid, 0, sizeof(struct str_hash_table)); + memset(_data.channel.credit_data_by_client, 0, sizeof(struct str_hash_table)); + memset(_data.channel.call_data_by_cid, 0, sizeof(struct str_hash_table)); + _data.stats = (stats_t *) shm_malloc(sizeof(stats_t)); if (!_data.stats) { @@ -655,17 +662,19 @@ static void __stop_billing(str *callid) { * Remove (and free) the call from the list of calls of the current credit_data */ clist_rm(call, next, prev); - /* - * don't free the call if all the credit data is being deallocated, - * it will be freed by terminate_all_calls() + + /* return if credit_data is being deallocated. + * the call and the credit data will be freed by terminate_all_calls() */ - if (!credit_data->deallocating) { - __free_call(call); + if (credit_data->deallocating) { + return; } + __free_call(call); /* * In case there are no active calls for a certain client, we remove the client-id from the hash table. * This way, we can save memory for useful clients. + * */ if (credit_data->number_of_calls == 0) { LM_DBG("Removing client [%.*s] and its calls from the list\n", credit_data->call_list->client_id.len, credit_data->call_list->client_id.s); @@ -882,9 +891,29 @@ static void __start_billing(str *callid, str *from_uri, str *to_uri, str tags[2] } // must be called with lock held on credit_data +/* terminate all calls and remove credit_data */ void terminate_all_calls(credit_data_t *credit_data) { call_t *call = NULL, *tmp = NULL; + struct str_hash_entry *cd_entry = NULL; + hash_tables_t *hts = NULL; + + switch(credit_data->type) { + case CREDIT_MONEY: + hts = &_data.money; + break; + case CREDIT_TIME: + hts = &_data.time; + break; + case CREDIT_CHANNEL: + hts = &_data.channel; + break; + default: + LM_ERR("BUG: Something went terribly wrong\n"); + return; + } + + cd_entry = str_hash_get(hts->credit_data_by_client, credit_data->call_list->client_id.s, credit_data->call_list->client_id.len); credit_data->deallocating = 1; @@ -902,6 +931,36 @@ void terminate_all_calls(credit_data_t *credit_data) { LM_WARN("invalid call structure %p\n", call); } } + + cnxcc_lock(hts->lock); + + if (_data.redis) { + redis_clean_up_if_last(credit_data); + shm_free(credit_data->str_id); + } + + /* + * Remove the credit_data_t from the hash table + */ + str_hash_del(cd_entry); + + cnxcc_unlock(hts->lock); + + /* + * Free client_id in list's root + */ + shm_free(credit_data->call_list->client_id.s); + shm_free(credit_data->call_list); + + /* + * Release the lock since we are going to free the entry down below + */ + cnxcc_unlock(credit_data->lock); + + /* + * Free the whole entry + */ + __free_credit_data_hash_entry(cd_entry); } /* @@ -1099,6 +1158,11 @@ static credit_data_t *__get_or_create_credit_data_entry(str *client_id, credit_t static credit_data_t *__alloc_new_credit_data(str *client_id, credit_type_t type) { credit_data_t *credit_data = shm_malloc(sizeof(credit_data_t));; + if (credit_data == NULL) + goto no_memory; + + memset(credit_data, 0, sizeof(credit_data_t)); + cnxcc_lock_init(credit_data->lock); credit_data->call_list = shm_malloc(sizeof(call_t));