modules/tm/t_lookup.c
dda9dab1
 /*
  * $Id$
  *
1f377e97
  * This C-file takes care of matching requests and replies with
  * existing transactions. Note that we do not do SIP-compliant
  * request matching as asked by SIP spec. We do bitwise matching of 
  * all header fields in requests which form a transaction key. 
84d8e165
  * It is much faster and it works pretty well -- we haven't 
1f377e97
  * had any interop issue neither in lab nor in bake-offs. The reason
  * is that retransmissions do look same as original requests
84d8e165
  * (it would be really silly if they would be mangled). The only
1f377e97
  * exception is we parse To as To in ACK is compared to To in
  * reply and both  of them are constructed by different software.
  * 
  * As for reply matching, we match based on branch value -- that is
  * faster too. There are two versions .. with SYNONYMs #define
  * enabled, the branch includes ordinal number of a transaction
  * in a synonym list in hash table and is somewhat faster but
  * not reboot-resilient. SYNONYMs turned off are little slower
  * but work across reboots as well.
  *
  * The branch parameter is formed as follows:
  * SYNONYMS  on: hash.synonym.branch
caf80ae6
  * SYNONYMS off: hash.md5.branch
1f377e97
  *
  * -jiri
  *
7dd0b342
  *
84d8e165
  * Copyright (C) 2001-2003 FhG Fokus
7dd0b342
  *
  * This file is part of ser, a free SIP server.
  *
  * ser is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version
  *
  * For a license to use the ser software under conditions
  * other than those described here, or to purchase support for this
  * software, please contact iptel.org by e-mail at the following addresses:
  *    info@iptel.org
  *
  * ser is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License 
  * along with this program; if not, write to the Free Software 
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
d9a8cf3a
  *
  * History:
  * ----------
d531a5d5
  * 2003-01-23  options for disabling r-uri matching introduced (jiri)
1ea91058
  *              nameser_compat.h (andrei)
b2fcef3c
  * 2003-01-27  next baby-step to removing ZT - PRESERVE_ZT (jiri)
  * 2003-01-28  scratchpad removed (jiri)
  * 2003-02-13  init_rb() is proto indep. & it uses struct dest_info (andrei)
  * 2003-02-24  s/T_NULL/T_NULL_CELL/ to avoid redefinition conflict w/
  * 2003-02-27  3261 ACK/200 consumption bug removed (jiri)
  * 2003-02-28 scratchpad compatibility abandoned (jiri)
  * 2003-03-01  kr set through a function now (jiri)
  * 2003-03-06  dialog matching introduced for ACKs -- that's important for 
  *             INVITE UAS (like INVITE) and 200/ACK proxy matching (jiri)
  * 2003-03-29  optimization: e2e ACK matching only if callback installed
  *             (jiri)
  * 2003-03-30  set_kr for requests only (jiri)
  * 2003-04-04  bug_fix: RESPONSE_IN callback not called for local
  *             UAC transactions (jiri)
87405423
  * 2003-04-07  new transactions inherit on_negative and on_relpy from script
84d8e165
  *             variables on instantiation (jiri)
6ef782ab
  * 2003-04-30  t_newtran clean up (jiri)
3c3c0044
  * 2003-08-21  request lookups fixed to skip UAC transactions, 
  *             thanks Ed (jiri)
a70eb298
  * 2003-12-04  global TM callbacks switched to per transaction callbacks
  *             (bogdan)
c2ea965c
  * 2004-02-11  FIFO/CANCEL + alignments (hash=f(callid,cseq)) (uli+jiri)
0be6158b
  * 2004-02-13: t->is_invite and t->local replaced with flags (bogdan)
5f8c3fbf
  * 2004-10-10: use of mhomed disabled for replies (jiri)
ddaf2976
  * 2005-02-01: use the incoming request interface for sending the replies
  *             - changes in init_rb() (bogdan)
ec76200f
  * 2005-12-09  added t_set_fr()  (andrei)
  * 2006-01-27  transaction lookup function will set up a cancel flag
  *             if the searched transaction was pre-canceled (andrei)
3ed13e77
  * 2006-10-16  401 & 407 replies are completely parsed if tm_aggregate_auth is
  *              set (andrei)
0575e3b1
  * 2006-11-10  a valid msg->hash_index is now marked by FL_HASH_INDEX in 
  *              msg_flags
  *             t_lookupOriginalT computes the hash_index by itself  if 
1b8b2899
  *               needed (andrei)
  * 2007-03-17  added callbacks for retransmitted request, ack to negative 
  *              replies and replies to local transactions (andrei)
c0ff60b6
  * 2007-06-01  support for different retransmissions intervals per transaction;
  *             added maximum inv. and non-inv. transaction life time (andrei)
b4a4494d
  * 2007-06-05  added delayed error reply support in t_unref;
 *              added support for turning off 100 repl. sending on inv. (andrei)
  * 2007-06-01  support for different retransmissions intervals per transaction;
  *             added maximum inv. and non-inv. transaction life time (andrei)
99e9192a
  * 2007-06-06  switched tm bucket list to a simpler and faster clist;
7dfb5eff
  * 2008-02-28  try matching e2e acks in t_lookup() only for transactions
  *               which have E2EACK callbacks registered (andrei)
989c2658
  * 2008-03-31  message flags are updated in shared memory even if they are set
  *             after t_newtran() (Miklos)
30ea1726
  * 2009-06-24  added T_branch and changed set_t() to take also a branch
  *              parameter (andrei)
dda9dab1
  */
 
ff979952
 #include "defs.h"
 
 
1540fad1
 #include "../../comp_defs.h"
66298eb4
 #include "../../compiler_opt.h"
dda9dab1
 #include "../../dprint.h"
 #include "../../config.h"
3881f12c
 #include "../../parser/parser_f.h"
fde02f64
 #include "../../parser/parse_from.h"
dda9dab1
 #include "../../ut.h"
 #include "../../timer.h"
57857a94
 #include "../../timer_ticks.h"
caf80ae6
 #include "../../hash_func.h"
 #include "../../globals.h"
 #include "../../forward.h"
b0570a15
 #include "t_funcs.h"
 #include "config.h"
3d2e8729
 #include "sip_msg.h"
1400b772
 #include "t_hooks.h"
49a20a49
 #include "t_fwd.h"
caf80ae6
 #include "t_lookup.h"
c2ea965c
 #include "dlg.h" /* for t_lookup_callid */
 #include "t_msgbuilder.h" /* for t_lookup_callid */
dda9dab1
 
049f64c2
 #define EQ_VIA_LEN(_via)\
 	( (p_msg->via1->bsize-(p_msg->_via->name.s-(p_msg->_via->hdr.s+p_msg->_via->hdr.len)))==\
 	  	(t_msg->via1->bsize-(t_msg->_via->name.s-(t_msg->_via->hdr.s+t_msg->_via->hdr.len))) )
 
 
baa4fa73
 
 #define EQ_LEN(_hf) (t_msg->_hf->body.len==p_msg->_hf->body.len)
049f64c2
 #define EQ_REQ_URI_LEN\
 	(p_msg->first_line.u.request.uri.len==t_msg->first_line.u.request.uri.len)
 
 #define EQ_STR(_hf) (memcmp(t_msg->_hf->body.s,\
 	p_msg->_hf->body.s, \
 	p_msg->_hf->body.len)==0)
 #define EQ_REQ_URI_STR\
 	( memcmp( t_msg->first_line.u.request.uri.s,\
 	p_msg->first_line.u.request.uri.s,\
 	p_msg->first_line.u.request.uri.len)==0)
 #define EQ_VIA_STR(_via)\
 	( memcmp( t_msg->_via->name.s,\
 	 p_msg->_via->name.s,\
 	 (t_msg->via1->bsize-(t_msg->_via->name.s-(t_msg->_via->hdr.s+t_msg->_via->hdr.len)))\
 	)==0 )
 
 
baa4fa73
 
1540fad1
 #define HF_LEN(_hf) ((_hf)->len)
caf80ae6
 
b5f0a0b6
 /* presumably matching transaction for an e2e ACK */
 static struct cell *t_ack;
 
caf80ae6
 /* this is a global variable which keeps pointer to
    transaction currently processed by a process; it it
    set by t_lookup_request or t_reply_matching; don't
    dare to change it anywhere else as it would
30ea1726
    break ref_counting.
    It has a valid value only if:
     - it's checked inside a failure or tm on_reply route (not core 
       on_reply[0]!)
     - global_msg_id == msg->id in all the other kinds of routes
       Note that this is the safest check and is valid also for
       failure routes (because fake_env() sets global_msg_id) or tm
       tm onreply routes (the internal reply_received() t_check() will set
       T and global_msg_id).
caf80ae6
 */
 static struct cell *T;
 
30ea1726
 /* this is a global variable which keeps the current branch
    for the transaction currently processed.
    It has a valid value only if T is valid (global_msg_id==msg->id -- see
    above, and T!=0 and T!=T_UNDEFINED).
    For a request it's value is T_BR_UNDEFINED (it can have valid values only
    for replies).
 */
 static int T_branch;
 
caf80ae6
 /* number of currently processed message; good to know
    to be able to doublecheck whether we are still working
    on a current transaction or a new message arrived;
30ea1726
    don't even think of changing it.
caf80ae6
 */
 unsigned int     global_msg_id;
 
b4a4494d
 
 
caf80ae6
 struct cell *get_t() { return T; }
30ea1726
 void set_t(struct cell *t, int branch) { T=t; T_branch=branch; }
 void init_t() {global_msg_id=0; set_t(T_UNDEFINED, T_BR_UNDEFINED);}
 int get_t_branch() { return T_branch; }
caf80ae6
 
