Ver Fonte

modules/ims_charging: added realtime DB support for Ro sessions

Jason Penton há 11 anos atrás
pai
commit
efcd3421c4

+ 7 - 1
modules/ims_charging/Ro_data.c

@@ -86,7 +86,8 @@ out_of_memory:
     return 0;
 }
 
-ims_information_t * new_ims_information(event_type_t * event_type, time_stamps_t * time_stamps, str * user_session_id, str * outgoing_session_id, str * calling_party, str * called_party, str * icid, str * orig_ioi, str * term_ioi, int node_role) {
+ims_information_t * new_ims_information(event_type_t * event_type, time_stamps_t * time_stamps, str * user_session_id, str * outgoing_session_id, str * calling_party, 
+	str * called_party, str * icid, str * orig_ioi, str * term_ioi, int node_role, str *trunk_id) {
 
     str_list_slot_t *sl = 0;
     ims_information_t *x = 0;
@@ -116,6 +117,9 @@ ims_information_t * new_ims_information(event_type_t * event_type, time_stamps_t
 
     if (called_party && called_party->s)
         str_dup_ptr(x->called_party_address, *called_party, pkg);
+    
+    if (trunk_id && trunk_id->s)
+        str_dup_ptr(x->trunk_id, *trunk_id, pkg);
 
     //WL_FREE_ALL(&(x->called_asserted_identity),str_list_t,pkg);
     //str_free_ptr(x->requested_party_address,pkg);
@@ -229,6 +233,8 @@ void ims_information_free(ims_information_t *x) {
     str_free_ptr(x->called_party_address, pkg);
     WL_FREE_ALL(&(x->called_asserted_identity), str_list_t, pkg);
     str_free_ptr(x->requested_party_address, pkg);
+    
+    str_free_ptr(x->trunk_id, pkg);
 
     time_stamps_free(x->time_stamps);
 

+ 4 - 1
modules/ims_charging/Ro_data.h

@@ -281,6 +281,8 @@ typedef struct {
     str *icid;
 
     str *service_id;
+    
+    str *trunk_id;
 
     service_specific_info_list_t service_specific_info;
 
@@ -393,7 +395,8 @@ ims_information_t * new_ims_information(event_type_t * event_type,
         str * icid,
         str * orig_ioi,
         str * term_ioi,
-        int node_role);
+        int node_role,
+		str *trunk_id);
 
 void event_type_free(event_type_t *x);
 void time_stamps_free(time_stamps_t *x);

+ 15 - 0
modules/ims_charging/ccr.c

@@ -3,6 +3,7 @@
 #include "ccr.h"
 #include "Ro_data.h"
 #include "ro_avp.h"
+#include "mod.h"
 
 extern cdp_avp_bind_t *cdp_avp;
 extern struct cdp_binds cdpb;
@@ -94,6 +95,20 @@ int Ro_write_ims_information_avps(AAA_AVP_LIST * avp_list, ims_information_t* x)
     if (x->called_party_address)
         if (!cdp_avp->epcapp.add_Called_Party_Address(&aList2, *(x->called_party_address), 0))
             goto error;
+    
+    if (x->trunk_id && x->role_of_node) {
+	if (*(x->role_of_node) == RO_ORIG_DIRECTION) {
+	    if (!cdp_avp->epcapp.add_Outgoing_Trunk_Group_Id(&aList, *(x->trunk_id), 0))
+                goto error;
+	    
+	} else if (*(x->role_of_node) == RO_TERM_DIRECTION){
+	    if (!cdp_avp->epcapp.add_Incoming_Trunk_Group_Id(&aList, *(x->trunk_id), 0))
+                goto error;
+	}
+	if (!cdp_avp->epcapp.add_Trunk_Group_Id(&aList2, &aList, 0))
+            goto error;
+        aList.head = aList.tail = 0;
+    }
 
     for (sl = x->called_asserted_identity.head; sl; sl = sl->next) {
         if (!cdp_avp->epcapp.add_Called_Asserted_Identity(&aList2, sl->data, 0))

+ 39 - 8
modules/ims_charging/dialog.c

@@ -1,11 +1,15 @@
+#include "mod.h"
 #include "dialog.h"
 #include "ro_session_hash.h"
 #include "../ims_usrloc_scscf/usrloc.h"
 #include "../ims_usrloc_scscf/udomain.h"
+#include "ro_db_handler.h"
 
 struct cdp_binds cdpb;
 
 extern usrloc_api_t ul;
+extern int ro_db_mode;
+extern char *domain;
 
 void dlg_reply(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params) {
 	struct sip_msg *reply;
@@ -91,6 +95,13 @@ void dlg_reply(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params) {
 		} else {
 			ref_ro_session_unsafe(session, 1); // lock already acquired
 		}
+
+		if (ro_db_mode == DB_MODE_REALTIME) {
+		    session->flags |= RO_SESSION_FLAG_CHANGED;
+		    if (update_ro_dbinfo_unsafe(session) != 0) {
+			LM_ERR("Failed to update ro_session in database... continuing\n");
+		    };
+		}
 				
 		ro_session_unlock(ro_session_table, ro_session_entry);
 
@@ -173,6 +184,14 @@ void dlg_terminated(struct dlg_cell *dlg, int type, struct dlg_cb_params *_param
 				LM_DBG("Sending CCR STOP on Ro_Session [%p]\n", ro_session);
 				send_ccr_stop(ro_session);
 				ro_session->active = 0;
+				
+				if (ro_db_mode == DB_MODE_REALTIME) {
+				    ro_session->flags |= RO_SESSION_FLAG_DELETED;
+				    if (update_ro_dbinfo_unsafe(ro_session) != 0) {
+					LM_ERR("Unable to update Ro session in DB...continuing\n");
+				    }
+				}
+				
 				//ro_session->start_time;
 				unref_ro_session_unsafe(ro_session, 1+unref, ro_session_entry); //lock already acquired
 				//unref_ro_session_unsafe(ro_session, 2+unref, ro_session_entry); //lock already acquired
@@ -189,9 +208,15 @@ void remove_dlg_data_from_contact(struct dlg_cell *dlg, int type, struct dlg_cb_
     struct ucontact* ucontact;
     str callid = {0, 0};
     str path = {0, 0};
+    udomain_t* domain_t;
     
     LM_DBG("dialog [%p] terminated, lets remove dlg data from contact\n", dlg);
     
+    if (ul.register_udomain(domain, &domain_t) < 0) {
+	    LM_ERR("Unable to register usrloc domain....aborting\n");
+	    return;
+    }
+    
     if(_params && _params->param){
 	impu_data = (struct impu_data*)*_params->param;
 	if (!impu_data) {
@@ -200,10 +225,10 @@ void remove_dlg_data_from_contact(struct dlg_cell *dlg, int type, struct dlg_cb_
 	}
 	
 	LM_DBG("IMPU data is present, contact: <%.*s> identity <%.*s>", impu_data->contact.len, impu_data->contact.s, impu_data->identity.len, impu_data->identity.s);
-	LM_DBG("IMPU data domain <%.*s>", impu_data->d->name->len, impu_data->d->name->s);
+	LM_DBG("IMPU data domain <%.*s>", domain_t->name->len, domain_t->name->s);
 	
-	ul.lock_udomain(impu_data->d, &impu_data->identity);
-	if (ul.get_impurecord(impu_data->d, &impu_data->identity, &implicit_impurecord) != 0) {
+	ul.lock_udomain(domain_t, &impu_data->identity);
+	if (ul.get_impurecord(domain_t, &impu_data->identity, &implicit_impurecord) != 0) {
 	    LM_DBG("usrloc does not have imprecord for implicity IMPU, ignore\n");
 	}else {
 	    if (ul.get_ucontact(implicit_impurecord, &impu_data->contact, &callid, &path, 0/*cseq*/,  &ucontact) != 0) { //contact does not exist
@@ -212,7 +237,7 @@ void remove_dlg_data_from_contact(struct dlg_cell *dlg, int type, struct dlg_cb_
 		ul.remove_dialog_data_from_contact(ucontact, dlg->h_entry, dlg->h_id);
 	    }
 	}
-	ul.unlock_udomain(impu_data->d, &impu_data->identity);
+	ul.unlock_udomain(domain_t, &impu_data->identity);
 	free_impu_data(impu_data);
     }
 }
@@ -224,9 +249,15 @@ void add_dlg_data_to_contact(struct dlg_cell *dlg, int type, struct dlg_cb_param
     struct ucontact* ucontact;
     str callid = {0, 0};
     str path = {0, 0};
+    udomain_t* domain_t;
     
     LM_DBG("dialog [%p] confirmed, lets add dlg data to contact\n", dlg);
     
+    if (ul.register_udomain(domain, &domain_t) < 0) {
+	    LM_ERR("Unable to register usrloc domain....aborting\n");
+	    return;
+    }
+    
     if(_params && _params->param){
 	impu_data = (struct impu_data*)*_params->param;
 	if (!impu_data) {
@@ -235,10 +266,10 @@ void add_dlg_data_to_contact(struct dlg_cell *dlg, int type, struct dlg_cb_param
 	}
 	
 	LM_DBG("IMPU data is present, contact: <%.*s> identity <%.*s>", impu_data->contact.len, impu_data->contact.s, impu_data->identity.len, impu_data->identity.s);
-	LM_DBG("IMPU data domain <%.*s>", impu_data->d->name->len, impu_data->d->name->s);
+	LM_DBG("IMPU data domain <%.*s>", domain_t->name->len, domain_t->name->s);
 	
-	ul.lock_udomain(impu_data->d, &impu_data->identity);
-	if (ul.get_impurecord(impu_data->d, &impu_data->identity, &implicit_impurecord) != 0) {
+	ul.lock_udomain(domain_t, &impu_data->identity);
+	if (ul.get_impurecord(domain_t, &impu_data->identity, &implicit_impurecord) != 0) {
 	    LM_DBG("usrloc does not have imprecord for implicity IMPU, ignore\n");
 	}else {
 	    if (ul.get_ucontact(implicit_impurecord, &impu_data->contact, &callid, &path, 0/*cseq*/,  &ucontact) != 0) { //contact does not exist
@@ -247,6 +278,6 @@ void add_dlg_data_to_contact(struct dlg_cell *dlg, int type, struct dlg_cb_param
 		ul.add_dialog_data_to_contact(ucontact, dlg->h_entry, dlg->h_id);
 	    }
 	}
-	ul.unlock_udomain(impu_data->d, &impu_data->identity);
+	ul.unlock_udomain(domain_t, &impu_data->identity);
     }
 } 

+ 78 - 54
modules/ims_charging/ims_ro.c

@@ -31,6 +31,7 @@
 #include "ro_session_hash.h"
 #include "stats.h"
 #include "ro_avp.h"
+#include "ro_db_handler.h"
 
 extern struct tm_binds tmb;
 extern struct cdp_binds cdpb;
@@ -38,6 +39,7 @@ extern client_ro_cfg cfg;
 extern struct dlg_binds dlgb;
 extern cdp_avp_bind_t *cdp_avp;
 extern str ro_forced_peer;
+extern int ro_db_mode;
 
 struct session_setup_data {
 	struct ro_session *ro_session;
@@ -56,8 +58,6 @@ extern int voice_service_identifier;
 extern int voice_rating_group;
 extern int video_service_identifier;
 extern int video_rating_group;
-extern int active_service_identifier;
-extern int active_rating_group;
 
 static int create_cca_return_code(int result);
 static void resume_on_initial_ccr(int is_timeout, void *param, AAAMessage *cca, long elapsed_msecs);
@@ -182,7 +182,7 @@ inline int Ro_add_termination_cause(AAAMessage *msg, unsigned int term_code) {
 }
 
 /* called only when building stop record AVPS */
-inline int Ro_add_multiple_service_credit_Control_stop(AAAMessage *msg, int used_unit) {
+inline int Ro_add_multiple_service_credit_Control_stop(AAAMessage *msg, int used_unit, int active_rating_group, int active_service_identifier) {
     AAA_AVP_LIST used_list, mscc_list;
     str used_group;
     char x[4];
@@ -217,12 +217,9 @@ inline int Ro_add_multiple_service_credit_Control_stop(AAAMessage *msg, int used
     return Ro_add_avp(msg, used_group.s, used_group.len, AVP_Multiple_Services_Credit_Control, AAA_AVP_FLAG_MANDATORY, 0, AVP_FREE_DATA, __FUNCTION__);
 }
 
-inline int Ro_add_multiple_service_credit_Control(AAAMessage *msg, unsigned int requested_unit, int used_unit) {
+inline int Ro_add_multiple_service_credit_Control(AAAMessage *msg, unsigned int requested_unit, int used_unit, int active_rating_group, int active_service_identifier) {
     AAA_AVP_LIST list, used_list, mscc_list;
     str group, used_group;
-    //unsigned int service_id = 1000; //VOICE TODO FIX as config item - should be a MAP that can be identified based on SDP params
-    
-    //unsigned int rating_group = 500; //VOICE TODO FIX as config item - should be a MAP that can be identified based on SDP params
     
     char x[4];
 
@@ -384,7 +381,7 @@ int get_timestamps(struct sip_msg * req, struct sip_msg * reply, time_t * req_ti
  *
  */
 
-Ro_CCR_t * dlg_create_ro_session(struct sip_msg * req, struct sip_msg * reply, AAASession ** authp, int dir, str asserted_identity, str called_asserted_identity, str subscription_id, int subscription_id_type) {
+Ro_CCR_t * dlg_create_ro_session(struct sip_msg * req, struct sip_msg * reply, AAASession ** authp, int dir, str asserted_identity, str called_asserted_identity, str subscription_id, int subscription_id_type, str* trunk_id) {
 
     Ro_CCR_t * ro_ccr_data = 0;
     AAASession * auth = NULL;
@@ -422,7 +419,7 @@ Ro_CCR_t * dlg_create_ro_session(struct sip_msg * req, struct sip_msg * reply, A
     if (!(time_stamps = new_time_stamps(&req_timestamp, NULL, &reply_timestamp, NULL)))
         goto error;
 
-    if (!(ims_info = new_ims_information(event_type, time_stamps, &callid, &callid, &asserted_identity, &called_asserted_identity, &icid, &orig_ioi, &term_ioi, dir)))
+    if (!(ims_info = new_ims_information(event_type, time_stamps, &callid, &callid, &asserted_identity, &called_asserted_identity, &icid, &orig_ioi, &term_ioi, dir, trunk_id)))
         goto error;
     event_type = 0;
     time_stamps = 0;
@@ -469,12 +466,12 @@ error :
     return NULL;
 }
 
-int sip_create_ro_ccr_data(struct sip_msg * msg, int dir, Ro_CCR_t ** ro_ccr_data, AAASession ** auth, str asserted_identity, str called_asserted_identity, str subscription_id, int subscription_id_type) {
+int sip_create_ro_ccr_data(struct sip_msg * msg, int dir, Ro_CCR_t ** ro_ccr_data, AAASession ** auth, str asserted_identity, str called_asserted_identity, str subscription_id, int subscription_id_type, str* trunk_id) {
 
     if (msg->first_line.type == SIP_REQUEST) {
         /*end of session*/
         if (strncmp(msg->first_line.u.request.method.s, "INVITE", 6) == 0) {
-            if (!(*ro_ccr_data = dlg_create_ro_session(msg, NULL, auth, dir, asserted_identity, called_asserted_identity, subscription_id, subscription_id_type)))
+            if (!(*ro_ccr_data = dlg_create_ro_session(msg, NULL, auth, dir, asserted_identity, called_asserted_identity, subscription_id, subscription_id_type, trunk_id)))
                 goto error;
         }
     } else {
@@ -498,7 +495,6 @@ void send_ccr_interim(struct ro_session* ro_session, unsigned int used, unsigned
 	struct interim_ccr *i_req = shm_malloc(sizeof(struct interim_ccr));
 	int ret = 0;
     event_type_t *event_type;
-    int node_role = 0;
 
 	memset(i_req, 0, sizeof(sizeof(struct interim_ccr)));
     i_req->ro_session	= ro_session;
@@ -512,18 +508,21 @@ void send_ccr_interim(struct ro_session* ro_session, unsigned int used, unsigned
 
     event_type = new_event_type(&sip_method, &sip_event, 0);
 
-    LM_DBG("Sending interim CCR request for (usage:new) [%i:%i] seconds for user [%.*s] using session id [%.*s]",
+    LM_DBG("Sending interim CCR request for (usage:new) [%i:%i] seconds for user [%.*s] using session id [%.*s] active rating group [%d] active service identifier [%d] trunk_id [%.*s]\n",
     						used,
     						reserve,
     						ro_session->asserted_identity.len, ro_session->asserted_identity.s,
-    						ro_session->ro_session_id.len, ro_session->ro_session_id.s);
+    						ro_session->ro_session_id.len, ro_session->ro_session_id.s,
+						ro_session->rating_group, ro_session->service_identifier, 
+						ro_session->trunk_id.len, ro_session->trunk_id.s);
 
     req_timestamp = time(0);
 
     if (!(time_stamps = new_time_stamps(&req_timestamp, NULL, NULL, NULL)))
         goto error;
 
-    if (!(ims_info = new_ims_information(event_type, time_stamps, &ro_session->callid, &ro_session->callid, &ro_session->asserted_identity, &ro_session->called_asserted_identity, 0, 0, 0, node_role)))
+    if (!(ims_info = new_ims_information(event_type, time_stamps, &ro_session->callid, &ro_session->callid, &ro_session->asserted_identity, 
+	    &ro_session->called_asserted_identity, 0, 0, 0, ro_session->direction, &ro_session->trunk_id)))
         goto error;
 
     LM_DBG("Created IMS information\n");
@@ -600,7 +599,7 @@ void send_ccr_interim(struct ro_session* ro_session, unsigned int used, unsigned
         LM_ERR("Problem adding Subscription ID data\n");
     }
 
-    if (!Ro_add_multiple_service_credit_Control(ccr, interim_request_credits/*INTERIM_CREDIT_REQ_AMOUNT*/, used)) {
+    if (!Ro_add_multiple_service_credit_Control(ccr, interim_request_credits/*INTERIM_CREDIT_REQ_AMOUNT*/, used, ro_session->rating_group, ro_session->service_identifier)) {
         LM_ERR("Problem adding Multiple Service Credit Control data\n");
     }
 
@@ -734,7 +733,6 @@ void send_ccr_stop(struct ro_session *ro_session) {
     update_stat(billed_secs, used);
 
     event_type_t *event_type;
-    int node_role = 0;
 
     str sip_method = str_init("dummy");
     str sip_event = str_init("dummy");
@@ -743,15 +741,20 @@ void send_ccr_stop(struct ro_session *ro_session) {
 
     event_type = new_event_type(&sip_method, &sip_event, 0);
     
-    LM_DBG("Sending CCR STOP request for for user:[%.*s] using session id:[%.*s] and units:[%d]\n",
-    		ro_session->asserted_identity.len, ro_session->asserted_identity.s, ro_session->ro_session_id.len, ro_session->ro_session_id.s, used);
+    LM_DBG("Sending stop CCR request for (usage) [%i] seconds for user [%.*s] using session id [%.*s] active rating group [%d] active service identifier [%d] trunk_id [%.*s]\n",
+    						used,
+    						ro_session->asserted_identity.len, ro_session->asserted_identity.s,
+    						ro_session->ro_session_id.len, ro_session->ro_session_id.s,
+						ro_session->rating_group, ro_session->service_identifier, 
+						ro_session->trunk_id.len, ro_session->trunk_id.s);
 
     req_timestamp = time(0);
 
     if (!(time_stamps = new_time_stamps(&req_timestamp, NULL, NULL, NULL)))
         goto error0;
 
-    if (!(ims_info = new_ims_information(event_type, time_stamps, &ro_session->callid, &ro_session->callid, &ro_session->asserted_identity, &ro_session->called_asserted_identity, 0, 0, 0, node_role)))
+    if (!(ims_info = new_ims_information(event_type, time_stamps, &ro_session->callid, &ro_session->callid, &ro_session->asserted_identity, 
+		&ro_session->called_asserted_identity, 0, 0, 0, ro_session->direction, &ro_session->trunk_id)))
         goto error0;
     
     event_type = 0;
@@ -782,7 +785,7 @@ void send_ccr_stop(struct ro_session *ro_session) {
 
     ro_ccr_data = new_Ro_CCR(acc_record_type, &user_name, ims_info, &subscr);
     if (!ro_ccr_data) {
-        LM_ERR("dlg_create_ro_session: no memory left for generic\n");
+        LM_ERR("send_ccr_stop: no memory left for generic\n");
         goto error0;
     }
     ims_info = 0;
@@ -826,7 +829,7 @@ void send_ccr_stop(struct ro_session *ro_session) {
         LM_ERR("Problem adding Subscription ID data\n");
     }
     
-    if (!Ro_add_multiple_service_credit_Control_stop(ccr, used)) {
+    if (!Ro_add_multiple_service_credit_Control_stop(ccr, used, ro_session->rating_group, ro_session->service_identifier)) {
         LM_ERR("Problem adding Multiple Service Credit Control data\n");
     }
     
@@ -920,7 +923,7 @@ error:
  *
  * @returns #CSCF_RETURN_BREAK if OK, #CSCF_RETURN_ERROR on error
  */
-int Ro_Send_CCR(struct sip_msg *msg, struct dlg_cell *dlg, int dir, str* charge_type, str* unit_type, int reservation_units,
+int Ro_Send_CCR(struct sip_msg *msg, struct dlg_cell *dlg, int dir, str* charge_type, str* unit_type, int reservation_units, str* trunk_id,
 						cfg_action_t* action, unsigned int tindex, unsigned int tlabel) {
 	str session_id = { 0, 0 },
 		called_asserted_identity = {0 , 0 },
@@ -942,8 +945,19 @@ int Ro_Send_CCR(struct sip_msg *msg, struct dlg_cell *dlg, int dir, str* charge_
     sdp_session_cell_t* msg_sdp_session;
     sdp_stream_cell_t* msg_sdp_stream;
     
+    int active_service_identifier;
+    int active_rating_group;
+    
     int sdp_stream_num = 0;
 
+    LM_DBG("Sending initial CCR request for charge_type [%.*s] unit_type [%.*s] reservation_units [%d] trunk_id [%.*s]\n",
+						charge_type->len, charge_type->s,
+    						unit_type->len, unit_type->s,
+    						reservation_units,
+						trunk_id->len, trunk_id->s);
+    
+    
+    
     ssd = shm_malloc(sizeof(struct session_setup_data)); // lookup structure used to load session info from cdp callback on CCA
     if (!ssd) {
     	LM_ERR("no more shm mem\n");
@@ -986,32 +1000,8 @@ int Ro_Send_CCR(struct sip_msg *msg, struct dlg_cell *dlg, int dir, str* charge_
     str mac	= {0,0};
     if (get_mac_avp_value(msg, &mac) != 0)
     	LM_DBG(RO_MAC_AVP_NAME" was not set. Using default.");
-
-	//create a session object without auth and diameter session id - we will add this later.
-	new_session = build_new_ro_session(dir, 0, 0, &session_id, &dlg->callid,
-			&asserted_identity, &called_asserted_identity, &mac, dlg->h_entry, dlg->h_id,
-			reservation_units, 0);
-
-	if (!new_session) {
-		LM_ERR("Couldn't create new Ro Session - this is BAD!\n");
-		goto error;
-	}
-
-	ssd->action	= action;
-	ssd->tindex	= tindex;
-	ssd->tlabel	= tlabel;
-	ssd->ro_session	= new_session;
-
-    if (!sip_create_ro_ccr_data(msg, dir, &ro_ccr_data, &cc_acc_session, asserted_identity, called_asserted_identity, subscription_id, subscription_id_type))
-        goto error;
-
-    if (!ro_ccr_data)
-        goto error;
-
-    if (!cc_acc_session)
-    	goto error;
-
-	//by default we use voice service id and rate group
+    
+    //by default we use voice service id and rate group
 	//then we check SDP - if we find video then we use video service id and rate group
 	LM_DBG("Setting default SID to %d and RG to %d for voice", 
 			    voice_service_identifier, voice_rating_group);
@@ -1049,6 +1039,32 @@ int Ro_Send_CCR(struct sip_msg *msg, struct dlg_cell *dlg, int dir, str* charge_
 	}
 	
 	free_sdp((sdp_info_t**) (void*) &msg->body);
+
+	//create a session object without auth and diameter session id - we will add this later.
+	new_session = build_new_ro_session(dir, 0, 0, &session_id, &dlg->callid,
+			&asserted_identity, &called_asserted_identity, &mac, dlg->h_entry, dlg->h_id,
+			reservation_units, 0, active_rating_group, active_service_identifier, trunk_id);
+
+	if (!new_session) {
+		LM_ERR("Couldn't create new Ro Session - this is BAD!\n");
+		goto error;
+	}
+
+	ssd->action	= action;
+	ssd->tindex	= tindex;
+	ssd->tlabel	= tlabel;
+	ssd->ro_session	= new_session;
+
+    if (!sip_create_ro_ccr_data(msg, dir, &ro_ccr_data, &cc_acc_session, asserted_identity, called_asserted_identity, subscription_id, subscription_id_type, trunk_id))
+        goto error;
+
+    if (!ro_ccr_data)
+        goto error;
+
+    if (!cc_acc_session)
+    	goto error;
+
+	
 	
 	
     if (!(ccr = Ro_new_ccr(cc_acc_session, ro_ccr_data)))
@@ -1078,11 +1094,11 @@ int Ro_Send_CCR(struct sip_msg *msg, struct dlg_cell *dlg, int dir, str* charge_
         LM_ERR("Problem adding Subscription ID data\n");
         goto error;
     }
-    if (!Ro_add_multiple_service_credit_Control(ccr, reservation_units, -1)) {
+    if (!Ro_add_multiple_service_credit_Control(ccr, reservation_units, -1, active_rating_group, active_service_identifier)) {
         LM_ERR("Problem adding Multiple Service Credit Control data\n");
         goto error;
     }
-
+	
     /* before we send, update our session object with CC App session ID and data */
     new_session->auth_appid = cc_acc_session->application_id;
     new_session->auth_session_type = cc_acc_session->type;
@@ -1212,9 +1228,17 @@ static void resume_on_initial_ccr(int is_timeout, void *param, AAAMessage *cca,
     LM_DBG("Freeing CCA message\n");
     cdpb.AAAFreeMessage(&cca);
 
-    link_ro_session(ssd->ro_session, 1);            //create extra ref for the fact that dialog has a handle in the callbacks
-    unref_ro_session(ssd->ro_session, 1);
-
+    link_ro_session(ssd->ro_session, 1);            /* create extra ref for the fact that dialog has a handle in the callbacks */
+    
+    if (ro_db_mode == DB_MODE_REALTIME) {
+	ssd->ro_session->flags |= RO_SESSION_FLAG_NEW;
+	if (update_ro_dbinfo(ssd->ro_session) != 0) {
+	    LM_ERR("Failed to update ro_session in database... continuing\n");
+	};
+    }
+    
+    unref_ro_session(ssd->ro_session, 1);	    /* release our reference */
+    
     create_cca_return_code(RO_RETURN_TRUE);
 
     if (t)

+ 1 - 2
modules/ims_charging/ims_ro.h

@@ -14,8 +14,7 @@ struct interim_ccr {
 
 void credit_control_session_callback(int event, void* session);
 void remove_aaa_session(str *session_id);
-int Ro_Send_CCR(struct sip_msg *msg, struct dlg_cell *dlg, int dir, str* charge_type, str* unit_type, int reservation_units, cfg_action_t* action, unsigned int tindex, unsigned int tlabel);
-//void send_ccr_interim(struct ro_session *ro_session, str* from_uri, str *to_uri, int *new_credit, int *credit_valid_for, unsigned int used, unsigned int reserve, unsigned int *is_final_allocation);
+int Ro_Send_CCR(struct sip_msg *msg, struct dlg_cell *dlg, int dir, str* charge_type, str* unit_type, int reservation_units, str *trunk_id, cfg_action_t* action, unsigned int tindex, unsigned int tlabel);
 void send_ccr_interim(struct ro_session* ro_session, unsigned int used, unsigned int reserve);
 void send_ccr_stop(struct ro_session *ro_session);
 int get_direction_as_int(str* direction);

+ 58 - 28
modules/ims_charging/mod.c

@@ -20,6 +20,7 @@
 #include "dialog.h"
 #include "../ims_usrloc_scscf/usrloc.h"
 #include "../../lib/ims/ims_getters.h"
+#include "ro_db_handler.h"
 
 MODULE_VERSION
 
@@ -40,8 +41,15 @@ int voice_rating_group = 100;
 int video_service_identifier = 1001;
 int video_rating_group = 200;
 
-int active_service_identifier = 1000; //current SID to be used - will  be changed depending on SDP info
-int active_rating_group = 200; //current RG to be used - will  be changed depending on SDP info
+
+/* DB params */
+static str db_url = str_init(DEFAULT_DB_URL);
+static unsigned int db_update_period = DB_DEFAULT_UPDATE_PERIOD;
+int ro_db_mode_param = DB_MODE_NONE;
+static int db_fetch_rows = 200;
+int ro_db_mode = DB_MODE_NONE;
+
+char *domain = "location";
 
 client_ro_cfg cfg = { str_init("scscf.ims.smilecoms.com"),
     str_init("ims.smilecoms.com"),
@@ -83,10 +91,9 @@ static int mod_init(void);
 static int mod_child_init(int);
 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, char *_d);
+static int w_ro_ccr(struct sip_msg *msg, str* route_name, str* direction, str* charge_type, str* unit_type, int reservation_units, str* trunk_id);
 //void ro_session_ontimeout(struct ro_tl *tl);
 
-static int domain_fixup(void** param);
 static int ro_fixup(void **param, int param_no);
 
 static cmd_export_t cmds[] = {
@@ -115,11 +122,14 @@ static param_export_t params[] = {
 		{ "service_context_id_ext", PARAM_STRING,			&ro_service_context_id_ext_s 	},
 		{ "service_context_id_mnc", PARAM_STRING,			&ro_service_context_id_mnc_s 	},
 		{ "service_context_id_mcc", PARAM_STRING,			&ro_service_context_id_mcc_s 	},
-		{ "service_context_id_release",	PARAM_STRING, 		&ro_service_context_id_release_s},
+		{ "service_context_id_release",	PARAM_STRING,			&ro_service_context_id_release_s},
 		{ "voice_service_identifier", 	INT_PARAM, 			&voice_service_identifier },/*service id for voice*/
 		{ "voice_rating_group", 	INT_PARAM, 			&voice_rating_group },/*rating group for voice*/
 		{ "video_service_identifier", 	INT_PARAM, 			&video_service_identifier },/*service id for voice*/
 		{ "video_rating_group", 	INT_PARAM, 			&video_rating_group },/*rating group for voice*/
+		{ "db_mode",			INT_PARAM,			&ro_db_mode_param		},
+		{ "db_url",			PARAM_STRING,			&db_url 			},
+		{ "db_update_period",		INT_PARAM,			&db_update_period		},
 		{ 0, 0, 0 }
 };
 
@@ -280,6 +290,27 @@ static int mod_init(void) {
 		LM_ERR("failed to register core statistics\n");
 		return -1;
 	}*/
+	
+	/* if a database should be used to store the dialogs' information */
+	ro_db_mode = ro_db_mode_param;
+	if (ro_db_mode == DB_MODE_NONE) {
+	    db_url.s = 0;
+	    db_url.len = 0;
+	} else {
+	    if (ro_db_mode != DB_MODE_REALTIME && ro_db_mode != DB_MODE_SHUTDOWN) {
+		LM_ERR("unsupported db_mode %d\n", ro_db_mode);
+		return -1;
+	    }
+	    if (!db_url.s || db_url.len == 0) {
+		LM_ERR("db_url not configured for db_mode %d\n", ro_db_mode);
+		return -1;
+	    }
+	    if (init_ro_db(&db_url, ro_session_hash_size, db_update_period, db_fetch_rows) != 0) {
+		LM_ERR("failed to initialize the DB support\n");
+		return -1;
+	    }
+//	    run_load_callbacks();
+	}
 
 	return 0;
 
@@ -290,14 +321,32 @@ error:
 }
 
 static int mod_child_init(int rank) {
-	return 0;
+    ro_db_mode = ro_db_mode_param;
+
+    if (((ro_db_mode == DB_MODE_REALTIME) && (rank > 0 || rank == PROC_TIMER)) ||
+	    (ro_db_mode == DB_MODE_SHUTDOWN && (rank == PROC_MAIN))) {
+	if (ro_connect_db(&db_url)) {
+	    LM_ERR("failed to connect to database (rank=%d)\n", rank);
+	    return -1;
+	}
+    }
+
+    /* in DB_MODE_SHUTDOWN only PROC_MAIN will do a DB dump at the end, so
+     * for the rest of the processes will be the same as DB_MODE_NONE */
+    if (ro_db_mode == DB_MODE_SHUTDOWN && rank != PROC_MAIN)
+	ro_db_mode = DB_MODE_NONE;
+    /* in DB_MODE_REALTIME and DB_MODE_DELAYED the PROC_MAIN have no DB handle */
+    if ((ro_db_mode == DB_MODE_REALTIME) && rank == PROC_MAIN)
+	ro_db_mode = DB_MODE_NONE;
+    
+    return 0;
 }
 
 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, char* _d) {
+static int w_ro_ccr(struct sip_msg *msg, str* route_name, str* direction, str* charge_type, str* unit_type, int reservation_units, str* trunk_id) {
 	/* PSEUDOCODE/NOTES
 	 * 1. What mode are we in - terminating or originating
 	 * 2. check request type - 	IEC - Immediate Event Charging
@@ -322,7 +371,6 @@ static int w_ro_ccr(struct sip_msg *msg, str* route_name, str* direction, str* c
 	unsigned int tindex = 0,
 				 tlabel = 0;
 	struct impu_data *impu_data;
-	udomain_t* domain_t = (udomain_t*) _d;
 	char *p;
 	struct dlg_cell* dlg;
 	unsigned int len;
@@ -402,8 +450,6 @@ static int w_ro_ccr(struct sip_msg *msg, str* route_name, str* direction, str* c
 	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);
@@ -475,7 +521,7 @@ send_ccr:
 		goto done;
 	}
 	
-	ret = Ro_Send_CCR(msg, dlg, dir, charge_type, unit_type, reservation_units, cfg_action, tindex, tlabel);
+	ret = Ro_Send_CCR(msg, dlg, dir, charge_type, unit_type, reservation_units, trunk_id, cfg_action, tindex, tlabel);
 	
 	if(ret < 0){
 	    LM_ERR("Failed to send CCR\n");
@@ -487,24 +533,11 @@ done:
 	return ret;
 }
 
-///* fixups */
-static int domain_fixup(void** param)
-{
-	udomain_t* d;
-
-	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) {
 	str s;
 	unsigned int num;
 
-	if (param_no > 0 && param_no <= 4) {
+	if ( (param_no > 0 && param_no <= 4) || (param_no == 6) ) {
 		return fixup_var_str_12(param, param_no);
 	} else if (param_no == 5) {
 		/*convert to int */
@@ -517,9 +550,6 @@ static int ro_fixup(void **param, int param_no) {
 		}
 		LM_ERR("Bad reservation units: <%s>n", (char*)(*param));
 		return E_CFG;
-	} 
-	else if (param_no == 6) {
-		return domain_fixup(param);
 	}
 	
 	return 0;

+ 9 - 3
modules/ims_charging/mod.h

@@ -14,9 +14,9 @@
 #define RO_CC_INTERIM 	2
 #define RO_CC_STOP 		3
 
-#define RO_UNKNOWN_DIRECTION 0
-#define RO_ORIG_DIRECTION 1
-#define RO_TERM_DIRECTION 2
+#define RO_UNKNOWN_DIRECTION -1
+#define RO_ORIG_DIRECTION 0
+#define RO_TERM_DIRECTION 1
 
 /** Return and break the execution of routing script */
 #define RO_RETURN_BREAK	0
@@ -47,4 +47,10 @@
 
 #define RO_MAC_AVP_NAME	"$avp(ro_mac_value)"
 
+#define DB_DEFAULT_UPDATE_PERIOD	60
+
+#define DB_MODE_NONE				0
+#define DB_MODE_REALTIME			1
+#define DB_MODE_SHUTDOWN			2
+
 #endif /* MOD_H_ */

+ 251 - 0
modules/ims_charging/ro_db_handler.c

@@ -0,0 +1,251 @@
+#include "ro_db_handler.h"
+#include "../../lib/srdb1/db.h"
+
+static db1_con_t* ro_db_handle = 0; /* database connection handle */
+static db_func_t ro_dbf;
+
+str ro_session_table_name = str_init(RO_SESSION_TABLE_NAME);
+str id_column = str_init(ID_COL);
+str h_entry_column = str_init(HASH_ENTRY_COL);
+str h_id_column = str_init(HASH_ID_COL);
+str session_id_column = str_init(SESSION_ID_COL);
+str dlg_h_entry_column = str_init(DLG_HASH_ENTRY_COL);
+str dlg_h_id_column = str_init(DLG_HASH_ID_COL);
+str direction_column = str_init(DIRECTION_COL);
+str asserted_column = str_init(ASSERTED_ID_COL);
+str callee_column = str_init(CALLEE_COL);
+str start_time_col = str_init(START_TIME_COL);
+str last_event_ts_column = str_init(LAST_EVENT_TS_COL);
+str reserved_sec_column = str_init(RESERVED_SECS_COL);
+str valid_for_column = str_init(VALID_FOR_COL);
+str state_column = str_init(STATE_COL);
+
+typedef enum ro_session_field_idx {
+    ID_COL_IDX = 0,
+    HASH_ENTRY_COL_IDX,
+    HASH_ID_COL_IDX,
+    SESSION_ID_COL_IDX,
+    DLG_HASH_ENTRY_COL_IDX,
+    DLG_HASH_ID_COL_IDX,
+    DIRECTION_COL_IDX,
+    ASSERTED_ID_COL_IDX,
+    CALLEE_COL_IDX,
+    START_TIME_COL_IDX,
+    LAST_EVENT_TS_COL_IDX,
+    RESERVED_SECS_COL_IDX,
+    VALID_FOR_COL_IDX,
+    STATE_COL_IDX
+} ro_session_field_idx_t;
+
+#define GET_FIELD_IDX(_val, _idx)\
+		(_val + _idx)
+
+#define SET_STR_VALUE(_val, _str)\
+	do{\
+			VAL_STR((_val)).s = (_str).s;\
+			VAL_STR((_val)).len = (_str).len;\
+	}while(0);
+
+#define SET_NULL_FLAG(_vals, _i, _max, _flag)\
+	do{\
+		for((_i) = 0;(_i)<(_max); (_i)++)\
+			VAL_NULL((_vals)+(_i)) = (_flag);\
+	}while(0);
+
+#define SET_PROPER_NULL_FLAG(_str, _vals, _index)\
+	do{\
+		if( (_str).len == 0)\
+			VAL_NULL( (_vals)+(_index) ) = 1;\
+		else\
+			VAL_NULL( (_vals)+(_index) ) = 0;\
+	}while(0);
+
+#define GET_STR_VALUE(_res, _values, _index, _not_null, _unref)\
+	do{\
+		if (VAL_NULL((_values)+ (_index))) { \
+			if (_not_null) {\
+				if (_unref) unref_dlg(dlg,1);\
+				goto next_dialog; \
+			} else { \
+				(_res).s = 0; \
+				(_res).len = 0; \
+			}\
+		} else { \
+			(_res).s = VAL_STR((_values)+ (_index)).s;\
+			(_res).len = strlen(VAL_STR((_values)+ (_index)).s);\
+		} \
+	}while(0);
+
+int init_ro_db(const str *db_url, int dlg_hash_size, int db_update_period, int fetch_num_rows) {
+    /* Find a database module */
+    if (db_bind_mod(db_url, &ro_dbf) < 0) {
+	LM_ERR("Unable to bind to a database driver\n");
+	return -1;
+    }
+
+    if (ro_connect_db(db_url) != 0) {
+	LM_ERR("unable to connect to the database\n");
+	return -1;
+    }
+
+    if (db_check_table_version(&ro_dbf, ro_db_handle, &ro_session_table_name, RO_TABLE_VERSION) < 0) {
+	LM_ERR("error during dialog-table version check.\n");
+	return -1;
+    }
+
+    //	if( (dlg_db_mode==DB_MODE_DELAYED) && 
+    //	(register_timer( dialog_update_db, 0, db_update_period)<0 )) {
+    //		LM_ERR("failed to register update db\n");
+    //		return -1;
+    //	}
+
+    if ((load_ro_info_from_db(dlg_hash_size, fetch_num_rows)) != 0) {
+	LM_ERR("unable to load the dialog data\n");
+	return -1;
+    }
+
+    ro_dbf.close(ro_db_handle);
+    ro_db_handle = 0;
+
+    return 0;
+}
+
+int load_ro_info_from_db(int hash_size, int fetch_num_rows) {
+    LM_WARN("not supported yet");
+    return 0;
+}
+
+int ro_connect_db(const str *db_url) {
+    if (ro_db_handle) {
+	LM_CRIT("BUG - db connection found already open\n");
+	return -1;
+    }
+    if ((ro_db_handle = ro_dbf.init(db_url)) == 0)
+	return -1;
+
+    /* use default table */
+    if (ro_dbf.use_table(ro_db_handle, &ro_session_table_name) != 0) {
+	LM_ERR("Error in use table for table name [%.*s]\n", ro_session_table_name.len, ro_session_table_name.s);
+	return -1;
+    }
+
+    return 0;
+}
+
+void db_set_int_val(db_val_t* values, int index, int val) {
+    VAL_TYPE(GET_FIELD_IDX(values, index)) = DB1_INT;
+    VAL_NULL(GET_FIELD_IDX(values, index)) = 0;
+    VAL_INT(GET_FIELD_IDX(values, index)) = val;
+}
+
+void db_set_str_val(db_val_t* values, int index, str* val) {
+    VAL_TYPE(GET_FIELD_IDX(values, index)) = DB1_STR;
+    VAL_NULL(GET_FIELD_IDX(values, index)) = 0;
+    SET_STR_VALUE(GET_FIELD_IDX(values, index), *val);
+}
+
+void db_set_datetime_val(db_val_t* values, int index, time_t val) {
+    VAL_TYPE(GET_FIELD_IDX(values, index)) = DB1_DATETIME;
+    VAL_NULL(GET_FIELD_IDX(values, index)) = 0;
+    VAL_TIME(GET_FIELD_IDX(values, index)) = val;
+}
+
+int update_ro_dbinfo_unsafe(struct ro_session* ro_session) {
+    if ((ro_session->flags & RO_SESSION_FLAG_NEW) != 0 && (ro_session->flags & RO_SESSION_FLAG_INSERTED) == 0) {
+
+	db_val_t values[RO_SESSION_TABLE_COL_NUM];
+	db_key_t insert_keys[RO_SESSION_TABLE_COL_NUM] = {
+	    &id_column, &h_entry_column, &h_id_column, &session_id_column, &dlg_h_entry_column, &dlg_h_id_column,
+	    &direction_column, &asserted_column, &callee_column, &start_time_col, &last_event_ts_column,
+	    &reserved_sec_column, &valid_for_column, &state_column
+	};
+
+	VAL_TYPE(GET_FIELD_IDX(values, ID_COL_IDX)) = DB1_INT;
+	VAL_NULL(GET_FIELD_IDX(values, ID_COL_IDX)) = 1;
+
+	db_set_int_val(values, HASH_ENTRY_COL_IDX, ro_session->h_entry);
+	db_set_int_val(values, HASH_ID_COL_IDX, ro_session->h_id);
+	db_set_str_val(values, SESSION_ID_COL_IDX, &ro_session->ro_session_id);
+	db_set_int_val(values, DLG_HASH_ENTRY_COL_IDX, ro_session->dlg_h_entry);
+	db_set_int_val(values, DLG_HASH_ID_COL_IDX, ro_session->dlg_h_id);
+	db_set_int_val(values, DIRECTION_COL_IDX, ro_session->direction);
+	db_set_str_val(values, ASSERTED_ID_COL_IDX, &ro_session->asserted_identity);
+	db_set_str_val(values, CALLEE_COL_IDX, &ro_session->called_asserted_identity);
+	db_set_datetime_val(values, START_TIME_COL_IDX, ro_session->start_time);
+	db_set_datetime_val(values, LAST_EVENT_TS_COL_IDX, ro_session->last_event_timestamp);
+	db_set_int_val(values, RESERVED_SECS_COL_IDX, ro_session->reserved_secs);
+	db_set_int_val(values, VALID_FOR_COL_IDX, ro_session->valid_for);
+	db_set_int_val(values, STATE_COL_IDX, ro_session->active);
+
+	LM_DBG("Inserting ro_session into database\n");
+	if ((ro_dbf.insert(ro_db_handle, insert_keys, values, RO_SESSION_TABLE_COL_NUM)) != 0) {
+	    LM_ERR("could not add new Ro session into DB.... continuing\n");
+	    goto error;
+	}
+	ro_session->flags &= ~(RO_SESSION_FLAG_NEW | RO_SESSION_FLAG_CHANGED);
+	ro_session->flags |= RO_SESSION_FLAG_INSERTED;
+
+    } else if ((ro_session->flags & RO_SESSION_FLAG_CHANGED) != 0 && (ro_session->flags & RO_SESSION_FLAG_INSERTED) != 0) {
+
+	db_val_t values[13];
+	db_key_t update_keys[13] = {
+	    &h_entry_column, &h_id_column, &session_id_column, &dlg_h_entry_column, &dlg_h_id_column,
+	    &direction_column, &asserted_column, &callee_column, &start_time_col, &last_event_ts_column,
+	    &reserved_sec_column, &valid_for_column, &state_column
+	};
+
+	db_set_int_val(values, HASH_ENTRY_COL_IDX - 1, ro_session->h_entry);
+	db_set_int_val(values, HASH_ID_COL_IDX - 1, ro_session->h_id);
+	db_set_str_val(values, SESSION_ID_COL_IDX - 1, &ro_session->ro_session_id);
+	db_set_int_val(values, DLG_HASH_ENTRY_COL_IDX - 1, ro_session->dlg_h_entry);
+	db_set_int_val(values, DLG_HASH_ID_COL_IDX - 1, ro_session->dlg_h_id);
+	db_set_int_val(values, DIRECTION_COL_IDX - 1, ro_session->direction);
+	db_set_str_val(values, ASSERTED_ID_COL_IDX - 1, &ro_session->asserted_identity);
+	db_set_str_val(values, CALLEE_COL_IDX - 1, &ro_session->called_asserted_identity);
+	db_set_datetime_val(values, START_TIME_COL_IDX - 1, ro_session->start_time);
+	db_set_datetime_val(values, LAST_EVENT_TS_COL_IDX - 1, ro_session->last_event_timestamp);
+	db_set_int_val(values, RESERVED_SECS_COL_IDX - 1, ro_session->reserved_secs);
+	db_set_int_val(values, VALID_FOR_COL_IDX - 1, ro_session->valid_for);
+	db_set_int_val(values, STATE_COL_IDX - 1, ro_session->active);
+
+	LM_DBG("Updating ro_session in database\n");
+	if ((ro_dbf.update(ro_db_handle, update_keys/*match*/, 0/*match*/, values/*match*/, update_keys/*update*/, values/*update*/, 3/*match*/, 13/*update*/)) != 0) {
+	    LM_ERR("could not update Ro session information in DB... continuing\n");
+	    goto error;
+	}
+	ro_session->flags &= ~RO_SESSION_FLAG_CHANGED;
+    } else if ((ro_session->flags & RO_SESSION_FLAG_DELETED) != 0) {
+	db_val_t values[3];
+	db_key_t match_keys[3] = {&h_entry_column, &h_id_column, &session_id_column};
+	
+	db_set_int_val(values, HASH_ENTRY_COL_IDX - 1, ro_session->h_entry);
+	db_set_int_val(values, HASH_ID_COL_IDX - 1, ro_session->h_id);
+	db_set_str_val(values, SESSION_ID_COL_IDX - 1, &ro_session->ro_session_id);
+	
+	if(ro_dbf.delete(ro_db_handle, match_keys, 0, values, 3) < 0) {
+		LM_ERR("failed to delete ro session database information... continuing\n");
+		return -1;
+	}
+    } else {
+	LM_WARN("Asked to update Ro session in strange state [%d]\n", ro_session->flags);
+    }
+
+    return 0;
+
+error:
+    return -1;
+}
+
+int update_ro_dbinfo(struct ro_session* ro_session) {
+    struct ro_session_entry entry;
+    /* lock the entry */
+    entry = (ro_session_table->entries)[ro_session->h_entry];
+    ro_session_lock(ro_session_table, &entry);
+    if (update_ro_dbinfo_unsafe(ro_session) != 0) {
+	LM_ERR("failed to update ro_session in DB\n");
+	ro_session_unlock(ro_session_table, &entry);
+	return -1;
+    }
+    ro_session_unlock(ro_session_table, &entry);
+    return 0;
+}

+ 41 - 0
modules/ims_charging/ro_db_handler.h

@@ -0,0 +1,41 @@
+/* 
+ * File:   ro_db_handler.h
+ * Author: jaybeepee
+ *
+ * Created on 02 September 2014, 11:20 AM
+ */
+
+#ifndef RO_DB_HANDLER_H
+#define	RO_DB_HANDLER_H
+
+#include "../../str.h"
+#include "../../lib/srdb1/db.h"
+#include "ro_session_hash.h"
+
+#define RO_TABLE_VERSION            1
+#define RO_SESSION_TABLE_NAME       "ro_session"
+#define RO_SESSION_TABLE_COL_NUM    14
+
+#define ID_COL                      "id"
+#define HASH_ENTRY_COL              "hash_entry"
+#define HASH_ID_COL                 "hash_id"
+#define SESSION_ID_COL              "session_id"
+#define DLG_HASH_ENTRY_COL          "dlg_hash_entry"
+#define DLG_HASH_ID_COL             "dlg_hash_id"
+#define DIRECTION_COL               "direction"
+#define ASSERTED_ID_COL             "asserted_identity"
+#define CALLEE_COL                  "callee"
+#define START_TIME_COL              "start_time"
+#define LAST_EVENT_TS_COL           "last_event_timestamp"
+#define RESERVED_SECS_COL           "reserved_secs"
+#define VALID_FOR_COL               "valid_for"
+#define STATE_COL                   "state"
+
+int init_ro_db(const str *db_url, int dlg_hash_size , int db_update_period, int fetch_num_rows);
+int load_ro_info_from_db(int hash_size, int fetch_num_rows);
+int ro_connect_db(const str *db_url);
+int update_ro_dbinfo_unsafe(struct ro_session* ro_session);
+int update_ro_dbinfo(struct ro_session* ro_session);
+
+#endif	/* RO_DB_HANDLER_H */
+

+ 12 - 2
modules/ims_charging/ro_session_hash.c

@@ -174,10 +174,12 @@ void destroy_dlg_table(void) {
     return;
 }
 
-struct ro_session* build_new_ro_session(int direction, int auth_appid, int auth_session_type, str *session_id, str *callid, str *asserted_identity, str* called_asserted_identity, str* mac, unsigned int dlg_h_entry, unsigned int dlg_h_id, unsigned int requested_secs, unsigned int validity_timeout){
+struct ro_session* build_new_ro_session(int direction, int auth_appid, int auth_session_type, str *session_id, str *callid, str *asserted_identity, 
+	str* called_asserted_identity, str* mac, unsigned int dlg_h_entry, unsigned int dlg_h_id, unsigned int requested_secs, unsigned int validity_timeout,
+	int active_rating_group, int active_service_identifier, str *trunk_id){
     LM_DBG("Building Ro Session **********");
     char *p;
-    unsigned int len = session_id->len + callid->len + asserted_identity->len + called_asserted_identity->len + mac->len + sizeof (struct ro_session);
+    unsigned int len = session_id->len + callid->len + asserted_identity->len + called_asserted_identity->len + mac->len + trunk_id->len + sizeof (struct ro_session);
     struct ro_session *new_ro_session = (struct ro_session*) shm_malloc(len);
 
     if (!new_ro_session) {
@@ -208,6 +210,9 @@ struct ro_session* build_new_ro_session(int direction, int auth_appid, int auth_
     new_ro_session->h_entry = dlg_h_entry; /* we will use the same entry ID as the dlg - saves us using our own hash function */
     new_ro_session->h_id = 0;
     new_ro_session->ref = 0;
+    
+    new_ro_session->rating_group = active_rating_group;
+    new_ro_session->service_identifier = active_service_identifier;
 
     p = (char*) (new_ro_session + 1);
     new_ro_session->callid.s = p;
@@ -230,6 +235,11 @@ struct ro_session* build_new_ro_session(int direction, int auth_appid, int auth_
     memcpy(p, called_asserted_identity->s, called_asserted_identity->len);
     p += called_asserted_identity->len;
     
+    new_ro_session->trunk_id.s = p;
+    new_ro_session->trunk_id.len = trunk_id->len;
+    memcpy(p, trunk_id->s, trunk_id->len);
+    p += trunk_id->len;
+    
     new_ro_session->avp_value.mac.s		= p;
     new_ro_session->avp_value.mac.len	= mac->len;
     memcpy(p, mac->s, mac->len);

+ 14 - 3
modules/ims_charging/ro_session_hash.h

@@ -13,6 +13,13 @@
 #include "../ims_usrloc_scscf/usrloc.h"
 #include <stdlib.h>
 
+
+/* ro session flags */
+#define RO_SESSION_FLAG_NEW          (1<<0) /*!< new ro session */
+#define RO_SESSION_FLAG_INSERTED     (1<<1) /*!< session has been written to DB */
+#define RO_SESSION_FLAG_CHANGED      (1<<2) /*!< ro session has been updated */
+#define RO_SESSION_FLAG_DELETED      (1<<3) /*!< ro session has been deleted */
+
 enum ro_session_event_type {
     pending,
     answered,
@@ -28,7 +35,6 @@ struct diameter_avp_value {
 struct impu_data {
     str identity;
     str contact;
-    udomain_t* d;
 } impu_data_t;
 
 
@@ -42,6 +48,7 @@ struct ro_session {
     str callid;
     str asserted_identity;
     str called_asserted_identity;
+    str trunk_id;
     unsigned int hop_by_hop;
     struct ro_tl ro_tl;
     unsigned int reserved_secs;
@@ -56,8 +63,10 @@ struct ro_session {
     int auth_appid;
     int auth_session_type;
     int active;
-
+    unsigned int flags;
     struct diameter_avp_value avp_value;
+    int rating_group;
+    int service_identifier;
 };
 
 /*! entries in the main ro_session table */
@@ -179,7 +188,9 @@ void link_ro_session(struct ro_session *ro_session, int n);
 
 void remove_aaa_session(str *session_id);
 
-struct ro_session* build_new_ro_session(int direction, int auth_appid, int auth_session_type, str *session_id, str *callid, str *asserted_identity, str* called_asserted_identity, str* mac, unsigned int dlg_h_entry, unsigned int dlg_h_id, unsigned int requested_secs, unsigned int validity_timeout);
+struct ro_session* build_new_ro_session(int direction, int auth_appid, int auth_session_type, str *session_id, str *callid, str *asserted_identity, str* called_asserted_identity, 
+	str* mac, unsigned int dlg_h_entry, unsigned int dlg_h_id, unsigned int requested_secs, unsigned int validity_timeout,
+	int active_rating_group, int active_service_identifier, str *trunk_id);
 
 /*!
  * \brief Refefence a ro_session with locking

+ 10 - 1
modules/ims_charging/ro_timer.c

@@ -15,10 +15,12 @@
 #include "ro_session_hash.h"
 #include "ims_ro.h"
 #include "stats.h"
+#include "ro_db_handler.h"
+#include "mod.h"
 
 extern int interim_request_credits;
 extern int ro_timer_buffer;
-
+extern int ro_db_mode;
 extern struct dlg_binds dlgb;
 
 /*! global dialog timer */
@@ -317,6 +319,13 @@ void resume_ro_session_ontimeout(struct interim_ccr *i_req) {
 		else {
 			ref_ro_session_unsafe(i_req->ro_session, 1);
 		}
+		
+		if (ro_db_mode == DB_MODE_REALTIME) {
+		    i_req->ro_session->flags |= RO_SESSION_FLAG_CHANGED;
+		    if (update_ro_dbinfo_unsafe(i_req->ro_session) != 0) {
+			LM_ERR("Failed to update Ro session in DB... continuing\n");
+		    }
+		}
 	}
 	else {
 		/* just put the timer back in with however many seconds are left (if any!!! in which case we need to kill */