/*
 * $Id$
 *
 * 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 worx 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 wuld 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. 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
 * SYNONYMS off: hash.md5.branch
 *
 * -jiri
 *
 *
 * Copyright (C) 2001-2003 Fhg Fokus
 *
 * 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
 *
 * History:
 * ----------
 * 2003-01-23  options for disabling r-uri matching introduced (jiri)
 *              nameser_compat.h (andrei)
 * 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)
 */


#include "defs.h"


#include <assert.h>
#include "../../comp_defs.h"
#include "../../dprint.h"
#include "../../config.h"
#include "../../parser/parser_f.h"
#include "../../parser/parse_from.h"
#include "../../ut.h"
#include "../../timer.h"
#include "../../hash_func.h"
#include "../../globals.h"
#include "../../forward.h"
#include "t_funcs.h"
#include "config.h"
#include "sip_msg.h"
#include "t_hooks.h"
#include "t_lookup.h"

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

/* should be request-uri matching used as a part of pre-3261 
 * transaction matching, as the standard wants us to do so
 * (and is reasonable to do so, to be able to distinguish
 * spirals)? turn only off for better interaction with 
 * devices that are broken and send different r-uri in
 * CANCEL/ACK than in original INVITE
 */
int ruri_matching=1;

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

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

static struct cell *T;

/* 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
*/
unsigned int     global_msg_id;

struct cell *get_t() { return T; }
void set_t(struct cell *t) { T=t; }
void init_t() {global_msg_id=0; set_t(T_UNDEFINED);}

static inline int parse_dlg( struct sip_msg *msg )
{
	if (parse_headers(msg, HDR_FROM | HDR_CSEQ | HDR_TO, 0)==-1) {
		LOG(L_ERR, "ERROR: tid_matching: From or Cseq or To invalid\n");
		return 0;
	}
	if (parse_from_header(msg)==-1) {
		LOG(L_ERR, "ERROR: tid_matching: From broken\n");
		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;
}

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 (p_cell->relaied_reply_branch!=-2) {
		return 2; /* e2e proxied ACK */
	}
	/* 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
	 * originater 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)
		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;
}


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

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

	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;

	for ( p_cell = get_tm_table()->entrys[p_msg->hash_index].first_cell;
		p_cell; p_cell = p_cell->next_cell ) 
	{
		t_msg=p_cell->uas.request;
		if (skip_method & t_msg->REQ_METHOD)
			continue;

		/* dialog matching needs to be applied for ACK/200s */
		if (is_ack && p_cell->uas.status<300) {
			/* make sure we have parsed all things we need for dialog
			 * matching */
			if (!dlg_parsed) {
				dlg_parsed=1;
				if (!parse_dlg(p_msg)) {
					LOG(L_ERR, "ERROR: tid_matching: dlg parsing failed\n");
					return 0;
				}
			}
			ret=ack_matching(p_cell /* t w/invite */, p_msg /* ack */);
			if (ret>0) {
				*trans=p_cell;
				return ret; /* 2: e2e proxied ACK, 1 e2e UAS ACK */
			}
			/* 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;
		}
		/* now real tid matching occurs  for negative ACKs and any 
	 	 * other requests */
		if (!via_matching(t_msg->via1 /* inv via */, via1 /* ack */ ))
			continue;
		/* all matched -- we found the transaction ! */
		DBG("DEBUG: RFC3261 transaction matched, tid=%.*s\n",
			via1->tid.len, via1->tid.s);

		*trans=p_cell;
		return 1;
	}
	/* :-( ... we didn't find any */
	DBG("DEBUG: RFC3261 transaction matching failed\n");
	return 0;
}


/* function returns:
 *      negative - transaction wasn't found
 *			(-2 = possibly e2e ACK matched )
 *      positive - transaction found
 */