fde02f64
 static inline int parse_dlg( struct sip_msg *msg )
 {
5c28a534
 	if (parse_headers(msg, HDR_FROM_F | HDR_CSEQ_F | HDR_TO_F, 0)==-1) {
1d4c5c00
 		LOG(L_ERR, "ERROR: parse_dlg: From or Cseq or To invalid\n");
fde02f64
 		return 0;
 	}
a512f028
 	if ((msg->from==0)||(msg->cseq==0)||(msg->to==0)) {
 		LOG(L_ERR, "ERROR: parse_dlg: missing From or Cseq or To\n");
 		return 0;
 	}
 
fde02f64
 	if (parse_from_header(msg)==-1) {
1d4c5c00
 		LOG(L_ERR, "ERROR: parse_dlg: From broken\n");
fde02f64
 		return 0;
 	}
 	/* To is automatically parsed through HDR_TO in parse bitmap,
 	 * we don't need to worry about it now
 	if (parse_to_header(msg)==-1) {
 		LOG(L_ERR, "ERROR: tid_matching: To broken\n");
 		return 0;
 	}
 	*/
 	return 1;
 }
 
 /* is the ACK (p_msg) in p_msg dialog-wise equal to the INVITE (t_msg) 
  * except to-tags? */
 static inline int partial_dlg_matching(struct sip_msg *t_msg, struct sip_msg *p_msg)
 {
 	struct to_body *inv_from;
 
 	if (!EQ_LEN(callid)) return 0;
 	if (get_cseq(t_msg)->number.len!=get_cseq(p_msg)->number.len)
 		return 0;
 	inv_from=get_from(t_msg);
 	if (!inv_from) {
 		LOG(L_ERR, "ERROR: partial_dlg_matching: INV/From not parsed\n");
 		return 0;
 	}
 	if (inv_from->tag_value.len!=get_from(p_msg)->tag_value.len)
 		return 0;
 	if (!EQ_STR(callid)) 
 		return 0;
 	if (memcmp(get_cseq(t_msg)->number.s, get_cseq(p_msg)->number.s,
 			get_cseq(p_msg)->number.len)!=0)
 		return 0;
 	if (memcmp(inv_from->tag_value.s, get_from(p_msg)->tag_value.s,
 			get_from(p_msg)->tag_value.len)!=0)
 		return 0;
 	return 1;
 }
 
 /* are to-tags in ACK/200 same as those we sent out? */
 static inline int dlg_matching(struct cell *p_cell, struct sip_msg *ack )
 {
 	if (get_to(ack)->tag_value.len!=p_cell->uas.local_totag.len)
 		return 0;
 	if (memcmp(get_to(ack)->tag_value.s,p_cell->uas.local_totag.s,
 				p_cell->uas.local_totag.len)!=0)
 		return 0;
 	return 1;
 }
 
7dfb5eff
 
 
 /* returns 2 if one of the save totags matches the totag in the current
  * message (which should be an ACK) and 0 if not */
 static inline int totag_e2e_ack_matching(struct cell* p_cell, 
 												struct sip_msg *ack)
 {
 	struct totag_elem *i;
 	str *tag;
 	
 	tag=&get_to(ack)->tag_value;
 	/* no locking needed for reading/searching, see update_totag_set() */
 	for (i=p_cell->fwded_totags; i; i=i->next){
 		membar_depends(); /* make sure we don't see some old i content
 							(needed on CPUs like Alpha) */
 		if (i->tag.len==tag->len && memcmp(i->tag.s, tag->s, tag->len)==0) {
 			return 2;
 		}
 	}
 	return 0;
 }
 
 
 
 /* returns: 0 - no match
  *          1 - full match to a local transaction
  *          2 - full match to a proxied transaction
  *          3 - partial match to a proxied transaction (totag not checked) =>
  *          care must be taken not to falsely match an ACK for a negative
  *          reply to a "fork" of the transaction
  */
fde02f64
 static inline int ack_matching(struct cell *p_cell, struct sip_msg *p_msg) 
 {
 	/* partial dialog matching -- no to-tag, only from-tag, 
 	 * callid, cseq number ; */
 	if (!partial_dlg_matching(p_cell->uas.request, p_msg)) 
 		return 0;
 
   	/* if this transaction is proxied (as opposed to UAS) we're
 	 * done now -- we ignore to-tags; the ACK simply belongs to
 	 * this UAS part of dialog, whatever to-tag it gained
 	 */
7dfb5eff
 	if (likely(p_cell->relayed_reply_branch!=-2)) {
 		if (likely(has_tran_tmcbs(p_cell, 
 							TMCB_E2EACK_IN|TMCB_E2EACK_RETR_IN)))
 			return totag_e2e_ack_matching(p_cell, p_msg); /* 2 or 0 */
 		else
 			LOG(L_WARN, "WARNING: ack_matching() attempted on"
 					" a transaction with no E2EACK callbacks => the results"
 					" are not completely reliable when forking is involved\n");
 		return 3; /* e2e proxied ACK partial match */
fde02f64
 	}
 	/* it's a local dialog -- we wish to verify to-tags too */
 	if (dlg_matching(p_cell, p_msg)) {
 		return 1;
 	}
 	return 0;
 }
 
 /* branch-based transaction matching */
 static inline int via_matching( struct via_body *inv_via, 
 				struct via_body *ack_via )
 {
 	if (inv_via->tid.len!=ack_via->tid.len)
 		return 0;
 	if (memcmp(inv_via->tid.s, ack_via->tid.s,
 				ack_via->tid.len)!=0)
 		return 0;
 	/* ok, tid matches -- now make sure that the
84d8e165
 	 * originator matches too to avoid confusion with
fde02f64
 	 * different senders generating the same tid
 	 */
 	if (inv_via->host.len!=ack_via->host.len)
 		return 0;;
 	if (memcmp(inv_via->host.s, ack_via->host.s,
 			ack_via->host.len)!=0)
 		return 0;
 	if (inv_via->port!=ack_via->port)
 		return 0;
 	if (inv_via->transport.len!=ack_via->transport.len)
 		return 0;
 	if (memcmp(inv_via->transport.s, ack_via->transport.s,
 			ack_via->transport.len)!=0)
 		return 0;
 	/* everything matched -- we found it */
 	return 1;
 }
 
baa4fa73
 
3bd0930b
 /* transaction matching a-la RFC-3261 using transaction ID in branch
fde02f64
    (the function assumes there is magic cookie in branch) 
    It returns:
 	 2 if e2e ACK for a proxied transaction found
      1  if found (covers ACK for local UAS)
 	 0  if not found (trans undefined)
ec76200f
 	It also sets *cancel if a cancel was found for the searched transaction
fde02f64
 */
3bd0930b
 
fde02f64
 static int matching_3261( struct sip_msg *p_msg, struct cell **trans,
ec76200f
 			enum request_method skip_method, int* cancel)
3bd0930b
 {
 	struct cell *p_cell;
7dfb5eff
 	struct cell *e2e_ack_trans;
3bd0930b
 	struct sip_msg  *t_msg;
fde02f64
 	struct via_body *via1;
 	int is_ack;
 	int dlg_parsed;
31d48be0
 	int ret = 0;
99e9192a
 	struct entry* hash_bucket;
3bd0930b
 
ec76200f
 	*cancel=0;
81ff9d36
 	e2e_ack_trans=0;
fde02f64
 	via1=p_msg->via1;
 	is_ack=p_msg->REQ_METHOD==METHOD_ACK;
 	dlg_parsed=0;
3bd0930b
 	/* update parsed tid */
 	via1->tid.s=via1->branch->value.s+MCOOKIE_LEN;
 	via1->tid.len=via1->branch->value.len-MCOOKIE_LEN;
 
99e9192a
 	hash_bucket=&(get_tm_table()->entries[p_msg->hash_index]);
 	clist_foreach(hash_bucket, p_cell, next_c){
 		prefetch_loc_r(p_cell->next_c, 1);
3bd0930b
 		t_msg=p_cell->uas.request;
a36d396e
 		if (unlikely(!t_msg)) continue;/*don't try matching UAC transactions */
ec76200f
 		/* we want to set *cancel for transaction for which there is
 		 * already a canceled transaction (e.g. re-ordered INV-CANCEL, or
 		 *  INV blocked in dns lookup); we don't care about ACKs */
 		if ((is_ack || (t_msg->REQ_METHOD!=METHOD_CANCEL)) && 
 				(skip_method & t_msg->REQ_METHOD)) 
 			continue;
fde02f64
 
81ff9d36
 		/* here we do an exercise which will be removed from future code
 		   versions: we try to match end-2-end ACKs if they appear at our
 		   server. This allows some applications bound to TM via callbacks
 		   to correlate the e2e ACKs with transaction context, e.g., for
 		   purpose of accounting. We think it is a bad place here, among
 		   other things because it is not reliable. If a transaction loops
 		   via SER the ACK can't be matched to proper INVITE transaction
 		   (it is a separate transactino with its own branch ID) and it
 		   matches all transaction instances in the loop dialog-wise.
 		   Eventually, regardless to which transaction in the loop the
 		   ACK belongs, only the first one will match.
 		*/
 
7dfb5eff
 		/* dialog matching needs to be applied for ACK/200s but only if
 		 * this is a local transaction or its a proxied transaction interested
 		 *  in e2e ACKs (has E2EACK* callbacks installed) */
 		if (unlikely(is_ack && p_cell->uas.status<300)) {
 			if (unlikely(has_tran_tmcbs(p_cell, 
 							TMCB_E2EACK_IN|TMCB_E2EACK_RETR_IN) ||
 							(p_cell->relayed_reply_branch==-2)  )) {
 				/* make sure we have parsed all things we need for dialog
 				 * matching */
 				if (!dlg_parsed) {
 					dlg_parsed=1;
 					if (unlikely(!parse_dlg(p_msg))) {
 						LOG(L_INFO, "ERROR: matching_3261: dlg parsing "
 								"failed\n");
 						return 0;
 					}
fde02f64
 				}
7dfb5eff
 				ret=ack_matching(p_cell /* t w/invite */, p_msg /* ack */);
 				if (unlikely(ret>0)) {
 					/* if ret==1 => fully matching e2e ack for local trans 
 					 * if ret==2 => matching e2e ack for proxied  transaction.
 					 *  which is interested in it (E2EACK* callbacks)
 					 * if ret==3 => partial match => we should at least
 					 *  make sure the ACK is not for a negative reply
 					 *  (FIXME: ret==3 should never happen, it's a bug catch
 					 *    case)*/
 					if (unlikely(ret==1)) goto found;
 					if (unlikely(ret==3)){
 						if (e2e_ack_trans==0)
 							e2e_ack_trans=p_cell;
 						continue; /* maybe we get a better 
 													   match for a neg. 
 													   replied trans. */
 					}
 					e2e_ack_trans=p_cell;
 					goto e2eack_found;
 				}
 				/* this ACK is neither local "negative" one, nor a proxied
 				* end-2-end one, nor an end-2-end one for a UAS transaction
 				* -- we failed to match */
a36d396e
 				continue;
fde02f64
 			}
7dfb5eff
 			/* not interested, it's an ack and a 2xx replied
 			  transaction but the transaction is not local and
 			  the transaction is not interested in e2eacks (no e2e callbacks)*/
3bd0930b
 			continue;
fde02f64
 		}
 		/* now real tid matching occurs  for negative ACKs and any 
 	 	 * other requests */
 		if (!via_matching(t_msg->via1 /* inv via */, via1 /* ack */ ))
3bd0930b
 			continue;
ec76200f
 		if (t_msg->REQ_METHOD==METHOD_CANCEL){
 			if ((p_msg->REQ_METHOD!=METHOD_CANCEL) && !is_ack){
 			/* found an existing cancel for the searched transaction */
 				*cancel=1;
 			}
 			if (skip_method & t_msg->REQ_METHOD) continue;
 		}
a36d396e
 found:
99e9192a
 		prefetch_w(p_cell); /* great chance of modifiying it */
3bd0930b
 		/* all matched -- we found the transaction ! */
 		DBG("DEBUG: RFC3261 transaction matched, tid=%.*s\n",
 			via1->tid.len, via1->tid.s);
fde02f64
 		*trans=p_cell;
 		return 1;
3bd0930b
 	}
 	/* :-( ... we didn't find any */
81ff9d36
 	
a36d396e
 	/* just check if it we found an e2e ACK previously
 	 * (Note: this is not very reliable, since we match e2e proxy ACKs
 	 *  w/o totag => for a pre-forked invite it might match the wrong
 	 *  transaction) */
81ff9d36
 	if (e2e_ack_trans) {
7dfb5eff
 e2eack_found:
81ff9d36
 		*trans=e2e_ack_trans;
a36d396e
 		return 2;
81ff9d36
 	}
3bd0930b
 	DBG("DEBUG: RFC3261 transaction matching failed\n");
 	return 0;
 }
 
 
