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

« back to all changes in this revision

Viewing changes to modules/ims_charging/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
 * mod.c
 
3
 *
 
4
 *  Created on: 21 Feb 2013
 
5
 *      Author: jaybeepee
 
6
 */
 
7
 
 
8
#include "mod.h"
 
9
#include "../../sr_module.h"
 
10
#include "../../modules/dialog_ng/dlg_load.h"
 
11
#include "../../modules/dialog_ng/dlg_hash.h"
 
12
#include "../cdp/cdp_load.h"
 
13
#include "../cdp_avp/mod_export.h"
 
14
#include "../../parser/parse_to.h"
 
15
#include "stats.h"
 
16
#include "ro_timer.h"
 
17
#include "ro_session_hash.h"
 
18
#include "ims_ro.h"
 
19
#include "config.h"
 
20
#include "dialog.h"
 
21
 
 
22
MODULE_VERSION
 
23
 
 
24
/* parameters */
 
25
char* ro_origin_host_s = "scscf.ims.smilecoms.com";
 
26
char* ro_origin_realm_s = "ims.smilecoms.com";
 
27
char* ro_destination_realm_s = "ims.smilecoms.com";
 
28
char* ro_destination_host_s = "hss.ims.smilecoms.com";
 
29
char* ro_service_context_id_root_s = "32260@3gpp.org";
 
30
char* ro_service_context_id_ext_s = "ext";
 
31
char* ro_service_context_id_mnc_s = "01";
 
32
char* ro_service_context_id_mcc_s = "001";
 
33
char* ro_service_context_id_release_s = "8";
 
34
static int ro_session_hash_size = 4096;
 
35
int ro_timer_buffer = 5;
 
36
int interim_request_credits = 30;
 
37
client_ro_cfg cfg;
 
38
 
 
39
struct cdp_binds cdpb;
 
40
struct dlg_binds dlgb;
 
41
cdp_avp_bind_t *cdp_avp;
 
42
struct tm_binds tmb;
 
43
 
 
44
char* rx_dest_realm_s = "ims.smilecoms.com";
 
45
str rx_dest_realm;
 
46
/* Only used if we want to force the Ro peer usually this is configured at a stack level and the first request uses realm routing */
 
47
//char* rx_forced_peer_s = "";
 
48
str ro_forced_peer;
 
49
int ro_auth_expiry = 7200;
 
50
int cdp_event_latency = 1; /*flag: report slow processing of CDP callback events or not - default enabled */
 
51
int cdp_event_threshold = 500; /*time in ms above which we should report slow processing of CDP callback event - default 500ms*/
 
52
int cdp_event_latency_loglevel = 0; /*log-level to use to report slow processing of CDP callback event - default ERROR*/
 
53
 
 
54
stat_var *initial_ccrs;
 
55
stat_var *interim_ccrs;
 
56
stat_var *final_ccrs;
 
57
stat_var *successful_initial_ccrs;
 
58
stat_var *successful_interim_ccrs;
 
59
stat_var *successful_final_ccrs;
 
60
stat_var *ccr_responses_time;
 
61
stat_var *billed_secs;
 
62
stat_var *killed_calls;
 
63
stat_var *ccr_timeouts;
 
64
 
 
65
/** module functions */
 
66
static int mod_init(void);
 
67
static int mod_child_init(int);
 
68
static void mod_destroy(void);
 
69
static int w_ro_ccr(struct sip_msg *msg, str* route_name, str* direction, str* charge_type, str* unit_type, int reservation_units);
 
70
//void ro_session_ontimeout(struct ro_tl *tl);
 
71
 
 
72
static int ro_fixup(void **param, int param_no);
 
73
 
 
74
static cmd_export_t cmds[] = {
 
75
                { "Ro_CCR",     (cmd_function) w_ro_ccr, 5, ro_fixup, 0, REQUEST_ROUTE },
 
76
                { 0, 0, 0, 0, 0, 0 }
 
77
};
 
