modules/tm/tm.c
caf80ae6
 /*
  * $Id$
  *
  * TM module
  *
7dd0b342
  *
4c09747c
  * ***************************************************
  * * Jiri's Source Memorial                          *
  * *                                                 *
421acea1
  * * Welcome, pilgrim ! This is the greatest place   *
  * * where dramatic changes happend. There are not   *
  * * many places with a history like this, as there  *
  * * are not so many people like Jiri, one of the    *
  * * ser's fathers, who brought everywhere the wind  *
  * * of change, the flood of clean-up. We all felt   *
  * * his fatherly eye watching over us day and night.*
4c09747c
  * *                                                 *
  * * Please, preserve this codework heritage, as     *
  * * it's unlikly for fresh, juicy pices of code to  *
  * * arise to give him the again the chance to       *
  * * demonstrate his clean-up and improvement skills.*
  * *                                                 *
  * * Hereby, we solicit you to adopt this historical *
421acea1
  * * piece of code. For $100, your name will be      *
4c09747c
  * * be printed in this banner and we will use       *
  * * collected funds to create and display an ASCII  *
  * * statue of Jiri  .                               *
  * ***************************************************
  *
  *
7dd0b342
  * 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
caf80ae6
  */
d531a5d5
 /*
  * History:
  * --------
  *  2003-02-18  added t_forward_nonack_{udp, tcp}, t_relay_to_{udp,tcp},
  *               t_replicate_{udp, tcp} (andrei)
b3a91b6f
  *  2003-02-19  added t_rely_{udp, tcp} (andrei)
d505936f
  *  2003-03-06  voicemail changes accepted (jiri)
a045b453
  *  2003-03-10  module export interface updated to the new format (andrei)
0c8cd163
  *  2003-03-16  flags export parameter added (janakj)
8710b7ee
  *  2003-03-19  replaced all mallocs/frees w/ pkg_malloc/pkg_free (andrei)
acee2897
  *  2003-03-30  set_kr for requests only (jiri)
87405423
  *  2003-04-05  s/reply_route/failure_route, onreply_route introduced (jiri)
a7cad316
  *  2003-04-14  use protocol from uri (jiri)
d662d431
  *  2003-07-07  added t_relay_to_tls, t_replicate_tls, t_forward_nonack_tls
  *              added #ifdef USE_TCP, USE_TLS
  *              removed t_relay_{udp,tcp,tls} (andrei)
6be72156
  *  2003-09-26  added t_forward_nonack_uri() - same as t_forward_nonack() but
  *              takes no parameters -> forwards to uri (bogdan)
d531a5d5
  */
caf80ae6
 
7dd0b342
 
ff979952
 #include "defs.h"
 
 
caf80ae6
 #include <stdio.h>
 #include <string.h>
 #include <netdb.h>
 
 #include "../../sr_module.h"
 #include "../../dprint.h"
 #include "../../error.h"
 #include "../../ut.h"
 #include "../../script_cb.h"
 #include "../../fifo_server.h"
8710b7ee
 #include "../../mem/mem.h"
caf80ae6
 
 #include "sip_msg.h"
 #include "h_table.h"
 #include "t_funcs.h"
 #include "t_hooks.h"
 #include "tm_load.h"
 #include "ut.h"
 #include "t_reply.h"
 #include "uac.h"
c5867ab3
 #include "uac_fifo.h"
caf80ae6
 #include "t_fwd.h"
 #include "t_lookup.h"
c55b0dfd
 #include "t_stats.h"
c5867ab3
 #include "callid.h"
bc27f23b
 #include "t_cancel.h"
caf80ae6
 
2dcb8b67
 MODULE_VERSION
 
5c51440a
 /* fixup functions */
 static int fixup_t_send_reply(void** param, int param_no);
 static int fixup_str2int( void** param, int param_no);
 static int fixup_hostport2proxy(void** param, int param_no);
 static int fixup_str2regexp(void** param, int param_no);
 
 
 /* init functions */
 static int mod_init(void);
 static int child_init(int rank);
 
 
 /* exported functions */
caf80ae6
 inline static int w_t_check(struct sip_msg* msg, char* str, char* str2);
 inline static int w_t_reply(struct sip_msg* msg, char* str, char* str2);
 inline static int w_t_release(struct sip_msg* msg, char* str, char* str2);
5c51440a
 inline static int w_t_retransmit_reply(struct sip_msg* p_msg, char* foo,
 				char* bar );
caf80ae6
 inline static int w_t_newtran(struct sip_msg* p_msg, char* foo, char* bar );
 inline static int w_t_relay( struct sip_msg  *p_msg , char *_foo, char *_bar);
d531a5d5
 inline static int w_t_relay_to_udp( struct sip_msg  *p_msg , char *proxy, 
5c51440a
 				 char *);