85529b20
 /** find the transaction corresponding to a request.
  *  @return - negative - transaction wasn't found (-1) or
  *                        possible e2eACK match (-2).
  *            1        - transaction found
  *            0        - parse error
  * It also sets *cancel if there is already a cancel transaction.
30ea1726
  * Side-effects: sets T and T_branch 
  * (T_branch is always set to T_BR_UNDEFINED).
1400b772
  */
 
ec76200f
 int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked,
 						int* cancel)
1400b772
 {
 	struct cell         *p_cell;
 	unsigned int       isACK;
 	struct sip_msg  *t_msg;
 	int ret;
3bd0930b
 	struct via_param *branch;
fde02f64
 	int match_status;
81ff9d36
 	struct cell *e2e_ack_trans;
99e9192a
 	struct entry* hash_bucket;
1400b772
 
 	/* parse all*/
99e9192a
 	if (unlikely(check_transaction_quadruple(p_msg)==0))
1400b772
 	{
 		LOG(L_ERR, "ERROR: TM module: t_lookup_request: too few headers\n");
30ea1726
 		set_t(0, T_BR_UNDEFINED);
1400b772
 		/* stop processing */
 		return 0;
 	}
 
 	/* start searching into the table */
0575e3b1
 	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;
 	}
1400b772
 	isACK = p_msg->REQ_METHOD==METHOD_ACK;
 	DBG("t_lookup_request: start searching: hash=%d, isACK=%d\n",
 		p_msg->hash_index,isACK);
 
3bd0930b
 
84d8e165
 	/* assume not found */
1400b772
 	ret=-1;
81ff9d36
 	e2e_ack_trans = 0;
1400b772
 
3bd0930b
 	/* 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");
30ea1726
 		set_t(0, T_BR_UNDEFINED);
3bd0930b
 		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);
fde02f64
 		match_status=matching_3261(p_msg,&p_cell, 
ec76200f
 				/* skip transactions with different method; otherwise CANCEL 
 				 * would  match the previous INVITE trans.  */
 				isACK ? ~METHOD_INVITE: ~p_msg->REQ_METHOD, 
 				cancel);
fde02f64
 		switch(match_status) {
 				case 0:	goto notfound;	/* no match */
99e9192a
 				case 1:	 goto found; 	/* match */
fde02f64
 				case 2:	goto e2e_ack;	/* e2e proxy ACK */
 		}
3bd0930b
 	}
 
fde02f64
 	/* 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 */
3bd0930b
 	DBG("DEBUG: proceeding to pre-RFC3261 transaction matching\n");
ec76200f
 	*cancel=0;
3bd0930b
 	/* lock the whole entry*/
caf80ae6
 	LOCK_HASH(p_msg->hash_index);
1400b772
 
99e9192a
 	hash_bucket=&(get_tm_table()->entries[p_msg->hash_index]);
f34a5e13
 	
 	if (likely(!isACK)) {	
 		/* all the transactions from the entry are compared */
 		clist_foreach(hash_bucket, p_cell, next_c){
 			prefetch_loc_r(p_cell->next_c, 1);
 			t_msg = p_cell->uas.request;
 			if (!t_msg) continue; /* skip UAC transactions */
ec76200f
 			/* 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;
1400b772
 			/* compare lengths first */ 
 			if (!EQ_LEN(callid)) continue;
ec76200f
 			/* CSeq only the number without method ! */
 			if (get_cseq(t_msg)->number.len!=get_cseq(p_msg)->number.len)
 				continue;
1400b772
 			if (!EQ_LEN(from)) continue;
 			if (!EQ_LEN(to)) continue;
f34a5e13
 			if (cfg_get(tm, tm_cfg, ruri_matching) && !EQ_REQ_URI_LEN) 
 				continue;
 			if (cfg_get(tm, tm_cfg, via1_matching) && !EQ_VIA_LEN(via1))
 				continue;
1400b772
 			/* length ok -- move on */
 			if (!EQ_STR(callid)) continue;
ec76200f
 			if (memcmp(get_cseq(t_msg)->number.s, get_cseq(p_msg)->number.s,
 				get_cseq(p_msg)->number.len)!=0) continue;
1400b772
 			if (!EQ_STR(from)) continue;
 			if (!EQ_STR(to)) continue;
f34a5e13
 			if (cfg_get(tm, tm_cfg, ruri_matching) && !EQ_REQ_URI_STR)
 				continue;
 			if (cfg_get(tm, tm_cfg, via1_matching) && !EQ_VIA_STR(via1))
 				continue;
ec76200f
 			
 			if ((t_msg->REQ_METHOD==METHOD_CANCEL) &&
 				(p_msg->REQ_METHOD!=METHOD_CANCEL)){
 				/* we've matched an existing CANCEL */
 				*cancel=1;
 				continue;
 			}
 			
1400b772
 			/* request matched ! */
 			DBG("DEBUG: non-ACK matched\n");
 			goto found;
f34a5e13
 		} /* synonym loop */
 	} else { /* it's an ACK request*/
 		/* all the transactions from the entry are compared */
 		clist_foreach(hash_bucket, p_cell, next_c){
 			prefetch_loc_r(p_cell->next_c, 1);
 			t_msg = p_cell->uas.request;
 			if (!t_msg) continue; /* skip UAC transactions */
1400b772
 			/* ACK's relate only to INVITEs */
 			if (t_msg->REQ_METHOD!=METHOD_INVITE) continue;
fde02f64
 			/* From|To URI , CallID, CSeq # must be always there */
1400b772
 			/* 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;
fde02f64
 			/* To only the uri -- to many UACs screw up tags  */
1400b772
 			if (get_to(t_msg)->uri.len!=get_to(p_msg)->uri.len)
 				continue;
fde02f64
 			if (!EQ_STR(callid)) continue;
 			if (memcmp(get_cseq(t_msg)->number.s, get_cseq(p_msg)->number.s,
1400b772
 				get_cseq(p_msg)->number.len)!=0) continue;
 			if (memcmp(get_to(t_msg)->uri.s, get_to(p_msg)->uri.s,
 				get_to(t_msg)->uri.len)!=0) continue;
f34a5e13
 			
fde02f64
 			/* it is e2e ACK/200 */
7dfb5eff
 			if (p_cell->uas.status<300) {
eddf3e3b
 				/* For e2e ACKs, From's tag 'MUST' equal INVITE's, while use
 				 * of the URI in this case is to be deprecated (Sec. 12.2.1.1).
 				 * Comparing entire From body is dangerous, since some UAs
 				 * screw the display name up. */
 				if (parse_from_header(p_msg) < 0) {
 					ERR("failed to parse From HF; ACK might not match.\n");
 					continue;
 				}
 				if (! STR_EQ(get_from(t_msg)->tag_value, 
 						get_from(p_msg)->tag_value))
 					continue;
 #ifdef TM_E2E_ACK_CHECK_FROM_URI
 				if (! STR_EQ(get_from(t_msg)->uri, 
 						get_from(p_msg)->uri))
 					continue;
 #endif
 
fde02f64
 				/* all criteria for proxied ACK are ok */
7dfb5eff
 				if (likely(p_cell->relayed_reply_branch!=-2)) {
 					if (unlikely(has_tran_tmcbs(p_cell, 
 									TMCB_E2EACK_IN|TMCB_E2EACK_RETR_IN))){
 						if (likely(totag_e2e_ack_matching(p_cell, p_msg)==2))
 							goto e2e_ack;
 						else if (e2e_ack_trans==0)
 							e2e_ack_trans=p_cell;
 					}
81ff9d36
 					continue;
 				}
fde02f64
 				/* it's a local UAS transaction */
 				if (dlg_matching(p_cell, p_msg))
 					goto found;
 				continue;
eddf3e3b
 			} else {
 				/* for hbh ACKs, From HF 'MUST' equal INVITE's one */
 				if (! EQ_LEN(from)) continue;
 				if (! EQ_STR(from)) continue;
1400b772
 			}
f34a5e13
 			
fde02f64
 			/* 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 */
f34a5e13
 			if (cfg_get(tm, tm_cfg, ruri_matching) && !EQ_REQ_URI_LEN )
 				continue;
 			if (cfg_get(tm, tm_cfg, via1_matching) && !EQ_VIA_LEN(via1))
 				continue;
 			if (cfg_get(tm, tm_cfg, ruri_matching) && !EQ_REQ_URI_STR)
 				continue;
 			if (cfg_get(tm, tm_cfg, via1_matching) && !EQ_VIA_STR(via1))
 				continue;
 			
1400b772
 			/* wow -- we survived all the check! we matched! */
 			DBG("DEBUG: non-2xx ACK matched\n");
 			goto found;
f34a5e13
 		} /* synonym loop */
 	} /* ACK */
1400b772
 
3bd0930b
 notfound:
81ff9d36
 
 	if (e2e_ack_trans) {
 		p_cell=e2e_ack_trans;
 		goto e2e_ack;
 	}
 		
1400b772
 	/* no transaction found */
30ea1726
 	set_t(0, T_BR_UNDEFINED);
caf80ae6
 	if (!leave_new_locked) {
 		UNLOCK_HASH(p_msg->hash_index);
af64f4fb
 	}
 	DBG("DEBUG: t_lookup_request: no transaction found\n");
fde02f64
 	return -1;
 
 e2e_ack:
 	t_ack=p_cell;	/* e2e proxied ACK */
30ea1726
 	set_t(0, T_BR_UNDEFINED);
fde02f64
 	if (!leave_new_locked) {
 		UNLOCK_HASH(p_msg->hash_index);
 	}
 	DBG("DEBUG: t_lookup_request: e2e proxy ACK found\n");
 	return -2;
dda9dab1
 
 found:
30ea1726
 	set_t(p_cell, T_BR_UNDEFINED);
caf80ae6
 	REF_UNSAFE( T );
