/*
 * 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.
 * It is much faster and it works pretty well -- we haven't
 * had any interop issue neither in lab nor in bake-offs. The reason
 * is that retransmissions do look same as original requests
 * (it would be really silly if they would be mangled). The only
 * 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.
 * The branch parameter is formed as follows: hash.md5.branch
 *
 * -jiri
 *
 *
 * Copyright (C) 2001-2003 FhG Fokus
 *
 * This file is part of Kamailio, a free SIP server.
 *
 * Kamailio 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
 *
 * Kamailio 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */


#include "../../core/comp_defs.h"
#include "../../core/compiler_opt.h"
#include "../../core/dprint.h"
#include "../../core/config.h"
#include "../../core/parser/parser_f.h"
#include "../../core/parser/parse_from.h"
#include "../../core/ut.h"
#include "../../core/fmsg.h"
#include "../../core/timer.h"
#include "../../core/timer_ticks.h"
#include "../../core/hash_func.h"
#include "../../core/globals.h"
#include "../../core/forward.h"
#include "t_funcs.h"
#include "config.h"
#include "sip_msg.h"
#include "t_hooks.h"
#include "t_fwd.h"
#include "t_lookup.h"
#include "dlg.h"		  /* for t_lookup_callid */
#include "t_msgbuilder.h" /* for t_lookup_callid */

#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))))


#define EQ_LEN(_hf) (t_msg->_hf->body.len == p_msg->_hf->body.len)
#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)


#define HF_LEN(_hf) ((_hf)->len)

/* presumably matching transaction for an e2e ACK */
static struct cell *t_ack = NULL;

/* 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
 * 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]!)
 * - tm_global_ctx_id.{msgid, pid} == msg->{id, pid} 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 tm_global_ctx_id) or tm
 * tm onreply routes (the internal reply_received() t_check() will set
 * T and tm_global_ctx_id).
 */
static struct cell *T = NULL;

/* 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 (tm_global_ctx_id.{msgid, pid}==msg->{id, pid}
 * -- 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 = 0;

/* 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;
 * don't even think of changing it.
 */
msg_ctx_id_t tm_global_ctx_id = {0};


struct cell *get_t()
{
	return T;
}

void set_t(struct cell *t, int branch)
{
	T = t;
	T_branch = branch;
}

void init_t()
{
	tm_global_ctx_id.msgid = 0;
	tm_global_ctx_id.pid = 0;
	set_t(T_UNDEFINED, T_BR_UNDEFINED);
}

int get_t_branch()
{
	return T_branch;
}

static inline int parse_dlg(struct sip_msg *msg)
{
	if(parse_headers(msg, HDR_FROM_F | HDR_CSEQ_F | HDR_TO_F, 0) == -1) {
		LM_ERR("From or Cseq or To invalid\n");
		return 0;
	}
	if((msg->from == 0) || (msg->cseq == 0) || (msg->to == 0)) {
		LM_ERR("missing From or Cseq or To\n");
		return 0;
	}

	if(parse_from_header(msg) == -1) {
		LM_ERR("From 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) {
		LM_ERR("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;
}


/* 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
 */
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
	 */
	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
			LM_WARN("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 */
	}
	/* 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
	 * originator matches too to avoid confusion with
	 * 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) {
		if(inv_via->port == 0 && ack_via->port != SIP_PORT
				&& ack_via->port != SIPS_PORT)
			return 0;
		if(ack_via->port == 0 && inv_via->port != SIP_PORT
				&& inv_via->port != SIPS_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;

	if(inv_via->port != ack_via->port
			&& (inv_via->port == 0 || ack_via->port == 0)) {
		/* test SIPS_PORT (5061) is used with TLS transport */
		if(inv_via->port == SIPS_PORT || ack_via->port == SIPS_PORT) {
			if(inv_via->transport.len != 3
					|| memcmp(inv_via->transport.s, "TLS", 3) != 0) {
				return 0;
			}
		}
	}

	/* everything matched -- we found it */
	return 1;
}


/* transaction matching a-la RFC-3261 using transaction ID in branch
 * (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)
 * It also sets *cancel if a cancel was found for the searched transaction
 */

static int matching_3261(struct sip_msg *p_msg, struct cell **trans,
		enum request_method skip_method, int *cancel)
{
	struct cell *p_cell;
	struct cell *e2e_ack_trans;
	struct sip_msg *t_msg;
	struct via_body *via1;
	int is_ack;
	int dlg_parsed;
	int ret = 0;
	struct entry *hash_bucket;

	*cancel = 0;
	e2e_ack_trans = 0;
	via1 = p_msg->via1;
	is_ack = p_msg->REQ_METHOD == METHOD_ACK;
	dlg_parsed = 0;
	/* update parsed tid */
	via1->tid.s = via1->branch->value.s + MCOOKIE_LEN;
	via1->tid.len = via1->branch->value.len - MCOOKIE_LEN;

	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);
		t_msg = p_cell->uas.request;
		if(unlikely(!t_msg))
			continue; /*don't try matching UAC transactions */
		/* 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;

		/* 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 server 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.
		 */

		/* 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, "dlg parsing failed\n");
						return 0;
					}
				}
				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 */
				continue;
			}
			/* 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)*/
			continue;
		}
		/* now real tid matching occurs  for negative ACKs and any
		 * other requests */
		if(!via_matching(t_msg->via1 /* inv via */, via1 /* ack */))
			continue;
		/* check if call-id is still the same */
		if(cfg_get(tm, tm_cfg, callid_matching) && !EQ_LEN(callid)
				&& !EQ_STR(callid)) {
			LM_ERR("matching transaction found but callids"
				   " don't match (received: %.*s stored: %.*s)\n",
					p_msg->callid->body.len, p_msg->callid->body.s,
					t_msg->callid->body.len, t_msg->callid->body.s);
			continue;
		}
		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) {
				LM_DBG("matched skip method - s:0x%x t:0x%x m:0x%x -"
					   " continue searching\n",
						skip_method, t_msg->REQ_METHOD, p_msg->REQ_METHOD);
				continue;
			}
		}
	found:
		prefetch_w(p_cell); /* great chance of modifiying it */
		/* all matched -- we found the transaction ! */
		LM_DBG("RFC3261 transaction matched, tid=%.*s\n", via1->tid.len,
				via1->tid.s);
		*trans = p_cell;
		return 1;
	}
	/* ... we didn't find any */

	/* 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) */
	if(e2e_ack_trans) {
	e2eack_found:
		*trans = e2e_ack_trans;
		return 2;
	}
	LM_DBG("RFC3261 transaction matching failed - via branch [%.*s]\n",
			via1->branch->value.len, via1->branch->value.s);
	return 0;
}


