~ubuntu-branches/debian/sid/kamailio/sid

« back to all changes in this revision

Viewing changes to modules/cnxcc/cnxcc_mod.c

  • Committer: Package Import Robot
  • Author(s): Victor Seva
  • Date: 2014-01-06 11:47:13 UTC
  • mfrom: (1.1.5)
  • Revision ID: package-import@ubuntu.com-20140106114713-t8xidp4arzrnyeya
Tags: 4.1.1-1
* New upstream release
* debian/patches:
  - add upstream fixes
* Added tls outbound websocket autheph dnssec modules
  - openssl exception added to their license
* removing sparc and ia64 from supported archs
  for mono module (Closes: #728915)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id$
 
3
 *
 
4
 * Copyright (C) 2012 Carlos Ruiz Díaz (caruizdiaz.com),
 
5
 *                    ConexionGroup (www.conexiongroup.com)
 
6
 *
 
7
 * This file is part of Kamailio, a free SIP server.
 
8
 *
 
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
 
13
 *
 
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.
 
18
 *
 
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
 
22
 *
 
23
 */
 
24
 
 
25
#include <stdio.h>
 
26
#include <string.h>
 
27
#include <stdlib.h>
 
28
#include <sys/types.h>
 
29
#include <sys/ipc.h>
 
30
#include <unistd.h>
 
31
#include <fcntl.h>
 
32
#include <time.h>
 
33
#include <ctype.h>
 
34
 
 
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"
 
61
 
 
62
#include "cnxcc_mod.h"
 
63
#include "cnxcc.h"
 
64
#include "cnxcc_sip_msg_faker.h"
 
65
#include "cnxcc_check.h"
 
66
#include "cnxcc_rpc.h"
 
67
#include "cnxcc_select.h"
 
68
 
 
69
MODULE_VERSION
 
70
 
 
71
#define HT_SIZE                                         229
 
72
#define MODULE_NAME                                     "cnxcc"
 
73
#define NUMBER_OF_TIMERS                        2
 
74
 
 
75
#define TRUE                                            1
 
76
#define FALSE                                           0
 
77
 
 
78
data_t _data;
 
79
struct dlg_binds _dlgbinds;
 
80
 
 
81
static int fixup_par(void** param, int param_no);
 
82
 
 
83
/*
 
84
 *  module core functions
 
85
 */
 
86
static int mod_init(void);
 
87
static int child_init(int);
 
88
static int init_hashtable(struct str_hash_table *ht);
 
89
 
 
90
/*
 
91
 * Memory management functions
 
92
 */
 
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);
 
95
 
 
96
/*
 
97
 * PV management functions
 
98
 */
 
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);
 
102
 
 
103
/*
 
104
 * Billing management functions
 
105
 */
 
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);
 
112
 
 
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);
 
123
 
 
124
/*
 
125
 * MI interface
 
126
 */
 
127
static struct mi_root *mi_credit_control_stats(struct mi_root *tree, void *param);
 
128
 
 
129
/*
 
130
 * Dialog management callback functions
 
131
 */
 
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);
 
135
 
 
136
static pv_export_t mod_pvs[] =
 
137
{
 
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 }
 
141
};
 
142
 
 
143
static cmd_export_t cmds[] =
 
144
{
 
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},
 
151
 
 
152
        {0,0,0,0,0,0}
 
153
};
 
154
 
 
155
static param_export_t params[] =
 
156
{
 
157
        {"dlg_flag",                            INT_PARAM,                      &_data.ctrl_flag        },
 
158
        {"credit_check_period",         INT_PARAM,                      &_data.check_period     },
 
159
        { 0, 0, 0 }
 
160
};
 
161
 
 
162
static const char* rpc_active_clients_doc[2] =
 
163
{
 
164
        "List of clients with active calls",
 
165
        0
 
166
};
 
167
 
 
168
static const char* rpc_check_client_stats_doc[2] =
 
169
{
 
170
        "Check specific client calls",
 
171
        0
 
172
};
 
173
 
 
174
static const char* rpc_kill_call_doc[2] =
 
175
{
 
176
        "Kill call using its call ID",
 
177
        0
 
178
};
 
179
 
 
180
rpc_export_t ul_rpc[] =
 
181
{
 
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},
 
185
    {0, 0, 0, 0}
 
186
};
 
187
 
 
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},
 
193
 
 
194
        { NULL, SEL_PARAM_STR, STR_NULL, NULL, 0}
 
195
};
 
196
 
 
197
/** module exports */
 
198
struct module_exports exports =
 
199
{
 
200
        MODULE_NAME,
 
201
        DEFAULT_DLFLAGS,        /* dlopen flags */
 
202
        cmds,
 
203
        params,
 
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 */
 
209
        0,
 
210
        0,
 
211
        child_init          /* per-child init function */
 
212
};
 
213
 
 
214
static int fixup_par(void** param, int param_no)
 
215
{
 
216
        str var;
 
217
 
 
218
        var.s   = (char *) *param;
 
219
        var.len = strlen(var.s);
 
220
 
 
221
        if (fixup_pvar_null(param, 1))
 
222
        {
 
223
                LM_ERR("Invalid PV [%.*s] as parameter\n", var.len, var.s);
 
224
                return E_CFG;
 
225
        }
 
226
/*
 
227
        if (((pv_spec_t*)(*param))->setf == NULL)
 
228
        {
 
229
                LM_ERR("[%.*s] has to be writable\n", var.len, var.s);
 
230
                return E_CFG;
 
231
        } */
 
232
 
 
233
        return 0;
 
234
}
 
235
 
 
236
static int mod_init(void)
 
237
{
 
238
        LM_INFO("Loading " MODULE_NAME " module\n");
 
239
 
 
240
        _data.cs_route_number = route_get(&event_rt, "cnxcc:call-shutdown");
 
241
 
 
242
        if (_data.cs_route_number < 0)
 
243
                LM_INFO("No cnxcc:call-shutdown event route found");
 
244
 
 
245
        if (_data.cs_route_number > 0 && event_rt.rlist[_data.cs_route_number] == NULL)
 
246
        {
 
247
                LM_INFO("cnxcc:call-shutdown route is empty");
 
248
                _data.cs_route_number   = -1;
 
249
        }
 
250
 
 
251
        if (_data.check_period <= 0)
 
252
        {
 
253
                LM_INFO("credit_check_period cannot be less than 1 second");
 
254
                return -1;
 
255
        }
 
256
 
 
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));
 
263
 
 
264
        _data.stats                                                     = (stats_t *) shm_malloc(sizeof(stats_t));
 
265
 
 
266
        if (!_data.stats)
 
267
        {
 
268
                LM_ERR("Error allocating shared memory stats\n");
 
269
                return -1;
 
270
        }
 
271
 
 
272
        _data.stats->active             = 0;
 
273
        _data.stats->dropped    = 0;
 
274
        _data.stats->total              = 0;
 
275
 
 
276
        if (init_hashtable(_data.time.credit_data_by_client) != 0)
 
277
                return -1;
 
278
 
 
279
        if (init_hashtable(_data.time.call_data_by_cid) != 0)
 
280
                return -1;
 
281
 
 
282
        if (init_hashtable(_data.money.credit_data_by_client) != 0)
 
283
                return -1;
 
284
 
 
285
        if (init_hashtable(_data.money.call_data_by_cid) != 0)
 
286
                return -1;
 
287
 
 
288
        if (init_hashtable(_data.channel.credit_data_by_client) != 0)
 
289
                return -1;
 
290
 
 
291
        if (init_hashtable(_data.channel.call_data_by_cid) != 0)
 
292
                return -1;
 
293
 
 
294
        lock_init(&_data.lock);
 
295
        lock_init(&_data.time.lock);
 
296
        lock_init(&_data.money.lock);
 
297
        lock_init(&_data.channel.lock);
 
298
 
 
299
        register_mi_cmd(mi_credit_control_stats, "cnxcc_stats", NULL, NULL, 0);
 
300
 
 
301
        /*
 
302
         * One for time based monitoring
 
303
         * One for money based monitoring
 
304
         */
 
305
        register_dummy_timers(NUMBER_OF_TIMERS);
 
306
 
 
307
        if (rpc_register_array(ul_rpc) != 0)
 
308
        {
 
309
                LM_ERR("Failed registering RPC commands\n");
 
310
                return -1;
 
311
        }
 
312
 
 
313
        if (load_dlg_api(&_dlgbinds) != 0)
 
314
        {
 
315
                LM_ERR("Error loading dialog API\n");
 
316
            return -1;
 
317
        }
 
318
 
 
319
        _dlgbinds.register_dlgcb(NULL, DLGCB_CREATED, dialog_created_callback, NULL, NULL);
 
320
 
 
321
         register_select_table(sel_declaration);
 
322
 
 
323
        return 0;
 
324
}
 