fde02f64
 	set_kr(REQ_EXIST);
caf80ae6
 	UNLOCK_HASH( p_msg->hash_index );
 	DBG("DEBUG: t_lookup_request: transaction found (T=%p)\n",T);
af64f4fb
 	return 1;
dda9dab1
 }
 
 
 
84d8e165
 /* function lookups transaction being canceled by CANCEL in p_msg;
3bd0930b
  * it returns:
dda9dab1
  *       0 - transaction wasn't found
  *       T - transaction found
  */
b1f1656e
 struct cell* t_lookupOriginalT(  struct sip_msg* p_msg )
dda9dab1
 {
549d5e1c
 	struct cell     *p_cell;
caf80ae6
 	unsigned int     hash_index;
 	struct sip_msg  *t_msg;
3bd0930b
 	struct via_param *branch;
99e9192a
 	struct entry* hash_bucket;
ec76200f
 	int foo;
fde02f64
 	int ret;
dda9dab1
 
 
caf80ae6
 	/* start searching in the table */
0575e3b1
 	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;
 	}
d3b31abd
 	hash_index = p_msg->hash_index;
549d5e1c
 	DBG("DEBUG: t_lookupOriginalT: searching on hash entry %d\n",hash_index );
 
3bd0930b
 
 	/* 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) {
1d4c5c00
 		LOG(L_ERR, "ERROR: t_lookupOriginalT: no via\n");
3bd0930b
 		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);
fde02f64
 		ret=matching_3261(p_msg, &p_cell,
3bd0930b
 				/* we are seeking the original transaction --
 				 * skip CANCEL transactions during search
 				 */
ec76200f
 				METHOD_CANCEL, &foo);
fde02f64
 		if (ret==1) goto found; else goto notfound;
3bd0930b
 	}
 
 	/* no cookies --proceed to old-fashioned pre-3261 t-matching */
 
 	LOCK_HASH(hash_index);
 
99e9192a
 	hash_bucket=&(get_tm_table()->entries[hash_index]);
549d5e1c
 	/* all the transactions from the entry are compared */
99e9192a
 	clist_foreach(hash_bucket, p_cell, next_c){
 		prefetch_loc_r(p_cell->next_c, 1);
46931a4d
 		t_msg = p_cell->uas.request;
549d5e1c
 
3c3c0044
 		if (!t_msg) continue; /* skip UAC transactions */
 
caf80ae6
 		/* we don't cancel CANCELs ;-) */
99e9192a
 		if (unlikely(t_msg->REQ_METHOD==METHOD_CANCEL))
caf80ae6
 			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;
15b681f5
 #ifdef CANCEL_TAG
caf80ae6
 		if (!EQ_LEN(to))
 			continue;
15b681f5
 #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
2b36d889
 		if (cfg_get(tm, tm_cfg, ruri_matching) && !EQ_REQ_URI_LEN)
caf80ae6
 			continue;
2b36d889
 		if (cfg_get(tm, tm_cfg, via1_matching) && !EQ_VIA_LEN(via1))
caf80ae6
 			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;
15b681f5
 #ifdef CANCEL_TAG
caf80ae6
 		if (!EQ_STR(to))
 			continue;
15b681f5
 #else
 		if (memcmp(get_to(t_msg)->uri.s, get_to(p_msg)->uri.s,
 					get_to(t_msg)->uri.len)!=0)
 			continue;
 #endif
2b36d889
 		if (cfg_get(tm, tm_cfg, ruri_matching) && !EQ_REQ_URI_STR)
caf80ae6
 			continue;
2b36d889
 		if (cfg_get(tm, tm_cfg, via1_matching) && !EQ_VIA_STR(via1))
caf80ae6
 			continue;
 
 		/* found */
3bd0930b
 		goto found;
549d5e1c
 	}
 
3bd0930b
 notfound:
549d5e1c
 	/* no transaction found */
84d8e165
 	DBG("DEBUG: t_lookupOriginalT: no CANCEL matching found! \n" );
141123d4
 	UNLOCK_HASH(hash_index);
 	DBG("DEBUG: t_lookupOriginalT completed\n");
549d5e1c
 	return 0;
3bd0930b
 
 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;
dda9dab1
 }
 
 
 
 
85529b20
 /** get the transaction corresponding to a reply.
  * @return -1 - nothing found,  1  - T found
30ea1726
  * Side-effects: sets T and T_branch on success.
549d5e1c
  */
caf80ae6
 int t_reply_matching( struct sip_msg *p_msg , int *p_branch )
dda9dab1
 {
3b84d176
 	struct cell*  p_cell;
33d814e0
 	unsigned int hash_index   = 0;
3d942590
 	unsigned int entry_label  = 0;
33d814e0
 	unsigned int branch_id    = 0;
40633485
 	char  *hashi, *branchi, *p, *n;
99e9192a
 	struct entry* hash_bucket;
40633485
 	int hashl, branchl;
3b84d176
 	int scan_space;
caf80ae6
 	str cseq_method;
 	str req_method;
 
6beabeca
 	char *loopi;
 	int loopl;
40633485
 	char *syni;
 	int synl;
caf80ae6
 	
 	short is_cancel;
 
84d8e165
 	/* make compiler warnings happy */
caf80ae6
 	loopi=0;
 	loopl=0;
 	syni=0;
 	synl=0;
3b84d176
 
 	/* split the branch into pieces: loop_detection_check(ignored),
549d5e1c
 	 hash_table_id, synonym_id, branch_id */
3b84d176
 
549d5e1c
 	if (!(p_msg->via1 && p_msg->via1->branch && p_msg->via1->branch->value.s))
3b84d176
 		goto nomatch2;
 
7958eeae
 	/* 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;
 
3b84d176
 
 	/* 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--;
 
caf80ae6
 	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--;
 	}
3b84d176
 
 	/* 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 */
99e9192a
 	if (unlikely(reverse_hex2int(hashi, hashl, &hash_index)<0
caf80ae6
 		||hash_index>=TABLE_ENTRIES
33d814e0
 		|| reverse_hex2int(branchi, branchl, &branch_id)<0
caf80ae6
 		||branch_id>=MAX_BRANCHES
33d814e0
 		|| (syn_branch ? (reverse_hex2int(syni, synl, &entry_label))<0 
99e9192a
 			: loopl!=MD5_LEN ))
549d5e1c
 	) {
84d8e165
 		DBG("DEBUG: t_reply_matching: poor reply labels %d label %d "
33d814e0
 			"branch %d\n", hash_index, entry_label, branch_id );
dda9dab1
 		goto nomatch2;
 	}
 
 
3b84d176
 	DBG("DEBUG: t_reply_matching: hash %d label %d branch %d\n",
549d5e1c
 		hash_index, entry_label, branch_id );
dda9dab1
 
 
1f377e97
 	/* search the hash table list at entry 'hash_index'; lock the
 	   entry first 
 	*/
caf80ae6
 	cseq_method=get_cseq(p_msg)->method;
 	is_cancel=cseq_method.len==CANCEL_LEN 
 		&& memcmp(cseq_method.s, CANCEL, CANCEL_LEN)==0;
 	LOCK_HASH(hash_index);
99e9192a
 	hash_bucket=&(get_tm_table()->entries[hash_index]);
 	/* all the transactions from the entry are compared */
 	clist_foreach(hash_bucket, p_cell, next_c){
 		prefetch_loc_r(p_cell->next_c, 1);
caf80ae6
 		/* first look if branch matches */
99e9192a
 		if (likely(syn_branch)) {
caf80ae6
 			if (p_cell->label != entry_label) 
1f377e97
 				continue;
caf80ae6
 		} else {
 			if ( memcmp(p_cell->md5, loopi,MD5_LEN)!=0)
 					continue;
 		}
 
1f377e97
 		/* sanity check ... too high branch ? */
99e9192a
 		if (unlikely(branch_id>=p_cell->nr_of_outgoings))
1f377e97
 			continue;
caf80ae6
 
 		/* does method match ? (remember -- CANCELs have the same branch
84d8e165
 		   as canceled transactions) */
caf80ae6
 		req_method=p_cell->method;
 		if ( /* method match */
 			! ((cseq_method.len==req_method.len 
 			&& memcmp( cseq_method.s, req_method.s, cseq_method.len )==0)
 			/* or it is a local cancel */
0be6158b
 			|| (is_cancel && is_invite(p_cell)
141123d4
 				/* commented out -- should_cancel_branch set it to
84d8e165
 				   BUSY_BUFFER to avoid collisions with replies;
 				   thus, we test here by buffer size
141123d4
 				*/
 				/* && p_cell->uac[branch_id].local_cancel.buffer ))) */
 				&& p_cell->uac[branch_id].local_cancel.buffer_len ))) 
caf80ae6
 			continue;
 
 
1f377e97
 		/* we passed all disqualifying factors .... the transaction has been
 		   matched !
 		*/
30ea1726
 		set_t(p_cell, (int)branch_id);
33d814e0
 		*p_branch =(int) branch_id;
caf80ae6
 		REF_UNSAFE( T );
 		UNLOCK_HASH(hash_index);
 		DBG("DEBUG: t_reply_matching: reply matched (T=%p)!\n",T);
fde02f64
 		/* if this is a 200 for INVITE, we will wish to store to-tags to be
84d8e165
 		 * able to distinguish retransmissions later and not to call
fde02f64
  		 * 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
 		 */
66298eb4
 		if (unlikely( is_invite(p_cell) && p_msg->REPLY_STATUS>=200 
 			&& p_msg->REPLY_STATUS<300 
 			&& ((!is_local(p_cell) &&
89f03bcf
 				has_tran_tmcbs(p_cell, 
 					TMCB_RESPONSE_OUT|TMCB_E2EACK_IN|TMCB_E2EACK_RETR_IN) )
66298eb4
 			|| (is_local(p_cell)&&has_tran_tmcbs(p_cell, TMCB_LOCAL_COMPLETED))
 		)) ) {
5c28a534
 			if (parse_headers(p_msg, HDR_TO_F, 0)==-1) {
fde02f64
 				LOG(L_ERR, "ERROR: t_reply_matching: to parsing failed\n");
 			}
 		}
66298eb4
 		if (unlikely(has_tran_tmcbs(T, TMCB_RESPONSE_IN |
 										TMCB_LOCAL_RESPONSE_IN))){
 			if (!is_local(p_cell)) {
 				run_trans_callbacks( TMCB_RESPONSE_IN, T, T->uas.request,
 										p_msg, p_msg->REPLY_STATUS);
 			}else{
 				run_trans_callbacks( TMCB_LOCAL_RESPONSE_IN, T, T->uas.request,
 										p_msg, p_msg->REPLY_STATUS);
 			}
a70eb298
 		}
1f377e97
 		return 1;
 	} /* for cycle */
3b84d176
 
 	/* nothing found */
caf80ae6
 	UNLOCK_HASH(hash_index);
3b84d176
 	DBG("DEBUG: t_reply_matching: no matching transaction exists\n");
dda9dab1
 
 nomatch2:
3b84d176
 	DBG("DEBUG: t_reply_matching: failure to match a transaction\n");
 	*p_branch = -1;
30ea1726
 	set_t(0, T_BR_UNDEFINED);
3b84d176
 	return -1;
dda9dab1
 }
 
 
 
 