/** 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.
 * Side-effects: sets T and T_branch
 * (T_branch is always set to T_BR_UNDEFINED).
 */

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;
	struct via_param *branch;
	int match_status;
	struct cell *e2e_ack_trans;
	struct entry *hash_bucket;

	/* parse all*/
	if(unlikely(check_transaction_quadruple(p_msg) == 0)) {
		LM_ERR("too few headers\n");
		set_t(0, T_BR_UNDEFINED);
		/* 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;
	LM_DBG("start searching: hash=%d, isACK=%d\n", p_msg->hash_index, isACK);


	/* assume not found */
	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) {
		LM_ERR("no via\n");
		set_t(0, T_BR_UNDEFINED);
		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 */
	LM_DBG("proceeding to pre-RFC3261 transaction matching\n");
	*cancel = 0;
	/* lock the whole entry*/
	LOCK_HASH(p_msg->hash_index);

	hash_bucket = &(get_tm_table()->entries[p_msg->hash_index]);

	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 */
			/* 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(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;
			/* 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(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;

			if((t_msg->REQ_METHOD == METHOD_CANCEL)
					&& (p_msg->REQ_METHOD != METHOD_CANCEL)) {
				/* we've matched an existing CANCEL */
				*cancel = 1;
				continue;
			}

			/* request matched ! */
			LM_DBG("non-ACK matched\n");
			goto found;
		}	 /* 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 */
			/* 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;
			/* 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(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) {
				/* 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) {
					LM_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;

				/* all criteria for proxied ACK are ok */
				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;
					}
					continue;
				}
				/* it's a local UAS transaction */
				if(dlg_matching(p_cell, p_msg))
					goto found;
				continue;
			} else {
				/* for hbh ACKs, From HF 'MUST' equal INVITE's one */
				if(!EQ_LEN(from))
					continue;
				if(!EQ_STR(from))
					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 a config option for broken
			 * UACs */
			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;

			/* wow -- we survived all the check! we matched! */
			LM_DBG("non-2xx ACK matched\n");
			goto found;
		} /* synonym loop */
	}	  /* ACK */

notfound:

	if(e2e_ack_trans) {
		p_cell = e2e_ack_trans;
		goto e2e_ack;
	}

	/* no transaction found */
	set_t(0, T_BR_UNDEFINED);
	if(!leave_new_locked) {
		UNLOCK_HASH(p_msg->hash_index);
	}
	LM_DBG("no transaction found\n");
	return -1;

e2e_ack:
	t_ack = p_cell; /* e2e proxied ACK */
	set_t(0, T_BR_UNDEFINED);
	if(!leave_new_locked) {
		UNLOCK_HASH(p_msg->hash_index);
	}
	LM_DBG("e2e proxy ACK found\n");
	return -2;

found:
	set_t(p_cell, T_BR_UNDEFINED);
	REF_UNSAFE(T);
	set_kr(REQ_EXIST);
	UNLOCK_HASH(p_msg->hash_index);
	LM_DBG("transaction found (T=%p)\n", T);
	return 1;
}


