/** * retrieves the ims charging id, also named as ICID, from the request or reply * if the P-Charging-Vector SIP header is not included in the request or reply, it might be stored internally * the returned icid is allocated in the pkg memory, do not forget to free after use * retrieves also the originating/terminating inter-operator identifier, for the moment not stored in pkg memory * @param req - the SIP request * @param reply - the SIP reply * @param icid - the ICID * @param orig_ioi - the ORIGinating IOI if contained in the P-Charging-Vector * @param term_ioi - the TERMinating IOI if contained in the P-Charging-Vector */ int get_ims_charging_info(struct sip_msg *req, struct sip_msg * reply, int dir, str * icid, str * orig_ioi, str * term_ioi, uint32_t * rating_group){ str callid = {0,0}; LOG(L_DBG, "get ims charging info\n"); if(req) cscf_get_p_charging_vector(req, icid, orig_ioi, term_ioi); if(reply) cscf_get_p_charging_vector(reply, icid, orig_ioi, term_ioi); if(req) callid = cscf_get_call_id(req, 0); if((!callid.len || !callid.s) && reply) callid = cscf_get_call_id(reply, 0); if(!callid.len || !callid.s) return 1; if(!icid->len || !icid->s){ if(!get_ims_charg_info(callid, dir, icid, rating_group)) return 0; }else if(!get_ims_charg_info(callid, dir, NULL, rating_group)) return 0; return 1; }
/** * Callback for the UAC response to NOTIFY */ void uac_request_cb(struct cell *t,int type,struct tmcb_params *ps) { LOG(L_DBG,"DBG:"M_NAME":uac_request_cb: Type %d\n",type); #ifdef WITH_IMS_PM if (((int) *ps->param) && (ps->rpl != (void*)-1) ){ if (ps->code>=200 && ps->code<300) IMS_PM_LOG12(UR_SuccDeRegCscf,cscf_get_call_id(ps->rpl,0),cscf_get_cseq(ps->rpl,0),ps->code); else if (ps->code>=300) IMS_PM_LOG12(UR_FailDeRegCscf,cscf_get_call_id(ps->rpl,0),cscf_get_cseq(ps->rpl,0),ps->code); } #endif }
/* * alloc a new ESQK and a user data element for the current user * @param msg: current OPTIONS request * @param str1: not used * @param str2: not used */ int LRF_alloc_user_data(struct sip_msg* msg, char*str1, char*str2){ str user_uri; user_d * user_data; str service; struct trans_info options_tr; if(tmb.t_get_trans_ident(msg, &options_tr.hash_index, &options_tr.label) != 1){ LOG(L_ERR, "ERR:"M_NAME":LRF_alloc_user_data:could not retrive hash_index and label of the current message's transaction\n"); return CSCF_RETURN_FALSE; } service = cscf_get_headers_content(msg , service_hdr_name); if(!service.len || !service.s){ LOG(L_ERR, "ERR:"M_NAME":LRF_alloc_user_data: could not find the service header in the OPTIONS, or could not be parsed\n"); return CSCF_RETURN_FALSE; } str callid = cscf_get_call_id(msg, NULL); if(!callid.s || !callid.len){ LOG(L_ERR, "ERR:"M_NAME":LRF_alloc_user_data: could not find the callid header in the OPTIONS request\n"); return CSCF_RETURN_FALSE; } options_tr.callid.s = callid.s; options_tr.callid.len = callid.len; user_uri = msg->first_line.u.request.uri; user_data = add_user_data(user_uri, service, &options_tr); if(!user_data) return CSCF_RETURN_FALSE; print_lrf_user_data(L_INFO); return CSCF_RETURN_TRUE; }
/** * Find out if a message is within a saved dialog. * @param msg - the SIP message * @param str1 - the direction of the dialog ("orig"/"term") * @param str2 - not used * @returns #CSCF_RETURN_TRUE if in, #CSCF_RETURN_FALSE else or #CSCF_RETURN_BREAK on error */ int P_is_in_dialog(struct sip_msg* msg, char* str1, char* str2) { str call_id; str host; int port,transport; enum p_dialog_direction dir; dir = get_dialog_direction(str1); if (!find_dialog_contact(msg,dir,&host,&port,&transport)){ LOG(L_ERR,"ERR:"M_NAME":P_is_in_dialog(%s): Error retrieving %s contact\n",str1,str1); return CSCF_RETURN_BREAK; } //print_p_dialog(L_ERR); call_id = cscf_get_call_id(msg,0); if (!call_id.len) return CSCF_RETURN_FALSE; if (is_p_dialog(call_id,host,port,transport,0)) { return CSCF_RETURN_TRUE; } else return CSCF_RETURN_FALSE; }
int ims_pm_pre_script(struct sip_msg *msg,void *param) { str method={0,0}; if (msg->first_line.type == SIP_REQUEST){ method = msg->first_line.u.request.method; if (method.len==s_invite.len && strncasecmp(method.s,s_invite.s,s_invite.len)==0){ /* INVITE */ IMS_PM_LOG11(SC_AttSession,cscf_get_call_id(msg,0),cscf_get_cseq(msg,0)); IMS_PM_LOG21(IC_AttSessionFromOtherNtwkDmn,cscf_get_call_id(msg,0), cscf_get_asserted_identity_domain(msg), cscf_get_cseq(msg,0)); IMS_PM_LOG21(IC_AttSessionToOtherNtwkDmn,cscf_get_call_id(msg,0), cscf_get_realm_from_ruri(msg), cscf_get_cseq(msg,0)); }else{ /* Other requests */ IMS_PM_LOG21(OTHER_Att,cscf_get_call_id(msg,0),method,cscf_get_cseq(msg,0)); } }else{ unsigned int code = msg->first_line.u.reply.statuscode; method = cscf_get_cseq_method(msg,0); if (method.len==s_invite.len && strncasecmp(method.s,s_invite.s,s_invite.len)==0){ /* INVITE response */ if (code<300) IMS_PM_LOG12(SC_SuccSession,cscf_get_call_id(msg,0),cscf_get_cseq(msg,0),code); else if (code>=300) { IMS_PM_LOG12(SC_FailSession,cscf_get_call_id(msg,0),cscf_get_cseq(msg,0),code); if (code==403) { IMS_PM_LOG22(IC_403SessionFromOtherNtwkDmn,cscf_get_call_id(msg,0), cscf_get_asserted_identity_domain(msg),cscf_get_cseq(msg,0),code); IMS_PM_LOG22(IC_403SessionToOtherNtwkDmn,cscf_get_call_id(msg,0), cscf_get_realm_from_ruri(msg),cscf_get_cseq(msg,0),code); } } }else{ /* Other responses */ if (code>=200 && code<300) IMS_PM_LOG22(OTHER_Succ,cscf_get_call_id(msg,0),method,cscf_get_cseq(msg,0),code); else if (code>=300) IMS_PM_LOG22(OTHER_Fail,cscf_get_call_id(msg,0),method,cscf_get_cseq(msg,0),code); } } return 1; }
int I_scscf_drop(struct sip_msg* msg, char* str1, char* str2) { str call_id; //print_scscf_list(L_ERR); call_id = cscf_get_call_id(msg,0); LOG(L_DBG,"DBG:"M_NAME":I_scscf_drop(): <%.*s>\n",call_id.len,call_id.s); if (!call_id.len) return CSCF_RETURN_FALSE; del_scscf_list(call_id); return CSCF_RETURN_TRUE; }
/** * Saves a dialog. * @param msg - the initial request * @param str1 - direction - "orig" or "term" * @param str2 - not used * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error */ int S_save_dialog(struct sip_msg* msg, char* str1, char* str2) { str call_id; s_dialog *d; str aor; str uri,tag; str ruri; enum s_dialog_direction dir = get_dialog_direction(str1); if (!find_dialog_aor(msg,dir,&aor)){ LOG(L_ERR,"ERR:"M_NAME":S_save_dialog(): Error retrieving %s contact\n",str1); return CSCF_RETURN_BREAK; } call_id = cscf_get_call_id(msg,0); if (!call_id.len) return CSCF_RETURN_FALSE; LOG(L_INFO,"DBG:"M_NAME":S_save_dialog(%s): Call-ID <%.*s>\n",str1,call_id.len,call_id.s); if (is_s_dialog(call_id,aor)){ LOG(L_ERR,"ERR:"M_NAME":S_save_dialog: dialog already exists!\n"); return CSCF_RETURN_FALSE; } d = add_s_dialog(call_id,aor,dir); if (!d) return CSCF_RETURN_FALSE; d->method = get_dialog_method(msg->first_line.u.request.method); STR_SHM_DUP(d->method_str,msg->first_line.u.request.method,"shm"); d->first_cseq = cscf_get_cseq(msg,0); d->last_cseq = d->first_cseq; d->state = DLG_STATE_INITIAL; d->expires = d_act_time()+60; cscf_get_from_tag(msg,&tag); cscf_get_from_uri(msg,&uri); ruri=cscf_get_identity_from_ruri(msg); tmb.new_dlg_uac(&call_id, &tag, d->first_cseq,&uri, &ruri, &d->dialog_c); tmb.new_dlg_uas(msg,99,&d->dialog_s); d_unlock(d->hash); // print_s_dialogs(L_INFO); return CSCF_RETURN_TRUE; }
/** * Create and send a Server-Assignment-Request and returns the Answer received for it. * This function performs the Server Assignment operation. * @param msg - the SIP message to send for * @parma public_identity - the public identity of the user * @param server_name - local name of the S-CSCF to save on the HSS * @param assignment_type - type of the assignment * @param data_available - if the data is already available * @returns the SAA */ int cxdx_send_sar(struct sip_msg *msg, str public_identity, str private_identity, str server_name, int assignment_type, int data_available, saved_transaction_t* transaction_data) { AAAMessage *sar = 0; AAASession *session = 0; unsigned int hash = 0, label = 0; struct hdr_field *hdr; session = cdpb.AAACreateSession(0); sar = cdpb.AAACreateRequest(IMS_Cx, IMS_SAR, Flag_Proxyable, session); if (session) { cdpb.AAADropSession(session); session = 0; } if (!sar) goto error1; if (send_vs_callid_avp) if (!cxdx_add_call_id(sar, cscf_get_call_id(msg, &hdr))) goto error1; if (!cxdx_add_destination_realm(sar, cxdx_dest_realm)) goto error1; if (!cxdx_add_vendor_specific_appid(sar, IMS_vendor_id_3GPP, IMS_Cx, 0 /*IMS_Cx*/)) goto error1; if (!cxdx_add_auth_session_state(sar, 1)) goto error1; if (!cxdx_add_public_identity(sar, public_identity)) goto error1; if (!cxdx_add_server_name(sar, server_name)) goto error1; if (private_identity.len) if (!cxdx_add_user_name(sar, private_identity)) goto error1; if (!cxdx_add_server_assignment_type(sar, assignment_type)) goto error1; if (!cxdx_add_userdata_available(sar, data_available)) goto error1; if (msg && tmb.t_get_trans_ident(msg, &hash, &label) < 0) { // it's ok cause we can call this async with a message for ul callbacks! LM_DBG("SIP message without transaction... must be a ul callback\n"); //return 0; } if (cxdx_forced_peer.len) cdpb.AAASendMessageToPeer(sar, &cxdx_forced_peer, (void*) async_cdp_callback, (void*) transaction_data); else cdpb.AAASendMessage(sar, (void*) async_cdp_callback, (void*) transaction_data); return 0; error1: //Only free SAR IFF it has not been passed to CDP if (sar) cdpb.AAAFreeMessage(&sar); return -1; }
/** * Drops and deletes a dialog. * @param msg - the request/response * @param str1 - direction - "orig" or "term" * @param str2 - not used * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error */ int S_drop_dialog(struct sip_msg* msg, char* str1, char* str2) { str call_id; s_dialog *d; int hash; // struct sip_msg *req; enum s_dialog_direction dir = get_dialog_direction(str1); // if (!find_dialog_aor(msg,str1,&aor)){ // LOG(L_ERR,"ERR:"M_NAME":S_is_in_dialog(): Error retrieving %s contact\n",str1); // return CSCF_RETURN_BREAK; // } call_id = cscf_get_call_id(msg,0); if (!call_id.len) return CSCF_RETURN_FALSE; LOG(L_DBG,"DBG:"M_NAME":S_drop_dialog(%s): Call-ID <%.*s> DIR[%d]\n", str1,call_id.len,call_id.s, dir); d = get_s_dialog_dir(call_id,dir); // if (!d && msg->first_line.type==SIP_REPLY){ // /* Try to get the dialog from the request */ // req = cscf_get_request_from_reply(msg); // if (!find_dialog_aor(req,str1,&aor)){ // LOG(L_ERR,"ERR:"M_NAME":S_update_dialog(%s): Error retrieving %s contact\n",str1,str1); // return CSCF_RETURN_BREAK; // } // d = get_s_dialog(call_id,aor); // } if (!d){ LOG(L_ERR,"ERR:"M_NAME":S_drop_dialog: dialog does not exists!\n"); return CSCF_RETURN_FALSE; } hash = d->hash; del_s_dialog(d); d_unlock(hash); print_s_dialogs(L_INFO); return CSCF_RETURN_TRUE; }
/** * Drops and deletes a dialog. * @param msg - the request/response * @param str1 - direction - "orig" or "term" * @param str2 - not used * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error */ int P_drop_dialog(struct sip_msg* msg, char* str1, char* str2) { str call_id; p_dialog *d; int hash; str host; int port,transport; struct sip_msg *req; enum p_dialog_direction dir; dir = get_dialog_direction(str1); if (msg->first_line.type==SIP_REPLY) req = cscf_get_request_from_reply(msg); else req = msg; if (!find_dialog_contact(req,dir,&host,&port,&transport)){ LOG(L_ERR,"ERR:"M_NAME":P_is_in_dialog(): Error retrieving %s contact\n",str1); return CSCF_RETURN_BREAK; } call_id = cscf_get_call_id(msg,0); if (!call_id.len) return CSCF_RETURN_FALSE; LOG(L_DBG,"DBG:"M_NAME":P_drop_dialog(%s): Call-ID <%.*s> %d://%.*s:%d\n", str1,call_id.len,call_id.s, transport,host.len,host.s,port); d = get_p_dialog(call_id,host,port,transport,&dir); if (!d) d = get_p_dialog(call_id,host,port,transport,0); if (!d){ LOG(L_INFO,"INFO:"M_NAME":P_drop_dialog: dialog does not exists!\n"); return CSCF_RETURN_FALSE; } hash = d->hash; del_p_dialog(d); d_unlock(hash); print_p_dialogs(L_INFO); return CSCF_RETURN_TRUE; }
int get_sip_header_info(struct sip_msg * req, struct sip_msg * reply, int interim, int32_t * acc_record_type, str * sip_method, str * event, uint32_t * expires, str * callid, str * from_uri, str * to_uri){ LOG(L_DBG, "retrieving sip info\n"); sip_method->s = req->first_line.u.request.method.s; sip_method->len = req->first_line.u.request.method.len; if(!interim && sip_method->len == 6 && strncmp(sip_method->s, "INVITE",6) == 0) *acc_record_type = AAA_ACCT_START; else if (sip_method->len == 3 && strncmp(sip_method->s, "BYE",3) == 0) *acc_record_type = AAA_ACCT_STOP; else if (sip_method->len == 7 && strncmp(sip_method->s, "MESSAGE", 7) == 0) *acc_record_type = AAA_ACCT_EVENT; else if(interim && sip_method->len == 6 && (strncmp(sip_method->s, "INVITE", 6) == 0 || strncmp(sip_method->s, "UPDATE", 6) ==0)) *acc_record_type = AAA_ACCT_INTERIM; 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(!cscf_get_from_uri(req, from_uri)) goto error; if(!cscf_get_to_uri(req, to_uri)) goto error; LOG(L_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, from_uri->len, from_uri->s, to_uri->len, to_uri->s); return 1; error: return 0; }
/* * delete the user data of the current user if exists(the URI is the R-URI of the current OPTIONS msg) * @param msg: current OPTIONS request * @param str1: not used * @param str2: not used */ int LRF_del_user_data(struct sip_msg* msg, char*str1, char*str2){ str user_uri; user_d * d; unsigned int hash; str service; if (msg->first_line.u.request.method.len!=7|| memcmp(msg->first_line.u.request.method.s,"OPTIONS",7)!=0){ LOG(L_WARN,"WARN:"M_NAME":LRF_del_user_data: The method is not an OPTIONS, trying to replace the message\n"); msg = cscf_get_request_from_reply(NULL); if(! msg || msg->first_line.type!=SIP_REQUEST || msg->first_line.u.request.method.len!=7|| memcmp(msg->first_line.u.request.method.s,"OPTIONS",7)!=0){ LOG(L_ERR,"BUG:"M_NAME":LRF_del_user_data: The new message is not an OPTIONS request either\n"); return CSCF_RETURN_ERROR; } } service = cscf_get_headers_content(msg , service_hdr_name); if(!service.len || !service.s){ LOG(L_ERR, "ERR:"M_NAME":LRF_del_user_data: could not find the service header in the OPTIONS, or could not be parsed\n"); return CSCF_RETURN_FALSE; } str callid = cscf_get_call_id(msg, NULL); if(!callid.s || !callid.len){ LOG(L_ERR, "ERR:"M_NAME":LRF_get_psap: could not find the callid header in the OPTIONS request\n"); return CSCF_RETURN_FALSE; } user_uri = msg->first_line.u.request.uri; d = get_user_data(user_uri, service, callid); if(!d) return CSCF_RETURN_FALSE; if(d->loc_subscr) del_loc_subscription((loc_subscription*)d->loc_subscr); hash = d->hash; del_user_data(d); lrf_unlock(hash); return CSCF_RETURN_TRUE; }
/** * Releases a call from the on reply route block * called with any reply to an INVITE * useful in cases of rejecting a call when you are processing the SDP * or handling QoS things * @msg - the sip message being processed * @str1 - the first parameter "orig" or "term" * @str2 - [optional] the Reason header that you want to go to the messages * @returns - TRUE on success or FALSE on misscall and BREAK on error */ int P_release_call_onreply(struct sip_msg *msg,char *str1,char *str2) { enum p_dialog_direction dir; p_dialog *d=NULL; str callid; struct hdr_field *h1; str reason={NULL,0}; if (str2) { reason.s=str2; reason.len=strlen(str2); } else reason = _488_text_s; dir= (str1[0]=='o' || str1[0]=='O' || str1[0]=='0')? DLG_MOBILE_ORIGINATING : DLG_MOBILE_TERMINATING; if (msg->first_line.type== SIP_REQUEST) { LOG(L_ERR,"ERR: P_release_call_on_reply called with a request\n"); return CSCF_RETURN_FALSE; } callid=cscf_get_call_id(msg,&h1); if (is_p_dialog_dir(callid,dir)) { d=get_p_dialog_dir(callid,dir); if (msg->first_line.u.reply.statuscode > 199) { release_call_previous(d,RELEASE_CALL_WEIRD,488,reason); d_unlock(d->hash); return CSCF_RETURN_TRUE; } else { release_call_previous(d,RELEASE_CALL_EARLY,488,reason); d_unlock(d->hash); return CSCF_RETURN_TRUE; } } else { LOG(L_ERR,"ERR:"M_NAME "P_release_call_onreply : unable to find dialog\n"); return CSCF_RETURN_BREAK; } }
/** * Drops and deletes a dialog. * @param msg - the request/response * @param str1 - direction - "orig" or "term" * @param str2 - not used * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error */ int LRF_drop_dialog(struct sip_msg* msg, char* str1, char* str2) { str call_id; lrf_dialog *d; int hash; struct sip_msg *req; enum lrf_dialog_direction dir; str target_uri = {0,0}; dir = get_dialog_direction(str1); if (msg->first_line.type==SIP_REPLY) req = cscf_get_request_from_reply(msg); else req = msg; if (!find_dialog_contact(req,dir,&target_uri)){ LOG(L_ERR,"ERR:"M_NAME":LRF_is_in_dialog(): Error retrieving %s contact\n",str1); return CSCF_RETURN_BREAK; } call_id = cscf_get_call_id(msg,0); if (!call_id.len) return CSCF_RETURN_FALSE; LOG(L_DBG,"DBG:"M_NAME":LRF_drop_dialog(%s): Call-ID <%.*s>: target <%.*s>\n", str1,call_id.len,call_id.s, target_uri.len, target_uri.s); d = get_lrf_dialog(call_id, &dir); if (!d) d = get_lrf_dialog(call_id, NULL); if (!d){ LOG(L_INFO,"INFO:"M_NAME":LRF_drop_dialog: dialog does not exists!\n"); return CSCF_RETURN_FALSE; } hash = d->hash; del_lrf_dialog(d); d_unlock(hash); print_lrf_dialogs(L_INFO); return CSCF_RETURN_TRUE; }
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; }
/** * Find out if a message is within a saved dialog. * @param msg - the SIP message * @param str1 - the direction of the dialog ("orig"/"term") * @param str2 - not used * @returns #CSCF_RETURN_TRUE if in, #CSCF_RETURN_FALSE else or #CSCF_RETURN_BREAK on error */ int S_is_in_dialog(struct sip_msg* msg, char* str1, char* str2) { str call_id; enum s_dialog_direction dir = get_dialog_direction(str1); enum s_dialog_direction dirmsg = find_dialog_route_dir(msg); // LOG(L_CRIT,"%d - %d\n",dir,dirmsg); if (dir!=dirmsg) return CSCF_RETURN_FALSE; // print_s_dialogs(L_ERR); call_id = cscf_get_call_id(msg,0); if (!call_id.len){ return CSCF_RETURN_FALSE; } if (is_s_dialog_dir(call_id,dir)) return CSCF_RETURN_TRUE; else return CSCF_RETURN_FALSE; }
/** * Find out if a message is within a saved dialog. * @param msg - the SIP message * @param str1 - the direction of the dialog ("orig"/"term") * @param str2 - not used * @returns #CSCF_RETURN_TRUE if in, #CSCF_RETURN_FALSE else or #CSCF_RETURN_BREAK on error */ int LRF_is_in_dialog(struct sip_msg* msg, char* str1, char* str2) { str call_id; enum lrf_dialog_direction dir; dir = get_dialog_direction(str1); str target_uri={0,0}; if (!find_dialog_contact(msg,dir,&target_uri)){ LOG(L_ERR,"ERR:"M_NAME":LRF_is_in_dialog(%s): Error retrieving %s contact\n",str1,str1); return CSCF_RETURN_BREAK; } //print_lrf_dialog(L_ERR); call_id = cscf_get_call_id(msg,0); if (!call_id.len) return CSCF_RETURN_FALSE; if (is_lrf_dialog(call_id, 0)) { return CSCF_RETURN_TRUE; } else return CSCF_RETURN_FALSE; }
/* Send the OPTIONS response to the E-CSCF * could be used after a LOCSIP NOTIFY is received * @param msg - the OPTIONS request from the ECSCF * @param str1 - not used * @param str2 - not used * @return CSCF_RETURN_TRUE if ok, or CSCF_RETURN_FALSE if error */ int LRF_call_query_resp(struct sip_msg* msg, char*str1, char*str2){ str user_uri; user_d * d= NULL; str service; struct cell * trans = NULL; str resp_body = {0,0}; str headers = {0,0}; unsigned int hash_index, label; LOG(L_INFO, "INFO:"M_NAME":LRF_call_query_resp\n"); if (msg->first_line.u.request.method.len!=7|| memcmp(msg->first_line.u.request.method.s,"OPTIONS",7)!=0){ LOG(L_WARN,"WARN:"M_NAME":LRF_call_query_resp: The method is not an OPTIONS, trying to replace the message\n"); msg = cscf_get_request_from_reply(NULL); if(! msg || msg->first_line.type!=SIP_REQUEST || msg->first_line.u.request.method.len!=7|| memcmp(msg->first_line.u.request.method.s,"OPTIONS",7)!=0){ LOG(L_ERR,"BUG:"M_NAME":LRF_call_query_resp: The new message is not an OPTIONS request either\n"); return CSCF_RETURN_ERROR; } } service = cscf_get_headers_content(msg, service_hdr_name); if(!service.len || !service.s){ LOG(L_ERR, "ERR:"M_NAME":LRF_call_query_resp: could not find the service header in the OPTIONS, or could not be parsed\n"); return CSCF_RETURN_FALSE; } str callid = cscf_get_call_id(msg, NULL); if(!callid.s || !callid.len){ LOG(L_ERR, "ERR:"M_NAME":LRF_get_psap: could not find the callid header in the OPTIONS request\n"); return CSCF_RETURN_FALSE; } user_uri = msg->first_line.u.request.uri; d = get_user_data(user_uri, service, callid); if(!d) { LOG(L_ERR, "ERR:"M_NAME":LRF_call_query_resp: could not found user data for uri %.*s and service %.*s\n", user_uri.len, user_uri.s, service.len, service.s); goto error; } if(!d->psap_uri.len || !d->psap_uri.s){ LOG(L_ERR, "ERR: "M_NAME":LRF_call_query_resp: null psap uri\n"); goto error; } if(d->loc && d->locsip_loc){ LOG(L_DBG, "DBG: "M_NAME":LRF_call_query_resp: LRF has location information from the LOCSIP server\n"); if(get_options_resp_body(&resp_body, d)){ LOG(L_ERR, "ERR:"M_NAME":LRF_call_query_resp:could not get the OPTIONS response body\n"); goto error; } } if(get_options_resp_headers(&headers, d)){ LOG(L_ERR, "ERR:"M_NAME":LRF_call_query_resp:could not get the OPTIONS response headers\n"); goto error; } //get crt trans if(cscf_get_transaction(msg, &hash_index, &label)<0){ LOG(L_ERR, "ERR:"M_NAME":LRF_call_query_resp: could not get the trans from the message\n"); goto error; } if(tmb.t_lookup_ident(&trans, hash_index, label)!=1){ LOG(L_ERR, "ERR:"M_NAME":LRF_call_query_resp: could not get the trans from the hash and index\n"); goto error; } if(tmb.t_reply_with_body(trans, 200, "OK - PSAP found", resp_body.s, headers.s, "lrf" )!= 1){ LOG(L_ERR, "ERR:"M_NAME":LRF_call_query_resp: could not send the response\n"); goto error2; } #ifndef TM_DEL_UNREF LOG(L_ERR, "ERR:"M_NAME":LRF_call_query_resp: options ref count %i\n", trans->ref_count); #endif lrf_unlock(d->hash); if(resp_body.s) pkg_free(resp_body.s); if(headers.s) pkg_free(headers.s); return CSCF_RETURN_TRUE; error2: //tmb.t_unref_ident(trans->hash_index, trans->label); error: LOG(L_DBG, "DBG: "M_NAME":LRF_call_query_resp: error label\n"); if(d) lrf_unlock(d->hash); LOG(L_DBG, "DBG: "M_NAME":LRF_call_query_resp: error label\n"); //if(resp_body.s) pkg_free(resp_body.s); LOG(L_DBG, "DBG: "M_NAME":LRF_call_query_resp: error label\n"); //if(headers.s) pkg_free(headers.s); LOG(L_DBG, "DBG: "M_NAME":LRF_call_query_resp: error label\n"); return CSCF_RETURN_FALSE; }
/** * Saves a dialog. * @param msg - the initial request * @param str1 - direction - "orig" or "term" * @param str2 - not used * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error */ int S_save_dialog(struct sip_msg* msg, char* str1, char* str2) { str call_id; s_dialog *d; str aor; char buf1[256],buf2[256]; str uri,tag,ruri,x; time_t t_time; str ses_exp = {0,0}; str refresher = {0,0}; str event = {0,0}; struct hdr_field *h; unsigned int hash; enum s_dialog_direction dir = get_dialog_direction(str1); if (!find_dialog_aor(msg,dir,&aor)){ LOG(L_ERR,"ERR:"M_NAME":S_save_dialog(): Error retrieving %s contact\n",str1); return CSCF_RETURN_BREAK; } call_id = cscf_get_call_id(msg,0); if (!call_id.len) return CSCF_RETURN_FALSE; LOG(L_INFO,"DBG:"M_NAME":S_save_dialog(%s): Call-ID <%.*s>\n",str1,call_id.len,call_id.s); if (is_s_dialog(call_id,aor,dir)){ LOG(L_ERR,"ERR:"M_NAME":S_save_dialog: dialog already exists!\n"); return CSCF_RETURN_TRUE; } d = add_s_dialog(call_id,aor,dir); if (!d) return CSCF_RETURN_FALSE; d->method = get_dialog_method(msg->first_line.u.request.method); STR_SHM_DUP(d->method_str,msg->first_line.u.request.method,"shm"); d->first_cseq = cscf_get_cseq(msg,0); d->last_cseq = d->first_cseq; d->state = DLG_STATE_INITIAL; d->uac_supp_timer = supports_extension(msg, &str_ext_timer); ses_exp = cscf_get_session_expires_body(msg, &h); t_time = cscf_get_session_expires(ses_exp, &refresher); if (!t_time) { d->expires = d_act_time() + 60; d->lr_session_expires = 0; } else { d->expires = d_act_time() + t_time; d->lr_session_expires = t_time; if (refresher.len) STR_SHM_DUP(d->refresher, refresher, "DIALOG_REFRESHER"); } cscf_get_from_tag(msg,&tag); cscf_get_from_uri(msg,&x); uri.len = snprintf(buf1,256,"<%.*s>",x.len,x.s); uri.s = buf1; cscf_get_to_uri(msg,&x); ruri.len = snprintf(buf2,256,"<%.*s>",x.len,x.s); ruri.s = buf2; tmb.new_dlg_uac(&call_id, &tag, d->first_cseq,&uri, &ruri, &d->dialog_c); tmb.new_dlg_uas(msg,99,&d->dialog_s); event = cscf_get_event(msg); if (event.len){ STR_SHM_DUP(d->event,event,"shm"); } else d->event = event; d_unlock(d->hash); print_s_dialogs(L_INFO); return CSCF_RETURN_TRUE; out_of_memory: if (d){ hash = d->hash; del_s_dialog(d); d_unlock(hash); } return CSCF_RETURN_ERROR; }
/** * Updates a dialog. * If the initial request was: * - INVITE - refreshes the expiration or looks for the BYE and destroys the dialog * if found * - SUBSCRIBE - looks for the Subscription-state in NOTIFY, refreshes the expiration * and if terminated destroys the dialog * - When adding more dialogs, add the refreshal methods here or they will expire and will * be destroyed. Also add the termination to reduce the memory consumption and improve the * performance. * @param msg - the request/response * @param str1 - direction - "orig" or "term" * @param str2 - not used * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error */ int P_update_dialog(struct sip_msg* msg, char* str1, char* str2) { str call_id; p_dialog *d; int response; int cseq; struct hdr_field *h=0; struct sip_msg *req=0; str host; int port,transport; int expires; str totag; time_t t_time=0; str ses_exp = {0,0}; str refresher = {0,0}; enum p_dialog_direction dir; dir = get_dialog_direction(str1); if (msg->first_line.type==SIP_REPLY) req = cscf_get_request_from_reply(msg); else req = msg; if (!find_dialog_contact(req,dir,&host,&port,&transport)){ LOG(L_ERR,"ERR:"M_NAME":P_update_dialog(%s): Error retrieving %s contact\n",str1,str1); return CSCF_RETURN_BREAK; } call_id = cscf_get_call_id(msg,0); if (!call_id.len) return CSCF_RETURN_FALSE; LOG(L_DBG,"DBG:"M_NAME":P_update_dialog(%s): Call-ID <%.*s>\n",str1,call_id.len,call_id.s); d = get_p_dialog(call_id,host,port,transport,&dir); if (!d) d = get_p_dialog(call_id,host,port,transport,0); if (!d){ if (msg->first_line.type==SIP_REQUEST && msg->first_line.u.request.method.len == 3 && strncasecmp(msg->first_line.u.request.method.s,"ACK",3)){ /* to skip the ACK after a 4xx when the dialog was dropped already*/ return CSCF_RETURN_TRUE; }else{ LOG(L_CRIT,"ERR:"M_NAME":P_update_dialog: dialog does not exists!\n"); return CSCF_RETURN_FALSE; } } if (msg->first_line.type==SIP_REQUEST){ /* Request */ LOG(L_DBG,"DBG:"M_NAME":P_update_dialog(%s): Method <%.*s> \n",str1, msg->first_line.u.request.method.len,msg->first_line.u.request.method.s); cseq = cscf_get_cseq(msg,&h); if (cseq>d->last_cseq) d->last_cseq = cseq; if (get_dialog_method(msg->first_line.u.request.method) == DLG_METHOD_INVITE) { d->uac_supp_timer = supports_extension(msg, &str_ext_timer); ses_exp = cscf_get_session_expires_body(msg, &h); t_time = cscf_get_session_expires(ses_exp, &refresher); if (!t_time){ d->expires = d_act_time()+pcscf_dialogs_expiration_time; d->lr_session_expires = 0; } else { d->expires = d_act_time() + t_time; d->lr_session_expires = t_time; if (refresher.len) STR_SHM_DUP(d->refresher, refresher, "DIALOG_REFRESHER"); } } else if (d->method == DLG_METHOD_SUBSCRIBE && msg->first_line.u.request.method.len == 6 && strncasecmp(msg->first_line.u.request.method.s,"NOTIFY",6)==0) { // Subscription-State header is mandatory for NOTIFY. See RFC 3265, Section 7.2 expires = cscf_get_subscription_state(msg); if (expires >= 0) { d->expires = d_act_time()+expires; } else { d->expires = d_act_time()+pcscf_dialogs_expiration_time; } } else { expires = cscf_get_expires_hdr(msg); if (expires >= 0) { LOG(L_INFO,"DBG:"M_NAME":P_update_dialog(%.*s): Update expiration time to %d via Expire header 2\n",call_id.len,call_id.s,expires); d->expires = d_act_time()+expires; } else { LOG(L_INFO,"INF:"M_NAME": update_dialog(%.*s): d->expires+=pcscf_dialogs_expiration_time 4\n",call_id.len,call_id.s); d->expires = d_act_time()+pcscf_dialogs_expiration_time; } d->lr_session_expires = 0; } }else{ /* Reply */ response = msg->first_line.u.reply.statuscode; LOG(L_DBG,"DBG:"M_NAME":P_update_dialog(%s): <%d> \n",str1,response); cseq = cscf_get_cseq(msg,&h); if (cseq==0 || h==0) return CSCF_RETURN_FALSE; if (d->first_cseq==cseq && d->method_str.len == ((struct cseq_body *)h->parsed)->method.len && strncasecmp(d->method_str.s,((struct cseq_body *)h->parsed)->method.s,d->method_str.len)==0 && d->state < DLG_STATE_CONFIRMED){ /* reply to initial request */ if (response<200 && response>100){ save_dialog_routes(msg,str1,d); d->state = DLG_STATE_EARLY; d->expires = d_act_time()+300; cscf_get_to_tag(msg,&totag); tmb.update_dlg_uas(d->dialog_s,response,&totag); tmb.dlg_response_uac(d->dialog_c,msg,IS_NOT_TARGET_REFRESH); }else if (response>=200 && response<300){ save_dialog_routes(msg,str1,d); d->state = DLG_STATE_CONFIRMED; update_dialog_on_reply(msg, d); cscf_get_to_tag(msg,&totag); tmb.update_dlg_uas(d->dialog_s,response,&totag); tmb.dlg_response_uac(d->dialog_c,msg,IS_NOT_TARGET_REFRESH); }else if (response>300){ d->state = DLG_STATE_TERMINATED; d_unlock(d->hash); return P_drop_dialog(msg,str1,str2); } }else{ /* reply to subsequent request */ if (!req) req = cscf_get_request_from_reply(msg); /* destroy dialogs on specific methods */ switch (d->method){ case DLG_METHOD_OTHER: expires = cscf_get_expires_hdr(msg); if (expires >= 0) { d->expires = d_act_time()+expires; } else { d->expires = d_act_time()+pcscf_dialogs_expiration_time; } d->lr_session_expires = 0; break; case DLG_METHOD_INVITE: if (req && req->first_line.u.request.method.len==3 && strncasecmp(req->first_line.u.request.method.s,"BYE",3)==0){ d->state = DLG_STATE_TERMINATED; d_unlock(d->hash); return P_drop_dialog(msg,str1,str2); } update_dialog_on_reply(msg, d); break; case DLG_METHOD_SUBSCRIBE: // if (req && req->first_line.u.request.method.len==9 && // strncasecmp(req->first_line.u.request.method.s,"SUBSCRIBE",9)==0 && // cscf_get_expires_hdr(msg)==0){ // d->state = DLG_STATE_TERMINATED; // d_unlock(d->hash); // return P_drop_dialog(msg,str1,str2); // } if (req && req->first_line.u.request.method.len==6 && strncasecmp(req->first_line.u.request.method.s,"NOTIFY",6)==0){ expires = cscf_get_subscription_state(req); if (expires==0){ d->state = DLG_STATE_TERMINATED; d_unlock(d->hash); return P_drop_dialog(msg,str1,str2); }else if (expires>0){ d->expires = d_act_time() + expires; } } break; } if (cseq>d->last_cseq) d->last_cseq = cseq; } } d_unlock(d->hash); print_p_dialogs(L_INFO); return CSCF_RETURN_TRUE; out_of_memory: d_unlock(d->hash); return CSCF_RETURN_ERROR; }
/** * Updates a dialog. * If the initial request was: * - INVITE - refreshes the expiration or looks for the BYE and destroys the dialog * if found * - SUBSCRIBE - looks for the Subscription-state in NOTIFY, refreshes the expiration * and if terminated destroys the dialog * - When adding more dialogs, add the refreshal methods here or they will expire and will * be destroyed. Also add the termination to reduce the memory consumption and improve the * performance. * @param msg - the request/response * @param str1 - direction - "orig" or "term" * @param str2 - not used * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error */ int S_update_dialog(struct sip_msg* msg, char* str1, char* str2) { str call_id; s_dialog *d; int response; int cseq; struct hdr_field *h=0; struct sip_msg *req=0; int expires=0; str totag; time_t t_time; str ses_exp = {0,0}; str refresher = {0,0}; enum s_dialog_direction dir = get_dialog_direction(str1); // if (!find_dialog_aor(msg,str1,&aor)){ // req = cscf_get_request_from_reply(msg); // if (!find_dialog_aor(req,str1,&aor)){ // LOG(L_ERR,"ERR:"M_NAME":S_update_dialog(%s): Error retrieving %s contact\n",str1,str1); // return CSCF_RETURN_BREAK; // } // } call_id = cscf_get_call_id(msg,0); if (!call_id.len) return CSCF_RETURN_FALSE; LOG(L_DBG,"DBG:"M_NAME":S_update_dialog(%s): Call-ID <%.*s>\n",str1,call_id.len,call_id.s); d = get_s_dialog_dir(call_id,dir); // if (!d && msg->first_line.type==SIP_REPLY){ // /* Try to get the dialog from the request */ // if (!req) req = cscf_get_request_from_reply(msg); // if (!find_dialog_aor(req,str1,&aor)){ // LOG(L_ERR,"ERR:"M_NAME":S_update_dialog(%s): Error retrieving %s contact\n",str1,str1); // return CSCF_RETURN_BREAK; // } // d = get_s_dialog_dir(call_id,aor); // } if (!d){ LOG(L_INFO,"INFO:"M_NAME":S_update_dialog: dialog does not exists!\n"); return CSCF_RETURN_FALSE; } if (msg->first_line.type==SIP_REQUEST){ /* Request */ LOG(L_DBG,"DBG:"M_NAME":S_update_dialog(%s): Method <%.*s> \n",str1, msg->first_line.u.request.method.len,msg->first_line.u.request.method.s); cseq = cscf_get_cseq(msg,&h); if (cseq>d->last_cseq) d->last_cseq = cseq; if (get_dialog_method(msg->first_line.u.request.method) == DLG_METHOD_INVITE) { d->uac_supp_timer = supports_extension(msg, &str_ext_timer); ses_exp = cscf_get_session_expires_body(msg, &h); t_time = cscf_get_session_expires(ses_exp, &refresher); if (!t_time) { d->expires = d_act_time()+scscf_dialogs_expiration_time; d->lr_session_expires = 0; } else { d->expires = d_act_time() + t_time; d->lr_session_expires = t_time; if (refresher.len) STR_SHM_DUP(d->refresher, refresher, "DIALOG_REFRESHER"); } } else if (d->method == DLG_METHOD_SUBSCRIBE && msg->first_line.u.request.method.len == 6 && strncasecmp(msg->first_line.u.request.method.s,"NOTIFY",6)==0) { // Subscription-State header is mandatory for NOTIFY. See RFC 3265, Section 7.2 expires = cscf_get_subscription_state(msg); if (expires >= 0) d->expires = d_act_time()+expires; else d->expires = d_act_time()+scscf_dialogs_expiration_time; } else { expires = cscf_get_expires_hdr(msg,0); if (expires >= 0) d->expires = d_act_time()+expires; else d->expires = d_act_time()+scscf_dialogs_expiration_time; d->lr_session_expires = 0; } }else{ /* Reply */ response = msg->first_line.u.reply.statuscode; LOG(L_DBG,"DBG:"M_NAME":S_update_dialog(%s): <%d> \n",str1,response); cseq = cscf_get_cseq(msg,&h); if (cseq==0 || h==0) return CSCF_RETURN_FALSE; if (d->first_cseq==cseq && d->method_str.len == ((struct cseq_body *)h->parsed)->method.len && strncasecmp(d->method_str.s,((struct cseq_body *)h->parsed)->method.s,d->method_str.len)==0 && d->state < DLG_STATE_CONFIRMED){ /* reply to initial request */ if (response<200){ d->state = DLG_STATE_EARLY; d->expires = d_act_time()+300; }else if (response>=200 && response<300){ d->state = DLG_STATE_CONFIRMED; update_dialog_on_reply(msg, d); /*I save the dialogs only here because * i only want to release confirmed dialogs*/ cscf_get_to_tag(msg,&totag); if (d->dialog_s){ tmb.update_dlg_uas(d->dialog_s,response,&totag); tmb.dlg_response_uac(d->dialog_c,msg,IS_NOT_TARGET_REFRESH); }else{ LOG(L_ERR,"ERR:S_update_dialog(): dialog_s for dialog was NULL!\n"); } }else if (response>300){ d->state = DLG_STATE_TERMINATED; d_unlock(d->hash); struct cell * t = tmb.t_gett(); if(t->nr_of_outgoings < 2) return S_drop_dialog(msg,str1,str2); } }else{ /* reply to subsequent request */ if (!req) req = cscf_get_request_from_reply(msg); /* destroy dialogs on specific methods */ switch (d->method){ case DLG_METHOD_OTHER: d->expires = d_act_time()+scscf_dialogs_expiration_time; d->lr_session_expires = 0; break; case DLG_METHOD_INVITE: if (req && req->first_line.u.request.method.len==3 && strncasecmp(req->first_line.u.request.method.s,"BYE",3)==0){ d->state = DLG_STATE_TERMINATED; d_unlock(d->hash); return S_drop_dialog(msg,str1,str2); } update_dialog_on_reply(msg, d); break; case DLG_METHOD_SUBSCRIBE: // if (req && req->first_line.u.request.method.len==9 && // strncasecmp(req->first_line.u.request.method.s,"SUBSCRIBE",9)==0 && // cscf_get_expires_hdr(msg)==0){ // d->state = DLG_STATE_TERMINATED; // d_unlock(d->hash); // return P_dros_dialog(msg,str1,str2); // } if (req && req->first_line.u.request.method.len==6 && strncasecmp(req->first_line.u.request.method.s,"NOTIFY",6)==0){ expires = cscf_get_subscription_state(req); if (expires==0){ d->state = DLG_STATE_TERMINATED; d_unlock(d->hash); return S_drop_dialog(msg,str1,str2); }else if (expires>0){ d->expires = d_act_time() + expires; } } else if (req && req->first_line.u.request.method.len==9 && strncasecmp(req->first_line.u.request.method.s,"SUBSCRIBE",9)==0){ expires = cscf_get_expires_hdr(msg,0); if (expires >= 0) d->expires = d_act_time()+expires; else d->expires = d_act_time()+scscf_dialogs_expiration_time; } break; } if (cseq>d->last_cseq) d->last_cseq = cseq; } } d_unlock(d->hash); print_s_dialogs(L_INFO); return CSCF_RETURN_TRUE; out_of_memory: if (d) d_unlock(d->hash); return CSCF_RETURN_ERROR; }
/** * Checks if the message follows the saved dialog routes. * @param msg - the SIP request * @param str1 - direction - "orig" or "term" * @param str2 - not used * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error */ int P_follows_dialog_routes(struct sip_msg *msg,char *str1,char *str2) { int i; struct hdr_field *hdr=0; rr_t *r; p_dialog *d; str call_id,host; int port,transport; enum p_dialog_direction dir; dir = get_dialog_direction(str1); if (!find_dialog_contact(msg,dir,&host,&port,&transport)){ LOG(L_ERR,"ERR:"M_NAME":P_follows_dialog_routes(): Error retrieving %s contact\n",str1); return CSCF_RETURN_BREAK; } call_id = cscf_get_call_id(msg,0); if (!call_id.len) return CSCF_RETURN_FALSE; LOG(L_DBG,"DBG:"M_NAME":P_follows_dialog_routes(%s): Call-ID <%.*s> %d://%.*s:%d\n", str1,call_id.len,call_id.s, transport,host.len,host.s,port); d = get_p_dialog(call_id,host,port,transport,&dir); if (!d) d = get_p_dialog(call_id,host,port,transport,0); if (!d){ LOG(L_ERR,"ERR:"M_NAME":P_follows_dialog_routes: dialog does not exists!\n"); return CSCF_RETURN_FALSE; } /* todo - fix this to match exactly the first request */ if (d->first_cseq == cscf_get_cseq(msg,0) && d->method == get_dialog_method(msg->first_line.u.request.method)){ LOG(L_INFO,"INF:"M_NAME":P_follows_dialog_routes: this looks like the initial request (retransmission?)!\n"); goto ok; } hdr = cscf_get_next_route(msg,0); r = 0; if (!hdr){ if (d->routes_cnt==0) goto ok; else goto nok; } r = (rr_t*) hdr->parsed; for(i=0;i<d->routes_cnt;i++){ LOG(L_DBG,"DBG:"M_NAME":P_follows_dialog_routes: must <%.*s>\n", d->routes[i].len,d->routes[i].s); if (!r) { hdr = cscf_get_next_route(msg,hdr); if (!hdr) goto nok; r = (rr_t*) hdr->parsed; } LOG(L_DBG,"DBG:"M_NAME":P_follows_dialog_routes: src %.*s\n", r->nameaddr.uri.len,r->nameaddr.uri.s); if (r->nameaddr.uri.len==d->routes[i].len && strncasecmp(r->nameaddr.uri.s, d->routes[i].s,d->routes[i].len)==0) { LOG(L_DBG,"DBG:"M_NAME":P_follows_dialog_routes: src match\n"); } else { LOG(L_DBG,"DBG:"M_NAME":P_follows_dialog_routes: found <%.*s>\n", r->nameaddr.uri.len,r->nameaddr.uri.s); goto nok; } r = r->next; } if (r) { LOG(L_DBG,"DBG:"M_NAME":P_follows_dialog_routes: still has some extra Routes\n"); goto nok; } else if (cscf_get_next_route(msg,hdr)) goto nok; ok: if (d) d_unlock(d->hash); return CSCF_RETURN_TRUE; nok: if (d) d_unlock(d->hash); return CSCF_RETURN_FALSE; }
int I_scscf_select(struct sip_msg* msg, char* str1, char* str2) { str call_id,scscf_name={0,0}; struct sip_msg *req; int result; str hdr={0,0}; //print_scscf_list(L_ERR); call_id = cscf_get_call_id(msg,0); LOG(L_DBG,"DBG:"M_NAME":I_scscf_select(): <%.*s>\n",call_id.len,call_id.s); if (!call_id.len) return CSCF_RETURN_FALSE; scscf_name = take_scscf_entry(call_id); if (!scscf_name.len){ I_scscf_drop(msg,str1,str2); cscf_reply_transactional(msg,600,MSG_600_FORWARDING_FAILED); return CSCF_RETURN_BREAK; } if (msg->first_line.u.request.method.len==8 && strncasecmp(msg->first_line.u.request.method.s,"REGISTER",8)==0) { /* REGISTER fwding */ if (str1&&str1[0]=='0'){ /* first time */ //LOG(L_CRIT,"rewrite uri\n"); if (rewrite_uri(msg, &(scscf_name)) < 0) { LOG(L_ERR,"ERR:"M_NAME":I_UAR_forward: Unable to Rewrite URI\n"); result = CSCF_RETURN_FALSE; }else result = CSCF_RETURN_TRUE; }else{ /* subsequent */ //LOG(L_CRIT,"append branch\n"); req = msg;//cscf_get_request_from_reply(msg); append_branch(req,scscf_name.s,scscf_name.len,0,0,0,0); result = CSCF_RETURN_TRUE; } }else{ /* Another request */ result = CSCF_RETURN_TRUE; hdr.len = route_hdr_s.len+scscf_name.len+route_hdr_e.len; hdr.s = pkg_malloc(hdr.len); if (!hdr.s){ LOG(L_ERR,"ERR:"M_NAME":Mw_REQUEST_forward: Error allocating %d bytes\n", hdr.len); result = CSCF_RETURN_TRUE; } hdr.len=0; STR_APPEND(hdr,route_hdr_s); STR_APPEND(hdr,scscf_name); STR_APPEND(hdr,route_hdr_e); if (!cscf_add_header_first(msg,&hdr,HDR_ROUTE_T)){ pkg_free(hdr.s); result = CSCF_RETURN_TRUE; } if (msg->dst_uri.s) pkg_free(msg->dst_uri.s); STR_PKG_DUP(msg->dst_uri,scscf_name,"pkg"); } if (scscf_name.s) shm_free(scscf_name.s); return result; out_of_memory: if (scscf_name.s) shm_free(scscf_name.s); return CSCF_RETURN_ERROR; }
/* Wrapper to send AAR from config file - this only allows for AAR for calls - not register, which uses r_rx_aar_register * return: 1 - success, <=0 failure. 2 - message not a AAR generating message (ie proceed without PCC if you wish) */ static int w_rx_aar(struct sip_msg *msg, char *route, char* str1, char* bar) { int ret = CSCF_RETURN_ERROR; struct cell *t; AAASession* auth_session; rx_authsessiondata_t* rx_authdata_p = 0; str *rx_session_id; str callid = {0, 0}; str ftag = {0, 0}; str ttag = {0, 0}; str route_name; cfg_action_t* cfg_action = 0; saved_transaction_t* saved_t_data = 0; //data specific to each contact's AAR async call char* direction = str1; 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("Rx AAR called\n"); //create the default return code AVP create_return_code(ret); //We don't ever do AAR on request for calling scenario... if (msg->first_line.type != SIP_REPLY) { LM_DBG("Can't do AAR for call session in request\n"); return CSCF_RETURN_ERROR; } //is it appropriate to send AAR at this stage? t = tmb.t_gett(); if (t == NULL || t == T_UNDEFINED) { LM_WARN("Cannot get transaction for AAR based on SIP Request\n"); //goto aarna; return CSCF_RETURN_ERROR; } //we dont apply QoS if its not a reply to an INVITE! or UPDATE or PRACK! if ((t->method.len == 5 && memcmp(t->method.s, "PRACK", 5) == 0) || (t->method.len == 6 && (memcmp(t->method.s, "INVITE", 6) == 0 || memcmp(t->method.s, "UPDATE", 6) == 0))) { if (cscf_get_content_length(msg) == 0 || cscf_get_content_length(t->uas.request) == 0) { LM_DBG("No SDP offer answer -> therefore we can not do Rx AAR"); //goto aarna; //AAR na if we dont have offer/answer pair return CSCF_RETURN_ERROR; } } else { LM_DBG("Message is not response to INVITE, PRACK or UPDATE -> therefore we do not Rx AAR"); return CSCF_RETURN_ERROR; } /* get callid, from and to tags to be able to identify dialog */ callid = cscf_get_call_id(msg, 0); if (callid.len <= 0 || !callid.s) { LM_ERR("unable to get callid\n"); return CSCF_RETURN_ERROR; } if (!cscf_get_from_tag(msg, &ftag)) { LM_ERR("Unable to get ftag\n"); return CSCF_RETURN_ERROR; } if (!cscf_get_to_tag(msg, &ttag)) { LM_ERR("Unable to get ttag\n"); return CSCF_RETURN_ERROR; } //check to see that this is not a result of a retransmission in reply route only if (msg->cseq == NULL && ((parse_headers(msg, HDR_CSEQ_F, 0) == -1) || (msg->cseq == NULL))) { LM_ERR("No Cseq header found - aborting\n"); return CSCF_RETURN_ERROR; } saved_t_data = (saved_transaction_t*) shm_malloc(sizeof (saved_transaction_t)); if (!saved_t_data) { LM_ERR("Unable to allocate memory for transaction data, trying to send AAR\n"); return CSCF_RETURN_ERROR; } memset(saved_t_data, 0, sizeof (saved_transaction_t)); saved_t_data->act = cfg_action; //OTHER parms need after async response set here //store call id saved_t_data->callid.s = (char*) shm_malloc(callid.len + 1); if (!saved_t_data->callid.s) { LM_ERR("no more memory trying to save transaction state : callid\n"); shm_free(saved_t_data); return CSCF_RETURN_ERROR; } memset(saved_t_data->callid.s, 0, callid.len + 1); memcpy(saved_t_data->callid.s, callid.s, callid.len); saved_t_data->callid.len = callid.len; //store ttag saved_t_data->ttag.s = (char*) shm_malloc(ttag.len + 1); if (!saved_t_data->ttag.s) { LM_ERR("no more memory trying to save transaction state : ttag\n"); shm_free(saved_t_data); return CSCF_RETURN_ERROR; } memset(saved_t_data->ttag.s, 0, ttag.len + 1); memcpy(saved_t_data->ttag.s, ttag.s, ttag.len); saved_t_data->ttag.len = ttag.len; //store ftag saved_t_data->ftag.s = (char*) shm_malloc(ftag.len + 1); if (!saved_t_data->ftag.s) { LM_ERR("no more memory trying to save transaction state : ftag\n"); shm_free(saved_t_data); return CSCF_RETURN_ERROR; } memset(saved_t_data->ftag.s, 0, ftag.len + 1); memcpy(saved_t_data->ftag.s, ftag.s, ftag.len); saved_t_data->ftag.len = ftag.len; //store branch int branch; if (tmb.t_check( msg , &branch )==-1){ LOG(L_ERR, "ERROR: t_suspend: failed find UAC branch\n"); return CSCF_RETURN_ERROR; } //Check that we dont already have an auth session for this specific dialog //if not we create a new one and attach it to the dialog (via session ID). enum dialog_direction dlg_direction = get_dialog_direction(direction); if (dlg_direction == DLG_MOBILE_ORIGINATING) { rx_session_id = dlgb.get_dlg_var(&callid, &ftag, &ttag, &orig_session_key); } else { rx_session_id = dlgb.get_dlg_var(&callid, &ftag, &ttag, &term_session_key); } if (!rx_session_id || rx_session_id->len <= 0 || !rx_session_id->s) { LM_DBG("New AAR session for this dialog in mode %s\n", direction); //create new diameter auth session int ret = create_new_callsessiondata(&callid, &ftag, &ttag, &rx_authdata_p); if (!ret) { LM_DBG("Unable to create new media session data parcel\n"); goto error; } auth_session = cdpb.AAACreateClientAuthSession(1, callback_for_cdp_session, rx_authdata_p); //returns with a lock if (!auth_session) { LM_ERR("Rx: unable to create new Rx Media Session\n"); if (auth_session) cdpb.AAASessionsUnlock(auth_session->hash); if (rx_authdata_p) { shm_free(rx_authdata_p); rx_authdata_p = 0; } goto error; } //attach new cdp auth session to dlg for this direction if (dlg_direction == DLG_MOBILE_ORIGINATING) { dlgb.set_dlg_var(&callid, &ftag, &ttag, &orig_session_key, &auth_session->id); } else { dlgb.set_dlg_var(&callid, &ftag, &ttag, &term_session_key, &auth_session->id); } LM_DBG("Attached CDP auth session [%.*s] for Rx to dialog in %s mode\n", auth_session->id.len, auth_session->id.s, direction); } else { LM_DBG("Update AAR session for this dialog in mode %s\n", direction); if (saved_t_data) free_saved_transaction_global_data(saved_t_data); //only free global data if no AARs were sent. if one was sent we have to rely on the callback (CDP) to free create_return_code(CSCF_RETURN_TRUE); return CSCF_RETURN_TRUE; } LM_DBG("Suspending SIP TM transaction\n"); if (tmb.t_suspend(msg, &saved_t_data->tindex, &saved_t_data->tlabel) < 0) { LM_ERR("failed to suspend the TM processing\n"); free_saved_transaction_global_data(saved_t_data); return CSCF_RETURN_ERROR; } LM_DBG("Sending Rx AAR"); ret = rx_send_aar(t->uas.request, msg, auth_session, direction, saved_t_data); if (!ret) { LM_ERR("Failed to send AAR\n"); tmb.t_cancel_suspend(saved_t_data->tindex, saved_t_data->tlabel); goto error; } else { LM_DBG("Successful async send of AAR\n"); return CSCF_RETURN_BREAK; //on success we break - because rest of cfg file will be executed by async process } error: LM_ERR("Error trying to send AAR (calling)\n"); if (saved_t_data) free_saved_transaction_global_data(saved_t_data); //only free global data if no AARs were sent. if one was sent we have to rely on the callback (CDP) to free //otherwise the callback will segfault return CSCF_RETURN_ERROR; }
/** * Perform User Authorization Request. * creates and send the user authorization query * @param msg - the SIP message * @param str1 - the realm * @param str2 - if to do capabilities * @returns true if OK, false if not */ int I_perform_user_authorization_request(struct sip_msg* msg, char* str1, char* str2) { str private_identity, public_identity, visited_network_id; int authorization_type = AVP_IMS_UAR_REGISTRATION; int expires = 3600; struct hdr_field *hdr; str realm; contact_t *c; int sos_reg = 0; contact_body_t *b = 0; str call_id; saved_uar_transaction_t* saved_t; tm_cell_t *t = 0; int intvalue_param; cfg_action_t* cfg_action; uar_param_t* ap = (uar_param_t*) str1; if (fixup_get_ivalue(msg, ap->ivalue, &intvalue_param) != 0) { LM_ERR("no int value param passed\n"); return CSCF_RETURN_ERROR; } cfg_action = ap->paction->next; realm = cscf_get_realm_from_ruri(msg); //check if we received what we should, we do this even though it should be done in cfg file - double checking! if (msg->first_line.type != SIP_REQUEST) { LM_ERR("ERR:I_UAR: The message is not a request\n"); return CSCF_RETURN_ERROR; } if (msg->first_line.u.request.method.len != 8 || memcmp(msg->first_line.u.request.method.s, "REGISTER", 8) != 0) { LM_ERR("ERR:I_UAR: The method is not a REGISTER\n"); return CSCF_RETURN_ERROR; } private_identity = cscf_get_private_identity(msg, realm); if (!private_identity.len) { LM_ERR("ERR:I_UAR: Private Identity not found, responding with 400\n"); cscf_reply_transactional(msg, 400, MSG_400_NO_PRIVATE); return CSCF_RETURN_BREAK; } public_identity = cscf_get_public_identity(msg); if (!public_identity.len) { LM_ERR("ERR:I_UAR: Public Identity not found, responding with 400\n"); cscf_reply_transactional(msg, 400, MSG_400_NO_PUBLIC); return CSCF_RETURN_BREAK; } b = cscf_parse_contacts(msg); if (!b || (!b->contacts && !b->star)) { LM_DBG("DBG:I_UAR: No contacts found\n"); return CSCF_RETURN_ERROR; } for (c = b->contacts; c; c = c->next) { sos_reg = cscf_get_sos_uri_param(c->uri); if (sos_reg == -1) { //error case LM_ERR("ERR:I_UAR: MSG_400_MALFORMED_CONTACT, responding with 400\n"); cscf_reply_transactional(msg, 400, MSG_400_MALFORMED_CONTACT); return CSCF_RETURN_BREAK; } else if (sos_reg == -2) { LM_ERR("ERR:I_UAR: MSG_500_SERVER_ERROR_OUT_OF_MEMORY, responding with 500\n"); cscf_reply_transactional(msg, 500, MSG_500_SERVER_ERROR_OUT_OF_MEMORY); return CSCF_RETURN_BREAK; } } visited_network_id = cscf_get_visited_network_id(msg, &hdr); if (!visited_network_id.len) { LM_ERR("ERR:I_UAR: Visited Network Identity not found, responding with 400\n"); cscf_reply_transactional(msg, 400, MSG_400_NO_VISITED); return CSCF_RETURN_BREAK; } if (atoi(str1)) authorization_type = AVP_IMS_UAR_REGISTRATION_AND_CAPABILITIES; else { expires = cscf_get_max_expires(msg, 0); if (expires == 0) authorization_type = AVP_IMS_UAR_DE_REGISTRATION; } LM_DBG("SENDING UAR: PI: [%.*s], PU: [%.*s], VNID: [%.*s]\n", private_identity.len, private_identity.s, public_identity.len, public_identity.s, visited_network_id.len, visited_network_id.s); //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_uar_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_uar_transaction_t)); saved_t->act = cfg_action; call_id = cscf_get_call_id(msg, 0); saved_t->callid.s = (char*) shm_malloc(call_id.len + 1); if (!saved_t->callid.s) { LM_ERR("no more memory trying to save transaction state : callid\n"); shm_free(saved_t); return CSCF_RETURN_ERROR; } memset(saved_t->callid.s, 0, call_id.len + 1); memcpy(saved_t->callid.s, call_id.s, call_id.len); saved_t->callid.len = call_id.len; LM_DBG("Setting default AVP return code used for async callbacks to default as ERROR \n"); create_uaa_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_uar_transaction_data(saved_t); cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR); return CSCF_RETURN_BREAK; } if (cxdx_send_uar(msg, private_identity, public_identity, visited_network_id, authorization_type, sos_reg, saved_t) != 0) { LM_ERR("ERR:I_UAR: Error sending UAR or UAR time-out\n"); tmb.t_cancel_suspend(saved_t->tindex, saved_t->tlabel); free_saved_uar_transaction_data(saved_t); cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR); return CSCF_RETURN_BREAK; } //we use async replies therefore we send break and not true when successful return CSCF_RETURN_BREAK; }
/** * Updates a dialog. * If the initial request was: * - INVITE - refreshes the expiration or looks for the BYE and destroys the dialog * if found * - SUBSCRIBE - looks for the Subscription-state in NOTIFY, refreshes the expiration * and if terminated destroys the dialog * - When adding more dialogs, add the refreshal methods here or they will expire and will * be destroyed. Also add the termination to reduce the memory consumption and improve the * performance. * @param msg - the request/response * @param str1 - direction - "orig" or "term" * @param str2 - not used * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error */ int S_update_dialog(struct sip_msg* msg, char* str1, char* str2) { str call_id; s_dialog *d; int response; int cseq; struct hdr_field *h=0; struct sip_msg *req=0; int expires=0; str totag; enum s_dialog_direction dir = get_dialog_direction(str1); // if (!find_dialog_aor(msg,str1,&aor)){ // req = cscf_get_request_from_reply(msg); // if (!find_dialog_aor(req,str1,&aor)){ // LOG(L_ERR,"ERR:"M_NAME":S_update_dialog(%s): Error retrieving %s contact\n",str1,str1); // return CSCF_RETURN_BREAK; // } // } call_id = cscf_get_call_id(msg,0); if (!call_id.len) return CSCF_RETURN_FALSE; LOG(L_INFO,"DBG:"M_NAME":S_update_dialog(%s): Call-ID <%.*s>\n",str1,call_id.len,call_id.s); d = get_s_dialog_dir(call_id,dir); // if (!d && msg->first_line.type==SIP_REPLY){ // /* Try to get the dialog from the request */ // if (!req) req = cscf_get_request_from_reply(msg); // if (!find_dialog_aor(req,str1,&aor)){ // LOG(L_ERR,"ERR:"M_NAME":S_update_dialog(%s): Error retrieving %s contact\n",str1,str1); // return CSCF_RETURN_BREAK; // } // d = get_s_dialog_dir(call_id,aor); // } if (!d){ LOG(L_INFO,"INFO:"M_NAME":S_update_dialog: dialog does not exists!\n"); return CSCF_RETURN_FALSE; } if (msg->first_line.type==SIP_REQUEST){ /* Request */ LOG(L_DBG,"DBG:"M_NAME":S_update_dialog(%s): Method <%.*s> \n",str1, msg->first_line.u.request.method.len,msg->first_line.u.request.method.s); cseq = cscf_get_cseq(msg,&h); if (cseq>d->last_cseq) d->last_cseq = cseq; d->expires = d_act_time()+scscf_dialogs_expiration_time; }else{ /* Reply */ response = msg->first_line.u.reply.statuscode; LOG(L_DBG,"DBG:"M_NAME":S_update_dialog(%s): <%d> \n",str1,response); cseq = cscf_get_cseq(msg,&h); if (cseq==0 || h==0) return CSCF_RETURN_FALSE; if (d->first_cseq==cseq && d->method_str.len == ((struct cseq_body *)h->parsed)->method.len && strncasecmp(d->method_str.s,((struct cseq_body *)h->parsed)->method.s,d->method_str.len)==0 && d->state < DLG_STATE_CONFIRMED){ /* reply to initial request */ if (response<200){ d->state = DLG_STATE_EARLY; d->expires = d_act_time()+300; }else if (response>=200 && response<300){ d->state = DLG_STATE_CONFIRMED; d->expires = d_act_time()+scscf_dialogs_expiration_time; /*I save the dialogs only here because * i only want to release confirmed dialogs*/ cscf_get_to_tag(msg,&totag); tmb.update_dlg_uas(d->dialog_s,response,&totag); tmb.dlg_response_uac(d->dialog_c,msg,IS_NOT_TARGET_REFRESH); }else if (response>300){ d->state = DLG_STATE_TERMINATED; d_unlock(d->hash); return S_drop_dialog(msg,str1,str2); } }else{ /* reply to subsequent request */ if (!req) req = cscf_get_request_from_reply(msg); /* destroy dialogs on specific methods */ switch (d->method){ case DLG_METHOD_OTHER: d->expires = d_act_time()+scscf_dialogs_expiration_time; break; case DLG_METHOD_INVITE: if (req && req->first_line.u.request.method.len==3 && strncasecmp(req->first_line.u.request.method.s,"BYE",3)==0){ d->state = DLG_STATE_TERMINATED; d_unlock(d->hash); return S_drop_dialog(msg,str1,str2); } d->expires = d_act_time()+scscf_dialogs_expiration_time; break; case DLG_METHOD_SUBSCRIBE: // if (req && req->first_line.u.request.method.len==9 && // strncasecmp(req->first_line.u.request.method.s,"SUBSCRIBE",9)==0 && // cscf_get_expires_hdr(msg)==0){ // d->state = DLG_STATE_TERMINATED; // d_unlock(d->hash); // return P_dros_dialog(msg,str1,str2); // } if (req && req->first_line.u.request.method.len==6 && strncasecmp(req->first_line.u.request.method.s,"NOTIFY",6)==0){ expires = cscf_get_subscription_state(req); if (expires==0){ d->state = DLG_STATE_TERMINATED; d_unlock(d->hash); return S_drop_dialog(msg,str1,str2); }else if (expires>0){ d->expires = expires; } } break; } if (cseq>d->last_cseq) d->last_cseq = cseq; } } d_unlock(d->hash); // print_s_dialogs(L_INFO); return CSCF_RETURN_TRUE; }
/** * Releases a call from the on reply route block * called with any reply to an INVITE * useful in cases of rejecting a call when you are processing the SDP * or handling QoS things * @msg - the sip message being processed * @str1 - the first parameter "orig" or "term" * @str2 - [optional] the Reason header that you want to go to the messages * @returns - BREAK ... whatever happens this message is not relayed */ int P_release_call_onreply(struct sip_msg *msg,char *str1,char *str2) { enum p_dialog_direction dir; p_dialog *d=NULL; str callid; struct hdr_field *h1; str reason= {NULL,0}; unsigned int hash; struct cell* t; /*needed to distinguish between UPDATE and INVITE*/ LOG(L_INFO,ANSI_WHITE"P_release_call_on_reply\n"); if (str2) { reason.s=str2; reason.len=strlen(str2); } else reason = _488_text_s; dir= (str1[0]=='o' || str1[0]=='O' || str1[0]=='0')? DLG_MOBILE_ORIGINATING : DLG_MOBILE_TERMINATING; if (msg->first_line.type== SIP_REQUEST) { LOG(L_ERR,"ERR: P_release_call_on_reply called with a request\n"); return CSCF_RETURN_FALSE; } callid=cscf_get_call_id(msg,&h1); if (is_p_dialog_dir(callid,dir)) { d=get_p_dialog_dir(callid,dir); hash=d->hash; t=tmb.t_gett(); if (!t) { LOG(L_ERR,"P_release_call_onreply(): unable to get transaction\n"); return CSCF_RETURN_BREAK; } if (t->method.len==6 && memcmp(t->method.s,"INVITE",6)==0) { // If its an INVTE, the state depends on which reply we are processing if (msg->first_line.u.reply.statuscode > 199) { release_call_previous(d,RELEASE_CALL_WEIRD,488,reason); } else { release_call_previous(d,RELEASE_CALL_EARLY,488,reason); } // This means we already finished with the dialog if (d->pcc_session_id.s) shm_free(d->pcc_session_id.s); d->pcc_session_id.s=0; d->pcc_session_id.len=0; d_unlock(hash); return CSCF_RETURN_BREAK; } else { //UPDATE so early release_call_early(d,488,reason); d_unlock(hash); return CSCF_RETURN_BREAK; } } else { LOG(L_ERR,"ERR:"M_NAME "P_release_call_onreply : unable to find dialog\n"); return CSCF_RETURN_ERROR; } }
/** * Inserts the Route header containing the dialog routes to be enforced * @param msg - the SIP message to add to * @param str1 - the value to insert - !!! quoted if needed * @param str2 - not used * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error */ int P_enforce_dialog_routes(struct sip_msg *msg,char *str1,char*str2) { int i; str newuri={0,0}; p_dialog *d; str call_id,host; int port,transport; str x; enum p_dialog_direction dir; dir = get_dialog_direction(str1); if (!find_dialog_contact(msg,dir,&host,&port,&transport)){ LOG(L_ERR,"ERR:"M_NAME":P_enforce_dialog_routes(): Error retrieving %s contact\n",str1); return CSCF_RETURN_BREAK; } call_id = cscf_get_call_id(msg,0); if (!call_id.len) return CSCF_RETURN_FALSE; LOG(L_INFO,"DBG:"M_NAME":P_enforce_dialog_routes(%s): Call-ID <%.*s> %d://%.*s:%d\n", str1,call_id.len,call_id.s, transport,host.len,host.s,port); d = get_p_dialog(call_id,host,port,transport,&dir); if (!d) d = get_p_dialog(call_id,host,port,transport,0); if (!d){ LOG(L_ERR,"ERR:"M_NAME":P_enforce_dialog_routes: dialog does not exists!\n"); return CSCF_RETURN_FALSE; } if (!d->routes_cnt){ d_unlock(d->hash); return CSCF_RETURN_TRUE; } x.len = route_s.len + route_e.len + (d->routes_cnt-1)*route_1.len; for(i=0;i<d->routes_cnt;i++) x.len+=d->routes[i].len; x.s = pkg_malloc(x.len); if (!x.s){ LOG(L_ERR, "ERR:"M_NAME":P_enforce_dialog_routes: Error allocating %d bytes\n", x.len); x.len=0; d_unlock(d->hash); return CSCF_RETURN_ERROR; } x.len=0; STR_APPEND(x,route_s); for(i=0;i<d->routes_cnt;i++){ if (i) STR_APPEND(x,route_1); STR_APPEND(x,d->routes[i]); } STR_APPEND(x,route_e); newuri.s = pkg_malloc(d->routes[0].len); if (!newuri.s){ LOG(L_ERR, "ERR:"M_NAME":P_enforce_dialog_routes: Error allocating %d bytes\n", d->routes[0].len); d_unlock(d->hash); return CSCF_RETURN_ERROR; } newuri.len = d->routes[0].len; memcpy(newuri.s,d->routes[0].s,newuri.len); if (msg->dst_uri.s) pkg_free(msg->dst_uri.s); msg->dst_uri = newuri; //LOG(L_ERR,"%.*s",x.len,x.s); d_unlock(d->hash); if (cscf_add_header_first(msg,&x,HDR_ROUTE_T)) { if (cscf_del_all_headers(msg,HDR_ROUTE_T)) return CSCF_RETURN_TRUE; else { LOG(L_ERR,"ERR:"M_NAME":P_enforce_dialog_routes: new Route headers added, but failed to drop old ones.\n"); return CSCF_RETURN_ERROR; } } else { if (x.s) pkg_free(x.s); return CSCF_RETURN_ERROR; } }