int assert_called_identity(struct sip_msg* _m, udomain_t* _d) { int ret=CSCF_RETURN_FALSE; str called_party_id={0,0},x={0,0}; struct sip_msg* req; struct hdr_field *h=0; //get request from reply req = get_request_from_reply(_m); if (!req) { LM_ERR("Unable to get request from reply for REGISTER. No transaction\n"); goto error; } called_party_id = cscf_get_public_identity_from_called_party_id(req, &h); if (!called_party_id.len){ goto error; }else{ LM_DBG("Called Party ID from request: %.*s\n", called_party_id.len, called_party_id.s); x.len = p_asserted_identity_s.len+p_asserted_identity_m.len+called_party_id.len+p_asserted_identity_e.len; x.s = pkg_malloc(x.len); if (!x.s){ LM_ERR("P_assert_called_identity: Error allocating %d bytes\n", x.len); x.len=0; goto error; } x.len=0; STR_APPEND(x,p_asserted_identity_s); STR_APPEND(x,p_asserted_identity_m); STR_APPEND(x,called_party_id); STR_APPEND(x,p_asserted_identity_e); if (cscf_add_header(_m,&x,HDR_OTHER_T)) ret = CSCF_RETURN_TRUE; else goto error; } return ret; error: ret=CSCF_RETURN_FALSE; 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; }