/* ================================================================= */ static void func_invite(struct cell *t,struct sip_msg *msg,int code,void *param) { int i; //callback function if (!check_transaction_quadruple(msg)) { //we do not have a correct message from/callid/cseq/to return; } i = encode_contact(msg,"enc_prefix","193.175.135.38"); fprintf(stdout,"decode/encode = returned %d\n",i);fflush(stdout); if (t->is_invite) { if (msg->buf != NULL) { fprintf(stdout,"INVITE:received \n%s\n",msg->buf);fflush(stdout); i = sdp_mangle_port(msg,"1000",NULL); fprintf(stdout,"sdp_mangle_port returned %d\n",i);fflush(stdout); i = sdp_mangle_ip(msg,"10.0.0.0/16","123.124.125.126"); fprintf(stdout,"sdp_mangle_ip returned %d\n",i);fflush(stdout); } else fprintf(stdout,"INVITE:received NULL\n");fflush(stdout); } else { fprintf(stdout,"NOT INVITE(REGISTER?) received \n%s\n",msg->buf);fflush(stdout); //i = decode_contact(msg,NULL,NULL); //fprintf(stdout,"decode/encode = returned %d\n",i);fflush(stdout); } fflush(stdout); }
inline static int t_check_trans(struct sip_msg* msg) { struct cell *trans; if (msg->REQ_METHOD==METHOD_CANCEL) { /* parse needed hdrs*/ if (check_transaction_quadruple(msg)==0) { LM_ERR("too few headers\n"); return 0; /*drop request!*/ } if (!msg->hash_index) msg->hash_index = tm_hash(msg->callid->body,get_cseq(msg)->number); /* performe lookup */ trans = t_lookupOriginalT( msg ); return trans?1:-1; } else { trans = get_t(); if (trans==NULL) return -1; if (trans!=T_UNDEFINED) return 1; switch ( t_lookup_request( msg , 0) ) { case 1: /* transaction found -> is it local ACK? */ if (msg->REQ_METHOD==METHOD_ACK) return 1; /* .... else -> retransmission */ trans = get_t(); t_retransmit_reply(trans); UNREF(trans); set_t(0); return 0; case -2: /* e2e ACK found */ return 1; default: /* notfound */ return -1; } } }
inline static int t_check_trans(struct sip_msg* msg, char *foo, char *bar) { struct cell *trans; struct cell *bkup; int ret; if (msg->REQ_METHOD==METHOD_CANCEL) { /* parse needed hdrs*/ if (check_transaction_quadruple(msg)==0) { LOG(L_ERR, "ERROR:tm:t_check_trans: too few headers\n"); return 0; /*drop request!*/ } if (!msg->hash_index) msg->hash_index = hash(msg->callid->body,get_cseq(msg)->number); /* performe lookup */ trans = t_lookupOriginalT( msg ); if (trans) { UNREF( trans ); return 1; } else { return -1; } } else { bkup = get_t(); ret = t_lookup_request( msg , 0); if ( (trans=get_t())!=0 ) UNREF(trans); set_t( bkup ); switch (ret) { case 1: /* transaction found */ return 1; case -2: /* e2e ACK found */ return 1; default: /* notfound */ return -1; } } return ret; }
/*Actions are composed as follows: * (the action length and type as always= 5 bytes) * 4:uac_id * * int request(str* method, str* req_uri, str* to, str* from, str* headers, str* body, transaction_cb c, void* cp) * TODO performance speedup: instead of using * dynamically allocated memory for headers,body,totag,reason and my_msg * use static buffers. * */ int ac_uac_req(as_p the_as,unsigned char processor_id,unsigned int flags,char *action,int len) { unsigned int cseq; char err_buf[MAX_REASON_LEN]; struct sip_msg *my_msg; struct to_body *fb,*tb; struct cseq_body *cseqb; struct as_uac_param *the_param; dlg_t *my_dlg; int k,retval,uac_id,sip_error,ret,err_ret; long clen; str headers,body,fake_uri; uac_req_t uac_r; headers.s=body.s=fake_uri.s=NULL; my_dlg=NULL; my_msg=NULL; the_param=NULL; k=clen=0; net2hostL(uac_id,action,k); if(!(headers.s=pkg_malloc(MAX_HEADER))){ LM_ERR("Out of Memory!!"); goto error; } headers.len=0; LM_DBG("Action UAC Message: uac_id:%d processor_id=%d\n",uac_id,processor_id); if (!(my_msg = parse_ac_msg(HDR_EOH_F,action+k,len-k))) { LM_ERR("out of memory!\n"); goto error; } if(my_msg->first_line.type==SIP_REPLY){ LM_ERR("trying to create a UAC with a SIP response!!\n"); goto error; } if(parse_headers(my_msg,HDR_EOH_F,0)==-1){ LM_ERR("ERROR:seas:ac_uac_req:parsing headers\n"); goto error; } if(parse_from_header(my_msg)<0){ LM_ERR("parsing from header ! \n"); goto error; } if(check_transaction_quadruple(my_msg)==0){ as_action_fail_resp(uac_id,SE_UAC,"Headers missing (to,from,call-id,cseq)?",0); LM_ERR("Headers missing (to,from,call-id,cseq)?"); goto error; } if(!(get_from(my_msg)) || !(get_from(my_msg)->tag_value.s) || !(get_from(my_msg)->tag_value.len)){ as_action_fail_resp(uac_id,SE_UAC,"From tag missing",0); LM_ERR("From tag missing"); goto error; } fb=my_msg->from->parsed; tb=my_msg->to->parsed; cseqb=my_msg->cseq->parsed; if(0!=(str2int(&cseqb->number,&cseq))){ LM_DBG("unable to parse CSeq\n"); goto error; } if(my_msg->first_line.u.request.method_value != METHOD_ACK && my_msg->first_line.u.request.method_value != METHOD_CANCEL) { /** we trick req_within */ cseq--; } if(seas_f.tmb.new_dlg_uac(&(my_msg->callid->body),&(fb->tag_value),cseq,\ &(fb->uri),&(tb->uri),&my_dlg) < 0) { as_action_fail_resp(uac_id,SE_UAC,"Error creating new dialog",0); LM_ERR("Error while creating new dialog\n"); goto error; } if(seas_f.tmb.dlg_add_extra(my_dlg,&(fb->display),&(tb->display)) < 0 ) { as_action_fail_resp(uac_id,SE_UAC, "Error adding the display names to the new dialog",0); LM_ERR("failed to add display names to the new dialog\n"); goto error; } if(tb->tag_value.s && tb->tag_value.len) shm_str_dup(&my_dlg->id.rem_tag,&tb->tag_value); /**Awful hack: to be able to set our own CSeq, from_tag and call-ID we have * to use req_within instead of req_outside (it sets it's own CSeq,Call-ID * and ftag), so we have to simulate that the dialog is already in completed * state so... */ server_signature=0; my_dlg->state = DLG_CONFIRMED; if(0>(headers.len=extract_allowed_headers(my_msg,1,-1,HDR_CONTENTLENGTH_F|HDR_ROUTE_F|HDR_TO_F|HDR_FROM_F|HDR_CALLID_F|HDR_CSEQ_F,headers.s,MAX_HEADER))) { LM_ERR("Unable to extract allowed headers!!\n"); goto error; } headers.s[headers.len]=0; /*let's get the body*/ if(my_msg->content_length) clen=(long)get_content_length(my_msg); if(clen!=0){ if(!(body.s=pkg_malloc(clen))){ LM_ERR("Out of Memory!"); goto error; } memcpy(body.s,get_body(my_msg),clen); body.len=clen; body.s[clen]=0; LM_DBG("Trying to construct a Sip Request with: body:%d[%.*s] headers:%d[%.*s]\n",\ body.len,body.len,body.s,headers.len,headers.len,headers.s); /*t_reply_with_body un-ref-counts the transaction, so dont use it anymore*/ }else{ body.s=NULL; body.len=0; } /*Now... create the UAC !! * it would be great to know the hash_index and the label that have been assigned * to our newly created cell, but t_uac does not leave any way for us to know... * only that when that transaction transitions its state (ie. a response is received, * a timeout is reached, etc...) the callback will be called with the given parameter. * * So the only way we have to know who we are, is passing as a parameter a structure with * 2 pointers: one to the app_server and the other, the identifier of the UAC (uac_id). * */ if(!(the_param=shm_malloc(sizeof(struct as_uac_param)))){ LM_ERR("out of shared memory\n"); goto error; } the_param->who=my_as; the_param->uac_id=uac_id; the_param->processor_id=processor_id; the_param->destroy_cb_set=0; shm_str_dup(&my_dlg->rem_target,&my_msg->first_line.u.request.uri); if (my_msg->route) { if (parse_rr(my_msg->route) < 0) { LM_ERR( "Error while parsing Route body\n"); goto error; } /* TODO route_set should be a shm copy of my_msg->route->parsed */ my_dlg->route_set=(rr_t*)my_msg->route->parsed; /** this SHOULD be: shm_duplicate_rr(&my_dlg->route_set,my_msg->route->parsed); * but it will last more... */ } calculate_hooks(my_dlg); if(flags & SPIRAL_FLAG){ memcpy(headers.s+headers.len,SPIRAL_HDR CRLF,SPIRAL_HDR_LEN + CRLF_LEN); headers.len+=SPIRAL_HDR_LEN+CRLF_LEN; headers.s[headers.len]=0; fake_uri.s=pkg_malloc(200); fake_uri.len=print_local_uri(the_as,processor_id,fake_uri.s,200); if(fake_uri.len<0){ LM_ERR("printing local uri\n"); goto error; } my_dlg->hooks.next_hop=&fake_uri; } /* Kamailio and OpenSIPs seem to have diverged quite a bit on flags and events notified to UACs. Let's see if kamailio gets it right by now, if not this is a TODO: check PASS_PROVISIONAL my_dlg->T_flags=T_NO_AUTO_ACK|T_PASS_PROVISIONAL_FLAG ; this is the same as (TMCB_DONT_ACK|TMCB_LOCAL_RESPONSE_OUT) in Kamailio */ set_uac_req(&uac_r, &(my_msg->first_line.u.request.method), &headers, &body, my_dlg,TMCB_DONT_ACK|TMCB_LOCAL_RESPONSE_OUT, uac_cb, (void*)the_param); ret=seas_f.tmb.t_request_within(&uac_r); /** now undo all the fakes we have put in my_dlg*/ /*because my_dlg->route_set should be shm but we fake it (its pkg_mem)*/ my_dlg->route_set=(rr_t *)0; if (ret < 0) { err_ret = err2reason_phrase(ret,&sip_error,err_buf, sizeof(err_buf), "SEAS/UAC"); LM_ERR("failed to send the [%.*s] request\n",uac_r.method->len,uac_r.method->s); LM_ERR("Error on request_within %s\n",err_buf ); if(err_ret > 0) { as_action_fail_resp(uac_id,ret,err_buf,0); }else{ as_action_fail_resp(uac_id,E_UNSPEC,"500 SEAS/UAC error",0); } goto error; } retval=0; goto exit; error: retval = -1; if(the_param) shm_free(the_param); exit: seas_f.tmb.free_dlg(my_dlg); if(headers.s) pkg_free(headers.s); if(body.s) pkg_free(body.s); if(fake_uri.s) pkg_free(fake_uri.s); if(my_msg){ if(my_msg->headers) free_hdr_field_lst(my_msg->headers); pkg_free(my_msg); } return retval; }
/* function lookups transaction being canceled by CANCEL in p_msg; * it returns: * 0 - transaction wasn't found * T - transaction found */ struct cell* t_lookupOriginalT( struct sip_msg* p_msg ) { struct cell *p_cell; unsigned int hash_index; struct sip_msg *t_msg; struct via_param *branch; int foo; int ret; /* start searching in the table */ if (!(p_msg->msg_flags & FL_HASH_INDEX)){ /* parse all*/ if (check_transaction_quadruple(p_msg)==0) { LOG(L_ERR, "ERROR: TM module: t_lookupOriginalT:" " too few headers\n"); /* stop processing */ return 0; } p_msg->hash_index=hash( p_msg->callid->body , get_cseq(p_msg)->number); p_msg->msg_flags|=FL_HASH_INDEX; } hash_index = p_msg->hash_index; DBG("DEBUG: t_lookupOriginalT: searching on hash entry %d\n",hash_index ); /* first of all, look if there is RFC3261 magic cookie in branch; if * so, we can do very quick matching and skip the old-RFC bizzar * comparison of many header fields */ if (!p_msg->via1) { LOG(L_ERR, "ERROR: t_lookupOriginalT: no via\n"); return 0; } branch=p_msg->via1->branch; if (branch && branch->value.s && branch->value.len>MCOOKIE_LEN && memcmp(branch->value.s,MCOOKIE,MCOOKIE_LEN)==0) { /* huhuhu! the cookie is there -- let's proceed fast */ LOCK_HASH(hash_index); ret=matching_3261(p_msg, &p_cell, /* we are seeking the original transaction -- * skip CANCEL transactions during search */ METHOD_CANCEL, &foo); if (ret==1) goto found; else goto notfound; } /* no cookies --proceed to old-fashioned pre-3261 t-matching */ LOCK_HASH(hash_index); /* all the transactions from the entry are compared */ for (p_cell=get_tm_table()->entrys[hash_index].first_cell; p_cell; p_cell = p_cell->next_cell ) { t_msg = p_cell->uas.request; if (!t_msg) continue; /* skip UAC transactions */ /* we don't cancel CANCELs ;-) */ if (t_msg->REQ_METHOD==METHOD_CANCEL) continue; /* check lengths now */ if (!EQ_LEN(callid)) continue; if (get_cseq(t_msg)->number.len!=get_cseq(p_msg)->number.len) continue; if (!EQ_LEN(from)) continue; #ifdef CANCEL_TAG if (!EQ_LEN(to)) continue; #else /* relaxed matching -- we don't care about to-tags anymore, * many broken UACs screw them up and ignoring them does not * actually hurt */ if (get_to(t_msg)->uri.len!=get_to(p_msg)->uri.len) continue; #endif if (ruri_matching && !EQ_REQ_URI_LEN) continue; if (via1_matching && !EQ_VIA_LEN(via1)) continue; /* check the content now */ if (!EQ_STR(callid)) continue; if (memcmp(get_cseq(t_msg)->number.s, get_cseq(p_msg)->number.s,get_cseq(p_msg)->number.len)!=0) continue; if (!EQ_STR(from)) continue; #ifdef CANCEL_TAG if (!EQ_STR(to)) continue; #else if (memcmp(get_to(t_msg)->uri.s, get_to(p_msg)->uri.s, get_to(t_msg)->uri.len)!=0) continue; #endif if (ruri_matching && !EQ_REQ_URI_STR) continue; if (via1_matching && !EQ_VIA_STR(via1)) continue; /* found */ goto found; } notfound: /* no transaction found */ DBG("DEBUG: t_lookupOriginalT: no CANCEL matching found! \n" ); UNLOCK_HASH(hash_index); DBG("DEBUG: t_lookupOriginalT completed\n"); return 0; found: DBG("DEBUG: t_lookupOriginalT: canceled transaction" " found (%p)! \n",p_cell ); REF_UNSAFE( p_cell ); UNLOCK_HASH(hash_index); DBG("DEBUG: t_lookupOriginalT completed\n"); return p_cell; }
int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked, int* cancel) { struct cell *p_cell; unsigned int isACK; struct sip_msg *t_msg; int ret; struct via_param *branch; int match_status; struct cell *e2e_ack_trans; /* parse all*/ if (check_transaction_quadruple(p_msg)==0) { LOG(L_ERR, "ERROR: TM module: t_lookup_request: too few headers\n"); set_t(0); /* stop processing */ return 0; } /* start searching into the table */ if (!(p_msg->msg_flags & FL_HASH_INDEX)){ p_msg->hash_index=hash( p_msg->callid->body , get_cseq(p_msg)->number); p_msg->msg_flags|=FL_HASH_INDEX; } isACK = p_msg->REQ_METHOD==METHOD_ACK; DBG("t_lookup_request: start searching: hash=%d, isACK=%d\n", p_msg->hash_index,isACK); /* assume not found */ ret=-1; e2e_ack_trans = 0; /* first of all, look if there is RFC3261 magic cookie in branch; if * so, we can do very quick matching and skip the old-RFC bizzar * comparison of many header fields */ if (!p_msg->via1) { LOG(L_ERR, "ERROR: t_lookup_request: no via\n"); set_t(0); return 0; } branch=p_msg->via1->branch; if (branch && branch->value.s && branch->value.len>MCOOKIE_LEN && memcmp(branch->value.s,MCOOKIE,MCOOKIE_LEN)==0) { /* huhuhu! the cookie is there -- let's proceed fast */ LOCK_HASH(p_msg->hash_index); match_status=matching_3261(p_msg,&p_cell, /* skip transactions with different method; otherwise CANCEL * would match the previous INVITE trans. */ isACK ? ~METHOD_INVITE: ~p_msg->REQ_METHOD, cancel); switch(match_status) { case 0: goto notfound; /* no match */ case 1: goto found; /* match */ case 2: goto e2e_ack; /* e2e proxy ACK */ } } /* ok -- it's ugly old-fashioned transaction matching -- it is * a bit simplified to be fast -- we don't do all the comparisons * of parsed uri, which was simply too bloated */ DBG("DEBUG: proceeding to pre-RFC3261 transaction matching\n"); *cancel=0; /* lock the whole entry*/ LOCK_HASH(p_msg->hash_index); /* all the transactions from the entry are compared */ for ( p_cell = get_tm_table()->entrys[p_msg->hash_index].first_cell; p_cell; p_cell = p_cell->next_cell ) { t_msg = p_cell->uas.request; if (!t_msg) continue; /* skip UAC transactions */ if (!isACK) { /* for non-ACKs we want same method matching, we * make an exception for pre-exisiting CANCELs because we * want to set *cancel */ if ((t_msg->REQ_METHOD!=p_msg->REQ_METHOD) && (t_msg->REQ_METHOD!=METHOD_CANCEL)) continue; /* compare lengths first */ if (!EQ_LEN(callid)) continue; /* CSeq only the number without method ! */ if (get_cseq(t_msg)->number.len!=get_cseq(p_msg)->number.len) continue; if (!EQ_LEN(from)) continue; if (!EQ_LEN(to)) continue; if (ruri_matching && !EQ_REQ_URI_LEN) continue; if (via1_matching && !EQ_VIA_LEN(via1)) continue; /* length ok -- move on */ if (!EQ_STR(callid)) continue; if (memcmp(get_cseq(t_msg)->number.s, get_cseq(p_msg)->number.s, get_cseq(p_msg)->number.len)!=0) continue; if (!EQ_STR(from)) continue; if (!EQ_STR(to)) continue; if (ruri_matching && !EQ_REQ_URI_STR) continue; if (via1_matching && !EQ_VIA_STR(via1)) continue; if ((t_msg->REQ_METHOD==METHOD_CANCEL) && (p_msg->REQ_METHOD!=METHOD_CANCEL)){ /* we've matched an existing CANCEL */ *cancel=1; continue; } /* request matched ! */ DBG("DEBUG: non-ACK matched\n"); goto found; } else { /* it's an ACK request*/ /* ACK's relate only to INVITEs */ if (t_msg->REQ_METHOD!=METHOD_INVITE) continue; /* From|To URI , CallID, CSeq # must be always there */ /* compare lengths now */ if (!EQ_LEN(callid)) continue; /* CSeq only the number without method ! */ if (get_cseq(t_msg)->number.len!=get_cseq(p_msg)->number.len) continue; if (! EQ_LEN(from)) continue; /* To only the uri -- to many UACs screw up tags */ if (get_to(t_msg)->uri.len!=get_to(p_msg)->uri.len) continue; if (!EQ_STR(callid)) continue; if (memcmp(get_cseq(t_msg)->number.s, get_cseq(p_msg)->number.s, get_cseq(p_msg)->number.len)!=0) continue; if (!EQ_STR(from)) continue; if (memcmp(get_to(t_msg)->uri.s, get_to(p_msg)->uri.s, get_to(t_msg)->uri.len)!=0) continue; /* it is e2e ACK/200 */ if (p_cell->uas.status<300 && e2e_ack_trans==0) { /* all criteria for proxied ACK are ok */ if (p_cell->relayed_reply_branch!=-2) { e2e_ack_trans=p_cell; continue; } /* it's a local UAS transaction */ if (dlg_matching(p_cell, p_msg)) goto found; continue; } /* it is not an e2e ACK/200 -- perhaps it is * local negative case; in which case we will want * more elements to match: r-uri and via; allow * mismatching r-uri as an config option for broken * UACs */ if (ruri_matching && !EQ_REQ_URI_LEN ) continue; if (via1_matching && !EQ_VIA_LEN(via1)) continue; if (ruri_matching && !EQ_REQ_URI_STR) continue; if (via1_matching && !EQ_VIA_STR(via1)) continue; /* wow -- we survived all the check! we matched! */ DBG("DEBUG: non-2xx ACK matched\n"); goto found; } /* ACK */ } /* synonym loop */ notfound: if (e2e_ack_trans) { p_cell=e2e_ack_trans; goto e2e_ack; } /* no transaction found */ set_t(0); if (!leave_new_locked) { UNLOCK_HASH(p_msg->hash_index); } DBG("DEBUG: t_lookup_request: no transaction found\n"); return -1; e2e_ack: t_ack=p_cell; /* e2e proxied ACK */ set_t(0); if (!leave_new_locked) { UNLOCK_HASH(p_msg->hash_index); } DBG("DEBUG: t_lookup_request: e2e proxy ACK found\n"); return -2; found: set_t(p_cell); REF_UNSAFE( T ); set_kr(REQ_EXIST); UNLOCK_HASH( p_msg->hash_index ); DBG("DEBUG: t_lookup_request: transaction found (T=%p)\n",T); return 1; }
int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked ) { struct cell *p_cell; unsigned int isACK; struct sip_msg *t_msg; struct via_param *branch; int match_status; isACK = p_msg->REQ_METHOD==METHOD_ACK; if (isACK) { if (e2eack_T==NULL) return -1; if (e2eack_T!=T_UNDEFINED) return -2; } /* parse all*/ if (check_transaction_quadruple(p_msg)==0) { LM_ERR("too few headers\n"); set_t(0); /* stop processing */ return 0; } /* start searching into the table */ if (!p_msg->hash_index) p_msg->hash_index=tm_hash( p_msg->callid->body , get_cseq(p_msg)->number ) ; LM_DBG("start searching: hash=%d, isACK=%d\n", p_msg->hash_index,isACK); /* first of all, look if there is RFC3261 magic cookie in branch; if * so, we can do very quick matching and skip the old-RFC bizzar * comparison of many header fields */ if (!p_msg->via1) { LM_ERR("no via\n"); set_t(0); return 0; } branch=p_msg->via1->branch; if (branch && branch->value.s && branch->value.len>MCOOKIE_LEN && memcmp(branch->value.s,MCOOKIE,MCOOKIE_LEN)==0) { /* huhuhu! the cookie is there -- let's proceed fast */ LOCK_HASH(p_msg->hash_index); match_status=matching_3261(p_msg,&p_cell, /* skip transactions with different method; otherwise CANCEL * would match the previous INVITE trans. */ isACK ? ~METHOD_INVITE: ~p_msg->REQ_METHOD); switch(match_status) { case 0: goto notfound; /* no match */ case 1: goto found; /* match */ case 2: goto e2e_ack; /* e2e proxy ACK */ } } /* ok -- it's ugly old-fashioned transaction matching -- it is * a bit simplified to be fast -- we don't do all the comparisons * of parsed uri, which was simply too bloated */ LM_DBG("proceeding to pre-RFC3261 transaction matching\n"); /* lock the whole entry*/ LOCK_HASH(p_msg->hash_index); /* all the transactions from the entry are compared */ for ( p_cell = get_tm_table()->entrys[p_msg->hash_index].first_cell; p_cell; p_cell = p_cell->next_cell ) { t_msg = p_cell->uas.request; if (!t_msg) continue; /* skip UAC transactions */ if (!isACK) { /* compare lengths first */ if (!EQ_LEN(callid)) continue; if (!EQ_LEN(cseq)) continue; if (!EQ_LEN(from)) continue; if (!EQ_LEN(to)) continue; if (ruri_matching && !EQ_REQ_URI_LEN) continue; if (via1_matching && !EQ_VIA_LEN(via1)) continue; /* length ok -- move on */ if (!EQ_STR(callid)) continue; if (!EQ_STR(cseq)) continue; if (!EQ_STR(from)) continue; if (!EQ_STR(to)) continue; if (ruri_matching && !EQ_REQ_URI_STR) continue; if (via1_matching && !EQ_VIA_STR(via1)) continue; /* request matched ! */ LM_DBG("non-ACK matched\n"); goto found; } else { /* it's an ACK request*/ /* ACK's relate only to INVITEs - and we look only for 2 types of * INVITEs : (a) negative INVITEs or (b) pozitive UAS INVITEs */ if ( t_msg->REQ_METHOD!=METHOD_INVITE || !(p_cell->uas.status>=300 || (p_cell->nr_of_outgoings==0 && p_cell->uas.status>=200)) ) continue; /* From|To URI , CallID, CSeq # must be always there */ /* compare lengths now */ if (!EQ_LEN(callid)) continue; /* CSeq only the number without method ! */ if (get_cseq(t_msg)->number.len!=get_cseq(p_msg)->number.len) continue; if (! EQ_LEN(from)) continue; /* To only the uri -- to many UACs screw up tags */ if (get_to(t_msg)->uri.len!=get_to(p_msg)->uri.len) continue; if (!EQ_STR(callid)) continue; if (memcmp(get_cseq(t_msg)->number.s, get_cseq(p_msg)->number.s, get_cseq(p_msg)->number.len)!=0) continue; if (!EQ_STR(from)) continue; if (memcmp(get_to(t_msg)->uri.s, get_to(p_msg)->uri.s, get_to(t_msg)->uri.len)!=0) continue; if (p_cell->uas.status<300) { /* it's a 2xx local UAS transaction */ if (dlg_matching(p_cell, p_msg)) goto e2e_ack; continue; } /* it is not an e2e ACK/200 -- perhaps it is * local negative case; in which case we will want * more elements to match: r-uri and via; allow * mismatching r-uri as an config option for broken * UACs */ if (ruri_matching && !EQ_REQ_URI_LEN ) continue; if (via1_matching && !EQ_VIA_LEN(via1)) continue; if (ruri_matching && !EQ_REQ_URI_STR) continue; if (via1_matching && !EQ_VIA_STR(via1)) continue; /* wow -- we survived all the check! we matched! */ LM_DBG("non-2xx ACK matched\n"); goto found; } /* ACK */ } /* synonym loop */ notfound: /* no transaction found */ set_t(0); e2eack_T = NULL; if (!leave_new_locked || isACK) { UNLOCK_HASH(p_msg->hash_index); } LM_DBG("no transaction found\n"); return -1; e2e_ack: REF_UNSAFE( p_cell ); UNLOCK_HASH(p_msg->hash_index); e2eack_T = p_cell; set_t(0); LM_DBG("e2e proxy ACK found\n"); return -2; found: set_t(p_cell); REF_UNSAFE( T ); set_kr(REQ_EXIST); UNLOCK_HASH( p_msg->hash_index ); LM_DBG("transaction found (T=%p)\n",T); if (has_tran_tmcbs( T, TMCB_MSG_MATCHED_IN) ) run_trans_callbacks( TMCB_MSG_MATCHED_IN, T, p_msg, 0,0); return 1; }