325
 
 
326
static int child_init(int rank)
 
327
{
 
328
        if (rank != PROC_MAIN)
 
329
                return 0;
 
330
 
 
331
 
 
332
        if(fork_dummy_timer(PROC_TIMER, "CNXCC TB TIMER", 1,
 
333
                        check_calls_by_money, NULL, _data.check_period) < 0)
 
334
        {
 
335
                LM_ERR("failed to register TB TIMER routine as process\n");
 
336
                return -1;
 
337
        }
 
338
 
 
339
        if(fork_dummy_timer(PROC_TIMER, "CNXCC MB TIMER", 1,
 
340
                                                                check_calls_by_time, NULL, _data.check_period) < 0)
 
341
        {
 
342
                LM_ERR("failed to register MB TIMER routine as process\n");
 
343
                return -1;
 
344
        }
 
345
 
 
346
        return 0;
 
347
}
 
348
 
 
349
static int init_hashtable(struct str_hash_table *ht)
 
350
{
 
351
        if (shm_str_hash_alloc(ht, HT_SIZE) != 0)
 
352
        {
 
353
                LM_ERR("Error allocating shared memory hashtable\n");
 
354
                return -1;
 
355
        }
 
356
 
 
357
        str_hash_init(ht);
 
358
 
 
359
        return 0;
 
360
}
 
361
 
 
362
static void dialog_created_callback(struct dlg_cell *cell, int type, struct dlg_cb_params *params)
 
363
{
 
364
        struct sip_msg *msg     = NULL;
 
365
 
 
366
        msg     = params->direction == SIP_REPLY ? params->rpl : params->req;
 
367
 
 
368
        if (msg == NULL)
 
369
        {
 
370
                LM_ERR("Error getting direction of SIP msg\n");
 
371
                return;
 
372
        }
 
373
 
 
374
        if (isflagset(msg, _data.ctrl_flag) == -1)
 
375
        {
 
376
                LM_DBG("Flag is not set for this message. Ignoring\n");
 
377
                return;
 
378
        }
 
379
 
 
380
        LM_DBG("Dialog created for CID [%.*s]", cell->callid.len, cell->callid.s);
 
381
 
 
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);
 
384
 
 
385
        setup_billing(&cell->callid, cell->h_entry, cell->h_id);
 
386
}
 
387
 
 
388
static void dialog_confirmed_callback(struct dlg_cell *cell, int type, struct dlg_cb_params *params)
 
389
{
 
390
        LM_DBG("Dialog confirmed for CID [%.*s]", cell->callid.len, cell->callid.s);
 
391
 
 
392
        start_billing(&cell->callid, cell->tag);
 
393
}
 
394
 
 
395
static void dialog_terminated_callback(struct dlg_cell *cell, int type, struct dlg_cb_params *params)
 
396
{
 
397
        LM_DBG("Dialog terminated for CID [%.*s]", cell->callid.len, cell->callid.s);
 
398
 
 
399
        stop_billing(&cell->callid);
 
400
}
 
401
 
 
402
static void notify_call_termination(str *callid, str *from_tag, str *to_tag)
 
403
{
 
404
        struct run_act_ctx ra_ctx;
 
405
        struct sip_msg *msg;
 
406
 
 
407
        if (_data.cs_route_number < 0)
 
408
                return;
 
409
 
 
410
        if (faked_msg_init_with_dlg_info(callid, from_tag, to_tag,  &msg) != 0)
 
411
        {
 
412
                LM_ERR("[%.*s]: error generating faked sip message\n", callid->len, callid->s);
 
413
                return;
 
414
        }
 
415
 
 
416
        init_run_actions_ctx(&ra_ctx);
 
417
        //run_top_route(event_rt.rlist[_data.cs_route_number], msg, &ra_ctx);
 
418
 
 
419
        if (run_actions(&ra_ctx, event_rt.rlist[_data.cs_route_number], msg) < 0)
 
420
                LM_ERR("Error executing cnxcc:call-shutdown route");
 
421
}
 
422
 
 
423
int try_get_credit_data_entry(str *client_id, credit_data_t **credit_data)
 
424
{
 
425
        struct str_hash_entry *cd_entry = NULL;
 
426
        hash_tables_t *hts                              = NULL;
 
427
        *credit_data                                    = NULL;
 
428
 
 
429
        /* by money */
 
430
        hts                                     = &_data.money;
 
431
        lock_get(&hts->lock);
 
432
 
 
433
        cd_entry                        = str_hash_get(hts->credit_data_by_client, client_id->s, client_id->len);
 
434
 
 
435
        if (cd_entry != NULL)
 
436
        {
 
437
                *credit_data    = cd_entry->u.p;
 
438
                lock_release(&hts->lock);
 
439
                return 0;
 
440
        }
 
441
 
 
442
        lock_release(&hts->lock);
 
443
 
 
444
        /* by time */
 
445
        hts                                     = &_data.time;
 
446
        lock_get(&hts->lock);
 
447
 
 
448
        cd_entry                        = str_hash_get(hts->credit_data_by_client, client_id->s, client_id->len);
 
449
 
 
450
        if (cd_entry != NULL)
 
451
        {
 
452
                *credit_data    = cd_entry->u.p;
 
453
                lock_release(&hts->lock);
 
454
                return 0;
 
455
        }
 
456
 
 
457
        lock_release(&hts->lock);
 
458
 
 
459
        /* by channel */
 
460
        hts                                     = &_data.channel;
 
461
        lock_get(&hts->lock);
 
462
 
 
463
        cd_entry                        = str_hash_get(hts->credit_data_by_client, client_id->s, client_id->len);
 
464
 
 
465
        if (cd_entry != NULL)
 
466
        {
 
467
                *credit_data    = cd_entry->u.p;
 
468
                lock_release(&hts->lock);
 
469
                return 0;
 
470
        }
 
471
 
 
472
        lock_release(&hts->lock);
 
473
 
 
474
        return -1;
 
475
}
 
476
 
 
477
int try_get_call_entry(str *callid, call_t **call, hash_tables_t **hts)
 
478
{
 
479
        struct str_hash_entry *call_entry       = NULL;
 
480
 
 
481
        *call                                   = NULL;
 
482
 
 
483
        /* by money */
 
484
        *hts                                    = &_data.money;
 
485
        lock_get(&(*hts)->lock);
 
486
 
 
487
        call_entry                      = str_hash_get((*hts)->call_data_by_cid, callid->s, callid->len);
 
488
 
 
489
        if (call_entry != NULL)
 
490
        {
 
491
                *call   = call_entry->u.p;
 
492
                lock_release(&(*hts)->lock);
 
493
                return 0;
 
494
        }
 
495
 
 
496
        lock_release(&(*hts)->lock);
 
497
 
 
498
        /* by time */
 
499
        *hts                            = &_data.time;
 
500
        lock_get(&(*hts)->lock);
 
501
 
 
502
        call_entry                      = str_hash_get((*hts)->call_data_by_cid, callid->s, callid->len);
 
503
 
 
504
        if (call_entry != NULL)
 
505
        {
 
506
                *call   = call_entry->u.p;
 
507
                lock_release(&(*hts)->lock);
 
508
                return 0;
 
509
        }
 
510
 
 
511
        lock_release(&(*hts)->lock);
 
512
 
 
513
        /* by channel */
 
514
        *hts                            = &_data.channel;
 
515
        lock_get(&(*hts)->lock);
 
516
 
 
517
        call_entry                      = str_hash_get((*hts)->call_data_by_cid, callid->s, callid->len);
 
518
 
 
519
        if (call_entry != NULL)
 
520
        {
 
521
                *call   = call_entry->u.p;
 
522
                lock_release(&(*hts)->lock);
 
523
                return 0;
 
524
        }
 
525
 
 
526
        lock_release(&(*hts)->lock);
 
527
 
 
528
        return -1;
 
529
}
 
530
 
 
531
static void stop_billing(str *callid)
 
532
{
 
533
        struct str_hash_entry *cd_entry         = NULL;
 
534
        call_t *call                                            = NULL;
 
535
        hash_tables_t *hts                                      = NULL;
 
536
        credit_data_t *credit_data                      = NULL;
 
537
 
 
538
        /*
 
539
         * Search call data by call-id
 
540
         */
 
541
        if (try_get_call_entry(callid, &call, &hts) != 0)
 
542
        {
 
543
                LM_ERR("Call [%.*s] not found", callid->len, callid->s);
 
544
                return;
 
545
        }
 
546
 
 
547
        if (call == NULL)
 
548
        {
 
549
                LM_ERR("[%.*s] call pointer is null", callid->len, callid->s);
 
550
                return;
 
551
        }
 
552
 
 
553
        if (hts == NULL)
 
554
        {
 
555
                LM_ERR("[%.*s] result hashtable pointer is null", callid->len, callid->s);
 
556
                return;
 
557
        }
 
558
 
 
559
        lock_get(&hts->lock);
 
560
 
 
561
        /*
 
562
         * Search credit_data by client_id
 
563
         */
 
564
        cd_entry                        = str_hash_get(hts->credit_data_by_client, call->client_id.s, call->client_id.len);
 
565
 
 
566
        if (cd_entry == NULL)
 
567
        {
 
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);
 
570
                return;
 
571
        }
 