int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked )
{
	struct cell         *p_cell;
	unsigned int       isACK;
	struct sip_msg  *t_msg;
	int ret;
	struct via_param *branch;
	int match_status;

	/* parse all*/
	if (check_transaction_quadruple(p_msg)==0)
	{
		LOG(L_ERR, "ERROR: TM module: t_lookup_request: too few headers\n");
		set_t(0);	
		/* stop processing */
		return 0;
	}

	/* start searching into the table */
	if (!p_msg->hash_index)
		p_msg->hash_index=hash( p_msg->callid->body , get_cseq(p_msg)->number ) ;
	isACK = p_msg->REQ_METHOD==METHOD_ACK;
	DBG("t_lookup_request: start searching: hash=%d, isACK=%d\n",
		p_msg->hash_index,isACK);


	/* asume not found */
	ret=-1;

	/* first of all, look if there is RFC3261 magic cookie in branch; if
	 * so, we can do very quick matching and skip the old-RFC bizzar
	 * comparison of many header fields
	 */
	if (!p_msg->via1) {
		LOG(L_ERR, "ERROR: t_lookup_request: no via\n");
		set_t(0);	
		return 0;
	}
	branch=p_msg->via1->branch;
	if (branch && branch->value.s && branch->value.len>MCOOKIE_LEN
			&& memcmp(branch->value.s,MCOOKIE,MCOOKIE_LEN)==0) {
		/* huhuhu! the cookie is there -- let's proceed fast */
		LOCK_HASH(p_msg->hash_index);
		match_status=matching_3261(p_msg,&p_cell, 
				/* skip transactions with different method; otherwise CANCEL would 
	 	 		 * match the previous INVITE trans.  */
				isACK ? ~METHOD_INVITE: ~p_msg->REQ_METHOD);
		switch(match_status) {
				case 0:	goto notfound;	/* no match */
				case 1:	goto found; 	/* match */
				case 2:	goto e2e_ack;	/* e2e proxy ACK */
		}
	}

	/* ok -- it's ugly old-fashioned transaction matching -- it is
	 * a bit simplified to be fast -- we don't do all the comparisons
	 * of parsed uri, which was simply too bloated */
	DBG("DEBUG: proceeding to pre-RFC3261 transaction matching\n");

	/* lock the whole entry*/
	LOCK_HASH(p_msg->hash_index);

	/* all the transactions from the entry are compared */
	for ( p_cell = get_tm_table()->entrys[p_msg->hash_index].first_cell;
		  p_cell; p_cell = p_cell->next_cell ) 
	{
		t_msg = p_cell->uas.request;

		if (!isACK) {	
			/* compare lengths first */ 
			if (!EQ_LEN(callid)) continue;
			if (!EQ_LEN(cseq)) continue;
			if (!EQ_LEN(from)) continue;
			if (!EQ_LEN(to)) continue;
			if (ruri_matching && !EQ_REQ_URI_LEN) continue;
			if (!EQ_VIA_LEN(via1)) continue;

			/* length ok -- move on */
			if (!EQ_STR(callid)) continue;
			if (!EQ_STR(cseq)) continue;
			if (!EQ_STR(from)) continue;
			if (!EQ_STR(to)) continue;
			if (ruri_matching && !EQ_REQ_URI_STR) continue;
			if (!EQ_VIA_STR(via1)) continue;

			/* request matched ! */
			DBG("DEBUG: non-ACK matched\n");
			goto found;
		} else { /* it's an ACK request*/
			/* ACK's relate only to INVITEs */
			if (t_msg->REQ_METHOD!=METHOD_INVITE) continue;

			/* From|To URI , CallID, CSeq # must be always there */
			/* compare lengths now */
			if (!EQ_LEN(callid)) continue;
			/* CSeq only the number without method ! */
			if (get_cseq(t_msg)->number.len!=get_cseq(p_msg)->number.len)
				continue;
			if (! EQ_LEN(from)) continue;
			/* To only the uri -- to many UACs screw up tags  */
			if (get_to(t_msg)->uri.len!=get_to(p_msg)->uri.len)
				continue;
			if (!EQ_STR(callid)) continue;
			if (memcmp(get_cseq(t_msg)->number.s, get_cseq(p_msg)->number.s,
				get_cseq(p_msg)->number.len)!=0) continue;
			if (!EQ_STR(from)) continue;
			if (memcmp(get_to(t_msg)->uri.s, get_to(p_msg)->uri.s,
				get_to(t_msg)->uri.len)!=0) continue;

			/* it is e2e ACK/200 */
			if (p_cell->uas.status<300) {
				/* all criteria for proxied ACK are ok */
				if (p_cell->relaied_reply_branch!=-2) 
					goto e2e_ack;
				/* it's a local UAS transaction */
				if (dlg_matching(p_cell, p_msg))
					goto found;
				continue;
			}

			/* it is not an e2e ACK/200 -- perhaps it is 
			 * local negative case; in which case we will want
			 * more elements to match: r-uri and via; allow
			 * mismatching r-uri as an config option for broken
			 * UACs */
			if (ruri_matching && ! EQ_REQ_URI_LEN ) continue;
			if (! EQ_VIA_LEN(via1)) continue;
			if (ruri_matching && !EQ_REQ_URI_STR) continue;
			if (!EQ_VIA_STR(via1)) continue;

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

notfound:
	/* no transaction found */
	set_t(0);
	if (!leave_new_locked) {
		UNLOCK_HASH(p_msg->hash_index);
	}
	DBG("DEBUG: t_lookup_request: no transaction found\n");
	return -1;

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

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



/* function lookups transaction being cancelled by CANCEL in p_msg;
 * it returns:
 *       0 - transaction wasn't found
 *       T - transaction found
 */
struct cell* t_lookupOriginalT(  struct sip_msg* p_msg )
{
	struct cell     *p_cell;
	unsigned int     hash_index;
	struct sip_msg  *t_msg;
	struct via_param *branch;
	int ret;


	/* start searching in the table */
	hash_index = p_msg->hash_index;
	DBG("DEBUG: t_lookupOriginalT: searching on hash entry %d\n",hash_index );


	/* first of all, look if there is RFC3261 magic cookie in branch; if
	 * so, we can do very quick matching and skip the old-RFC bizzar
	 * comparison of many header fields
	 */
	if (!p_msg->via1) {
		LOG(L_ERR, "ERROR: t_lookup_request: no via\n");
		set_t(0);
		return 0;
	}
	branch=p_msg->via1->branch;
	if (branch && branch->value.s && branch->value.len>MCOOKIE_LEN
			&& memcmp(branch->value.s,MCOOKIE,MCOOKIE_LEN)==0) {
		/* huhuhu! the cookie is there -- let's proceed fast */
		LOCK_HASH(hash_index);
		ret=matching_3261(p_msg, &p_cell,
				/* we are seeking the original transaction --
				 * skip CANCEL transactions during search
				 */
				METHOD_CANCEL);
		if (ret==1) goto found; else goto notfound;
	}

	/* no cookies --proceed to old-fashioned pre-3261 t-matching */

	LOCK_HASH(hash_index);

	/* all the transactions from the entry are compared */
	for (p_cell=get_tm_table()->entrys[hash_index].first_cell;
		p_cell; p_cell = p_cell->next_cell )
	{
		t_msg = p_cell->uas.request;

		/* we don't cancel CANCELs ;-) */
		if (p_cell->uas.request->REQ_METHOD==METHOD_CANCEL)
			continue;

		/* check lengths now */	
		if (!EQ_LEN(callid))
			continue;
		if (get_cseq(t_msg)->number.len!=get_cseq(p_msg)->number.len)
			continue;
		if (!EQ_LEN(from))
			continue;
#ifdef CANCEL_TAG
		if (!EQ_LEN(to))
			continue;
#else
		/* relaxed matching -- we don't care about to-tags anymore,
		 * many broken UACs screw them up and ignoring them does not
		 * actually hurt
		 */
		if (get_to(t_msg)->uri.len!=get_to(p_msg)->uri.len)
			continue;
#endif
		if (ruri_matching && !EQ_REQ_URI_LEN)
			continue;
		if (!EQ_VIA_LEN(via1))
			continue;

		/* check the content now */
		if (!EQ_STR(callid))
			continue;
		if (memcmp(get_cseq(t_msg)->number.s,
			get_cseq(p_msg)->number.s,get_cseq(p_msg)->number.len)!=0)
			continue;
		if (!EQ_STR(from))
			continue;
#ifdef CANCEL_TAG
		if (!EQ_STR(to))
			continue;
#else
		if (memcmp(get_to(t_msg)->uri.s, get_to(p_msg)->uri.s,
					get_to(t_msg)->uri.len)!=0)
			continue;
#endif
		if (ruri_matching && !EQ_REQ_URI_STR)
			continue;
		if (!EQ_VIA_STR(via1))
			continue;

		/* found */
		goto found;
	}

notfound:
	/* no transaction found */
	DBG("DEBUG: t_lookupOriginalT: no CANCEL maching found! \n" );
	UNLOCK_HASH(hash_index);
	DBG("DEBUG: t_lookupOriginalT completed\n");
	return 0;

found:
	DBG("DEBUG: t_lookupOriginalT: canceled transaction"
		" found (%p)! \n",p_cell );
	REF_UNSAFE( p_cell );
	UNLOCK_HASH(hash_index);
	DBG("DEBUG: t_lookupOriginalT completed\n");
	return p_cell;
}




/* Returns 0 - nothing found
 *         1  - T found
 */
int t_reply_matching( struct sip_msg *p_msg , int *p_branch )
{
	struct cell*  p_cell;
	int hash_index   = 0;
	int entry_label  = 0;
	int branch_id    = 0;
	char  *hashi, *branchi, *p, *n;
	int hashl, branchl;
	int scan_space;
	str cseq_method;
	str req_method;

	char *loopi;
	int loopl;
	char *syni;
	int synl;
	
	short is_cancel;

	/* make compiler warnnings happy */
	loopi=0;
	loopl=0;
	syni=0;
	synl=0;

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

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

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

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


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

	if (!syn_branch) {
		/* md5 value */
		n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR );
		loopl = n-p;
		scan_space-= loopl;
		if (n==p || scan_space<2 || *n!=BRANCH_SEPARATOR) 
			goto nomatch2;
		loopi=p;
		p=n+1; scan_space--;
	} else {
		/* synonym id */
		n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR);
		synl=n-p;
		scan_space-=synl;
		if (!synl || scan_space<2 || *n!=BRANCH_SEPARATOR) 
			goto nomatch2;
		syni=p;
		p=n+1;scan_space--;
	}

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

	/* sanity check */
	if ((hash_index=reverse_hex2int(hashi, hashl))<0
		||hash_index>=TABLE_ENTRIES
		|| (branch_id=reverse_hex2int(branchi, branchl))<0
		||branch_id>=MAX_BRANCHES
		|| (syn_branch ? (entry_label=reverse_hex2int(syni, synl))<0 
			: loopl!=MD5_LEN )
	) {
		DBG("DEBUG: t_reply_matching: poor reply lables %d label %d "
			"branch %d\n",hash_index, entry_label, branch_id );
		goto nomatch2;
	}


	DBG("DEBUG: 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);
	for (p_cell = get_tm_table()->entrys[hash_index].first_cell; p_cell; 
		p_cell=p_cell->next_cell) {

		/* first look if branch matches */

		if (syn_branch) {
			if (p_cell->label != entry_label) 
				continue;
		} else {
			if ( memcmp(p_cell->md5, loopi,MD5_LEN)!=0)
					continue;
		}

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

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


		/* we passed all disqualifying factors .... the transaction has been
		   matched !
		*/
		set_t(p_cell);
		*p_branch = branch_id;
		REF_UNSAFE( T );
		UNLOCK_HASH(hash_index);
		DBG("DEBUG: t_reply_matching: reply matched (T=%p)!\n",T);
		/* if this is a 200 for INVITE, we will wish to store to-tags to be
		 * able to distuingish 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 (p_cell->is_invite && p_msg->REPLY_STATUS>=200 
				&& p_msg->REPLY_STATUS<300 
				&& ( (!p_cell->local && 
					(callback_array[TMCB_RESPONSE_OUT]||
						callback_array[TMCB_E2EACK_IN]))
					|| (p_cell->local && callback_array[TMCB_LOCAL_COMPLETED]) )) {
			if (parse_headers(p_msg, HDR_TO, 0)==-1) {
				LOG(L_ERR, "ERROR: t_reply_matching: to parsing failed\n");
			}
		}
		if (!p_cell->local) 
			callback_event(TMCB_RESPONSE_IN, T, p_msg, p_msg->REPLY_STATUS);
		return 1;
	} /* for cycle */

	/* nothing found */
	UNLOCK_HASH(hash_index);
	DBG("DEBUG: t_reply_matching: no matching transaction exists\n");

nomatch2:
	DBG("DEBUG: t_reply_matching: failure to match a transaction\n");
	*p_branch = -1;
	set_t(0);
	return -1;
}




/* Determine current transaction
 *
 *                   Found      Not Found     Error (e.g. parsing)
 *  Return Value     1          0             -1
 *  T                ptr        0             T_UNDEFINED
 */
int t_check( struct sip_msg* p_msg , int *param_branch )
{
	int local_branch;

	/* is T still up-to-date ? */
	DBG("DEBUG: t_check: msg id=%d global id=%d T start=%p\n", 
		p_msg->id,global_msg_id,T);
	if ( p_msg->id != global_msg_id || T==T_UNDEFINED )
	{
		global_msg_id = p_msg->id;
		T = T_UNDEFINED;
		/* transaction lookup */
		if ( p_msg->first_line.type==SIP_REQUEST ) {
			/* force parsing all the needed headers*/
			if (parse_headers(p_msg, HDR_EOH, 0 )==-1) {
				LOG(L_ERR, "ERROR: t_check: parsing error\n");
				return -1;
			}
			/* 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) {
				LOG(L_ERR, "ERROR: t_check: from parsing failed\n");
				return -1;
			}
			t_lookup_request( p_msg , 0 /* unlock before returning */ );
		} else {
			/* we need Via for branch and Cseq method to distinguish
			   replies with the same branch/cseqNr (CANCEL)
			*/
			if ( parse_headers(p_msg, HDR_VIA1|HDR_CSEQ, 0 )==-1
			|| !p_msg->via1 || !p_msg->cseq ) {
				LOG(L_ERR, "ERROR: reply cannot be parsed\n");
				return -1;
			}

			/* 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, 0)==-1
						|| !p_msg->to)  {
						LOG(L_ERR, "ERROR: INVITE reply cannot be parsed\n");
						return -1;
					}
			}

			t_reply_matching( p_msg ,
				param_branch!=0?param_branch:&local_branch );

		}
#ifdef EXTRA_DEBUG
		if ( T && T!=T_UNDEFINED && T->damocles) {
			LOG( L_ERR, "ERROR: transaction %p scheduled for deletion "
				"and called from t_check\n", T);
			abort();
		}
#endif
		DBG("DEBUG: t_check: msg id=%d global id=%d T end=%p\n",
			p_msg->id,global_msg_id,T);
	} else {
		if (T)
			DBG("DEBUG: t_check: T alredy found!\n");
		else
			DBG("DEBUG: t_check: T previously sought and not found\n");
	}

	return T ? (T==T_UNDEFINED ? -1 : 1 ) : 0;
}

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

	via=msg->via1;
	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),via )==-1) {
			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;
		}
		proto=via->proto;
	}
	rb->dst.proto=proto;
	rb->dst.proto_reserved1=msg->rcv.proto_reserved1;
	send_sock=get_send_socket(&rb->dst.to, proto);
	if (send_sock==0) {
		LOG(L_ERR, "ERROR: init_rb: cannot fwd to af %d "
			"no socket\n", rb->dst.to.s.sa_family);
		ser_error=E_BAD_VIA;
		return 0;
	}
	rb->dst.send_sock=send_sock;
	
    return 1;
}



/* atomic "new_tran" construct; it returns:

	<0	on error

	+1	if a request did not match a transaction
		- it that was an ack, the calling function
		  shall forward statelessy
		- otherwise it means, a new transaction was
		  introduced and the calling function
		  shall reply/relay/whatever_appropriate

	0 on retransmission
*/
int t_newtran( struct sip_msg* p_msg )
{

	int ret, lret;
	struct cell *new_cell;
	struct sip_msg *shm_msg;

	ret=1;

	/* is T still up-to-date ? */
	DBG("DEBUG: t_addifnew: msg id=%d , global msg id=%d ,"
		" T on entrance=%p\n",p_msg->id,global_msg_id,T);

	if ( T && T!=T_UNDEFINED  ) {
		LOG(L_ERR, "ERROR: t_newtran: "
			"transaction already in process %p\n", T );
		return E_SCRIPT;
	}

	global_msg_id = p_msg->id;
	T = T_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, 0 )) {
		LOG(L_ERR, "ERROR: t_newtran: parse_headers failed\n");
		return E_BAD_REQ;
	}
	if ((p_msg->parsed_flag & HDR_EOH)!=HDR_EOH) {
			LOG(L_ERR, "ERROR: t_newtran: EoH not parsed\n");
			return E_OUT_OF_MEM;
	}
	/* t_lookup_requests attmpts 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 */ );
	/* on error, pass the error in the stack ... */
	if (lret==0) return E_BAD_TUPEL;
	/* transaction not found, it's a new request;
	   establish a new transaction (unless it is an ACK) */
	if (lret<0) {
		new_cell=0;
		if ( p_msg->REQ_METHOD!=METHOD_ACK ) {
			/* REVIEW */
			/* for ACK-dlw-wise matching, we want From-tags */
			if (p_msg->REQ_METHOD==METHOD_INVITE) {
				if (parse_from_header(p_msg)<0) {
					LOG(L_ERR, "ERROR: t_newtran: no valid From\n");
					return E_BAD_REQ;
				}
			}
			/* REVIEW */
			/* make sure uri will be parsed before cloning */
			if (parse_sip_msg_uri(p_msg)<0) {
				LOG(L_ERR, "ERROR: t_new_tran: uri invalid\n");
				return E_BAD_REQ;
			}
			
			/* add new transaction */
			new_cell = build_cell( p_msg ) ;
			if  ( !new_cell ){
				LOG(L_ERR, "ERROR: t_addifnew: out of mem:\n");
				ret = E_OUT_OF_MEM;
			} else {
				insert_into_hash_table_unsafe( new_cell );
				set_t(new_cell);
				INIT_REF_UNSAFE(T);
				/* init pointers to headers needed to construct local
				   requests such as CANCEL/ACK
				*/

				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;
				new_cell->is_invite=p_msg->REQ_METHOD==METHOD_INVITE;

			}

		}

		/* was it an e2e ACK ? if so, trigger a callback */
		if (lret==-2) {
				/* no callbacks? complete quickly */
				if (!callback_array[TMCB_E2EACK_IN]) {
					UNLOCK_HASH(p_msg->hash_index);
				} else {
					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)) {
						callback_event( TMCB_E2EACK_IN, t_ack, p_msg, 
							p_msg->REQ_METHOD );
					}
					UNREF(t_ack);
				}
		} else { /* not e2e ACK */
			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 (new_cell && p_msg->REQ_METHOD!=METHOD_ACK) {
				if (!init_rb( &T->uas.response, p_msg)) {
					LOG(L_ERR, "ERROR: t_newtran: unresolveable via1\n");
					put_on_wait( T );
					t_unref(p_msg);
					ret=E_BAD_VIA;
				}
			}
		}

		return ret;
	} 

	/* transaction found, it's a retransmission  or hbh ACK */
	if (p_msg->REQ_METHOD==METHOD_ACK) {
		t_release_transaction(T);
	} else {
		t_retransmit_reply(T);
	}
	/* things are done -- return from script */
	return 0;

}


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 (kr==0 
				||(p_msg->REQ_METHOD==METHOD_ACK && !(kr & REQ_RLSD))) {
			LOG(L_WARN, "WARNING: script writer didn't release transaction\n");
			t_release_transaction(T);
		}
	}
	UNREF( T );
	set_t(T_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){
	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;
}

int t_lookup_ident(struct cell ** trans, unsigned int hash_index, unsigned int label)
{
    struct cell* p_cell;

    if(hash_index >= TABLE_ENTRIES){
		LOG(L_ERR,"ERROR: t_lookup_ident: invalid hash_index=%u\n",hash_index);
		return -1;
    }

    LOCK_HASH(hash_index);

    /* all the transactions from the entry are compared */
    for ( p_cell = get_tm_table()->entrys[hash_index].first_cell;
	  p_cell; p_cell = p_cell->next_cell ) 
    {
		if(p_cell->label == label){
			REF_UNSAFE(p_cell);
    		UNLOCK_HASH(hash_index);
			set_t(p_cell);
			*trans=p_cell;
			DBG("DEBUG: t_lookup_ident: transaction found\n");
			return 1;
		}
    }
	
	UNLOCK_HASH(hash_index);
	set_t(0);
	*trans=p_cell;

	DBG("DEBUG: t_lookup_ident: transaction not found\n");
    
    return -1;
}

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;
    }
    
    return t->local;
}