85529b20
 /** Determine current transaction (w/ e2eack support).
fde02f64
  *
85529b20
  * script/t_lookup_request  return convention:
  *                   Found      Not Found     Error (e.g. parsing) E2E ACK
  *  @return          1         -1              0                  -2
  *  T                ptr        0              T_UNDEFINED| 0      0
30ea1726
  * Side-effects: sets T and T_branch.
fde02f64
  */
85529b20
 int t_check_msg( struct sip_msg* p_msg , int *param_branch )
dda9dab1
 {
c836adad
 	int local_branch;
ec76200f
 	int canceled;
85529b20
 	int ret;
 	
 	ret=0;
c836adad
 	/* is T still up-to-date ? */
85529b20
 	DBG("DEBUG: t_check_msg: msg id=%d global id=%d T start=%p\n", 
c836adad
 		p_msg->id,global_msg_id,T);
 	if ( p_msg->id != global_msg_id || T==T_UNDEFINED )
 	{
 		global_msg_id = p_msg->id;
30ea1726
 		set_t(T_UNDEFINED, T_BR_UNDEFINED);
c836adad
 		/* transaction lookup */
 		if ( p_msg->first_line.type==SIP_REQUEST ) {
baa4fa73
 			/* force parsing all the needed headers*/
99e9192a
 			prefetch_loc_r(p_msg->unparsed+64, 1);
5c28a534
 			if (parse_headers(p_msg, HDR_EOH_F, 0 )==-1) {
85529b20
 				LOG(L_ERR, "ERROR: t_check_msg: parsing error\n");
 				goto error;
fde02f64
 			}
 			/* in case, we act as UAS for INVITE and reply with 200,
 			 * we will need to run dialog-matching for subsequent
 			 * ACK, for which we need From-tag; We also need from-tag
 			 * in case people want to have proxied e2e ACKs accounted
 			 */
 			if (p_msg->REQ_METHOD==METHOD_INVITE 
 							&& parse_from_header(p_msg)==-1) {
85529b20
 				LOG(L_ERR, "ERROR: t_check_msg: from parsing failed\n");
 				goto error;
fde02f64
 			}
85529b20
 			ret=t_lookup_request( p_msg , 0 /* unlock before returning */,
 									&canceled);
549d5e1c
 		} else {
caf80ae6
 			/* we need Via for branch and Cseq method to distinguish
 			   replies with the same branch/cseqNr (CANCEL)
3ed13e77
 			   and we need all the WWW/Proxy Authenticate headers for
 			   401 & 407 replies
caf80ae6
 			*/
2b36d889
 			if (cfg_get(tm, tm_cfg, tm_aggregate_auth) && 
3ed13e77
 					(p_msg->REPLY_STATUS==401 || p_msg->REPLY_STATUS==407)){
 				if (parse_headers(p_msg, HDR_EOH_F,0)==-1){
 					LOG(L_WARN, "WARNING: the reply cannot be "
 								"completely parsed\n");
 					/* try to continue, via1 & cseq are checked below */
 				}
 			}else if ( parse_headers(p_msg, HDR_VIA1_F|HDR_CSEQ_F, 0 )==-1) {
caf80ae6
 				LOG(L_ERR, "ERROR: reply cannot be parsed\n");
85529b20
 				goto error;
caf80ae6
 			}
3ed13e77
 			if ((p_msg->via1==0) || (p_msg->cseq==0)){
85529b20
 				LOG(L_ERR, "ERROR: reply doesn't have a via or cseq"
 							" header\n");
 				goto error;
3ed13e77
 			}
caf80ae6
 			/* if that is an INVITE, we will also need to-tag
 			   for later ACK matching
 			*/
85529b20
 			if ( get_cseq(p_msg)->method.len==INVITE_LEN 
 				&& memcmp( get_cseq(p_msg)->method.s, INVITE, INVITE_LEN )==0)
 			{
 				if (parse_headers(p_msg, HDR_TO_F, 0)==-1 || !p_msg->to) {
 					LOG(L_ERR, "ERROR: INVITE reply cannot be parsed\n");
 					goto error;
 				}
caf80ae6
 			}
85529b20
 			ret=t_reply_matching( p_msg ,
 							param_branch!=0?param_branch:&local_branch );
baa4fa73
 		}
549d5e1c
 #ifdef EXTRA_DEBUG
57857a94
 		if ( T && T!=T_UNDEFINED && T->flags & (T_IN_AGONY)) {
31c707fd
 			LOG( L_WARN, "WARNING: transaction %p scheduled for deletion "
85529b20
 				"and called from t_check_msg (flags=%x) (but it might be ok)"
 				"\n", T, T->flags);
c836adad
 		}
549d5e1c
 #endif
85529b20
 		DBG("DEBUG: t_check_msg: msg id=%d global id=%d T end=%p\n",
c836adad
 			p_msg->id,global_msg_id,T);
85529b20
 	} else { /*  ( p_msg->id == global_msg_id && T!=T_UNDEFINED ) */
 		if (T){
 			DBG("DEBUG: t_check_msg: T already found!\n");
 			ret=1;
 		}else{
 			DBG("DEBUG: t_check_msg: T previously sought and not found\n");
 			ret=-1;
 		}
30ea1726
 		if (likely(param_branch))
 			*param_branch=T_branch;
dda9dab1
 	}
85529b20
 	return ret;
 error:
 	return 0;
 }
 
 
 
 /** Determine current transaction (old version).
  *
  *                   Found      Not Found     Error (e.g. parsing)
  *  @return          1          0             -1
  *  T                ptr        0             T_UNDEFINED | 0
30ea1726
  *
  * Side-effects: sets T and T_branch.
85529b20
  */
 int t_check( struct sip_msg* p_msg , int *param_branch )
 {
 	int ret;
dda9dab1
 
85529b20
 	ret=t_check_msg(p_msg, param_branch);
 	/* fix t_check_msg return */
 	switch(ret){
 		case -2: /* e2e ack */     return 0;  /* => not found */
 		case -1: /* not found */   return 0;  /* => not found */
 		case  0: /* parse error */ return -1; /* => error */
 		case  1: /* found */       return ret; /* =>  found */
 	};
 	return ret;
dda9dab1
 }
 
85529b20
 
 
d531a5d5
 int init_rb( struct retr_buf *rb, struct sip_msg *msg)
dda9dab1
 {
ddaf2976
 	/*struct socket_info* send_sock;*/
caf80ae6
 	struct via_body* via;
d531a5d5
 	int proto;
c6bd2a4c
 	int backup_mhomed;
dda9dab1
 
57857a94
 	/* rb. timers are init. init_t()/new_cell() */
d531a5d5
 	via=msg->via1;
7a068ff3
 	/* rb->dst is already init (0) by new_t()/build_cell() */
caf80ae6
 	if (!reply_to_via) {
d531a5d5
 		update_sock_struct_from_ip( &rb->dst.to, msg );
 		proto=msg->rcv.proto;
caf80ae6
 	} else {
 		/*init retrans buffer*/
b99da544
 		if (update_sock_struct_from_via( &(rb->dst.to), msg, via )==-1) {
caf80ae6
 			LOG(L_ERR, "ERROR: init_rb: cannot lookup reply dst: %.*s\n",
 				via->host.len, via->host.s );
 			ser_error=E_BAD_VIA;
 			return 0;
 		}
d531a5d5
 		proto=via->proto;
caf80ae6
 	}
d531a5d5
 	rb->dst.proto=proto;
e6a2b12e
 	rb->dst.id=msg->rcv.proto_reserved1;
7a068ff3
 #ifdef USE_COMP
 	rb->dst.comp=via->comp_no;
 #endif
bf0a0d42
 	rb->dst.send_flags=msg->rpl_send_flags;
c6bd2a4c
 	/* turn off mhomed for generating replies -- they are ideally sent to where
 	   request came from to make life with NATs and other beasts easier
 	*/
 	backup_mhomed=mhomed;
 	mhomed=0;
 	mhomed=backup_mhomed;
ddaf2976
 	/* use for sending replies the incoming interface of the request -bogdan */
 	/*send_sock=get_send_socket(msg, &rb->dst.to, proto);
caf80ae6
 	if (send_sock==0) {
5dcfb23d
 		LOG(L_ERR, "ERROR: init_rb: cannot fwd to af %d, proto %d "
 			"no socket\n", rb->dst.to.s.sa_family, proto);
caf80ae6
 		ser_error=E_BAD_VIA;
 		return 0;
ddaf2976
 	}*/
 	rb->dst.send_sock=msg->rcv.bind_address;
 	return 1;
dda9dab1
 }
 
b908cdeb
 