572
 
 
573
        credit_data     = (credit_data_t *) cd_entry->u.p;
 
574
 
 
575
        if (credit_data == NULL)
 
576
        {
 
577
                LM_ERR("[%.*s]: credit_data pointer is null", callid->len, callid->s);
 
578
                lock_release(&hts->lock);
 
579
                return;
 
580
        }
 
581
 
 
582
        lock_release(&hts->lock);
 
583
 
 
584
        /*
 
585
         * Update calls statistics
 
586
         */
 
587
        lock_get(&_data.lock);
 
588
 
 
589
        _data.stats->active--;
 
590
        _data.stats->total--;
 
591
 
 
592
        lock_release(&_data.lock);
 
593
 
 
594
        lock(&credit_data->lock);
 
595
 
 
596
        LM_DBG("Call [%.*s] of client-ID [%.*s], ended\n", callid->len, callid->s, call->client_id.len, call->client_id.s);
 
597
 
 
598
        /*
 
599
         * This call just ended and we need to remove it from the summ.
 
600
         */
 
601
        if (call->confirmed)
 
602
        {
 
603
                credit_data->concurrent_calls--;
 
604
                credit_data->ended_calls_consumed_amount += call->consumed_amount;
 
605
        }
 
606
 
 
607
        credit_data->number_of_calls--;
 
608
 
 
609
        if (credit_data->concurrent_calls < 0)
 
610
        {
 
611
                LM_ERR("[BUG]: number of concurrent calls dropped to negative value: %d", credit_data->concurrent_calls);
 
612
        }
 
613
 
 
614
        if (credit_data->number_of_calls < 0)
 
615
        {
 
616
                LM_ERR("[BUG]: number of calls dropped to negative value: %d", credit_data->number_of_calls);
 
617
        }
 
618
 
 
619
        /*
 
620
         * Remove (and free) the call from the list of calls of the current credit_data
 
621
         */
 
622
        clist_rm(call, next, prev);
 
623
        free_call(call);
 
624
 
 
625
        /*
 
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.
 
628
         */
 
629
        if (credit_data->number_of_calls == 0)
 
630
        {
 
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);
 
632
 
 
633
                lock(&hts->lock);
 
634
                /*
 
635
                 * Remove the credit_data_t from the hash table
 
636
                 */
 
637
                str_hash_del(cd_entry);
 
638
 
 
639
                lock_release(&hts->lock);
 
640
 
 
641
                /*
 
642
                 * Free client_id in list's root
 
643
                 */
 
644
                shm_free(credit_data->call_list->client_id.s);
 
645
                shm_free(credit_data->call_list);
 
646
 
 
647
                /*
 
648
                 * Release the lock since we are going to free the entry down below
 
649
                 */
 
650
                lock_release(&credit_data->lock);
 
651
 
 
652
                /*
 
653
                 * Free the whole entry
 
654
                 */
 
655
                free_credit_data_hash_entry(cd_entry);
 
656
 
 
657
                /*
 
658
                 * return without releasing the acquired lock over credit_data. Why? Because we just freed it.
 
659
                 */
 
660
                return;
 
661
        }
 
662
 
 
663
        lock_release(&credit_data->lock);
 
664
}
 
665
 
 
666
static void setup_billing(str *callid, unsigned int h_entry, unsigned int h_id)
 
667
{
 
668
        call_t *call                                            = NULL;
 
669
        hash_tables_t *hts                                      = NULL;
 
670
 
 
671
        LM_DBG("Creating dialog for [%.*s], h_id [%u], h_entry [%u]", callid->len, callid->s, h_id, h_entry);
 
672
 
 
673
//      lock_get(&_data.lock);
 
674
 
 
675
        /*
 
676
         * Search call data by call-id
 
677
         */
 
678
        if (try_get_call_entry(callid, &call, &hts) != 0)
 
679
        {
 
680
                LM_ERR("Call [%.*s] not found", callid->len, callid->s);
 
681
                return;
 
682
        }
 
683
 
 
684
        if (call == NULL)
 
685
        {
 
686
                LM_ERR("[%.*s] call pointer is null", callid->len, callid->s);
 
687
                return;
 
688
        }
 
689
 
 
690
        if (hts == NULL)
 
691
        {
 
692
                LM_ERR("[%.*s] result hashtable pointer is null", callid->len, callid->s);
 
693
                return;
 
694
        }
 
695
 
 
696
        /*
 
697
         * Update calls statistics
 
698
         */
 
699
        lock_get(&_data.lock);
 
700
 
 
701
        _data.stats->active++;
 
702
        _data.stats->total++;
 
703
 
 
704
        lock_release(&_data.lock);
 
705
 
 
706
        lock_get(&call->lock);
 
707
 
 
708
        call->dlg_h_entry               = h_entry;
 
709
        call->dlg_h_id                  = h_id;
 
710
 
 
711
        LM_DBG("Call [%.*s] from client [%.*s], created\n", callid->len, callid->s, call->client_id.len, call->client_id.s);
 
712
 
 
713
        lock_release(&call->lock);
 
714
}
 
715
 
 
716
static void start_billing(str *callid, str tags[2])
 
717
{
 
718
        struct str_hash_entry *cd_entry         = NULL;
 
719
        call_t *call                                            = NULL;
 
720
        hash_tables_t *hts                                      = NULL;
 
721
        credit_data_t *credit_data                      = NULL;
 
722
 
 
723
        LM_DBG("Billing started for call [%.*s]", callid->len, callid->s);
 
724
 
 
725
//      lock_get(&_data.lock);
 
726
 
 
727
        /*
 
728
         * Search call data by call-id
 
729
         */
 
730
        if (try_get_call_entry(callid, &call, &hts) != 0)
 
731
        {
 
732
                LM_ERR("Call [%.*s] not found", callid->len, callid->s);
 
733
                return;
 
734
        }
 
735
 
 
736
        if (call == NULL)
 
737
        {
 
738
                LM_ERR("[%.*s] call pointer is null", callid->len, callid->s);
 
739
                return;
 
740
        }
 
741
 
 
742
        if (hts == NULL)
 
743
        {
 
744
                LM_ERR("[%.*s] result hashtable pointer is null", callid->len, callid->s);
 
745
                return;
 
746
        }
 
747
 
 
748
        lock_get(&hts->lock);
 
749
 
 
750
        /*
 
751
         * Search credit_data by client_id
 
752
         */
 
753
        cd_entry                        = str_hash_get(hts->credit_data_by_client, call->client_id.s, call->client_id.len);
 
754
 
 
755
        if (cd_entry == NULL)
 
756
        {
 
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);
 
759
                return;
 
760
        }
 
761
 
 
762
        credit_data     = (credit_data_t *) cd_entry->u.p;
 
763
 
 
764
        if (credit_data == NULL)
 
765
        {
 
766
                LM_ERR("[%.*s]: credit_data pointer is null", callid->len, callid->s);
 
767
                lock_release(&hts->lock);
 
768
                return;
 
769
        }
 
770
 
 
771
        lock_release(&hts->lock);
 
772
 
 
773
        lock(&credit_data->lock);
 
774
 
 
775
        /*
 
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.
 
778
         *
 
779
         */
 
780
        credit_data->concurrent_calls++;
 
781
 
 
782
        if (credit_data->max_amount == 0)
 
783
                credit_data->max_amount = call->max_amount; // first time setup
 
784
 
 
785
        if (call->max_amount > credit_data->max_amount)
 
786
        {
 
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);
 
789
 
 
790
                credit_data->max_amount += call->max_amount - credit_data->max_amount;
 
791
        }
 
792
 
 
793
        /*
 
794
         * Update max_amount, discounting what was already consumed by other calls of the same client
 
795
         */
 
796
 
 
797
        call->max_amount = credit_data->max_amount - credit_data->consumed_amount;
 
798
 
 
799
        lock_release(&credit_data->lock);
 
800
 
 
801
        lock_get(&call->lock);
 
802
 
 
803
        /*
 
804
         * Store from-tag value
 
805
         */
 
806
        if (shm_str_dup(&call->sip_data.from_tag, &tags[0]) != 0)
 
807
        {
 
808
                LM_ERR("No more pkg memory\n");
 
809
                goto exit;
 
810
        }
 
811
 
 
812
        /*
 
813
         * Store to-tag value
 
814
         */
 
815
        if (shm_str_dup(&call->sip_data.to_tag, &tags[1]) != 0)
 