d662d431
 #ifdef USE_TCP
d531a5d5
 inline static int w_t_relay_to_tcp( struct sip_msg  *p_msg , char *proxy,
5c51440a
 				char *);
d662d431
 #endif
 #ifdef USE_TLS
 inline static int w_t_relay_to_tls( struct sip_msg  *p_msg , char *proxy,
5c51440a
 				char *);
d662d431
 #endif
caf80ae6
 inline static int w_t_replicate( struct sip_msg  *p_msg , 
5c51440a
 				char *proxy, /* struct proxy_l *proxy expected */
 				char *_foo       /* nothing expected */ );
d531a5d5
 inline static int w_t_replicate_udp( struct sip_msg  *p_msg , 
5c51440a
 				char *proxy, /* struct proxy_l *proxy expected */
 				char *_foo       /* nothing expected */ );
d662d431
 #ifdef USE_TCP
d531a5d5
 inline static int w_t_replicate_tcp( struct sip_msg  *p_msg , 
5c51440a
 				char *proxy, /* struct proxy_l *proxy expected */
 				char *_foo       /* nothing expected */ );
d662d431
 #endif
 #ifdef USE_TLS
 inline static int w_t_replicate_tls( struct sip_msg  *p_msg , 
5c51440a
 				char *proxy, /* struct proxy_l *proxy expected */
 				char *_foo       /* nothing expected */ );
d662d431
 #endif
caf80ae6
 inline static int w_t_forward_nonack(struct sip_msg* msg, char* str, char* );
6be72156
 inline static int w_t_forward_nonack_uri(struct sip_msg* msg, char* str,char*);
d531a5d5
 inline static int w_t_forward_nonack_udp(struct sip_msg* msg, char* str,char*);
d662d431
 #ifdef USE_TCP
d531a5d5
 inline static int w_t_forward_nonack_tcp(struct sip_msg* msg, char* str,char*);
d662d431
 #endif
 #ifdef USE_TLS
 inline static int w_t_forward_nonack_tls(struct sip_msg* msg, char* str,char*);
 #endif
5c51440a
 inline static int w_t_on_negative(struct sip_msg* msg, char *go_to, char *foo);
 inline static int w_t_on_reply(struct sip_msg* msg, char *go_to, char *foo );
 inline static int t_check_status(struct sip_msg* msg, char *regexp, char *foo);
 inline static int t_flush_flags(struct sip_msg* msg, char *dir, char *foo);
caf80ae6
 
 
 