/* 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;
	struct entry *hash_bucket;
	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) {
			LM_ERR("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;
	LM_DBG("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) {
		LM_ERR("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);

	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);
		t_msg = p_cell->uas.request;

		if(!t_msg)
			continue; /* skip UAC transactions */

		/* we don't cancel CANCELs ;-) */
		if(unlikely(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(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;

		/* 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(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;

		/* found */
		goto found;
	}

notfound:
	/* no transaction found */
	LM_DBG(" no CANCEL matching found! \n");
	UNLOCK_HASH(hash_index);
	LM_DBG("lookup completed\n");
	return 0;

found:
	LM_DBG("canceled transaction found (%p)! \n", p_cell);
	REF_UNSAFE(p_cell);
	UNLOCK_HASH(hash_index);
	LM_DBG("found - lookup completed\n");
	return p_cell;
}


/** get the transaction corresponding to a reply.
 * @return -1 - nothing found,  1  - T found
 * Side-effects: sets T and T_branch on success.
 */
int t_reply_matching(struct sip_msg *p_msg, int *p_branch)
{
	struct cell *p_cell;
	unsigned int hash_index = 0;
	unsigned int entry_label = 0;
	unsigned int branch_id = 0;
	char *hashi, *branchi, *p, *n;
	struct entry *hash_bucket;
	int hashl, branchl;
	int scan_space;
	str cseq_method;
	str req_method;

	char *loopi;
	int loopl;

	short is_cancel;

	/* make compiler warnings happy */
	loopi = 0;
	loopl = 0;

	/* split the branch into pieces: loop_detection_check(ignored),
	 * hash_table_id, synonym_id, branch_id */

	if(!(p_msg->via1 && p_msg->via1->branch && p_msg->via1->branch->value.s))
		goto nomatch2;

	/* we do RFC 3261 tid matching and want to see first if there is
	 * magic cookie in branch */
	if(p_msg->via1->branch->value.len <= MCOOKIE_LEN)
		goto nomatch2;
	if(memcmp(p_msg->via1->branch->value.s, MCOOKIE, MCOOKIE_LEN) != 0)
		goto nomatch2;

	p = p_msg->via1->branch->value.s + MCOOKIE_LEN;
	scan_space = p_msg->via1->branch->value.len - MCOOKIE_LEN;


	/* hash_id */
	n = eat_token2_end(p, p + scan_space, BRANCH_SEPARATOR);
	hashl = n - p;
	scan_space -= hashl;
	if(!hashl || scan_space < 2 || *n != BRANCH_SEPARATOR)
		goto nomatch2;
	hashi = p;
	p = n + 1;
	scan_space--;

	/* 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--;

	/* branch id  -  should exceed the scan_space */
	n = eat_token_end(p, p + scan_space);
	branchl = n - p;
	if(!branchl)
		goto nomatch2;
	branchi = p;

	/* sanity check */
	if(unlikely(reverse_hex2int(hashi, hashl, &hash_index) < 0
				|| hash_index >= TABLE_ENTRIES
				|| reverse_hex2int(branchi, branchl, &branch_id) < 0
				|| branch_id >= sr_dst_max_branches || loopl != MD5_LEN)) {
		LM_DBG("poor reply ids - index %d label %d branch %d loopl %d/%d\n",
				hash_index, entry_label, branch_id, loopl, MD5_LEN);
		goto nomatch2;
	}


	LM_DBG("t_reply_matching: hash %d label %d branch %d\n", hash_index,
			entry_label, branch_id);


	/* search the hash table list at entry 'hash_index'; lock the entry first */
	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);
	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);

		if(cfg_get(tm, tm_cfg, callid_cseq_matching)) {
			if(memcmp(p_cell->callid.s + strlen("Call-ID: "),
					   p_msg->callid->body.s, p_msg->callid->body.len)
					!= 0) {
				LM_ERR("t_reply_matching: failed callid matching (instead of "
					   "md5): %d p_cell=%.*s p_msg=%.*s",
						p_msg->first_line.u.reply.statuscode,
						p_cell->callid.len, p_cell->callid.s,
						p_msg->callid->body.len, p_msg->callid->body.s);
				continue;
			}

			if(memcmp(p_cell->cseq_n.s + strlen("CSeq: "),
					   get_cseq(p_msg)->number.s, get_cseq(p_msg)->number.len)
					!= 0) {
				LM_ERR("t_reply_matching: failed cseq matching (instead of "
					   "md5): %d p_cell=%.*s p_msg=%.*s",
						p_msg->first_line.u.reply.statuscode,
						p_cell->cseq_n.len, p_cell->cseq_n.s,
						get_cseq(p_msg)->number.len, get_cseq(p_msg)->number.s);
				continue;
			}
		} else {
			if(memcmp(p_cell->md5, loopi, MD5_LEN) != 0)
				continue;
		}

		/* sanity check ... too high branch ? */
		if(unlikely(branch_id >= p_cell->nr_of_outgoings))
			continue;

		/* does method match ? (remember -- CANCELs have the same branch
		 * as canceled transactions) */
		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 */
						|| (is_cancel
								&& is_invite(p_cell)
								/* commented out -- should_cancel_branch set it to
						 * BUSY_BUFFER to avoid collisions with replies;
						 * thus, we test here by buffer size
						 */
								/* && p_cell->uac[branch_id].local_cancel.buffer ))) */
								&& p_cell->uac[branch_id]
										   .local_cancel.buffer_len)))
			continue;

		if(cfg_get(tm, tm_cfg, callid_matching) && p_cell->uas.request
				&& p_cell->uas.request->callid
				&& (p_msg->callid->body.len
								!= p_cell->uas.request->callid->body.len
						|| memcmp(p_msg->callid->body.s,
								   p_cell->uas.request->callid->body.s,
								   p_msg->callid->body.len)
								   != 0)) {
			LM_ERR("matching transaction found but callids"
				   " don't match (received: %.*s stored: %.*s)\n",
					p_msg->callid->body.len, p_msg->callid->body.s,
					p_cell->uas.request->callid->body.len,
					p_cell->uas.request->callid->body.s);
			continue;
		}

		/* passed all disqualifying factors - the transaction has been matched */
		set_t(p_cell, (int)branch_id);
		*p_branch = (int)branch_id;
		REF_UNSAFE(T);
		UNLOCK_HASH(hash_index);
		LM_DBG("reply (%p) matched an active transaction (T=%p)!\n", p_msg, T);
		if(likely(!(p_msg->msg_flags & FL_TM_RPL_MATCHED))) {
			/* if this is a 200 for INVITE, we will wish to store to-tags to be
			 * able to distinguish retransmissions later and not to call
			 * TMCB_RESPONSE_OUT uselessly; we do it only if callbacks are
			 * enabled -- except callback customers, nobody cares about
			 * retransmissions of multiple 200/INV or ACK/200s
			 */
			if(unlikely(is_invite(p_cell) && p_msg->REPLY_STATUS >= 200
						&& p_msg->REPLY_STATUS < 300
						&& ((!is_local(p_cell)
									&& has_tran_tmcbs(p_cell,
											TMCB_RESPONSE_OUT
													| TMCB_RESPONSE_READY
													| TMCB_E2EACK_IN
													| TMCB_E2EACK_RETR_IN))
								|| (is_local(p_cell)
										&& has_tran_tmcbs(p_cell,
												TMCB_LOCAL_COMPLETED))))) {
				if(parse_headers(p_msg, HDR_TO_F, 0) == -1) {
					LM_ERR("to parsing failed\n");
				}
			}
			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);
				}
			}
			p_msg->msg_flags |= FL_TM_RPL_MATCHED;
		} else {
			LM_DBG("reply in callbacks already done (T=%p)!\n", T);
		}
		return 1;
	} /* for cycle */

	/* nothing found */
	UNLOCK_HASH(hash_index);
	LM_DBG("no matching transaction exists\n");

