/** * Check if we already did record-route * @param msg - the SIP message to add to * @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_is_record_routed(struct sip_msg *msg,char *str1,char *str2) { str rr; str u = {0,0},scheme={0,0},scscf={0,0}; struct hdr_field *hdr=0; rr_t *rr_s; enum s_dialog_direction dir = get_dialog_direction(str1); switch (dir){ case DLG_MOBILE_ORIGINATING: STR_PKG_DUP(rr,scscf_record_route_mo,"pkg"); break; case DLG_MOBILE_TERMINATING: STR_PKG_DUP(rr,scscf_record_route_mt,"pkg"); break; default: u.s = str1; u.len = strlen(str1); if (scscf_name_str.len>4 && strncasecmp(scscf_name_str.s,"sip:",4)==0){ scheme.s = scscf_name_str.s; scheme.len = 4; }else if (scscf_name_str.len>5 && strncasecmp(scscf_name_str.s,"sips:",5)==0){ scheme.s = scscf_name_str.s; scheme.len = 4; } scscf.s = scheme.s+scheme.len; scscf.len = scscf_name_str.len - scheme.len; rr.len = scheme.len+u.len+1+scscf.len; rr.s = pkg_malloc(rr.len); if (!rr.s){ LOG(L_ERR,"ERR:"M_NAME":S_record_route: error allocating %d bytes!\n",rr.len); return CSCF_RETURN_BREAK; } rr.len = 0; STR_APPEND(rr,scheme); STR_APPEND(rr,u); rr.s[rr.len++]='@'; STR_APPEND(rr,scscf); } for(hdr = cscf_get_next_record_route(msg,(struct hdr_field*) 0); hdr ; hdr = cscf_get_next_record_route(msg,hdr)){ for (rr_s = (rr_t *)hdr->parsed;rr_s; rr_s = rr_s->next) if (rr_s->nameaddr.uri.len == rr.len && strncasecmp(rr_s->nameaddr.uri.s,rr.s,rr.len)==0){ pkg_free(rr.s); return CSCF_RETURN_TRUE; } } pkg_free(rr.s); return CSCF_RETURN_FALSE; out_of_memory: return CSCF_RETURN_ERROR; }
/** * Save the Record-routes for a dialog. * @param msg - the SIP message to extract RRs from * @param str1 - the direction to know if to reverse the RR list or not * @param d - dialog to save to */ void save_dialog_routes(struct sip_msg* msg, char* str1,p_dialog *d) { int i; rr_t *rr,*ri; struct hdr_field *hdr; if (d->routes){ for(i=0;i<d->routes_cnt;i++) shm_free(d->routes[i].s); shm_free(d->routes); d->routes = 0; } d->routes_cnt = 0; for(hdr=cscf_get_next_record_route(msg,0);hdr;hdr=cscf_get_next_record_route(msg,hdr)){ rr = (rr_t*)hdr->parsed; for(ri=rr;ri;ri=ri->next) d->routes_cnt++; } d->routes = shm_malloc(sizeof(str)*d->routes_cnt); if (!d->routes){ LOG(L_ERR,"ERR:"M_NAME":save_dialog_routes(): Unable to alloc %d bytes\n", sizeof(str)*d->routes_cnt); d->routes_cnt = 0; return; } if (!str1) return; if (str1[0]=='o'||str1[0]=='0'||str1[0]=='O'){ /* originating - reverse order */ i = d->routes_cnt-1; for(hdr=cscf_get_next_record_route(msg,0);hdr;hdr=cscf_get_next_record_route(msg,hdr)){ rr = (rr_t*)hdr->parsed; for(ri=rr;ri;ri=ri->next){ STR_SHM_DUP(d->routes[i],ri->nameaddr.uri,"shm"); i--; } } }else{ /* terminating - normal order */ i = 0; for(hdr=cscf_get_next_record_route(msg,0);hdr;hdr=cscf_get_next_record_route(msg,hdr)){ rr = (rr_t*)hdr->parsed; for(ri=rr;ri;ri=ri->next){ STR_SHM_DUP(d->routes[i],ri->nameaddr.uri,"shm"); i++; } } } out_of_memory: return; }
/** * Checks if a response on the MT side includes all the required Record Routes, as present in the request * @param msg - the SIP reply to check * @param str1 - not used * @param str2 - not used * @return #CSCF_RETURN_TRUE on match, #CSCF_RETURN_FALSE if not matching */ int P_follows_record_routes(struct sip_msg *msg, char *str1, char *str2) { struct hdr_field *temp_hdr_req = NULL,*temp_hdr_rpl = NULL; struct sip_msg * req = NULL; rr_t * rr_req = NULL, *rr_req_i = NULL; rr_t * rr_rpl = NULL; LOG(L_INFO,"INF:"M_NAME":P_follows_record_routes(): Checking if RR in %d reply match the request ones\n", msg->first_line.u.reply.statuscode); // Get the first RR in reply temp_hdr_rpl = cscf_get_next_record_route(msg,temp_hdr_rpl); if (!temp_hdr_rpl || !(rr_rpl = (rr_t*)temp_hdr_rpl->parsed)){ LOG(L_ERR,"ERR:"M_NAME":P_follows_record_routes(): No RR's found in reply.\n"); goto nok; } // Checking first RR - this is a special case because the saved request does not include it if (pcscf_record_route_mt_uri.len != rr_rpl->nameaddr.uri.len || strncmp(pcscf_record_route_mt_uri.s,rr_rpl->nameaddr.uri.s,pcscf_record_route_mt_uri.len)!=0){ LOG(L_ERR,"ERR:"M_NAME":P_follows_record_routes(): First RR did not match P-CSCF MT = %.*s , Rpl = %.*s \n", pcscf_record_route_mt_uri.len,pcscf_record_route_mt_uri.s,rr_rpl->nameaddr.uri.len,rr_rpl->nameaddr.uri.s); goto nok; } rr_rpl = rr_rpl->next; if (!rr_rpl){ temp_hdr_rpl = cscf_get_next_record_route(msg,temp_hdr_rpl); if (temp_hdr_rpl) rr_rpl = (rr_t*)temp_hdr_rpl->parsed; } // Find the request if(!(req = cscf_get_request_from_reply(msg))) { LOG(L_ERR,"ERR:"M_NAME":P_follows_record_routes(): No transactional request found.\n"); goto nok; } temp_hdr_req = cscf_get_next_record_route(req,temp_hdr_req); if (temp_hdr_req) { rr_req = (rr_t*)temp_hdr_req->parsed; rr_req_i = rr_req; } // Cycle through the request/reply headers and compare while(rr_rpl && rr_req_i) { if(rr_req_i->nameaddr.uri.len != rr_rpl->nameaddr.uri.len || strncmp(rr_req_i->nameaddr.uri.s,rr_rpl->nameaddr.uri.s,rr_req_i->nameaddr.uri.len)!=0){ LOG(L_ERR,"ERR:"M_NAME":P_follows_record_routes(): Mismatch in RR URIs Req = %.*s , Rpl = %.*s \n", rr_req_i->nameaddr.uri.len,rr_req_i->nameaddr.uri.s,rr_rpl->nameaddr.uri.len,rr_rpl->nameaddr.uri.s); goto nok; } rr_rpl = rr_rpl->next; if (!rr_rpl){ temp_hdr_rpl = cscf_get_next_record_route(msg,temp_hdr_rpl); if (temp_hdr_rpl) rr_rpl = (rr_t*)temp_hdr_rpl->parsed; } rr_req_i = rr_req_i->next; if (!rr_req_i){ if (rr_req){ free_rr(&rr_req); temp_hdr_req->parsed = NULL; } temp_hdr_req = cscf_get_next_record_route(req,temp_hdr_req); if (temp_hdr_req) { rr_req = (rr_t*)temp_hdr_req->parsed; rr_req_i = rr_req; } } } if(rr_rpl){ LOG(L_ERR,"ERR:"M_NAME":P_follows_record_routes(): More RR headers in reply than in request\n"); goto nok; } if(rr_req){ LOG(L_ERR,"ERR:"M_NAME":P_follows_record_routes(): More RR headers in request than in reply\n"); goto nok; } if (rr_req){ free_rr(&rr_req); temp_hdr_req->parsed = NULL; } return CSCF_RETURN_TRUE; nok: if (rr_req){ free_rr(&rr_req); temp_hdr_req->parsed = NULL; } return CSCF_RETURN_FALSE; }