6ef782ab
 static inline void init_new_t(struct cell *new_cell, struct sip_msg *p_msg)
 {
 	struct sip_msg *shm_msg;
57857a94
 	unsigned int timeout; /* avp timeout gets stored here (in s) */
c0ff60b6
 	ticks_t lifetime;
6ef782ab
 
 	shm_msg=new_cell->uas.request;
 	new_cell->from.s=shm_msg->from->name.s;
 	new_cell->from.len=HF_LEN(shm_msg->from);
 	new_cell->to.s=shm_msg->to->name.s;
 	new_cell->to.len=HF_LEN(shm_msg->to);
 	new_cell->callid.s=shm_msg->callid->name.s;
 	new_cell->callid.len=HF_LEN(shm_msg->callid);
 	new_cell->cseq_n.s=shm_msg->cseq->name.s;
 	new_cell->cseq_n.len=get_cseq(shm_msg)->number.s
 		+get_cseq(shm_msg)->number.len
 		-shm_msg->cseq->name.s;
 
 	new_cell->method=new_cell->uas.request->first_line.u.request.method;
c0ff60b6
 	if (p_msg->REQ_METHOD==METHOD_INVITE){
4f03bb4d
 		/* set flags */
 		new_cell->flags |= T_IS_INVITE_FLAG |
 			get_msgid_val(user_cell_set_flags, p_msg->id, int);
 		new_cell->flags|=T_AUTO_INV_100 &
2b36d889
 					(!cfg_get(tm, tm_cfg, tm_auto_inv_100) -1);
4f03bb4d
 		new_cell->flags|=T_DISABLE_6xx &
 					(!cfg_get(tm, tm_cfg, disable_6xx) -1);
 		/* reset flags */
 		new_cell->flags &=
 			(~ get_msgid_val(user_cell_reset_flags, p_msg->id, int));
 		
c0ff60b6
 		lifetime=(ticks_t)get_msgid_val(user_inv_max_lifetime,
 												p_msg->id, int);
 		if (likely(lifetime==0))
2b36d889
 			lifetime=cfg_get(tm, tm_cfg, tm_max_inv_lifetime);
c0ff60b6
 	}else{
 		lifetime=(ticks_t)get_msgid_val(user_noninv_max_lifetime, 
 											p_msg->id, int);
 		if (likely(lifetime==0))
2b36d889
 			lifetime=cfg_get(tm, tm_cfg, tm_max_noninv_lifetime);
c0ff60b6
 	}
6ef782ab
 	new_cell->on_negative=get_on_negative();
 	new_cell->on_reply=get_on_reply();
c0ff60b6
 	new_cell->end_of_life=get_ticks_raw()+lifetime;;
57857a94
 	new_cell->fr_timeout=(ticks_t)get_msgid_val(user_fr_timeout,
 												p_msg->id, int);
 	new_cell->fr_inv_timeout=(ticks_t)get_msgid_val(user_fr_inv_timeout,
 												p_msg->id, int);
c0ff60b6
 	if (likely(new_cell->fr_timeout==0)){
 		if (unlikely(!fr_avp2timer(&timeout))) {
57857a94
 			DBG("init_new_t: FR__TIMER = %d s\n", timeout);
 			new_cell->fr_timeout=S_TO_TICKS((ticks_t)timeout);
 		}else{
2b36d889
 			new_cell->fr_timeout=cfg_get(tm, tm_cfg, fr_timeout);
57857a94
 		}
 	}
c0ff60b6
 	if (likely(new_cell->fr_inv_timeout==0)){
 		if (unlikely(!fr_inv_avp2timer(&timeout))) {
57857a94
 			DBG("init_new_t: FR_INV_TIMER = %d s\n", timeout);
 			new_cell->fr_inv_timeout=S_TO_TICKS((ticks_t)timeout);
 			new_cell->flags |= T_NOISY_CTIMER_FLAG;
 		}else{
2b36d889
 			new_cell->fr_inv_timeout=cfg_get(tm, tm_cfg, fr_inv_timeout);
57857a94
 		}
 	}
c0ff60b6
 #ifdef TM_DIFF_RT_TIMEOUT
 	new_cell->rt_t1_timeout=(ticks_t)get_msgid_val(user_rt_t1_timeout,
 												p_msg->id, int);
 	if (likely(new_cell->rt_t1_timeout==0))
2b36d889
 		new_cell->rt_t1_timeout=cfg_get(tm, tm_cfg, rt_t1_timeout);
c0ff60b6
 	new_cell->rt_t2_timeout=(ticks_t)get_msgid_val(user_rt_t2_timeout,
 												p_msg->id, int);
 	if (likely(new_cell->rt_t2_timeout==0))
2b36d889
 		new_cell->rt_t2_timeout=cfg_get(tm, tm_cfg, rt_t2_timeout);
c0ff60b6
 #endif
49a20a49
 	new_cell->on_branch=get_on_branch();
6ef782ab
 }
 
30ea1726
 
 
 /** creates a new transaction from a message.
  * No checks are made if the transaction exists. It is created and
  * added to the tm hashes. T is set to the new transaction.
  * @param p_msg - pointer to sip message
  * @return  >0 on success, <0 on error (an E_* error code, see error.h)
  * Side-effects: sets T and T_branch (T_branch always to T_BR_UNDEFINED).
  */
6ef782ab
 static inline int new_t(struct sip_msg *p_msg)
 {
 	struct cell *new_cell;
 
 	/* for ACK-dlw-wise matching, we want From-tags */
 	if (p_msg->REQ_METHOD==METHOD_INVITE && parse_from_header(p_msg)<0) {
 			LOG(L_ERR, "ERROR: new_t: no valid From in INVITE\n");
 			return E_BAD_REQ;
 	}
 	/* make sure uri will be parsed before cloning */
 	if (parse_sip_msg_uri(p_msg)<0) {
 		LOG(L_ERR, "ERROR: new_t: uri invalid\n");
 		return E_BAD_REQ;
 	}
 			
 	/* add new transaction */
 	new_cell = build_cell( p_msg ) ;
 	if  ( !new_cell ){
 		LOG(L_ERR, "ERROR: new_t: out of mem:\n");
 		return E_OUT_OF_MEM;
 	} 
 
e67d9509
 #ifdef TM_DEL_UNREF
 	INIT_REF(new_cell, 2); /* 1 because it will be ref'ed from the
 									   hash and +1 because we set T to it */
 #endif
c2ea965c
 	insert_into_hash_table_unsafe( new_cell, p_msg->hash_index );
30ea1726
 	set_t(new_cell, T_BR_UNDEFINED);
e67d9509
 #ifndef TM_DEL_UNREF
6ef782ab
 	INIT_REF_UNSAFE(T);
e67d9509
 #endif
6ef782ab
 	/* init pointers to headers needed to construct local
 	   requests such as CANCEL/ACK
 	*/
 	init_new_t(new_cell, p_msg);
 	return 1;
 }
caf80ae6
 
1400b772
 
 
30ea1726
 /** if no transaction already exists for the message, create a new one.
  * atomic "new_tran" construct; it returns:
  *
  * @return <0	on error
  *          +1	if a request did not match a transaction
  *           0	on retransmission
  * On success, if the request was an ack, the calling function shall
  * forward statelessly. Otherwise it means, a new transaction was
  * introduced and the calling function shall reply/relay/whatever_appropriate.
  * Side-effects: sets T and T_branch (T_branch always to T_BR_UNDEFINED).
1400b772
 */
 int t_newtran( struct sip_msg* p_msg )
 {
004c9173
 	int lret, my_err;
ec76200f
 	int canceled;
1400b772
 
c5867ab3
 
1400b772
 	/* is T still up-to-date ? */
1d4c5c00
 	DBG("DEBUG: t_newtran: msg id=%d , global msg id=%d ,"
1400b772
 		" T on entrance=%p\n",p_msg->id,global_msg_id,T);
 
caf80ae6
 	if ( T && T!=T_UNDEFINED  ) {
e5ef14a7
 		/* ERROR message moved to w_t_newtran */
 		DBG("DEBUG: t_newtran: "
caf80ae6
 			"transaction already in process %p\n", T );
989c2658
 
 		/* t_newtran() has been already called, and the script
 		might changed the flags after it, so we must update the flags
 		in shm memory -- Miklos */
 		if (T->uas.request)
 			T->uas.request->flags = p_msg->flags;
 
caf80ae6
 		return E_SCRIPT;
1400b772
 	}
 
 	global_msg_id = p_msg->id;
30ea1726
 	set_t(T_UNDEFINED, T_BR_UNDEFINED);
6ef782ab
 	/* first of all, parse everything -- we will store in shared memory 
 	   and need to have all headers ready for generating potential replies 
 	   later; parsing later on demand is not an option since the request 
 	   will be in shmem and applying parse_headers to it would intermix 
 	   shmem with pkg_mem
caf80ae6
 	*/
 	
5c28a534
 	if (parse_headers(p_msg, HDR_EOH_F, 0 )) {
caf80ae6
 		LOG(L_ERR, "ERROR: t_newtran: parse_headers failed\n");
 		return E_BAD_REQ;
 	}
5c28a534
 	if ((p_msg->parsed_flag & HDR_EOH_F)!=HDR_EOH_F) {
caf80ae6
 			LOG(L_ERR, "ERROR: t_newtran: EoH not parsed\n");
 			return E_OUT_OF_MEM;
 	}
84d8e165
 	/* t_lookup_requests attempts to find the transaction; 
caf80ae6
 	   it also calls check_transaction_quadruple -> it is
 	   safe to assume we have from/callid/cseq/to
 	*/ 
ec76200f
 	lret = t_lookup_request( p_msg, 1 /* leave locked if not found */,
 								&canceled );
fde02f64
 
6ef782ab
 	/* on error, pass the error in the stack ... nothing is locked yet
 	   if 0 is returned */
 	if (lret==0) return E_BAD_TUPEL;
caf80ae6
 
6ef782ab
 	/* transaction found, it's a retransmission  */
 	if (lret>0) {
 		if (p_msg->REQ_METHOD==METHOD_ACK) {
66298eb4
 			if (unlikely(has_tran_tmcbs(T, TMCB_ACK_NEG_IN)))
 				run_trans_callbacks(TMCB_ACK_NEG_IN, T, p_msg, 0, 
 										p_msg->REQ_METHOD);
6ef782ab
 			t_release_transaction(T);
 		} else {
66298eb4
 			if (unlikely(has_tran_tmcbs(T, TMCB_REQ_RETR_IN)))
 				run_trans_callbacks(TMCB_REQ_RETR_IN, T, p_msg, 0,
 										p_msg->REQ_METHOD);
6ef782ab
 			t_retransmit_reply(T);
1400b772
 		}
6ef782ab
 		/* things are done -- return from script */
 		return 0;
 	}
b5f0a0b6
 
6ef782ab
 	/* from now on, be careful -- hash table is locked */
 
 	if (lret==-2) { /* was it an e2e ACK ? if so, trigger a callback */
 		/* no callbacks? complete quickly */
89f03bcf
 		if (likely( !has_tran_tmcbs(t_ack, 
 						TMCB_E2EACK_IN|TMCB_E2EACK_RETR_IN) )) {
caf80ae6
 			UNLOCK_HASH(p_msg->hash_index);
6ef782ab
 			return 1;
 		} 
 		REF_UNSAFE(t_ack);
 		UNLOCK_HASH(p_msg->hash_index);
 		/* we don't call from within REPLY_LOCK -- that introduces
a70eb298
 		 * a race condition; however, it is so unlikely and the
 		 * impact is so small (callback called multiple times of
 		 * multiple ACK/200s received in parallel), that we do not
 		 * better waste time in locks  */
6ef782ab
 		if (unmatched_totag(t_ack, p_msg)) {
89f03bcf
 			if (likely (has_tran_tmcbs(t_ack, TMCB_E2EACK_IN)))
 				run_trans_callbacks( TMCB_E2EACK_IN , t_ack, p_msg, 0,
 										-p_msg->REQ_METHOD );
 		}else if (unlikely(has_tran_tmcbs(t_ack, TMCB_E2EACK_RETR_IN))){
 			run_trans_callbacks( TMCB_E2EACK_RETR_IN , t_ack, p_msg, 0,
 									-p_msg->REQ_METHOD );
b5f0a0b6
 		}
6ef782ab
 		UNREF(t_ack);
 		return 1;
89f03bcf
 	}
0505ec51
 
6ef782ab
 
 	/* transaction not found, it's a new request (lret<0, lret!=-2);
 	   establish a new transaction ... */
 	if (p_msg->REQ_METHOD==METHOD_ACK) { /* ... unless it is in ACK */
 		my_err=1;
 		goto new_err;
1400b772
 	}
6ef782ab
 
 	my_err=new_t(p_msg);
 	if (my_err<0) {
 		LOG(L_ERR, "ERROR: t_newtran: new_t failed\n");
 		goto new_err;
 	}
ec76200f
 	if (canceled) T->flags|=T_CANCELED; /* mark it for future ref. */
6ef782ab
 
 
 	UNLOCK_HASH(p_msg->hash_index);
 	/* now, when the transaction state exists, check if
  	   there is a meaningful Via and calculate it; better
  	   do it now than later: state is established so that
  	   subsequent retransmissions will be absorbed and will
   	  not possibly block during Via DNS resolution; doing
 	   it later would only burn more CPU as if there is an
 	   error, we cannot relay later whatever comes out of the
   	   the transaction 
 	*/
 	if (!init_rb( &T->uas.response, p_msg)) {
84d8e165
 		LOG(L_ERR, "ERROR: t_newtran: unresolvable via1\n");
6ef782ab
 		put_on_wait( T );
 		t_unref(p_msg);
 		return E_BAD_VIA;
 	}
 
 	return 1;
 
caf80ae6
 
d7027ef9
 new_err:
 	UNLOCK_HASH(p_msg->hash_index);
 	return my_err;
 
1400b772
 }
 
 
