/** * ac_reply: UAS transaction Reply action. It replies to an incoming request with a response. * @param the_as The App Server that sent this action. * @param action action * @param len length * * function description * * Returns: what */ int ac_reply(as_p the_as,unsigned char processor_id,unsigned int flags,char *action,int len) { unsigned int hash_index,label,contentlength; struct cell *c=NULL; struct sip_msg *my_msg; struct to_body *tb; str new_header,body,totag; char *ttag; int i,k,retval; static char headers[MAX_HEADER]; struct as_uac_param *the_param; contentlength=0; ttag=NULL; my_msg=NULL; i=k=0; the_param=NULL; net2hostL(hash_index,action,k); net2hostL(label,action,k); if(seas_f.tmb.t_lookup_ident(&c,hash_index,label)<0){ LM_ERR("Failed to t_lookup_ident hash_idx=%d,label=%d\n",hash_index,label); goto error; } if(use_stats) action_stat(c); if(c->uas.status>=200){ LM_ERR("ac_reply: trying to reply to a \"%.*s\" transaction" "that is already in completed state\n",REQ_LINE(c->uas.request).method.len,REQ_LINE(c->uas.request).method.s); goto error; } if (!(my_msg=parse_ac_msg(HDR_EOH_F,action+k,len-k))) { LM_ERR("Failed to parse_ac_msg hash_idx=%d,label=%d\n",hash_index,label); goto error; } tb=(struct to_body*)my_msg->to->parsed; if(tb->tag_value.s && tb->tag_value.len){ totag=tb->tag_value; }else{ totag.s=NULL; totag.len=0; /*if(!(ttag=pkg_malloc(TOTAG_VALUE_LEN))){ LM_ERR("Out of memory !!!\n"); goto error; } totag.s=ttag; calc_crc_suffix(c->uas.request,seas_tag_suffix); LM_DBG("seas_tags = %.*s\n",TOTAG_VALUE_LEN,seas_tags); memcpy(totag.s,seas_tags,TOTAG_VALUE_LEN); totag.len=TOTAG_VALUE_LEN;*/ } LM_DBG("Using totag=[%.*s]\n",totag.len,totag.s); if(my_msg->content_length) contentlength=(unsigned int)(long)my_msg->content_length->parsed; if(0>(i=recordroute_diff(c->uas.request,my_msg))){/*not likely..*/ LM_DBG("Seems that request had more RecordRoutes than response...\n"); /* This prevents host->proxy->host from working. TODO review recordroute_diff code. goto error; */ }else LM_DBG("Recordroute Diff = %d\n",i); if(0>(i=extract_allowed_headers(my_msg,0,i,HDR_VIA_F|HDR_TO_F|HDR_FROM_F|HDR_CSEQ_F|HDR_CALLID_F|HDR_CONTENTLENGTH_F,headers,MAX_HEADER))){ LM_ERR("ac_reply() filtering headers !\n"); goto error; } headers[i]=0; new_header.s=headers; new_header.len=i; /* If it is INVITE and response is success (>=200 && <300), we mark it as local so that * SER does NOT retransmit the final response (by default, SER retransmit local UAS final * responses...*/ if(is_invite(c) && my_msg->first_line.u.reply.statuscode>=200 && my_msg->first_line.u.reply.statuscode<300){ c->flags |= T_IS_LOCAL_FLAG; if(!(the_param=shm_malloc(sizeof(struct as_uac_param)))){ LM_ERR("no more share memory\n"); goto error; } the_param->processor_id=processor_id; the_param->who=my_as; the_param->destroy_cb_set=0; if (seas_f.tmb.register_tmcb( 0, c, TMCB_E2EACK_IN,uas_e2e_ack_cb, the_param,¶m_free)<=0) { LM_ERR("cannot register additional callbacks\n"); goto error; } } /*WARNING casting unsigned int to int*/ body.len=contentlength; body.s=get_body(my_msg); LM_DBG("Trying to construct a SipReply with: ReasonPhrase:[%.*s] body:[%.*s] headers:[%.*s] totag:[%.*s]\n",\ my_msg->first_line.u.reply.reason.len,my_msg->first_line.u.reply.reason.s,\ body.len,body.s,new_header.len,new_header.s,totag.len,totag.s); /* t_reply_with_body un-ref-counts the transaction, so dont use it anymore*/ if(seas_f.tmb.t_reply_with_body(c,my_msg->first_line.u.reply.statuscode,&(my_msg->first_line.u.reply.reason),&body,&new_header,&totag)<0){ LM_ERR("Failed to t_reply\n"); goto error; } retval=0; goto exit; error: retval = -1; if(c) seas_f.tmb.unref_cell(c); if(the_param) shm_free(the_param); exit: if(ttag) pkg_free(ttag); if(my_msg){ free_sip_msg_lite(my_msg); pkg_free(my_msg); } return retval; }
static int assemble_msg(struct sip_msg* msg, struct tw_info *twi) { static char id_buf[IDBUF_LEN]; static char route_buffer[ROUTE_BUFFER_MAX]; static char append_buf[APPEND_BUFFER_MAX]; static char cmd_buf[CMD_BUFFER_MAX]; static str empty_param = {".",1}; unsigned int hash_index, label; contact_body_t* cb=0; contact_t* c=0; name_addr_t na; rr_t* record_route; struct hdr_field* p_hdr; param_hooks_t hooks; int l; char* s, fproxy_lr; str route, next_hop, append, tmp_s, body, str_uri; if(msg->first_line.type != SIP_REQUEST){ LM_ERR("called for something else then a SIP request\n"); goto error; } /* parse all -- we will need every header field for a UAS */ if ( parse_headers(msg, HDR_EOH_F, 0)==-1) { LM_ERR("parse_headers failed\n"); goto error; } /* find index and hash; (the transaction can be safely used due * to refcounting till script completes) */ if( t_get_trans_ident(msg,&hash_index,&label) == -1 ) { LM_ERR("t_get_trans_ident failed\n"); goto error; } /* parse from header */ if (msg->from->parsed==0 && parse_from_header(msg)<0 ) { LM_ERR("failed to parse <From:> header\n"); goto error; } /* parse the RURI (doesn't make any malloc) */ msg->parsed_uri_ok = 0; /* force parsing */ if (parse_sip_msg_uri(msg)<0) { LM_ERR("uri has not been parsed\n"); goto error; } /* parse contact header */ str_uri.s = 0; str_uri.len = 0; if(msg->contact) { if (msg->contact->parsed==0 && parse_contact(msg->contact)<0) { LM_ERR("failed to parse <Contact:> header\n"); goto error; } cb = (contact_body_t*)msg->contact->parsed; if(cb && (c=cb->contacts)) { str_uri = c->uri; if (find_not_quoted(&str_uri,'<')) { parse_nameaddr(&str_uri,&na); str_uri = na.uri; } } } /* str_uri is taken from caller's contact or from header * for backwards compatibility with pre-3261 (from is already parsed)*/ if(!str_uri.len || !str_uri.s) str_uri = get_from(msg)->uri; /* parse Record-Route headers */ route.s = s = route_buffer; route.len = 0; fproxy_lr = 0; next_hop = empty_param; p_hdr = msg->record_route; if(p_hdr) { if (p_hdr->parsed==0 && parse_rr(p_hdr)!=0 ) { LM_ERR("failed to parse 'Record-Route:' header\n"); goto error; } record_route = (rr_t*)p_hdr->parsed; } else { record_route = 0; } if( record_route ) { if ( (tmp_s.s=find_not_quoted(&record_route->nameaddr.uri,';'))!=0 && tmp_s.s+1!=record_route->nameaddr.uri.s+ record_route->nameaddr.uri.len) { /* Parse all parameters */ tmp_s.len = record_route->nameaddr.uri.len - (tmp_s.s- record_route->nameaddr.uri.s); if (parse_params( &tmp_s, CLASS_URI, &hooks, &record_route->params) < 0) { LM_ERR("failed to parse record route uri params\n"); goto error; } fproxy_lr = (hooks.uri.lr != 0); LM_DBG("record_route->nameaddr.uri: %.*s\n", record_route->nameaddr.uri.len,record_route->nameaddr.uri.s); if(fproxy_lr){ LM_DBG("first proxy has loose routing\n"); copy_route(s,route.len,record_route->nameaddr.uri.s, record_route->nameaddr.uri.len); } } for(p_hdr = p_hdr->next;p_hdr;p_hdr = p_hdr->next) { /* filter out non-RR hdr and empty hdrs */ if( (p_hdr->type!=HDR_RECORDROUTE_T) || p_hdr->body.len==0) continue; if(p_hdr->parsed==0 && parse_rr(p_hdr)!=0 ){ LM_ERR("failed to parse <Record-route:> header\n"); goto error; } for(record_route=p_hdr->parsed; record_route; record_route=record_route->next){ LM_DBG("record_route->nameaddr.uri: <%.*s>\n", record_route->nameaddr.uri.len, record_route->nameaddr.uri.s); copy_route(s,route.len,record_route->nameaddr.uri.s, record_route->nameaddr.uri.len); } } if(!fproxy_lr){ copy_route(s,route.len,str_uri.s,str_uri.len); str_uri = ((rr_t*)msg->record_route->parsed)->nameaddr.uri; } else { next_hop = ((rr_t*)msg->record_route->parsed)->nameaddr.uri; } } LM_DBG("calculated route: %.*s\n",route.len,route.len ? route.s : ""); LM_DBG("next r-uri: %.*s\n",str_uri.len,str_uri.len ? str_uri.s : ""); if ( REQ_LINE(msg).method_value==METHOD_INVITE || (twi->append && twi->append->add_body) ) { /* get body */ if( (body.s = get_body(msg)) == 0 ){ LM_ERR("get_body failed\n"); goto error; } body.len = msg->len - (body.s - msg->buf); } else { body = empty_param; } /* flags & additional headers */ append.s = s = append_buf; if (sizeof(flag_t)*2+12+1 >= APPEND_BUFFER_MAX) { LM_ERR("buffer overflow while copying flags\n"); goto error; } append_str(s,"P-MsgFlags: ",12); l = APPEND_BUFFER_MAX - (12+1); /* include trailing `\n'*/ if (int2reverse_hex(&s, &l, (int)msg->msg_flags) == -1) { LM_ERR("buffer overflow while copying optional header\n"); goto error; } append_chr(s,'\n'); if ( twi->append && ((s=append2buf( s, APPEND_BUFFER_MAX-(s-append.s), msg, twi->append->elems))==0) ) goto error; /* body separator */ append_chr(s,'.'); append.len = s-append.s; eol_line(1).s = s = cmd_buf; if(twi->action.len+12 >= CMD_BUFFER_MAX){ LM_ERR("buffer overflow while copying command name\n"); goto error; } append_str(s,"sip_request.",12); append_str(s,twi->action.s,twi->action.len); eol_line(1).len = s-eol_line(1).s; eol_line(2)=REQ_LINE(msg).method; /* method type */ eol_line(3)=msg->parsed_uri.user; /* user from r-uri */ eol_line(4)=msg->parsed_uri.host; /* domain */ eol_line(5)=msg->rcv.bind_address->address_str; /* dst ip */ eol_line(6)=msg->rcv.dst_port==SIP_PORT ? empty_param : msg->rcv.bind_address->port_no_str; /* port */ /* r_uri ('Contact:' for next requests) */ eol_line(7)=*GET_RURI(msg); /* r_uri for subsequent requests */ eol_line(8)=str_uri.len?str_uri:empty_param; eol_line(9)=get_from(msg)->body; /* from */ eol_line(10)=msg->to->body; /* to */ eol_line(11)=msg->callid->body; /* callid */ eol_line(12)=get_from(msg)->tag_value; /* from tag */ eol_line(13)=get_to(msg)->tag_value; /* to tag */ eol_line(14)=get_cseq(msg)->number; /* cseq number */ eol_line(15).s=id_buf; /* hash:label */ s = int2str(hash_index, &l); if (l+1>=IDBUF_LEN) { LM_ERR("too big hash\n"); goto error; } memcpy(id_buf, s, l); id_buf[l]=':'; eol_line(15).len=l+1; s = int2str(label, &l); if (l+1+eol_line(15).len>=IDBUF_LEN) { LM_ERR("too big label\n"); goto error; } memcpy(id_buf+eol_line(15).len, s, l); eol_line(15).len+=l; eol_line(16) = route.len ? route : empty_param; eol_line(17) = next_hop; eol_line(18) = append; eol_line(19) = body; /* success */ return 1; error: /* 0 would lead to immediate script exit -- -1 returns * with 'false' to script processing */ return -1; }
/** * ac_reply: UAS transaction Reply action. It replies to an incoming request with a response. * @param the_as The App Server that sent this action. * @param action action * @param len length * * function description * * Returns: what */ int ac_reply(as_p the_as,char *action,int len) { unsigned int flags,hash_index,label; struct cell *c; struct sip_msg *my_msg; struct to_body *tb; str new_header,body,totag; char *ttag; int i,k,retval; static char headers[MAX_HEADER]; ttag=NULL; my_msg=NULL; i=k=0; net2hostL(flags,action,k); net2hostL(hash_index,action,k); net2hostL(label,action,k); if(seas_f.tmb.t_lookup_ident(&c,hash_index,label)<0){ LM_ERR("Failed to t_lookup_ident hash_idx=%d,label=%d\n",hash_index,label); goto error; } if(use_stats) action_stat(c); if(c->uas.status>=200){ LM_ERR("ac_reply: trying to reply to a \"%.*s\" transaction" "that is already in completed state\n",REQ_LINE(c->uas.request).method.len,REQ_LINE(c->uas.request).method.s); goto error; } if (!(my_msg=parse_ac_msg(HDR_EOH_F,action+k,len-k))) { LM_ERR("Failed to parse_ac_msg hash_idx=%d,label=%d\n",hash_index,label); goto error; } tb=(struct to_body*)my_msg->to->parsed; if(tb->tag_value.s && tb->tag_value.len){ totag=tb->tag_value; }else{ totag.s=NULL; totag.len=0; /*if(!(ttag=pkg_malloc(TOTAG_VALUE_LEN))){ LM_ERR("Out of memory !!!\n"); goto error; } totag.s=ttag; calc_crc_suffix(c->uas.request,seas_tag_suffix); LM_DBG("seas_tags = %.*s\n",TOTAG_VALUE_LEN,seas_tags); memcpy(totag.s,seas_tags,TOTAG_VALUE_LEN); totag.len=TOTAG_VALUE_LEN;*/ } LM_DBG("Using totag=[%.*s]\n",totag.len,totag.s); if(0>(i=recordroute_diff(c->uas.request,my_msg))){/*not likely..*/ LM_DBG("Seems that request had more RecordRoutes than response...\n"); goto error; }else LM_DBG("Recordroute Diff = %d\n",i); if(0>(i=extract_allowed_headers(my_msg,0,i,HDR_VIA_F|HDR_TO_F|HDR_FROM_F|HDR_CSEQ_F|HDR_CALLID_F|HDR_CONTENTLENGTH_F,headers,MAX_HEADER))){ LM_ERR("ac_reply() filtering headers !\n"); goto error; } headers[i]=0; new_header.s=headers; new_header.len=i; /* If it is INVITE and response is success (>=200 && <300), we mark it as local so that * SER does NOT retransmit the final response (by default, SER retransmit local UAS final * responses...*/ if(is_invite(c) && my_msg->first_line.u.reply.statuscode>=200 && my_msg->first_line.u.reply.statuscode<300) c->flags |= T_IS_LOCAL_FLAG; /*WARNING casting unsigned int to int*/ get_body(my_msg, &body); LM_DBG("Trying to construct a SipReply with: ReasonPhrase:[%.*s] body:[%.*s] headers:[%.*s] totag:[%.*s]\n",\ my_msg->first_line.u.reply.reason.len,my_msg->first_line.u.reply.reason.s,\ body.len,body.s,new_header.len,new_header.s,totag.len,totag.s); if(seas_f.tmb.t_reply_with_body(c,my_msg->first_line.u.reply.statuscode, &(my_msg->first_line.u.reply.reason),&body,&new_header,&totag)<0){ LM_ERR("Failed to t_reply\n"); goto error; } seas_f.tmb.unref_cell(c); retval=0; goto exit; error: retval = -1; seas_f.tmb.unref_cell(c); exit: if(ttag) pkg_free(ttag); if(my_msg){ free_sip_msg_lite(my_msg); pkg_free(my_msg); } return retval; }
/* Returns 0 - nothing found * 1 - T found */ int t_reply_matching( struct sip_msg *p_msg , int *p_branch ) { struct cell* p_cell; unsigned int hash_index = 0; unsigned int entry_label = 0; unsigned int branch_id = 0; char *hashi, *branchi, *p, *n; int hashl, branchl; int scan_space; struct cseq_body *cseq; char *loopi; int loopl; char *syni; int synl; /* make compiler warnings happy */ loopi=0; loopl=0; syni=0; synl=0; /* split the branch into pieces: loop_detection_check(ignored), hash_table_id, synonym_id, branch_id */ if (!(p_msg->via1 && p_msg->via1->branch && p_msg->via1->branch->value.s)) goto nomatch2; /* we do RFC 3261 tid matching and want to see first if there is * magic cookie in branch */ if (p_msg->via1->branch->value.len<=MCOOKIE_LEN) goto nomatch2; if (memcmp(p_msg->via1->branch->value.s, MCOOKIE, MCOOKIE_LEN)!=0) goto nomatch2; p=p_msg->via1->branch->value.s+MCOOKIE_LEN; scan_space=p_msg->via1->branch->value.len-MCOOKIE_LEN; /* hash_id */ n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR); hashl=n-p; scan_space-=hashl; if (!hashl || scan_space<2 || *n!=BRANCH_SEPARATOR) goto nomatch2; hashi=p; p=n+1;scan_space--; if (!syn_branch) { /* md5 value */ n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR ); loopl = n-p; scan_space-= loopl; if (n==p || scan_space<2 || *n!=BRANCH_SEPARATOR) goto nomatch2; loopi=p; p=n+1; scan_space--; } else { /* synonym id */ n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR); synl=n-p; scan_space-=synl; if (!synl || scan_space<2 || *n!=BRANCH_SEPARATOR) goto nomatch2; syni=p; p=n+1;scan_space--; } /* branch id - should exceed the scan_space */ n=eat_token_end( p, p+scan_space ); branchl=n-p; if (!branchl ) goto nomatch2; branchi=p; /* sanity check */ if (reverse_hex2int(hashi, hashl, &hash_index)<0 ||hash_index>=TM_TABLE_ENTRIES || reverse_hex2int(branchi, branchl, &branch_id)<0 ||branch_id>=MAX_BRANCHES || (syn_branch ? reverse_hex2int(syni, synl, &entry_label)<0 : loopl!=MD5_LEN ) ) { LM_DBG("poor reply labels %u label %u branch %u\n", hash_index, entry_label, branch_id ); goto nomatch2; } LM_DBG("hash %u label %d branch %u\n",hash_index, entry_label, branch_id); cseq = get_cseq(p_msg); /* search the hash table list at entry 'hash_index'; lock the entry first */ LOCK_HASH(hash_index); for (p_cell = get_tm_table()->entrys[hash_index].first_cell; p_cell; p_cell=p_cell->next_cell) { /* first look if branch matches */ if (syn_branch) { if (p_cell->label != entry_label) continue; } else { if ( memcmp(p_cell->md5, loopi,MD5_LEN)!=0) continue; } /* sanity check ... too high branch ? */ if ( branch_id>=p_cell->nr_of_outgoings ) continue; /* does method match ? (remember -- CANCELs have the same branch as canceled transactions) */ if (!( /* it's a local cancel */ (cseq->method_id==METHOD_CANCEL && is_invite(p_cell) && p_cell->uac[branch_id].local_cancel.buffer.len ) /* method match */ || ((cseq->method_id!=METHOD_OTHER && p_cell->uas.request)? (cseq->method_id==REQ_LINE(p_cell->uas.request).method_value) :(EQ_STRS(cseq->method,p_cell->method))) )) continue; /* we passed all disqualifying factors .... the transaction has been matched ! */ set_t(p_cell); *p_branch = branch_id; REF_UNSAFE( T ); UNLOCK_HASH(hash_index); LM_DBG("reply matched (T=%p)!\n",T); /* if this is a 200 for INVITE, we will wish to store to-tags to be * able to distinguish retransmissions later and not to call * TMCB_RESPONSE_OUT uselessly; we do it only if callbacks are * enabled -- except callback customers, nobody cares about * retransmissions of multiple 200/INV or ACK/200s */ if (is_invite(p_cell) && p_msg->REPLY_STATUS>=200 && p_msg->REPLY_STATUS<300 && ( (!is_local(p_cell) && has_tran_tmcbs(p_cell, TMCB_RESPONSE_OUT|TMCB_RESPONSE_PRE_OUT) ) || (is_local(p_cell)&&has_tran_tmcbs(p_cell,TMCB_LOCAL_COMPLETED)) )) { if (parse_headers(p_msg, HDR_TO_F, 0)==-1) { LM_ERR("to parsing failed\n"); } } return 1; } /* for cycle */ /* nothing found */ UNLOCK_HASH(hash_index); LM_DBG("no matching transaction exists\n"); nomatch2: LM_DBG("failure to match a transaction\n"); *p_branch = -1; set_t(0); return -1; }
int th_unmask_ruri(sip_msg_t *msg) { str eval; struct lump* l; str out; /* Do nothing if ruri is not encoded */ if (th_uri_prefix_checks && ((REQ_LINE(msg).uri.len<th_uri_prefix.len) || (strncasecmp(REQ_LINE(msg).uri.s, th_uri_prefix.s, th_uri_prefix.len)!=0))) { LM_DBG("ruri [%.*s] is not encoded",REQ_LINE(msg).uri.len,REQ_LINE(msg).uri.s); return 0; } if(th_get_uri_param_value(&REQ_LINE(msg).uri, &th_uparam_name, &eval)<0 || eval.len<=0) { LM_DBG("no uri param [%.*s] in [%.*s]\n", th_uparam_name.len, th_uparam_name.s, REQ_LINE(msg).uri.len,REQ_LINE(msg).uri.s); return -1; } out.s = th_mask_decode(eval.s, eval.len, &th_uparam_prefix, 0, &out.len); if(out.s==NULL) { LM_ERR("cannot decode r-uri [%.*s]\n", REQ_LINE(msg).uri.len,REQ_LINE(msg).uri.s); return -1; } LM_DBG("+decoded: %d: [%.*s]\n", out.len, out.len, out.s); l=del_lump(msg, REQ_LINE(msg).uri.s-msg->buf, REQ_LINE(msg).uri.len, 0); if (l==0) { LM_ERR("failed deleting r-uri\n"); pkg_free(out.s); return -1; } if (insert_new_lump_after(l, out.s, out.len, 0)==0) { LM_ERR("could not insert new lump\n"); pkg_free(out.s); return -1; } return 0; }