|
@@ -18,6 +18,8 @@
|
|
#include "ims_ro.h"
|
|
#include "ims_ro.h"
|
|
#include "config.h"
|
|
#include "config.h"
|
|
#include "dialog.h"
|
|
#include "dialog.h"
|
|
|
|
+#include "../ims_usrloc_scscf/usrloc.h"
|
|
|
|
+#include "../../lib/ims/ims_getters.h"
|
|
|
|
|
|
MODULE_VERSION
|
|
MODULE_VERSION
|
|
|
|
|
|
@@ -41,6 +43,8 @@ struct dlg_binds dlgb;
|
|
cdp_avp_bind_t *cdp_avp;
|
|
cdp_avp_bind_t *cdp_avp;
|
|
struct tm_binds tmb;
|
|
struct tm_binds tmb;
|
|
|
|
|
|
|
|
+usrloc_api_t ul; /*!< Structure containing pointers to usrloc functions*/
|
|
|
|
+
|
|
char* rx_dest_realm_s = "ims.smilecoms.com";
|
|
char* rx_dest_realm_s = "ims.smilecoms.com";
|
|
str rx_dest_realm;
|
|
str rx_dest_realm;
|
|
/* 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 */
|
|
/* 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 */
|
|
@@ -50,6 +54,7 @@ int ro_auth_expiry = 7200;
|
|
int cdp_event_latency = 1; /*flag: report slow processing of CDP callback events or not - default enabled */
|
|
int cdp_event_latency = 1; /*flag: report slow processing of CDP callback events or not - default enabled */
|
|
int cdp_event_threshold = 500; /*time in ms above which we should report slow processing of CDP callback event - default 500ms*/
|
|
int cdp_event_threshold = 500; /*time in ms above which we should report slow processing of CDP callback event - default 500ms*/
|
|
int cdp_event_latency_loglevel = 0; /*log-level to use to report slow processing of CDP callback event - default ERROR*/
|
|
int cdp_event_latency_loglevel = 0; /*log-level to use to report slow processing of CDP callback event - default ERROR*/
|
|
|
|
+int single_ro_session_per_dialog = 0; /*whether to to have 1 ro_session per dialog or let user decide from config - default is an ro session every time Ro_CCR called from config file*/
|
|
|
|
|
|
stat_var *initial_ccrs;
|
|
stat_var *initial_ccrs;
|
|
stat_var *interim_ccrs;
|
|
stat_var *interim_ccrs;
|
|
@@ -66,13 +71,15 @@ stat_var *ccr_timeouts;
|
|
static int mod_init(void);
|
|
static int mod_init(void);
|
|
static int mod_child_init(int);
|
|
static int mod_child_init(int);
|
|
static void mod_destroy(void);
|
|
static void mod_destroy(void);
|
|
-static int w_ro_ccr(struct sip_msg *msg, str* route_name, str* direction, str* charge_type, str* unit_type, int reservation_units);
|
|
|
|
|
|
+
|
|
|
|
+static int w_ro_ccr(struct sip_msg *msg, str* route_name, str* direction, str* charge_type, str* unit_type, int reservation_units, char *_d);
|
|
//void ro_session_ontimeout(struct ro_tl *tl);
|
|
//void ro_session_ontimeout(struct ro_tl *tl);
|
|
|
|
|
|
|
|
+static int domain_fixup(void** param);
|
|
static int ro_fixup(void **param, int param_no);
|
|
static int ro_fixup(void **param, int param_no);
|
|
|
|
|
|
static cmd_export_t cmds[] = {
|
|
static cmd_export_t cmds[] = {
|
|
- { "Ro_CCR", (cmd_function) w_ro_ccr, 5, ro_fixup, 0, REQUEST_ROUTE },
|
|
|
|
|
|
+ { "Ro_CCR", (cmd_function) w_ro_ccr, 6, ro_fixup, 0, REQUEST_ROUTE },
|
|
{ 0, 0, 0, 0, 0, 0 }
|
|
{ 0, 0, 0, 0, 0, 0 }
|
|
};
|
|
};
|
|
|
|
|
|
@@ -88,6 +95,7 @@ static param_export_t params[] = {
|
|
report slow processing of CDP callback event*/
|
|
report slow processing of CDP callback event*/
|
|
{ "cdp_event_latency_log", INT_PARAM, &cdp_event_latency_loglevel },/*log-level to use to report
|
|
{ "cdp_event_latency_log", INT_PARAM, &cdp_event_latency_loglevel },/*log-level to use to report
|
|
slow processing of CDP callback event*/
|
|
slow processing of CDP callback event*/
|
|
|
|
+ { "single_ro_session_per_dialog", INT_PARAM, &single_ro_session_per_dialog },
|
|
{ "origin_host", STR_PARAM, &ro_origin_host_s },
|
|
{ "origin_host", STR_PARAM, &ro_origin_host_s },
|
|
{ "origin_realm", STR_PARAM, &ro_origin_realm_s },
|
|
{ "origin_realm", STR_PARAM, &ro_origin_realm_s },
|
|
{ "destination_realm", STR_PARAM, &ro_destination_realm_s },
|
|
{ "destination_realm", STR_PARAM, &ro_destination_realm_s },
|
|
@@ -177,6 +185,7 @@ static int mod_init(void) {
|
|
int n;
|
|
int n;
|
|
load_dlg_f load_dlg;
|
|
load_dlg_f load_dlg;
|
|
load_tm_f load_tm;
|
|
load_tm_f load_tm;
|
|
|
|
+ bind_usrloc_t bind_usrloc;
|
|
|
|
|
|
if (!fix_parameters()) {
|
|
if (!fix_parameters()) {
|
|
LM_ERR("unable to set Ro configuration parameters correctly\n");
|
|
LM_ERR("unable to set Ro configuration parameters correctly\n");
|
|
@@ -241,6 +250,23 @@ static int mod_init(void) {
|
|
return -1;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ bind_usrloc = (bind_usrloc_t) find_export("ul_bind_usrloc", 1, 0);
|
|
|
|
+ if (!bind_usrloc) {
|
|
|
|
+ LM_ERR("can't bind usrloc\n");
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (bind_usrloc(&ul) < 0) {
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /*Register for callback of URECORD being deleted - so we can send a SAR*/
|
|
|
|
+
|
|
|
|
+ if (ul.register_ulcb == NULL) {
|
|
|
|
+ LM_ERR("Could not import ul_register_ulcb\n");
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
/* register statistics */
|
|
/* register statistics */
|
|
if (register_module_stats(exports.name, charging_stats) != 0) {
|
|
if (register_module_stats(exports.name, charging_stats) != 0) {
|
|
LM_ERR("failed to register core statistics\n");
|
|
LM_ERR("failed to register core statistics\n");
|
|
@@ -268,7 +294,7 @@ static void mod_destroy(void) {
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
-static int w_ro_ccr(struct sip_msg *msg, str* route_name, str* direction, str* charge_type, str* unit_type, int reservation_units) {
|
|
|
|
|
|
+static int w_ro_ccr(struct sip_msg *msg, str* route_name, str* direction, str* charge_type, str* unit_type, int reservation_units, char* _d) {
|
|
/* PSEUDOCODE/NOTES
|
|
/* PSEUDOCODE/NOTES
|
|
* 1. What mode are we in - terminating or originating
|
|
* 1. What mode are we in - terminating or originating
|
|
* 2. check request type - IEC - Immediate Event Charging
|
|
* 2. check request type - IEC - Immediate Event Charging
|
|
@@ -282,11 +308,23 @@ static int w_ro_ccr(struct sip_msg *msg, str* route_name, str* direction, str* c
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
*/
|
|
|
|
+ int ret = RO_RETURN_TRUE;
|
|
|
|
+ int dir = 0;
|
|
|
|
+ str identity = {0, 0},
|
|
|
|
+ contact = {0, 0};
|
|
|
|
+ struct hdr_field *h=0;
|
|
|
|
+
|
|
cfg_action_t* cfg_action;
|
|
cfg_action_t* cfg_action;
|
|
tm_cell_t *t;
|
|
tm_cell_t *t;
|
|
unsigned int tindex = 0,
|
|
unsigned int tindex = 0,
|
|
tlabel = 0;
|
|
tlabel = 0;
|
|
-
|
|
|
|
|
|
+ struct impu_data *impu_data;
|
|
|
|
+ udomain_t* domain_t = (udomain_t*) _d;
|
|
|
|
+ char *p;
|
|
|
|
+ struct dlg_cell* dlg;
|
|
|
|
+ unsigned int len;
|
|
|
|
+ struct ro_session *ro_session = 0;
|
|
|
|
+
|
|
LM_DBG("Ro CCR initiated: direction:%.*s, charge_type:%.*s, unit_type:%.*s, reservation_units:%i, route_name:%.*s",
|
|
LM_DBG("Ro CCR initiated: direction:%.*s, charge_type:%.*s, unit_type:%.*s, reservation_units:%i, route_name:%.*s",
|
|
direction->len, direction->s,
|
|
direction->len, direction->s,
|
|
charge_type->len, charge_type->s,
|
|
charge_type->len, charge_type->s,
|
|
@@ -294,11 +332,98 @@ static int w_ro_ccr(struct sip_msg *msg, str* route_name, str* direction, str* c
|
|
reservation_units,
|
|
reservation_units,
|
|
route_name->len, route_name->s);
|
|
route_name->len, route_name->s);
|
|
|
|
|
|
- if (msg->first_line.type != SIP_REQUEST) {
|
|
|
|
- LM_ERR("Ro_CCR() called from SIP reply.");
|
|
|
|
- return -1;
|
|
|
|
- }
|
|
|
|
|
|
+ if (msg->first_line.type != SIP_REQUEST) {
|
|
|
|
+ LM_ERR("Ro_CCR() called from SIP reply.");
|
|
|
|
+ return RO_RETURN_ERROR;;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //make sure we can get the dialog! if not, we can't continue
|
|
|
|
+
|
|
|
|
+ dlg = dlgb.get_dlg(msg);
|
|
|
|
+ if (!dlg) {
|
|
|
|
+ LM_ERR("Unable to find dialog and cannot do Ro charging without it\n");
|
|
|
|
+ return RO_RETURN_ERROR;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ dir = get_direction_as_int(direction);
|
|
|
|
+
|
|
|
|
+ if (dir == RO_ORIG_DIRECTION) {
|
|
|
|
+ //get caller IMPU from asserted identity
|
|
|
|
+ if ((identity = cscf_get_asserted_identity(msg, 0)).len == 0) {
|
|
|
|
+ LM_DBG("No P-Asserted-Identity hdr found. Using From hdr for asserted_identity");
|
|
|
|
+ identity = dlg->from_uri;
|
|
|
|
+ }
|
|
|
|
+ //get caller contact from contact header - if not present then skip this
|
|
|
|
+ if ((contact = cscf_get_contact(msg)).len == 0) {
|
|
|
|
+ LM_WARN("Can not get contact from message - will not get callbacks if this IMPU is removed to terminate call");
|
|
|
|
+ goto send_ccr;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ } else if (dir == RO_TERM_DIRECTION){
|
|
|
|
+ //get callee IMPU from called part id - if not present then skip this
|
|
|
|
+ if ((identity = cscf_get_called_party_id(msg, &h)).len == 0) {
|
|
|
|
+ LM_WARN("No P-Called-Identity hdr found - will not get callbacks if this IMPU is removed to terminate call");
|
|
|
|
+ goto send_ccr;
|
|
|
|
+ }
|
|
|
|
+ //get callee contact from request URI
|
|
|
|
+ contact = msg->first_line.u.request.uri;
|
|
|
|
+
|
|
|
|
+ } else {
|
|
|
|
+ LM_CRIT("don't know what to do in unknown mode - should we even get here\n");
|
|
|
|
+ return RO_RETURN_ERROR;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //create impu_data_parcel
|
|
|
|
+ len = identity.len + contact.len + sizeof (struct impu_data);
|
|
|
|
+ impu_data = (struct impu_data*) shm_malloc(len);
|
|
|
|
+ if (!impu_data) {
|
|
|
|
+ LM_ERR("Unable to allocate memory for impu_data, trying to send CCR\n");
|
|
|
|
+ return RO_RETURN_ERROR;
|
|
|
|
+ }
|
|
|
|
+ memset(impu_data, 0, len);
|
|
|
|
+
|
|
|
|
+ p = (char*) (impu_data + 1);
|
|
|
|
+ impu_data->identity.s = p;
|
|
|
|
+ impu_data->identity.len = identity.len;
|
|
|
|
+ memcpy(p, identity.s, identity.len);
|
|
|
|
+ p += identity.len;
|
|
|
|
+
|
|
|
|
+ impu_data->contact.s = p;
|
|
|
|
+ impu_data->contact.len = contact.len;
|
|
|
|
+ memcpy(p, contact.s, contact.len);
|
|
|
|
+ p += contact.len;
|
|
|
|
+
|
|
|
|
+ impu_data->d = domain_t;
|
|
|
|
|
|
|
|
+ if (p != (((char*) impu_data) + len)) {
|
|
|
|
+ LM_ERR("buffer overflow creating impu data, trying to send CCR\n");
|
|
|
|
+ shm_free(impu_data);
|
|
|
|
+ return RO_RETURN_ERROR;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ //reg for callbacks on confirmed and terminated
|
|
|
|
+ if (dlgb.register_dlgcb(dlg, /* DLGCB_RESPONSE_FWDED */ DLGCB_CONFIRMED, add_dlg_data_to_contact, (void*)impu_data ,NULL ) != 0) {
|
|
|
|
+ LM_CRIT("cannot register callback for dialog confirmation\n");
|
|
|
|
+ return RO_RETURN_ERROR;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (dlgb.register_dlgcb(dlg, DLGCB_TERMINATED | DLGCB_FAILED | DLGCB_EXPIRED /*| DLGCB_DESTROY */, remove_dlg_data_from_contact, (void*)impu_data, NULL ) != 0) {
|
|
|
|
+ LM_CRIT("cannot register callback for dialog termination\n");
|
|
|
|
+ return RO_RETURN_ERROR;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+send_ccr:
|
|
|
|
+
|
|
|
|
+ //check if we need to send_ccr -
|
|
|
|
+ //we get the ro_session based on dlg->h_id and dlg->h_entry and direction 0 (so get any ro_session)
|
|
|
|
+ //if it already exists then we go to done
|
|
|
|
+ if (single_ro_session_per_dialog && (ro_session = lookup_ro_session(dlg->h_entry, &dlg->callid, 0, 0))) {
|
|
|
|
+ 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");
|
|
|
|
+ unref_ro_session(ro_session,1);//for the lookup ro session ref
|
|
|
|
+ goto done;
|
|
|
|
+ }
|
|
|
|
+
|
|
LM_DBG("Looking for route block [%.*s]\n", route_name->len, route_name->s);
|
|
LM_DBG("Looking for route block [%.*s]\n", route_name->len, route_name->s);
|
|
|
|
|
|
int ri = route_get(&main_rt, route_name->s);
|
|
int ri = route_get(&main_rt, route_name->s);
|
|
@@ -311,7 +436,7 @@ static int w_ro_ccr(struct sip_msg *msg, str* route_name, str* direction, str* c
|
|
if (!cfg_action) {
|
|
if (!cfg_action) {
|
|
LM_ERR("empty action lists in route block [%.*s]\n", route_name->len, route_name->s);
|
|
LM_ERR("empty action lists in route block [%.*s]\n", route_name->len, route_name->s);
|
|
return RO_RETURN_ERROR;
|
|
return RO_RETURN_ERROR;
|
|
- }
|
|
|
|
|
|
+ }
|
|
|
|
|
|
//before we send lets suspend the transaction
|
|
//before we send lets suspend the transaction
|
|
t = tmb.t_gett();
|
|
t = tmb.t_gett();
|
|
@@ -332,8 +457,29 @@ static int w_ro_ccr(struct sip_msg *msg, str* route_name, str* direction, str* c
|
|
LM_ERR("failed to suspend the TM processing\n");
|
|
LM_ERR("failed to suspend the TM processing\n");
|
|
return RO_RETURN_ERROR;
|
|
return RO_RETURN_ERROR;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ ret = Ro_Send_CCR(msg, dlg, dir, charge_type, unit_type, reservation_units, cfg_action, tindex, tlabel);
|
|
|
|
+
|
|
|
|
+ if(ret < 0){
|
|
|
|
+ LM_ERR("Failed to send CCR\n");
|
|
|
|
+ tmb.t_cancel_suspend(tindex, tlabel);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+done:
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+///* fixups */
|
|
|
|
+static int domain_fixup(void** param)
|
|
|
|
+{
|
|
|
|
+ udomain_t* d;
|
|
|
|
|
|
- return Ro_Send_CCR(msg, direction, charge_type, unit_type, reservation_units, cfg_action, tindex, tlabel);
|
|
|
|
|
|
+ if (ul.register_udomain((char*)*param, &d) < 0) {
|
|
|
|
+ LM_ERR("failed to register domain\n");
|
|
|
|
+ return E_UNSPEC;
|
|
|
|
+ }
|
|
|
|
+ *param = (void*)d;
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
static int ro_fixup(void **param, int param_no) {
|
|
static int ro_fixup(void **param, int param_no) {
|
|
@@ -353,6 +499,10 @@ static int ro_fixup(void **param, int param_no) {
|
|
}
|
|
}
|
|
LM_ERR("Bad reservation units: <%s>n", (char*)(*param));
|
|
LM_ERR("Bad reservation units: <%s>n", (char*)(*param));
|
|
return E_CFG;
|
|
return E_CFG;
|
|
|
|
+ }
|
|
|
|
+ else if (param_no == 6) {
|
|
|
|
+ return domain_fixup(param);
|
|
}
|
|
}
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|