/** * Get the public identity from P-Asserted-Identity, or From if asserted not found. * @param msg - the SIP message * @param uri - uri to fill into * @returns 1 if found, 0 if not */ int cscf_get_originating_user( struct sip_msg * msg, str *uri ) { struct to_body * from; *uri = cscf_get_asserted_identity(msg, 0); if (!uri->len) { /* Fallback to From header */ if ( parse_from_header( msg ) == -1 ) { LM_ERR("ERROR:cscf_get_originating_user: unable to extract URI from FROM header\n" ); return 0; } if (!msg->from) return 0; from = (struct to_body*) msg->from->parsed; *uri = from->uri; cscf_strip_uri(uri); } DBG("DEBUG:cscf_get_originating_user: From %.*s\n", uri->len,uri->s ); return 1; }
int get_sip_header_info(struct sip_msg * req, struct sip_msg * reply, int32_t * acc_record_type, str * sip_method, str * event, uint32_t * expires, str * callid, str * asserted_id_uri, str * to_uri) { sip_method->s = req->first_line.u.request.method.s; sip_method->len = req->first_line.u.request.method.len; if (strncmp(sip_method->s, "INVITE", 6) == 0) *acc_record_type = AAA_ACCT_START; else if (strncmp(sip_method->s, "BYE", 3) == 0) *acc_record_type = AAA_ACCT_STOP; else *acc_record_type = AAA_ACCT_EVENT; *event = cscf_get_event(req); *expires = cscf_get_expires_hdr(req, 0); *callid = cscf_get_call_id(req, NULL); if ((*asserted_id_uri = cscf_get_asserted_identity(req, 0)).len == 0) { LM_DBG("No P-Asserted-Identity hdr found. Using From hdr"); if (!cscf_get_from_uri(req, asserted_id_uri)) { LM_ERR("Error assigning P-Asserted-Identity using From hdr"); goto error; } } *to_uri = req->first_line.u.request.uri; LM_DBG("retrieved sip info : sip_method %.*s acc_record_type %i, event %.*s expires %u " "call_id %.*s from_uri %.*s to_uri %.*s\n", sip_method->len, sip_method->s, *acc_record_type, event->len, event->s, *expires, callid->len, callid->s, asserted_id_uri->len, asserted_id_uri->s, to_uri->len, to_uri->s); return 1; error: return 0; }
/** * Finds the AOR for a dialog * @param msg - the SIP message to add to * @param d - the dialog direction * @param aor - aor to fill * @returns 1 if found, 0 if not */ static inline int find_dialog_aor(struct sip_msg *msg,enum s_dialog_direction d,str *aor) { if (msg->first_line.type!=SIP_REQUEST) return 0; switch(d){ case DLG_MOBILE_ORIGINATING: *aor = cscf_get_asserted_identity(msg); if (!aor->len) return 0; return 1; break; case DLG_MOBILE_TERMINATING: *aor = cscf_get_called_party_id(msg,0); if (!aor->len) *aor = cscf_get_identity_from_ruri(msg); if (!aor->len) return 0; return 1; break; default: LOG(L_CRIT,"ERR:"M_NAME":find_dialog_aor(): Unknown direction %d",d); return 0; } return 1; }
/** * Get the public identity from P-Asserted-Identity, or From if asserted not found. * @param msg - the SIP message * @param uri - uri to fill into * @returns 1 if found, 0 if not */ int isc_get_originating_user( struct sip_msg * msg, isc_mark *mark, str *uri ) { struct to_body * from; if (mark && mark->aor.len){ *uri = mark->aor; return 1; } *uri = cscf_get_asserted_identity(msg); if (!uri->len) { /* Fallback to From header */ if ( parse_from_header( msg ) == -1 ) { LOG(L_ERR,"ERROR:"M_NAME":isc_get_originating_user: unable to extract URI from FROM header\n" ); return 0; } if (!msg->from) return 0; from = (struct to_body*) msg->from->parsed; *uri = from->uri; isc_strip_uri(uri); } DBG("DEBUG:"M_NAME":isc_get_originating_user: From %.*s\n", uri->len,uri->s ); return 1; }
/** * Perform an LIR * @param msg - sip message * @returns 1 on success or 0 on failure */ int I_perform_location_information_request(struct sip_msg* msg, char* route, char* str1, char* str2) { str public_identity = {0, 0}; int orig = 0; tm_cell_t *t = 0; saved_lir_transaction_t* saved_t; str route_name; cfg_action_t* cfg_action; if (fixup_get_svalue(msg, (gparam_t*) route, &route_name) != 0) { LM_ERR("no async route block for assign_server_unreg\n"); return -1; } LM_DBG("Looking for route block [%.*s]\n", route_name.len, route_name.s); int ri = route_get(&main_rt, route_name.s); if (ri < 0) { LM_ERR("unable to find route block [%.*s]\n", route_name.len, route_name.s); return -1; } cfg_action = main_rt.rlist[ri]; if (cfg_action == NULL) { LM_ERR("empty action lists in route block [%.*s]\n", route_name.len, route_name.s); return -1; } LM_DBG("DBG:I_LIR: Starting ...\n"); /* check if we received what we should */ if (msg->first_line.type != SIP_REQUEST) { LM_ERR("ERR:I_LIR: The message is not a request\n"); return CSCF_RETURN_BREAK; } /* check orig uri parameter in topmost Route */ if (cscf_has_originating(msg, str1, str2) == CSCF_RETURN_TRUE) { orig = 1; LM_DBG("DBG:I_LIR: orig\n"); } /* extract data from message */ if (orig) { public_identity = cscf_get_asserted_identity(msg, 0); } else { public_identity = cscf_get_public_identity_from_requri(msg); } if (!public_identity.len) { LM_ERR("ERR:I_LIR: Public Identity not found, responding with 400\n"); if (orig) cscf_reply_transactional(msg, 400, MSG_400_NO_PUBLIC_FROM); else cscf_reply_transactional(msg, 400, MSG_400_NO_PUBLIC); return CSCF_RETURN_BREAK; } //before we send lets suspend the transaction t = tmb.t_gett(); if (t == NULL || t == T_UNDEFINED) { if (tmb.t_newtran(msg) < 0) { LM_ERR("cannot create the transaction for UAR async\n"); cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR); return CSCF_RETURN_BREAK; } t = tmb.t_gett(); if (t == NULL || t == T_UNDEFINED) { LM_ERR("cannot lookup the transaction\n"); cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR); return CSCF_RETURN_BREAK; } } saved_t = shm_malloc(sizeof (saved_lir_transaction_t)); if (!saved_t) { LM_ERR("no more memory trying to save transaction state\n"); return CSCF_RETURN_ERROR; } memset(saved_t, 0, sizeof (saved_lir_transaction_t)); saved_t->act = cfg_action; saved_t->orig = orig; LM_DBG("Setting default AVP return code used for async callbacks to default as ERROR \n"); create_lia_return_code(CSCF_RETURN_ERROR); LM_DBG("Suspending SIP TM transaction\n"); if (tmb.t_suspend(msg, &saved_t->tindex, &saved_t->tlabel) < 0) { LM_ERR("failed to suspend the TM processing\n"); free_saved_lir_transaction_data(saved_t); cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR); return CSCF_RETURN_BREAK; } if (cxdx_send_lir(msg, public_identity, saved_t) != 0) { LM_ERR("ERR:I_LIR: Error sending LIR or LIR time-out\n"); tmb.t_cancel_suspend(saved_t->tindex, saved_t->tlabel); free_saved_lir_transaction_data(saved_t); cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR); if (public_identity.s && !orig) shm_free(public_identity.s); // shm_malloc in cscf_get_public_identity_from_requri return CSCF_RETURN_BREAK; } if (public_identity.s && !orig) shm_free(public_identity.s); // shm_malloc in cscf_get_public_identity_from_requri //we use async replies therefore we send break and not true when successful return CSCF_RETURN_BREAK; }
/** * Check if this message quallifies for a subscription. * Only 3 entities can subscribe: * - the user agent to its own state * - the P-CSCF specified in a Path header for that user * - AS (not implemented yet * \todo Allow also the AS listed in iFC and not belonging to a 3rd party * @param msg - the SIP SUBSCRIBE message * @param str1 - not used * @param str2 - not used * @returns #CSCF_RETURN_TRUE if allowed, #CSCF_RETURN_FALSE if not, #CSCF_RETURN_ERROR on error */ int S_can_subscribe(struct sip_msg *msg,char *str1,char *str2) { int ret=CSCF_RETURN_FALSE; struct sip_uri puri; str uri={0,0}; str event; str asserted_id; r_public *p=0; r_contact *c=0; ims_public_identity *pi=0; int i,j; LOG(L_DBG,"DBG:"M_NAME":S_can_subscribe: Checking if allowed to SUBSCRIBE\n"); /* First check the parameters */ if (msg->first_line.type!=SIP_REQUEST) { LOG(L_ERR,"ERR:"M_NAME":S_can_subscribe: This message is not a request\n"); goto error; } if (msg->first_line.u.request.method.len != 9 || memcmp(msg->first_line.u.request.method.s,"SUBSCRIBE",9)!=0) { LOG(L_ERR,"ERR:"M_NAME":S_can_subscribe: This message is not a SUBSCRIBE\n"); goto error; } /* 1. Get the event */ event = cscf_get_event(msg); if (event.len!=3||strncasecmp(event.s,"reg",3)!=0){ LOG(L_ERR,"ERR:"M_NAME":S_can_subscribe: Accepting only <Event: reg>. Found: <%.*s>\n", event.len,event.s); ret = CSCF_RETURN_FALSE; goto done; } /* 2. Get the target of the SUBSCRIBE from RequestURI */ if (msg->new_uri.s) uri = msg->new_uri; else uri = msg->first_line.u.request.uri; if (parse_uri(uri.s, uri.len, &puri) < 0) { LOG(L_ERR,"ERR:"M_NAME":S_can_subscribe: Error parsing uri <%.*s>\n", uri.len,uri.s); goto error; } uri.len = lookup_sip.len+puri.user.len+1+puri.host.len; uri.s = pkg_malloc(uri.len); if (!uri.s){ LOG(L_ERR,"ERR:"M_NAME":S_can_subscribe: Error allocating %d bytes\n",uri.len); goto error; } uri.len=0; memcpy(uri.s,lookup_sip.s,lookup_sip.len); uri.len+=lookup_sip.len; memcpy(uri.s+uri.len,puri.user.s,puri.user.len); uri.len+=puri.user.len; uri.s[uri.len++]='@'; memcpy(uri.s+uri.len,puri.host.s,puri.host.len); uri.len+=puri.host.len; /* 3. Check if the asserted identity is in the same group with the ReqURI */ asserted_id = cscf_get_asserted_identity(msg); if (!asserted_id.len){ LOG(L_ERR,"ERR:"M_NAME":S_can_subscribe: P-Asserted-Identity empty.\n"); ret = CSCF_RETURN_FALSE; goto done; } LOG(L_DBG,"DBG:"M_NAME":S_can_subscribe: P-Asserted-Identity <%.*s>.\n", asserted_id.len,asserted_id.s); p = get_r_public(uri); if (!p){ LOG(L_ERR,"ERR:"M_NAME":S_can_subscribe: Identity not found <%.*s>\n", uri.len,uri.s); ret = CSCF_RETURN_FALSE; goto done; } if (p->aor.len == asserted_id.len && strncasecmp(p->aor.s,asserted_id.s,asserted_id.len)==0) { LOG(L_DBG,"DBG:"M_NAME":S_can_subscribe: Identity found as AOR <%.*s>\n", uri.len,uri.s); ret = CSCF_RETURN_TRUE; goto done; } if (p->s){ for(i=0;i<p->s->service_profiles_cnt;i++) for(j=0;j<p->s->service_profiles[i].public_identities_cnt;j++) { pi = &(p->s->service_profiles[i].public_identities[j]); if (!pi->barring && pi->public_identity.len == asserted_id.len && strncasecmp(pi->public_identity.s,asserted_id.s,asserted_id.len)==0) { LOG(L_DBG,"DBG:"M_NAME":S_can_subscribe: Identity found in SP[%d][%d]\n", i,j); ret = CSCF_RETURN_TRUE; goto done; } } } /* 4. Check if it present in any of the Path headers */ c=p->head; while(c){ if (c->path.len){ for(i=0;i<c->path.len-asserted_id.len;i++) if (strncasecmp(c->path.s+i,asserted_id.s,asserted_id.len)==0){ LOG(L_DBG,"DBG:"M_NAME":S_can_subscribe: Identity found in Path <%.*s>\n", c->path.len,c->path.s); ret = CSCF_RETURN_TRUE; goto done; } } c = c->next; } done: if (p) r_unlock(p->hash); if (uri.s) pkg_free(uri.s); return ret; error: if (p) r_unlock(p->hash); if (uri.s) pkg_free(uri.s); ret=CSCF_RETURN_ERROR; return ret; }
/** * Send a CCR to the OCS based on the SIP message (INVITE ONLY) * @param msg - SIP message * @param direction - orig|term * @param reservation_units - units to try to reserve * @param reservation_units - config route to call when receiving a CCA * @param tindex - transaction index * @param tindex - transaction label * * @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, int reservation_units, str* incoming_trunk_id, str* outgoing_trunk_id, str* pani, cfg_action_t* action, unsigned int tindex, unsigned int tlabel) { str session_id = {0, 0}, called_asserted_identity = {0, 0}, subscription_id = {0, 0}, asserted_identity = {0, 0}; int subscription_id_type = AVP_EPC_Subscription_Id_Type_End_User_SIP_URI; AAASession* cc_acc_session = NULL; Ro_CCR_t * ro_ccr_data = 0; AAAMessage * ccr = 0; struct ro_session *new_session = 0; struct session_setup_data *ssd; int ret = 0; struct hdr_field *h = 0; char *p; int cc_event_number = 0; //According to IOT tests this should start at 0 int cc_event_type = RO_CC_START; int free_called_asserted_identity = 0; 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 (%c) for reservation_units [%d] incoming_trunk_id [%.*s] outgoing_trunk_id [%.*s]\n", dir==RO_ORIG_DIRECTION?'O':'T', reservation_units, incoming_trunk_id->len, incoming_trunk_id->s, outgoing_trunk_id->len, outgoing_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"); goto error; } //getting asserted identity if ((asserted_identity = cscf_get_asserted_identity(msg, 0)).len == 0) { LM_DBG("No P-Asserted-Identity hdr found. Using From hdr for asserted_identity"); asserted_identity = dlg->from_uri; if (asserted_identity.len > 0 && asserted_identity.s) { p=(char*)memchr(asserted_identity.s, ';',asserted_identity.len); if (p) asserted_identity.len = (p-asserted_identity.s); } } //getting called asserted identity if ((called_asserted_identity = cscf_get_public_identity_from_called_party_id(msg, &h)).len == 0) { LM_DBG("No P-Called-Identity hdr found. Using request URI for called_asserted_identity"); called_asserted_identity = cscf_get_public_identity_from_requri(msg); free_called_asserted_identity = 1; } if (dir == RO_ORIG_DIRECTION) { subscription_id.s = asserted_identity.s; subscription_id.len = asserted_identity.len; } else if (dir == RO_TERM_DIRECTION) { subscription_id.s = called_asserted_identity.s; subscription_id.len = called_asserted_identity.len; } else { LM_CRIT("don't know what to do in unknown mode - should we even get here\n"); goto error; } //getting subscription id type if (strncasecmp(subscription_id.s, "tel:", 4) == 0) { subscription_id_type = Subscription_Type_MSISDN; } else { subscription_id_type = Subscription_Type_IMPU; //default is END_USER_SIP_URI } str mac = {0, 0}; if (get_mac_avp_value(msg, &mac) != 0) LM_DBG(RO_MAC_AVP_NAME" was not set. Using default."); //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); active_service_identifier = voice_service_identifier; active_rating_group = voice_rating_group; //check SDP - if there is video then set default to video, if not set it to audio if (parse_sdp(msg) < 0) { LM_ERR("Unable to parse req SDP\n"); goto error; } msg_sdp_session = get_sdp_session(msg, 0); if (!msg_sdp_session) { LM_ERR("Missing SDP session information from rpl\n"); } else { for (;;) { msg_sdp_stream = get_sdp_stream(msg, 0, sdp_stream_num); if (!msg_sdp_stream) { //LM_ERR("Missing SDP stream information\n"); break; } int intportA = atoi(msg_sdp_stream->port.s); if (intportA != 0 && strncasecmp(msg_sdp_stream->media.s, "video", 5) == 0) { LM_DBG("This SDP has a video component and src ports not equal to 0 - so we set default SID to %d and RG to %d for video", video_service_identifier, video_rating_group); active_service_identifier = video_service_identifier; active_rating_group = video_rating_group; break; } sdp_stream_num++; } } 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, incoming_trunk_id, outgoing_trunk_id, pani); 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, incoming_trunk_id, outgoing_trunk_id, pani)) 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))) goto error; if (!Ro_add_vendor_specific_appid(ccr, IMS_vendor_id_3GPP, IMS_Ro, 0)) { LM_ERR("Problem adding Vendor specific ID\n"); goto error; } if (!Ro_add_cc_request(ccr, cc_event_type, cc_event_number)) { LM_ERR("Problem adding CC-Request data\n"); goto error; } if (!Ro_add_event_timestamp(ccr, time(NULL))) { LM_ERR("Problem adding Event-Timestamp data\n"); goto error; } if (!Ro_add_user_equipment_info(ccr, AVP_EPC_User_Equipment_Info_Type_MAC, mac)) { LM_ERR("Problem adding User-Equipment data\n"); goto error; } if (!Ro_add_subscription_id(ccr, subscription_id_type, &subscription_id)) { LM_ERR("Problem adding Subscription ID data\n"); goto error; } 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; new_session->ro_session_id.s = (char*) shm_malloc(cc_acc_session->id.len); if (!new_session->ro_session_id.s) { LM_ERR("no more shm mem\n"); goto error; } new_session->ro_session_id.len = cc_acc_session->id.len; memcpy(new_session->ro_session_id.s, cc_acc_session->id.s, cc_acc_session->id.len); LM_DBG("new CC Ro Session ID: [%.*s] stored in shared memory address [%p]\n", cc_acc_session->id.len, cc_acc_session->id.s, new_session); LM_DBG("Sending CCR Diameter message.\n"); // new_session->ccr_sent = 1; //assume we will send successfully cdpb.AAASessionsUnlock(cc_acc_session->hash); if (ro_forced_peer.len > 0) { LM_DBG("Sending message with Peer\n"); ret = cdpb.AAASendMessageToPeer(ccr, &ro_forced_peer, resume_on_initial_ccr, (void *) ssd); } else { LM_DBG("Sending message without Peer and realm is [%.*s]\n", ccr->dest_realm->data.len, ccr->dest_realm->data.s); ret = cdpb.AAASendMessage(ccr, resume_on_initial_ccr, (void *) ssd); } if (ret != 1) { LM_ERR("Failed to send Diameter CCR\n"); // new_session->ccr_sent = 0; goto error; } Ro_free_CCR(ro_ccr_data); LM_DBG("Registering for callbacks on Dialog [%p] and charging session [%p]\n", dlg, new_session); //TODO: if the following fail, we should clean up the Ro session....... if (dlgb.register_dlgcb(dlg, DLGCB_TERMINATED | DLGCB_FAILED | DLGCB_EXPIRED | DLGCB_CONFIRMED, dlg_callback_received, (void*) new_session, NULL) != 0) { LM_CRIT("cannot register callback for dialog confirmation\n"); goto error; } counter_inc(ims_charging_cnts_h.initial_ccrs); counter_inc(ims_charging_cnts_h.active_ro_sessions); if (free_called_asserted_identity) shm_free(called_asserted_identity.s); // shm_malloc in cscf_get_public_identity_from_requri return RO_RETURN_BREAK; error: LM_DBG("Trying to reserve credit on initial INVITE failed.\n"); if (free_called_asserted_identity) shm_free(called_asserted_identity.s); // shm_malloc in cscf_get_public_identity_from_requri Ro_free_CCR(ro_ccr_data); if (cc_acc_session) { cdpb.AAASessionsUnlock(cc_acc_session->hash); cdpb.AAADropSession(cc_acc_session); } if (ssd) shm_free(ssd); return RO_RETURN_ERROR; }
static int w_ro_ccr(struct sip_msg *msg, char* c_route_name, char* c_direction, char* c_charge_type, char* c_unit_type, int reservation_units, char* c_trunk_id) { /* PSEUDOCODE/NOTES * 1. What mode are we in - terminating or originating * 2. check request type - IEC - Immediate Event Charging * ECUR - Event Charging with Unit Reservation * SCUR - Session Charging with Unit Reservation * 3. probably only do SCUR in this module for now - can see event based charging in another component instead (AS for SMS for example, etc) * 4. Check a dialog exists for call, if not we fail * 5. make sure we dont already have an Ro Session for this dialog * 6. create new Ro Session * 7. register for DLG callback passing new Ro session as parameter - (if dlg torn down we know which Ro session it is associated with) * * */ 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; tm_cell_t *t; unsigned int tindex = 0, tlabel = 0; struct impu_data *impu_data; char *p; struct dlg_cell* dlg; unsigned int len; struct ro_session *ro_session = 0; int free_contact = 0; str s_route_name, s_direction, s_charge_type, s_unit_type, s_trunk_id; if (get_str_fparam(&s_route_name, msg, (fparam_t*) c_route_name) < 0) { LM_ERR("failed to get s_route_name\n"); return RO_RETURN_ERROR; } if (get_str_fparam(&s_direction, msg, (fparam_t*) c_direction) < 0) { LM_ERR("failed to get s_direction\n"); return RO_RETURN_ERROR; } if (get_str_fparam(&s_charge_type, msg, (fparam_t*) c_charge_type) < 0) { LM_ERR("failed to get s_charge_type\n"); return RO_RETURN_ERROR; } if (get_str_fparam(&s_unit_type, msg, (fparam_t*) c_unit_type) < 0) { LM_ERR("failed to get s_unit_type\n"); return RO_RETURN_ERROR; } if (get_str_fparam(&s_trunk_id, msg, (fparam_t*) c_trunk_id) < 0) { LM_ERR("failed to get s_trunk_id\n"); return RO_RETURN_ERROR; } LM_DBG("Ro CCR initiated: direction:%.*s, charge_type:%.*s, unit_type:%.*s, reservation_units:%i, route_name:%.*s, trunk_id:%.*s\n", s_direction.len, s_direction.s, s_charge_type.len, s_charge_type.s, s_unit_type.len, s_unit_type.s, reservation_units, s_route_name.len, s_route_name.s, s_trunk_id.len, s_trunk_id.s); 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(&s_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_public_identity_from_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 = cscf_get_contact_from_requri(msg); free_contact = 1; } else { LM_CRIT("don't know what to do in unknown mode - should we even get here\n"); ret = RO_RETURN_ERROR; goto done; } LM_DBG("IMPU data to pass to usrloc: contact <%.*s> identity <%.*s>\n", contact.len, contact.s, identity.len, identity.s); //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"); ret = RO_RETURN_ERROR; goto done; } 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; if (p != (((char*) impu_data) + len)) { LM_ERR("buffer overflow creating impu data, trying to send CCR\n"); shm_free(impu_data); ret = RO_RETURN_ERROR; goto done; } //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"); ret = RO_RETURN_ERROR; goto done; } 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"); ret = RO_RETURN_ERROR; goto done; } 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", s_route_name.len, s_route_name.s); int ri = route_get(&main_rt, s_route_name.s); if (ri < 0) { LM_ERR("unable to find route block [%.*s]\n", s_route_name.len, s_route_name.s); ret = RO_RETURN_ERROR; goto done; } cfg_action = main_rt.rlist[ri]; if (!cfg_action) { LM_ERR("empty action lists in route block [%.*s]\n", s_route_name.len, s_route_name.s); ret = RO_RETURN_ERROR; goto done; } //before we send lets suspend the transaction t = tmb.t_gett(); if (t == NULL || t == T_UNDEFINED) { if (tmb.t_newtran(msg) < 0) { LM_ERR("cannot create the transaction for CCR async\n"); ret = RO_RETURN_ERROR; goto done; } t = tmb.t_gett(); if (t == NULL || t == T_UNDEFINED) { LM_ERR("cannot lookup the transaction\n"); ret = RO_RETURN_ERROR; goto done; } } LM_DBG("Suspending SIP TM transaction\n"); if (tmb.t_suspend(msg, &tindex, &tlabel) < 0) { LM_ERR("failed to suspend the TM processing\n"); ret = RO_RETURN_ERROR; goto done; } ret = Ro_Send_CCR(msg, dlg, dir, &s_charge_type, &s_unit_type, reservation_units, &s_trunk_id, cfg_action, tindex, tlabel); if(ret < 0){ LM_ERR("Failed to send CCR\n"); tmb.t_cancel_suspend(tindex, tlabel); } done: if(free_contact) shm_free(contact.s);// shm_malloc in cscf_get_public_identity_from_requri return ret; }