816
        {
 
817
                LM_ERR("No more pkg memory\n");
 
818
                goto exit;
 
819
        }
 
820
 
 
821
        call->start_timestamp   = get_current_timestamp();
 
822
        call->confirmed                 = TRUE;
 
823
 
 
824
        LM_DBG("Call [%.*s] from client [%.*s], confirmed\n", callid->len, callid->s, call->client_id.len, call->client_id.s);
 
825
 
 
826
exit:
 
827
        lock_release(&call->lock);
 
828
}
 
829
 
 
830
 
 
831
void terminate_all_calls(credit_data_t *credit_data)
 
832
{
 
833
        call_t  *call   = NULL,
 
834
                        *tmp    = NULL;
 
835
 
 
836
        clist_foreach_safe(credit_data->call_list, call, tmp, next)
 
837
        {
 
838
                LM_DBG("Killing call with CID [%.*s]\n", call->sip_data.callid.len, call->sip_data.callid.s);
 
839
 
 
840
                /*
 
841
                 * Update number of calls forced to end
 
842
                 */
 
843
                _data.stats->dropped++;
 
844
 
 
845
                terminate_call(call);
 
846
        }
 
847
}
 
848
 
 
849
/*
 
850
 * WARNING: When calling this function, the proper lock should have been acquired
 
851
 */
 
852
static void free_call(call_t *call)
 
853
{
 
854
        struct str_hash_entry *e        = NULL;
 
855
 
 
856
        LM_DBG("Freeing call [%.*s]\n", call->sip_data.callid.len, call->sip_data.callid.s);
 
857
 
 
858
        e                       = str_hash_get(_data.money.call_data_by_cid, call->sip_data.callid.s, call->sip_data.callid.len);
 
859
 
 
860
        if (e == NULL)
 
861
        {
 
862
                e                       = str_hash_get(_data.time.call_data_by_cid, call->sip_data.callid.s, call->sip_data.callid.len);
 
863
 
 
864
                if (e == NULL)
 
865
                {
 
866
                        e                       = str_hash_get(_data.channel.call_data_by_cid, call->sip_data.callid.s, call->sip_data.callid.len);
 
867
 
 
868
                        if (e == NULL)
 
869
                        {
 
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);
 
871
                                return;
 
872
                        }
 
873
                }
 
874
        }
 
875
 
 
876
        str_hash_del(e);
 
877
 
 
878
        shm_free(e->key.s);
 
879
        shm_free(e);
 
880
 
 
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);
 
884
 
 
885
        shm_free(call);
 
886
}
 
887
 
 
888
/*
 
889
 * WARNING: When calling this function, the proper lock should have been acquired
 
890
 */
 
891
static void free_credit_data_hash_entry(struct str_hash_entry *e)
 
892
{
 
893
        shm_free(e->key.s);
 
894
//      shm_free(((credit_data_t *) e->u.p)->call);
 
895
        shm_free(e->u.p);
 
896
        shm_free(e);
 
897
}
 
898
 
 
899
static int shm_str_hash_alloc(struct str_hash_table *ht, int size)
 
900
{
 
901
        ht->table       = shm_malloc(sizeof(struct str_hash_head) * size);
 
902
 
 
903
        if (!ht->table)
 
904
                return -1;
 
905
 
 
906
        ht->size        = size;
 
907
        return 0;
 
908
}
 
909
 
 
910
static credit_data_t *get_or_create_credit_data_entry(str *client_id, credit_type_t type)
 
911
{
 
912
        struct str_hash_table *ht       = NULL;
 
913
        gen_lock_t *lock                        = NULL;
 
914
        struct str_hash_entry *e        = NULL;
 
915
 
 
916
        switch(type)
 
917
        {
 
918
        case CREDIT_MONEY:
 
919
                ht              = _data.money.credit_data_by_client;
 
920
                lock    =  &_data.money.lock;
 
921
                break;
 
922
        case CREDIT_TIME:
 
923
                ht              = _data.time.credit_data_by_client;
 
924
                lock    =  &_data.time.lock;
 
925
                break;
 
926
        case CREDIT_CHANNEL:
 
927
                ht              = _data.channel.credit_data_by_client;
 
928
                lock    =  &_data.channel.lock;
 
929
                break;
 
930
        default:
 
931
                LM_ERR("Something went terribly wrong");
 
932
                return NULL;
 
933
        }
 
934
 
 
935
 
 
936
        lock_get(lock);
 
937
        e                                                       = str_hash_get(ht, client_id->s, client_id->len);
 
938
        lock_release(lock);
 
939
 
 
940
        /*
 
941
         * Alloc new call_array_t if it doesn't exist
 
942
         */
 
943
        if (e != NULL)
 
944
        {
 
945
                LM_DBG("Found key %.*s in hash table\n", e->key.len, e->key.s);
 
946
        }
 
947
        else
 
948
        {
 
949
                credit_data_t *credit_data      = NULL;
 
950
                e                                                       = shm_malloc(sizeof(struct str_hash_entry));
 
951
 
 
952
                if (e == NULL)
 
953
                {
 
954
                        LM_ERR("No shared memory left\n");
 
955
                        return NULL;
 
956
                }
 
957
 
 
958
                if (shm_str_dup(&e->key, client_id) != 0)
 
959
                {
 
960
                        LM_ERR("No shared memory left\n");
 
961
                        return NULL;
 
962
                }
 
963
 
 
964
                e->flags                                        = 0;
 
965
                e->u.p                                          = (void *) shm_malloc(sizeof(credit_data_t));
 
966
                credit_data                                     = (credit_data_t *) e->u.p;
 
967
 
 
968
                lock_init(&credit_data->lock);
 
969
 
 
970
                credit_data->call_list          = shm_malloc(sizeof(call_t));
 
971
 
 
972
                if (credit_data->call_list == NULL)
 
973
                {
 
974
                        LM_ERR("No shared memory left\n");
 
975
                        return NULL;
 
976
                }
 
977
 
 
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;
 
983
 
 
984
                credit_data->type                                               = type;
 
985
 
 
986
                /*
 
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.
 
990
                 */
 
991
                if (shm_str_dup(&credit_data->call_list->client_id, client_id) != 0)
 
992
                {
 
993
                        LM_ERR("No shared memory left\n");
 
994
                        return NULL;
 
995
                }
 
996
 
 
997
                clist_init(credit_data->call_list, next, prev);
 
998
 
 
999
                lock_get(lock);
 
1000
                str_hash_add(ht, e);
 
1001
                lock_release(lock);
 
1002
 
 
1003
                LM_DBG("Call didn't exist. Allocated new entry\n");
 
1004
        }
 
1005
 
 
1006
        return (credit_data_t *) e->u.p;
 
1007
}
 
1008
 
 
1009
int terminate_call(call_t *call)
 
1010
{
 
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,
 
1015
                                                call->client_id.s,
 
1016
                                                call->dlg_h_id,
 
1017
                                                call->dlg_h_entry);
 
1018
 
 
1019
        struct mi_root *root, *result   = NULL;
 
1020
        struct mi_node *node, *node1    = NULL;
 
1021
        struct mi_cmd *end_dlg_cmd              = NULL;
 
1022
 
 
1023
        root    = init_mi_tree(0, 0, 0);
 
1024
        if (root == NULL)
 
1025
        {
 
1026
                LM_ERR("Error initializing tree to terminate call\n");
 
1027
                goto error;
 
1028
        }
 
1029
 
 
1030
        node    = &root->node;
 
1031
 
 
1032
        node1   = addf_mi_node_child(node, MI_DUP_VALUE, MI_SSTR("h_entry"), "%u", call->dlg_h_entry);
 
1033
        if (node1 == NULL)
 
1034
        {
 
1035
                LM_ERR("Error initializing h_entry node to terminate call\n");
 
1036
                goto error;
 
1037
        }
 
1038
 
 
1039
        node1   = addf_mi_node_child(node, MI_DUP_VALUE, MI_SSTR("h_id"), "%u", call->dlg_h_id);
 
1040
        if (node1 == NULL)
 
1041
        {
 
1042
                LM_ERR("Error initializing dlg_h_id node to terminate call\n");
 
1043
                goto error;
 
1044
        }
 
1045
 
 
1046
        end_dlg_cmd = lookup_mi_cmd(MI_SSTR("dlg_end_dlg"));
 
1047
        if (node == NULL)
 
1048
        {
 
1049
                LM_ERR("Error initializing dlg_end_dlg command\n");
 
1050
                goto error;
 
1051
        }
 
1052
 
 
1053
        result          = run_mi_cmd(end_dlg_cmd, root);
 
1054
        if (result == NULL)
 
1055
        {
 
1056
                LM_ERR("Error executing dlg_end_dlg command\n");
 
1057
                goto error;
 
1058
        }
 
1059
 
 
1060
        if (result->code == 200)
 