78
 
 
79
static param_export_t params[] = {
 
80
                { "hash_size",                          INT_PARAM,                      &ro_session_hash_size           },
 
81
                { "interim_update_credits",     INT_PARAM,                      &interim_request_credits        },
 
82
                { "timer_buffer",                       INT_PARAM,                      &ro_timer_buffer                        },
 
83
                { "ro_forced_peer",             STR_PARAM,                      &ro_forced_peer.s                       },
 
84
                { "ro_auth_expiry",                     INT_PARAM,                      &ro_auth_expiry                         },
 
85
                { "cdp_event_latency",          INT_PARAM,                      &cdp_event_latency                      }, /*flag: report slow processing of CDP
 
86
                                                                                                                                                                                callback events or not */
 
87
                { "cdp_event_threshold",        INT_PARAM,                      &cdp_event_threshold            }, /*time in ms above which we should
 
88
                                                                                                                                                                                report slow processing of CDP callback event*/
 
89
                { "cdp_event_latency_log",      INT_PARAM,                      &cdp_event_latency_loglevel },/*log-level to use to report
 
90
                                                                                                                                                                                slow processing of CDP callback event*/
 
91
                { "origin_host",                        STR_PARAM,                      &ro_origin_host_s                       },
 
92
                { "origin_realm",                       STR_PARAM,                      &ro_origin_realm_s                      },
 
93
                { "destination_realm",          STR_PARAM,                      &ro_destination_realm_s         },
 
94
                { "destination_host",           STR_PARAM,                      &ro_destination_host_s          },
 
95
                { "service_context_id_root",STR_PARAM,                  &ro_service_context_id_root_s   },
 
96
                { "service_context_id_ext", STR_PARAM,                  &ro_service_context_id_ext_s    },
 
97
                { "service_context_id_mnc", STR_PARAM,                  &ro_service_context_id_mnc_s    },
 
98
                { "service_context_id_mcc", STR_PARAM,                  &ro_service_context_id_mcc_s    },
 
99
                { "service_context_id_release", STR_PARAM,              &ro_service_context_id_release_s},
 
100
                { 0, 0, 0 }
 
101
};
 
102
 
 
103
stat_export_t charging_stats[] = {
 
104
    {"initial_ccrs", STAT_NO_RESET, &initial_ccrs},
 
105
    {"interim_ccrs", STAT_NO_RESET, &interim_ccrs},
 
106
    {"final_ccrs", STAT_NO_RESET, &final_ccrs},
 
107
    {"successful_initial_ccrs", STAT_NO_RESET, &successful_initial_ccrs},
 
108
    {"successful_interim_ccr", STAT_NO_RESET, &successful_interim_ccrs},
 
109
    {"successful_final_ccrs", STAT_NO_RESET, &successful_final_ccrs},
 
110
    {"failed_initial_ccrs", STAT_IS_FUNC, (stat_var**) get_failed_initial_ccrs},
 
111
    {"failed_interim_ccr", STAT_IS_FUNC, (stat_var**) get_failed_interim_ccrs},
 
112
    {"failed_final_ccrs", STAT_IS_FUNC, (stat_var**) get_failed_final_ccrs},
 
113
    {"ccr_avg_response_time", STAT_IS_FUNC, (stat_var**) get_ccr_avg_response_time},
 
114
    {"ccr_responses_time", STAT_NO_RESET, &ccr_responses_time},
 
115
    {"billed_secs", STAT_NO_RESET, &billed_secs},
 
116
    {"killed_calls", STAT_NO_RESET, &killed_calls},
 
117
    {"ccr_timeouts", STAT_NO_RESET, &ccr_timeouts},
 
118
    {0, 0, 0}
 
119
};
 
120
 
 
121
/** module exports */
 
122
struct module_exports exports = { MOD_NAME, DEFAULT_DLFLAGS, /* dlopen flags */
 
123
                cmds,           /* Exported functions */
 
124
                params,         /* Exported params */
 
125
                charging_stats, /* exported statistics */
 
126
                0,                      /* exported MI functions */
 
127
                0,                      /* exported pseudo-variables */
 
128
                0,                      /* extra processes */
 
129
                mod_init,       /* module initialization function */
 
130
                0,
 
131
                mod_destroy,    /* module destroy functoin */
 
132
                mod_child_init  /* per-child init function */
 
133
};
 
134
 
 
135
int fix_parameters() {
 
136
        cfg.origin_host.s = ro_origin_host_s;
 
137
        cfg.origin_host.len = strlen(ro_origin_host_s);
 
138
 
 
139
        cfg.origin_realm.s = ro_origin_realm_s;
 
140
        cfg.origin_realm.len = strlen(ro_origin_realm_s);
 
141
 
 
142
        cfg.destination_realm.s = ro_destination_realm_s;
 
143
        cfg.destination_realm.len = strlen(ro_destination_realm_s);
 
144
 
 
145
        cfg.destination_host.s = ro_destination_host_s;
 
146
        cfg.destination_host.len = strlen(ro_destination_host_s);
 
147
 
 
148
        cfg.service_context_id = shm_malloc(sizeof(str));
 
149
        if (!cfg.service_context_id) {
 
150
                LM_ERR("fix_parameters:not enough shm memory\n");
 
151
                return 0;
 
152
        }
 
153
        cfg.service_context_id->len = strlen(ro_service_context_id_ext_s)
 
154
                        + strlen(ro_service_context_id_mnc_s)
 
155
                        + strlen(ro_service_context_id_mcc_s)
 
156
                        + strlen(ro_service_context_id_release_s)
 
157
                        + strlen(ro_service_context_id_root_s) + 5;
 
158
        cfg.service_context_id->s =
 
159
                        pkg_malloc(cfg.service_context_id->len * sizeof (char));
 
160
        if (!cfg.service_context_id->s) {
 
161
                LM_ERR("fix_parameters: not enough memory!\n");
 
162
                return 0;
 
163
        }
 
164
        cfg.service_context_id->len = sprintf(cfg.service_context_id->s,
 
165
                        "%s.%s.%s.%s.%s", ro_service_context_id_ext_s,
 
166
                        ro_service_context_id_mnc_s, ro_service_context_id_mcc_s,
 
167
                        ro_service_context_id_release_s, ro_service_context_id_root_s);
 
168
        if (cfg.service_context_id->len < 0) {
 
169
                LM_ERR("fix_parameters: error while creating service_context_id\n");
 
170
                return 0;
 
171
        }
 
172
 
 
173
        return 1;
 
174
}
 