30ea1726
 
 /** releases the current transaction (corresp. to p_msg).
  * The current transaction (T) corresponding to the sip message being
  * processed is released. Delayed replies are sent (if no other reply
  * was sent in the script). Extra checks are made to see if the transaction
  * was forwarded, explicitly replied or explicitly released. If not the
  * transaction * is force-killed and a warning is logged (script error).
  * @param p_msg - sip message being processed
  * @return -1 on error, 1 on success.
  * Side-effects: resets T and T_branch to T_UNDEFINED, T_BR_UNDEFINED,
  *  resets tm_error.
  */
caf80ae6
 int t_unref( struct sip_msg* p_msg  )
 {
fde02f64
 	enum kill_reason kr;
 
1ea91058
 	if (T==T_UNDEFINED || T==T_NULL_CELL)
caf80ae6
 		return -1;
acee2897
 	if (p_msg->first_line.type==SIP_REQUEST){
 		kr=get_kr();
b4a4494d
 		if (unlikely(kr == REQ_ERR_DELAYED)){
 			DBG("t_unref: delayed error reply generation(%d)\n", tm_error);
29e00cb9
 			if (unlikely(is_route_type(FAILURE_ROUTE))){
b4a4494d
 				BUG("tm: t_unref: called w/ kr=REQ_ERR_DELAYED in failure"
b539318a
 						" route for %p\n", T);
b4a4494d
 			}else if (unlikely( kill_transaction(T, tm_error)<=0 )){
b539318a
 				ERR("ERROR: t_unref: generation of a delayed stateful reply"
b4a4494d
 						" failed\n");
 				t_release_transaction(T);
 			}
 		}else if ( unlikely (kr==0 ||(p_msg->REQ_METHOD==METHOD_ACK && 
 								!(kr & REQ_RLSD)))) {
acee2897
 			LOG(L_WARN, "WARNING: script writer didn't release transaction\n");
 			t_release_transaction(T);
5ac814a7
 		}else if (unlikely((kr & REQ_ERR_DELAYED) &&
 					 (kr & ~(REQ_RLSD|REQ_RPLD|REQ_ERR_DELAYED)))){
b539318a
 			BUG("tm: t_unref: REQ_ERR DELAYED should have been caught much"
 					" earlier for %p: %d (hex %x)\n",T, kr, kr);
 			t_release_transaction(T);
acee2897
 		}
caf80ae6
 	}
f04b9c4c
 	tm_error=0; /* clear it */
caf80ae6
 	UNREF( T );
30ea1726
 	set_t(T_UNDEFINED, T_BR_UNDEFINED);
caf80ae6
 	return 1;
 }
d3b31abd
 
b4a4494d
 
 
96dd9e9f
 int t_get_trans_ident(struct sip_msg* p_msg, unsigned int* hash_index, unsigned int* label)
 {
     struct cell* t;
     if(t_check(p_msg,0) != 1){
 	LOG(L_ERR,"ERROR: t_get_trans_ident: no transaction found\n");
 	return -1;
     }
     t = get_t();
     if(!t){
 	LOG(L_ERR,"ERROR: t_get_trans_ident: transaction found is NULL\n");
 	return -1;
     }
     
     *hash_index = t->hash_index;
     *label = t->label;
 
     return 1;
 }
 
d65cdd3f
 #ifdef WITH_AS_SUPPORT
 /**
  * Returns the hash coordinates of the transaction current CANCEL is targeting.
  */
 int t_get_canceled_ident(struct sip_msg* msg, unsigned int* hash_index, 
 		unsigned int* label)
 {
 	struct cell *orig;
 	if (msg->REQ_METHOD != METHOD_CANCEL) {
 		WARN("looking up original transaction for non-CANCEL method (%d).\n",
 				msg->REQ_METHOD);
 		return -1;
 	}
 	orig = t_lookupOriginalT(msg);
 	if ((orig == T_NULL_CELL) || (orig == T_UNDEFINED))
 		return -1;
 	*hash_index = orig->hash_index;
 	*label = orig->label;
 	DEBUG("original T found @%p, %d:%d.\n", orig, *hash_index, *label);
 	/* TODO: why's w_t_lookup_cancel setting T to 'undefined'?? */
 	UNREF(orig);
 	return 1;
 }
 #endif /* WITH_AS_SUPPORT */
 
30ea1726
 
 
 /** lookup a transaction based on its identifier (hash_index:label).
  * @param trans - double pointer to cell structure, that will be filled
  *                with the result (a pointer to an existing transaction or
  *                0).
  * @param hash_index - searched transaction hash_index (part of the ident).
  * @param label - searched transaction label (part of the ident).
  * @return -1 on error/not found, 1 on success (found)
  * Side-effects: sets T and T_branch (T_branch always to T_BR_UNDEFINED).
  */
99e9192a
 int t_lookup_ident(struct cell ** trans, unsigned int hash_index, 
 					unsigned int label)
96dd9e9f
 {
99e9192a
 	struct cell* p_cell;
 	struct entry* hash_bucket;
96dd9e9f
 
99e9192a
 	if(unlikely(hash_index >= TABLE_ENTRIES)){
fde02f64
 		LOG(L_ERR,"ERROR: t_lookup_ident: invalid hash_index=%u\n",hash_index);
 		return -1;
99e9192a
 	}
 	
 	LOCK_HASH(hash_index);
d65cdd3f
 
 #ifndef E2E_CANCEL_HOP_BY_HOP
 #warning "t_lookup_ident() can only reliably match INVITE transactions in " \
 		"E2E_CANCEL_HOP_BY_HOP mode"
 #endif
99e9192a
 	hash_bucket=&(get_tm_table()->entries[hash_index]);
 	/* all the transactions from the entry are compared */
 	clist_foreach(hash_bucket, p_cell, next_c){
 		prefetch_loc_r(p_cell->next_c, 1);
fde02f64
 		if(p_cell->label == label){
 			REF_UNSAFE(p_cell);
c5867ab3
     			UNLOCK_HASH(hash_index);
30ea1726
 			set_t(p_cell, T_BR_UNDEFINED);
fde02f64
 			*trans=p_cell;
 			DBG("DEBUG: t_lookup_ident: transaction found\n");
 			return 1;
 		}
96dd9e9f
     }
fde02f64
 	
 	UNLOCK_HASH(hash_index);
30ea1726
 	set_t(0, T_BR_UNDEFINED);
fde02f64
 	*trans=p_cell;
96dd9e9f
 
 	DBG("DEBUG: t_lookup_ident: transaction not found\n");
     
fde02f64
     return -1;
96dd9e9f
 }
 
30ea1726
 
 
 /** check if a transaction is local or not.
  * Check if the transaction corresponding to the current message
  * is local or not.
  * @param p_msg - pointer to sip_msg
  * @return -1 on error, 0 if the transaction is not local, 1 if it is local.
  * Side-effects: sets T and T_branch.
  */
96dd9e9f
 int t_is_local(struct sip_msg* p_msg)
 {
     struct cell* t;
     if(t_check(p_msg,0) != 1){
 	LOG(L_ERR,"ERROR: t_is_local: no transaction found\n");
 	return -1;
     }
     t = get_t();
     if(!t){
 	LOG(L_ERR,"ERROR: t_is_local: transaction found is NULL\n");
 	return -1;
     }
     
0be6158b
     return is_local(t);
96dd9e9f
 }
c2ea965c
 
30ea1726
 /** lookup a transaction based on callid and cseq.
  * The parameters are pure header field content only,
  * e.g. "123@10.0.0.1" and "11"
  * @param trans - double pointer to the transaction, filled with a pointer
  *                to the found transaction on success and with 0 if the
  *                transaction was not found.
  * @param callid - callid for the searched transaction.
  * @param cseq - cseq for the searched transaction.
  * @return -1 on error/not found, 1 if found.
  * Side-effects: sets T and T_branch (T_branch always to T_BR_UNDEFINED).
c2ea965c
  */
 int t_lookup_callid(struct cell ** trans, str callid, str cseq) {
 	struct cell* p_cell;
 	unsigned hash_index;
99e9192a
 	struct entry* hash_bucket;
c2ea965c
 
84d8e165
 	/* I use MAX_HEADER, not sure if this is a good choice... */
c2ea965c
 	char callid_header[MAX_HEADER];
 	char cseq_header[MAX_HEADER];
 	/* save return value of print_* functions here */
 	char* endpos;
 
 	/* need method, which is always INVITE in our case */
 	/* CANCEL is only useful after INVITE */
 	str invite_method;
 	char* invite_string = INVITE;
 	
 	invite_method.s = invite_string;
 	invite_method.len = INVITE_LEN;
 	
 	/* lookup the hash index where the transaction is stored */
 	hash_index=hash(callid, cseq);
 
99e9192a
 	if(unlikely(hash_index >= TABLE_ENTRIES)){
c2ea965c
 		LOG(L_ERR,"ERROR: t_lookup_callid: invalid hash_index=%u\n",hash_index);
 		return -1;
 	}
 
 	/* create header fields the same way tm does itself, then compare headers */
 	endpos = print_callid_mini(callid_header, callid);
a9fae28b
 	DBG("created comparable call_id header field: >%.*s<\n", 
 			(int)(endpos - callid_header), callid_header); 
c2ea965c
 
 	endpos = print_cseq_mini(cseq_header, &cseq, &invite_method);
a9fae28b
 	DBG("created comparable cseq header field: >%.*s<\n", 
 			(int)(endpos - cseq_header), cseq_header); 
c2ea965c
 
 	LOCK_HASH(hash_index);
 	DBG("just locked hash index %u, looking for transactions there:\n", hash_index);
 
99e9192a
 	hash_bucket=&(get_tm_table()->entries[hash_index]);
c2ea965c
 	/* all the transactions from the entry are compared */
99e9192a
 	clist_foreach(hash_bucket, p_cell, next_c){
c2ea965c
 		
99e9192a
 		prefetch_loc_r(p_cell->next_c, 1);
 		/* compare complete header fields, casecmp to make sure invite=INVITE*/
 		if ((strncmp(callid_header, p_cell->callid.s, p_cell->callid.len) == 0)
 			&& (strncasecmp(cseq_header, p_cell->cseq_n.s, p_cell->cseq_n.len)
 				== 0)) {
 			DBG("we have a match: callid=>>%.*s<< cseq=>>%.*s<<\n",
 					p_cell->callid.len, p_cell->callid.s, p_cell->cseq_n.len,
 					p_cell->cseq_n.s);
c2ea965c
 			REF_UNSAFE(p_cell);
 			UNLOCK_HASH(hash_index);
30ea1726
 			set_t(p_cell, T_BR_UNDEFINED);
c2ea965c
 			*trans=p_cell;
 			DBG("DEBUG: t_lookup_callid: transaction found.\n");
 			return 1;
 		}
 		DBG("NO match: callid=%.*s cseq=%.*s\n", p_cell->callid.len, 
 			p_cell->callid.s, p_cell->cseq_n.len, p_cell->cseq_n.s);
 			
 	}
 
 	UNLOCK_HASH(hash_index);
 	DBG("DEBUG: t_lookup_callid: transaction not found.\n");
     
 	return -1;
 }
 