1061
        {
 
1062
                LM_DBG("dlg_end_dlg sent to call [%.*s]\n", call->sip_data.callid.len, call->sip_data.callid.s);
 
1063
                free_mi_tree(root);
 
1064
                free_mi_tree(result);
 
1065
 
 
1066
                notify_call_termination(&call->sip_data.callid, &call->sip_data.from_tag, &call->sip_data.to_tag);
 
1067
 
 
1068
                return 0;
 
1069
        }
 
1070
 
 
1071
        LM_ERR("Error executing dlg_end_dlg command. Return code was [%d]\n", result->code);
 
1072
error:
 
1073
        if (root)
 
1074
                free_mi_tree(root);
 
1075
 
 
1076
        return -1;
 
1077
}
 
1078
 
 
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)
 
1081
{
 
1082
        call_t *call            = NULL;
 
1083
 
 
1084
        lock_get(&credit_data->lock);
 
1085
 
 
1086
        if (credit_data->call_list == NULL)
 
1087
        {
 
1088
                LM_ERR("Credit data call list is NULL\n");
 
1089
                goto error;
 
1090
        }
 
1091
 
 
1092
        call                            = shm_malloc(sizeof(call_t));
 
1093
        if (call == NULL)
 
1094
        {
 
1095
                LM_ERR("No shared memory left\n");
 
1096
                goto error;
 
1097
        }
 
1098
 
 
1099
        if ( (!msg->callid && parse_headers(msg, HDR_CALLID_F, 0) != 0) ||
 
1100
                   shm_str_dup(&call->sip_data.callid, &msg->callid->body) != 0 )
 
1101
        {
 
1102
                LM_ERR("Error processing CALLID hdr\n");
 
1103
                goto error;
 
1104
        }
 
1105
 
 
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;
 
1110
 
 
1111
        call->consumed_amount           = initial_pulse * cost_per_second;
 
1112
        call->confirmed                         = FALSE;
 
1113
        call->max_amount                        = credit;
 
1114
 
 
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;
 
1118
 
 
1119
        /*
 
1120
         * Reference the client_id from the root of the list
 
1121
         */
 
1122
        call->client_id.s                       = credit_data->call_list->client_id.s;
 
1123
        call->client_id.len                     = credit_data->call_list->client_id.len;
 
1124
 
 
1125
        /*
 
1126
         * Insert the newly created call to the list of calls
 
1127
         */
 
1128
        clist_insert(credit_data->call_list, call, next, prev);
 
1129
 
 
1130
        lock_init(&call->lock);
 
1131
 
 
1132
        /*
 
1133
         * Increase the number of calls for this client. This call is not yet confirmed.
 
1134
         */
 
1135
        credit_data->number_of_calls++;
 
1136
 
 
1137
        lock_release(&credit_data->lock);
 
1138
 
 
1139
        LM_DBG("New call allocated for client [%.*s]\n", call->client_id.len, call->client_id.s);
 
1140
 
 
1141
        return call;
 
1142
 
 
1143
error:
 
1144
        lock_release(&credit_data->lock);
 
1145
        return NULL;
 
1146
}
 
1147
 
 
1148
static call_t *alloc_new_call_by_time(credit_data_t *credit_data, struct sip_msg *msg, int max_secs)
 
1149
{
 
1150
        call_t *call            = NULL;
 
1151
 
 
1152
        lock_get(&credit_data->lock);
 
1153
 
 
1154
        if (credit_data->call_list == NULL)
 
1155
        {
 
1156
                LM_ERR("Credit data call list is NULL\n");
 
1157
                goto error;
 
1158
        }
 
1159
 
 
1160
        call                            = shm_malloc(sizeof(call_t));
 
1161
        if (call == NULL)
 
1162
        {
 
1163
                LM_ERR("No shared memory left\n");
 
1164
                goto error;
 
1165
        }
 
1166
 
 
1167
        if ( (!msg->callid && parse_headers(msg, HDR_CALLID_F, 0) != 0) ||
 
1168
                   shm_str_dup(&call->sip_data.callid, &msg->callid->body) != 0 )
 
1169
        {
 
1170
                LM_ERR("Error processing CALLID hdr\n");
 
1171
                goto error;
 
1172
        }
 
1173
 
 
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;
 
1178
 
 
1179
        call->consumed_amount           = 0;
 
1180
        call->confirmed                         = FALSE;
 
1181
        call->max_amount                        = max_secs;
 
1182
 
 
1183
        /*
 
1184
         * Reference the client_id from the root of the list
 
1185
         */
 
1186
        call->client_id.s                       = credit_data->call_list->client_id.s;
 
1187
        call->client_id.len                     = credit_data->call_list->client_id.len;
 
1188
 
 
1189
        /*
 
1190
         * Insert the newly created call to the list of calls
 
1191
         */
 
1192
        clist_insert(credit_data->call_list, call, next, prev);
 
1193
 
 
1194
        lock_init(&call->lock);
 
1195
 
 
1196
        /*
 
1197
         * Increase the number of calls for this client. This call is not yet confirmed.
 
1198
         */
 
1199
        credit_data->number_of_calls++;
 
1200
 
 
1201
        lock_release(&credit_data->lock);
 
1202
 
 
1203
        LM_DBG("New call allocated for client [%.*s]\n", call->client_id.len, call->client_id.s);
 
1204
 
 
1205
        return call;
 
1206
 
 
1207
error:
 
1208
        lock_release(&credit_data->lock);
 
1209
        return NULL;
 
1210
}
 
1211
 
 
1212
static call_t *alloc_new_call_by_channel(credit_data_t *credit_data, struct sip_msg *msg, int max_chan)
 
1213
{
 
1214
        call_t *call            = NULL;
 
1215
 
 
1216
        lock_get(&credit_data->lock);
 
1217
 
 
1218
        if (credit_data->call_list == NULL)
 
1219
        {
 
1220
                LM_ERR("Credit data call list is NULL\n");
 
1221
                goto error;
 
1222
        }
 
1223
 
 
1224
        call                            = shm_malloc(sizeof(call_t));
 
1225
        if (call == NULL)
 
1226
        {
 
1227
                LM_ERR("No shared memory left\n");
 
1228
                goto error;
 
1229
        }
 
1230
 
 
1231
        if ( (!msg->callid && parse_headers(msg, HDR_CALLID_F, 0) != 0) ||
 
1232
                   shm_str_dup(&call->sip_data.callid, &msg->callid->body) != 0 )
 
1233
        {
 
1234
                LM_ERR("Error processing CALLID hdr\n");
 
1235
                goto error;
 
1236
        }
 
1237
 
 
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;
 
1242
 
 
1243
        call->consumed_amount           = 0;
 
1244
        call->confirmed                         = FALSE;
 
1245
        call->max_amount                        = max_chan;
 
1246
 
 
1247
        /*
 
1248
         * Reference the client_id from the root of the list
 
1249
         */
 
1250
        call->client_id.s                       = credit_data->call_list->client_id.s;
 
1251
        call->client_id.len                     = credit_data->call_list->client_id.len;
 
1252
 
 
1253
        /*
 
1254
         * Insert the newly created call to the list of calls
 
1255
         */
 
1256
        clist_insert(credit_data->call_list, call, next, prev);
 
1257
 
 
1258
        lock_init(&call->lock);
 
1259
 
 
1260
        /*
 
1261
         * Increase the number of calls for this client. This call is not yet confirmed.
 
1262
         */
 
1263
        credit_data->number_of_calls++;
 
1264
 
 
1265
        lock_release(&credit_data->lock);
 
1266
 
 
1267
        LM_DBG("New call allocated for client [%.*s]\n", call->client_id.len, call->client_id.s);
 
1268
 
 
1269
 
 
1270
        return call;
 
1271
 
 
1272
error:
 
1273
        lock_release(&credit_data->lock);
 
1274
        return NULL;
 
1275
}
 
1276
 
 
1277
static int add_call_by_cid(str *cid, call_t *call, credit_type_t type)
 
1278
{
 
1279
        struct str_hash_table *ht       = NULL;
 
1280
        gen_lock_t *lock                        = NULL;
 
1281
        struct str_hash_entry *e        = NULL;
 
1282
 
 
1283
        switch(type)
 
1284
        {
 
1285
        case CREDIT_MONEY:
 
1286
                ht              = _data.money.call_data_by_cid;
 
1287
                lock    =  &_data.money.lock;
 
1288
                break;
 
1289
        case CREDIT_TIME:
 
1290
                ht              = _data.time.call_data_by_cid;
 
1291
                lock    =  &_data.time.lock;
 
1292
                break;
 
1293
        case CREDIT_CHANNEL:
 
1294
                ht              = _data.channel.call_data_by_cid;
 
1295
                lock    =  &_data.channel.lock;
 
1296
                break;
 
1297
        default:
 
1298
                LM_ERR("Something went terribly wrong");
 
1299
                return -1;
 
1300
        }
 
1301
 
 
1302
        e       = str_hash_get(ht, cid->s, cid->len);
 
1303
 
 
1304
        if (e != NULL)
 
1305
        {
 
1306
                LM_DBG("e != NULL\n");
 
1307
 
 
1308
                call_t *value   = (call_t *) e->u.p;
 
1309
 
 
1310
                if (value == NULL)
 
1311
                {
 
1312
                        LM_ERR("Value of CID [%.*s] is NULL\n", cid->len, cid->s);
 
1313
                        return -1;
 
1314
                }
 
1315
 
 
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);
 
1318
 
 
1319
                if (value->sip_data.callid.len != cid->len ||
 
1320
                        strncasecmp(value->sip_data.callid.s, cid->s, cid->len) != 0)
 
1321
                {
 
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);
 
1324
                        return -1;
 
1325
                }
 