nomatch2:
	LM_DBG("failure to match a transaction\n");
	*p_branch = -1;
	set_t(0, T_BR_UNDEFINED);
	return -1;
}


/** Determine current transaction (w/ e2eack support).
 *
 * 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
 * Side-effects: sets T and T_branch.
 */
int t_check_msg(struct sip_msg *p_msg, int *param_branch)
{
	int local_branch;
	int canceled;
	int ret;

	ret = 0;
	/* is T still up-to-date ? */
	LM_DBG("msg (%p) id=%u/%d global id=%u/%d T start=%p\n", p_msg, p_msg->id,
			p_msg->pid, tm_global_ctx_id.msgid, tm_global_ctx_id.pid, T);
	if(msg_ctx_id_match(p_msg, &tm_global_ctx_id) != 1 || T == T_UNDEFINED) {
		msg_ctx_id_set(p_msg, &tm_global_ctx_id);
		set_t(T_UNDEFINED, T_BR_UNDEFINED);
		/* transaction lookup */
		if(p_msg->first_line.type == SIP_REQUEST) {
			/* force parsing all the needed headers*/
			prefetch_loc_r(p_msg->unparsed + 64, 1);
			if(parse_headers(p_msg, HDR_EOH_F, 0) == -1) {
				LM_ERR("parsing error\n");
				goto error;
			}
			/* 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) {
				LM_ERR("from parsing failed\n");
				goto error;
			}
			ret = t_lookup_request(
					p_msg, 0 /* unlock before returning */, &canceled);
		} else {
			/* we need Via for branch and Cseq method to distinguish
			 * replies with the same branch/cseqNr (CANCEL)
			 * and we need all the WWW/Proxy Authenticate headers for
			 * 401 & 407 replies
			 */
			if(cfg_get(tm, tm_cfg, tm_aggregate_auth)
					&& (p_msg->REPLY_STATUS == 401
							|| p_msg->REPLY_STATUS == 407)) {
				if(parse_headers(p_msg, HDR_EOH_F, 0) == -1) {
					LM_WARN("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 | HDR_CALLID_F, 0)
					  == -1) {
				LM_ERR("reply cannot be parsed\n");
				goto error;
			}
			if((p_msg->via1 == 0) || (p_msg->cseq == 0)
					|| (p_msg->callid == 0)) {
				LM_ERR("reply doesn't have a via, cseq or call-id header\n");
				goto error;
			}
			/* if that is an INVITE, we will also need to-tag
			 * for later ACK matching
			 */
			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) {
					LM_ERR("INVITE reply cannot be parsed\n");
					goto error;
				}
			}
			ret = t_reply_matching(
					p_msg, param_branch != 0 ? param_branch : &local_branch);
		}
#ifdef EXTRA_DEBUG
		if(T && T != T_UNDEFINED && T->flags & (T_IN_AGONY)) {
			LM_WARN("transaction %p scheduled for deletion "
					"and called from t_check_msg (flags=%x) (but it might be "
					"ok)"
					" (msg %p)\n",
					T, T->flags, p_msg);
		}
#endif
		LM_DBG("msg (%p) id=%u/%d global id=%u/%d T end=%p\n", p_msg, p_msg->id,
				p_msg->pid, tm_global_ctx_id.msgid, tm_global_ctx_id.pid, T);
	} else { /* (msg_ctx_id_match(p_msg, &tm_global_ctx_id)!=1 || && T!=T_UNDEFINED ) */
		if(T) {
			LM_DBG("T (%p) already found for msg (%p)!\n", T, p_msg);
			ret = 1;
		} else {
			LM_DBG("T previously sought and not found for msg (%p)\n", p_msg);
			ret = -1;
		}
		if(likely(param_branch))
			*param_branch = T_branch;
	}
	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
 *
 * Side-effects: sets T and T_branch.
 */