57857a94
 
 
 /* params: fr_inv & fr value in ms, 0 means "do not touch"
  * ret: 1 on success, -1 on error (script safe)*/
 int t_set_fr(struct sip_msg* msg, unsigned int fr_inv_to, unsigned int fr_to)
 {
 	struct cell *t;
 	ticks_t fr_inv, fr;
 	
 	
 	fr_inv=MS_TO_TICKS((ticks_t)fr_inv_to);
 	if ((fr_inv==0) && (fr_inv_to!=0)){
 		ERR("t_set_fr_inv: fr_inv_timeout too small (%d)\n", fr_inv_to);
 		return -1;
 	}
 	fr=MS_TO_TICKS((ticks_t)fr_to);
 	if ((fr==0) && (fr_to!=0)){
 		ERR("t_set_fr_inv: fr_timeout too small (%d)\n", fr_to);
 		return -1;
 	}
 	
 	t=get_t();
29e00cb9
 	/* in REPLY_ROUTE and FAILURE_ROUTE T will be set to current transaction;
 	 * in REQUEST_ROUTE T will be set only if the transaction was already
c0ff60b6
 	 * created; if not -> use the static variables */
57857a94
 	if (!t || t==T_UNDEFINED ){
 		set_msgid_val(user_fr_inv_timeout, msg->id, int, (int)fr_inv);
 		set_msgid_val(user_fr_timeout, msg->id, int, (int)fr);
 	}else{
 		change_fr(t, fr_inv, fr); /* change running uac timers */
 	}
 	return 1;
 }
c0ff60b6
 
16daadfd
 /* reset fr_timer and fr_inv_timer to the default values */
 int t_reset_fr()
 {
 	struct cell *t;
 
 	t=get_t();
29e00cb9
 	/* in REPLY_ROUTE and FAILURE_ROUTE T will be set to current transaction;
 	 * in REQUEST_ROUTE T will be set only if the transaction was already
16daadfd
 	 * created; if not -> use the static variables */
 	if (!t || t==T_UNDEFINED ){
 		memset(&user_fr_inv_timeout, 0, sizeof(user_fr_inv_timeout));
 		memset(&user_fr_timeout, 0, sizeof(user_fr_timeout));
 	}else{
 		change_fr(t,
 			cfg_get(tm, tm_cfg, fr_inv_timeout),
 			cfg_get(tm, tm_cfg, fr_timeout)); /* change running uac timers */
 	}
 	return 1;
 }
c0ff60b6
 
 #ifdef TM_DIFF_RT_TIMEOUT
 
 /* params: retr. t1 & retr. t2 value in ms, 0 means "do not touch"
  * ret: 1 on success, -1 on error (script safe)*/
 int t_set_retr(struct sip_msg* msg, unsigned int t1_to, unsigned int t2_to)
 {
 	struct cell *t;
 	ticks_t retr_t1, retr_t2;
 	
 	
 	retr_t1=MS_TO_TICKS((ticks_t)t1_to);
 	if (unlikely((retr_t1==0) && (t1_to!=0))){
 		ERR("t_set_retr: retr. t1 interval too small (%u)\n", t1_to);
 		return -1;
 	}
 	if (unlikely(MAX_UVAR_VALUE(t->rt_t1_timeout) < retr_t1)){
 		ERR("t_set_retr: retr. t1 interval too big: %d (max %lu)\n",
 				t1_to, TICKS_TO_MS(MAX_UVAR_VALUE(t->rt_t1_timeout))); 
 		return -1;
 	} 
 	retr_t2=MS_TO_TICKS((ticks_t)t2_to);
 	if (unlikely((retr_t2==0) && (t2_to!=0))){
 		ERR("t_set_retr: retr. t2 interval too small (%d)\n", t2_to);
 		return -1;
 	}
 	if (unlikely(MAX_UVAR_VALUE(t->rt_t2_timeout) < retr_t2)){
 		ERR("t_set_retr: retr. t2 interval too big: %u (max %lu)\n",
 				t2_to, TICKS_TO_MS(MAX_UVAR_VALUE(t->rt_t2_timeout))); 
 		return -1;
 	} 
 	
 	t=get_t();
29e00cb9
 	/* in REPLY_ROUTE and FAILURE_ROUTE T will be set to current transaction;
 	 * in REQUEST_ROUTE T will be set only if the transaction was already
c0ff60b6
 	 * created; if not -> use the static variables */
 	if (!t || t==T_UNDEFINED ){
 		set_msgid_val(user_rt_t1_timeout, msg->id, int, (int)retr_t1);
 		set_msgid_val(user_rt_t2_timeout, msg->id, int, (int)retr_t2);
 	}else{
 		change_retr(t, 1, retr_t1, retr_t2); /* change running uac timers */
 	}
 	return 1;
 }
16daadfd
 
 /* reset retr. t1 and t2 to the default values */
 int t_reset_retr()
 {
 	struct cell *t;
 
 	t=get_t();
29e00cb9
 	/* in REPLY_ROUTE and FAILURE_ROUTE T will be set to current transaction;
 	 * in REQUEST_ROUTE T will be set only if the transaction was already
16daadfd
 	 * created; if not -> use the static variables */
 	if (!t || t==T_UNDEFINED ){
 		memset(&user_rt_t1_timeout, 0, sizeof(user_rt_t1_timeout));
 		memset(&user_rt_t2_timeout, 0, sizeof(user_rt_t2_timeout));
 	}else{
 		change_retr(t,
 			1,
 			cfg_get(tm, tm_cfg, rt_t1_timeout),
 			cfg_get(tm, tm_cfg, rt_t2_timeout)); /* change running uac timers */
 	}
 	return 1;
 }
c0ff60b6
 #endif
 
 
 /* params: maximum transaction lifetime for inv and non-inv
  *         0 means do not touch"
  * ret: 1 on success, -1 on error (script safe)*/
 int t_set_max_lifetime(struct sip_msg* msg,
 						unsigned int lifetime_inv_to,
 						unsigned int lifetime_noninv_to)
 {
 	struct cell *t;
 	ticks_t max_inv_lifetime, max_noninv_lifetime;
 	
 	
 	max_noninv_lifetime=MS_TO_TICKS((ticks_t)lifetime_noninv_to);
 	max_inv_lifetime=MS_TO_TICKS((ticks_t)lifetime_inv_to);
 	if (unlikely((max_noninv_lifetime==0) && (lifetime_noninv_to!=0))){
 		ERR("t_set_max_lifetime: non-inv. interval too small (%d)\n",
 				lifetime_noninv_to);
 		return -1;
 	}
 	if (unlikely((max_inv_lifetime==0) && (lifetime_inv_to!=0))){
 		ERR("t_set_max_lifetime: inv. interval too small (%d)\n",
 				lifetime_inv_to);
 		return -1;
 	}
 	
 	t=get_t();
29e00cb9
 	/* in REPLY_ROUTE and FAILURE_ROUTE T will be set to current transaction;
 	 * in REQUEST_ROUTE T will be set only if the transaction was already
c0ff60b6
 	 * created; if not -> use the static variables */
 	if (!t || t==T_UNDEFINED ){
 		set_msgid_val(user_noninv_max_lifetime, msg->id, int,
 						(int)max_noninv_lifetime);
 		set_msgid_val(user_inv_max_lifetime, msg->id, int,
 						(int)max_inv_lifetime);
 	}else{
 		change_end_of_life(t, 1, is_invite(t)?max_inv_lifetime:
 												max_noninv_lifetime);
 	}
 	return 1;
 }
16daadfd
 
 /* reset maximum invite/non-invite lifetime to the default value */
 int t_reset_max_lifetime()
 {
 	struct cell *t;
 
 	t=get_t();
29e00cb9
 	/* in REPLY_ROUTE and FAILURE_ROUTE T will be set to current transaction;
 	 * in REQUEST_ROUTE T will be set only if the transaction was already
16daadfd
 	 * created; if not -> use the static variables */
 	if (!t || t==T_UNDEFINED ){
 		memset(&user_inv_max_lifetime, 0, sizeof(user_inv_max_lifetime));
 		memset(&user_noninv_max_lifetime, 0, sizeof(user_noninv_max_lifetime));
 	}else{
 		change_end_of_life(t,
 				1,
 				is_invite(t)?
 					cfg_get(tm, tm_cfg, tm_max_inv_lifetime):
 					cfg_get(tm, tm_cfg, tm_max_noninv_lifetime)
 				);
 	}
 	return 1;
 }
 
ded63f91
 #ifdef WITH_TM_CTX
 
 tm_ctx_t _tm_ctx;
 
 tm_ctx_t* tm_ctx_get(void)
 {
 	return &_tm_ctx;
 }
 
 void tm_ctx_init(void)
 {
 	memset(&_tm_ctx, 0, sizeof(tm_ctx_t));
 }
 
 void tm_ctx_set_branch_index(int v)
 {
 	_tm_ctx.branch_index = v;
 }
 
 #endif