/** * 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; }
/** * Record routes, with given user as parameter. * @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_record_route(struct sip_msg *msg,char *str1,char *str2) { str rr={0,0}; str u = {0,0},scheme={0,0},scscf={0,0}; 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 = s_record_route_s.len+scheme.len+u.len+1+scscf.len+s_record_route_e.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,s_record_route_s); STR_APPEND(rr,scheme); STR_APPEND(rr,u); rr.s[rr.len++]='@'; STR_APPEND(rr,scscf); STR_APPEND(rr,s_record_route_e); } if (cscf_add_header_first(msg,&rr,HDR_RECORDROUTE_T)) return CSCF_RETURN_TRUE; else{ if (rr.s) pkg_free(rr.s); return CSCF_RETURN_BREAK; } out_of_memory: return CSCF_RETURN_BREAK; }
/** * Creates notifications with the given content for all of the subscribers. * @param pv - r_public* to which it refers * @param cv - the r_contact* to which it refers or NULL if for all * @param ps - the r_subscriber* to which it refers or NULL if for all * @param content - the body content * @param expires - the remaining subcription expiration time in seconds */ static void r_create_notifications(void *pv,void *cv,void *ps,str content,long expires) { r_notification *n; r_public *p=(r_public*)pv; // r_contact *c; r_subscriber *for_s=(r_subscriber*)ps; r_subscriber *s; str uri={0,0},req_uri={0,0},subscription_state={"active;expires=10000000000",26}, event={0,0},content_type={"application/reginfo+xml",23}; uri = p->aor; if (!for_s) s = p->shead; else s = for_s; while(s){ req_uri.len = s->subscriber.len+ruri_lr.len; req_uri.s = pkg_malloc(req_uri.len); if (!req_uri.s) { LOG(L_ERR,"ERR:"M_NAME":r_create_notifications: Error allocating %d bytes.\n",req_uri.len); return; } memcpy(req_uri.s,s->subscriber.s,s->subscriber.len); memcpy(req_uri.s+s->subscriber.len,ruri_lr.s,ruri_lr.len); //route = s->path; if (s->expires>time_now) { subscription_state.s = pkg_malloc(32); subscription_state.len=0; if (subscription_state.s){ sprintf(subscription_state.s,"%.*s%ld",subs_active.len,subs_active.s,expires); subscription_state.len=strlen(subscription_state.s); } }else { STR_PKG_DUP(subscription_state,subs_terminated,"pkg subs state"); } n = new_r_notification(req_uri,uri,subscription_state,event, content_type,content,s->dialog,s->version++); if (req_uri.s) pkg_free(req_uri.s); if (subscription_state.s) pkg_free(subscription_state.s); if (n) { #ifdef WITH_IMS_PM n->is_scscf_dereg=(expires==0); #endif add_r_notification(n); } if (!for_s) s = s->next; else s = 0; } return; out_of_memory: if (req_uri.s) pkg_free(req_uri.s); return; }
/** * Enforce a response coming from a UE to contain the same Record Route headers sent in the * corresponding request. * @param msg - the SIP reply * @param str1 - not used * @param str2 - not used * @returns #CSCF_RETURN_TRUE on success, #CSCF_RETURN_ERROR on error */ int P_enforce_record_routes(struct sip_msg *msg,char *str1, char *str2) { str hdr = {0,0}; str rr_req = {0,0}; struct sip_msg *req = cscf_get_request_from_reply(msg); LOG(L_INFO,"INF:"M_NAME":P_enforce_record_routes(): Enforcing RR in %d reply with the request ones\n", msg->first_line.u.reply.statuscode); if (!req){ LOG(L_ERR,"ERR:"M_NAME":P_enforce_record_routes(): No transactional request found.\n"); return CSCF_RETURN_ERROR; } if(!cscf_del_all_headers(msg, HDR_RECORDROUTE_T)){ LOG(L_ERR,"ERR:"M_NAME":P_enforce_record_routes(): error while deleting headers\n"); return CSCF_RETURN_ERROR; } rr_req = cscf_get_record_routes(req); if(rr_req.len){ hdr.len = pcscf_record_route_mt.len + s_record_route_s.len + rr_req.len+s_record_route_e.len; if(!(hdr.s = pkg_malloc(hdr.len))){ LOG(L_ERR,"ERR:"M_NAME":P_enforce_record_routes(): Unable to allocate memory for hdr\n"); goto out_of_memory; } hdr.len = 0; STR_APPEND(hdr,pcscf_record_route_mt); STR_APPEND(hdr,s_record_route_s); STR_APPEND(hdr,rr_req); STR_APPEND(hdr,s_record_route_e); }else{ LOG(L_ERR,"ERR:"M_NAME":P_enforce_record_routes(): Unable to get record routes - the RR should not be empty...\n"); // still, let it continue, maybe it was empty on purpose //return CSCF_RETURN_ERROR; STR_PKG_DUP(hdr,pcscf_record_route_mt,"pkg"); } if(!cscf_add_header_first(msg,&hdr,HDR_RECORDROUTE_T)){ LOG(L_ERR,"ERR:"M_NAME":P_enforce_record_routes(): Unable to add header\n"); if (hdr.s) pkg_free(hdr.s); return CSCF_RETURN_FALSE; } return CSCF_RETURN_TRUE; out_of_memory: return CSCF_RETURN_ERROR; }
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; }
/** * Remove from <str1> headers the <str2> tag * \note Does not work if you call it multiple times for the same hdr_name! * \note Because of the note above, this needs a fix to accept multiple tags in the str2 parameter! * @param msg - SIP Request * @param str1 - the header to remove from * @param str2 - the tag to remove * @returns #CSCF_RETURN_TRUE if removed, #CSCF_RETURN_FALSE if no changes required or #CSCF_RETURN_FALSE on error */ int P_remove_header_tag(struct sip_msg *msg,char *str1, char *str2) { str hdr_name,tag,x,y; struct hdr_field *hdr; char *c; int found,i,j,changed=0; hdr_name.s = str1; hdr_name.len = strlen(str1); tag.s = str2; tag.len = strlen(str2); hdr = cscf_get_header(msg,hdr_name); while (hdr){ /* get the original body */ x = hdr->body; LOG(L_INFO,"DBG:"M_NAME":P_remove_header_tag(): Original <%.*s> -> <%.*s>\n", hdr_name.len,hdr_name.s,x.len,x.s); /* duplicate the original body */ x.len++; STR_PKG_DUP(y,x,"P_remove_header_tag"); if (!y.s) goto error; y.len--; y.s[y.len]=0; /* look for occurences of tag and overwrite with \0 */ found=0; c = strtok(y.s," \t\r\n,"); while (c){ if (strlen(c)==tag.len && strncasecmp(c,tag.s,tag.len)==0){ found++; memset(c,0,tag.len); } c = strtok(0," \t\r\n,"); } /* if not found just skip to next header */ if (!found) goto next; /* compact the remaining tags by removing the \0 */ for(i=0,j=0;i<y.len;i++) if (y.s[i]!=0){ y.s[j++]=y.s[i]; } else { if (j!=0) y.s[j++]=','; while(i+1<y.len && y.s[i+1]==0) i++; } y.len = j; if (y.s[y.len-1]==',') y.len--; LOG(L_INFO,"DBG:"M_NAME":P_remove_header_tag(): Modified <%.*s> -> <%.*s>\n", hdr_name.len,hdr_name.s,y.len,y.s); /* write the changes */ if (y.len){ /* replace just the content */ if (!cscf_replace_string(msg,x,y)){ LOG(L_ERR,"ERR:"M_NAME":P_remove_header_tag(): Error replacing string!\n"); if (y.s) pkg_free(y.s); goto error; } }else{ /* remove the whole header */ if (y.s) pkg_free(y.s); if (!cscf_del_header(msg,hdr)){ LOG(L_ERR,"ERR:"M_NAME":P_remove_header_tag(): Error removing the whole header!\n"); goto error; } } changed++; next: hdr = cscf_get_next_header(msg,hdr_name,hdr); } return changed?CSCF_RETURN_TRUE:CSCF_RETURN_FALSE; error: out_of_memory: return CSCF_RETURN_ERROR; }