int t_check(struct sip_msg *p_msg, int *param_branch)
{
	int ret;

	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;
}


int init_rb(struct retr_buf *rb, struct sip_msg *msg)
{
	/*struct socket_info* send_sock;*/
	struct via_body *via;
	int proto;

	/* rb. timers are init. init_t()/new_cell() */
	via = msg->via1;
	/* rb->dst is already init (0) by new_t()/build_cell() */
	if(!reply_to_via) {
		update_sock_struct_from_ip(&rb->dst.to, msg);
		proto = msg->rcv.proto;
	} else {
		/*init retrans buffer*/
		if(update_sock_struct_from_via(&(rb->dst.to), msg, via) == -1) {
			LM_ERR("cannot lookup reply dst: %.*s\n", via->host.len,
					via->host.s);
			ser_error = E_BAD_VIA;
			return 0;
		}
		proto = via->proto;
	}
	rb->dst.proto = proto;
	rb->dst.id = msg->rcv.proto_reserved1;
#ifdef USE_COMP
	rb->dst.comp = via->comp_no;
#endif
	rb->dst.send_flags = msg->rpl_send_flags;

	membar_write();
	rb->dst.send_sock = msg->rcv.bind_address;
	return 1;
}


static inline void init_new_t(struct cell *new_cell, struct sip_msg *p_msg)
{
	struct sip_msg *shm_msg;
	unsigned int timeout; /* avp timeout gets stored here (in s) */
	ticks_t lifetime;

	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;
	if(p_msg->REQ_METHOD == METHOD_INVITE) {
		/* 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 & (!cfg_get(tm, tm_cfg, tm_auto_inv_100) - 1);
		new_cell->flags |=
				T_DISABLE_6xx & (!cfg_get(tm, tm_cfg, disable_6xx) - 1);
		new_cell->flags |= T_NO_E2E_CANCEL_REASON
						   & (!!cfg_get(tm, tm_cfg, e2e_cancel_reason) - 1);
		/* reset flags */
		new_cell->flags &=
				(~get_msgid_val(user_cell_reset_flags, p_msg->id, int));

		lifetime =
				(ticks_t)get_msgid_val(user_inv_max_lifetime, p_msg->id, int);
		if(likely(lifetime == 0))
			lifetime = cfg_get(tm, tm_cfg, tm_max_inv_lifetime);
	} else {
		lifetime = (ticks_t)get_msgid_val(
				user_noninv_max_lifetime, p_msg->id, int);
		if(likely(lifetime == 0))
			lifetime = cfg_get(tm, tm_cfg, tm_max_noninv_lifetime);
	}
	new_cell->on_failure = get_on_failure();
	new_cell->on_branch_failure = get_on_branch_failure();
	new_cell->on_reply = get_on_reply();
	new_cell->end_of_life = get_ticks_raw() + lifetime;
	;
	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);
	if(likely(new_cell->fr_timeout == 0)) {
		if(unlikely(!fr_avp2timer(&timeout))) {
			LM_DBG("init_new_t: FR__TIMER = %d s\n", timeout);
			new_cell->fr_timeout = S_TO_TICKS((ticks_t)timeout);
		} else {
			new_cell->fr_timeout = cfg_get(tm, tm_cfg, fr_timeout);
		}
	}
	if(likely(new_cell->fr_inv_timeout == 0)) {
		if(unlikely(!fr_inv_avp2timer(&timeout))) {
			LM_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 {
			new_cell->fr_inv_timeout = cfg_get(tm, tm_cfg, fr_inv_timeout);
		}
	}
	new_cell->rt_t1_timeout_ms = (retr_timeout_t)get_msgid_val(
			user_rt_t1_timeout_ms, p_msg->id, int);
	if(likely(new_cell->rt_t1_timeout_ms == 0))
		new_cell->rt_t1_timeout_ms = cfg_get(tm, tm_cfg, rt_t1_timeout_ms);
	new_cell->rt_t2_timeout_ms = (retr_timeout_t)get_msgid_val(
			user_rt_t2_timeout_ms, p_msg->id, int);
	if(likely(new_cell->rt_t2_timeout_ms == 0))
		new_cell->rt_t2_timeout_ms = cfg_get(tm, tm_cfg, rt_t2_timeout_ms);
	new_cell->on_branch = get_on_branch();
}