175
 
 
176
static int mod_init(void) {
 
177
        int n;
 
178
        load_dlg_f load_dlg;
 
179
        load_tm_f load_tm;
 
180
 
 
181
        if (!fix_parameters()) {
 
182
                LM_ERR("unable to set Ro configuration parameters correctly\n");
 
183
                goto error;
 
184
        }
 
185
 
 
186
        /* bind to the tm module */
 
187
        if (!(load_tm = (load_tm_f) find_export("load_tm", NO_SCRIPT, 0))) {
 
188
                LM_ERR("Can not import load_tm. This module requires tm module\n");
 
189
                goto error;
 
190
        }
 
191
        if (load_tm(&tmb) == -1)
 
192
                goto error;
 
193
 
 
194
        if (!(load_dlg = (load_dlg_f) find_export("load_dlg", 0, 0))) { /* bind to dialog module */
 
195
                LM_ERR("can not import load_dlg. This module requires Kamailio dialog module.\n");
 
196
        }
 
197
        if (load_dlg(&dlgb) == -1) {
 
198
                goto error;
 
199
        }
 
200
 
 
201
        if (load_cdp_api(&cdpb) != 0) { /* load the CDP API */
 
202
                LM_ERR("can't load CDP API\n");
 
203
                goto error;
 
204
        }
 
205
 
 
206
        if (load_dlg_api(&dlgb) != 0) { /* load the dialog API */
 
207
                LM_ERR("can't load Dialog API\n");
 
208
                goto error;
 
209
        }
 
210
 
 
211
        cdp_avp = load_cdp_avp(); /* load CDP_AVP API */
 
212
        if (!cdp_avp) {
 
213
                LM_ERR("can't load CDP_AVP API\n");
 
214
                goto error;
 
215
        }
 
216
 
 
217
        /* init timer lists*/
 
218
        if (init_ro_timer(ro_session_ontimeout) != 0) {
 
219
                LM_ERR("cannot init timer list\n");
 
220
                return -1;
 
221
        }
 
222
 
 
223
        /* initialized the hash table */
 
224
        for (n = 0; n < (8 * sizeof(n)); n++) {
 
225
                if (ro_session_hash_size == (1 << n))
 
226
                        break;
 
227
                if (ro_session_hash_size < (1 << n)) {
 
228
                        LM_WARN("hash_size is not a power of 2 as it should be -> rounding from %d to %d\n", ro_session_hash_size, 1 << (n - 1));
 
229
                        ro_session_hash_size = 1 << (n - 1);
 
230
                }
 
231
        }
 
232
 
 
233
        if (init_ro_session_table(ro_session_hash_size) < 0) {
 
234
                LM_ERR("failed to create ro session hash table\n");
 
235
                return -1;
 
236
        }
 
237
 
 
238
        /* register global timer */
 
239
        if (register_timer(ro_timer_routine, 0/*(void*)ro_session_list*/, 1) < 0) {
 
240
                LM_ERR("failed to register timer \n");
 
241
                return -1;
 
242
        }
 
243
 
 
244
         /* register statistics */
 
245
        if (register_module_stats(exports.name, charging_stats) != 0) {
 
246
                LM_ERR("failed to register core statistics\n");
 
247
                return -1;
 
248
        }
 
249
 
 
250
        /*if (register_stat(MOD_NAME, "ccr_responses_time", &ccr_responses_time, 0)) {
 
251
                LM_ERR("failed to register core statistics\n");
 
252
                return -1;
 
253
        }*/
 
254
 
 
255
        return 0;
 
256
 
 
257
error:
 
258
        LM_ERR("Failed to initialise ims_qos module\n");
 
259
        return RO_RETURN_FALSE;
 
260
 
 
261
}
 