1326
 
 
1327
                LM_DBG("CID already present\n");
 
1328
 
 
1329
                return 0;
 
1330
        }
 
1331
 
 
1332
        e       = shm_malloc(sizeof(struct str_hash_entry));
 
1333
 
 
1334
        if (e == NULL)
 
1335
        {
 
1336
                LM_ERR("No shared memory left\n");
 
1337
                return -1;
 
1338
        }
 
1339
 
 
1340
        if (shm_str_dup(&e->key, cid) != 0)
 
1341
        {
 
1342
                LM_ERR("No shared memory left\n");
 
1343
                return -1;
 
1344
        }
 
1345
 
 
1346
        e->u.p          = call;
 
1347
 
 
1348
        lock_get(lock);
 
1349
        str_hash_add(ht, e);
 
1350
        lock_release(lock);
 
1351
 
 
1352
        return 0;
 
1353
}
 
1354
 
 
1355
static inline void set_ctrl_flag(struct sip_msg* msg)
 
1356
{
 
1357
        if (_data.ctrl_flag != -1)
 
1358
        {
 
1359
                LM_DBG("Flag set!\n");
 
1360
                setflag(msg, _data.ctrl_flag);
 
1361
        }
 
1362
}
 
1363
 
 
1364
static inline int get_pv_value(struct sip_msg* msg, pv_spec_t* spec, pv_value_t* value)
 
1365
{
 
1366
        if (pv_get_spec_value(msg, spec, value) != 0)
 
1367
        {
 
1368
                LM_ERR("Can't get PV's value\n");
 
1369
                return -1;
 
1370
        }
 
1371
 
 
1372
        return 0;
 
1373
}
 
1374
 
 
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)
 
1379
{
 
1380
        credit_data_t *credit_data      = NULL;
 
1381
        call_t *call                            = NULL;
 
1382
 
 
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;
 
1388
 
 
1389
        pv_value_t client_id_val,
 
1390
                                credit_val,
 
1391
                                cps_val,
 
1392
                                initial_pulse_val,
 
1393
                                final_pulse_val;
 
1394
 
 
1395
        double credit                                   = 0,
 
1396
                   cost_per_second                      = 0;
 
1397
 
 
1398
        unsigned int initial_pulse              = 0,
 
1399
                        final_pulse                             = 0;
 
1400
 
 
1401
        if (msg->first_line.type == SIP_REQUEST && msg->first_line.u.request.method_value == METHOD_INVITE)
 
1402
        {
 
1403
                if (has_to_tag(msg))
 
1404
                {
 
1405
                        LM_ERR("INVITE is a reINVITE\n");
 
1406
                        return -1;
 
1407
                }
 
1408
 
 
1409
                if (pv_get_spec_value(msg, client_id_spec, &client_id_val) != 0)
 
1410
                {
 
1411
                        LM_ERR("Can't get client_id's value\n");
 
1412
                        return -1;
 
1413
                }
 
1414
 
 
1415
                if (pv_get_spec_value(msg, credit_spec, &credit_val) != 0)
 
1416
                {
 
1417
                        LM_ERR("Can't get credit's value\n");
 
1418
                        return -1;
 
1419
                }
 
1420
 
 
1421
                credit  = str2double(&credit_val.rs);
 
1422
 
 
1423
                if (credit <= 0)
 
1424
                {
 
1425
                        LM_ERR("credit value must be > 0: %f", credit);
 
1426
                        return -1;
 
1427
                }
 
1428
 
 
1429
                if (pv_get_spec_value(msg, cps_spec, &cps_val) != 0)
 
1430
                {
 
1431
                        LM_ERR("Can't get cost_per_sec's value\n");
 
1432
                        return -1;
 
1433
                }
 
1434
 
 
1435
                cost_per_second = str2double(&cps_val.rs);
 
1436
 
 
1437
                if (cost_per_second <= 0)
 
1438
                {
 
1439
                        LM_ERR("cost_per_second value must be > 0: %f", cost_per_second);
 
1440
                        return -1;
 
1441
                }
 
1442
 
 
1443
                if (pv_get_spec_value(msg, initial_pulse_spec, &initial_pulse_val) != 0)
 
1444
                {
 
1445
                        LM_ERR("Can't get initial_pulse's value\n");
 
1446
                        return -1;
 
1447
                }
 
1448
 
 
1449
                if (str2int(&initial_pulse_val.rs, &initial_pulse) != 0)
 
1450
                {
 
1451
                        LM_ERR("initial_pulse value is invalid: %.*s", initial_pulse_val.rs.len, initial_pulse_val.rs.s);
 
1452
                        return -1;
 
1453
                }
 
1454
 
 
1455
                if (pv_get_spec_value(msg, final_pulse_spec, &final_pulse_val) != 0)
 
1456
                {
 
1457
                        LM_ERR("Can't get final_pulse's value\n");
 
1458
                        return -1;
 
1459
                }
 
1460
 
 
1461
                if (str2int(&final_pulse_val.rs, &final_pulse) != 0)
 
1462
                {
 
1463
                        LM_ERR("final_pulse value is invalid: %.*s", final_pulse_val.rs.len, final_pulse_val.rs.s);
 
1464
                        return -1;
 
1465
                }
 
1466
 
 
1467
                if (client_id_val.rs.len == 0 || client_id_val.rs.s == NULL)
 
1468
                {
 
1469
                        LM_ERR("[%.*s]: client ID cannot be null\n", msg->callid->body.len, msg->callid->body.s);
 
1470
                        return -1;
 
1471
                }
 
1472
 
 
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,
 
1476
                                                                                                         credit,
 
1477
                                                                                                         cost_per_second, initial_pulse,
 
1478
                                                                                                         final_pulse, msg->callid->body.len, msg->callid->body.s);
 
1479
                set_ctrl_flag(msg);
 
1480
 
 
1481
                if ((credit_data = get_or_create_credit_data_entry(&client_id_val.rs, CREDIT_MONEY)) == NULL)
 
1482
                {
 
1483
                        LM_ERR("Error retrieving credit data from shared memory for client [%.*s]\n", client_id_val.rs.len, client_id_val.rs.s);
 
1484
                        return -1;
 
1485
                }
 
1486
 
 
1487
                if ((call = alloc_new_call_by_money(credit_data, msg, credit, cost_per_second, initial_pulse, final_pulse)) == NULL)
 
1488
                {
 
1489
                        LM_ERR("Unable to allocate new call for client [%.*s]\n", client_id_val.rs.len, client_id_val.rs.s);
 
1490
                        return -1;
 
1491
                }
 
1492
 
 
1493
                if (add_call_by_cid(&call->sip_data.callid, call, CREDIT_MONEY) != 0)
 
1494
                {
 
1495
                        LM_ERR("Unable to allocate new cid_by_client for client [%.*s]\n", client_id_val.rs.len, client_id_val.rs.s);
 
1496
                        return -1;
 
1497
                }
 
1498
        }
 
1499
        else
 
1500
        {
 
1501
                LM_ALERT("MSG was not an INVITE\n");
 
1502
                return -1;
 
1503
        }
 
1504
 
 
1505
        return 1;
 
1506
}
 
1507
 
 
1508
static int terminate_all(struct sip_msg* msg, char* str_pv_client)
 
1509
{
 
1510
        credit_data_t *credit_data      = NULL;
 
1511
        pv_spec_t *client_id_spec       = (pv_spec_t *) str_pv_client;
 
1512
 
 
1513
        pv_value_t client_id_val;
 
1514
 
 
1515
        if (pv_get_spec_value(msg, client_id_spec, &client_id_val) != 0)
 
1516
        {
 
1517
                LM_ERR("[%.*s]: can't get client_id pvar value\n", msg->callid->body.len, msg->callid->body.s);
 
1518
                return -1;
 
1519
        }
 
1520
 
 
1521
        if (client_id_val.rs.len == 0 || client_id_val.rs.s == NULL)
 
1522
        {
 
1523
                LM_ERR("[%.*s]: client ID cannot be null\n", msg->callid->body.len, msg->callid->body.s);
 
1524
                return -1;
 
1525
        }
 
1526
 
 
1527
        if (try_get_credit_data_entry(&client_id_val.rs, &credit_data) != 0)
 
1528
        {
 
1529
                LM_DBG("[%.*s] not found\n", msg->callid->body.len, msg->callid->body.s);
 
1530
                return -1;
 
1531
        }
 
1532
 
 
1533
        terminate_all_calls(credit_data);
 
1534
 
 
1535
        return 1;
 
1536
}
 