/** 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).
 */
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) {
		LM_ERR("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) {
		LM_ERR("uri invalid\n");
		return E_BAD_REQ;
	}

	/* add new transaction */
	new_cell = build_cell(p_msg);
	if(!new_cell) {
		LM_ERR("out of mem:\n");
		return E_OUT_OF_MEM;
	}

	INIT_REF(new_cell, 2); /* 1 because it will be ref'ed from the
							* hash and +1 because we set T to it */
	insert_into_hash_table_unsafe(new_cell, p_msg->hash_index);
	set_t(new_cell, T_BR_UNDEFINED);
	/* init pointers to headers needed to construct local
	 * requests such as CANCEL/ACK
	 */
	init_new_t(new_cell, p_msg);
	return 1;
}


/** 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).
 */
int t_newtran(struct sip_msg *p_msg)
{
	int lret, my_err;
	int canceled;


	/* is T still up-to-date ? */
	LM_DBG("msg (%p) id=%u/%d global id=%u/%d T start=%p\n", p_msg, p_msg->id,
			p_msg->pid, tm_global_ctx_id.msgid, tm_global_ctx_id.pid, T);

	if(faked_msg_match(p_msg)) {
		LM_INFO("attempt to create transaction for a faked request"
				" - try to avoid it\n");
	}
	if(T && T != T_UNDEFINED) {
		/* ERROR message moved to w_t_newtran */
		LM_DBG("transaction already in process %p\n", T);

		/* 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;
			memcpy(T->uas.request->xflags, p_msg->xflags,
					KSR_XFLAGS_SIZE * sizeof(flag_t));
		}

		return E_SCRIPT;
	}

	msg_ctx_id_set(p_msg, &tm_global_ctx_id);
	set_t(T_UNDEFINED, T_BR_UNDEFINED);
	/* 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
	 */

	if(parse_headers(p_msg, HDR_EOH_F, 0)) {
		LM_ERR("parse_headers failed\n");
		return E_BAD_REQ;
	}
	if((p_msg->parsed_flag & HDR_EOH_F) != HDR_EOH_F) {
		LM_ERR("EoH not parsed\n");
		return E_OUT_OF_MEM;
	}
	/* t_lookup_requests attempts to find the transaction;
	 * it also calls check_transaction_quadruple -> it is
	 * safe to assume we have from/callid/cseq/to
	 */
	lret = t_lookup_request(
			p_msg, 1 /* leave locked if not found */, &canceled);

	/* on error, pass the error in the stack ... nothing is locked yet
	 * if 0 is returned */
	if(lret == 0)
		return E_BAD_TUPEL;

	/* transaction found, it's a retransmission  */
	if(lret > 0) {
		if(T == NULL || T == T_UNDEFINED) {
			LM_ERR("BUG: transaction is gone\n");
			return 0;
		}
		if(p_msg->REQ_METHOD == METHOD_ACK) {
			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);
			t_release_transaction(T);
		} else {
			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);
			t_retransmit_reply(T);
		}
		/* things are done -- return from script */
		return 0;
	}

	/* 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 */
		if(likely(!has_tran_tmcbs(
				   t_ack, TMCB_E2EACK_IN | TMCB_E2EACK_RETR_IN))) {
			UNLOCK_HASH(p_msg->hash_index);
			return 1;
		}
		REF_UNSAFE(t_ack);
		UNLOCK_HASH(p_msg->hash_index);
		/* we don't call from within REPLY_LOCK -- that introduces
		 * 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  */
		if(unmatched_totag(t_ack, p_msg)) {
			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);
		}
		UNREF(t_ack);
		return 1;
	}


	/* 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;
	}

	my_err = new_t(p_msg);
	if(my_err < 0) {
		LM_ERR("new_t failed\n");
		goto new_err;
	}
	if(canceled)
		T->flags |= T_CANCELED; /* mark it for future ref. */


	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)) {
		LM_ERR("unresolvable via1\n");
		put_on_wait(T);
		t_unref(p_msg);
		return E_BAD_VIA;
	}

	return 1;


new_err:
	UNLOCK_HASH(p_msg->hash_index);
	return my_err;
}


/** 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.
 */