262
 
 
263
static int mod_child_init(int rank) {
 
264
        return 0;
 
265
}
 
266
 
 
267
static void mod_destroy(void) {
 
268
 
 
269
}
 
270
 
 
271
static int w_ro_ccr(struct sip_msg *msg, str* route_name, str* direction, str* charge_type, str* unit_type, int reservation_units) {
 
272
        /* PSEUDOCODE/NOTES
 
273
         * 1. What mode are we in - terminating or originating
 
274
         * 2. check request type -      IEC - Immediate Event Charging
 
275
         *                                                      ECUR - Event Charging with Unit Reservation
 
276
         *                                                      SCUR - Session Charging with Unit Reservation
 
277
         * 3. probably only do SCUR in this module for now - can see event based charging in another component instead (AS for SMS for example, etc)
 
278
         * 4. Check a dialog exists for call, if not we fail
 
279
         * 5. make sure we dont already have an Ro Session for this dialog
 
280
         * 6. create new Ro Session
 
281
         * 7. register for DLG callback passing new Ro session as parameter - (if dlg torn down we know which Ro session it is associated with)
 
282
         *
 
283
         *
 
284
         */
 
285
        cfg_action_t* cfg_action;
 
286
        tm_cell_t *t;
 
287
        unsigned int tindex = 0,
 
288
                                 tlabel = 0;
 
289
 
 
290
        LM_DBG("Ro CCR initiated: direction:%.*s, charge_type:%.*s, unit_type:%.*s, reservation_units:%i, route_name:%.*s",
 
291
                        direction->len, direction->s,
 
292
                        charge_type->len, charge_type->s,
 
293
                        unit_type->len, unit_type->s,
 
294
                        reservation_units,
 
295
                        route_name->len, route_name->s);
 
296
 
 
297
    if (msg->first_line.type != SIP_REQUEST) {
 
298
        LM_ERR("Ro_CCR() called from SIP reply.");
 
299
        return -1;
 
300
    }
 
301
 
 
302
        LM_DBG("Looking for route block [%.*s]\n", route_name->len, route_name->s);
 
303
 
 
304
        int ri = route_get(&main_rt, route_name->s);
 
305
        if (ri < 0) {
 
306
                LM_ERR("unable to find route block [%.*s]\n", route_name->len, route_name->s);
 
307
                return RO_RETURN_ERROR;
 
308
        }
 
309
        
 
310
        cfg_action = main_rt.rlist[ri];
 
311
        if (!cfg_action) {
 
312
                LM_ERR("empty action lists in route block [%.*s]\n", route_name->len, route_name->s);
 
313
                return RO_RETURN_ERROR;
 
314
    }
 
315
 
 
316
        //before we send lets suspend the transaction
 
317
        t = tmb.t_gett();
 
318
        if (t == NULL || t == T_UNDEFINED) {
 
319
                if (tmb.t_newtran(msg) < 0) {
 
320
                        LM_ERR("cannot create the transaction for CCR async\n");
 
321
                        return RO_RETURN_ERROR;
 
322
                }
 
323
                t = tmb.t_gett();
 
324
                if (t == NULL || t == T_UNDEFINED) {
 
325
                        LM_ERR("cannot lookup the transaction\n");
 
326
                        return RO_RETURN_ERROR;
 
327
                }
 
328
        }
 
329
 
 
330
        LM_DBG("Suspending SIP TM transaction\n");
 
331
        if (tmb.t_suspend(msg, &tindex, &tlabel) < 0) {
 
332
                LM_ERR("failed to suspend the TM processing\n");
 
333
                return RO_RETURN_ERROR;
 
334
        }
 
335
 
 
336
        return Ro_Send_CCR(msg, direction, charge_type, unit_type, reservation_units, cfg_action, tindex, tlabel);
 
337
}
 
338
 
 
339
static int ro_fixup(void **param, int param_no) {
 
340
        str s;
 
341
        unsigned int num;
 
342
 
 
343
        if (param_no > 0 && param_no <= 4) {
 
344
                return fixup_var_str_12(param, param_no);
 
345
        } else if (param_no == 5) {
 
346
                /*convert to int */
 
347
                s.s = (char*)*param;
 
348
                s.len = strlen(s.s);
 
349
                if (str2int(&s, &num)==0) {
 
350
                        pkg_free(*param);
 
351
                        *param = (void*)(unsigned long)num;
 
352
                        return 0;
 
353
                }
 
354
                LM_ERR("Bad reservation units: <%s>n", (char*)(*param));
 
355
                return E_CFG;
 
356
        }
 
357
        return 0;
 
358
}