1537
 
 
1538
static int get_channel_count(struct sip_msg* msg, char* str_pv_client, char* str_pv_chan_count)
 
1539
{
 
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;
 
1543
 
 
1544
        pv_value_t chan_count_val, client_id_val;
 
1545
        int value                                       = -1;
 
1546
 
 
1547
        if (pv_get_spec_value(msg, client_id_spec, &client_id_val) != 0)
 
1548
        {
 
1549
                LM_ERR("[%.*s]: can't get client_id pvar value\n", msg->callid->body.len, msg->callid->body.s);
 
1550
                return -1;
 
1551
        }
 
1552
 
 
1553
        if (client_id_val.rs.len == 0 || client_id_val.rs.s == NULL)
 
1554
        {
 
1555
                LM_ERR("[%.*s]: client ID cannot be null\n", msg->callid->body.len, msg->callid->body.s);
 
1556
                return -1;
 
1557
        }
 
1558
 
 
1559
        if (try_get_credit_data_entry(&client_id_val.rs, &credit_data) == 0)
 
1560
                value   = credit_data->number_of_calls;
 
1561
        else
 
1562
                LM_ALERT("[%.*s] not found\n", msg->callid->body.len, msg->callid->body.s);
 
1563
 
 
1564
        if (!pv_is_w(chan_count_spec))
 
1565
        {
 
1566
                LM_ERR("pvar is not writable");
 
1567
                return -1;
 
1568
        }
 
1569
 
 
1570
        memset(&chan_count_val, 0, sizeof(chan_count_val));
 
1571
 
 
1572
        chan_count_val.flags    = PV_VAL_STR;
 
1573
 
 
1574
        if (value > 0)
 
1575
                chan_count_val.rs.s     = int2str(value, &chan_count_val.rs.len);
 
1576
        else
 
1577
        {
 
1578
                char buff[2]                    = { '-', '1' };
 
1579
                chan_count_val.rs.s     = buff;
 
1580
                chan_count_val.rs.len   = 2;
 
1581
        }
 
1582
 
 
1583
        if (pv_set_spec_value(msg, chan_count_spec, 0, &chan_count_val) != 0)
 
1584
        {
 
1585
                LM_ERR("Error writing value to pvar");
 
1586
                return -1;
 
1587
        }
 
1588
 
 
1589
        return 1;
 
1590
}
 
1591
 
 
1592
static int set_max_channels(struct sip_msg* msg, char* str_pv_client, char* str_pv_max_chan)
 
1593
{
 
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;
 
1599
        int max_chan                            = 0;
 
1600
 
 
1601
        set_ctrl_flag(msg);
 
1602
 
 
1603
        if (parse_headers(msg, HDR_CALLID_F, 0) != 0)
 
1604
        {
 
1605
                LM_ERR("Error parsing Call-ID");
 
1606
                return -1;
 
1607
        }
 
1608
 
 
1609
        if (msg->first_line.type == SIP_REQUEST && msg->first_line.u.request.method_value == METHOD_INVITE)
 
1610
        {
 
1611
                if (has_to_tag(msg))
 
1612
                {
 
1613
                        LM_ERR("INVITE is a reINVITE\n");
 
1614
                        return -1;
 
1615
                }
 
1616
 
 
1617
                if (pv_get_spec_value(msg, max_chan_spec, &max_chan_val) != 0)
 
1618
                {
 
1619
                        LM_ERR("Can't get max_chan pvar value\n");
 
1620
                        return -1;
 
1621
                }
 
1622
                max_chan        = max_chan_val.ri;
 
1623
 
 
1624
                if (max_chan <= 0)
 
1625
                {
 
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);
 
1627
                        return -1;
 
1628
                }
 
1629
 
 
1630
                if (pv_get_spec_value(msg, client_id_spec, &client_id_val) != 0)
 
1631
                {
 
1632
                        LM_ERR("[%.*s]: can't get client_id pvar value\n", msg->callid->body.len, msg->callid->body.s);
 
1633
                        return -1;
 
1634
                }
 
1635
 
 
1636
                if (client_id_val.rs.len == 0 || client_id_val.rs.s == NULL)
 
1637
                {
 
1638
                        LM_ERR("[%.*s]: client ID cannot be null\n", msg->callid->body.len, msg->callid->body.s);
 
1639
                        return -1;
 
1640
                }
 
1641
 
 
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,
 
1643
                                                                                                                                                max_chan,
 
1644
                                                                                                                                                msg->callid->body.len, msg->callid->body.s);
 
1645
 
 
1646
                if ((credit_data = get_or_create_credit_data_entry(&client_id_val.rs, CREDIT_CHANNEL)) == NULL)
 
1647
                {
 
1648
                        LM_ERR("Error retrieving credit data from shared memory for client [%.*s]\n", client_id_val.rs.len, client_id_val.rs.s);
 
1649
                        return -1;
 
1650
                }
 
1651
 
 
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
 
1654
 
 
1655
                if (credit_data->concurrent_calls + 1 > max_chan)
 
1656
                        return -3; // you have the max amount of established calls already
 
1657
 
 
1658
                if ((call = alloc_new_call_by_channel(credit_data, msg, max_chan)) == NULL)
 
1659
                {
 
1660
                        LM_ERR("Unable to allocate new call for client [%.*s]\n", client_id_val.rs.len, client_id_val.rs.s);
 
1661
                        return -1;
 
1662
                }
 
1663
 
 
1664
                if (add_call_by_cid(&call->sip_data.callid, call, CREDIT_CHANNEL) != 0)
 
1665
                {
 
1666
                        LM_ERR("Unable to allocate new cid_by_client for client [%.*s]\n", client_id_val.rs.len, client_id_val.rs.s);
 
1667
                        return -1;
 
1668
                }
 
1669
 
 
1670
                return 1;
 
1671
        }
 
1672
        else
 
1673
        {
 
1674
                LM_ALERT("MSG was not an INVITE\n");
 
1675
                return -1;
 
1676
        }
 
1677
}
 
1678
 
 
1679
static int set_max_time(struct sip_msg* msg, char* str_pv_client, char* str_pv_maxsecs)
 
1680
{
 
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;
 
1686
        int max_secs                            = 0;
 
1687
 
 
1688
        set_ctrl_flag(msg);
 
1689
 
 
1690
        if (parse_headers(msg, HDR_CALLID_F, 0) != 0)
 
1691
        {
 
1692
                LM_ERR("Error parsing Call-ID");
 
1693
                return -1;
 
1694
        }
 
1695
 
 
1696
        if (msg->first_line.type == SIP_REQUEST && msg->first_line.u.request.method_value == METHOD_INVITE)
 
1697
        {
 
1698
                if (has_to_tag(msg))
 
1699
                {
 
1700
                        LM_ERR("INVITE is a reINVITE\n");
 
1701
                        return -1;
 
1702
                }
 
1703
 
 
1704
                if (pv_get_spec_value(msg, max_secs_spec, &max_secs_val) != 0)
 
1705
                {
 
1706
                        LM_ERR("Can't get max_secs PV value\n");
 
1707
                        return -1;
 
1708
                }
 
1709
                max_secs        = max_secs_val.ri;
 
1710
 
 
1711
                if (max_secs <= 0)
 
1712
                {
 
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);
 
1714
                        return -1;
 
1715
                }
 
1716
 
 
1717
                if (pv_get_spec_value(msg, client_id_spec, &client_id_val) != 0)
 
1718
                {
 
1719
                        LM_ERR("[%.*s]: can't get client_id PV value\n", msg->callid->body.len, msg->callid->body.s);
 
1720
                        return -1;
 
1721
                }
 
1722
 
 
1723
                if (client_id_val.rs.len == 0 || client_id_val.rs.s == NULL)
 
1724
                {
 
1725
                        LM_ERR("[%.*s]: client ID cannot be null\n", msg->callid->body.len, msg->callid->body.s);
 
1726
                        return -1;
 
1727
                }
 
1728
 
 
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,
 
1730
                                                                                                                                                max_secs,
 
1731
                                                                                                                                                msg->callid->body.len, msg->callid->body.s);
 
1732
 
 
1733
                if ((credit_data = get_or_create_credit_data_entry(&client_id_val.rs, CREDIT_TIME)) == NULL)
 