int t_unref(struct sip_msg *p_msg)
{
	enum kill_reason kr;

	if(T == T_UNDEFINED || T == T_NULL_CELL)
		return -1;
	if(p_msg->first_line.type == SIP_REQUEST) {
		kr = get_kr();
		if(unlikely(kr == REQ_ERR_DELAYED)) {
			LM_DBG("delayed error reply generation(%d)\n", tm_error);
			if(unlikely(is_route_type(FAILURE_ROUTE))) {
				LM_BUG("called w/ kr=REQ_ERR_DELAYED in failure"
					   " route for %p\n",
						T);
			} else if(unlikely(kill_transaction(T, tm_error) <= 0)) {
				// could be a valid error, or due to an immediate CANCEL
				LM_WARN("generation of a delayed stateful reply"
						" failed\n");
				t_release_transaction(T);
			}
		} else if(unlikely(kr == 0
						   || (p_msg->REQ_METHOD == METHOD_ACK
								   && !(kr & REQ_RLSD)))) {
			LM_WARN("script writer didn't release transaction\n");
			t_release_transaction(T);
		} else if(unlikely((kr & REQ_ERR_DELAYED)
						   && (kr
								   & ~(REQ_RLSD | REQ_RPLD | REQ_ERR_DELAYED
										   | REQ_FWDED)))) {
			LM_BUG("REQ_ERR DELAYED should have been caught much"
				   " earlier for %p: %d (hex %x)\n",
					T, kr, kr);
			t_release_transaction(T);
		}
	}
	tm_error = 0; /* clear it */
	UNREF(T);
	set_t(T_UNDEFINED, T_BR_UNDEFINED);
	return 1;
}


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) {
		LM_ERR("no transaction found\n");
		return -1;
	}
	t = get_t();
	if(!t) {
		LM_ERR("transaction found is NULL\n");
		return -1;
	}

	*hash_index = t->hash_index;
	*label = t->label;

	return 1;
}

/**
 * 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) {
		LM_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;
	LM_DBG("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;
}


/** 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).
 * @param filter - if 1, filter out transactions put on-wait (terminated state).
 * @return -1 on error/not found, 1 on success (found)
 * Side-effects: sets T and T_branch (T_branch always to T_BR_UNDEFINED).
 */
int t_lookup_ident_filter(struct cell **trans, unsigned int hash_index,
		unsigned int label, int filter)
{
	struct cell *p_cell;
	struct entry *hash_bucket;

	if(unlikely(hash_index >= TABLE_ENTRIES)) {
		LM_ERR("invalid hash_index=%u\n", hash_index);
		return -1;
	}

	LOCK_HASH(hash_index);

#ifndef E2E_CANCEL_HOP_BY_HOP
#warning "t_lookup_ident() can only reliably match INVITE transactions in " \
	"E2E_CANCEL_HOP_BY_HOP mode"
#endif
	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);
		if(p_cell->label == label) {
			if(filter == 1) {
				if(t_on_wait(p_cell)) {
					/* transaction in terminated state */
					UNLOCK_HASH(hash_index);
					set_t(0, T_BR_UNDEFINED);
					*trans = NULL;
					LM_DBG("transaction in terminated phase - skipping\n");
					return -1;
				}
			}
			REF_UNSAFE(p_cell);
			UNLOCK_HASH(hash_index);
			set_t(p_cell, T_BR_UNDEFINED);
			*trans = p_cell;
			LM_DBG("transaction found\n");
			return 1;
		}
	}

	UNLOCK_HASH(hash_index);
	set_t(0, T_BR_UNDEFINED);
	*trans = NULL;

	LM_DBG("transaction not found\n");

	return -1;
}

/** 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).
 */
int t_lookup_ident(
		struct cell **trans, unsigned int hash_index, unsigned int label)
{
	return t_lookup_ident_filter(trans, hash_index, label, 0);
}

/** find 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).
 * @param filter - if 1, skip transaction put on-wait (terminated state).
 * @return transaction cell pointer
 * Note: it does not sets T and T_branch, nor reference the transaction,
 *   useful to quickly check if a transaction still exists
 */
tm_cell_t *t_find_ident_filter(
		unsigned int hash_index, unsigned int label, int filter)
{
	tm_cell_t *p_cell;
	tm_entry_t *hash_bucket;

	if(unlikely(hash_index >= TABLE_ENTRIES)) {
		LM_ERR("invalid hash_index=%u\n", hash_index);
		return NULL;
	}

	LOCK_HASH(hash_index);

	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);
		if(p_cell->label == label) {
			if(filter == 1) {
				if(t_on_wait(p_cell)) {
					/* transaction in terminated state */
					UNLOCK_HASH(hash_index);
					LM_DBG("transaction in terminated phase - skipping\n");
					return NULL;
				}
			}
			UNLOCK_HASH(hash_index);
			LM_DBG("transaction found\n");
			return p_cell;
		}
	}

	UNLOCK_HASH(hash_index);
	LM_DBG("transaction not found\n");

	return NULL;
}

/** 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.
 */
int t_is_local(struct sip_msg *p_msg)
{
	struct cell *t;
	if(t_check(p_msg, 0) != 1) {
		LM_ERR("no transaction found\n");
		return -1;
	}
	t = get_t();
	if(!t) {
		LM_ERR("transaction found is NULL\n");
		return -1;
	}

	return is_local(t);
}

/** 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).
 */
