...
|
...
|
@@ -22,6 +22,7 @@
|
22
|
22
|
#include "ims_charging_stats.h"
|
23
|
23
|
#include "ro_session_hash.h"
|
24
|
24
|
#include "ims_charging_stats.h"
|
|
25
|
+#include "../../core/kemi.h"
|
25
|
26
|
|
26
|
27
|
MODULE_VERSION
|
27
|
28
|
|
...
|
...
|
@@ -101,204 +102,209 @@ static int w_ro_set_session_id_avp(struct sip_msg *msg, char *str1, char *str2);
|
101
|
102
|
static int ro_fixup(void **param, int param_no);
|
102
|
103
|
static int ro_fixup_stop(void **param, int param_no);
|
103
|
104
|
|
|
105
|
+static int ki_ro_set_session_id_avp(sip_msg_t *msg);
|
|
106
|
+static int ki_ro_ccr_stop(sip_msg_t *msg, str* p_direction, int p_code, str* p_reason);
|
|
107
|
+static int ki_ro_ccr(sip_msg_t *msg, str* s_route_name, str* s_direction, int reservation_units, str* s_incoming_trunk_id, str* s_outgoing_trunk_id);
|
|
108
|
+
|
|
109
|
+
|
104
|
110
|
static cmd_export_t cmds[] = {
|
105
|
|
- { "Ro_CCR", (cmd_function) w_ro_ccr, 5, ro_fixup, 0, REQUEST_ROUTE },
|
106
|
|
- { "Ro_CCR_Stop",(cmd_function) w_ro_ccr_stop, 3, ro_fixup_stop, 0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE},
|
|
111
|
+ { "Ro_CCR", (cmd_function) w_ro_ccr, 5, ro_fixup, 0, REQUEST_ROUTE },
|
|
112
|
+ { "Ro_CCR_Stop",(cmd_function) w_ro_ccr_stop, 3, ro_fixup_stop, 0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE},
|
107
|
113
|
{ "Ro_set_session_id_avp", (cmd_function) w_ro_set_session_id_avp, 0, 0, 0, REQUEST_ROUTE | ONREPLY_ROUTE },
|
108
|
|
- { 0, 0, 0, 0, 0, 0 }
|
|
114
|
+ { 0, 0, 0, 0, 0, 0 }
|
109
|
115
|
};
|
110
|
116
|
|
111
|
117
|
static param_export_t params[] = {
|
112
|
|
- { "hash_size", INT_PARAM, &ro_session_hash_size },
|
113
|
|
- { "interim_update_credits", INT_PARAM, &interim_request_credits },
|
114
|
|
- { "timer_buffer", INT_PARAM, &ro_timer_buffer },
|
115
|
|
- { "ro_forced_peer", PARAM_STR, &ro_forced_peer },
|
116
|
|
- { "ro_auth_expiry", INT_PARAM, &ro_auth_expiry },
|
117
|
|
- { "cdp_event_latency", INT_PARAM, &cdp_event_latency }, /*flag: report slow processing of CDP
|
118
|
|
- callback events or not */
|
119
|
|
- { "cdp_event_threshold", INT_PARAM, &cdp_event_threshold }, /*time in ms above which we should
|
120
|
|
- report slow processing of CDP callback event*/
|
121
|
|
- { "cdp_event_latency_log", INT_PARAM, &cdp_event_latency_loglevel },/*log-level to use to report
|
122
|
|
- slow processing of CDP callback event*/
|
123
|
|
- { "single_ro_session_per_dialog", INT_PARAM, &single_ro_session_per_dialog },
|
124
|
|
- { "origin_host", PARAM_STR, &cfg.origin_host },
|
125
|
|
- { "origin_realm", PARAM_STR, &cfg.origin_realm },
|
126
|
|
- { "destination_realm", PARAM_STR, &cfg.destination_realm },
|
127
|
|
- { "destination_host", PARAM_STR, &cfg.destination_host },
|
128
|
|
- { "service_context_id_root",PARAM_STRING, &ro_service_context_id_root_s },
|
129
|
|
- { "service_context_id_ext", PARAM_STRING, &ro_service_context_id_ext_s },
|
130
|
|
- { "service_context_id_mnc", PARAM_STRING, &ro_service_context_id_mnc_s },
|
131
|
|
- { "service_context_id_mcc", PARAM_STRING, &ro_service_context_id_mcc_s },
|
132
|
|
- { "service_context_id_release", PARAM_STRING, &ro_service_context_id_release_s},
|
133
|
|
- { "voice_service_identifier", INT_PARAM, &voice_service_identifier },/*service id for voice*/
|
134
|
|
- { "voice_rating_group", INT_PARAM, &voice_rating_group },/*rating group for voice*/
|
135
|
|
- { "video_service_identifier", INT_PARAM, &video_service_identifier },/*service id for voice*/
|
136
|
|
- { "video_rating_group", INT_PARAM, &video_rating_group },/*rating group for voice*/
|
137
|
|
- { "db_mode", INT_PARAM, &ro_db_mode_param },
|
138
|
|
- { "db_url", PARAM_STR, &db_url },
|
139
|
|
- { "db_update_period", INT_PARAM, &db_update_period },
|
140
|
|
- { "vendor_specific_chargeinfo", INT_PARAM, &vendor_specific_chargeinfo }, /* VSI for extra charing info in Ro */
|
141
|
|
- { "vendor_specific_id", INT_PARAM, &vendor_specific_id }, /* VSI for extra charing info in Ro */
|
142
|
|
- { "custom_user_avp", PARAM_STR, &custom_user_spec},
|
143
|
|
- { "app_provided_party_avp", PARAM_STR, &app_provided_party_spec},
|
144
|
|
- { 0, 0, 0 }
|
|
118
|
+ { "hash_size", INT_PARAM, &ro_session_hash_size },
|
|
119
|
+ { "interim_update_credits", INT_PARAM, &interim_request_credits },
|
|
120
|
+ { "timer_buffer", INT_PARAM, &ro_timer_buffer },
|
|
121
|
+ { "ro_forced_peer", PARAM_STR, &ro_forced_peer },
|
|
122
|
+ { "ro_auth_expiry", INT_PARAM, &ro_auth_expiry },
|
|
123
|
+ { "cdp_event_latency", INT_PARAM, &cdp_event_latency }, /*flag: report slow processing of CDP
|
|
124
|
+ callback events or not */
|
|
125
|
+ { "cdp_event_threshold", INT_PARAM, &cdp_event_threshold }, /*time in ms above which we should
|
|
126
|
+ report slow processing of CDP callback event*/
|
|
127
|
+ { "cdp_event_latency_log", INT_PARAM, &cdp_event_latency_loglevel },/*log-level to use to report
|
|
128
|
+ slow processing of CDP callback event*/
|
|
129
|
+ { "single_ro_session_per_dialog", INT_PARAM, &single_ro_session_per_dialog },
|
|
130
|
+ { "origin_host", PARAM_STR, &cfg.origin_host },
|
|
131
|
+ { "origin_realm", PARAM_STR, &cfg.origin_realm },
|
|
132
|
+ { "destination_realm", PARAM_STR, &cfg.destination_realm },
|
|
133
|
+ { "destination_host", PARAM_STR, &cfg.destination_host },
|
|
134
|
+ { "service_context_id_root",PARAM_STRING, &ro_service_context_id_root_s },
|
|
135
|
+ { "service_context_id_ext", PARAM_STRING, &ro_service_context_id_ext_s },
|
|
136
|
+ { "service_context_id_mnc", PARAM_STRING, &ro_service_context_id_mnc_s },
|
|
137
|
+ { "service_context_id_mcc", PARAM_STRING, &ro_service_context_id_mcc_s },
|
|
138
|
+ { "service_context_id_release", PARAM_STRING, &ro_service_context_id_release_s},
|
|
139
|
+ { "voice_service_identifier", INT_PARAM, &voice_service_identifier },/*service id for voice*/
|
|
140
|
+ { "voice_rating_group", INT_PARAM, &voice_rating_group },/*rating group for voice*/
|
|
141
|
+ { "video_service_identifier", INT_PARAM, &video_service_identifier },/*service id for voice*/
|
|
142
|
+ { "video_rating_group", INT_PARAM, &video_rating_group },/*rating group for voice*/
|
|
143
|
+ { "db_mode", INT_PARAM, &ro_db_mode_param },
|
|
144
|
+ { "db_url", PARAM_STR, &db_url },
|
|
145
|
+ { "db_update_period", INT_PARAM, &db_update_period },
|
|
146
|
+ { "vendor_specific_chargeinfo", INT_PARAM, &vendor_specific_chargeinfo }, /* VSI for extra charing info in Ro */
|
|
147
|
+ { "vendor_specific_id", INT_PARAM, &vendor_specific_id }, /* VSI for extra charing info in Ro */
|
|
148
|
+ { "custom_user_avp", PARAM_STR, &custom_user_spec},
|
|
149
|
+ { "app_provided_party_avp", PARAM_STR, &app_provided_party_spec},
|
|
150
|
+ { 0, 0, 0 }
|
145
|
151
|
};
|
146
|
152
|
|
147
|
153
|
/** module exports */
|
148
|
154
|
struct module_exports exports = { MOD_NAME, DEFAULT_DLFLAGS, /* dlopen flags */
|
149
|
|
- cmds, /* Exported functions */
|
150
|
|
- params, /* Exported params */
|
151
|
|
- 0, /* exported RPC methods */
|
152
|
|
- 0, /* exported pseudo-variables */
|
153
|
|
- 0,
|
154
|
|
- mod_init, /* module initialization function */
|
155
|
|
- mod_child_init, /* per-child init function */
|
156
|
|
- mod_destroy /* module destroy functoin */
|
|
155
|
+ cmds, /* Exported functions */
|
|
156
|
+ params, /* Exported params */
|
|
157
|
+ 0, /* exported RPC methods */
|
|
158
|
+ 0, /* exported pseudo-variables */
|
|
159
|
+ 0,
|
|
160
|
+ mod_init, /* module initialization function */
|
|
161
|
+ mod_child_init, /* per-child init function */
|
|
162
|
+ mod_destroy /* module destroy functoin */
|
157
|
163
|
};
|
158
|
164
|
|
159
|
165
|
int fix_parameters() {
|
160
|
|
- cfg.service_context_id = shm_malloc(sizeof(str));
|
161
|
|
- if (!cfg.service_context_id) {
|
162
|
|
- LM_ERR("fix_parameters:not enough shm memory\n");
|
163
|
|
- return 0;
|
164
|
|
- }
|
165
|
|
- cfg.service_context_id->len = strlen(ro_service_context_id_ext_s)
|
166
|
|
- + strlen(ro_service_context_id_mnc_s)
|
167
|
|
- + strlen(ro_service_context_id_mcc_s)
|
168
|
|
- + strlen(ro_service_context_id_release_s)
|
169
|
|
- + strlen(ro_service_context_id_root_s) + 5;
|
170
|
|
- cfg.service_context_id->s =
|
171
|
|
- pkg_malloc(cfg.service_context_id->len * sizeof (char));
|
172
|
|
- if (!cfg.service_context_id->s) {
|
173
|
|
- LM_ERR("fix_parameters: not enough memory!\n");
|
174
|
|
- return 0;
|
175
|
|
- }
|
176
|
|
- cfg.service_context_id->len = sprintf(cfg.service_context_id->s,
|
177
|
|
- "%s.%s.%s.%s.%s", ro_service_context_id_ext_s,
|
178
|
|
- ro_service_context_id_mnc_s, ro_service_context_id_mcc_s,
|
179
|
|
- ro_service_context_id_release_s, ro_service_context_id_root_s);
|
180
|
|
- if (cfg.service_context_id->len < 0) {
|
181
|
|
- LM_ERR("fix_parameters: error while creating service_context_id\n");
|
182
|
|
- return 0;
|
183
|
|
- }
|
184
|
|
-
|
185
|
|
- if (custom_user_spec.s) {
|
186
|
|
- if (pv_parse_spec(&custom_user_spec, &custom_user_avp) == 0
|
187
|
|
- && (custom_user_avp.type != PVT_AVP)) {
|
188
|
|
- LM_ERR("malformed or non AVP custom_user "
|
189
|
|
- "AVP definition in '%.*s'\n", custom_user_spec.len,custom_user_spec.s);
|
190
|
|
- return -1;
|
191
|
|
- }
|
192
|
|
- }
|
193
|
|
-
|
194
|
|
- if (app_provided_party_spec.s) {
|
195
|
|
- if (pv_parse_spec(&app_provided_party_spec, &app_provided_party_avp) == 0
|
196
|
|
- && (app_provided_party_avp.type != PVT_AVP)) {
|
197
|
|
- LM_ERR("malformed or non AVP app_provided_party "
|
198
|
|
- "AVP definition in '%.*s'\n",
|
199
|
|
- app_provided_party_spec.len,
|
200
|
|
- app_provided_party_spec.s);
|
201
|
|
- return -1;
|
202
|
|
- }
|
203
|
|
- }
|
204
|
|
-
|
205
|
|
- init_custom_user(custom_user_spec.s ? &custom_user_avp : 0);
|
206
|
|
- init_app_provided_party(app_provided_party_spec.s ? &app_provided_party_avp : 0);
|
207
|
|
-
|
208
|
|
- return 1;
|
|
166
|
+ cfg.service_context_id = shm_malloc(sizeof(str));
|
|
167
|
+ if (!cfg.service_context_id) {
|
|
168
|
+ LM_ERR("fix_parameters:not enough shm memory\n");
|
|
169
|
+ return 0;
|
|
170
|
+ }
|
|
171
|
+ cfg.service_context_id->len = strlen(ro_service_context_id_ext_s)
|
|
172
|
+ + strlen(ro_service_context_id_mnc_s)
|
|
173
|
+ + strlen(ro_service_context_id_mcc_s)
|
|
174
|
+ + strlen(ro_service_context_id_release_s)
|
|
175
|
+ + strlen(ro_service_context_id_root_s) + 5;
|
|
176
|
+ cfg.service_context_id->s =
|
|
177
|
+ pkg_malloc(cfg.service_context_id->len * sizeof (char));
|
|
178
|
+ if (!cfg.service_context_id->s) {
|
|
179
|
+ LM_ERR("fix_parameters: not enough memory!\n");
|
|
180
|
+ return 0;
|
|
181
|
+ }
|
|
182
|
+ cfg.service_context_id->len = sprintf(cfg.service_context_id->s,
|
|
183
|
+ "%s.%s.%s.%s.%s", ro_service_context_id_ext_s,
|
|
184
|
+ ro_service_context_id_mnc_s, ro_service_context_id_mcc_s,
|
|
185
|
+ ro_service_context_id_release_s, ro_service_context_id_root_s);
|
|
186
|
+ if (cfg.service_context_id->len < 0) {
|
|
187
|
+ LM_ERR("fix_parameters: error while creating service_context_id\n");
|
|
188
|
+ return 0;
|
|
189
|
+ }
|
|
190
|
+
|
|
191
|
+ if (custom_user_spec.s) {
|
|
192
|
+ if (pv_parse_spec(&custom_user_spec, &custom_user_avp) == 0
|
|
193
|
+ && (custom_user_avp.type != PVT_AVP)) {
|
|
194
|
+ LM_ERR("malformed or non AVP custom_user "
|
|
195
|
+ "AVP definition in '%.*s'\n", custom_user_spec.len,custom_user_spec.s);
|
|
196
|
+ return -1;
|
|
197
|
+ }
|
|
198
|
+ }
|
|
199
|
+
|
|
200
|
+ if (app_provided_party_spec.s) {
|
|
201
|
+ if (pv_parse_spec(&app_provided_party_spec, &app_provided_party_avp) == 0
|
|
202
|
+ && (app_provided_party_avp.type != PVT_AVP)) {
|
|
203
|
+ LM_ERR("malformed or non AVP app_provided_party "
|
|
204
|
+ "AVP definition in '%.*s'\n",
|
|
205
|
+ app_provided_party_spec.len,
|
|
206
|
+ app_provided_party_spec.s);
|
|
207
|
+ return -1;
|
|
208
|
+ }
|
|
209
|
+ }
|
|
210
|
+
|
|
211
|
+ init_custom_user(custom_user_spec.s ? &custom_user_avp : 0);
|
|
212
|
+ init_app_provided_party(app_provided_party_spec.s ? &app_provided_party_avp : 0);
|
|
213
|
+
|
|
214
|
+ return 1;
|
209
|
215
|
}
|
210
|
216
|
|
211
|
217
|
static int mod_init(void) {
|
212
|
|
- int n;
|
213
|
|
- load_tm_f load_tm;
|
214
|
|
-
|
215
|
|
- if (!fix_parameters()) {
|
216
|
|
- LM_ERR("unable to set Ro configuration parameters correctly\n");
|
217
|
|
- goto error;
|
218
|
|
- }
|
219
|
|
-
|
220
|
|
- /* bind to the tm module */
|
221
|
|
- if (!(load_tm = (load_tm_f) find_export("load_tm", NO_SCRIPT, 0))) {
|
222
|
|
- LM_ERR("Can not import load_tm. This module requires tm module\n");
|
223
|
|
- goto error;
|
224
|
|
- }
|
225
|
|
- if (load_tm(&tmb) == -1)
|
226
|
|
- goto error;
|
227
|
|
-
|
228
|
|
- if (load_cdp_api(&cdpb) != 0) { /* load the CDP API */
|
229
|
|
- LM_ERR("can't load CDP API\n");
|
230
|
|
- goto error;
|
231
|
|
- }
|
232
|
|
-
|
233
|
|
- if (load_ims_dlg_api(&dlgb) != 0) { /* load the dialog API */
|
234
|
|
- LM_ERR("can't load Dialog API\n");
|
235
|
|
- goto error;
|
236
|
|
- }
|
237
|
|
-
|
238
|
|
- cdp_avp = load_cdp_avp(); /* load CDP_AVP API */
|
239
|
|
- if (!cdp_avp) {
|
240
|
|
- LM_ERR("can't load CDP_AVP API\n");
|
241
|
|
- goto error;
|
242
|
|
- }
|
|
218
|
+ int n;
|
|
219
|
+ load_tm_f load_tm;
|
|
220
|
+
|
|
221
|
+ if (!fix_parameters()) {
|
|
222
|
+ LM_ERR("unable to set Ro configuration parameters correctly\n");
|
|
223
|
+ goto error;
|
|
224
|
+ }
|
|
225
|
+
|
|
226
|
+ /* bind to the tm module */
|
|
227
|
+ if (!(load_tm = (load_tm_f) find_export("load_tm", NO_SCRIPT, 0))) {
|
|
228
|
+ LM_ERR("Can not import load_tm. This module requires tm module\n");
|
|
229
|
+ goto error;
|
|
230
|
+ }
|
|
231
|
+ if (load_tm(&tmb) == -1)
|
|
232
|
+ goto error;
|
|
233
|
+
|
|
234
|
+ if (load_cdp_api(&cdpb) != 0) { /* load the CDP API */
|
|
235
|
+ LM_ERR("can't load CDP API\n");
|
|
236
|
+ goto error;
|
|
237
|
+ }
|
|
238
|
+
|
|
239
|
+ if (load_ims_dlg_api(&dlgb) != 0) { /* load the dialog API */
|
|
240
|
+ LM_ERR("can't load Dialog API\n");
|
|
241
|
+ goto error;
|
|
242
|
+ }
|
|
243
|
+
|
|
244
|
+ cdp_avp = load_cdp_avp(); /* load CDP_AVP API */
|
|
245
|
+ if (!cdp_avp) {
|
|
246
|
+ LM_ERR("can't load CDP_AVP API\n");
|
|
247
|
+ goto error;
|
|
248
|
+ }
|
243
|
249
|
|
244
|
|
- /* init timer lists*/
|
245
|
|
- if (init_ro_timer(ro_session_ontimeout) != 0) {
|
246
|
|
- LM_ERR("cannot init timer list\n");
|
247
|
|
- return -1;
|
248
|
|
- }
|
249
|
|
-
|
250
|
|
- /* initialized the hash table */
|
251
|
|
- for (n = 0; n < (8 * sizeof(n)); n++) {
|
252
|
|
- if (ro_session_hash_size == (1 << n))
|
253
|
|
- break;
|
254
|
|
- if (ro_session_hash_size < (1 << n)) {
|
255
|
|
- 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));
|
256
|
|
- ro_session_hash_size = 1 << (n - 1);
|
257
|
|
- }
|
258
|
|
- }
|
259
|
|
-
|
260
|
|
- if (init_ro_session_table(ro_session_hash_size) < 0) {
|
261
|
|
- LM_ERR("failed to create ro session hash table\n");
|
262
|
|
- return -1;
|
263
|
|
- }
|
264
|
|
-
|
265
|
|
- /* register global timer */
|
266
|
|
- if (register_timer(ro_timer_routine, 0/*(void*)ro_session_list*/, 1) < 0) {
|
267
|
|
- LM_ERR("failed to register timer \n");
|
268
|
|
- return -1;
|
269
|
|
- }
|
270
|
|
-
|
271
|
|
- if (ims_charging_init_counters() != 0) {
|
272
|
|
- LM_ERR("Failed to register counters for ims_charging module\n");
|
273
|
|
- return -1;
|
274
|
|
- }
|
275
|
|
-
|
276
|
|
- /* if a database should be used to store the dialogs' information */
|
277
|
|
- ro_db_mode = ro_db_mode_param;
|
278
|
|
- if (ro_db_mode == DB_MODE_NONE) {
|
279
|
|
- db_url.s = 0;
|
280
|
|
- db_url.len = 0;
|
281
|
|
- } else {
|
282
|
|
- if (ro_db_mode != DB_MODE_REALTIME && ro_db_mode != DB_MODE_SHUTDOWN) {
|
283
|
|
- LM_ERR("unsupported db_mode %d\n", ro_db_mode);
|
284
|
|
- return -1;
|
285
|
|
- }
|
286
|
|
- if (!db_url.s || db_url.len == 0) {
|
287
|
|
- LM_ERR("db_url not configured for db_mode %d\n", ro_db_mode);
|
288
|
|
- return -1;
|
289
|
|
- }
|
290
|
|
- if (init_ro_db(&db_url, ro_session_hash_size, db_update_period, db_fetch_rows) != 0) {
|
291
|
|
- LM_ERR("failed to initialize the DB support\n");
|
292
|
|
- return -1;
|
293
|
|
- }
|
|
250
|
+ /* init timer lists*/
|
|
251
|
+ if (init_ro_timer(ro_session_ontimeout) != 0) {
|
|
252
|
+ LM_ERR("cannot init timer list\n");
|
|
253
|
+ return -1;
|
|
254
|
+ }
|
|
255
|
+
|
|
256
|
+ /* initialized the hash table */
|
|
257
|
+ for (n = 0; n < (8 * sizeof(n)); n++) {
|
|
258
|
+ if (ro_session_hash_size == (1 << n))
|
|
259
|
+ break;
|
|
260
|
+ if (ro_session_hash_size < (1 << n)) {
|
|
261
|
+ 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));
|
|
262
|
+ ro_session_hash_size = 1 << (n - 1);
|
|
263
|
+ }
|
|
264
|
+ }
|
|
265
|
+
|
|
266
|
+ if (init_ro_session_table(ro_session_hash_size) < 0) {
|
|
267
|
+ LM_ERR("failed to create ro session hash table\n");
|
|
268
|
+ return -1;
|
|
269
|
+ }
|
|
270
|
+
|
|
271
|
+ /* register global timer */
|
|
272
|
+ if (register_timer(ro_timer_routine, 0/*(void*)ro_session_list*/, 1) < 0) {
|
|
273
|
+ LM_ERR("failed to register timer \n");
|
|
274
|
+ return -1;
|
|
275
|
+ }
|
|
276
|
+
|
|
277
|
+ if (ims_charging_init_counters() != 0) {
|
|
278
|
+ LM_ERR("Failed to register counters for ims_charging module\n");
|
|
279
|
+ return -1;
|
|
280
|
+ }
|
|
281
|
+
|
|
282
|
+ /* if a database should be used to store the dialogs' information */
|
|
283
|
+ ro_db_mode = ro_db_mode_param;
|
|
284
|
+ if (ro_db_mode == DB_MODE_NONE) {
|
|
285
|
+ db_url.s = 0;
|
|
286
|
+ db_url.len = 0;
|
|
287
|
+ } else {
|
|
288
|
+ if (ro_db_mode != DB_MODE_REALTIME && ro_db_mode != DB_MODE_SHUTDOWN) {
|
|
289
|
+ LM_ERR("unsupported db_mode %d\n", ro_db_mode);
|
|
290
|
+ return -1;
|
|
291
|
+ }
|
|
292
|
+ if (!db_url.s || db_url.len == 0) {
|
|
293
|
+ LM_ERR("db_url not configured for db_mode %d\n", ro_db_mode);
|
|
294
|
+ return -1;
|
|
295
|
+ }
|
|
296
|
+ if (init_ro_db(&db_url, ro_session_hash_size, db_update_period, db_fetch_rows) != 0) {
|
|
297
|
+ LM_ERR("failed to initialize the DB support\n");
|
|
298
|
+ return -1;
|
|
299
|
+ }
|
294
|
300
|
// run_load_callbacks();
|
295
|
|
- }
|
|
301
|
+ }
|
296
|
302
|
|
297
|
|
- return 0;
|
|
303
|
+ return 0;
|
298
|
304
|
|
299
|
305
|
error:
|
300
|
|
- LM_ERR("Failed to initialise ims_charging module\n");
|
301
|
|
- return RO_RETURN_FALSE;
|
|
306
|
+ LM_ERR("Failed to initialise ims_charging module\n");
|
|
307
|
+ return RO_RETURN_FALSE;
|
302
|
308
|
|
303
|
309
|
}
|
304
|
310
|
|
...
|
...
|
@@ -306,20 +312,20 @@ static int mod_child_init(int rank) {
|
306
|
312
|
ro_db_mode = ro_db_mode_param;
|
307
|
313
|
|
308
|
314
|
if (((ro_db_mode == DB_MODE_REALTIME) && (rank > 0 || rank == PROC_TIMER)) ||
|
309
|
|
- (ro_db_mode == DB_MODE_SHUTDOWN && (rank == PROC_MAIN))) {
|
310
|
|
- if (ro_connect_db(&db_url)) {
|
311
|
|
- LM_ERR("failed to connect to database (rank=%d)\n", rank);
|
312
|
|
- return -1;
|
313
|
|
- }
|
|
315
|
+ (ro_db_mode == DB_MODE_SHUTDOWN && (rank == PROC_MAIN))) {
|
|
316
|
+ if (ro_connect_db(&db_url)) {
|
|
317
|
+ LM_ERR("failed to connect to database (rank=%d)\n", rank);
|
|
318
|
+ return -1;
|
|
319
|
+ }
|
314
|
320
|
}
|
315
|
321
|
|
316
|
322
|
/* in DB_MODE_SHUTDOWN only PROC_MAIN will do a DB dump at the end, so
|
317
|
323
|
* for the rest of the processes will be the same as DB_MODE_NONE */
|
318
|
324
|
if (ro_db_mode == DB_MODE_SHUTDOWN && rank != PROC_MAIN)
|
319
|
|
- ro_db_mode = DB_MODE_NONE;
|
|
325
|
+ ro_db_mode = DB_MODE_NONE;
|
320
|
326
|
/* in DB_MODE_REALTIME and DB_MODE_DELAYED the PROC_MAIN have no DB handle */
|
321
|
327
|
if ((ro_db_mode == DB_MODE_REALTIME) && rank == PROC_MAIN)
|
322
|
|
- ro_db_mode = DB_MODE_NONE;
|
|
328
|
+ ro_db_mode = DB_MODE_NONE;
|
323
|
329
|
|
324
|
330
|
return 0;
|
325
|
331
|
}
|
...
|
...
|
@@ -348,39 +354,68 @@ int create_response_avp_string(char* name, str* val) {
|
348
|
354
|
|
349
|
355
|
//This function gets the dlg from the current msg, gets the ro_session from the dlg and sets a AVP for use in the cfg file: ro_session_id
|
350
|
356
|
static int w_ro_set_session_id_avp(struct sip_msg *msg, char *str1, char *str2) {
|
351
|
|
- struct ro_session *ro_session = 0;
|
352
|
|
- struct dlg_cell* dlg;
|
353
|
|
- int res = -1;
|
354
|
|
-
|
355
|
|
- //get dlg from msg
|
356
|
|
- dlg = dlgb.get_dlg(msg);
|
357
|
|
- if (!dlg) {
|
358
|
|
- LM_ERR("Unable to find dialog and cannot do Ro charging without it\n");
|
359
|
|
- return RO_RETURN_ERROR;
|
|
357
|
+ return ki_ro_set_session_id_avp(msg);
|
|
358
|
+}
|
|
359
|
+
|
|
360
|
+static int w_ro_ccr_stop(struct sip_msg *msg, char* c_direction, char* _code, char* _reason) {
|
|
361
|
+ str s_code, s_reason, s_direction;
|
|
362
|
+ s_direction.s = c_direction;
|
|
363
|
+ s_direction.len = strlen(c_direction);
|
|
364
|
+ unsigned int code;
|
|
365
|
+
|
|
366
|
+ if (get_str_fparam(&s_code, msg, (fparam_t*) _code) < 0) {
|
|
367
|
+ LM_ERR("failed to get code\n");
|
|
368
|
+ return RO_RETURN_ERROR;
|
360
|
369
|
}
|
361
|
|
-
|
362
|
|
- //get ro session id from dialog
|
363
|
|
- ro_session= lookup_ro_session(dlg->h_entry, &dlg->callid, 0, 0);
|
364
|
|
- if(!ro_session) {
|
365
|
|
- LM_ERR("Unable to find Ro charging data\n");
|
366
|
|
- dlgb.release_dlg(dlg);
|
367
|
|
- return RO_RETURN_ERROR;
|
|
370
|
+ LM_DBG("Code is [%.*s]\n", s_code.len, s_code.s);
|
|
371
|
+ if (get_str_fparam(&s_reason, msg, (fparam_t*) _reason) < 0) {
|
|
372
|
+ LM_ERR("failed to get reason\n");
|
|
373
|
+ return RO_RETURN_ERROR;
|
|
374
|
+ }
|
|
375
|
+
|
|
376
|
+ if (str2int(&s_code, &code) != 0) {
|
|
377
|
+ LM_ERR("Bad response code: [%.*s]\n", s_code.len, s_code.s);
|
|
378
|
+ return RO_RETURN_FALSE;
|
368
|
379
|
}
|
|
380
|
+
|
|
381
|
+ return ki_ro_ccr_stop(msg, &s_direction, (int) code, &s_reason);
|
|
382
|
+
|
|
383
|
+}
|
|
384
|
+
|
|
385
|
+static int w_ro_ccr(struct sip_msg *msg, char* c_route_name, char* c_direction, int reservation_units, char* c_incoming_trunk_id, char* c_outgoing_trunk_id) {
|
|
386
|
+ str s_route_name, s_direction, s_incoming_trunk_id, s_outgoing_trunk_id;
|
369
|
387
|
|
370
|
|
- //set avp response with session id
|
371
|
|
- res = create_response_avp_string("ro_session_id", &ro_session->ro_session_id);
|
372
|
|
- dlgb.release_dlg(dlg);
|
373
|
|
- unref_ro_session(ro_session, 1, 1);
|
374
|
|
- return res;
|
|
388
|
+ if (get_str_fparam(&s_route_name, msg, (fparam_t*) c_route_name) < 0) {
|
|
389
|
+ LM_ERR("failed to get s_route_name\n");
|
|
390
|
+ return RO_RETURN_ERROR;
|
|
391
|
+ }
|
|
392
|
+ if (get_str_fparam(&s_direction, msg, (fparam_t*) c_direction) < 0) {
|
|
393
|
+ LM_ERR("failed to get s_direction\n");
|
|
394
|
+ return RO_RETURN_ERROR;
|
|
395
|
+ }
|
|
396
|
+ if (get_str_fparam(&s_incoming_trunk_id, msg, (fparam_t*) c_incoming_trunk_id) < 0) {
|
|
397
|
+ LM_ERR("failed to get s_incoming_trunk_id\n");
|
|
398
|
+ return RO_RETURN_ERROR;
|
|
399
|
+ }
|
|
400
|
+ if (get_str_fparam(&s_outgoing_trunk_id, msg, (fparam_t*) c_outgoing_trunk_id) < 0) {
|
|
401
|
+ LM_ERR("failed to get s_outgoing_trunk_id\n");
|
|
402
|
+ return RO_RETURN_ERROR;
|
|
403
|
+ }
|
|
404
|
+
|
|
405
|
+ return ki_ro_ccr(msg, &s_route_name, &s_direction, reservation_units, &s_incoming_trunk_id, &s_outgoing_trunk_id);
|
375
|
406
|
}
|
376
|
407
|
|
377
|
|
-static int w_ro_ccr_stop(struct sip_msg *msg, char* c_direction, char* _code, char* _reason) {
|
|
408
|
+static int ki_ro_ccr_stop(sip_msg_t *msg, str* p_direction, int p_code, str* p_reason) {
|
378
|
409
|
struct ro_session* ro_session;
|
379
|
410
|
struct ro_session_entry *ro_session_entry;
|
380
|
411
|
unsigned int h_entry;
|
381
|
412
|
str s_code, s_reason;
|
382
|
413
|
unsigned int code;
|
383
|
414
|
int dir = 0; /*any side*/
|
|
415
|
+ char *c_direction;
|
|
416
|
+ c_direction = p_direction->s;
|
|
417
|
+ s_reason = *p_reason;
|
|
418
|
+ code = (unsigned int)p_code;
|
384
|
419
|
|
385
|
420
|
LM_DBG("Inside Ro_CCR_Stop with direction [%s]\n", c_direction);
|
386
|
421
|
if (strlen(c_direction) == 4) {
|
...
|
...
|
@@ -399,24 +434,6 @@ static int w_ro_ccr_stop(struct sip_msg *msg, char* c_direction, char* _code, ch
|
399
|
434
|
return RO_RETURN_ERROR;
|
400
|
435
|
}
|
401
|
436
|
|
402
|
|
- if (get_str_fparam(&s_code, msg, (fparam_t*) _code) < 0) {
|
403
|
|
- LM_ERR("failed to get code\n");
|
404
|
|
- dlgb.release_dlg(dlg);
|
405
|
|
- return RO_RETURN_ERROR;
|
406
|
|
- }
|
407
|
|
- LM_DBG("Code is [%.*s]\n", s_code.len, s_code.s);
|
408
|
|
- if (get_str_fparam(&s_reason, msg, (fparam_t*) _reason) < 0) {
|
409
|
|
- LM_ERR("failed to get reason\n");
|
410
|
|
- dlgb.release_dlg(dlg);
|
411
|
|
- return RO_RETURN_ERROR;
|
412
|
|
- }
|
413
|
|
-
|
414
|
|
- if (str2int(&s_code, &code) != 0) {
|
415
|
|
- LM_ERR("Bad response code: [%.*s]\n", s_code.len, s_code.s);
|
416
|
|
- dlgb.release_dlg(dlg);
|
417
|
|
- return RO_RETURN_FALSE;
|
418
|
|
- }
|
419
|
|
-
|
420
|
437
|
// switch (code) {
|
421
|
438
|
// case 486:
|
422
|
439
|
// termcode = VS_TERMCODE_BUSYHERE;
|
...
|
...
|
@@ -463,193 +480,226 @@ done:
|
463
|
480
|
return RO_RETURN_TRUE;
|
464
|
481
|
}
|
465
|
482
|
|
466
|
|
-static int w_ro_ccr(struct sip_msg *msg, char* c_route_name, char* c_direction, int reservation_units, char* c_incoming_trunk_id, char* c_outgoing_trunk_id) {
|
467
|
|
- /* PSEUDOCODE/NOTES
|
468
|
|
- * 1. What mode are we in - terminating or originating
|
469
|
|
- * 2. We assume this is SCUR in this module for now - can see event based charging in another component instead (AS for SMS for example, etc)
|
470
|
|
- * 4. Check a dialog exists for call, if not we fail
|
471
|
|
- * 5. make sure we dont already have an Ro Session for this dialog
|
472
|
|
- * 6. create new Ro Session
|
473
|
|
- * 7. register for DLG callback passing new Ro session as parameter - (if dlg torn down we know which Ro session it is associated with)
|
474
|
|
- *
|
475
|
|
- *
|
476
|
|
- */
|
477
|
|
- int ret = RO_RETURN_TRUE;
|
478
|
|
- int dir = 0;
|
479
|
|
- str identity = {0, 0},
|
480
|
|
- pani = {0,0},
|
481
|
|
- contact = {0, 0};
|
482
|
|
- struct hdr_field *h=0;
|
483
|
|
-
|
484
|
|
- cfg_action_t* cfg_action;
|
485
|
|
- tm_cell_t *t;
|
486
|
|
- unsigned int tindex = 0,
|
487
|
|
- tlabel = 0;
|
488
|
|
- struct dlg_cell* dlg;
|
489
|
|
- struct ro_session *ro_session = 0;
|
490
|
|
- int free_contact = 0;
|
491
|
|
-
|
492
|
|
- str s_route_name, s_direction, s_incoming_trunk_id, s_outgoing_trunk_id;
|
493
|
|
-
|
494
|
|
- if (get_str_fparam(&s_route_name, msg, (fparam_t*) c_route_name) < 0) {
|
495
|
|
- LM_ERR("failed to get s_route_name\n");
|
496
|
|
- return RO_RETURN_ERROR;
|
497
|
|
- }
|
498
|
|
- if (get_str_fparam(&s_direction, msg, (fparam_t*) c_direction) < 0) {
|
499
|
|
- LM_ERR("failed to get s_direction\n");
|
500
|
|
- return RO_RETURN_ERROR;
|
501
|
|
- }
|
502
|
|
- if (get_str_fparam(&s_incoming_trunk_id, msg, (fparam_t*) c_incoming_trunk_id) < 0) {
|
503
|
|
- LM_ERR("failed to get s_incoming_trunk_id\n");
|
504
|
|
- return RO_RETURN_ERROR;
|
505
|
|
- }
|
506
|
|
- if (get_str_fparam(&s_outgoing_trunk_id, msg, (fparam_t*) c_outgoing_trunk_id) < 0) {
|
507
|
|
- LM_ERR("failed to get s_outgoing_trunk_id\n");
|
508
|
|
- return RO_RETURN_ERROR;
|
509
|
|
- }
|
510
|
|
-
|
511
|
|
- LM_DBG("Ro CCR initiated: direction:%.*s, reservation_units:%i, route_name:%.*s, incoming_trunk_id:%.*s outgoing_trunk_id:%.*s\n",
|
512
|
|
- s_direction.len, s_direction.s,
|
513
|
|
- reservation_units,
|
514
|
|
- s_route_name.len, s_route_name.s,
|
515
|
|
- s_incoming_trunk_id.len, s_incoming_trunk_id.s,
|
516
|
|
- s_outgoing_trunk_id.len, s_outgoing_trunk_id.s);
|
517
|
|
-
|
518
|
|
-
|
519
|
|
- if (msg->first_line.type != SIP_REQUEST) {
|
520
|
|
- LM_ERR("Ro_CCR() called from SIP reply.\n");
|
521
|
|
- return RO_RETURN_ERROR;;
|
522
|
|
- }
|
523
|
|
-
|
524
|
|
- //make sure we can get the dialog! if not, we can't continue
|
525
|
|
-
|
526
|
|
- dlg = dlgb.get_dlg(msg);
|
527
|
|
- if (!dlg) {
|
528
|
|
- LM_ERR("Unable to find dialog and cannot do Ro charging without it\n");
|
529
|
|
- return RO_RETURN_ERROR;
|
530
|
|
- }
|
531
|
|
-
|
532
|
|
- dir = get_direction_as_int(&s_direction);
|
533
|
|
-
|
534
|
|
- if (dir == RO_ORIG_DIRECTION) {
|
535
|
|
- //get caller IMPU from asserted identity
|
536
|
|
- if ((identity = cscf_get_asserted_identity(msg, 0)).len == 0) {
|
537
|
|
- LM_DBG("No P-Asserted-Identity hdr found. Using From hdr for asserted_identity\n");
|
538
|
|
- identity = dlg->from_uri;
|
539
|
|
- }
|
540
|
|
- //get caller contact from contact header - if not present then skip this
|
541
|
|
- if ((contact = cscf_get_contact(msg)).len == 0) {
|
542
|
|
- LM_WARN("Can not get contact from message - will not get callbacks if this IMPU is removed to terminate call\n");
|
543
|
|
- goto send_ccr;
|
544
|
|
- }
|
545
|
|
-
|
546
|
|
- pani = cscf_get_access_network_info(msg, &h);
|
547
|
|
- } else if (dir == RO_TERM_DIRECTION){
|
548
|
|
- //get callee IMPU from called part id - if not present then skip this
|
549
|
|
- if ((identity = cscf_get_public_identity_from_called_party_id(msg, &h)).len == 0) {
|
550
|
|
- LM_DBG("No P-Called-Identity hdr found - will not get callbacks if this IMPU is removed to terminate call\n");
|
551
|
|
- goto send_ccr;
|
552
|
|
- }
|
553
|
|
- //get callee contact from request URI
|
554
|
|
- contact = cscf_get_contact_from_requri(msg);
|
555
|
|
- free_contact = 1;
|
556
|
|
-
|
557
|
|
- } else {
|
558
|
|
- LM_CRIT("don't know what to do in unknown mode - should we even get here\n");
|
559
|
|
- ret = RO_RETURN_ERROR;
|
560
|
|
- goto done;
|
561
|
|
- }
|
562
|
|
-
|
563
|
|
- LM_DBG("IMPU data to pass to usrloc: contact <%.*s> identity <%.*s>\n", contact.len, contact.s, identity.len, identity.s);
|
|
483
|
+static int ki_ro_ccr(sip_msg_t *msg, str* s_route_name, str* s_direction, int reservation_units, str* s_incoming_trunk_id, str* s_outgoing_trunk_id) {
|
|
484
|
+ /* PSEUDOCODE/NOTES
|
|
485
|
+ * 1. What mode are we in - terminating or originating
|
|
486
|
+ * 2. We assume this is SCUR in this module for now - can see event based charging in another component instead (AS for SMS for example, etc)
|
|
487
|
+ * 4. Check a dialog exists for call, if not we fail
|
|
488
|
+ * 5. make sure we dont already have an Ro Session for this dialog
|
|
489
|
+ * 6. create new Ro Session
|
|
490
|
+ * 7. register for DLG callback passing new Ro session as parameter - (if dlg torn down we know which Ro session it is associated with)
|
|
491
|
+ *
|
|
492
|
+ *
|
|
493
|
+ */
|
|
494
|
+ int ret = RO_RETURN_TRUE;
|
|
495
|
+ int dir = 0;
|
|
496
|
+ str identity = {0, 0},
|
|
497
|
+ pani = {0,0},
|
|
498
|
+ contact = {0, 0};
|
|
499
|
+ struct hdr_field *h=0;
|
|
500
|
+
|
|
501
|
+ cfg_action_t* cfg_action;
|
|
502
|
+ tm_cell_t *t;
|
|
503
|
+ unsigned int tindex = 0,
|
|
504
|
+ tlabel = 0;
|
|
505
|
+ struct dlg_cell* dlg;
|
|
506
|
+ struct ro_session *ro_session = 0;
|
|
507
|
+ int free_contact = 0;
|
|
508
|
+
|
|
509
|
+ LM_DBG("Ro CCR initiated: direction:%.*s, reservation_units:%i, route_name:%.*s, incoming_trunk_id:%.*s outgoing_trunk_id:%.*s\n",
|
|
510
|
+ s_direction->len, s_direction->s,
|
|
511
|
+ reservation_units,
|
|
512
|
+ s_route_name->len, s_route_name->s,
|
|
513
|
+ s_incoming_trunk_id->len, s_incoming_trunk_id->s,
|
|
514
|
+ s_outgoing_trunk_id->len, s_outgoing_trunk_id->s);
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+ if (msg->first_line.type != SIP_REQUEST) {
|
|
518
|
+ LM_ERR("Ro_CCR() called from SIP reply.\n");
|
|
519
|
+ return RO_RETURN_ERROR;;
|
|
520
|
+ }
|
|
521
|
+
|
|
522
|
+ //make sure we can get the dialog! if not, we can't continue
|
|
523
|
+
|
|
524
|
+ dlg = dlgb.get_dlg(msg);
|
|
525
|
+ if (!dlg) {
|
|
526
|
+ LM_ERR("Unable to find dialog and cannot do Ro charging without it\n");
|
|
527
|
+ return RO_RETURN_ERROR;
|
|
528
|
+ }
|
|
529
|
+
|
|
530
|
+ dir = get_direction_as_int(&s_direction);
|
|
531
|
+
|
|
532
|
+ if (dir == RO_ORIG_DIRECTION) {
|
|
533
|
+ //get caller IMPU from asserted identity
|
|
534
|
+ if ((identity = cscf_get_asserted_identity(msg, 0)).len == 0) {
|
|
535
|
+ LM_DBG("No P-Asserted-Identity hdr found. Using From hdr for asserted_identity\n");
|
|
536
|
+ identity = dlg->from_uri;
|
|
537
|
+ }
|
|
538
|
+ //get caller contact from contact header - if not present then skip this
|
|
539
|
+ if ((contact = cscf_get_contact(msg)).len == 0) {
|
|
540
|
+ LM_WARN("Can not get contact from message - will not get callbacks if this IMPU is removed to terminate call\n");
|
|
541
|
+ goto send_ccr;
|
|
542
|
+ }
|
|
543
|
+
|
|
544
|
+ pani = cscf_get_access_network_info(msg, &h);
|
|
545
|
+ } else if (dir == RO_TERM_DIRECTION){
|
|
546
|
+ //get callee IMPU from called part id - if not present then skip this
|
|
547
|
+ if ((identity = cscf_get_public_identity_from_called_party_id(msg, &h)).len == 0) {
|
|
548
|
+ LM_DBG("No P-Called-Identity hdr found - will not get callbacks if this IMPU is removed to terminate call\n");
|
|
549
|
+ goto send_ccr;
|
|
550
|
+ }
|
|
551
|
+ //get callee contact from request URI
|
|
552
|
+ contact = cscf_get_contact_from_requri(msg);
|
|
553
|
+ free_contact = 1;
|
|
554
|
+
|
|
555
|
+ } else {
|
|
556
|
+ LM_CRIT("don't know what to do in unknown mode - should we even get here\n");
|
|
557
|
+ ret = RO_RETURN_ERROR;
|
|
558
|
+ goto done;
|
|
559
|
+ }
|
|
560
|
+
|
|
561
|
+ LM_DBG("IMPU data to pass to usrloc: contact <%.*s> identity <%.*s>\n", contact.len, contact.s, identity.len, identity.s);
|
564
|
562
|
|
565
|
563
|
send_ccr:
|
566
|
564
|
|
567
|
|
- //check if we need to send_ccr -
|
568
|
|
- //we get the ro_session based on dlg->h_id and dlg->h_entry and direction 0 (so get any ro_session)
|
569
|
|
- //if it already exists then we go to done
|
570
|
|
- if (single_ro_session_per_dialog && (ro_session = lookup_ro_session(dlg->h_entry, &dlg->callid, 0, 0))) {
|
571
|
|
- LM_DBG("single_ro_session_per_dialog = 1 and ro_session already exists for this dialog -so we don't need to send another one\n");
|
572
|
|
- unref_ro_session(ro_session,1,1);//for the lookup ro session ref
|
573
|
|
- goto done;
|
574
|
|
- }
|
575
|
|
-
|
576
|
|
- LM_DBG("Looking for route block [%.*s]\n", s_route_name.len, s_route_name.s);
|
577
|
|
-
|
578
|
|
- int ri = route_get(&main_rt, s_route_name.s);
|
579
|
|
- if (ri < 0) {
|
580
|
|
- LM_ERR("unable to find route block [%.*s]\n", s_route_name.len, s_route_name.s);
|
581
|
|
- ret = RO_RETURN_ERROR;
|
582
|
|
- goto done;
|
583
|
|
- }
|
584
|
|
-
|
585
|
|
- cfg_action = main_rt.rlist[ri];
|
586
|
|
- if (!cfg_action) {
|
587
|
|
- LM_ERR("empty action lists in route block [%.*s]\n", s_route_name.len, s_route_name.s);
|
588
|
|
- ret = RO_RETURN_ERROR;
|
589
|
|
- goto done;
|
590
|
|
- }
|
591
|
|
-
|
592
|
|
- //before we send lets suspend the transaction
|
593
|
|
- t = tmb.t_gett();
|
594
|
|
- if (t == NULL || t == T_UNDEFINED) {
|
595
|
|
- if (tmb.t_newtran(msg) < 0) {
|
596
|
|
- LM_ERR("cannot create the transaction for CCR async\n");
|
597
|
|
- ret = RO_RETURN_ERROR;
|
598
|
|
- goto done;
|
599
|
|
- }
|
600
|
|
- t = tmb.t_gett();
|
601
|
|
- if (t == NULL || t == T_UNDEFINED) {
|
602
|
|
- LM_ERR("cannot lookup the transaction\n");
|
603
|
|
- ret = RO_RETURN_ERROR;
|
604
|
|
- goto done;
|
605
|
|
- }
|
606
|
|
- }
|
607
|
|
-
|
608
|
|
- LM_DBG("Suspending SIP TM transaction\n");
|
609
|
|
- if (tmb.t_suspend(msg, &tindex, &tlabel) != 0) {
|
610
|
|
- LM_ERR("failed to suspend the TM processing\n");
|
611
|
|
- ret = RO_RETURN_ERROR;
|
612
|
|
- goto done;
|
613
|
|
- }
|
614
|
|
-
|
615
|
|
- ret = Ro_Send_CCR(msg, dlg, dir, reservation_units, &s_incoming_trunk_id, &s_outgoing_trunk_id, &pani, cfg_action, tindex, tlabel);
|
616
|
|
-
|
617
|
|
- if(ret < 0){
|
618
|
|
- LM_ERR("Failed to send CCR\n");
|
619
|
|
- tmb.t_cancel_suspend(tindex, tlabel);
|
620
|
|
- }
|
|
565
|
+ //check if we need to send_ccr -
|
|
566
|
+ //we get the ro_session based on dlg->h_id and dlg->h_entry and direction 0 (so get any ro_session)
|
|
567
|
+ //if it already exists then we go to done
|
|
568
|
+ if (single_ro_session_per_dialog && (ro_session = lookup_ro_session(dlg->h_entry, &dlg->callid, 0, 0))) {
|
|
569
|
+ LM_DBG("single_ro_session_per_dialog = 1 and ro_session already exists for this dialog -so we don't need to send another one\n");
|
|
570
|
+ unref_ro_session(ro_session,1,1);//for the lookup ro session ref
|
|
571
|
+ goto done;
|
|
572
|
+ }
|
|
573
|
+
|
|
574
|
+ LM_DBG("Looking for route block [%.*s]\n", s_route_name->len, s_route_name->s);
|
|
575
|
+
|
|
576
|
+ int ri = route_get(&main_rt, s_route_name->s);
|
|
577
|
+ if (ri < 0) {
|
|
578
|
+ LM_ERR("unable to find route block [%.*s]\n", s_route_name->len, s_route_name->s);
|
|
579
|
+ ret = RO_RETURN_ERROR;
|
|
580
|
+ goto done;
|
|
581
|
+ }
|
|
582
|
+
|
|
583
|
+ cfg_action = main_rt.rlist[ri];
|
|
584
|
+ if (!cfg_action) {
|
|
585
|
+ LM_ERR("empty action lists in route block [%.*s]\n", s_route_name->len, s_route_name->s);
|
|
586
|
+ ret = RO_RETURN_ERROR;
|
|
587
|
+ goto done;
|
|
588
|
+ }
|
|
589
|
+
|
|
590
|
+ //before we send lets suspend the transaction
|
|
591
|
+ t = tmb.t_gett();
|
|
592
|
+ if (t == NULL || t == T_UNDEFINED) {
|
|
593
|
+ if (tmb.t_newtran(msg) < 0) {
|
|
594
|
+ LM_ERR("cannot create the transaction for CCR async\n");
|
|
595
|
+ ret = RO_RETURN_ERROR;
|
|
596
|
+ goto done;
|
|
597
|
+ }
|
|
598
|
+ t = tmb.t_gett();
|
|
599
|
+ if (t == NULL || t == T_UNDEFINED) {
|
|
600
|
+ LM_ERR("cannot lookup the transaction\n");
|
|
601
|
+ ret = RO_RETURN_ERROR;
|
|
602
|
+ goto done;
|
|
603
|
+ }
|
|
604
|
+ }
|
|
605
|
+
|
|
606
|
+ LM_DBG("Suspending SIP TM transaction\n");
|
|
607
|
+ if (tmb.t_suspend(msg, &tindex, &tlabel) != 0) {
|
|
608
|
+ LM_ERR("failed to suspend the TM processing\n");
|
|
609
|
+ ret = RO_RETURN_ERROR;
|
|
610
|
+ goto done;
|
|
611
|
+ }
|
|
612
|
+
|
|
613
|
+ ret = Ro_Send_CCR(msg, dlg, dir, reservation_units, &s_incoming_trunk_id, &s_outgoing_trunk_id, &pani, cfg_action, tindex, tlabel);
|
|
614
|
+
|
|
615
|
+ if(ret < 0){
|
|
616
|
+ LM_ERR("Failed to send CCR\n");
|
|
617
|
+ tmb.t_cancel_suspend(tindex, tlabel);
|
|
618
|
+ }
|
621
|
619
|
|
622
|
620
|
done:
|
623
|
|
- if(free_contact) shm_free(contact.s);// shm_malloc in cscf_get_public_identity_from_requri
|
|
621
|
+ if(free_contact) shm_free(contact.s);// shm_malloc in cscf_get_public_identity_from_requri
|
624
|
622
|
dlgb.release_dlg(dlg);
|
625
|
|
- return ret;
|
|
623
|
+ return ret;
|
626
|
624
|
}
|
627
|
625
|
|
628
|
626
|
static int ro_fixup(void **param, int param_no) {
|
629
|
|
- str s;
|
630
|
|
- unsigned int num;
|
631
|
|
-
|
632
|
|
- if ( (param_no > 0 && param_no <= 2) || (param_no >= 4 && param_no <= 6)) {
|
633
|
|
- return fixup_var_str_12(param, param_no);
|
634
|
|
- } else if (param_no == 3) {
|
635
|
|
- /*convert to int */
|
636
|
|
- s.s = (char*)*param;
|
637
|
|
- s.len = strlen(s.s);
|
638
|
|
- if (str2int(&s, &num)==0) {
|
639
|
|
- pkg_free(*param);
|
640
|
|
- *param = (void*)(unsigned long)num;
|
641
|
|
- return 0;
|
642
|
|
- }
|
643
|
|
- LM_ERR("Bad reservation units: <%s>n", (char*)(*param));
|
644
|
|
- return E_CFG;
|
645
|
|
- }
|
646
|
|
-
|
647
|
|
- return 0;
|
|
627
|
+ str s;
|
|
628
|
+ unsigned int num;
|
|
629
|
+
|
|
630
|
+ if ( (param_no > 0 && param_no <= 2) || (param_no >= 4 && param_no <= 6)) {
|
|
631
|
+ return fixup_var_str_12(param, param_no);
|
|
632
|
+ } else if (param_no == 3) {
|
|
633
|
+ /*convert to int */
|
|
634
|
+ s.s = (char*)*param;
|
|
635
|
+ s.len = strlen(s.s);
|
|
636
|
+ if (str2int(&s, &num)==0) {
|
|
637
|
+ pkg_free(*param);
|
|
638
|
+ *param = (void*)(unsigned long)num;
|
|
639
|
+ return 0;
|
|
640
|
+ }
|
|
641
|
+ LM_ERR("Bad reservation units: <%s>n", (char*)(*param));
|
|
642
|
+ return E_CFG;
|
|
643
|
+ }
|
|
644
|
+
|
|
645
|
+ return 0;
|
|
646
|
+}
|
|
647
|
+
|
|
648
|
+static int ki_ro_set_session_id_avp(sip_msg_t *msg) {
|
|
649
|
+ struct ro_session *ro_session = 0;
|
|
650
|
+ struct dlg_cell* dlg;
|
|
651
|
+ int res = -1;
|
|
652
|
+
|
|
653
|
+ //get dlg from msg
|
|
654
|
+ dlg = dlgb.get_dlg(msg);
|
|
655
|
+ if (!dlg) {
|
|
656
|
+ LM_ERR("Unable to find dialog and cannot do Ro charging without it\n");
|
|
657
|
+ return RO_RETURN_ERROR;
|
|
658
|
+ }
|
|
659
|
+
|
|
660
|
+ //get ro session id from dialog
|
|
661
|
+ ro_session= lookup_ro_session(dlg->h_entry, &dlg->callid, 0, 0);
|
|
662
|
+ if(!ro_session) {
|
|
663
|
+ LM_ERR("Unable to find Ro charging data\n");
|
|
664
|
+ dlgb.release_dlg(dlg);
|
|
665
|
+ return RO_RETURN_ERROR;
|
|
666
|
+ }
|
|
667
|
+
|
|
668
|
+ //set avp response with session id
|
|
669
|
+ res = create_response_avp_string("ro_session_id", &ro_session->ro_session_id);
|
|
670
|
+ dlgb.release_dlg(dlg);
|
|
671
|
+ unref_ro_session(ro_session, 1, 1);
|
648
|
672
|
}
|
649
|
673
|
|
650
|
674
|
static int ro_fixup_stop(void **param, int param_no) {
|
651
|
|
- if (param_no == 2 || param_no == 3) {
|
652
|
|
- return fixup_var_pve_12(param, param_no);
|
653
|
|
- }
|
654
|
|
- return 0;
|
|
675
|
+ if (param_no == 2 || param_no == 3) {
|
|
676
|
+ return fixup_var_pve_12(param, param_no);
|
|
677
|
+ }
|
|
678
|
+ return 0;
|
655
|
679
|
}
|
|
680
|
+
|
|
681
|
+static sr_kemi_t ims_charging_kemi_exports[] = {
|
|
682
|
+ { str_init("ims_charging"), str_init("Ro_CCR"),
|
|
683
|
+ SR_KEMIP_INT, ki_ro_ccr,
|
|
684
|
+ { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_INT,
|
|
685
|
+ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE }
|
|
686
|
+ },
|
|
687
|
+ { str_init("ims_charging"), str_init("Ro_CCR_Stop"),
|
|
688
|
+ SR_KEMIP_INT, ki_ro_ccr_stop,
|
|
689
|
+ { SR_KEMIP_STR, SR_KEMIP_INT, SR_KEMIP_STR,
|
|
690
|
+ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
|
|
691
|
+ },
|
|
692
|
+ { str_init("ims_charging"), str_init("Ro_set_session_id_avp"),
|
|
693
|
+ SR_KEMIP_INT, ki_ro_set_session_id_avp,
|
|
694
|
+ { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
|
|
695
|
+ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
|
|
696
|
+ },
|
|
697
|
+
|
|
698
|
+ { {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
|
|
699
|
+};
|
|
700
|
+
|
|
701
|
+int mod_register(char *path, int *dlflags, void *p1, void *p2)
|
|
702
|
+{
|
|
703
|
+ sr_kemi_modules_add(ims_charging_kemi_exports);
|
|
704
|
+ return 0;
|
|
705
|
+}
|
656
|
706
|
\ No newline at end of file
|