a045b453
 static cmd_export_t cmds[]={
5c51440a
 	{"t_newtran",          w_t_newtran,             0, 0,
 			REQUEST_ROUTE},
 	{"t_lookup_request",   w_t_check,               0, 0,
 			REQUEST_ROUTE},
 	{T_REPLY,              w_t_reply,               2, fixup_t_send_reply,
87405423
 			REQUEST_ROUTE | FAILURE_ROUTE },
5c51440a
 	{"t_retransmit_reply", w_t_retransmit_reply,    0, 0,
 			REQUEST_ROUTE},
 	{"t_release",          w_t_release,             0, 0,
 			REQUEST_ROUTE},
 	{T_RELAY_TO_UDP,       w_t_relay_to_udp,        2, fixup_hostport2proxy,
 			REQUEST_ROUTE|FAILURE_ROUTE},
d662d431
 #ifdef USE_TCP
5c51440a
 	{T_RELAY_TO_TCP,       w_t_relay_to_tcp,        2, fixup_hostport2proxy,
 			REQUEST_ROUTE|FAILURE_ROUTE},
d662d431
 #endif
 #ifdef USE_TLS
5c51440a
 	{T_RELAY_TO_TLS,       w_t_relay_to_tls,        2, fixup_hostport2proxy,
 			REQUEST_ROUTE|FAILURE_ROUTE},
d662d431
 #endif
5c51440a
 	{"t_replicate",        w_t_replicate,           2, fixup_hostport2proxy,
 			REQUEST_ROUTE},
 	{"t_replicate_udp",    w_t_replicate_udp,       2, fixup_hostport2proxy,
 			REQUEST_ROUTE},
d662d431
 #ifdef USE_TCP
5c51440a
 	{"t_replicate_tcp",    w_t_replicate_tcp,       2, fixup_hostport2proxy,
 			REQUEST_ROUTE},
d662d431
 #endif
 #ifdef USE_TLS
5c51440a
 	{"t_replicate_tls",    w_t_replicate_tls,       2, fixup_hostport2proxy,
 			REQUEST_ROUTE},
d662d431
 #endif
5c51440a
 	{T_RELAY,              w_t_relay,               0, 0,
87405423
 			REQUEST_ROUTE | FAILURE_ROUTE },
5c51440a
 	{T_FORWARD_NONACK,     w_t_forward_nonack,      2, fixup_hostport2proxy,
 			REQUEST_ROUTE},
 	{T_FORWARD_NONACK_URI, w_t_forward_nonack_uri,  0, 0,
 			REQUEST_ROUTE},
 	{T_FORWARD_NONACK_UDP, w_t_forward_nonack_udp,  2, fixup_hostport2proxy,
 			REQUEST_ROUTE},
d662d431
 #ifdef USE_TCP
5c51440a
 	{T_FORWARD_NONACK_TCP, w_t_forward_nonack_tcp,  2, fixup_hostport2proxy,
 			REQUEST_ROUTE},
d662d431
 #endif
 #ifdef USE_TLS
5c51440a
 	{T_FORWARD_NONACK_TLS, w_t_forward_nonack_tls,  2, fixup_hostport2proxy,
 			REQUEST_ROUTE},
d662d431
 #endif
87405423
 	{"t_on_failure",       w_t_on_negative,         1, fixup_str2int,
 			REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
 	{"t_on_reply",         w_t_on_reply,            1, fixup_str2int,
 			REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
5c51440a
 	{"t_check_status",     t_check_status,          1, fixup_str2regexp,
 			REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
 	{"t_flush_flags",     t_flush_flags,            1, fixup_str2int,
 			REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
 
87405423
 	/* not applicable from the script */
5c51440a
 	{"register_tmcb",      (cmd_function)register_tmcb,     NO_SCRIPT,   0, 0},
 	{"load_tm",            (cmd_function)load_tm,           NO_SCRIPT,   0, 0},
 	{T_REPLY_WB,           (cmd_function)t_reply_with_body, NO_SCRIPT,   0, 0},
 	{T_IS_LOCAL,           (cmd_function)t_is_local,        NO_SCRIPT,   0, 0},
 	{T_GET_TI,             (cmd_function)t_get_trans_ident, NO_SCRIPT,   0, 0},
 	{T_LOOKUP_IDENT,       (cmd_function)t_lookup_ident,    NO_SCRIPT,   0, 0},
 	{T_ADDBLIND,           (cmd_function)add_blind_uac,     NO_SCRIPT,   0, 0},
 	{"t_request_within",   (cmd_function)req_within,        NO_SCRIPT,   0, 0},
 	{"t_request_outside",  (cmd_function)req_outside,       NO_SCRIPT,   0, 0},
 	{"t_request",          (cmd_function)request,           NO_SCRIPT,   0, 0},
 	{"new_dlg_uac",        (cmd_function)new_dlg_uac,       NO_SCRIPT,   0, 0},
 	{"dlg_response_uac",   (cmd_function)dlg_response_uac,  NO_SCRIPT,   0, 0},
 	{"new_dlg_uas",        (cmd_function)new_dlg_uas,       NO_SCRIPT,   0, 0},
 	{"dlg_request_uas",    (cmd_function)dlg_request_uas,   NO_SCRIPT,   0, 0},
 	{"free_dlg",           (cmd_function)free_dlg,          NO_SCRIPT,   0, 0},
 	{"print_dlg",          (cmd_function)print_dlg,         NO_SCRIPT,   0, 0},
0c8cd163
 	{0,0,0,0,0}
a045b453
 };
 
 static param_export_t params[]={
 	{"ruri_matching", INT_PARAM, &ruri_matching                         },
39ac030b
 	{"via1_matching", INT_PARAM, &via1_matching                         },
a045b453
 	{"fr_timer",      INT_PARAM, &(timer_id2timeout[FR_TIMER_LIST])     },
 	{"fr_inv_timer",  INT_PARAM, &(timer_id2timeout[FR_INV_TIMER_LIST]) },
 	{"wt_timer",      INT_PARAM, &(timer_id2timeout[WT_TIMER_LIST])     },
 	{"delete_timer",  INT_PARAM, &(timer_id2timeout[DELETE_LIST])       },
 	{"retr_timer1p1", INT_PARAM, &(timer_id2timeout[RT_T1_TO_1])        },
 	{"retr_timer1p2", INT_PARAM, &(timer_id2timeout[RT_T1_TO_2])        },
 	{"retr_timer1p3", INT_PARAM, &(timer_id2timeout[RT_T1_TO_3])        },
 	{"retr_timer2",   INT_PARAM, &(timer_id2timeout[RT_T2])             },
 	{"noisy_ctimer",  INT_PARAM, &noisy_ctimer                          },
c5867ab3
 	{"uac_from",      STR_PARAM, &uac_from                              },
a045b453
 	{0,0,0}
 };
 
 
caf80ae6
 #ifdef STATIC_TM
 struct module_exports tm_exports = {
 #else
 struct module_exports exports= {
 #endif
 	"tm",
 	/* -------- exported functions ----------- */
a045b453
 	cmds,
caf80ae6
 	/* ------------ exported variables ---------- */
a045b453
 	params,
 	
caf80ae6
 	mod_init, /* module initialization function */
87405423
 	(response_function) reply_received,
caf80ae6
 	(destroy_function) tm_shutdown,
 	0, /* w_onbreak, */
 	child_init /* per-child init function */
 };
 
5c51440a
 
 
 /**************************** fixup functions ******************************/
 static int fixup_str2int( void** param, int param_no)
caf80ae6
 {
b988daef
 	unsigned long go_to;
caf80ae6
 	int err;
 
 	if (param_no==1) {
 		go_to=str2s(*param, strlen(*param), &err );
 		if (err==0) {
8710b7ee
 			pkg_free(*param);
caf80ae6
 			*param=(void *)go_to;
 			return 0;
 		} else {
 			LOG(L_ERR, "ERROR: fixup_str2int: bad number <%s>\n",
 				(char *)(*param));
 			return E_CFG;
 		}
 	}
 	return 0;
 }
 
5c51440a
 
 /* (char *hostname, char *port_nr) ==> (struct proxy_l *, -)  */
 static int fixup_hostport2proxy(void** param, int param_no)
 {
 	unsigned int port;
 	char *host;
 	int err;
 	struct proxy_l *proxy;
 	str s;
 	
 	DBG("TM module: fixup_t_forward(%s, %d)\n", (char*)*param, param_no);
 	if (param_no==1){
 		DBG("TM module: fixup_t_forward: param 1.. do nothing, wait for #2\n");
 		return 0;
 	} else if (param_no==2) {
 
 		host=(char *) (*(param-1)); 
 		port=str2s(*param, strlen(*param), &err);
 		if (err!=0) {
 			LOG(L_ERR, "TM module:fixup_t_forward: bad port number <%s>\n",
 				(char*)(*param));
 			 return E_UNSPEC;
 		}
 		s.s = host;
 		s.len = strlen(host);
 		proxy=mk_proxy(&s, port, 0); /* FIXME: udp or tcp? */
 		if (proxy==0) {
 			LOG(L_ERR, "ERROR: fixup_t_forwardv6: bad host name in URI <%s>\n",
 				host );
 			return E_BAD_ADDRESS;
 		}
 		/* success -- fix the first parameter to proxy now ! */
 
 		/* FIXME: janakj, mk_proxy doesn't make copy of host !! */
 		/*pkg_free( *(param-1)); you're right --andrei*/
 		*(param-1)=proxy;
 		return 0;
 	} else {
 		LOG(L_ERR,"ERROR: fixup_t_forwardv6 called with parameter #<>{1,2}\n");
 		return E_BUG;
 	}
 }
 
 
 /* (char *code, char *reason_phrase)==>(int code, r_p as is) */
 static int fixup_t_send_reply(void** param, int param_no)
 {
 	unsigned long code;
 	int err;
 
 	if (param_no==1){
 		code=str2s(*param, strlen(*param), &err);
 		if (err==0){
 			pkg_free(*param);
 			*param=(void*)code;
 			return 0;
 		}else{
 			LOG(L_ERR, "TM module:fixup_t_send_reply: bad  number <%s>\n",
 					(char*)(*param));
 			return E_UNSPEC;
 		}
 	}
 	/* second param => no conversion*/
 	return 0;
 }
 
 
 static int fixup_str2regexp(void** param, int param_no)
 {
 	regex_t* re;
 
 	if (param_no==1) {
 		if ((re=pkg_malloc(sizeof(regex_t)))==0)
 			return E_OUT_OF_MEM;
 		if (regcomp(re, *param, REG_EXTENDED|REG_ICASE|REG_NEWLINE) ) {
 			pkg_free(re);
 			LOG(L_ERR,"ERROR: %s : bad re %s\n", exports.name, (char*)*param);
 			return E_BAD_RE;
 		}
 		/* free string */
 		pkg_free(*param);
 		/* replace it with the compiled re */
 		*param=re;
 	} else {
 		LOG(L_ERR,"ERROR: fixup_str2regexp called with parameter != 1\n");
 		return E_BUG;
 	}
 	return 0;
 }
 
 
 
 
 /***************************** init functions *****************************/
caf80ae6
 static int w_t_unref( struct sip_msg *foo, void *bar)
 {
 	return t_unref(foo);
 }
 
5c51440a
 
caf80ae6
 static int script_init( struct sip_msg *foo, void *bar)
 {   
 	/* we primarily reset all private memory here to make sure
5c51440a
 	 * private values left over from previous message will
 	 * not be used again */
caf80ae6
 
acee2897
 	if (foo->first_line.type==SIP_REQUEST){
 		/* make sure the new message will not inherit previous
5c51440a
 			message's t_on_negative value
acee2897
 		*/
 		t_on_negative( 0 );
87405423
 		t_on_reply(0);
acee2897
 		/* reset the kr status */
 		set_kr(0);
87405423
 		/* set request mode so that multiple-mode actions know
 		 * how to behave */
 		rmode=MODE_REQUEST;
acee2897
 	}
caf80ae6
 	return 1;
 }
 
5c51440a
 
caf80ae6
 static int mod_init(void)
 {
 	DBG( "TM - initializing...\n");
 	/* checking if we have sufficient bitmap capacity for given
 	   maximum number of  branches */
ba506d03
 	if (MAX_BRANCHES+1>31) {
caf80ae6
 		LOG(L_CRIT, "Too many max UACs for UAC branch_bm_t bitmap: %d\n",
 			MAX_BRANCHES );
 		return -1;
 	}
82802743
 
c5867ab3
 	if (init_callid() < 0) {
 		LOG(L_CRIT, "Error while initializin Call-ID generator\n");
 		return -1;
 	}
82802743
 
c5867ab3
 	if (register_fifo_cmd(fifo_uac, "t_uac_dlg", 0) < 0) {
 		LOG(L_CRIT, "cannot register fifo t_uac\n");
ff979952
 		return -1;
 	}
c5867ab3
 
bc27f23b
 	if (register_fifo_cmd(fifo_uac_cancel, "t_uac_cancel", 0) < 0) {
 		LOG(L_CRIT, "cannot register fifo t_uac_cancel\n");
 		return -1;
 	}
 
e7d79f5d
 	if (register_fifo_cmd(fifo_hash, "t_hash", 0)<0) {
 		LOG(L_CRIT, "cannot register hash\n");
 		return -1;
 	}
caf80ae6
 
b1f1656e
 	if (!init_hash_table()) {
 		LOG(L_ERR, "ERROR: mod_init: initializing hash_table failed\n");
 		return -1;
 	}
 
82802743
 
 	/* init static hidden values */
 	init_t();
 
b1f1656e
 	if (!tm_init_timers()) {
 		LOG(L_ERR, "ERROR: mod_init: timer init failed\n");
 		return -1;
 	}
82802743
 	/* register the timer function */
 	register_timer( timer_routine , 0 /* empty attr */, 1 );
 
 	/* init_tm_stats calls process_count, which should
 	 * NOT be called from mod_init, because one does not
 	 * now, if a timer is used and thus how many processes
 	 * will be started; however we started already our
 	 * timers, so we know and process_count should not
 	 * change any more
 	 */	
 	if (init_tm_stats()<0) {
 		LOG(L_CRIT, "ERROR: mod_init: failed to init stats\n");
 		return -1;
 	}
b1f1656e
 
82802743
 	/* building the hash table*/
b1f1656e
 
82802743
 	if (uac_init()==-1) {
 		LOG(L_ERR, "ERROR: mod_init: uac_init failed\n");
 		return -1;
 	}
 	/* register post-script clean-up function */
 	register_script_cb( w_t_unref, POST_SCRIPT_CB, 
 			0 /* empty param */ );
 	register_script_cb( script_init, PRE_SCRIPT_CB , 
 			0 /* empty param */ );
b1f1656e
 
17045ca6
 	tm_init_tags();
 
caf80ae6
 	return 0;
 }
 
 static int child_init(int rank) {
c5867ab3
 	if (child_init_callid(rank) < 0) {
 		LOG(L_ERR, "ERROR: child_init: Error while initializing Call-ID generator\n");
 		return -2;
82802743
 	}
c5867ab3
 
 	return 0;
caf80ae6
 }
 
 
 
 
dc85e6e9
 
5c51440a
 /**************************** wrapper functions ***************************/
 static int t_check_status(struct sip_msg* msg, char *regexp, char *foo)
 {
 	regmatch_t pmatch;
 	struct cell *t;
 	char *status;
 	char backup;
 	int lowest_status;
 	int n;
 
 	/* first get the transaction */
 	if (t_check( msg , 0 )==-1) return -1;
 	if ( (t=get_t())==0) {
 		LOG(L_ERR, "ERROR: t_check_status: cannot check status for a reply "
 			"which has no T-state established\n");
 		return -1;
caf80ae6
 	}
5c51440a
 	backup = 0;
 
 	switch (rmode) {
 		case MODE_REQUEST:
 			/* use the status of the last sent reply */
 			status = int2str( t->uas.status, 0);
 			break;
 		case MODE_ONREPLY:
 			/* use the status of the current reply */
 			status = msg->first_line.u.reply.status.s;
 			backup = status[msg->first_line.u.reply.status.len];
 			status[msg->first_line.u.reply.status.len] = 0;
 			break;
 		case MODE_ONFAILURE:
 			/* use the status of the winning reply */
8825be63
 			if (t_pick_branch( -1, 0, t, &lowest_status)<0 ) {
 				LOG(L_CRIT,"BUG:t_check_status: t_pick_branch failed to get "
 					" a final response in MODE_ONFAILURE\n");
 				return -1;
5c51440a
 			}
 			status = int2str( lowest_status , 0);
 			break;
 		default:
 			LOG(L_ERR,"ERROR:t_check_status: unsupported mode %d\n",rmode);
 			return -1;
 	}
 
 	DBG("DEBUG:t_check_status: checked status is <%s>\n",status);
 	/* do the checking */
 	n = regexec((regex_t*)regexp, status, 1, &pmatch, 0);
 
 	if (backup) status[msg->first_line.u.reply.status.len] = backup;
 	if (n!=0) return -1;
 	return 1;
caf80ae6
 }
 
 
5c51440a
 static int t_flush_flags(struct sip_msg* msg, char *dir, char *foo)
caf80ae6
 {
5c51440a
 	struct cell *t;
caf80ae6
 
5c51440a
 	/* first get the transaction */
 	if (t_check( msg , 0 )==-1) return -1;
 	if ( (t=get_t())==0) {
 		LOG(L_ERR, "ERROR: t_flush_flags: cannot flush flags for a message "
 			"which has no T-state established\n");
 		return -1;
caf80ae6
 	}
 
5c51440a
 	/* do the flush */
b6961680
 	switch ((long)dir) {
5c51440a
 		case  1:
 			t->uas.request->flags = msg->flags;
 			break;
 		case  2:
 			msg->flags = t->uas.request->flags;
 			break;
 		default:
b6961680
 			LOG(L_ERR,"ERROR:t_flush_flags: unknown direction %ld\n",
 					(long)dir);
5c51440a
 			return -1;
 	}
 	return 1;
 }
caf80ae6
 
 
 inline static int w_t_check(struct sip_msg* msg, char* str, char* str2)
 {
 	return t_check( msg , 0  ) ? 1 : -1;
 }
 
 
d531a5d5
 inline static int _w_t_forward_nonack(struct sip_msg* msg, char* proxy,
6be72156
 																	int proto)
caf80ae6
 {
 	struct cell *t;
fde02f64
 	if (t_check( msg , 0 )==-1) {
 		LOG(L_ERR, "ERROR: forward_nonack: "
 				"can't forward when no transaction was set up\n");
 		return -1;
 	}
caf80ae6
 	t=get_t();
 	if ( t && t!=T_UNDEFINED ) {
 		if (msg->REQ_METHOD==METHOD_ACK) {
 			LOG(L_WARN,"WARNING: you don't really want to fwd hbh ACK\n");
 			return -1;
 		}
d531a5d5
 		return t_forward_nonack(t, msg, ( struct proxy_l *) proxy, proto );
caf80ae6
 	} else {
 		DBG("DEBUG: t_forward_nonack: no transaction found\n");
 		return -1;
 	}
 }
 
 
d531a5d5
 inline static int w_t_forward_nonack( struct sip_msg* msg, char* proxy,
 										char* foo)
 {
6be72156
 	return _w_t_forward_nonack(msg, proxy, PROTO_NONE);
 }
 
5c51440a
 
6be72156
 inline static int w_t_forward_nonack_uri(struct sip_msg* msg, char *foo,
 																	char *bar)
 {
 	return _w_t_forward_nonack(msg, 0, PROTO_NONE);
a045b453
 }
d531a5d5
 
5c51440a
 
d531a5d5
 inline static int w_t_forward_nonack_udp( struct sip_msg* msg, char* proxy,
 										char* foo)
 {
6be72156
 	return _w_t_forward_nonack(msg, proxy, PROTO_UDP);
a045b453
 }
d531a5d5
 
5c51440a
 
d662d431
 #ifdef USE_TCP
d531a5d5
 inline static int w_t_forward_nonack_tcp( struct sip_msg* msg, char* proxy,
 										char* foo)
 {
6be72156
 	return _w_t_forward_nonack(msg, proxy, PROTO_TCP);
a045b453
 }
d662d431
 #endif
 
5c51440a
 
d662d431
 #ifdef USE_TLS
 inline static int w_t_forward_nonack_tls( struct sip_msg* msg, char* proxy,
 										char* foo)
 {
6be72156
 	return _w_t_forward_nonack(msg, proxy, PROTO_TLS);
d662d431
 }
 #endif
d531a5d5
 
 
caf80ae6
 inline static int w_t_reply(struct sip_msg* msg, char* str, char* str2)
 {
 	struct cell *t;
 
 	if (msg->REQ_METHOD==METHOD_ACK) {
 		LOG(L_WARN, "WARNING: t_reply: ACKs are not replied\n");
 		return -1;
 	}
 	if (t_check( msg , 0 )==-1) return -1;
 	t=get_t();
 	if (!t) {
 		LOG(L_ERR, "ERROR: t_reply: cannot send a t_reply to a message "
 			"for which no T-state has been established\n");
 		return -1;
 	}
eaf10d36
 	/* if called from reply_route, make sure that unsafe version
 	 * is called; we are already in a mutex and another mutex in
 	 * the safe version would lead to a deadlock
 	 */
87405423
 	if (rmode==MODE_ONFAILURE) { 
eaf10d36
 		DBG("DEBUG: t_reply_unsafe called from w_t_reply\n");
b988daef
 		return t_reply_unsafe(t, msg, (unsigned int)(long) str, str2);
87405423
 	} else if (rmode==MODE_REQUEST) {
b988daef
 		return t_reply( t, msg, (unsigned int)(long) str, str2);
87405423
 	} else {
 		LOG(L_CRIT, "BUG: w_t_reply entered in unsupported mode\n");
 		return -1;
eaf10d36
 	}
caf80ae6
 }
 
 
 inline static int w_t_release(struct sip_msg* msg, char* str, char* str2)
 {
 	struct cell *t;
 	if (t_check( msg  , 0  )==-1) return -1;
 	t=get_t();
 	if ( t && t!=T_UNDEFINED ) 
 		return t_release_transaction( t );
 	return 1;
 }
 
 
 inline static int w_t_retransmit_reply( struct sip_msg* p_msg, char* foo, char* bar)
 {
 	struct cell *t;
 
 
 	if (t_check( p_msg  , 0 )==-1) 
 		return 1;
 	t=get_t();
 	if (t) {
 		if (p_msg->REQ_METHOD==METHOD_ACK) {
 			LOG(L_WARN, "WARNING: : ACKs ansmit_replies not replied\n");
 			return -1;
 		}
 		return t_retransmit_reply( t );
 	} else 
 		return -1;
 }
 
 
 inline static int w_t_newtran( struct sip_msg* p_msg, char* foo, char* bar ) 
 {
 	/* t_newtran returns 0 on error (negative value means
 	   'transaction exists'
 	*/
 	return t_newtran( p_msg );
 }
 
 
 inline static int w_t_on_negative( struct sip_msg* msg, char *go_to, char *foo )
 {
87405423
 	struct cell *t;
 
 	if (rmode==MODE_REQUEST || rmode==MODE_ONFAILURE) {
 		t_on_negative( (unsigned int )(long) go_to );
 		return 1;
 	}
 	if (rmode==MODE_ONREPLY ) {
 		/* transaction state is established */
 		t=get_t();
 		if (!t || t==T_UNDEFINED) {
 			LOG(L_CRIT, "BUG: w_t_on_negative entered without t\n");
 			return -1;
 		}
 		t->on_negative=(unsigned int)(long)go_to;
 		return 1;
 	}
 	LOG(L_CRIT, "BUG: w_t_on_negative entered in unsupported mode\n");
 	return -1;
 }
5c51440a
 
 
87405423
 inline static int w_t_on_reply( struct sip_msg* msg, char *go_to, char *foo )
 {
 	struct cell *t;
 
 	if (rmode==MODE_REQUEST) {
 		/* it's still in initial request processing stage, transaction
 		 * state is not estabslihed yet, store it in private memory ...
 		 * it will be copied to transaction state when it is set up */
 		t_on_reply( (unsigned int )(long) go_to );
 		return 1;
 	}
 	if (rmode==MODE_ONREPLY || rmode==MODE_ONFAILURE) {
 		/* transaction state is established */
 		t=get_t();
 		if (!t || t==T_UNDEFINED) {
 			LOG(L_CRIT, "BUG: w_t_on_reply entered without t\n");
 			return -1;
 		}
 		t->on_reply=(unsigned int) (long)go_to;
 		return 1;
 	}
 	LOG(L_CRIT, "BUG: w_t_on_reply entered in unsupported mode\n");
 	return -1;
caf80ae6
 }
 
5c51440a
 
a7cad316
 inline static int _w_t_relay_to( struct sip_msg  *p_msg , 
 	struct proxy_l *proxy )
caf80ae6
 {
87405423
 	struct cell *t;
 
 	if (rmode==MODE_ONFAILURE) { 
 		t=get_t();
 		if (!t || t==T_UNDEFINED) {
 			LOG(L_CRIT, "BUG: w_t_relay_to: undefined T\n");
 			return -1;
 		}
a7cad316
 		if (t_forward_nonack(t, p_msg, proxy, PROTO_NONE)<=0 ) {
87405423
 			LOG(L_ERR, "ERROR: failure_route: t_relay_to failed\n");
 			return -1;
 		}
 		return 1;
 	}
 	if (rmode==MODE_REQUEST) 
a7cad316
 		return t_relay_to( p_msg, proxy, PROTO_NONE,
87405423
 			0 /* no replication */ );
 	LOG(L_CRIT, "ERROR: w_t_relay_to: unsupported mode: %d\n", rmode);
 	return 0;
d531a5d5
 }
 
5c51440a
 
d531a5d5
 inline static int w_t_relay_to_udp( struct sip_msg  *p_msg , 
 	char *proxy, /* struct proxy_l *proxy expected */
 	char *_foo       /* nothing expected */ )
 {
a7cad316
 	((struct proxy_l *)proxy)->proto=PROTO_UDP;
 	return _w_t_relay_to( p_msg, ( struct proxy_l *) proxy);
caf80ae6
 }
 
5c51440a
 
d662d431
 #ifdef USE_TCP
d531a5d5
 inline static int w_t_relay_to_tcp( struct sip_msg  *p_msg , 
 	char *proxy, /* struct proxy_l *proxy expected */
 	char *_foo       /* nothing expected */ )
 {
a7cad316
 	((struct proxy_l *)proxy)->proto=PROTO_TCP;
 	return _w_t_relay_to( p_msg, ( struct proxy_l *) proxy);
d531a5d5
 }
d662d431
 #endif
 
5c51440a
 
d662d431
 #ifdef USE_TLS
 inline static int w_t_relay_to_tls( struct sip_msg  *p_msg , 
 	char *proxy, /* struct proxy_l *proxy expected */
 	char *_foo       /* nothing expected */ )
 {
 	((struct proxy_l *)proxy)->proto=PROTO_TLS;
 	return _w_t_relay_to( p_msg, ( struct proxy_l *) proxy);
 }
 #endif
d531a5d5
 
 
caf80ae6
 inline static int w_t_replicate( struct sip_msg  *p_msg , 
 	char *proxy, /* struct proxy_l *proxy expected */
 	char *_foo       /* nothing expected */ )
 {
d531a5d5
 	return t_replicate(p_msg, ( struct proxy_l *) proxy, p_msg->rcv.proto );
caf80ae6
 }
 
5c51440a
 
d531a5d5
 inline static int w_t_replicate_udp( struct sip_msg  *p_msg , 
 	char *proxy, /* struct proxy_l *proxy expected */
 	char *_foo       /* nothing expected */ )
 {
 	return t_replicate(p_msg, ( struct proxy_l *) proxy, PROTO_UDP );
 }
 
5c51440a
 
d662d431
 #ifdef USE_TCP
d531a5d5
 inline static int w_t_replicate_tcp( struct sip_msg  *p_msg , 
 	char *proxy, /* struct proxy_l *proxy expected */
 	char *_foo       /* nothing expected */ )
 {
 	return t_replicate(p_msg, ( struct proxy_l *) proxy, PROTO_TCP );
 }
d662d431
 #endif
 
5c51440a
 
d662d431
 #ifdef USE_TLS
 inline static int w_t_replicate_tls( struct sip_msg  *p_msg , 
 	char *proxy, /* struct proxy_l *proxy expected */
 	char *_foo       /* nothing expected */ )
 {
 	return t_replicate(p_msg, ( struct proxy_l *) proxy, PROTO_TLS );
 }
 #endif
d531a5d5
 
 
caf80ae6
 inline static int w_t_relay( struct sip_msg  *p_msg , 
 						char *_foo, char *_bar)
 {
87405423
 	struct cell *t;
 
 	if (rmode==MODE_ONFAILURE) { 
 		t=get_t();
 		if (!t || t==T_UNDEFINED) {
 			LOG(L_CRIT, "BUG: w_t_relay: undefined T\n");
 			return -1;
 		} 
a7cad316
 		if (t_forward_nonack(t, p_msg, ( struct proxy_l *) 0, PROTO_NONE)<=0) {
87405423
 			LOG(L_ERR, "ERROR: w_t_relay (failure mode): forwarding failed\n");
 			return -1;
 		}
 		return 1;
 	}
 	if (rmode==MODE_REQUEST) 
 		return t_relay_to( p_msg, 
a7cad316
 		(struct proxy_l *) 0 /* no proxy */, PROTO_NONE,
caf80ae6
 		0 /* no replication */ );
87405423
 	LOG(L_CRIT, "ERROR: w_t_relay_to: unsupported mode: %d\n", rmode);
 	return 0;
caf80ae6
 }