4
* Copyright (C) 2012 Carlos Ruiz Díaz (caruizdiaz.com),
5
* ConexionGroup (www.conexiongroup.com)
7
* This file is part of Kamailio, a free SIP server.
9
* Kamailio is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU General Public License as published by
11
* the Free Software Foundation; either version 2 of the License, or
12
* (at your option) any later version
14
* Kamailio is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
19
* You should have received a copy of the GNU General Public License
20
* along with this program; if not, write to the Free Software
21
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28
#include <sys/types.h>
35
#include "../../sr_module.h"
36
#include "../../dprint.h"
37
#include "../../error.h"
38
#include "../../mem/mem.h"
39
#include "../../shm_init.h"
40
#include "../../mem/shm_mem.h"
41
#include "../../pvar.h"
42
#include "../../locking.h"
43
#include "../../lock_ops.h"
44
#include "../../str_hash.h"
45
#include "../../timer_proc.h"
46
#include "../../modules/tm/tm_load.h"
47
#include "../../parser/parse_from.h"
48
#include "../../parser/parse_to.h"
49
#include "../../parser/parse_uri.h"
50
#include "../../parser/parse_cseq.h"
51
#include "../../parser/contact/parse_contact.h"
52
#include "../../parser/contact/contact.h"
53
#include "../../parser/parse_rr.h"
54
#include "../../mod_fix.h"
55
#include "../dialog/dlg_load.h"
56
#include "../dialog/dlg_hash.h"
57
#include "../../mi/mi_types.h"
58
#include "../../lib/kcore/faked_msg.h"
59
#include "../../rpc.h"
60
#include "../../rpc_lookup.h"
62
#include "cnxcc_mod.h"
64
#include "cnxcc_sip_msg_faker.h"
65
#include "cnxcc_check.h"
66
#include "cnxcc_rpc.h"
67
#include "cnxcc_select.h"
72
#define MODULE_NAME "cnxcc"
73
#define NUMBER_OF_TIMERS 2
79
struct dlg_binds _dlgbinds;
81
static int fixup_par(void** param, int param_no);
84
* module core functions
86
static int mod_init(void);
87
static int child_init(int);
88
static int init_hashtable(struct str_hash_table *ht);
91
* Memory management functions
93
static int shm_str_hash_alloc(struct str_hash_table *ht, int size);
94
static void free_credit_data_hash_entry(struct str_hash_entry *e);
97
* PV management functions
99
static int pv_parse_calls_param(pv_spec_p sp, str *in);
100
static int pv_get_calls(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
101
//static int get_str_pv(struct sip_msg* msg, str *pv_name, str *pvvalue);
104
* Billing management functions
106
static int set_max_time(struct sip_msg* msg, char* number, char* str2);
107
static int update_max_time(struct sip_msg* msg, char* number, char* str2);
108
static int set_max_credit(struct sip_msg* msg, char *str_pv_client, char *str_pv_credit, char *str_pv_cps, char *str_pv_inip, char *str_pv_finp);
109
static int set_max_channels(struct sip_msg* msg, char* str_pv_client, char* str_pv_max_chan);
110
static int get_channel_count(struct sip_msg* msg, char* str_pv_client, char* str_pv_max_chan);
111
static int terminate_all(struct sip_msg* msg, char* str_pv_client);
113
static void start_billing(str *callid, str tags[2]);
114
static void setup_billing(str *callid, unsigned int h_entry, unsigned int h_id);
115
static void stop_billing(str *callid);
116
static int add_call_by_cid(str *cid, call_t *call, credit_type_t type);
117
static credit_data_t *get_or_create_credit_data_entry(str *client_id, credit_type_t type);
118
static call_t *alloc_new_call_by_time(credit_data_t *credit_data, struct sip_msg *msg, int max_secs);
119
static call_t *alloc_new_call_by_money(credit_data_t *credit_data, struct sip_msg *msg, double credit, double cost_per_second, int initial_pulse, int final_pulse);
120
static void notify_call_termination(str *callid, str *from_tag, str *to_tag);
121
static void free_call(call_t *call);
122
static int has_to_tag(struct sip_msg *msg);
127
static struct mi_root *mi_credit_control_stats(struct mi_root *tree, void *param);
130
* Dialog management callback functions
132
static void dialog_terminated_callback(struct dlg_cell *cell, int type, struct dlg_cb_params *params);
133
static void dialog_confirmed_callback(struct dlg_cell *cell, int type, struct dlg_cb_params *params);
134
static void dialog_created_callback(struct dlg_cell *cell, int type, struct dlg_cb_params *params);
136
static pv_export_t mod_pvs[] =
138
{ {"cnxcc", sizeof("cnxcc")-1 }, PVT_OTHER, pv_get_calls, 0,
139
pv_parse_calls_param, 0, 0, 0 },
140
{ {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
143
static cmd_export_t cmds[] =
145
{"cnxcc_set_max_time", (cmd_function) set_max_time, 2, fixup_pvar_pvar, fixup_free_pvar_pvar, ANY_ROUTE},
146
{"cnxcc_update_max_time", (cmd_function) update_max_time, 2, fixup_pvar_pvar, fixup_free_pvar_pvar, ANY_ROUTE},
147
{"cnxcc_set_max_credit", (cmd_function) set_max_credit, 5, fixup_par, NULL, ANY_ROUTE},
148
{"cnxcc_set_max_channels", (cmd_function) set_max_channels, 2, fixup_pvar_pvar, NULL, ANY_ROUTE},
149
{"cnxcc_get_channel_count", (cmd_function) get_channel_count, 2, fixup_pvar_pvar, NULL, ANY_ROUTE},
150
{"cnxcc_terminate_all", (cmd_function) terminate_all, 1, fixup_pvar_null, NULL, ANY_ROUTE},
155
static param_export_t params[] =
157
{"dlg_flag", INT_PARAM, &_data.ctrl_flag },
158
{"credit_check_period", INT_PARAM, &_data.check_period },
162
static const char* rpc_active_clients_doc[2] =
164
"List of clients with active calls",
168
static const char* rpc_check_client_stats_doc[2] =
170
"Check specific client calls",
174
static const char* rpc_kill_call_doc[2] =
176
"Kill call using its call ID",
180
rpc_export_t ul_rpc[] =
182
{"cnxcc.active_clients", rpc_active_clients, rpc_active_clients_doc, 0},
183
{"cnxcc.check_client", rpc_check_client_stats, rpc_check_client_stats_doc, 0},
184
{"cnxcc.kill_call", rpc_kill_call, rpc_kill_call_doc, 0},
188
/* selects declaration */
189
select_row_t sel_declaration[] = {
190
{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("cnxcc"), sel_root, SEL_PARAM_EXPECTED},
191
{ sel_root, SEL_PARAM_STR, STR_STATIC_INIT("channels"), sel_channels, SEL_PARAM_EXPECTED|CONSUME_NEXT_STR|FIXUP_CALL},
192
{ sel_channels, SEL_PARAM_STR, STR_STATIC_INIT("count"), sel_channels_count, 0},
194
{ NULL, SEL_PARAM_STR, STR_NULL, NULL, 0}
197
/** module exports */
198
struct module_exports exports =
201
DEFAULT_DLFLAGS, /* dlopen flags */
204
0, /* exported statistics */
205
0, /* exported MI functions */
206
mod_pvs, /* exported pseudo-variables */
207
0, /* extra processes */
208
mod_init, /* module initialization function */
211
child_init /* per-child init function */
214
static int fixup_par(void** param, int param_no)
218
var.s = (char *) *param;
219
var.len = strlen(var.s);
221
if (fixup_pvar_null(param, 1))
223
LM_ERR("Invalid PV [%.*s] as parameter\n", var.len, var.s);
227
if (((pv_spec_t*)(*param))->setf == NULL)
229
LM_ERR("[%.*s] has to be writable\n", var.len, var.s);
236
static int mod_init(void)
238
LM_INFO("Loading " MODULE_NAME " module\n");
240
_data.cs_route_number = route_get(&event_rt, "cnxcc:call-shutdown");
242
if (_data.cs_route_number < 0)
243
LM_INFO("No cnxcc:call-shutdown event route found");
245
if (_data.cs_route_number > 0 && event_rt.rlist[_data.cs_route_number] == NULL)
247
LM_INFO("cnxcc:call-shutdown route is empty");
248
_data.cs_route_number = -1;
251
if (_data.check_period <= 0)
253
LM_INFO("credit_check_period cannot be less than 1 second");
257
_data.time.credit_data_by_client = shm_malloc(sizeof(struct str_hash_table));
258
_data.time.call_data_by_cid = shm_malloc(sizeof(struct str_hash_table));
259
_data.money.credit_data_by_client = shm_malloc(sizeof(struct str_hash_table));
260
_data.money.call_data_by_cid = shm_malloc(sizeof(struct str_hash_table));
261
_data.channel.credit_data_by_client = shm_malloc(sizeof(struct str_hash_table));
262
_data.channel.call_data_by_cid = shm_malloc(sizeof(struct str_hash_table));
264
_data.stats = (stats_t *) shm_malloc(sizeof(stats_t));
268
LM_ERR("Error allocating shared memory stats\n");
272
_data.stats->active = 0;
273
_data.stats->dropped = 0;
274
_data.stats->total = 0;
276
if (init_hashtable(_data.time.credit_data_by_client) != 0)
279
if (init_hashtable(_data.time.call_data_by_cid) != 0)
282
if (init_hashtable(_data.money.credit_data_by_client) != 0)
285
if (init_hashtable(_data.money.call_data_by_cid) != 0)
288
if (init_hashtable(_data.channel.credit_data_by_client) != 0)
291
if (init_hashtable(_data.channel.call_data_by_cid) != 0)
294
lock_init(&_data.lock);
295
lock_init(&_data.time.lock);
296
lock_init(&_data.money.lock);
297
lock_init(&_data.channel.lock);
299
register_mi_cmd(mi_credit_control_stats, "cnxcc_stats", NULL, NULL, 0);
302
* One for time based monitoring
303
* One for money based monitoring
305
register_dummy_timers(NUMBER_OF_TIMERS);
307
if (rpc_register_array(ul_rpc) != 0)
309
LM_ERR("Failed registering RPC commands\n");
313
if (load_dlg_api(&_dlgbinds) != 0)
315
LM_ERR("Error loading dialog API\n");
319
_dlgbinds.register_dlgcb(NULL, DLGCB_CREATED, dialog_created_callback, NULL, NULL);
321
register_select_table(sel_declaration);
326
static int child_init(int rank)
328
if (rank != PROC_MAIN)
332
if(fork_dummy_timer(PROC_TIMER, "CNXCC TB TIMER", 1,
333
check_calls_by_money, NULL, _data.check_period) < 0)
335
LM_ERR("failed to register TB TIMER routine as process\n");
339
if(fork_dummy_timer(PROC_TIMER, "CNXCC MB TIMER", 1,
340
check_calls_by_time, NULL, _data.check_period) < 0)
342
LM_ERR("failed to register MB TIMER routine as process\n");
349
static int init_hashtable(struct str_hash_table *ht)
351
if (shm_str_hash_alloc(ht, HT_SIZE) != 0)
353
LM_ERR("Error allocating shared memory hashtable\n");
362
static void dialog_created_callback(struct dlg_cell *cell, int type, struct dlg_cb_params *params)
364
struct sip_msg *msg = NULL;
366
msg = params->direction == SIP_REPLY ? params->rpl : params->req;
370
LM_ERR("Error getting direction of SIP msg\n");
374
if (isflagset(msg, _data.ctrl_flag) == -1)
376
LM_DBG("Flag is not set for this message. Ignoring\n");
380
LM_DBG("Dialog created for CID [%.*s]", cell->callid.len, cell->callid.s);
382
_dlgbinds.register_dlgcb(cell, DLGCB_CONFIRMED, dialog_confirmed_callback, NULL, NULL);
383
_dlgbinds.register_dlgcb(cell, DLGCB_TERMINATED|DLGCB_FAILED|DLGCB_EXPIRED, dialog_terminated_callback, NULL, NULL);
385
setup_billing(&cell->callid, cell->h_entry, cell->h_id);
388
static void dialog_confirmed_callback(struct dlg_cell *cell, int type, struct dlg_cb_params *params)
390
LM_DBG("Dialog confirmed for CID [%.*s]", cell->callid.len, cell->callid.s);
392
start_billing(&cell->callid, cell->tag);
395
static void dialog_terminated_callback(struct dlg_cell *cell, int type, struct dlg_cb_params *params)
397
LM_DBG("Dialog terminated for CID [%.*s]", cell->callid.len, cell->callid.s);
399
stop_billing(&cell->callid);
402
static void notify_call_termination(str *callid, str *from_tag, str *to_tag)
404
struct run_act_ctx ra_ctx;
407
if (_data.cs_route_number < 0)
410
if (faked_msg_init_with_dlg_info(callid, from_tag, to_tag, &msg) != 0)
412
LM_ERR("[%.*s]: error generating faked sip message\n", callid->len, callid->s);
416
init_run_actions_ctx(&ra_ctx);
417
//run_top_route(event_rt.rlist[_data.cs_route_number], msg, &ra_ctx);
419
if (run_actions(&ra_ctx, event_rt.rlist[_data.cs_route_number], msg) < 0)
420
LM_ERR("Error executing cnxcc:call-shutdown route");
423
int try_get_credit_data_entry(str *client_id, credit_data_t **credit_data)
425
struct str_hash_entry *cd_entry = NULL;
426
hash_tables_t *hts = NULL;
431
lock_get(&hts->lock);
433
cd_entry = str_hash_get(hts->credit_data_by_client, client_id->s, client_id->len);
435
if (cd_entry != NULL)
437
*credit_data = cd_entry->u.p;
438
lock_release(&hts->lock);
442
lock_release(&hts->lock);
446
lock_get(&hts->lock);
448
cd_entry = str_hash_get(hts->credit_data_by_client, client_id->s, client_id->len);
450
if (cd_entry != NULL)
452
*credit_data = cd_entry->u.p;
453
lock_release(&hts->lock);
457
lock_release(&hts->lock);
460
hts = &_data.channel;
461
lock_get(&hts->lock);
463
cd_entry = str_hash_get(hts->credit_data_by_client, client_id->s, client_id->len);
465
if (cd_entry != NULL)
467
*credit_data = cd_entry->u.p;
468
lock_release(&hts->lock);
472
lock_release(&hts->lock);
477
int try_get_call_entry(str *callid, call_t **call, hash_tables_t **hts)
479
struct str_hash_entry *call_entry = NULL;
485
lock_get(&(*hts)->lock);
487
call_entry = str_hash_get((*hts)->call_data_by_cid, callid->s, callid->len);
489
if (call_entry != NULL)
491
*call = call_entry->u.p;
492
lock_release(&(*hts)->lock);
496
lock_release(&(*hts)->lock);
500
lock_get(&(*hts)->lock);
502
call_entry = str_hash_get((*hts)->call_data_by_cid, callid->s, callid->len);
504
if (call_entry != NULL)
506
*call = call_entry->u.p;
507
lock_release(&(*hts)->lock);
511
lock_release(&(*hts)->lock);
514
*hts = &_data.channel;
515
lock_get(&(*hts)->lock);
517
call_entry = str_hash_get((*hts)->call_data_by_cid, callid->s, callid->len);
519
if (call_entry != NULL)
521
*call = call_entry->u.p;
522
lock_release(&(*hts)->lock);
526
lock_release(&(*hts)->lock);
531
static void stop_billing(str *callid)
533
struct str_hash_entry *cd_entry = NULL;
535
hash_tables_t *hts = NULL;
536
credit_data_t *credit_data = NULL;
539
* Search call data by call-id
541
if (try_get_call_entry(callid, &call, &hts) != 0)
543
LM_ERR("Call [%.*s] not found", callid->len, callid->s);
549
LM_ERR("[%.*s] call pointer is null", callid->len, callid->s);
555
LM_ERR("[%.*s] result hashtable pointer is null", callid->len, callid->s);
559
lock_get(&hts->lock);
562
* Search credit_data by client_id
564
cd_entry = str_hash_get(hts->credit_data_by_client, call->client_id.s, call->client_id.len);
566
if (cd_entry == NULL)
568
LM_ERR("Credit data not found for CID [%.*s], client-ID [%.*s]\n", callid->len, callid->s, call->client_id.len, call->client_id.s);
569
lock_release(&hts->lock);
573
credit_data = (credit_data_t *) cd_entry->u.p;
575
if (credit_data == NULL)
577
LM_ERR("[%.*s]: credit_data pointer is null", callid->len, callid->s);
578
lock_release(&hts->lock);
582
lock_release(&hts->lock);
585
* Update calls statistics
587
lock_get(&_data.lock);
589
_data.stats->active--;
590
_data.stats->total--;
592
lock_release(&_data.lock);
594
lock(&credit_data->lock);
596
LM_DBG("Call [%.*s] of client-ID [%.*s], ended\n", callid->len, callid->s, call->client_id.len, call->client_id.s);
599
* This call just ended and we need to remove it from the summ.
603
credit_data->concurrent_calls--;
604
credit_data->ended_calls_consumed_amount += call->consumed_amount;
607
credit_data->number_of_calls--;
609
if (credit_data->concurrent_calls < 0)
611
LM_ERR("[BUG]: number of concurrent calls dropped to negative value: %d", credit_data->concurrent_calls);
614
if (credit_data->number_of_calls < 0)
616
LM_ERR("[BUG]: number of calls dropped to negative value: %d", credit_data->number_of_calls);
620
* Remove (and free) the call from the list of calls of the current credit_data
622
clist_rm(call, next, prev);
626
* In case there are no active calls for a certain client, we remove the client-id from the hash table.
627
* This way, we can save memory for useful clients.
629
if (credit_data->number_of_calls == 0)
631
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);
635
* Remove the credit_data_t from the hash table
637
str_hash_del(cd_entry);
639
lock_release(&hts->lock);
642
* Free client_id in list's root
644
shm_free(credit_data->call_list->client_id.s);
645
shm_free(credit_data->call_list);
648
* Release the lock since we are going to free the entry down below
650
lock_release(&credit_data->lock);
653
* Free the whole entry
655
free_credit_data_hash_entry(cd_entry);
658
* return without releasing the acquired lock over credit_data. Why? Because we just freed it.
663
lock_release(&credit_data->lock);
666
static void setup_billing(str *callid, unsigned int h_entry, unsigned int h_id)
669
hash_tables_t *hts = NULL;
671
LM_DBG("Creating dialog for [%.*s], h_id [%u], h_entry [%u]", callid->len, callid->s, h_id, h_entry);
673
// lock_get(&_data.lock);
676
* Search call data by call-id
678
if (try_get_call_entry(callid, &call, &hts) != 0)
680
LM_ERR("Call [%.*s] not found", callid->len, callid->s);
686
LM_ERR("[%.*s] call pointer is null", callid->len, callid->s);
692
LM_ERR("[%.*s] result hashtable pointer is null", callid->len, callid->s);
697
* Update calls statistics
699
lock_get(&_data.lock);
701
_data.stats->active++;
702
_data.stats->total++;
704
lock_release(&_data.lock);
706
lock_get(&call->lock);
708
call->dlg_h_entry = h_entry;
709
call->dlg_h_id = h_id;
711
LM_DBG("Call [%.*s] from client [%.*s], created\n", callid->len, callid->s, call->client_id.len, call->client_id.s);
713
lock_release(&call->lock);
716
static void start_billing(str *callid, str tags[2])
718
struct str_hash_entry *cd_entry = NULL;
720
hash_tables_t *hts = NULL;
721
credit_data_t *credit_data = NULL;
723
LM_DBG("Billing started for call [%.*s]", callid->len, callid->s);
725
// lock_get(&_data.lock);
728
* Search call data by call-id
730
if (try_get_call_entry(callid, &call, &hts) != 0)
732
LM_ERR("Call [%.*s] not found", callid->len, callid->s);
738
LM_ERR("[%.*s] call pointer is null", callid->len, callid->s);
744
LM_ERR("[%.*s] result hashtable pointer is null", callid->len, callid->s);
748
lock_get(&hts->lock);
751
* Search credit_data by client_id
753
cd_entry = str_hash_get(hts->credit_data_by_client, call->client_id.s, call->client_id.len);
755
if (cd_entry == NULL)
757
LM_ERR("Credit data not found for CID [%.*s], client-ID [%.*s]\n", callid->len, callid->s, call->client_id.len, call->client_id.s);
758
lock_release(&hts->lock);
762
credit_data = (credit_data_t *) cd_entry->u.p;
764
if (credit_data == NULL)
766
LM_ERR("[%.*s]: credit_data pointer is null", callid->len, callid->s);
767
lock_release(&hts->lock);
771
lock_release(&hts->lock);
773
lock(&credit_data->lock);
776
* Now that the call is confirmed, we can increase the count of "concurrent_calls".
777
* This will impact in the discount rate performed by the check_calls() function.
780
credit_data->concurrent_calls++;
782
if (credit_data->max_amount == 0)
783
credit_data->max_amount = call->max_amount; // first time setup
785
if (call->max_amount > credit_data->max_amount)
787
LM_ALERT("Maximum-speak-time/credit changed, maybe a credit reload? %f > %f. Client [%.*s]", call->max_amount, credit_data->max_amount,
788
call->client_id.len, call->client_id.s);
790
credit_data->max_amount += call->max_amount - credit_data->max_amount;
794
* Update max_amount, discounting what was already consumed by other calls of the same client
797
call->max_amount = credit_data->max_amount - credit_data->consumed_amount;
799
lock_release(&credit_data->lock);
801
lock_get(&call->lock);
804
* Store from-tag value
806
if (shm_str_dup(&call->sip_data.from_tag, &tags[0]) != 0)
808
LM_ERR("No more pkg memory\n");
815
if (shm_str_dup(&call->sip_data.to_tag, &tags[1]) != 0)
817
LM_ERR("No more pkg memory\n");
821
call->start_timestamp = get_current_timestamp();
822
call->confirmed = TRUE;
824
LM_DBG("Call [%.*s] from client [%.*s], confirmed\n", callid->len, callid->s, call->client_id.len, call->client_id.s);
827
lock_release(&call->lock);
831
void terminate_all_calls(credit_data_t *credit_data)
836
clist_foreach_safe(credit_data->call_list, call, tmp, next)
838
LM_DBG("Killing call with CID [%.*s]\n", call->sip_data.callid.len, call->sip_data.callid.s);
841
* Update number of calls forced to end
843
_data.stats->dropped++;
845
terminate_call(call);
850
* WARNING: When calling this function, the proper lock should have been acquired
852
static void free_call(call_t *call)
854
struct str_hash_entry *e = NULL;
856
LM_DBG("Freeing call [%.*s]\n", call->sip_data.callid.len, call->sip_data.callid.s);
858
e = str_hash_get(_data.money.call_data_by_cid, call->sip_data.callid.s, call->sip_data.callid.len);
862
e = str_hash_get(_data.time.call_data_by_cid, call->sip_data.callid.s, call->sip_data.callid.len);
866
e = str_hash_get(_data.channel.call_data_by_cid, call->sip_data.callid.s, call->sip_data.callid.len);
870
LM_ERR("Call [%.*s] not found. Couldn't be able to free it from hashtable", call->sip_data.callid.len, call->sip_data.callid.s);
881
str_shm_free_if_not_null(call->sip_data.callid);
882
str_shm_free_if_not_null(call->sip_data.to_tag);
883
str_shm_free_if_not_null(call->sip_data.from_tag);
889
* WARNING: When calling this function, the proper lock should have been acquired
891
static void free_credit_data_hash_entry(struct str_hash_entry *e)
894
// shm_free(((credit_data_t *) e->u.p)->call);
899
static int shm_str_hash_alloc(struct str_hash_table *ht, int size)
901
ht->table = shm_malloc(sizeof(struct str_hash_head) * size);
910
static credit_data_t *get_or_create_credit_data_entry(str *client_id, credit_type_t type)
912
struct str_hash_table *ht = NULL;
913
gen_lock_t *lock = NULL;
914
struct str_hash_entry *e = NULL;
919
ht = _data.money.credit_data_by_client;
920
lock = &_data.money.lock;
923
ht = _data.time.credit_data_by_client;
924
lock = &_data.time.lock;
927
ht = _data.channel.credit_data_by_client;
928
lock = &_data.channel.lock;
931
LM_ERR("Something went terribly wrong");
937
e = str_hash_get(ht, client_id->s, client_id->len);
941
* Alloc new call_array_t if it doesn't exist
945
LM_DBG("Found key %.*s in hash table\n", e->key.len, e->key.s);
949
credit_data_t *credit_data = NULL;
950
e = shm_malloc(sizeof(struct str_hash_entry));
954
LM_ERR("No shared memory left\n");
958
if (shm_str_dup(&e->key, client_id) != 0)
960
LM_ERR("No shared memory left\n");
965
e->u.p = (void *) shm_malloc(sizeof(credit_data_t));
966
credit_data = (credit_data_t *) e->u.p;
968
lock_init(&credit_data->lock);
970
credit_data->call_list = shm_malloc(sizeof(call_t));
972
if (credit_data->call_list == NULL)
974
LM_ERR("No shared memory left\n");
978
credit_data->max_amount = 0;
979
credit_data->concurrent_calls = 0;
980
credit_data->consumed_amount = 0;
981
credit_data->ended_calls_consumed_amount= 0;
982
credit_data->number_of_calls = 0;
984
credit_data->type = type;
987
* Copy the client_id value to the root of the calls list.
988
* This will be used later to get the credit_data_t of the
989
* call when it is being searched by call ID.
991
if (shm_str_dup(&credit_data->call_list->client_id, client_id) != 0)
993
LM_ERR("No shared memory left\n");
997
clist_init(credit_data->call_list, next, prev);
1000
str_hash_add(ht, e);
1003
LM_DBG("Call didn't exist. Allocated new entry\n");
1006
return (credit_data_t *) e->u.p;
1009
int terminate_call(call_t *call)
1011
LM_DBG("Got kill signal for call [%.*s] client [%.*s] h_id [%u] h_entry [%u]. Dropping it now\n",
1012
call->sip_data.callid.len,
1013
call->sip_data.callid.s,
1014
call->client_id.len,
1019
struct mi_root *root, *result = NULL;
1020
struct mi_node *node, *node1 = NULL;
1021
struct mi_cmd *end_dlg_cmd = NULL;
1023
root = init_mi_tree(0, 0, 0);
1026
LM_ERR("Error initializing tree to terminate call\n");
1032
node1 = addf_mi_node_child(node, MI_DUP_VALUE, MI_SSTR("h_entry"), "%u", call->dlg_h_entry);
1035
LM_ERR("Error initializing h_entry node to terminate call\n");
1039
node1 = addf_mi_node_child(node, MI_DUP_VALUE, MI_SSTR("h_id"), "%u", call->dlg_h_id);
1042
LM_ERR("Error initializing dlg_h_id node to terminate call\n");
1046
end_dlg_cmd = lookup_mi_cmd(MI_SSTR("dlg_end_dlg"));
1049
LM_ERR("Error initializing dlg_end_dlg command\n");
1053
result = run_mi_cmd(end_dlg_cmd, root);
1056
LM_ERR("Error executing dlg_end_dlg command\n");
1060
if (result->code == 200)
1062
LM_DBG("dlg_end_dlg sent to call [%.*s]\n", call->sip_data.callid.len, call->sip_data.callid.s);
1064
free_mi_tree(result);
1066
notify_call_termination(&call->sip_data.callid, &call->sip_data.from_tag, &call->sip_data.to_tag);
1071
LM_ERR("Error executing dlg_end_dlg command. Return code was [%d]\n", result->code);
1079
static call_t *alloc_new_call_by_money(credit_data_t *credit_data,
1080
struct sip_msg *msg, double credit, double cost_per_second, int initial_pulse, int final_pulse)
1082
call_t *call = NULL;
1084
lock_get(&credit_data->lock);
1086
if (credit_data->call_list == NULL)
1088
LM_ERR("Credit data call list is NULL\n");
1092
call = shm_malloc(sizeof(call_t));
1095
LM_ERR("No shared memory left\n");
1099
if ( (!msg->callid && parse_headers(msg, HDR_CALLID_F, 0) != 0) ||
1100
shm_str_dup(&call->sip_data.callid, &msg->callid->body) != 0 )
1102
LM_ERR("Error processing CALLID hdr\n");
1106
call->sip_data.to_tag.s = NULL;
1107
call->sip_data.to_tag.len = 0;
1108
call->sip_data.from_tag.s = NULL;
1109
call->sip_data.from_tag.len = 0;
1111
call->consumed_amount = initial_pulse * cost_per_second;
1112
call->confirmed = FALSE;
1113
call->max_amount = credit;
1115
call->money_based.cost_per_second = cost_per_second;
1116
call->money_based.initial_pulse = initial_pulse;
1117
call->money_based.final_pulse = final_pulse;
1120
* Reference the client_id from the root of the list
1122
call->client_id.s = credit_data->call_list->client_id.s;
1123
call->client_id.len = credit_data->call_list->client_id.len;
1126
* Insert the newly created call to the list of calls
1128
clist_insert(credit_data->call_list, call, next, prev);
1130
lock_init(&call->lock);
1133
* Increase the number of calls for this client. This call is not yet confirmed.
1135
credit_data->number_of_calls++;
1137
lock_release(&credit_data->lock);
1139
LM_DBG("New call allocated for client [%.*s]\n", call->client_id.len, call->client_id.s);
1144
lock_release(&credit_data->lock);
1148
static call_t *alloc_new_call_by_time(credit_data_t *credit_data, struct sip_msg *msg, int max_secs)
1150
call_t *call = NULL;
1152
lock_get(&credit_data->lock);
1154
if (credit_data->call_list == NULL)
1156
LM_ERR("Credit data call list is NULL\n");
1160
call = shm_malloc(sizeof(call_t));
1163
LM_ERR("No shared memory left\n");
1167
if ( (!msg->callid && parse_headers(msg, HDR_CALLID_F, 0) != 0) ||
1168
shm_str_dup(&call->sip_data.callid, &msg->callid->body) != 0 )
1170
LM_ERR("Error processing CALLID hdr\n");
1174
call->sip_data.to_tag.s = NULL;
1175
call->sip_data.to_tag.len = 0;
1176
call->sip_data.from_tag.s = NULL;
1177
call->sip_data.from_tag.len = 0;
1179
call->consumed_amount = 0;
1180
call->confirmed = FALSE;
1181
call->max_amount = max_secs;
1184
* Reference the client_id from the root of the list
1186
call->client_id.s = credit_data->call_list->client_id.s;
1187
call->client_id.len = credit_data->call_list->client_id.len;
1190
* Insert the newly created call to the list of calls
1192
clist_insert(credit_data->call_list, call, next, prev);
1194
lock_init(&call->lock);
1197
* Increase the number of calls for this client. This call is not yet confirmed.
1199
credit_data->number_of_calls++;
1201
lock_release(&credit_data->lock);
1203
LM_DBG("New call allocated for client [%.*s]\n", call->client_id.len, call->client_id.s);
1208
lock_release(&credit_data->lock);
1212
static call_t *alloc_new_call_by_channel(credit_data_t *credit_data, struct sip_msg *msg, int max_chan)
1214
call_t *call = NULL;
1216
lock_get(&credit_data->lock);
1218
if (credit_data->call_list == NULL)
1220
LM_ERR("Credit data call list is NULL\n");
1224
call = shm_malloc(sizeof(call_t));
1227
LM_ERR("No shared memory left\n");
1231
if ( (!msg->callid && parse_headers(msg, HDR_CALLID_F, 0) != 0) ||
1232
shm_str_dup(&call->sip_data.callid, &msg->callid->body) != 0 )
1234
LM_ERR("Error processing CALLID hdr\n");
1238
call->sip_data.to_tag.s = NULL;
1239
call->sip_data.to_tag.len = 0;
1240
call->sip_data.from_tag.s = NULL;
1241
call->sip_data.from_tag.len = 0;
1243
call->consumed_amount = 0;
1244
call->confirmed = FALSE;
1245
call->max_amount = max_chan;
1248
* Reference the client_id from the root of the list
1250
call->client_id.s = credit_data->call_list->client_id.s;
1251
call->client_id.len = credit_data->call_list->client_id.len;
1254
* Insert the newly created call to the list of calls
1256
clist_insert(credit_data->call_list, call, next, prev);
1258
lock_init(&call->lock);
1261
* Increase the number of calls for this client. This call is not yet confirmed.
1263
credit_data->number_of_calls++;
1265
lock_release(&credit_data->lock);
1267
LM_DBG("New call allocated for client [%.*s]\n", call->client_id.len, call->client_id.s);
1273
lock_release(&credit_data->lock);
1277
static int add_call_by_cid(str *cid, call_t *call, credit_type_t type)
1279
struct str_hash_table *ht = NULL;
1280
gen_lock_t *lock = NULL;
1281
struct str_hash_entry *e = NULL;
1286
ht = _data.money.call_data_by_cid;
1287
lock = &_data.money.lock;
1290
ht = _data.time.call_data_by_cid;
1291
lock = &_data.time.lock;
1293
case CREDIT_CHANNEL:
1294
ht = _data.channel.call_data_by_cid;
1295
lock = &_data.channel.lock;
1298
LM_ERR("Something went terribly wrong");
1302
e = str_hash_get(ht, cid->s, cid->len);
1306
LM_DBG("e != NULL\n");
1308
call_t *value = (call_t *) e->u.p;
1312
LM_ERR("Value of CID [%.*s] is NULL\n", cid->len, cid->s);
1316
LM_WARN("value cid: len=%d | value [%.*s]", value->sip_data.callid.len, value->sip_data.callid.len, value->sip_data.callid.s);
1317
LM_WARN("added cid: len=%d | value [%.*s]", cid->len, cid->len, cid->s);
1319
if (value->sip_data.callid.len != cid->len ||
1320
strncasecmp(value->sip_data.callid.s, cid->s, cid->len) != 0)
1322
LM_ERR("Value of CID is [%.*s] and differs from value being added [%.*s]\n", cid->len, cid->s,
1323
value->sip_data.callid.len, value->sip_data.callid.s);
1327
LM_DBG("CID already present\n");
1332
e = shm_malloc(sizeof(struct str_hash_entry));
1336
LM_ERR("No shared memory left\n");
1340
if (shm_str_dup(&e->key, cid) != 0)
1342
LM_ERR("No shared memory left\n");
1349
str_hash_add(ht, e);
1355
static inline void set_ctrl_flag(struct sip_msg* msg)
1357
if (_data.ctrl_flag != -1)
1359
LM_DBG("Flag set!\n");
1360
setflag(msg, _data.ctrl_flag);
1364
static inline int get_pv_value(struct sip_msg* msg, pv_spec_t* spec, pv_value_t* value)
1366
if (pv_get_spec_value(msg, spec, value) != 0)
1368
LM_ERR("Can't get PV's value\n");
1375
static int set_max_credit(struct sip_msg* msg,
1376
char *str_pv_client,
1377
char *str_pv_credit, char *str_pv_cps,
1378
char *str_pv_inip, char *str_pv_finp)
1380
credit_data_t *credit_data = NULL;
1381
call_t *call = NULL;
1383
pv_spec_t *client_id_spec = (pv_spec_t *) str_pv_client,
1384
*credit_spec = (pv_spec_t *) str_pv_credit,
1385
*cps_spec = (pv_spec_t *) str_pv_cps,
1386
*initial_pulse_spec = (pv_spec_t *) str_pv_inip,
1387
*final_pulse_spec = (pv_spec_t *) str_pv_finp;
1389
pv_value_t client_id_val,
1396
cost_per_second = 0;
1398
unsigned int initial_pulse = 0,
1401
if (msg->first_line.type == SIP_REQUEST && msg->first_line.u.request.method_value == METHOD_INVITE)
1403
if (has_to_tag(msg))
1405
LM_ERR("INVITE is a reINVITE\n");
1409
if (pv_get_spec_value(msg, client_id_spec, &client_id_val) != 0)
1411
LM_ERR("Can't get client_id's value\n");
1415
if (pv_get_spec_value(msg, credit_spec, &credit_val) != 0)
1417
LM_ERR("Can't get credit's value\n");
1421
credit = str2double(&credit_val.rs);
1425
LM_ERR("credit value must be > 0: %f", credit);
1429
if (pv_get_spec_value(msg, cps_spec, &cps_val) != 0)
1431
LM_ERR("Can't get cost_per_sec's value\n");
1435
cost_per_second = str2double(&cps_val.rs);
1437
if (cost_per_second <= 0)
1439
LM_ERR("cost_per_second value must be > 0: %f", cost_per_second);
1443
if (pv_get_spec_value(msg, initial_pulse_spec, &initial_pulse_val) != 0)
1445
LM_ERR("Can't get initial_pulse's value\n");
1449
if (str2int(&initial_pulse_val.rs, &initial_pulse) != 0)
1451
LM_ERR("initial_pulse value is invalid: %.*s", initial_pulse_val.rs.len, initial_pulse_val.rs.s);
1455
if (pv_get_spec_value(msg, final_pulse_spec, &final_pulse_val) != 0)
1457
LM_ERR("Can't get final_pulse's value\n");
1461
if (str2int(&final_pulse_val.rs, &final_pulse) != 0)
1463
LM_ERR("final_pulse value is invalid: %.*s", final_pulse_val.rs.len, final_pulse_val.rs.s);
1467
if (client_id_val.rs.len == 0 || client_id_val.rs.s == NULL)
1469
LM_ERR("[%.*s]: client ID cannot be null\n", msg->callid->body.len, msg->callid->body.s);
1473
LM_DBG("Setting up new call for client [%.*s], max-credit[%f], "
1474
"cost-per-sec[%f], initial-pulse [%d], "
1475
"final-pulse [%d], call-id[%.*s]\n", client_id_val.rs.len, client_id_val.rs.s,
1477
cost_per_second, initial_pulse,
1478
final_pulse, msg->callid->body.len, msg->callid->body.s);
1481
if ((credit_data = get_or_create_credit_data_entry(&client_id_val.rs, CREDIT_MONEY)) == NULL)
1483
LM_ERR("Error retrieving credit data from shared memory for client [%.*s]\n", client_id_val.rs.len, client_id_val.rs.s);
1487
if ((call = alloc_new_call_by_money(credit_data, msg, credit, cost_per_second, initial_pulse, final_pulse)) == NULL)
1489
LM_ERR("Unable to allocate new call for client [%.*s]\n", client_id_val.rs.len, client_id_val.rs.s);
1493
if (add_call_by_cid(&call->sip_data.callid, call, CREDIT_MONEY) != 0)
1495
LM_ERR("Unable to allocate new cid_by_client for client [%.*s]\n", client_id_val.rs.len, client_id_val.rs.s);
1501
LM_ALERT("MSG was not an INVITE\n");
1508
static int terminate_all(struct sip_msg* msg, char* str_pv_client)
1510
credit_data_t *credit_data = NULL;
1511
pv_spec_t *client_id_spec = (pv_spec_t *) str_pv_client;
1513
pv_value_t client_id_val;
1515
if (pv_get_spec_value(msg, client_id_spec, &client_id_val) != 0)
1517
LM_ERR("[%.*s]: can't get client_id pvar value\n", msg->callid->body.len, msg->callid->body.s);
1521
if (client_id_val.rs.len == 0 || client_id_val.rs.s == NULL)
1523
LM_ERR("[%.*s]: client ID cannot be null\n", msg->callid->body.len, msg->callid->body.s);
1527
if (try_get_credit_data_entry(&client_id_val.rs, &credit_data) != 0)
1529
LM_DBG("[%.*s] not found\n", msg->callid->body.len, msg->callid->body.s);
1533
terminate_all_calls(credit_data);
1538
static int get_channel_count(struct sip_msg* msg, char* str_pv_client, char* str_pv_chan_count)
1540
credit_data_t *credit_data = NULL;
1541
pv_spec_t *chan_count_spec = (pv_spec_t *) str_pv_chan_count,
1542
*client_id_spec = (pv_spec_t *) str_pv_client;
1544
pv_value_t chan_count_val, client_id_val;
1547
if (pv_get_spec_value(msg, client_id_spec, &client_id_val) != 0)
1549
LM_ERR("[%.*s]: can't get client_id pvar value\n", msg->callid->body.len, msg->callid->body.s);
1553
if (client_id_val.rs.len == 0 || client_id_val.rs.s == NULL)
1555
LM_ERR("[%.*s]: client ID cannot be null\n", msg->callid->body.len, msg->callid->body.s);
1559
if (try_get_credit_data_entry(&client_id_val.rs, &credit_data) == 0)
1560
value = credit_data->number_of_calls;
1562
LM_ALERT("[%.*s] not found\n", msg->callid->body.len, msg->callid->body.s);
1564
if (!pv_is_w(chan_count_spec))
1566
LM_ERR("pvar is not writable");
1570
memset(&chan_count_val, 0, sizeof(chan_count_val));
1572
chan_count_val.flags = PV_VAL_STR;
1575
chan_count_val.rs.s = int2str(value, &chan_count_val.rs.len);
1578
char buff[2] = { '-', '1' };
1579
chan_count_val.rs.s = buff;
1580
chan_count_val.rs.len = 2;
1583
if (pv_set_spec_value(msg, chan_count_spec, 0, &chan_count_val) != 0)
1585
LM_ERR("Error writing value to pvar");
1592
static int set_max_channels(struct sip_msg* msg, char* str_pv_client, char* str_pv_max_chan)
1594
credit_data_t *credit_data = NULL;
1595
call_t *call = NULL;
1596
pv_spec_t *max_chan_spec = (pv_spec_t *) str_pv_max_chan,
1597
*client_id_spec = (pv_spec_t *) str_pv_client;
1598
pv_value_t max_chan_val, client_id_val;
1603
if (parse_headers(msg, HDR_CALLID_F, 0) != 0)
1605
LM_ERR("Error parsing Call-ID");
1609
if (msg->first_line.type == SIP_REQUEST && msg->first_line.u.request.method_value == METHOD_INVITE)
1611
if (has_to_tag(msg))
1613
LM_ERR("INVITE is a reINVITE\n");
1617
if (pv_get_spec_value(msg, max_chan_spec, &max_chan_val) != 0)
1619
LM_ERR("Can't get max_chan pvar value\n");
1622
max_chan = max_chan_val.ri;
1626
LM_ERR("[%.*s] MAX_CHAN cannot be less than or equal to zero: %d\n", msg->callid->body.len, msg->callid->body.s, max_chan);
1630
if (pv_get_spec_value(msg, client_id_spec, &client_id_val) != 0)
1632
LM_ERR("[%.*s]: can't get client_id pvar value\n", msg->callid->body.len, msg->callid->body.s);
1636
if (client_id_val.rs.len == 0 || client_id_val.rs.s == NULL)
1638
LM_ERR("[%.*s]: client ID cannot be null\n", msg->callid->body.len, msg->callid->body.s);
1642
LM_DBG("Setting up new call for client [%.*s], max-chan[%d], call-id[%.*s]\n", client_id_val.rs.len, client_id_val.rs.s,
1644
msg->callid->body.len, msg->callid->body.s);
1646
if ((credit_data = get_or_create_credit_data_entry(&client_id_val.rs, CREDIT_CHANNEL)) == NULL)
1648
LM_ERR("Error retrieving credit data from shared memory for client [%.*s]\n", client_id_val.rs.len, client_id_val.rs.s);
1652
if (credit_data->number_of_calls + 1 > max_chan)
1653
return -2; // you have, between calls being setup plus those established, more than you maximum quota
1655
if (credit_data->concurrent_calls + 1 > max_chan)
1656
return -3; // you have the max amount of established calls already
1658
if ((call = alloc_new_call_by_channel(credit_data, msg, max_chan)) == NULL)
1660
LM_ERR("Unable to allocate new call for client [%.*s]\n", client_id_val.rs.len, client_id_val.rs.s);
1664
if (add_call_by_cid(&call->sip_data.callid, call, CREDIT_CHANNEL) != 0)
1666
LM_ERR("Unable to allocate new cid_by_client for client [%.*s]\n", client_id_val.rs.len, client_id_val.rs.s);
1674
LM_ALERT("MSG was not an INVITE\n");
1679
static int set_max_time(struct sip_msg* msg, char* str_pv_client, char* str_pv_maxsecs)
1681
credit_data_t *credit_data = NULL;
1682
call_t *call = NULL;
1683
pv_spec_t *max_secs_spec = (pv_spec_t *) str_pv_maxsecs,
1684
*client_id_spec = (pv_spec_t *) str_pv_client;
1685
pv_value_t max_secs_val, client_id_val;
1690
if (parse_headers(msg, HDR_CALLID_F, 0) != 0)
1692
LM_ERR("Error parsing Call-ID");
1696
if (msg->first_line.type == SIP_REQUEST && msg->first_line.u.request.method_value == METHOD_INVITE)
1698
if (has_to_tag(msg))
1700
LM_ERR("INVITE is a reINVITE\n");
1704
if (pv_get_spec_value(msg, max_secs_spec, &max_secs_val) != 0)
1706
LM_ERR("Can't get max_secs PV value\n");
1709
max_secs = max_secs_val.ri;
1713
LM_ERR("[%.*s] MAXSECS cannot be less than or equal to zero: %d\n", msg->callid->body.len, msg->callid->body.s, max_secs);
1717
if (pv_get_spec_value(msg, client_id_spec, &client_id_val) != 0)
1719
LM_ERR("[%.*s]: can't get client_id PV value\n", msg->callid->body.len, msg->callid->body.s);
1723
if (client_id_val.rs.len == 0 || client_id_val.rs.s == NULL)
1725
LM_ERR("[%.*s]: client ID cannot be null\n", msg->callid->body.len, msg->callid->body.s);
1729
LM_DBG("Setting up new call for client [%.*s], max-secs[%d], call-id[%.*s]\n", client_id_val.rs.len, client_id_val.rs.s,
1731
msg->callid->body.len, msg->callid->body.s);
1733
if ((credit_data = get_or_create_credit_data_entry(&client_id_val.rs, CREDIT_TIME)) == NULL)
1735
LM_ERR("Error retrieving credit data from shared memory for client [%.*s]\n", client_id_val.rs.len, client_id_val.rs.s);
1739
if ((call = alloc_new_call_by_time(credit_data, msg, max_secs)) == NULL)
1741
LM_ERR("Unable to allocate new call for client [%.*s]\n", client_id_val.rs.len, client_id_val.rs.s);
1745
if (add_call_by_cid(&call->sip_data.callid, call, CREDIT_TIME) != 0)
1747
LM_ERR("Unable to allocate new cid_by_client for client [%.*s]\n", client_id_val.rs.len, client_id_val.rs.s);
1753
LM_ALERT("MSG was not an INVITE\n");
1760
static int update_max_time(struct sip_msg* msg, char* str_pv_client, char* str_pv_secs)
1762
credit_data_t *credit_data = NULL;
1763
pv_spec_t *secs_spec = (pv_spec_t *) str_pv_secs,
1764
*client_id_spec = (pv_spec_t *) str_pv_client;
1765
pv_value_t secs_val, client_id_val;
1770
if (parse_headers(msg, HDR_CALLID_F, 0) != 0)
1772
LM_ERR("Error parsing Call-ID");
1776
if (pv_get_spec_value(msg, secs_spec, &secs_val) != 0)
1778
LM_ERR("Can't get secs PV value\n");
1785
LM_ERR("[%.*s] MAXSECS cannot be less than or equal to zero: %d\n", msg->callid->body.len, msg->callid->body.s, secs);
1789
if (pv_get_spec_value(msg, client_id_spec, &client_id_val) != 0)
1791
LM_ERR("[%.*s]: can't get client_id PV value\n", msg->callid->body.len, msg->callid->body.s);
1795
if (client_id_val.rs.len == 0 || client_id_val.rs.s == NULL)
1797
LM_ERR("[%.*s]: client ID cannot be null\n", msg->callid->body.len, msg->callid->body.s);
1801
LM_DBG("Updating call for client [%.*s], max-secs[%d], call-id[%.*s]\n", client_id_val.rs.len, client_id_val.rs.s,
1803
msg->callid->body.len, msg->callid->body.s);
1807
struct str_hash_table *ht = NULL;
1808
struct str_hash_entry *e = NULL;
1809
ht = _data.time.credit_data_by_client;
1810
double update_fraction = secs;
1811
call_t *call = NULL,
1814
lock_get(&_data.time.lock);
1815
e = str_hash_get(ht, client_id_val.rs.s, client_id_val.rs.len);
1816
lock_release(&_data.time.lock);
1820
LM_ERR("Client [%.*s] was not found\n", client_id_val.rs.len, client_id_val.rs.s);
1824
credit_data = (credit_data_t *) e->u.p;
1826
lock_get(&credit_data->lock);
1828
LM_DBG("Updating max-secs for [%.*s] from [%f] to [%f]\n", e->key.len, e->key.s, credit_data->max_amount, credit_data->max_amount + secs);
1830
credit_data->max_amount += secs;
1832
if (credit_data->number_of_calls > 0)
1833
update_fraction = secs / credit_data->number_of_calls;
1835
clist_foreach_safe(credit_data->call_list, call, tmp_call, next)
1837
if (!call->confirmed)
1840
call->max_amount += update_fraction;
1843
//redit_data->consumed_amount = 0;
1846
lock_release(&credit_data->lock);
1851
static int has_to_tag(struct sip_msg *msg)
1853
if (msg->to == NULL && parse_headers(msg, HDR_TO_F, 0) != 0)
1855
LM_ERR("Cannot parse to-tag\n");
1859
return !(get_to(msg)->tag_value.s == NULL || get_to(msg)->tag_value.len == 0);
1862
static int pv_parse_calls_param(pv_spec_p sp, str *in)
1864
if (sp == NULL || in == NULL || in->len == 0)
1870
if (strncmp("total", in->s, in->len) == 0)
1871
sp->pvp.pvn.u.isname.name.n = CNX_PV_TOTAL;
1876
if (strncmp("active", in->s, in->len) == 0)
1877
sp->pvp.pvn.u.isname.name.n = CNX_PV_ACTIVE;
1882
if (strncmp("dropped", in->s, in->len) == 0)
1883
sp->pvp.pvn.u.isname.name.n = CNX_PV_DROPPED;
1890
sp->pvp.pvn.type = PV_NAME_INTSTR;
1891
sp->pvp.pvn.u.isname.type = 0;
1896
static int pv_get_calls(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
1898
switch(param->pvn.u.isname.name.n)
1901
return pv_get_uintval(msg, param, res, _data.stats->active);
1903
return pv_get_uintval(msg, param, res, _data.stats->total);
1904
case CNX_PV_DROPPED:
1905
return pv_get_uintval(msg, param, res, _data.stats->dropped);
1907
LM_ERR("Unknown PV type %d\n", param->pvn.u.isname.name.n);
1914
static struct mi_root *mi_credit_control_stats(struct mi_root *tree, void *param)
1918
struct mi_root *rpl_tree;
1919
struct mi_node *node, *node1;
1921
rpl_tree = init_mi_tree(200, "OK", 2);
1922
node = &rpl_tree->node;
1924
node1 = add_mi_node_child(node, 0, MI_SSTR("CNX Credit Control"), 0, 0);
1927
LM_ERR("Error creating child node\n");
1931
p = int2str((unsigned long) _data.stats->active, &len);
1934
LM_ERR("Error converting INT to STR\n");
1937
add_mi_node_child(node1, MI_DUP_VALUE, MI_SSTR("active"), p, len);
1939
p = int2str((unsigned long) _data.stats->dropped, &len);
1942
LM_ERR("Error converting INT to STR\n");
1945
add_mi_node_child(node1, MI_DUP_VALUE, MI_SSTR("dropped"), p, len);
1947
p = int2str((unsigned long) _data.stats->total, &len);
1950
LM_ERR("Error converting INT to STR\n");
1954
add_mi_node_child(node1, MI_DUP_VALUE, MI_SSTR("total"), p, len);
1959
return init_mi_tree(500, MI_INTERNAL_ERR, MI_INTERNAL_ERR_LEN);