int t_lookup_callid(struct cell **trans, str callid, str cseq)
{
	struct cell *p_cell;
	unsigned hash_index;
	struct entry *hash_bucket;

	/* I use MAX_HEADER, not sure if this is a good choice... */
	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);

	if(unlikely(hash_index >= TABLE_ENTRIES)) {
		LM_ERR("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);
	LM_DBG("created comparable call_id header field: >%.*s<\n",
			(int)(endpos - callid_header), callid_header);

	endpos = print_cseq_mini(cseq_header, &cseq, &invite_method);
	LM_DBG("created comparable cseq header field: >%.*s<\n",
			(int)(endpos - cseq_header), cseq_header);

	LOCK_HASH(hash_index);
	LM_DBG("just locked hash index %u, looking for transactions there:\n",
			hash_index);

	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);
		/* 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)) {
			LM_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);
			REF_UNSAFE(p_cell);
			UNLOCK_HASH(hash_index);
			set_t(p_cell, T_BR_UNDEFINED);
			*trans = p_cell;
			LM_DBG("t_lookup_callid: transaction found.\n");
			return 1;
		}
		LM_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);
	LM_DBG("transaction not found.\n");

	return -1;
}


/* 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)) {
		LM_ERR("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)) {
		LM_ERR("fr_timeout too small (%d)\n", fr_to);
		return -1;
	}

	t = get_t();
	/* 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
	 * created; if not -> use the static variables */
	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 {
#ifdef TIMER_DEBUG
		LM_DBG("changing default FR timeout values: (\"fr_inv_timeout\": %d, "
			   "\"fr_timeout\": %d)\n",
				fr_inv, fr);
#endif
		change_fr(t, fr_inv, fr); /* change running uac timers */
	}
	return 1;
}

/* reset fr_timer and fr_inv_timer to the default values */
int t_reset_fr()
{
	struct cell *t;

	t = get_t();
	/* 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
	 * 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;
}


/* 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_ms, unsigned int t2_ms)
{
	struct cell *t;
	ticks_t retr_t1, retr_t2;

	retr_t1 = MS_TO_TICKS((ticks_t)t1_ms);
	if(unlikely((retr_t1 == 0) && (t1_ms != 0))) {
		LM_ERR("retr. t1 interval too small (%u)\n", t1_ms);
		return -1;
	}
	if(unlikely(MAX_UVAR_VALUE(t->rt_t1_timeout_ms) < t1_ms)) {
		LM_ERR("retr. t1 interval too big: %d (max %lu)\n", t1_ms,
				MAX_UVAR_VALUE(t->rt_t1_timeout_ms));
		return -1;
	}
	retr_t2 = MS_TO_TICKS((ticks_t)t2_ms);
	if(unlikely((retr_t2 == 0) && (t2_ms != 0))) {
		LM_ERR("retr. t2 interval too small (%d)\n", t2_ms);
		return -1;
	}
	if(unlikely(MAX_UVAR_VALUE(t->rt_t2_timeout_ms) < t2_ms)) {
		LM_ERR("retr. t2 interval too big: %u (max %lu)\n", t2_ms,
				MAX_UVAR_VALUE(t->rt_t2_timeout_ms));
		return -1;
	}

	t = get_t();
	/* 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
	 * created; if not -> use the static variables */
	if(!t || t == T_UNDEFINED) {
		set_msgid_val(user_rt_t1_timeout_ms, msg->id, int, (int)t1_ms);
		set_msgid_val(user_rt_t2_timeout_ms, msg->id, int, (int)t2_ms);
	} else {
#ifdef TIMER_DEBUG
		LM_DBG("changing default RETR timeout values to: "
			   "(\"retr_t1_interval\": %d, \"retr_t2_interval\": %d)\n",
				t1_ms, t2_ms);
#endif
		change_retr(t, 1, t1_ms, t2_ms); /* change running uac timers */
	}
	return 1;
}

/* reset retr. t1 and t2 to the default values */
int t_reset_retr()
{
	struct cell *t;

	t = get_t();
	/* 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
	 * created; if not -> use the static variables */
	if(!t || t == T_UNDEFINED) {
		memset(&user_rt_t1_timeout_ms, 0, sizeof(user_rt_t1_timeout_ms));
		memset(&user_rt_t2_timeout_ms, 0, sizeof(user_rt_t2_timeout_ms));
	} else {
		/* change running uac timers */
		change_retr(t, 1, cfg_get(tm, tm_cfg, rt_t1_timeout_ms),
				cfg_get(tm, tm_cfg, rt_t2_timeout_ms));
	}
	return 1;
}


/* 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))) {
		LM_ERR("non-inv. interval too small (%d)\n", lifetime_noninv_to);
		return -1;
	}
	if(unlikely((max_inv_lifetime == 0) && (lifetime_inv_to != 0))) {
		LM_ERR("inv. interval too small (%d)\n", lifetime_inv_to);
		return -1;
	}

	t = get_t();
	/* 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
	 * 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;
}

/* reset maximum invite/non-invite lifetime to the default value */
int t_reset_max_lifetime()
{
	struct cell *t;

	t = get_t();
	/* 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
	 * 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;
}

#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));
	_tm_ctx.branch_index = T_BR_UNDEFINED;
}

void tm_ctx_set_branch_index(int v)
{
	_tm_ctx.branch_index = v;
}

#endif