1734
                {
 
1735
                        LM_ERR("Error retrieving credit data from shared memory for client [%.*s]\n", client_id_val.rs.len, client_id_val.rs.s);
 
1736
                        return -1;
 
1737
                }
 
1738
 
 
1739
                if ((call = alloc_new_call_by_time(credit_data, msg, max_secs)) == NULL)
 
1740
                {
 
1741
                        LM_ERR("Unable to allocate new call for client [%.*s]\n", client_id_val.rs.len, client_id_val.rs.s);
 
1742
                        return -1;
 
1743
                }
 
1744
 
 
1745
                if (add_call_by_cid(&call->sip_data.callid, call, CREDIT_TIME) != 0)
 
1746
                {
 
1747
                        LM_ERR("Unable to allocate new cid_by_client for client [%.*s]\n", client_id_val.rs.len, client_id_val.rs.s);
 
1748
                        return -1;
 
1749
                }
 
1750
        }
 
1751
        else
 
1752
        {
 
1753
                LM_ALERT("MSG was not an INVITE\n");
 
1754
                return -1;
 
1755
        }
 
1756
 
 
1757
        return 1;
 
1758
}
 
1759
 
 
1760
static int update_max_time(struct sip_msg* msg, char* str_pv_client, char* str_pv_secs)
 
1761
{
 
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;
 
1766
        int secs                                = 0;
 
1767
 
 
1768
        set_ctrl_flag(msg);
 
1769
 
 
1770
        if (parse_headers(msg, HDR_CALLID_F, 0) != 0)
 
1771
        {
 
1772
                LM_ERR("Error parsing Call-ID");
 
1773
                return -1;
 
1774
        }
 
1775
 
 
1776
        if (pv_get_spec_value(msg, secs_spec, &secs_val) != 0)
 
1777
        {
 
1778
                LM_ERR("Can't get secs PV value\n");
 
1779
                return -1;
 
1780
        }
 
1781
        secs    = secs_val.ri;
 
1782
 
 
1783
        if (secs <= 0)
 
1784
        {
 
1785
                LM_ERR("[%.*s] MAXSECS cannot be less than or equal to zero: %d\n", msg->callid->body.len, msg->callid->body.s, secs);
 
1786
                return -1;
 
1787
        }
 
1788
 
 
1789
        if (pv_get_spec_value(msg, client_id_spec, &client_id_val) != 0)
 
1790
        {
 
1791
                LM_ERR("[%.*s]: can't get client_id PV value\n", msg->callid->body.len, msg->callid->body.s);
 
1792
                return -1;
 
1793
        }
 
1794
 
 
1795
        if (client_id_val.rs.len == 0 || client_id_val.rs.s == NULL)
 
1796
        {
 
1797
                LM_ERR("[%.*s]: client ID cannot be null\n", msg->callid->body.len, msg->callid->body.s);
 
1798
                return -1;
 
1799
        }
 
1800
 
 
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,
 
1802
                                                                                                        secs,
 
1803
                                                                                                        msg->callid->body.len, msg->callid->body.s);
 
1804
 
 
1805
 
 
1806
 
 
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,
 
1812
               *tmp_call                = NULL;
 
1813
 
 
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);
 
1817
 
 
1818
        if (e == NULL)
 
1819
        {
 
1820
                LM_ERR("Client [%.*s] was not found\n", client_id_val.rs.len, client_id_val.rs.s);
 
1821
                return -1;
 
1822
        }
 
1823
                
 
1824
        credit_data                                     = (credit_data_t *) e->u.p;
 
1825
 
 
1826
        lock_get(&credit_data->lock);
 
1827
 
 
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);
 
1829
        
 
1830
        credit_data->max_amount                         += secs;
 
1831
 
 
1832
        if (credit_data->number_of_calls > 0)
 
1833
                update_fraction = secs / credit_data->number_of_calls;
 
1834
 
 
1835
        clist_foreach_safe(credit_data->call_list, call, tmp_call, next)
 
1836
        {
 
1837
                if (!call->confirmed)
 
1838
                        continue;
 
1839
                
 
1840
                call->max_amount        += update_fraction;
 
1841
        }
 
1842
 
 
1843
//redit_data->consumed_amount                   = 0;
 
1844
 
 
1845
 
 
1846
        lock_release(&credit_data->lock);
 
1847
 
 
1848
        return 1;
 
1849
}
 
1850
 
 
1851
static int has_to_tag(struct sip_msg *msg)
 
1852
{
 
1853
        if (msg->to == NULL && parse_headers(msg, HDR_TO_F, 0) != 0)
 
1854
        {
 
1855
                LM_ERR("Cannot parse to-tag\n");
 
1856
                return 0;
 
1857
        }
 
1858
 
 
1859
        return !(get_to(msg)->tag_value.s == NULL || get_to(msg)->tag_value.len == 0);
 
1860
}
 
1861
 
 
1862
static int pv_parse_calls_param(pv_spec_p sp, str *in)
 
1863
{
 
1864
        if (sp == NULL || in == NULL || in->len == 0)
 
1865
                return -1;
 
1866
 
 
1867
        switch(in->len)
 
1868
        {
 
1869
        case 5:
 
1870
                if (strncmp("total", in->s, in->len) == 0)
 
1871
                        sp->pvp.pvn.u.isname.name.n     = CNX_PV_TOTAL;
 
1872
                else
 
1873
                        return -1;
 
1874
                break;
 
1875
        case 6:
 
1876
                if (strncmp("active", in->s, in->len) == 0)
 
1877
                        sp->pvp.pvn.u.isname.name.n     = CNX_PV_ACTIVE;
 
1878
                else
 
1879
                        return -1;
 
1880
                break;
 
1881
        case 7:
 
1882
                if (strncmp("dropped", in->s, in->len) == 0)
 
1883
                        sp->pvp.pvn.u.isname.name.n     = CNX_PV_DROPPED;
 
1884
                else
 
1885
                        return -1;
 
1886
                break;
 
1887
 
 
1888
        }
 
1889
 
 
1890
        sp->pvp.pvn.type = PV_NAME_INTSTR;
 
1891
        sp->pvp.pvn.u.isname.type = 0;
 
1892
 
 
1893
        return 0;
 
1894
}
 
1895
 
 
1896
static int pv_get_calls(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
 
1897
{
 
1898
        switch(param->pvn.u.isname.name.n)
 
1899
        {
 
1900
        case CNX_PV_ACTIVE:
 
1901
                return pv_get_uintval(msg, param, res, _data.stats->active);
 
1902
        case CNX_PV_TOTAL:
 
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);
 
1906
        default:
 
1907
                LM_ERR("Unknown PV type %d\n", param->pvn.u.isname.name.n);
 
1908
                break;
 
1909
        }
 
1910
 
 
1911
        return -1;
 
1912
}
 
1913
 
 
1914
static struct mi_root *mi_credit_control_stats(struct mi_root *tree, void *param)
 
1915
{
 
1916
        char *p;
 
1917
        int len;
 
1918
        struct mi_root *rpl_tree;
 
1919
        struct mi_node *node, *node1;
 
1920
 
 
1921
        rpl_tree        = init_mi_tree(200, "OK", 2);
 
1922
        node            = &rpl_tree->node;
 
1923
 
 
1924
        node1 = add_mi_node_child(node, 0, MI_SSTR("CNX Credit Control"), 0, 0);
 
1925
        if (node1 == NULL)
 
1926
        {
 
1927
                LM_ERR("Error creating child node\n");
 
1928
                goto error;
 
1929
        }
 
1930
 
 
1931
        p       = int2str((unsigned long) _data.stats->active, &len);
 
1932
        if (p == NULL)
 
1933
        {
 
1934
                LM_ERR("Error converting INT to STR\n");
 
1935
                goto error;
 
1936
        }
 
1937
        add_mi_node_child(node1, MI_DUP_VALUE, MI_SSTR("active"), p, len);
 
1938
 
 
1939
        p       = int2str((unsigned long) _data.stats->dropped, &len);
 
1940
        if (p == NULL)
 
1941
        {
 
1942
                LM_ERR("Error converting INT to STR\n");
 
1943
                goto error;
 
1944
        }
 
1945
        add_mi_node_child(node1, MI_DUP_VALUE, MI_SSTR("dropped"), p, len);
 
1946
 
 
1947
        p       = int2str((unsigned long) _data.stats->total, &len);
 
1948
        if (p == NULL)
 
1949
        {
 
1950
                LM_ERR("Error converting INT to STR\n");
 
1951
                goto error;
 
1952
        }
 
1953
 
 
1954
        add_mi_node_child(node1, MI_DUP_VALUE, MI_SSTR("total"), p, len);
 
1955
 
 
1956
        return rpl_tree;
 
1957
 
 
1958
error:
 
1959
        return init_mi_tree(500, MI_INTERNAL_ERR, MI_INTERNAL_ERR_LEN);
 
1960
}