Parcourir la source

ser_error processing, ipv6-ization of TM, new TM callbacks;
not stable yet (serial forking is screwed up)

Jiri Kuthan il y a 23 ans
Parent
commit
1400b77288

+ 11 - 3
action.c

@@ -16,6 +16,7 @@
 #include "ut.h"
 #include "ut.h"
 #include "sr_module.h"
 #include "sr_module.h"
 #include "mem/mem.h"
 #include "mem/mem.h"
+#include "globals.h"
 
 
 #include <sys/types.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/socket.h>
@@ -48,6 +49,13 @@ int do_action(struct action* a, struct sip_msg* msg)
 	struct sip_uri uri;
 	struct sip_uri uri;
 	unsigned short port;
 	unsigned short port;
 
 
+	/* reset the value of error to E_UNSPEC so avoid unknowledgable
+	   functions to return with errror (status<0) and not setting it
+	   leaving there previous error; cache the previous value though
+	   for functions which want to process it */
+	prev_ser_error=ser_error;
+	ser_error=E_UNSPEC;
+
 	ret=E_BUG;
 	ret=E_BUG;
 	switch (a->type){
 	switch (a->type){
 		case DROP_T:
 		case DROP_T:
@@ -63,10 +71,10 @@ int do_action(struct action* a, struct sip_msg* msg)
 						tmp=msg->first_line.u.request.uri.s;
 						tmp=msg->first_line.u.request.uri.s;
 						len=msg->first_line.u.request.uri.len;
 						len=msg->first_line.u.request.uri.len;
 				}
 				}
-				if (parse_uri(tmp, len, &uri)<0){
+				ret=parse_uri(tmp, len, &uri );
+				if (ret<0) {
 					LOG(L_ERR, "ERROR: do_action: forward: bad_uri <%s>,"
 					LOG(L_ERR, "ERROR: do_action: forward: bad_uri <%s>,"
 								" dropping packet\n",tmp);
 								" dropping packet\n",tmp);
-					ret=E_UNSPEC;
 					break;
 					break;
 				}
 				}
 				switch (a->p2_type){
 				switch (a->p2_type){
@@ -80,7 +88,7 @@ int do_action(struct action* a, struct sip_msg* msg)
 											LOG(L_ERR, "ERROR: do_action: "
 											LOG(L_ERR, "ERROR: do_action: "
 												"forward: bad port in "
 												"forward: bad port in "
 												"uri: <%s>\n", uri.port.s);
 												"uri: <%s>\n", uri.port.s);
-											ret=E_UNSPEC;
+											ret=E_BAD_URI;
 											goto error_fwd_uri;
 											goto error_fwd_uri;
 										}
 										}
 									}else port=SIP_PORT;
 									}else port=SIP_PORT;

+ 5 - 1
data_lump.c

@@ -5,6 +5,8 @@
 #include "data_lump.h"
 #include "data_lump.h"
 #include "dprint.h"
 #include "dprint.h"
 #include "mem/mem.h"
 #include "mem/mem.h"
+#include "globals.h"
+#include "error.h"
 
 
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
@@ -14,7 +16,6 @@
 #endif
 #endif
 
 
 
 
-
 /* adds a header to the end
 /* adds a header to the end
  * returns  pointer on success, 0 on error */
  * returns  pointer on success, 0 on error */
 struct lump* append_new_lump(struct lump** list, char* new_hdr,
 struct lump* append_new_lump(struct lump** list, char* new_hdr,
@@ -75,6 +76,7 @@ struct lump* insert_new_lump_after( struct lump* after, char* new_hdr,
 
 
 	tmp=pkg_malloc(sizeof(struct lump));
 	tmp=pkg_malloc(sizeof(struct lump));
 	if (tmp==0){
 	if (tmp==0){
+		ser_error=E_OUT_OF_MEM;
 		LOG(L_ERR, "ERROR: insert_new_lump_after: out of memory\n");
 		LOG(L_ERR, "ERROR: insert_new_lump_after: out of memory\n");
 		return 0;
 		return 0;
 	}
 	}
@@ -99,6 +101,7 @@ struct lump* insert_new_lump_before( struct lump* before, char* new_hdr,
 
 
 	tmp=pkg_malloc(sizeof(struct lump));
 	tmp=pkg_malloc(sizeof(struct lump));
 	if (tmp==0){
 	if (tmp==0){
+		ser_error=E_OUT_OF_MEM;
 		LOG(L_ERR,"ERROR: insert_new_lump_before: out of memory\n");
 		LOG(L_ERR,"ERROR: insert_new_lump_before: out of memory\n");
 		return 0;
 		return 0;
 	}
 	}
@@ -152,6 +155,7 @@ struct lump* anchor_lump(struct lump** list, int offset, int len, int type)
 
 
 	tmp=pkg_malloc(sizeof(struct lump));
 	tmp=pkg_malloc(sizeof(struct lump));
 	if (tmp==0){
 	if (tmp==0){
+		ser_error=E_OUT_OF_MEM;
 		LOG(L_ERR, "ERROR: insert_new_lump_before: out of memory\n");
 		LOG(L_ERR, "ERROR: insert_new_lump_before: out of memory\n");
 		return 0;
 		return 0;
 	}
 	}

+ 52 - 0
error.c

@@ -0,0 +1,52 @@
+/*
+ * $Id$
+ *
+ */
+
+#include "error.h"
+
+/* current function's error; */
+int ser_error=-1;
+/* previous error */
+int prev_ser_error=-1;
+
+int err2reason_phrase( 
+	int ser_error,  /* current itnernal ser error */
+	int *sip_error,  /* the sip error code to which ser 	
+					    ser error will be turned */
+	char *phrase,    /* resulting error text */
+	int etl, 		/* error text buffer length */
+	char *signature ) /* extra text to be appended */
+{
+
+	char *error_txt;
+
+	switch( ser_error ) {
+		case E_OUT_OF_MEM:
+			error_txt="Excuse me I ran out of memory";
+			*sip_error=500;
+			break;
+		case E_SEND:
+			error_txt="Unfortunately error on sending to next hop occured";
+			*sip_error=-ser_error;
+			break;
+		case E_BAD_ADDRESS:
+			error_txt="Unresolveable destination";
+			*sip_error=-ser_error;
+			break;
+		case E_BAD_REQ:
+			error_txt="Bad Request";
+			*sip_error=-ser_error;
+			break;
+		case E_BAD_URI:
+			error_txt="Regretfuly, we were not able to process the URI";
+			*sip_error=-ser_error;
+			break;
+		default:
+			error_txt="I'm terribly sorry, server error occured";
+			*sip_error=500;
+			break;
+	}
+	return snprintf( phrase, etl, "%s (%d/%s)", error_txt, 
+		-ser_error, signature );
+}

+ 19 - 1
error.h

@@ -8,9 +8,27 @@
 #define E_UNSPEC      -1
 #define E_UNSPEC      -1
 #define E_OUT_OF_MEM  -2
 #define E_OUT_OF_MEM  -2
 #define E_BAD_RE      -3
 #define E_BAD_RE      -3
-#define E_BAD_ADDRESS -4
+/* #define E_BAD_ADDRESS -4 */
 #define E_BUG         -5
 #define E_BUG         -5
 #define E_CFG         -6
 #define E_CFG         -6
+#define E_NO_SOCKET		-7
+
+#define E_SEND		  -477
+/* unresolveable next-hop address */
+#define E_BAD_ADDRESS -478
+/* unparseable URI */
+#define E_BAD_URI 	  -479
+/* misformated request */
+#define E_BAD_REQ	  -400
+
+#define MAX_REASON_LEN	128
+
+/* processing status of the last command */
+extern int ser_error;
+extern int prev_ser_error;
+
+int err2reason_phrase( int ser_error, int *sip_error, 
+                char *phrase, int etl, char *signature );
 
 
 
 
 #endif
 #endif

+ 3 - 0
forward.c

@@ -73,6 +73,7 @@ int forward_request( struct sip_msg* msg, struct proxy_l * p)
 	
 	
 	to=(union sockaddr_union*)malloc(sizeof(union sockaddr_union));
 	to=(union sockaddr_union*)malloc(sizeof(union sockaddr_union));
 	if (to==0){
 	if (to==0){
+		ser_error=E_OUT_OF_MEM;
 		LOG(L_ERR, "ERROR: forward_request: out of memory\n");
 		LOG(L_ERR, "ERROR: forward_request: out of memory\n");
 		goto error;
 		goto error;
 	}
 	}
@@ -96,6 +97,7 @@ int forward_request( struct sip_msg* msg, struct proxy_l * p)
 	if (send_sock==0){
 	if (send_sock==0){
 		LOG(L_ERR, "forward_req: ERROR: cannot forward to af %d "
 		LOG(L_ERR, "forward_req: ERROR: cannot forward to af %d "
 				"no coresponding listening socket\n", to->s.sa_family);
 				"no coresponding listening socket\n", to->s.sa_family);
+		ser_error=E_NO_SOCKET;
 		goto error;
 		goto error;
 	}
 	}
 	
 	
@@ -110,6 +112,7 @@ int forward_request( struct sip_msg* msg, struct proxy_l * p)
 	
 	
 	if (udp_send( send_sock, buf, len,  to, 
 	if (udp_send( send_sock, buf, len,  to, 
 							sizeof(union sockaddr_union))==-1){
 							sizeof(union sockaddr_union))==-1){
+			ser_error=E_SEND;
 			p->errors++;
 			p->errors++;
 			p->ok=0;
 			p->ok=0;
 			STATS_TX_DROPS;
 			STATS_TX_DROPS;

+ 5 - 1
modules/tm/h_table.c

@@ -9,6 +9,8 @@
 #include "../../md5utils.h"
 #include "../../md5utils.h"
 /* bogdan test */
 /* bogdan test */
 #include "../../ut.h"
 #include "../../ut.h"
+#include "../../globals.h"
+#include "../../error.h"
 
 
 
 
 
 
@@ -75,8 +77,10 @@ struct cell*  build_cell( struct sip_msg* p_msg )
 
 
 	/* allocs a new cell */
 	/* allocs a new cell */
 	new_cell = (struct cell*)sh_malloc( sizeof( struct cell ) );
 	new_cell = (struct cell*)sh_malloc( sizeof( struct cell ) );
-	if  ( !new_cell )
+	if  ( !new_cell ) {
+		ser_error=E_OUT_OF_MEM;
 		return NULL;
 		return NULL;
+	}
 
 
 	/* filling with 0 */
 	/* filling with 0 */
 	memset( new_cell, 0, sizeof( struct cell ) );
 	memset( new_cell, 0, sizeof( struct cell ) );

+ 8 - 2
modules/tm/h_table.h

@@ -54,7 +54,11 @@ typedef struct retr_buf
 	char *cancel;
 	char *cancel;
 	int   cancel_len;
 	int   cancel_len;
 
 
-	struct sockaddr_in to;
+	/* v6 changes; -jiri
+	struct sockaddr_in to; */
+	union sockaddr_union to;
+	struct socket_info* send_sock;
+
 	size_t tolen;
 	size_t tolen;
 
 
 	/* a message can be linked just to retransmission and FR list */
 	/* a message can be linked just to retransmission and FR list */
@@ -144,7 +148,9 @@ typedef struct cell
 
 
 	/* this is where destination is stored for picked branch;
 	/* this is where destination is stored for picked branch;
 	good if a need to forward ACK later on */
 	good if a need to forward ACK later on */
-	struct sockaddr_in ack_to;
+	/* v6 changes; -jiri
+	struct sockaddr_in ack_to; */
+	union sockaddr_union ack_to;
 #ifndef	USE_SYNONIM
 #ifndef	USE_SYNONIM
 	/* MD5checksum */
 	/* MD5checksum */
 	char md5[MD5_LEN];
 	char md5[MD5_LEN];

+ 95 - 0
modules/tm/t_fork.c

@@ -0,0 +1,95 @@
+/*
+ * $Id$
+ *
+ * forking requests
+ */
+
+#include "../../dprint.h"
+#include "../../config.h"
+#include "../../parser/parser_f.h"
+#include "../../ut.h"
+#include "hash_func.h"
+#include "t_funcs.h"
+#include "t_fork.h"
+
+
+
+unsigned int     nr_forks;
+struct fork      t_forks[ NR_OF_CLIENTS ];
+
+
+int t_add_fork( union sockaddr_union to, char* uri_s,
+			unsigned int uri_len, enum fork_type type, 
+			unsigned char free_flag)
+{
+	unsigned int pos=0;
+	char         *foo=0;
+
+	switch (type)
+	{
+		case DEFAULT:
+			if (nr_forks+1>=MAX_FORK)
+			{
+				LOG(L_ERR,"ERROR:t_add_fork: trying to add new fork ->"
+					" MAX_FORK exceded\n");
+				return -1;
+			}
+			pos = ++nr_forks;
+			break;
+		case NO_RESPONSE:
+			/* v6; -Jiri
+			if (t_forks[NO_RPL_BRANCH].ip)
+			*/
+			if (!t_forks[NO_RPL_BRANCH].inactive)
+				LOG(L_WARN,"WARNING:t_add_fork: trying to add NO_RPL fork ->"
+					" it was set before -> overriding\n");
+			if (uri_s && uri_len)
+			{
+				foo = (char*)shm_malloc(uri_len);
+				if (!foo)
+				{
+					LOG(L_ERR,"ERROR:t_add_fork: cannot get free memory\n");
+					return -1;
+				}
+				memcpy(foo,uri_s,uri_len);
+			}
+			if (free_flag && uri_s)
+				pkg_free(uri_s);
+			uri_s = foo;
+			free_flag = 0;
+			pos = NO_RPL_BRANCH;
+	}
+	/* -v6
+	t_forks[pos].ip = ip;
+	t_forks[pos].port = port;
+	*/
+	t_forks[pos].to=to;
+
+	if (uri_s && uri_len)
+	{
+		t_forks[pos].free_flag = free_flag;
+		t_forks[pos].uri.len = uri_len;
+		t_forks[pos].uri.s = uri_s;
+	}
+
+	return 1;
+}
+
+
+
+
+int t_clear_forks( )
+{
+	int i;
+
+	DBG("DEBUG: t_clear_forks: clearing tabel...\n");
+	for(i=1;i<nr_forks;i++)
+		if (t_forks[i].free_flag && t_forks[i].uri.s)
+			pkg_free(t_forks[i].uri.s);
+	memset( t_forks, 0, sizeof(t_forks));
+	nr_forks = 0;
+	return 1;
+}
+
+
+

+ 30 - 0
modules/tm/t_fork.h

@@ -0,0 +1,30 @@
+/*
+ * $Id$
+ */
+
+#ifndef _T_FORKS_H
+#define _T_FORKS_H
+
+#include "../../ip_addr.h"
+#include "../../str.h"
+
+
+struct fork
+{
+    union sockaddr_union to;
+    char inactive;
+    unsigned char free_flag;
+    str           uri;
+
+};
+
+extern struct fork      t_forks[ NR_OF_CLIENTS ];
+extern unsigned int     nr_forks;
+
+int t_add_fork( union sockaddr_union to, char* uri_s,
+				unsigned int uri_len, enum fork_type type,
+				unsigned char free_flag);
+int t_clear_forks();
+
+
+#endif

+ 4 - 730
modules/tm/t_funcs.c

@@ -1,38 +1,21 @@
 /*
 /*
  * $Id$
  * $Id$
  *
  *
+ * transaction maintenance functions
  */
  */
 
 
-#include "hash_func.h"
-#include "t_funcs.h"
 #include "../../dprint.h"
 #include "../../dprint.h"
 #include "../../config.h"
 #include "../../config.h"
 #include "../../parser/parser_f.h"
 #include "../../parser/parser_f.h"
 #include "../../ut.h"
 #include "../../ut.h"
-//#include "../../timer.h"
-
-
-
-#define  append_mem_block(_d,_s,_len) \
-		do{\
-			memcpy((_d),(_s),(_len));\
-			(_d) += (_len);\
-		}while(0);
-#define  req_line(_msg) \
-		((_msg)->first_line.u.request)
-
+#include "hash_func.h"
+#include "t_funcs.h"
+#include "t_fork.h"
 
 
 
 
 struct cell      *T;
 struct cell      *T;
 unsigned int     global_msg_id;
 unsigned int     global_msg_id;
 struct s_table*  hash_table;
 struct s_table*  hash_table;
-unsigned int     nr_forks;
-struct fork      t_forks[ NR_OF_CLIENTS ];
-
-
-
-void timer_routine(unsigned int, void*);
-
 
 
 
 
 int tm_startup()
 int tm_startup()
@@ -193,85 +176,6 @@ int t_update_timers_after_sending_reply( struct retr_buf *rb )
 
 
 
 
 
 
-/* Checks if the new reply (with new_code status) should be sent or not
- *  based on the current
- * transactin status.
- * Returns 	- branch number (0,1,...) which should be relayed
- *         -1 if nothing to be relayed
- */
-int t_should_relay_response( struct cell *Trans , int new_code,
-									int branch , int *should_store )
-{
-	//int T_code;
-	int b, lowest_b, lowest_s;
-
-	//if (Trans->uas.request->REQ_METHOD==METHOD_INVITE)
-	//	T_code = Trans->uac[branch].status;
-	//else
-	//T_code = Trans->uas.status;
-
-	/* note: this code never lets replies to CANCEL go through;
-	   we generate always a local 200 for CANCEL; 200s are
-	   not relayed because it's not an INVITE transaction;
-	   >= 300 are not relayed because 200 was already sent
-	   out
-	*/
-	DBG("->>>>>>>>> T_code=%d, new_code=%d\n",Trans->uas.status,new_code);
-	/* if final response sent out, allow only INVITE 2xx  */
-	if ( Trans->uas.status >= 200 ) {
-		if (new_code>=200 && new_code < 300  && 
-			Trans->uas.request->REQ_METHOD==METHOD_INVITE) {
-			DBG("DBG: t_should_relay: 200 INV after final sent\n");
-			*should_store=1;
-			return branch;
-		} else {
-			*should_store=0;
-			return -1;
-		}
-	} else { /* no final response sent yet */
-		/* negative replies subject to fork picking */
-		if (new_code >=300 ) {
-			*should_store=1;
-			/* if all_final return lowest */
-			lowest_b=-1; lowest_s=999;
-			for ( b=0; b<Trans->nr_of_outgoings ; b++ ) {
-				/* "fake" for the currently processed branch */
-				if (b==branch) {
-					if (new_code<lowest_s) {
-						lowest_b=b;
-						lowest_s=new_code;
-					}
-					continue;
-				}
-				/* there is still an unfinished UAC transaction; wait now! */
-				if ( Trans->uac[b].status<200 )
-					return -1;
-				if ( Trans->uac[b].status<lowest_s )
-				{
-					lowest_b =b;
-					lowest_s = T->uac[b].status;
-				}
-			}
-			return lowest_b;
-		/* 1xx except 100 and 2xx will be relayed */
-		} else if (new_code>100) {
-			*should_store=1;
-			return branch;
-		}
-		/* 100 won't be relayed */
-		else {
-			if (!T->uac[branch].rpl_received) *should_store=1;
-				else *should_store=0;
-			if (Trans->uas.status==0) return branch;
-				else return -1;
-		}
-	}
-
-	LOG(L_CRIT, "ERROR: Oh my gooosh! We don't know whether to relay\n");
-	abort();
-}
-
-
 /*
 /*
   */
   */
 int t_put_on_wait(  struct cell  *Trans  )
 int t_put_on_wait(  struct cell  *Trans  )
@@ -325,147 +229,6 @@ int t_put_on_wait(  struct cell  *Trans  )
 
 
 
 
 
 
-/* Builds a CANCEL request based on an INVITE request. CANCEL is send
- * to same address as the INVITE */
-int t_build_and_send_CANCEL(struct cell *Trans,unsigned int branch)
-{
-	struct sip_msg      *p_msg;
-	struct hdr_field    *hdr;
-	char                *cancel_buf, *p, *via;
-	unsigned int         len, via_len;
-
-	if ( !Trans->uac[branch].rpl_received )
-	{
-		DBG("DEBUG: t_build_and_send_CANCEL: no response ever received"
-			" : dropping local cancel! \n");
-		return 1;
-	}
-
-	if (Trans->uac[branch].request.cancel!=NO_CANCEL)
-	{
-		DBG("DEBUG: t_build_and_send_CANCEL: branch (%d)was already canceled"
-			" : dropping local cancel! \n",branch);
-		return 1;
-	}
-
-	cancel_buf = 0;
-	via = 0;
-	p_msg = Trans->uas.request;
-
-	len = 0;
-	/*first line's len - CANCEL and INVITE has the same lenght */
-	len += ( req_line(p_msg).version.s+req_line(p_msg).version.len)-
-		req_line(p_msg).method.s+CRLF_LEN;
-	/*check if the REQ URI was override */
-	if (Trans->uac[branch].uri.s)
-		len += Trans->uac[branch].uri.len - req_line(p_msg).uri.len;
-	/*via*/
-	if ( add_branch_label(Trans,p_msg,branch)==-1 )
-		goto error;
-	via = via_builder( p_msg , &via_len );
-	if (!via)
-	{
-		LOG(L_ERR, "ERROR: t_build_and_send_CANCEL: "
-			"no via header got from builder\n");
-		goto error;
-	}
-	len+= via_len;
-	/*headers*/
-	for ( hdr=p_msg->headers ; hdr ; hdr=hdr->next )
-		if (hdr->type==HDR_FROM || hdr->type==HDR_CALLID || 
-			hdr->type==HDR_CSEQ || hdr->type==HDR_TO )
-			len += ((hdr->body.s+hdr->body.len ) - hdr->name.s ) + CRLF_LEN ;
-	/* User Agent header*/
-	len += USER_AGENT_LEN + CRLF_LEN;
-	/* Content Lenght heder*/
-	len += CONTENT_LEN_LEN + CRLF_LEN;
-	/* end of message */
-	len += CRLF_LEN;
-
-	cancel_buf=sh_malloc( len+1 );
-	if (!cancel_buf)
-	{
-		LOG(L_ERR, "ERROR: t_build_and_send_CANCEL: cannot allocate memory\n");
-		goto error;
-	}
-	p = cancel_buf;
-
-	/* first line -> do we have a new URI? */
-	if (Trans->uac[branch].uri.s)
-	{
-		append_mem_block(p,req_line(p_msg).method.s,
-			req_line(p_msg).uri.s-req_line(p_msg).method.s);
-		append_mem_block(p,Trans->uac[branch].uri.s,
-			Trans->uac[branch].uri.len);
-		append_mem_block(p,req_line(p_msg).uri.s+req_line(p_msg).uri.len,
-			req_line(p_msg).version.s+req_line(p_msg).version.len-
-			(req_line(p_msg).uri.s+req_line(p_msg).uri.len))
-	}else{
-		append_mem_block(p,req_line(p_msg).method.s,
-			req_line(p_msg).version.s+req_line(p_msg).version.len-
-			req_line(p_msg).method.s);
-	}
-	/* changhing method name*/
-	memcpy(cancel_buf, CANCEL , CANCEL_LEN );
-	append_mem_block(p,CRLF,CRLF_LEN);
-	/* insert our via */
-	append_mem_block(p,via,via_len);
-
-	/*other headers*/
-	for ( hdr=p_msg->headers ; hdr ; hdr=hdr->next )
-	{
-		if(hdr->type==HDR_FROM||hdr->type==HDR_CALLID||hdr->type==HDR_TO)
-		{
-			append_mem_block(p,hdr->name.s,
-				((hdr->body.s+hdr->body.len)-hdr->name.s) );
-			append_mem_block(p, CRLF, CRLF_LEN );
-		}else if ( hdr->type==HDR_CSEQ )
-		{
-			append_mem_block(p,hdr->name.s,
-				((((struct cseq_body*)hdr->parsed)->method.s)-hdr->name.s));
-			append_mem_block(p, CANCEL CRLF, CANCEL_LEN +CRLF_LEN );
-		}
-}
-
-	/* User Agent header */
-	append_mem_block(p,USER_AGENT,USER_AGENT_LEN);
-	append_mem_block(p,CRLF,CRLF_LEN);
-	/* Content Lenght header*/
-	append_mem_block(p,CONTENT_LEN,CONTENT_LEN_LEN);
-	append_mem_block(p,CRLF,CRLF_LEN);
-	/* end of message */
-	append_mem_block(p,CRLF,CRLF_LEN);
-	*p=0;
-
-	if (Trans->uac[branch].request.cancel) {
-		shm_free( cancel_buf );
-		LOG(L_WARN, "send_cancel: Warning: CANCEL already sent out\n");
-		goto error;
-	}
-
-	Trans->uac[branch].request.activ_type = TYPE_LOCAL_CANCEL;
-	Trans->uac[branch].request.cancel = cancel_buf;
-	Trans->uac[branch].request.cancel_len = len;
-
-	/*sets and starts the FINAL RESPONSE timer */
-	set_timer(hash_table,&(Trans->uac[branch].request.fr_timer),FR_TIMER_LIST);
-	/* sets and starts the RETRANS timer */
-	Trans->uac[branch].request.retr_list = RT_T1_TO_1;
-	set_timer(hash_table,&(Trans->uac[branch].request.retr_timer),RT_T1_TO_1);
-	DBG("DEBUG: T_build_and_send_CANCEL : sending cancel...\n");
-	SEND_CANCEL_BUFFER( &(Trans->uac[branch].request) );
-
-	pkg_free(via);
-	return 1;
-error:
-	if (via) pkg_free(via);
-	return -1;
-}
-
-
-
-
-
 
 
 void delete_cell( struct cell *p_cell )
 void delete_cell( struct cell *p_cell )
 {
 {
@@ -524,492 +287,3 @@ void delete_cell( struct cell *p_cell )
 }
 }
 
 
 
 
-
-
-/* Returns  -1 = error
-                    0 = OK
-*/
-int get_ip_and_port_from_uri( str *uri , unsigned int *param_ip, unsigned int *param_port)
-{
-	struct hostent  *nhost;
-	unsigned int    ip, port;
-	struct sip_uri  parsed_uri;
-	int             err;
-#ifdef DNS_IP_HACK
-	int             len;
-#endif
-
-	/* parsing the request uri in order to get host and port */
-	if (parse_uri( uri->s , uri->len , &parsed_uri )<0)
-	{
-		LOG(L_ERR, "ERROR: get_ip_and_port_from_uri: "
-		   "unable to parse destination uri: %.*s\n", uri->len, uri->s );
-		goto error;
-	}
-
-	/* getting the port */
-	if ( parsed_uri.port.s==0 || parsed_uri.port.len==0 )
-		port = SIP_PORT;
-	else{
-		port = str2s( (unsigned char*) parsed_uri.port.s, parsed_uri.port.len,
-						&err );
-		if ( err<0 ){
-			LOG(L_ERR, "ERROR: get_ip_and_port_from_uri: converting port "
-				"from str to int failed; using default SIP port\n\turi:%.*s\n",
-				uri->len, uri->s );
-			port = SIP_PORT;
-		}
-	}
-	port = htons(port);
-
-	/* getting host address*/
-#ifdef DNS_IP_HACK
-	len=strlen( parsed_uri.host.s );
-	ip=str2ip( (unsigned char*)parsed_uri.host.s, len, &err);
-	if (err==0)
-		goto success;
-#endif
-	/* fail over to normal lookup */
-	nhost = gethostbyname( parsed_uri.host.s );
-	if ( !nhost )
-	{
-		LOG(L_ERR, "ERROR: get_ip_and_port_from_uri: "
-		  "cannot resolve host in uri: %.*s\n", uri->len, uri->s );
-		free_uri(&parsed_uri);
-		goto error;
-	}
-	memcpy(&ip, nhost->h_addr_list[0], sizeof(unsigned int));
-
-
-success:
-	free_uri(&parsed_uri);
-	*param_ip = ip;
-	*param_port = port;
-	return 0;
-
-error:
-	*param_ip = 0;
-	*param_port = 0;
-	return -1;
-}
-
-
-
-
-int t_add_fork( unsigned int ip, unsigned int port, char* uri_s,
-			unsigned int uri_len, enum fork_type type, unsigned char free_flag)
-{
-	unsigned int pos=0;
-	char         *foo=0;
-
-	switch (type)
-	{
-		case DEFAULT:
-			if (nr_forks+1>=MAX_FORK)
-			{
-				LOG(L_ERR,"ERROR:t_add_fork: trying to add new fork ->"
-					" MAX_FORK exceded\n");
-				return -1;
-			}
-			pos = ++nr_forks;
-			break;
-		case NO_RESPONSE:
-			if (t_forks[NO_RPL_BRANCH].ip)
-				LOG(L_WARN,"WARNING:t_add_fork: trying to add NO_RPL fork ->"
-					" it was set before -> overriding\n");
-			if (uri_s && uri_len)
-			{
-				foo = (char*)shm_malloc(uri_len);
-				if (!foo)
-				{
-					LOG(L_ERR,"ERROR:t_add_fork: cannot get free memory\n");
-					return -1;
-				}
-				memcpy(foo,uri_s,uri_len);
-			}
-			if (free_flag && uri_s)
-				pkg_free(uri_s);
-			uri_s = foo;
-			free_flag = 0;
-			pos = NO_RPL_BRANCH;
-	}
-	t_forks[pos].ip = ip;
-	t_forks[pos].port = port;
-	if (uri_s && uri_len)
-	{
-		t_forks[pos].free_flag = free_flag;
-		t_forks[pos].uri.len = uri_len;
-		t_forks[pos].uri.s = uri_s;
-	}
-
-	return 1;
-}
-
-
-
-
-int t_clear_forks( )
-{
-	int i;
-
-	DBG("DEBUG: t_clear_forks: clearing tabel...\n");
-	for(i=1;i<nr_forks;i++)
-		if (t_forks[i].free_flag && t_forks[i].uri.s)
-			pkg_free(t_forks[i].uri.s);
-	memset( t_forks, 0, sizeof(t_forks));
-	nr_forks = 0;
-	return 1;
-}
-
-
-
-
-
-/*---------------------------TIMERS FUNCTIONS-------------------------------*/
-
-
-
-
-
-inline void retransmission_handler( void *attr)
-{
-	struct retr_buf* r_buf ;
-	enum lists id;
-
-	r_buf = (struct retr_buf*)attr;
-#ifdef EXTRA_DEBUG
-	if (r_buf->my_T->damocles) {
-		LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and"
-			" called from RETR timer\n",r_buf->my_T);
-		abort();
-	}	
-#endif
-
-	/*the transaction is already removed from RETRANSMISSION_LIST by timer*/
-	/* retransmision */
-	DBG("DEBUG: retransmission_handler : resending (t=%p)\n", r_buf->my_T);
-	switch ( r_buf->activ_type )
-	{
-		case (TYPE_REQUEST):
-			SEND_BUFFER( r_buf );
-			break;
-		case (TYPE_LOCAL_CANCEL):
-			SEND_CANCEL_BUFFER( r_buf );
-			break;
-		default:
-			T=r_buf->my_T;
-			t_retransmit_reply();
-	}
-
-	id = r_buf->retr_list;
-	r_buf->retr_list = id < RT_T2 ? id + 1 : RT_T2;
-
-	set_timer(hash_table,&(r_buf->retr_timer),id < RT_T2 ? id + 1 : RT_T2 );
-
-	DBG("DEBUG: retransmission_handler : done\n");
-}
-
-
-
-
-inline void final_response_handler( void *attr)
-{
-	struct retr_buf* r_buf = (struct retr_buf*)attr;
-
-#ifdef EXTRA_DEBUG
-	if (r_buf->my_T->damocles) 
-	{
-		LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and"
-			" called from FR timer\n",r_buf->my_T);
-		abort();
-	}
-#endif
-
-	/* the transaction is already removed from FR_LIST by the timer */
-	if (r_buf->activ_type==TYPE_LOCAL_CANCEL)
-	{
-		DBG("DEBUG: FR_handler: stop retransmission for Local Cancel\n");
-		reset_timer( hash_table , &(r_buf->retr_timer) );
-		return;
-	}
-	/* send a 408 */
-	if ( r_buf->my_T->uac[r_buf->branch].status<200
-#ifdef SILENT_FR
-	&& (r_buf->my_T->nr_of_outgoings>1     /*if we have forked*/
-		|| r_buf->my_T->uas.request->first_line.u.request.method_value!=
-			METHOD_INVITE                  /*if is not an INVITE */
-		|| r_buf->my_T->uac[r_buf->my_T->nr_of_outgoings].uri.s
-		                                   /*if "no on no response" was set*/
-		|| r_buf->my_T->uac[r_buf->branch].rpl_received==0
-											/*if no reply was received*/
-	)
-#endif
-	)
-	{
-		DBG("DEBUG: FR_handler:stop retr. and send CANCEL (%p)\n",r_buf->my_T);
-		reset_timer( hash_table, &(r_buf->retr_timer) );
-		t_build_and_send_CANCEL( r_buf->my_T ,r_buf->branch);
-		/* dirty hack:t_send_reply would increase ref_count which would indeed
-		result in refcount++ which would not -- until timer processe's
-		T changes again; currently only on next call to t_send_reply from
-		FR timer; thus I fake the values now to avoid recalculating T
-		and refcount++ JKU */
-		T=r_buf->my_T;
-		global_msg_id=T->uas.request->id;
-		DBG("DEBUG: FR_handler: send 408 (%p)\n", r_buf->my_T);
-		t_send_reply( r_buf->my_T->uas.request, 408, "Request Timeout",
-			r_buf->branch);
-	}else{
-		/* put it on WT_LIST - transaction is over */
-		DBG("DEBUG: final_response_handler:-> put on wait"
-			" (t=%p)\n", r_buf->my_T);
-		t_put_on_wait(  r_buf->my_T );
-	}
-	DBG("DEBUG: final_response_handler : done\n");
-}
-
-
-
-
-inline void wait_handler( void *attr)
-{
-	struct cell *p_cell = (struct cell*)attr;
-
-#ifdef EXTRA_DEBUG
-	if (p_cell->damocles) {
-		LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and"
-			" called from WAIT timer\n",p_cell);
-		abort();
-	}	
-#endif
-
-	/* the transaction is already removed from WT_LIST by the timer */
-	/* the cell is removed from the hash table */
-	DBG("DEBUG: wait_handler : removing %p from table \n", p_cell );
-	remove_from_hash_table( hash_table, p_cell );
-	/* jku: no more here -- we do it when we put a transaction on wait */
-	DBG("DEBUG: wait_handler : stopping all timers\n");
-	reset_retr_timers(hash_table,p_cell) ; 
-	/* put it on DEL_LIST - sch for del */
-#ifdef EXTRA_DEBUG
-	p_cell->damocles = 1;
-#endif
-	delete_cell( p_cell );
-	DBG("DEBUG: wait_handler : done\n");
-}
-
-
-
-
-inline void delete_handler( void *attr)
-{
-	struct cell *p_cell = (struct cell*)attr;
-
-	DBG("DEBUG: delete_handler : removing %p \n", p_cell );
-#ifdef EXTRA_DEBUG
-	if (p_cell->damocles==0) {
-		LOG( L_ERR, "ERROR: transaction %p not scheduled for deletion"
-			" and called from DELETE timer\n",p_cell);
-		abort();
-	}	
-#endif
-	delete_cell( p_cell );
-    DBG("DEBUG: delete_handler : done\n");
-}
-
-
-
-
-#define run_handler_for_each( _tl , _handler ) \
-	while ((_tl))\
-	{\
-		/* reset the timer list linkage */\
-		tmp_tl = (_tl)->next_tl;\
-		(_tl)->next_tl = (_tl)->prev_tl = 0;\
-		DBG("DEBUG: timer routine:%d,tl=%p next=%p\n",\
-			id,(_tl),tmp_tl);\
-		(_handler)( (_tl)->payload );\
-		(_tl) = tmp_tl;\
-	}
-
-
-
-
-void timer_routine(unsigned int ticks , void * attr)
-{
-	struct s_table    *hash_table = (struct s_table *)attr;
-	struct timer_link *tl, *tmp_tl;
-	int                id;
-
-#ifdef BOGDAN_TRIFLE
-	DBG(" %d \n",ticks);
-#endif
-
-	for( id=0 ; id<NR_OF_TIMER_LISTS ; id++ )
-	{
-		/* to waste as little time in lock as possible, detach list
-		   with expired items and process them after leaving the lock */
-		tl=check_and_split_time_list( &(hash_table->timers[ id ]), ticks);
-		/* process items now */
-		switch (id)
-		{
-			case FR_TIMER_LIST:
-			case FR_INV_TIMER_LIST:
-				run_handler_for_each(tl,final_response_handler);
-				break;
-			case RT_T1_TO_1:
-			case RT_T1_TO_2:
-			case RT_T1_TO_3:
-			case RT_T2:
-				run_handler_for_each(tl,retransmission_handler);
-				break;
-			case WT_TIMER_LIST:
-				run_handler_for_each(tl,wait_handler);
-				break;
-			case DELETE_LIST:
-				run_handler_for_each(tl,delete_handler);
-				break;
-		}
-	}
-}
-
-
-
-
-
-
-
-/* Builds an ACK request based on an INVITE request. ACK is send
- * to same address */
-char *build_ack(struct sip_msg* rpl,struct cell *trans,int branch,int *ret_len)
-{
-	struct sip_msg      *p_msg , *r_msg;
-	struct hdr_field    *hdr;
-	char                *ack_buf, *p, *via;
-	unsigned int         len, via_len;
-
-	ack_buf = 0;
-	via =0;
-	p_msg = trans->uas.request;
-	r_msg = rpl;
-
-	if ( parse_headers(rpl,HDR_TO)==-1 || !rpl->to )
-	{
-		LOG(L_ERR, "ERROR: t_build_ACK: "
-			"cannot generate a HBH ACK if key HFs in reply missing\n");
-		goto error;
-	}
-
-	len = 0;
-	/*first line's len */
-	len += 4/*reply code and one space*/+
-		p_msg->first_line.u.request.version.len+CRLF_LEN;
-	/*uri's len*/
-	if (trans->uac[branch].uri.s)
-		len += trans->uac[branch].uri.len +1;
-	else
-		len += p_msg->first_line.u.request.uri.len +1;
-	/*adding branch param*/
-	if ( add_branch_label( trans , trans->uas.request , branch)==-1 )
-		goto error;
-	/*via*/
-	via = via_builder( p_msg , &via_len );
-	if (!via)
-	{
-		LOG(L_ERR, "ERROR: t_build_ACK: "
-			"no via header got from builder\n");
-		goto error;
-	}
-	len+= via_len;
-	/*headers*/
-	for ( hdr=p_msg->headers ; hdr ; hdr=hdr->next )
-		if (hdr->type==HDR_FROM||hdr->type==HDR_CALLID||hdr->type==HDR_CSEQ)
-			len += ((hdr->body.s+hdr->body.len ) - hdr->name.s ) + CRLF_LEN ;
-		else if ( hdr->type==HDR_TO )
-			len += ((r_msg->to->body.s+r_msg->to->body.len ) -
-				r_msg->to->name.s ) + CRLF_LEN ;
-	/* CSEQ method : from INVITE-> ACK */
-	len -= 3  ;
-	/* end of message */
-	len += CRLF_LEN; /*new line*/
-
-	ack_buf = sh_malloc(len+1);
-	if (!ack_buf)
-	{
-		LOG(L_ERR, "ERROR: t_build_and_ACK: cannot allocate memory\n");
-		goto error1;
-	}
-	p = ack_buf;
-
-	/* first line */
-	memcpy( p , "ACK " , 4);
-	p += 4;
-	/* uri */
-	if ( trans->uac[branch].uri.s )
-	{
-		memcpy(p,trans->uac[branch].uri.s,trans->uac[branch].uri.len);
-		p +=trans->uac[branch].uri.len;
-	}else{
-		memcpy(p,p_msg->orig+(p_msg->first_line.u.request.uri.s-p_msg->buf),
-			p_msg->first_line.u.request.uri.len );
-		p += p_msg->first_line.u.request.uri.len;
-	}
-	/* SIP version */
-	*(p++) = ' ';
-	memcpy(p,p_msg->orig+(p_msg->first_line.u.request.version.s-p_msg->buf),
-		p_msg->first_line.u.request.version.len );
-	p += p_msg->first_line.u.request.version.len;
-	memcpy( p, CRLF, CRLF_LEN );
-	p+=CRLF_LEN;
-
-	/* insert our via */
-	memcpy( p , via , via_len );
-	p += via_len;
-
-	/*other headers*/
-	for ( hdr=p_msg->headers ; hdr ; hdr=hdr->next )
-	{
-		if ( hdr->type==HDR_FROM || hdr->type==HDR_CALLID  )
-		{
-			memcpy( p , p_msg->orig+(hdr->name.s-p_msg->buf) ,
-				((hdr->body.s+hdr->body.len ) - hdr->name.s ) );
-			p += ((hdr->body.s+hdr->body.len ) - hdr->name.s );
-			memcpy( p, CRLF, CRLF_LEN );
-			p+=CRLF_LEN;
-		}
-		else if ( hdr->type==HDR_TO )
-		{
-			memcpy( p , r_msg->orig+(r_msg->to->name.s-r_msg->buf) ,
-				((r_msg->to->body.s+r_msg->to->body.len)-r_msg->to->name.s));
-			p+=((r_msg->to->body.s+r_msg->to->body.len)-r_msg->to->name.s);
-			memcpy( p, CRLF, CRLF_LEN );
-			p+=CRLF_LEN;
-		}
-		else if ( hdr->type==HDR_CSEQ )
-		{
-			memcpy( p , p_msg->orig+(hdr->name.s-p_msg->buf) ,
-				((((struct cseq_body*)hdr->parsed)->method.s)-hdr->name.s));
-			p+=((((struct cseq_body*)hdr->parsed)->method.s)-hdr->name.s);
-			memcpy( p , "ACK" CRLF, 3+CRLF_LEN );
-			p += 3+CRLF_LEN;
-		}
-	}
-
-	/* end of message */
-	memcpy( p , CRLF , CRLF_LEN );
-	p += CRLF_LEN;
-
-	pkg_free( via );
-	DBG("DEBUG: t_build_ACK: ACK generated\n");
-
-	*(ret_len) = p-ack_buf;
-	return ack_buf;
-
-error1:
-	pkg_free(via );
-error:
-	return 0;
-}
-
-
-

+ 49 - 33
modules/tm/t_funcs.h

@@ -17,12 +17,14 @@
 #include "../../timer.h"
 #include "../../timer.h"
 #include "../../forward.h"
 #include "../../forward.h"
 #include "../../mem/mem.h"
 #include "../../mem/mem.h"
-
 #include "../../md5utils.h"
 #include "../../md5utils.h"
+#include "../../ip_addr.h"
 
 
 #include "config.h"
 #include "config.h"
 #include "lock.h"
 #include "lock.h"
 #include "timer.h"
 #include "timer.h"
+#include "sh_malloc.h"
+#include "sip_msg.h"
 
 
 
 
 struct s_table;
 struct s_table;
@@ -30,27 +32,10 @@ struct timer;
 struct entry;
 struct entry;
 struct cell;
 struct cell;
 
 
-struct fork
-{
-	unsigned int  ip,port;
-	unsigned char free_flag;
-	str           uri;
-
-};
-
-
 extern struct cell      *T;
 extern struct cell      *T;
 extern unsigned int     global_msg_id;
 extern unsigned int     global_msg_id;
 extern struct s_table*  hash_table;
 extern struct s_table*  hash_table;
-extern struct fork      t_forks[ NR_OF_CLIENTS ];
-extern unsigned int     nr_forks;
-
-
-#include "sh_malloc.h"
 
 
-#include "timer.h"
-#include "lock.h"
-#include "sip_msg.h"
 
 
 
 
 #define LOCK_REPLIES(_t) lock(&(_t)->reply_mutex )
 #define LOCK_REPLIES(_t) lock(&(_t)->reply_mutex )
@@ -66,17 +51,35 @@ extern unsigned int     nr_forks;
    for reducing time spend in REPLIES locks
    for reducing time spend in REPLIES locks
 */
 */
 
 
-#define SEND_PR_BUFFER(_rb,_bf,_le ) \
-	{\
-		if ((_bf) && (_le) && (_bf) ) {\
-			udp_send( (_bf), (_le), (struct sockaddr*)&((_rb)->to) , \
-				sizeof(struct sockaddr_in) ); \
-		}else{ \
-			LOG(L_CRIT,"ERROR: sending an empty buffer from %s (%d)\n",\
-				__FUNCTION__, __LINE__ );\
-		}\
+inline static int send_pr_buffer( struct retr_buf *rb,
+	void *buf, int len, char *function, int line )
+{
+	if (buf && len && rb )
+		return udp_send( rb->send_sock, buf, 
+			len, &rb->to,  sizeof(union sockaddr_union) ) ;
+	else {
+		LOG(L_CRIT, "ERROR: sending an empty buffer from %s (%d)\n",
+			function, line );
+		return -1;
 	}
 	}
+}
+
+#define SEND_PR_BUFFER(_rb,_bf,_le ) \
+	send_pr_buffer( (_rb), (_bf), (_le),  __FUNCTION__, __LINE__ )
 
 
+/*
+#define SEND_PR_BUFFER(_rb,_bf,_le ) \
+	( ((_bf) && (_le) && (_bf)) ? \
+	udp_send( (_bf), (_le), &((_rb)->to), sizeof(union sockaddr_union) ) : \
+	log_send_error( __FUNCTION__, __LINE__ ) )
+*/
+
+/* just for understanding of authors of the following macros, who did not
+   include 'PR' in macro names though they use 'PR' macro: PR stands for
+   PRIVATE and indicates usage of memory buffers in PRIVATE memory space,
+   where -- as opposed to SHARED memory space -- no concurrent memory
+   access can occur and thus no locking is needed ! -jiri
+*/
 #define SEND_ACK_BUFFER( _rb ) \
 #define SEND_ACK_BUFFER( _rb ) \
 	SEND_PR_BUFFER( (_rb) , (_rb)->ack , (_rb)->ack_len )
 	SEND_PR_BUFFER( (_rb) , (_rb)->ack , (_rb)->ack_len )
 
 
@@ -134,9 +137,10 @@ extern unsigned int     nr_forks;
 
 
 
 
 
 
-
+/*
 enum addifnew_status { AIN_ERROR, AIN_RETR, AIN_NEW, AIN_NEWACK,
 enum addifnew_status { AIN_ERROR, AIN_RETR, AIN_NEW, AIN_NEWACK,
 	AIN_OLDACK, AIN_RTRACK } ;
 	AIN_OLDACK, AIN_RTRACK } ;
+*/
 
 
 
 
 int   tm_startup();
 int   tm_startup();
@@ -165,8 +169,10 @@ int t_check( struct sip_msg* , int *branch , int* is_cancel);
  *       1 - forward successfull
  *       1 - forward successfull
  *      -1 - error during forward
  *      -1 - error during forward
  */
  */
+/* v6; -jiri
 int t_forward( struct sip_msg* p_msg , unsigned int dst_ip ,
 int t_forward( struct sip_msg* p_msg , unsigned int dst_ip ,
 										unsigned int dst_port);
 										unsigned int dst_port);
+*/
 
 
 
 
 
 
@@ -175,7 +181,9 @@ int t_forward( struct sip_msg* p_msg , unsigned int dst_ip ,
  *       1 - forward successfull
  *       1 - forward successfull
  *      -1 - error during forward
  *      -1 - error during forward
  */
  */
+/* v6; -jiri
 int t_forward_uri( struct sip_msg* p_msg  );
 int t_forward_uri( struct sip_msg* p_msg  );
+*/
 
 
 
 
 
 
@@ -239,11 +247,16 @@ int t_unref( /* struct sip_msg* p_msg */ );
 
 
 
 
 
 
-
+/* v6; -jiri
 int t_forward_nonack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
 int t_forward_nonack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
 	unsigned int dest_port_param );
 	unsigned int dest_port_param );
 int t_forward_ack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
 int t_forward_ack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
 	unsigned int dest_port_param );
 	unsigned int dest_port_param );
+*/
+int t_forward_nonack( struct sip_msg* p_msg, struct proxy_l * p );
+int t_forward_ack( struct sip_msg* p_msg );
+
+
 int forward_serial_branch(struct cell* Trans,int branch);
 int forward_serial_branch(struct cell* Trans,int branch);
 struct cell* t_lookupOriginalT(  struct s_table* hash_table,
 struct cell* t_lookupOriginalT(  struct s_table* hash_table,
 	struct sip_msg* p_msg );
 	struct sip_msg* p_msg );
@@ -264,10 +277,11 @@ int get_ip_and_port_from_uri( str* uri , unsigned int *param_ip,
 int t_build_and_send_CANCEL(struct cell *Trans, unsigned int branch);
 int t_build_and_send_CANCEL(struct cell *Trans, unsigned int branch);
 char *build_ack( struct sip_msg* rpl, struct cell *trans, int branch ,
 char *build_ack( struct sip_msg* rpl, struct cell *trans, int branch ,
 	int *ret_len);
 	int *ret_len);
-enum addifnew_status t_addifnew( struct sip_msg* p_msg );
-int t_add_fork( unsigned int ip , unsigned int port, char* uri_s,
-	unsigned int uri_len, enum fork_type type, unsigned char free_flag);
-int t_clear_forks( );
+
+int t_addifnew( struct sip_msg* p_msg );
+
+void timer_routine(unsigned int, void*);
+
 
 
 
 
 
 
@@ -356,7 +370,9 @@ static inline void reset_retr_timers( struct s_table *h_table,
 	DBG("DEBUG:stop_RETR_and_FR_timers : timers stopped\n");
 	DBG("DEBUG:stop_RETR_and_FR_timers : timers stopped\n");
 }
 }
 
 
+void delete_cell( struct cell *p_cell );
 
 
+int t_newtran( struct sip_msg* p_msg );
 
 
 #endif
 #endif
 
 

+ 102 - 39
modules/tm/t_fwd.c

@@ -3,13 +3,14 @@
  *
  *
  */
  */
 
 
-#include "hash_func.h"
-#include "t_funcs.h"
 #include "../../dprint.h"
 #include "../../dprint.h"
 #include "../../config.h"
 #include "../../config.h"
 #include "../../parser/parser_f.h"
 #include "../../parser/parser_f.h"
 #include "../../ut.h"
 #include "../../ut.h"
 #include "../../timer.h"
 #include "../../timer.h"
+#include "hash_func.h"
+#include "t_funcs.h"
+#include "t_fork.h"
 
 
 #include "t_hooks.h"
 #include "t_hooks.h"
 
 
@@ -29,8 +30,11 @@
  *       1 - forward successfull
  *       1 - forward successfull
  *      -1 - error during forward
  *      -1 - error during forward
  */
  */
-int t_forward_nonack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
+int t_forward_nonack( struct sip_msg* p_msg , 
+					  struct proxy_l * p )
+/* v6; -jiri									unsigned int dest_ip_param ,
 												unsigned int dest_port_param )
 												unsigned int dest_port_param )
+*/
 {
 {
 	int          branch;
 	int          branch;
 	unsigned int len;
 	unsigned int len;
@@ -38,20 +42,18 @@ int t_forward_nonack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
 	struct cell  *T_source = T;
 	struct cell  *T_source = T;
 	struct lump  *a,*b,*b1,*c;
 	struct lump  *a,*b,*b1,*c;
 	str          backup_uri;
 	str          backup_uri;
+	int			 ret;
+	struct socket_info* send_sock;
+	union sockaddr_union to;
 
 
 
 
+	/* default error value == -1; be more specific if you want to */
+	ret=-1;
 	buf    = 0;
 	buf    = 0;
 	shbuf  = 0;
 	shbuf  = 0;
 	backup_uri.s = p_msg->new_uri.s;
 	backup_uri.s = p_msg->new_uri.s;
 	backup_uri.len = p_msg->new_uri.len;
 	backup_uri.len = p_msg->new_uri.len;
 
 
-	/* sets as first fork the default outgoing */
-	nr_forks++;
-	t_forks[0].ip = dest_ip_param;
-	t_forks[0].port = dest_port_param;
-	t_forks[0].uri.len = p_msg->new_uri.len;
-	t_forks[0].uri.s =  p_msg->new_uri.s;
-	t_forks[0].free_flag = 0;
 
 
 
 
 	/* are we forwarding for the first time? */
 	/* are we forwarding for the first time? */
@@ -61,9 +63,32 @@ int t_forward_nonack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
 		   somewhere else */
 		   somewhere else */
 		LOG( L_CRIT, "ERROR: t_forward_nonack: attempt to rewrite"
 		LOG( L_CRIT, "ERROR: t_forward_nonack: attempt to rewrite"
 			" request structures\n");
 			" request structures\n");
+		ser_error=E_BUG;
 		return 0;
 		return 0;
 	}
 	}
 
 
+	/* v6; -jiri ... copynpasted from forward_request */
+	/* if error try next ip address if possible */
+	if (p->ok==0){
+		if (p->host.h_addr_list[p->addr_idx+1])
+			p->addr_idx++;
+		else p->addr_idx=0;
+		p->ok=1;
+	}
+	hostent2su(&to, &p->host, p->addr_idx,
+    	(p->port)?htons(p->port):htons(SIP_PORT));
+
+	/* sets as first fork the default outgoing */
+	nr_forks++;
+	/* v6; -jiri
+	t_forks[0].ip = dest_ip_param;
+	t_forks[0].port = dest_port_param;
+	*/
+	t_forks[0].to=to;
+	t_forks[0].uri.len = p_msg->new_uri.len;
+	t_forks[0].uri.s =  p_msg->new_uri.s;
+	t_forks[0].free_flag = 0;
+
 	DBG("DEBUG: t_forward_nonack: first time forwarding\n");
 	DBG("DEBUG: t_forward_nonack: first time forwarding\n");
 	/* special case : CANCEL */
 	/* special case : CANCEL */
 	if ( p_msg->REQ_METHOD==METHOD_CANCEL  )
 	if ( p_msg->REQ_METHOD==METHOD_CANCEL  )
@@ -83,10 +108,14 @@ int t_forward_nonack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
 				{
 				{
 					DBG("DEBUG: t_forward_nonack: branch %d not finalize"
 					DBG("DEBUG: t_forward_nonack: branch %d not finalize"
 						": sending CANCEL for it\n",nr_forks);
 						": sending CANCEL for it\n",nr_forks);
+					/* v6; -jiri
 					t_forks[nr_forks].ip =
 					t_forks[nr_forks].ip =
-					  T->T_canceled->uac[nr_forks].request.to.sin_addr.s_addr;
+					  T->T_canceled->uac[nr_forks].request.to.sin_addr.s_addr; 
 					t_forks[nr_forks].port =
 					t_forks[nr_forks].port =
 					  T->T_canceled->uac[nr_forks].request.to.sin_port;
 					  T->T_canceled->uac[nr_forks].request.to.sin_port;
+					*/
+					t_forks[nr_forks].to = T->T_canceled->uac[nr_forks].request.to;
+
 					t_forks[nr_forks].uri.len =
 					t_forks[nr_forks].uri.len =
 					  T->T_canceled->uac[nr_forks].uri.len;
 					  T->T_canceled->uac[nr_forks].uri.len;
 					t_forks[nr_forks].uri.s =
 					t_forks[nr_forks].uri.s =
@@ -96,7 +125,10 @@ int t_forward_nonack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
 					/* transaction exists, but nothing to cancel */
 					/* transaction exists, but nothing to cancel */
 					DBG("DEBUG: t_forward_nonack: branch %d finalized"
 					DBG("DEBUG: t_forward_nonack: branch %d finalized"
 						": no CANCEL sent here\n",nr_forks);
 						": no CANCEL sent here\n",nr_forks);
+					/* -v6; -jiri
 					t_forks[nr_forks].ip = 0;
 					t_forks[nr_forks].ip = 0;
+					*/
+					t_forks[nr_forks].inactive= 1;
 				}
 				}
 			}
 			}
 #ifdef USE_SYNONIM
 #ifdef USE_SYNONIM
@@ -110,14 +142,16 @@ int t_forward_nonack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
 	}/* end special case CANCEL*/
 	}/* end special case CANCEL*/
 
 
 #ifndef USE_SYNONIM
 #ifndef USE_SYNONIM
-	if ( nr_forks && add_branch_label( T_source, T->uas.request , 0 )==-1)
+	branch=0;
+	if ( nr_forks && add_branch_label( T_source, T->uas.request , branch )==-1)
 		goto error;
 		goto error;
 #endif
 #endif
 
 
 	DBG("DEBUG: t_forward_nonack: nr_forks=%d\n",nr_forks);
 	DBG("DEBUG: t_forward_nonack: nr_forks=%d\n",nr_forks);
 	for(branch=0;branch<nr_forks;branch++)
 	for(branch=0;branch<nr_forks;branch++)
 	{
 	{
-		if (!t_forks[branch].ip)
+		/* -v6; -jiri if (!t_forks[branch].ip) */
+		if (t_forks[branch].inactive)
 			goto end_loop;
 			goto end_loop;
 		DBG("DEBUG: t_forward_nonack: branch = %d\n",branch);
 		DBG("DEBUG: t_forward_nonack: branch = %d\n",branch);
 		/*generates branch param*/
 		/*generates branch param*/
@@ -139,8 +173,24 @@ int t_forward_nonack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
 		/* updates the new uri*/
 		/* updates the new uri*/
 		p_msg->new_uri.s = t_forks[branch].uri.s;
 		p_msg->new_uri.s = t_forks[branch].uri.s;
 		p_msg->new_uri.len = t_forks[branch].uri.len;
 		p_msg->new_uri.len = t_forks[branch].uri.len;
-		if ( !(buf = build_req_buf_from_sip_req  ( p_msg, &len)))
+
+		T->uac[branch].request.to = t_forks[branch].to;
+		send_sock=get_send_socket( & T->uac[branch].request.to );
+		if (send_sock==0) {
+			LOG(L_ERR, "ERROR: t_forward_nonack: can't fwd to af %d "
+				"no corresponding listening socket\n", 
+				T->uac[branch].request.to.s.sa_family);
+			ser_error=E_NO_SOCKET;
 			goto error;
 			goto error;
+		}
+		T->uac[branch].request.send_sock=send_sock;
+		
+		callback_event( TMCB_REQUEST_OUT, p_msg );	
+		/* _test_insert_to_reply(p_msg, "Foo: Bar\r\n");*/
+		if ( !(buf = build_req_buf_from_sip_req  ( p_msg, &len, send_sock ))) {
+			ser_error=ret=E_OUT_OF_MEM;
+			goto error;
+		}
 		/* allocates a new retrans_buff for the outbound request */
 		/* allocates a new retrans_buff for the outbound request */
 		DBG("DEBUG: t_forward_nonack: building outbound request"
 		DBG("DEBUG: t_forward_nonack: building outbound request"
 			" for branch %d.\n",branch);
 			" for branch %d.\n",branch);
@@ -148,6 +198,7 @@ int t_forward_nonack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
 		if (!shbuf)
 		if (!shbuf)
 		{
 		{
 			LOG(L_ERR, "ERROR: t_forward_nonack: out of shmem buffer\n");
 			LOG(L_ERR, "ERROR: t_forward_nonack: out of shmem buffer\n");
+			ser_error=ret=E_OUT_OF_MEM;
 			goto error;
 			goto error;
 		}
 		}
 		T->uac[branch].request.buffer = shbuf;
 		T->uac[branch].request.buffer = shbuf;
@@ -159,10 +210,22 @@ int t_forward_nonack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
 		T->uac[branch].uri.len=t_forks[branch].uri.s?(t_forks[branch].uri.len)
 		T->uac[branch].uri.len=t_forks[branch].uri.s?(t_forks[branch].uri.len)
 			:(p_msg->first_line.u.request.uri.len);
 			:(p_msg->first_line.u.request.uri.len);
 		/* send the request */
 		/* send the request */
+		/* v6; -jiri
 		T->uac[branch].request.to.sin_addr.s_addr = t_forks[branch].ip;
 		T->uac[branch].request.to.sin_addr.s_addr = t_forks[branch].ip;
 		T->uac[branch].request.to.sin_port = t_forks[branch].port;
 		T->uac[branch].request.to.sin_port = t_forks[branch].port;
 		T->uac[branch].request.to.sin_family = AF_INET;
 		T->uac[branch].request.to.sin_family = AF_INET;
-		SEND_BUFFER( &(T->uac[branch].request) );
+		*/
+		T->uac[branch].request.to = t_forks[branch].to;
+		p->tx++;
+		p->tx_bytes+=len;
+		if (SEND_BUFFER( &(T->uac[branch].request) )==-1) {
+			p->errors++;
+			p->ok=0;
+			ser_error=ret=E_SEND;
+			goto error;
+		}
+		/* should have p->errors++; p->ok=0; on error here... */
+
 
 
 		pkg_free( buf ) ;
 		pkg_free( buf ) ;
 		buf=NULL;
 		buf=NULL;
@@ -185,11 +248,17 @@ int t_forward_nonack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
 
 
 	/* if we have a branch spec. for NO_RESPONSE_RECEIVED, we have to 
 	/* if we have a branch spec. for NO_RESPONSE_RECEIVED, we have to 
 	move it immediatly after the last parallel branch */
 	move it immediatly after the last parallel branch */
-	if (t_forks[NO_RPL_BRANCH].ip && T->nr_of_outgoings!=NO_RPL_BRANCH )
+	/* v6; -jiri 
+	if (t_forks[NO_RPL_BRANCH].ip && T->nr_of_outgoings!=NO_RPL_BRANCH ) */
+	if (!t_forks[NO_RPL_BRANCH].inactive && T->nr_of_outgoings!=NO_RPL_BRANCH )
 	{
 	{
 		branch = T->nr_of_outgoings;
 		branch = T->nr_of_outgoings;
+		/* v6; -jiri
 		T->uac[branch].request.to.sin_addr.s_addr = t_forks[NO_RPL_BRANCH].ip;
 		T->uac[branch].request.to.sin_addr.s_addr = t_forks[NO_RPL_BRANCH].ip;
 		T->uac[branch].request.to.sin_port = t_forks[NO_RPL_BRANCH].port;
 		T->uac[branch].request.to.sin_port = t_forks[NO_RPL_BRANCH].port;
+		*/
+		T->uac[branch].request.to = t_forks[NO_RPL_BRANCH].to;
+
 		T->uac[branch].uri.s = t_forks[NO_RPL_BRANCH].uri.s;
 		T->uac[branch].uri.s = t_forks[NO_RPL_BRANCH].uri.s;
 		T->uac[branch].uri.len = t_forks[NO_RPL_BRANCH].uri.len;
 		T->uac[branch].uri.len = t_forks[NO_RPL_BRANCH].uri.len;
 	}
 	}
@@ -205,22 +274,17 @@ error:
 	p_msg->new_uri.s = backup_uri.s;
 	p_msg->new_uri.s = backup_uri.s;
 	p_msg->new_uri.len = backup_uri.len;
 	p_msg->new_uri.len = backup_uri.len;
 	t_clear_forks();
 	t_clear_forks();
-	return -1;
+	return ret;
 }
 }
 
 
 
 
+#ifdef _YOU_DONT_REALLY_WANT_THIS
 
 
-
-int t_forward_ack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
-										unsigned int dest_port_param )
+int t_forward_ack( struct sip_msg* p_msg  )
 {
 {
 	int branch;
 	int branch;
 	unsigned int len;
 	unsigned int len;
 	char *buf, *ack;
 	char *buf, *ack;
-#ifdef _DONT_USE
-	struct sockaddr_in to_sock;
-#endif
-
 
 
 	/* drop local ACKs */
 	/* drop local ACKs */
 	if (T->uas.status/100!=2 ) {
 	if (T->uas.status/100!=2 ) {
@@ -272,21 +336,9 @@ int t_forward_ack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
 	SEND_PR_BUFFER( &(T->uac[branch].request), ack, len );
 	SEND_PR_BUFFER( &(T->uac[branch].request), ack, len );
 	callback_event( TMCB_E2EACK, p_msg );
 	callback_event( TMCB_E2EACK, p_msg );
 	return attach_ack( T, branch, ack , len );
 	return attach_ack( T, branch, ack , len );
+}
 
 
-#ifdef _DON_USE
-fwd_sl: /* some strange conditions occured; try statelessly */
-	LOG(L_ERR, "ERROR: fwd-ing a 2xx ACK with T-state failed; "
-		"trying statelessly\n");
-	memset( &to_sock, sizeof to_sock, 0 );
-	to_sock.sin_family = AF_INET;
-	to_sock.sin_port =  dest_port_param;
-	to_sock.sin_addr.s_addr = dest_ip_param;
-	udp_send( buf, len, (struct sockaddr*)(&to_sock), 
-		sizeof(struct sockaddr_in) );
-	free( buf );
-	return 1;
 #endif
 #endif
-}
 
 
 
 
 
 
@@ -298,6 +350,8 @@ int forward_serial_branch(struct cell* Trans,int branch)
 	unsigned int     len;
 	unsigned int     len;
 	char             *buf=0, *shbuf=0;
 	char             *buf=0, *shbuf=0;
 	str              backup_uri;
 	str              backup_uri;
+	union sockaddr_union *to;
+	struct socket_info* send_sock;
 
 
 	backup_uri.s = p_msg->new_uri.s;
 	backup_uri.s = p_msg->new_uri.s;
 	backup_uri.len = p_msg->new_uri.len;
 	backup_uri.len = p_msg->new_uri.len;
@@ -324,7 +378,16 @@ int forward_serial_branch(struct cell* Trans,int branch)
 	/* updates the new uri*/
 	/* updates the new uri*/
 	p_msg->new_uri.s = Trans->uac[branch].uri.s;
 	p_msg->new_uri.s = Trans->uac[branch].uri.s;
 	p_msg->new_uri.len = Trans->uac[branch].uri.len;
 	p_msg->new_uri.len = Trans->uac[branch].uri.len;
-	if ( !(buf = build_req_buf_from_sip_req  ( p_msg, &len)))
+
+	to=&Trans->uac[branch].request.to;
+	send_sock=get_send_socket(to);
+	if (send_sock==0) {
+		LOG(L_ERR, "ERROR: t_forward_nonack: can't fwd to af %d "
+		"no corresponding listening socket\n", to->s.sa_family );
+		ser_error=E_NO_SOCKET;
+		goto error;
+	}
+	if ( !(buf = build_req_buf_from_sip_req  ( p_msg, &len, send_sock )))
 		goto error;
 		goto error;
 	shm_free(Trans->uac[branch].uri.s);
 	shm_free(Trans->uac[branch].uri.s);
 
 
@@ -345,7 +408,7 @@ int forward_serial_branch(struct cell* Trans,int branch)
 		:(p_msg->first_line.u.request.uri.len);
 		:(p_msg->first_line.u.request.uri.len);
 	Trans->nr_of_outgoings++ ;
 	Trans->nr_of_outgoings++ ;
 	/* send the request */
 	/* send the request */
-	Trans->uac[branch].request.to.sin_family = AF_INET;
+	/* -v6; -jiri Trans->uac[branch].request.to.sin_family = AF_INET; */
 	SEND_BUFFER( &(T->uac[branch].request) );
 	SEND_BUFFER( &(T->uac[branch].request) );
 
 
 	pkg_free( buf ) ;
 	pkg_free( buf ) ;

+ 1 - 1
modules/tm/t_hooks.h

@@ -8,7 +8,7 @@
 #include "h_table.h"
 #include "h_table.h"
 #include "t_funcs.h"
 #include "t_funcs.h"
 
 
-typedef enum { TMCB_REPLY,  TMCB_E2EACK, TMCB_END } tmcb_type;
+typedef enum { TMCB_REPLY,  TMCB_E2EACK, TMCB_REPLY_IN, TMCB_REQUEST_OUT, TMCB_END } tmcb_type;
 
 
 typedef void (transaction_cb) ( struct cell* t, struct sip_msg* msg );
 typedef void (transaction_cb) ( struct cell* t, struct sip_msg* msg );
 
 

+ 218 - 1
modules/tm/t_lookup.c

@@ -37,6 +37,7 @@
 #include "t_funcs.h"
 #include "t_funcs.h"
 #include "config.h"
 #include "config.h"
 #include "sip_msg.h"
 #include "sip_msg.h"
+#include "t_hooks.h"
 
 
 
 
 #define EQ_LEN(_hf) (t_msg->_hf->body.len==p_msg->_hf->body.len)
 #define EQ_LEN(_hf) (t_msg->_hf->body.len==p_msg->_hf->body.len)
@@ -60,6 +61,144 @@
 	)==0 )
 	)==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;
+
+	/* parse all*/
+	if (check_transaction_quadruple(p_msg)==0)
+	{
+		LOG(L_ERR, "ERROR: TM module: t_lookup_request: too few headers\n");
+		T=0;
+		/* stop processing */
+		return 0;
+	}
+
+	/* start searching into the table */
+	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;
+
+	/* lock the hole entry*/
+	lock(&(hash_table->entrys[p_msg->hash_index].mutex));
+
+	/* all the transactions from the entry are compared */
+	for ( p_cell = hash_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 (!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 (!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;
+
+			/* 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 and ... */
+			if (get_to(t_msg)->uri.len!=get_to(p_msg)->uri.len)
+				continue;
+			/* ... its to-tag compared to reply's tag */
+			if (p_cell->uas.tag->len!=get_to(p_msg)->tag_value.len)
+				continue;
+
+			/* we first skip r-uri and Via and proceed with
+			   content of other header-fields */
+
+			if ( memcmp(t_msg->callid->body.s, p_msg->callid->body.s,
+				p_msg->callid->body.len)!=0) continue;
+			if ( memcmp(get_cseq(t_msg)->number.s, get_cseq(p_msg)->number.s,
+				get_cseq(p_msg)->number.len)!=0) continue;
+			if (!EQ_STR(from)) continue;
+			if (memcmp(get_to(t_msg)->uri.s, get_to(p_msg)->uri.s,
+				get_to(t_msg)->uri.len)!=0) continue;
+			if (memcmp(p_cell->uas.tag->s, get_to(p_msg)->tag_value.s,
+				p_cell->uas.tag->len)!=0) continue;
+	
+			/* ok, now only r-uri or via can mismatch; they must match
+			   for non-2xx; if it is a 2xx, we don't try to match
+			   (we might have checked that earlier to speed-up, but
+			   we still want to see a diagnosti message telling
+			   "this ACK presumably belongs to this 2xx transaction";
+			   might change in future); the reason is 2xx ACKs are
+			   a separate transaction which may carry different
+			   r-uri/via1 and is thus also impossible to match it
+			   uniquely to a spiraled transaction;
+			*/
+			if (p_cell->uas.status>=200 && p_cell->uas.status<300) {
+				DBG("DEBUG: an ACK hit a 2xx transaction (T=%p); "
+					"considered mismatch\n", p_cell );
+				/* perhaps there are some spirals on the synonym list, but
+				   it makes no sense to iterate the list until bitter end */
+				ret=-2;
+				break;
+			}
+			/* its for a >= 300 ... everything must match ! */
+			if (! EQ_REQ_URI_LEN ) continue;
+			if (! EQ_VIA_LEN(via1)) continue;
+			if (!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 */
+
+	/* no transaction found */
+	T = 0;
+	if (!leave_new_locked)
+		unlock(&(hash_table->entrys[p_msg->hash_index].mutex));
+	DBG("DEBUG: t_lookup_request: no transaction found\n");
+	return ret;
+
+found:
+	T=p_cell;
+	T_REF( T );
+	DBG("DEBUG: t_lookup_request: transaction found (T=%p , ref=%x)\n",
+		T,T->ref_bitmap);
+	unlock(&(hash_table->entrys[p_msg->hash_index].mutex));
+	return 1;
+}
+
+
+#ifdef __YOU_DONT_WANT_TO_DO_THIS
 
 
 /* function returns:
 /* function returns:
  *      -1 - transaction wasn't found
  *      -1 - transaction wasn't found
@@ -213,6 +352,7 @@ found:
 	return 1;
 	return 1;
 }
 }
 
 
+#endif
 
 
 
 
 
 
@@ -560,7 +700,7 @@ int add_branch_label( struct cell *trans, struct sip_msg *p_msg, int branch )
 }
 }
 
 
 
 
-
+#ifdef _YOU_DONT_REALLY_WANT_THIS
 
 
 /* atomic "add_if_new" construct; it returns:
 /* atomic "add_if_new" construct; it returns:
 	AIN_ERROR	if a fatal error (e.g, parsing) occured
 	AIN_ERROR	if a fatal error (e.g, parsing) occured
@@ -635,4 +775,81 @@ enum addifnew_status t_addifnew( struct sip_msg* p_msg )
 }
 }
 
 
 
 
+#endif
+
+
+/* atomic "new_tran" construct; it returns:
+
+	-1	if	a request matched a transaction
+		- if that was an ack, the calling function
+		  shall reset timers
+		- otherwise the calling function shall 
+		  attempt to retransmit
+
+	+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 error
+*/
+int t_newtran( struct sip_msg* p_msg )
+{
+
+	int ret, lret;
+	struct cell *new_cell;
+
+	/* 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 ( !(p_msg->id != global_msg_id || T==T_UNDEFINED 
+		/* if someone tried to do something previously by mistake with
+		   a transaction which did not exist yet, try to look-up
+		   the transacion too */
+		|| T==T_NULL)) 
+	{
+		LOG(L_ERR, "ERROR: t_newtran: alreaddy processing this message"
+			", T %s found\n", T ? "" : "not" );
+		return 0;
+	}
+
+	global_msg_id = p_msg->id;
+	T = T_UNDEFINED;
+	/* transaction lookup */
+	/* force parsing all the needed headers*/
+	if (parse_headers(p_msg, HDR_EOH )==-1)
+		return 0;
+	lret = t_lookup_request( p_msg, 1 /* leave locked */ );
+	/* on error, pass the error in the stack ... */
+	if (lret==0) return 0;
+	if (lret<0) {
+		/* transaction not found, it's a new request;
+		   establish a new transaction (unless it is an ACK) */
+		ret=1;
+		if ( p_msg->REQ_METHOD!=METHOD_ACK ) {
+			/* add new transaction */
+			new_cell = build_cell( p_msg ) ;
+			if  ( !new_cell ){
+				LOG(L_ERR, "ERROR: t_addifnew: out of mem:\n");
+				ret = 0;
+			} else {
+				insert_into_hash_table_unsafe( hash_table , new_cell );
+				T=new_cell;
+				T_REF(T);
+			}
+		}
+		unlock(&(hash_table->entrys[p_msg->hash_index].mutex));
+		/* it that was a presumable e2e ACK, run a callback */
+		if (lret==-2) callback_event( TMCB_E2EACK, p_msg );
+		return ret;
+	} else {
+		/* transaction found, it's a retransmission  or ACK */
+			return -1;
+	}
+}
+
+
 
 

+ 295 - 0
modules/tm/t_msgbuilder.c

@@ -0,0 +1,295 @@
+/*
+ * $Id$
+ *
+ * message printing
+ */
+
+#include "hash_func.h"
+#include "t_funcs.h"
+#include "../../dprint.h"
+#include "../../config.h"
+#include "../../parser/parser_f.h"
+#include "../../ut.h"
+#include "../../parser/msg_parser.h"
+
+
+
+#define  append_mem_block(_d,_s,_len) \
+		do{\
+			memcpy((_d),(_s),(_len));\
+			(_d) += (_len);\
+		}while(0);
+
+
+/* Builds a CANCEL request based on an INVITE request. CANCEL is send
+ * to same address as the INVITE */
+int t_build_and_send_CANCEL(struct cell *Trans,unsigned int branch)
+{
+	struct sip_msg      *p_msg;
+	struct hdr_field    *hdr;
+	char                *cancel_buf, *p, *via;
+	unsigned int         len, via_len;
+
+	if ( !Trans->uac[branch].rpl_received )
+	{
+		DBG("DEBUG: t_build_and_send_CANCEL: no response ever received"
+			" : dropping local cancel! \n");
+		return 1;
+	}
+
+	if (Trans->uac[branch].request.cancel!=NO_CANCEL)
+	{
+		DBG("DEBUG: t_build_and_send_CANCEL: branch (%d)was already canceled"
+			" : dropping local cancel! \n",branch);
+		return 1;
+	}
+
+	cancel_buf = 0;
+	via = 0;
+	p_msg = Trans->uas.request;
+
+	len = 0;
+	/*first line's len - CANCEL and INVITE has the same lenght */
+	len += ( REQ_LINE(p_msg).version.s+REQ_LINE(p_msg).version.len)-
+		REQ_LINE(p_msg).method.s+CRLF_LEN;
+	/*check if the REQ URI was override */
+	if (Trans->uac[branch].uri.s)
+		len += Trans->uac[branch].uri.len - REQ_LINE(p_msg).uri.len;
+	/*via*/
+	if ( add_branch_label(Trans,p_msg,branch)==-1 )
+		goto error;
+	via = via_builder(p_msg , &via_len, Trans->uac[branch].request.send_sock );
+	if (!via)
+	{
+		LOG(L_ERR, "ERROR: t_build_and_send_CANCEL: "
+			"no via header got from builder\n");
+		goto error;
+	}
+	len+= via_len;
+	/*headers*/
+	for ( hdr=p_msg->headers ; hdr ; hdr=hdr->next )
+		if (hdr->type==HDR_FROM || hdr->type==HDR_CALLID || 
+			hdr->type==HDR_CSEQ || hdr->type==HDR_TO )
+			len += ((hdr->body.s+hdr->body.len ) - hdr->name.s ) + CRLF_LEN ;
+	/* User Agent header*/
+	len += USER_AGENT_LEN + CRLF_LEN;
+	/* Content Lenght heder*/
+	len += CONTENT_LEN_LEN + CRLF_LEN;
+	/* end of message */
+	len += CRLF_LEN;
+
+	cancel_buf=sh_malloc( len+1 );
+	if (!cancel_buf)
+	{
+		LOG(L_ERR, "ERROR: t_build_and_send_CANCEL: cannot allocate memory\n");
+		goto error;
+	}
+	p = cancel_buf;
+
+	/* first line -> do we have a new URI? */
+	if (Trans->uac[branch].uri.s)
+	{
+		append_mem_block(p,REQ_LINE(p_msg).method.s,
+			REQ_LINE(p_msg).uri.s-REQ_LINE(p_msg).method.s);
+		append_mem_block(p,Trans->uac[branch].uri.s,
+			Trans->uac[branch].uri.len);
+		append_mem_block(p,REQ_LINE(p_msg).uri.s+REQ_LINE(p_msg).uri.len,
+			REQ_LINE(p_msg).version.s+REQ_LINE(p_msg).version.len-
+			(REQ_LINE(p_msg).uri.s+REQ_LINE(p_msg).uri.len))
+	}else{
+		append_mem_block(p,REQ_LINE(p_msg).method.s,
+			REQ_LINE(p_msg).version.s+REQ_LINE(p_msg).version.len-
+			REQ_LINE(p_msg).method.s);
+	}
+	/* changhing method name*/
+	memcpy(cancel_buf, CANCEL , CANCEL_LEN );
+	append_mem_block(p,CRLF,CRLF_LEN);
+	/* insert our via */
+	append_mem_block(p,via,via_len);
+
+	/*other headers*/
+	for ( hdr=p_msg->headers ; hdr ; hdr=hdr->next )
+	{
+		if(hdr->type==HDR_FROM||hdr->type==HDR_CALLID||hdr->type==HDR_TO)
+		{
+			append_mem_block(p,hdr->name.s,
+				((hdr->body.s+hdr->body.len)-hdr->name.s) );
+			append_mem_block(p, CRLF, CRLF_LEN );
+		}else if ( hdr->type==HDR_CSEQ )
+		{
+			append_mem_block(p,hdr->name.s,
+				((((struct cseq_body*)hdr->parsed)->method.s)-hdr->name.s));
+			append_mem_block(p, CANCEL CRLF, CANCEL_LEN +CRLF_LEN );
+		}
+}
+
+	/* User Agent header */
+	append_mem_block(p,USER_AGENT,USER_AGENT_LEN);
+	append_mem_block(p,CRLF,CRLF_LEN);
+	/* Content Lenght header*/
+	append_mem_block(p,CONTENT_LEN,CONTENT_LEN_LEN);
+	append_mem_block(p,CRLF,CRLF_LEN);
+	/* end of message */
+	append_mem_block(p,CRLF,CRLF_LEN);
+	*p=0;
+
+	if (Trans->uac[branch].request.cancel) {
+		shm_free( cancel_buf );
+		LOG(L_WARN, "send_cancel: Warning: CANCEL already sent out\n");
+		goto error;
+	}
+
+	Trans->uac[branch].request.activ_type = TYPE_LOCAL_CANCEL;
+	Trans->uac[branch].request.cancel = cancel_buf;
+	Trans->uac[branch].request.cancel_len = len;
+
+	/*sets and starts the FINAL RESPONSE timer */
+	set_timer(hash_table,&(Trans->uac[branch].request.fr_timer),FR_TIMER_LIST);
+	/* sets and starts the RETRANS timer */
+	Trans->uac[branch].request.retr_list = RT_T1_TO_1;
+	set_timer(hash_table,&(Trans->uac[branch].request.retr_timer),RT_T1_TO_1);
+	DBG("DEBUG: T_build_and_send_CANCEL : sending cancel...\n");
+	SEND_CANCEL_BUFFER( &(Trans->uac[branch].request) );
+
+	pkg_free(via);
+	return 1;
+error:
+	if (via) pkg_free(via);
+	return -1;
+}
+
+
+/* Builds an ACK request based on an INVITE request. ACK is send
+ * to same address */
+char *build_ack(struct sip_msg* rpl,struct cell *trans,int branch,int *ret_len)
+{
+	struct sip_msg      *p_msg , *r_msg;
+	struct hdr_field    *hdr;
+	char                *ack_buf, *p, *via;
+	unsigned int         len, via_len;
+
+	ack_buf = 0;
+	via =0;
+	p_msg = trans->uas.request;
+	r_msg = rpl;
+
+	if ( parse_headers(rpl,HDR_TO)==-1 || !rpl->to )
+	{
+		LOG(L_ERR, "ERROR: t_build_ACK: "
+			"cannot generate a HBH ACK if key HFs in reply missing\n");
+		goto error;
+	}
+
+	len = 0;
+	/*first line's len */
+	len += 4/*reply code and one space*/+
+		p_msg->first_line.u.request.version.len+CRLF_LEN;
+	/*uri's len*/
+	if (trans->uac[branch].uri.s)
+		len += trans->uac[branch].uri.len +1;
+	else
+		len += p_msg->first_line.u.request.uri.len +1;
+	/*adding branch param*/
+	if ( add_branch_label( trans , trans->uas.request , branch)==-1 )
+		goto error;
+	/*via*/
+	via = via_builder(p_msg , &via_len, trans->uac[branch].request.send_sock );
+	if (!via)
+	{
+		LOG(L_ERR, "ERROR: t_build_ACK: "
+			"no via header got from builder\n");
+		goto error;
+	}
+	len+= via_len;
+	/*headers*/
+	for ( hdr=p_msg->headers ; hdr ; hdr=hdr->next )
+		if (hdr->type==HDR_FROM||hdr->type==HDR_CALLID||hdr->type==HDR_CSEQ)
+			len += ((hdr->body.s+hdr->body.len ) - hdr->name.s ) + CRLF_LEN ;
+		else if ( hdr->type==HDR_TO )
+			len += ((r_msg->to->body.s+r_msg->to->body.len ) -
+				r_msg->to->name.s ) + CRLF_LEN ;
+	/* CSEQ method : from INVITE-> ACK */
+	len -= 3  ;
+	/* end of message */
+	len += CRLF_LEN; /*new line*/
+
+	ack_buf = sh_malloc(len+1);
+	if (!ack_buf)
+	{
+		LOG(L_ERR, "ERROR: t_build_and_ACK: cannot allocate memory\n");
+		goto error1;
+	}
+	p = ack_buf;
+
+	/* first line */
+	memcpy( p , "ACK " , 4);
+	p += 4;
+	/* uri */
+	if ( trans->uac[branch].uri.s )
+	{
+		memcpy(p,trans->uac[branch].uri.s,trans->uac[branch].uri.len);
+		p +=trans->uac[branch].uri.len;
+	}else{
+		memcpy(p,p_msg->orig+(p_msg->first_line.u.request.uri.s-p_msg->buf),
+			p_msg->first_line.u.request.uri.len );
+		p += p_msg->first_line.u.request.uri.len;
+	}
+	/* SIP version */
+	*(p++) = ' ';
+	memcpy(p,p_msg->orig+(p_msg->first_line.u.request.version.s-p_msg->buf),
+		p_msg->first_line.u.request.version.len );
+	p += p_msg->first_line.u.request.version.len;
+	memcpy( p, CRLF, CRLF_LEN );
+	p+=CRLF_LEN;
+
+	/* insert our via */
+	memcpy( p , via , via_len );
+	p += via_len;
+
+	/*other headers*/
+	for ( hdr=p_msg->headers ; hdr ; hdr=hdr->next )
+	{
+		if ( hdr->type==HDR_FROM || hdr->type==HDR_CALLID  )
+		{
+			memcpy( p , p_msg->orig+(hdr->name.s-p_msg->buf) ,
+				((hdr->body.s+hdr->body.len ) - hdr->name.s ) );
+			p += ((hdr->body.s+hdr->body.len ) - hdr->name.s );
+			memcpy( p, CRLF, CRLF_LEN );
+			p+=CRLF_LEN;
+		}
+		else if ( hdr->type==HDR_TO )
+		{
+			memcpy( p , r_msg->orig+(r_msg->to->name.s-r_msg->buf) ,
+				((r_msg->to->body.s+r_msg->to->body.len)-r_msg->to->name.s));
+			p+=((r_msg->to->body.s+r_msg->to->body.len)-r_msg->to->name.s);
+			memcpy( p, CRLF, CRLF_LEN );
+			p+=CRLF_LEN;
+		}
+		else if ( hdr->type==HDR_CSEQ )
+		{
+			memcpy( p , p_msg->orig+(hdr->name.s-p_msg->buf) ,
+				((((struct cseq_body*)hdr->parsed)->method.s)-hdr->name.s));
+			p+=((((struct cseq_body*)hdr->parsed)->method.s)-hdr->name.s);
+			memcpy( p , "ACK" CRLF, 3+CRLF_LEN );
+			p += 3+CRLF_LEN;
+		}
+	}
+
+	/* end of message */
+	memcpy( p , CRLF , CRLF_LEN );
+	p += CRLF_LEN;
+
+	pkg_free( via );
+	DBG("DEBUG: t_build_ACK: ACK generated\n");
+
+	*(ret_len) = p-ack_buf;
+	return ack_buf;
+
+error1:
+	pkg_free(via );
+error:
+	return 0;
+}
+
+
+

+ 125 - 9
modules/tm/t_reply.c

@@ -19,7 +19,7 @@
 
 
 inline int check_for_no_response( struct cell *Trans ,int code, int relay)
 inline int check_for_no_response( struct cell *Trans ,int code, int relay)
 {
 {
-	if ( code/100>3 && Trans->uac[Trans->nr_of_outgoings].uri.s )
+	if ( code/100>=3 && Trans->uac[Trans->nr_of_outgoings].uri.s )
 	{
 	{
 		forward_serial_branch( Trans , Trans->nr_of_outgoings );
 		forward_serial_branch( Trans , Trans->nr_of_outgoings );
 		return -1;
 		return -1;
@@ -59,16 +59,17 @@ int t_retransmit_reply( /* struct sip_msg* p_msg    */ )
 /* Force a new response into inbound response buffer.
 /* Force a new response into inbound response buffer.
   * returns 1 if everything was OK or -1 for error
   * returns 1 if everything was OK or -1 for error
   */
   */
-int t_send_reply( struct sip_msg* p_msg, unsigned int code, char * text,
-														unsigned int branch)
+int t_send_reply( struct sip_msg* p_msg, unsigned int code, 
+	char * text, unsigned int branch)
 {
 {
 	unsigned int len, buf_len=0;
 	unsigned int len, buf_len=0;
 	char * buf;
 	char * buf;
 	struct retr_buf *rb;
 	struct retr_buf *rb;
 	int relay, save_clone;
 	int relay, save_clone;
+	struct socket_info* send_sock;
 
 
-	buf = build_res_buf_from_sip_req(code,text,T->uas.tag->s,T->uas.tag->len,
-		T->uas.request,&len);
+	buf = build_res_buf_from_sip_req(code,text,T->uas.tag->s,
+		T->uas.tag->len, T->uas.request,&len);
 	DBG("DEBUG: t_send_reply: buffer computed\n");
 	DBG("DEBUG: t_send_reply: buffer computed\n");
 	if (!buf)
 	if (!buf)
 	{
 	{
@@ -96,7 +97,15 @@ int t_send_reply( struct sip_msg* p_msg, unsigned int code, char * text,
 					p_msg->via1->host.s );
 					p_msg->via1->host.s );
 				goto error2;
 				goto error2;
 			}
 			}
-			rb->to.sin_family = AF_INET;
+			send_sock=get_send_socket(&rb->to);
+			if (send_sock==0) {
+				LOG(L_ERR, "ERROR: t_send_reply: cannot fwd to af %d "
+					"no socket\n", rb->to.s.sa_family);
+				ser_error=E_NO_SOCKET;
+				goto error2;
+			}
+			rb->send_sock=send_sock;
+			/* rb->to.sin_family = AF_INET; */
 			rb->activ_type = code;
 			rb->activ_type = code;
 			buf_len = len + REPLY_OVERBUFFER_LEN;
 			buf_len = len + REPLY_OVERBUFFER_LEN;
 		}else{
 		}else{
@@ -195,7 +204,6 @@ error:
 #endif
 #endif
 
 
 
 
-
 /*  This function is called whenever a reply for our module is received; 
 /*  This function is called whenever a reply for our module is received; 
   * we need to register  this function on module initialization;
   * we need to register  this function on module initialization;
   *  Returns :   0 - core router stops
   *  Returns :   0 - core router stops
@@ -216,6 +224,7 @@ int t_on_reply( struct sip_msg  *p_msg )
 	/* buffer length (might be somewhat larger than message size */
 	/* buffer length (might be somewhat larger than message size */
 	unsigned int alloc_len;
 	unsigned int alloc_len;
 	str *str_foo;
 	str *str_foo;
+	struct socket_info* send_sock;
 
 
 
 
 	/* make sure we know the assosociated tranaction ... */
 	/* make sure we know the assosociated tranaction ... */
@@ -247,7 +256,8 @@ int t_on_reply( struct sip_msg  *p_msg )
 	msg_class=REPLY_CLASS(p_msg);
 	msg_class=REPLY_CLASS(p_msg);
 	is_invite= T->uas.request->REQ_METHOD==METHOD_INVITE;
 	is_invite= T->uas.request->REQ_METHOD==METHOD_INVITE;
 
 
-	/*  generate the retrans buffer, make a simplified
+#ifdef _DONT_DO_IT_MAN
+/*  generate the retrans buffer, make a simplified
 	assumption everything but 100 will be fwd-ed;
 	assumption everything but 100 will be fwd-ed;
 	sometimes it will result in useless CPU cycles
 	sometimes it will result in useless CPU cycles
 	but mostly the assumption holds and allows the
 	but mostly the assumption holds and allows the
@@ -263,6 +273,7 @@ int t_on_reply( struct sip_msg  *p_msg )
 			goto error;
 			goto error;
 		}
 		}
 	}
 	}
+#endif
 
 
 	/* *** stop timers *** */
 	/* *** stop timers *** */
 	/* stop retransmission */
 	/* stop retransmission */
@@ -317,6 +328,17 @@ int t_on_reply( struct sip_msg  *p_msg )
 
 
 	rb = & T->uas.response;
 	rb = & T->uas.response;
 	if (relay >= 0  && (relay=check_for_no_response(T,msg_status,relay))>=0 ) {
 	if (relay >= 0  && (relay=check_for_no_response(T,msg_status,relay))>=0 ) {
+
+		buf = build_res_buf_from_sip_res ( p_msg, &res_len);
+		if (!buf) {
+			UNLOCK_REPLIES( T );
+			start_fr = 1;
+			LOG(L_ERR, "ERROR: t_on_reply_received: "
+				"no mem for outbound reply buffer\n");
+			goto error1;
+		}
+		callback_event( TMCB_REPLY_IN, p_msg );
+
 		if (relay!=branch)
 		if (relay!=branch)
 		{
 		{
 			str_foo = &(T->uac[relay].rpl_buffer);
 			str_foo = &(T->uac[relay].rpl_buffer);
@@ -342,7 +364,16 @@ int t_on_reply( struct sip_msg  *p_msg )
 					p_msg->via2->host.s );
 					p_msg->via2->host.s );
 				goto error1;
 				goto error1;
 			}
 			}
-			rb->to.sin_family = AF_INET;
+			send_sock=get_send_socket(&rb->to);
+			if (send_sock==0) {
+				UNLOCK_REPLIES( T );
+				LOG(L_ERR, "ERROR: t_on_reply: cannot fwd to af %d "
+					"no socket\n", rb->to.s.sa_family);
+				start_fr=1;
+				goto error1;
+			}
+			/* rb->to.sin_family = AF_INET; */
+			rb->send_sock=send_sock;
 			rb->activ_type = p_msg->REPLY_STATUS;
 			rb->activ_type = p_msg->REPLY_STATUS;
 			/* allocate something more for the first message;
 			/* allocate something more for the first message;
 			   subsequent messages will be longer and buffer
 			   subsequent messages will be longer and buffer
@@ -419,3 +450,88 @@ error:
 	return 0;
 	return 0;
 }
 }
 
 
+
+/* Checks if the new reply (with new_code status) should be sent or not
+ *  based on the current
+ * transactin status.
+ * Returns 	- branch number (0,1,...) which should be relayed
+ *         -1 if nothing to be relayed
+ */
+int t_should_relay_response( struct cell *Trans , int new_code,
+									int branch , int *should_store )
+{
+	//int T_code;
+	int b, lowest_b, lowest_s;
+
+	//if (Trans->uas.request->REQ_METHOD==METHOD_INVITE)
+	//	T_code = Trans->uac[branch].status;
+	//else
+	//T_code = Trans->uas.status;
+
+	/* note: this code never lets replies to CANCEL go through;
+	   we generate always a local 200 for CANCEL; 200s are
+	   not relayed because it's not an INVITE transaction;
+	   >= 300 are not relayed because 200 was already sent
+	   out
+	*/
+	DBG("->>>>>>>>> T_code=%d, new_code=%d\n",Trans->uas.status,new_code);
+	/* if final response sent out, allow only INVITE 2xx  */
+	if ( Trans->uas.status >= 200 ) {
+		if (new_code>=200 && new_code < 300  && 
+			Trans->uas.request->REQ_METHOD==METHOD_INVITE) {
+			DBG("DBG: t_should_relay: 200 INV after final sent\n");
+			*should_store=1;
+			return branch;
+		} else {
+			*should_store=0;
+			return -1;
+		}
+	} else { /* no final response sent yet */
+		/* negative replies subject to fork picking */
+		if (new_code >=300 ) {
+			/* dirty hack by Jiri -- subject to clean up as all the
+			   reply_processing crap; if there are no branches at
+			   all, I guess TM wants to reply itself and allow that
+			*/
+			if (Trans->nr_of_outgoings==0)
+				return 0;
+			*should_store=1;
+			/* if all_final return lowest */
+			lowest_b=-1; lowest_s=999;
+			for ( b=0; b<Trans->nr_of_outgoings ; b++ ) {
+				/* "fake" for the currently processed branch */
+				if (b==branch) {
+					if (new_code<lowest_s) {
+						lowest_b=b;
+						lowest_s=new_code;
+					}
+					continue;
+				}
+				/* there is still an unfinished UAC transaction; wait now! */
+				if ( Trans->uac[b].status<200 )
+					return -1;
+				if ( Trans->uac[b].status<lowest_s )
+				{
+					lowest_b =b;
+					lowest_s = T->uac[b].status;
+				}
+			}
+			return lowest_b;
+		/* 1xx except 100 and 2xx will be relayed */
+		} else if (new_code>100) {
+			*should_store=1;
+			return branch;
+		}
+		/* 100 won't be relayed */
+		else {
+			if (!T->uac[branch].rpl_received) *should_store=1;
+				else *should_store=0;
+			if (Trans->uas.status==0) return branch;
+				else return -1;
+		}
+	}
+
+	LOG(L_CRIT, "ERROR: Oh my gooosh! We don't know whether to relay\n");
+	abort();
+}
+

+ 220 - 0
modules/tm/t_thandlers.c

@@ -0,0 +1,220 @@
+/*
+ * $Id$
+ *
+ * Timer handlers
+ */
+
+#include "hash_func.h"
+#include "t_funcs.h"
+#include "../../dprint.h"
+#include "../../config.h"
+#include "../../parser/parser_f.h"
+#include "../../ut.h"
+//#include "../../timer.h"
+
+
+
+
+
+inline void retransmission_handler( void *attr)
+{
+	struct retr_buf* r_buf ;
+	enum lists id;
+
+	r_buf = (struct retr_buf*)attr;
+#ifdef EXTRA_DEBUG
+	if (r_buf->my_T->damocles) {
+		LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and"
+			" called from RETR timer\n",r_buf->my_T);
+		abort();
+	}	
+#endif
+
+	/*the transaction is already removed from RETRANSMISSION_LIST by timer*/
+	/* retransmision */
+	DBG("DEBUG: retransmission_handler : resending (t=%p)\n", r_buf->my_T);
+	switch ( r_buf->activ_type )
+	{
+		case (TYPE_REQUEST):
+			SEND_BUFFER( r_buf );
+			break;
+		case (TYPE_LOCAL_CANCEL):
+			SEND_CANCEL_BUFFER( r_buf );
+			break;
+		default:
+			T=r_buf->my_T;
+			t_retransmit_reply();
+	}
+
+	id = r_buf->retr_list;
+	r_buf->retr_list = id < RT_T2 ? id + 1 : RT_T2;
+
+	set_timer(hash_table,&(r_buf->retr_timer),id < RT_T2 ? id + 1 : RT_T2 );
+
+	DBG("DEBUG: retransmission_handler : done\n");
+}
+
+
+
+
+inline void final_response_handler( void *attr)
+{
+	struct retr_buf* r_buf = (struct retr_buf*)attr;
+
+#ifdef EXTRA_DEBUG
+	if (r_buf->my_T->damocles) 
+	{
+		LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and"
+			" called from FR timer\n",r_buf->my_T);
+		abort();
+	}
+#endif
+
+	/* the transaction is already removed from FR_LIST by the timer */
+	if (r_buf->activ_type==TYPE_LOCAL_CANCEL)
+	{
+		DBG("DEBUG: FR_handler: stop retransmission for Local Cancel\n");
+		reset_timer( hash_table , &(r_buf->retr_timer) );
+		return;
+	}
+	/* send a 408 */
+	if ( r_buf->my_T->uac[r_buf->branch].status<200
+#ifdef SILENT_FR
+	&& (r_buf->my_T->nr_of_outgoings>1     /*if we have forked*/
+		|| r_buf->my_T->uas.request->first_line.u.request.method_value!=
+			METHOD_INVITE                  /*if is not an INVITE */
+		|| r_buf->my_T->uac[r_buf->my_T->nr_of_outgoings].uri.s
+		                                   /*if "no on no response" was set*/
+		|| r_buf->my_T->uac[r_buf->branch].rpl_received==0
+											/*if no reply was received*/
+	)
+#endif
+	)
+	{
+		DBG("DEBUG: FR_handler:stop retr. and send CANCEL (%p)\n",r_buf->my_T);
+		reset_timer( hash_table, &(r_buf->retr_timer) );
+		t_build_and_send_CANCEL( r_buf->my_T ,r_buf->branch);
+		/* dirty hack:t_send_reply would increase ref_count which would indeed
+		result in refcount++ which would not -- until timer processe's
+		T changes again; currently only on next call to t_send_reply from
+		FR timer; thus I fake the values now to avoid recalculating T
+		and refcount++ JKU */
+		T=r_buf->my_T;
+		global_msg_id=T->uas.request->id;
+		DBG("DEBUG: FR_handler: send 408 (%p)\n", r_buf->my_T);
+		t_send_reply( r_buf->my_T->uas.request, 408, "Request Timeout",
+			r_buf->branch);
+	}else{
+		/* put it on WT_LIST - transaction is over */
+		DBG("DEBUG: final_response_handler:-> put on wait"
+			" (t=%p)\n", r_buf->my_T);
+		t_put_on_wait(  r_buf->my_T );
+	}
+	DBG("DEBUG: final_response_handler : done\n");
+}
+
+
+
+
+inline void wait_handler( void *attr)
+{
+	struct cell *p_cell = (struct cell*)attr;
+
+#ifdef EXTRA_DEBUG
+	if (p_cell->damocles) {
+		LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and"
+			" called from WAIT timer\n",p_cell);
+		abort();
+	}	
+#endif
+
+	/* the transaction is already removed from WT_LIST by the timer */
+	/* the cell is removed from the hash table */
+	DBG("DEBUG: wait_handler : removing %p from table \n", p_cell );
+	remove_from_hash_table( hash_table, p_cell );
+	/* jku: no more here -- we do it when we put a transaction on wait */
+	DBG("DEBUG: wait_handler : stopping all timers\n");
+	reset_retr_timers(hash_table,p_cell) ; 
+	/* put it on DEL_LIST - sch for del */
+#ifdef EXTRA_DEBUG
+	p_cell->damocles = 1;
+#endif
+	delete_cell( p_cell );
+	DBG("DEBUG: wait_handler : done\n");
+}
+
+
+
+
+inline void delete_handler( void *attr)
+{
+	struct cell *p_cell = (struct cell*)attr;
+
+	DBG("DEBUG: delete_handler : removing %p \n", p_cell );
+#ifdef EXTRA_DEBUG
+	if (p_cell->damocles==0) {
+		LOG( L_ERR, "ERROR: transaction %p not scheduled for deletion"
+			" and called from DELETE timer\n",p_cell);
+		abort();
+	}	
+#endif
+	delete_cell( p_cell );
+    DBG("DEBUG: delete_handler : done\n");
+}
+
+
+
+
+#define run_handler_for_each( _tl , _handler ) \
+	while ((_tl))\
+	{\
+		/* reset the timer list linkage */\
+		tmp_tl = (_tl)->next_tl;\
+		(_tl)->next_tl = (_tl)->prev_tl = 0;\
+		DBG("DEBUG: timer routine:%d,tl=%p next=%p\n",\
+			id,(_tl),tmp_tl);\
+		(_handler)( (_tl)->payload );\
+		(_tl) = tmp_tl;\
+	}
+
+
+
+
+void timer_routine(unsigned int ticks , void * attr)
+{
+	struct s_table    *hash_table = (struct s_table *)attr;
+	struct timer_link *tl, *tmp_tl;
+	int                id;
+
+#ifdef BOGDAN_TRIFLE
+	DBG(" %d \n",ticks);
+#endif
+
+	for( id=0 ; id<NR_OF_TIMER_LISTS ; id++ )
+	{
+		/* to waste as little time in lock as possible, detach list
+		   with expired items and process them after leaving the lock */
+		tl=check_and_split_time_list( &(hash_table->timers[ id ]), ticks);
+		/* process items now */
+		switch (id)
+		{
+			case FR_TIMER_LIST:
+			case FR_INV_TIMER_LIST:
+				run_handler_for_each(tl,final_response_handler);
+				break;
+			case RT_T1_TO_1:
+			case RT_T1_TO_2:
+			case RT_T1_TO_3:
+			case RT_T2:
+				run_handler_for_each(tl,retransmission_handler);
+				break;
+			case WT_TIMER_LIST:
+				run_handler_for_each(tl,wait_handler);
+				break;
+			case DELETE_LIST:
+				run_handler_for_each(tl,delete_handler);
+				break;
+		}
+	}
+}
+

+ 37 - 0
modules/tm/test.c

@@ -0,0 +1,37 @@
+#include "hash_func.h"
+#include "t_funcs.h"
+#include "../../dprint.h"
+#include "../../config.h"
+#include "../../parser/parser_f.h"
+#include "../../ut.h"
+#include "../../timer.h"
+
+#include "t_hooks.h"
+
+int _test_insert_to_reply( struct sip_msg *msg, char *str )
+{
+    struct lump* anchor;
+    char *buf;
+    int len;
+
+    len=strlen( str );
+    buf=pkg_malloc( len );
+    if (!buf) {
+        LOG(L_ERR, "_test_insert_to_reply: no mem\n");
+        return 0;
+    }
+    memcpy( buf, str, len );
+
+    anchor = anchor_lump(&msg->add_rm,
+        msg->headers->name.s - msg->buf, 0 , 0);
+    if (anchor == NULL) {
+        LOG(L_ERR, "_test_insert_to_reply: anchor_lump failed\n");
+        return 0;
+    }
+    if (insert_new_lump_before(anchor,buf, len, 0)==0) {
+        LOG(L_ERR, "_test_insert_to_reply: inser_new_lump failed\n");
+        return 0;
+    }
+    return 1;
+}
+

+ 213 - 173
modules/tm/tm.c

@@ -19,27 +19,40 @@
 #include "t_funcs.h"
 #include "t_funcs.h"
 #include "t_hooks.h"
 #include "t_hooks.h"
 #include "tm_load.h"
 #include "tm_load.h"
+#include "t_fork.h"
+#include "ut.h"
 
 
 
 
 
 
-static int w_t_check(struct sip_msg* msg, char* str, char* str2);
-static int w_t_send_reply(struct sip_msg* msg, char* str, char* str2);
-static int w_t_release(struct sip_msg* msg, char* str, char* str2);
-static int fixup_t_forward(void** param, int param_no);
-static int fixup_t_send_reply(void** param, int param_no);
-static int w_t_unref( struct sip_msg* p_msg, char* foo, char* bar );
-static int w_t_retransmit_reply(struct sip_msg* p_msg, char* foo, char* bar );
-static int w_t_add_transaction(struct sip_msg* p_msg, char* foo, char* bar );
-static int t_relay_to( struct sip_msg *p_msg, char *str_ip, char *str_port);
-static int t_relay( struct sip_msg  *p_msg ,  char* foo, char* bar  );
-static int w_t_forward_ack(struct sip_msg* msg, char* str, char* str2);
-static int w_t_forward_nonack(struct sip_msg* msg, char* str, char* str2);
-static int w_t_add_fork_ip(struct sip_msg* msg, char* str, char* str2);
-static int w_t_add_fork_uri(struct sip_msg* msg, char* str, char* str2);
-static int fixup_t_add_fork_uri(void** param, int param_no);
-static int w_t_add_fork_on_no_rpl(struct sip_msg* msg,char* str,char* str2);
-static int w_t_clear_forks(struct sip_msg* msg, char* str, char* str2);
-static void w_onbreak(struct sip_msg* msg) { t_unref(); }
+inline static int w_t_check(struct sip_msg* msg, char* str, char* str2);
+inline static int w_t_send_reply(struct sip_msg* msg, char* str, char* str2);
+inline static int w_t_release(struct sip_msg* msg, char* str, char* str2);
+inline static int fixup_t_send_reply(void** param, int param_no);
+inline static int w_t_unref( struct sip_msg* p_msg, char* foo, char* bar );
+inline static int w_t_retransmit_reply(struct sip_msg* p_msg, char* foo, char* bar );
+/*
+inline static int w_t_add_transaction(struct sip_msg* p_msg, char* foo, char* bar );
+*/
+
+inline static int w_t_newtran(struct sip_msg* p_msg, char* foo, char* bar );
+
+inline static int t_relay( struct sip_msg  *p_msg ,  char* , char* );
+inline static int w_t_relay_to( struct sip_msg  *p_msg , char *proxy, char *);
+static int t_relay_to( struct sip_msg  *p_msg , struct proxy_l *proxy );
+/*
+inline static int w_t_forward_ack(struct sip_msg* msg, char* proxy, char* );
+*/
+inline static int w_t_forward_nonack(struct sip_msg* msg, char* str, char* );
+inline static int fixup_hostport2proxy(void** param, int param_no);
+
+inline static int w_t_add_fork_ip(struct sip_msg* msg, char* proxy, char* );
+inline static int w_t_add_fork_uri(struct sip_msg* msg, char* str, char* );
+inline static int w_t_add_fork_on_no_rpl(struct sip_msg* msg,char* str,char* );
+inline static int w_t_clear_forks(struct sip_msg* msg, char* , char* );
+
+inline static int fixup_uri2fork(void** param, int param_no);
+
+inline static void w_onbreak(struct sip_msg* msg) { t_unref(); }
 
 
 static int mod_init(void);
 static int mod_init(void);
 
 
@@ -51,7 +64,10 @@ struct module_exports exports= {
 	"tm",
 	"tm",
 	/* -------- exported functions ----------- */
 	/* -------- exported functions ----------- */
 	(char*[]){			
 	(char*[]){			
+/*		- obsoleted by atomic t_newtran 
 				"t_add_transaction",
 				"t_add_transaction",
+*/
+				"t_newtran",
 				"t_lookup_request",
 				"t_lookup_request",
 				"t_send_reply",
 				"t_send_reply",
 				"t_retransmit_reply",
 				"t_retransmit_reply",
@@ -60,7 +76,9 @@ struct module_exports exports= {
 				"t_relay_to",
 				"t_relay_to",
 				"t_relay",
 				"t_relay",
 				"t_forward_nonack",
 				"t_forward_nonack",
+/*
 				"t_forward_ack",
 				"t_forward_ack",
+*/
 				"t_fork_to_ip",
 				"t_fork_to_ip",
 				"t_fork_to_uri",
 				"t_fork_to_uri",
 				"t_clear_forks",
 				"t_clear_forks",
@@ -69,16 +87,20 @@ struct module_exports exports= {
 				"load_tm"
 				"load_tm"
 			},
 			},
 	(cmd_function[]){
 	(cmd_function[]){
+/*
 					w_t_add_transaction,
 					w_t_add_transaction,
+*/					w_t_newtran,
 					w_t_check,
 					w_t_check,
 					w_t_send_reply,
 					w_t_send_reply,
 					w_t_retransmit_reply,
 					w_t_retransmit_reply,
 					w_t_release,
 					w_t_release,
 					w_t_unref,
 					w_t_unref,
-					t_relay_to,
+					w_t_relay_to,
 					t_relay,
 					t_relay,
 					w_t_forward_nonack,
 					w_t_forward_nonack,
+/*
 					w_t_forward_ack,
 					w_t_forward_ack,
+*/
 					w_t_add_fork_ip,
 					w_t_add_fork_ip,
 					w_t_add_fork_uri,
 					w_t_add_fork_uri,
 					w_t_clear_forks,
 					w_t_clear_forks,
@@ -87,7 +109,7 @@ struct module_exports exports= {
 					(cmd_function) load_tm
 					(cmd_function) load_tm
 					},
 					},
 	(int[]){
 	(int[]){
-				0, /* t_add_transaction */
+				0, /* t_newtran */
 				0, /* t_lookup_request */
 				0, /* t_lookup_request */
 				2, /* t_send_reply */
 				2, /* t_send_reply */
 				0, /* t_retransmit_reply */
 				0, /* t_retransmit_reply */
@@ -96,7 +118,8 @@ struct module_exports exports= {
 				2, /* t_relay_to */
 				2, /* t_relay_to */
 				0, /* t_relay */
 				0, /* t_relay */
 				2, /* t_forward_nonack */
 				2, /* t_forward_nonack */
-				2, /* t_forward_ack */
+/* 				2,*/ /* t_forward_ack */
+
 				2, /* t_fork_to_ip */
 				2, /* t_fork_to_ip */
 				1, /* t_fork_to_uri */
 				1, /* t_fork_to_uri */
 				0, /* t_clear_forks */
 				0, /* t_clear_forks */
@@ -105,25 +128,25 @@ struct module_exports exports= {
 				1 /* load_tm */
 				1 /* load_tm */
 			},
 			},
 	(fixup_function[]){
 	(fixup_function[]){
-				0,						/* t_add_transaction */
+				0,						/* t_newtran */
 				0,						/* t_lookup_request */
 				0,						/* t_lookup_request */
 				fixup_t_send_reply,		/* t_send_reply */
 				fixup_t_send_reply,		/* t_send_reply */
 				0,						/* t_retransmit_reply */
 				0,						/* t_retransmit_reply */
 				0,						/* t_release */
 				0,						/* t_release */
 				0,						/* t_unref */
 				0,						/* t_unref */
-				fixup_t_forward,		/* t_relay_to */
+				fixup_hostport2proxy,	/* t_relay_to */
 				0,						/* t_relay */
 				0,						/* t_relay */
-				fixup_t_forward,		/* t_forward_nonack */
-				fixup_t_forward,		/* t_forward_ack */
-				fixup_t_forward,		/* t_fork_to_ip */
-				fixup_t_add_fork_uri,   /* t_fork_to_uri */
+				fixup_hostport2proxy,	/* t_forward_nonack */
+				/* fixup_hostport2proxy,	*/ /* t_forward_ack */
+				fixup_hostport2proxy,	/* t_fork_to_ip */
+				fixup_uri2fork,   		/* t_fork_to_uri */
 				0,						/* t_clear_forks */
 				0,						/* t_clear_forks */
-				fixup_t_add_fork_uri,	/* t_add_fork_on_no_response */
+				fixup_uri2fork,		/* t_add_fork_on_no_response */
 				0,						/* register_tmcb */
 				0,						/* register_tmcb */
 				0						/* load_tm */
 				0						/* load_tm */
 	
 	
 		},
 		},
-	16,
+	15,
 
 
 	/* ------------ exported variables ---------- */
 	/* ------------ exported variables ---------- */
 	(char *[]) { /* Module parameter names */
 	(char *[]) { /* Module parameter names */
@@ -176,60 +199,49 @@ static int mod_init(void)
 }
 }
 
 
 
 
+/* (char *hostname, char *port_nr) ==> (struct proxy_l *, -)  */
 
 
-
-static int fixup_t_forward(void** param, int param_no)
+inline static int fixup_hostport2proxy(void** param, int param_no)
 {
 {
-	char* name;
-	struct hostent* he;
 	unsigned int port;
 	unsigned int port;
+	char *host;
 	int err;
 	int err;
-#ifdef DNS_IP_HACK
-	unsigned int ip;
-	int len;
-#endif
-
+	struct proxy_l *proxy;
+	
 	DBG("TM module: fixup_t_forward(%s, %d)\n", (char*)*param, param_no);
 	DBG("TM module: fixup_t_forward(%s, %d)\n", (char*)*param, param_no);
 	if (param_no==1){
 	if (param_no==1){
-		name=*param;
-#ifdef DNS_IP_HACK
-		len=strlen(name);
-		ip=str2ip((unsigned char*)name, len, &err);
-		if (err==0){
-			goto copy;
+		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;
 		}
 		}
-#endif
-		/* fail over to normal lookup */
-		he=gethostbyname(name);
-		if (he==0){
-			LOG(L_CRIT, "ERROR: mk_proxy: could not resolve hostname:"
-						" \"%s\"\n", name);
+		proxy=mk_proxy(host, port);
+		if (proxy==0) {
+			LOG(L_ERR, "ERROR: fixup_t_forwardv6: bad host name in URI <%s>\n",
+				host );
 			return E_BAD_ADDRESS;
 			return E_BAD_ADDRESS;
 		}
 		}
-		memcpy(&ip, he->h_addr_list[0], sizeof(unsigned int));
-	copy:
-		free(*param);
-		*param=(void*)ip;
+		/* success -- fix the first parameter to proxy now ! */
+		free( *(param-1));
+		*(param-1)=proxy;
 		return 0;
 		return 0;
-	}else if (param_no==2){
-		port=htons(str2s(*param, strlen(*param), &err));
-		if (err==0){
-			free(*param);
-			*param=(void*)port;
-			return 0;
-		}else{
-			LOG(L_ERR, "TM module:fixup_t_forward: bad port number <%s>\n",
-					(char*)(*param));
-			return E_UNSPEC;
-		}
+	} else {
+		LOG(L_ERR, "ERROR: fixup_t_forwardv6 called with parameter #<>{1,2}\n");
+		return E_BUG;
 	}
 	}
-	return 0;
 }
 }
 
 
 
 
+/* (char *code, char *reason_phrase)==>(int code, r_p as is) */
 
 
 
 
-static int fixup_t_send_reply(void** param, int param_no)
+inline static int fixup_t_send_reply(void** param, int param_no)
 {
 {
 	unsigned int code;
 	unsigned int code;
 	int err;
 	int err;
@@ -253,40 +265,40 @@ static int fixup_t_send_reply(void** param, int param_no)
 
 
 
 
 
 
-static int w_t_check(struct sip_msg* msg, char* str, char* str2)
+inline static int w_t_check(struct sip_msg* msg, char* str, char* str2)
 {
 {
 	return t_check( msg , 0 , 0 ) ? 1 : -1;
 	return t_check( msg , 0 , 0 ) ? 1 : -1;
 }
 }
 
 
 
 
 
 
-
-static int w_t_forward_ack(struct sip_msg* msg, char* str, char* str2)
+#ifdef _TOO_OLD
+inline static int w_t_forward_ack(struct sip_msg* msg, char* proxy, char* _foo)
 {
 {
 	if (t_check( msg , 0 , 0 )==-1) return -1;
 	if (t_check( msg , 0 , 0 )==-1) return -1;
 	if (!T) {
 	if (!T) {
 		DBG("DEBUG: t_forward_ack: no transaction found \n");
 		DBG("DEBUG: t_forward_ack: no transaction found \n");
 		return -1;
 		return -1;
 	}
 	}
-	return t_forward_ack(msg, (unsigned int) str, (unsigned int) str2);
+	return t_forward_ack(msg /*, ( struct proxy_l *) proxy */ );
 }
 }
 
 
+#endif
 
 
 
 
-
-static int w_t_forward_nonack(struct sip_msg* msg, char* str, char* str2)
+inline static int w_t_forward_nonack(struct sip_msg* msg, char* proxy, char* _foo)
 {
 {
 	if (t_check( msg , 0 , 0)==-1) return -1;
 	if (t_check( msg , 0 , 0)==-1) return -1;
 	if (!T) {
 	if (!T) {
 		DBG("DEBUG: t_forward_nonack: no transaction found\n");
 		DBG("DEBUG: t_forward_nonack: no transaction found\n");
 		return -1;
 		return -1;
 	}
 	}
-	return t_forward_nonack(msg, (unsigned int) str, (unsigned int) str2);
+	return t_forward_nonack(msg, ( struct proxy_l *) proxy );
 }
 }
 
 
 
 
 
 
-static int w_t_send_reply(struct sip_msg* msg, char* str, char* str2)
+inline static int w_t_send_reply(struct sip_msg* msg, char* str, char* str2)
 {
 {
 	if (t_check( msg , 0 , 0)==-1) return -1;
 	if (t_check( msg , 0 , 0)==-1) return -1;
 	if (!T) {
 	if (!T) {
@@ -300,7 +312,7 @@ static int w_t_send_reply(struct sip_msg* msg, char* str, char* str2)
 
 
 
 
 
 
-static int w_t_release(struct sip_msg* msg, char* str, char* str2)
+inline static int w_t_release(struct sip_msg* msg, char* str, char* str2)
 {
 {
 	if (t_check( msg  , 0 , 0 )==-1) return 1;
 	if (t_check( msg  , 0 , 0 )==-1) return 1;
 	if ( T && T!=T_UNDEFINED ) 
 	if ( T && T!=T_UNDEFINED ) 
@@ -311,7 +323,7 @@ static int w_t_release(struct sip_msg* msg, char* str, char* str2)
 
 
 
 
 
 
-static int w_t_unref( struct sip_msg* p_msg, char* foo, char* bar )
+inline static int w_t_unref( struct sip_msg* p_msg, char* foo, char* bar )
 {
 {
 	if (T==T_UNDEFINED || T==T_NULL)
 	if (T==T_UNDEFINED || T==T_NULL)
 		return -1;
 		return -1;
@@ -321,7 +333,7 @@ static int w_t_unref( struct sip_msg* p_msg, char* foo, char* bar )
 
 
 
 
 
 
-static int w_t_retransmit_reply( struct sip_msg* p_msg, char* foo, char* bar)
+inline static int w_t_retransmit_reply( struct sip_msg* p_msg, char* foo, char* bar)
 {
 {
 	if (t_check( p_msg  , 0 , 0 )==-1) 
 	if (t_check( p_msg  , 0 , 0 )==-1) 
 		return 1;
 		return 1;
@@ -335,30 +347,38 @@ static int w_t_retransmit_reply( struct sip_msg* p_msg, char* foo, char* bar)
 
 
 
 
 
 
-static int w_t_add_transaction( struct sip_msg* p_msg, char* foo, char* bar ) {
+/* inline static int w_t_add_transaction( struct sip_msg* p_msg, 
+	char* foo, char* bar ) {
+*/
+inline static int w_t_newtran( struct sip_msg* p_msg, char* foo, char* bar ) {
 	if (t_check( p_msg , 0 , 0 )==-1) return -1;
 	if (t_check( p_msg , 0 , 0 )==-1) return -1;
 	if (T) {
 	if (T) {
 		LOG(L_ERR,"ERROR: t_add_transaction: won't add a retransmission\n");
 		LOG(L_ERR,"ERROR: t_add_transaction: won't add a retransmission\n");
 		return -1;
 		return -1;
 	}
 	}
-	return t_add_transaction( p_msg );
+	return t_newtran( p_msg );
 }
 }
 
 
 
 
 
 
 
 
-static int w_t_add_fork_ip(struct sip_msg* msg, char* str, char* str2)
+inline static int w_t_add_fork_ip(struct sip_msg* msg, char* proxy, char* _foo )
 {
 {
-	return t_add_fork((unsigned int)str, (unsigned int)str2, 0,0,DEFAULT,0);
+	struct proxy_l *p;
+	union sockaddr_union to;
+
+	p=(struct proxy_l *) proxy;
+	hostent2su(&to, &p->host, p->addr_idx, (p->port)?htons(p->port):htons(SIP_PORT));
+	return t_add_fork( to, 0,0,DEFAULT,0);
 }
 }
 
 
 
 
 
 
 
 
-static int fixup_t_add_fork_uri(void** param, int param_no)
+inline static int fixup_uri2fork (void** param, int param_no)
 {
 {
-	unsigned int ip, port;
 	struct fork* fork_pack;
 	struct fork* fork_pack;
+	struct proxy_l *p;
 
 
 	if (param_no==1)
 	if (param_no==1)
 	{
 	{
@@ -371,79 +391,128 @@ static int fixup_t_add_fork_uri(void** param, int param_no)
 		}
 		}
 		fork_pack->uri.len = strlen(*param);
 		fork_pack->uri.len = strlen(*param);
 		fork_pack->uri.s = *param;
 		fork_pack->uri.s = *param;
-		if ( get_ip_and_port_from_uri(&(fork_pack->uri), &ip, &port)==0 )
-		{
-			fork_pack->ip = ip;
-			fork_pack->port = port;
-			*param=(void*)fork_pack;
-			return 0;
-		}else{
-			LOG(L_ERR, "TM module:fixup_t_add_fork_uri: bad uri <%s>\n",
-			(char*)(*param));
-			return E_UNSPEC;
+
+		p=uri2proxy( & fork_pack->uri );
+		if (p==0) {
+			pkg_free( fork_pack );
+			return E_CFG;
 		}
 		}
+		hostent2su(&fork_pack->to, &p->host, p->addr_idx,
+        	(p->port)?htons(p->port):htons(SIP_PORT));
+
+		free_proxy(p); free(p);
+		*param=(void*)fork_pack;
+		return 0;
+	} else {
+		LOG(L_ERR, "Error: URI should not be followed by another parameter\n");
+		/* second param => no conversion*/
+		return E_BUG;
 	}
 	}
-	/* second param => no conversion*/
-	return 0;
 }
 }
 
 
 
 
 
 
 
 
-static int w_t_add_fork_uri(struct sip_msg* msg, char* str, char* str2)
+inline static int w_t_add_fork_uri(struct sip_msg* msg, char* str, char* _foo)
 {
 {
-	return t_add_fork( ((struct fork*)str)->ip, ((struct fork*)str)->port,
-		((struct fork*)str)->uri.s, ((struct fork*)str)->uri.len, DEFAULT,0);
+	struct fork *fp;
+	fp=(struct fork *) str;
+	return t_add_fork( fp->to, fp->uri.s, fp->uri.len, DEFAULT, 0);
 }
 }
 
 
+inline static int w_t_add_fork_on_no_rpl(struct sip_msg* msg, char* str, char* _foo )
+{
+	struct fork *fp;
+	fp=(struct fork *) str;
+	return t_add_fork(  fp->to, fp->uri.s, fp->uri.len, NO_RESPONSE, 0);
+}
 
 
-
-
-static int w_t_clear_forks(struct sip_msg* msg, char* str, char* str2)
+inline static int w_t_clear_forks(struct sip_msg* msg, char* _foo, char* _bar )
 {
 {
 	return t_clear_forks();
 	return t_clear_forks();
 }
 }
 
 
 
 
-
-
-static int w_t_add_fork_on_no_rpl(struct sip_msg* msg, char* str, char* str2)
+inline static int w_t_relay_to( struct sip_msg  *p_msg , 
+						 char *proxy, /* struct proxy_l *proxy expected */
+						 char *_foo       /* nothing expected */ )
 {
 {
-	return t_add_fork( ((struct fork*)str)->ip, ((struct fork*)str)->port,
-		((struct fork*)str)->uri.s,((struct fork*)str)->uri.len,NO_RESPONSE,0);
+	return t_relay_to( p_msg, ( struct proxy_l *) proxy );
 }
 }
 
 
-
-
-
-static int t_relay_to( struct sip_msg  *p_msg , char *str_ip , char *str_port)
+static int t_relay_to( struct sip_msg  *p_msg , struct proxy_l *proxy )
 {
 {
-	struct proxy_l *proxy;
-	enum addifnew_status status;
-	int ret=0;
-
-	status = t_addifnew( p_msg );
+	int ret;
+	int new_tran;
+	char err_buffer[128];
+	int sip_err;
+	int reply_ret;
+
+	ret=0;
+
+	new_tran = t_newtran( p_msg );
+
+	/* parsing error, memory alloc, whatever ... return -1;
+	   note -- this is a difference to writing a real script --
+	   we translate t_newtran 0 error to a negative value allowign
+	   some error handling; a script breaks on 0
+    */
+	if (new_tran==0) {
+		ret=E_UNSPEC;
+		goto done;
+	}
 
 
-	switch( status ) {
-		case AIN_ERROR:		/*  fatal error (e.g, parsing) occured */
-			ret = 0;
-			break;
-		case AIN_RETR:		/* it's a retransmission */
+	/* nothing new -- it is an existing transaction */
+	if (new_tran==-1) {
+		if ( p_msg->REQ_METHOD==METHOD_ACK) {
+			DBG( "SER: ACK received -> t_release\n");
+			if ( !t_release_transaction( p_msg ) )
+			{
+				DBG( "SER: WARNING: bad t_release\n");
+			}
+			/* ack fwd-ing not needed -- only hbh ACK
+			   match (new_tran==1) and do not need to
+			   be fwd-ed */
+			ret = 1;
+		} else { /* non-ACK -- retransmit */
 			ret=t_retransmit_reply( p_msg );
 			ret=t_retransmit_reply( p_msg );
 			/* look at ret for better debugging output ... */
 			/* look at ret for better debugging output ... */
 			if (ret>0) DBG("DEBUG: reply retransmitted (status %d)\n", ret);
 			if (ret>0) DBG("DEBUG: reply retransmitted (status %d)\n", ret);
 			else if (ret==-1) DBG("DEBUG: no reply to retransmit; "
 			else if (ret==-1) DBG("DEBUG: no reply to retransmit; "
 				"probably a non-INVITE transaction which was not replied\n");
 				"probably a non-INVITE transaction which was not replied\n");
 			else LOG(L_ERR, "ERROR: reply retranmission failed\n");
 			else LOG(L_ERR, "ERROR: reply retranmission failed\n");
-			/* eventually, do not worry and proceed whatever happened to you...*/
+			/* do not worry and proceed whatever happened to you...*/
 			ret = 1;
 			ret = 1;
-			break;
-		case AIN_NEW:		/* it's a new request */
-			if (!t_forward_nonack(p_msg,(unsigned int)str_ip,
-			(unsigned int) str_port ))
+		}
+	} else { /* it is a new transaction */
+		if ( p_msg->REQ_METHOD==METHOD_ACK) {
+			/* ACKs does not establish a transaction and is
+			   fwd-ed statelessly */
+			DBG( "SER: forwarding ACK  statelessly \n");
+			ret=forward_request( p_msg , proxy ) ;
+		} else {
+			ret=t_forward_nonack(p_msg, proxy);
+			if (ret<=0)
 			{
 			{
 				DBG( "SER:ERROR: t_forward \n");
 				DBG( "SER:ERROR: t_forward \n");
-				ret = 0;
+				/* we reply statefuly and enter WAIT state since error might 
+				   have occured in middle of forking and we do not 
+				   want to put the forking burden on upstream client;
+				   howver, it may fail too due to lack of memory */
+				err2reason_phrase( ser_error, &sip_err,
+					err_buffer, sizeof(err_buffer), "TM" );
+				reply_ret=t_send_reply( p_msg , sip_err, err_buffer,0);
+				t_release_transaction( p_msg );
+				if (reply_ret>0) {
+					/* we have taken care of all -- do nothing in
+				  	script */
+					DBG("ERROR: generation of a stateful reply "
+						"on error succeeded\n");
+					ret=0;
+				}  else {
+					DBG("ERROR: generation of a stateful reply "
+						"on error failed\n");
+				};
 			} else { /* let upstream know, I forwarded downstream */
 			} else { /* let upstream know, I forwarded downstream */
 				if ( p_msg->REQ_METHOD==METHOD_CANCEL)
 				if ( p_msg->REQ_METHOD==METHOD_CANCEL)
 				{
 				{
@@ -459,39 +528,12 @@ static int t_relay_to( struct sip_msg  *p_msg , char *str_ip , char *str_port)
 				} else {
 				} else {
 					DBG( "SER: new transaction\n");
 					DBG( "SER: new transaction\n");
 				}
 				}
-				ret = 1;
-			}
-			break;
-		case AIN_NEWACK:	/* it's an ACK for which no transaction exists */
-			DBG( "SER: forwarding ACK  statelessly \n");
-			proxy = mk_proxy_from_ip( (unsigned int)str_ip,
-				ntohs((unsigned int)str_port) );
-			forward_request( p_msg , proxy ) ;
-			free_proxy(proxy);
-			free(proxy);
-			ret=1;
-			break;
-		case AIN_OLDACK:	/* it's an ACK for an existing transaction */
-			DBG( "SER: ACK received -> t_release\n");
-			if ( !t_release_transaction( p_msg ) )
-			{
-				DBG( "SER: WARNING: bad t_release\n");
-			}
-			/* t_forward decides whether to forward (2xx) 
-			   or not (anything else) */
-			if ( !t_forward_ack( p_msg , (unsigned int) str_ip ,
-			(unsigned int) str_port ) )
-				DBG( "SER: WARNING: bad ACK forward\n");
-			ret = 1;
-			break;
-		case AIN_RTRACK:	/* ACK retransmission */
-			DBG( "SER: ACK retransmission\n");
-			ret = 1;
-			break;
-		default:
-			LOG(L_CRIT, "ERROR: unexpected addifnew return value: %d\n", ret);
-			abort();
-	};
+			} /* forward_nonack succeeded */
+		} /* a new non-ACK trancation */
+	} /* a new transaction */
+
+
+done:
 	if (T!=T_UNDEFINED && T!=T_NULL) {
 	if (T!=T_UNDEFINED && T!=T_NULL) {
 		T_UNREF( T );
 		T_UNREF( T );
 	}
 	}
@@ -499,27 +541,25 @@ static int t_relay_to( struct sip_msg  *p_msg , char *str_ip , char *str_port)
 }
 }
 
 
 
 
-
-
-static int t_relay( struct sip_msg  *p_msg , char* foo, char* bar)
+static int t_relay( struct sip_msg  *p_msg , char* _foo , char* _bar )
 {
 {
-	unsigned int  ip, port;
 	str           *uri;
 	str           *uri;
+	struct proxy_l *p;
+	int ret;
 
 
 	/* the original uri has been changed? */
 	/* the original uri has been changed? */
 	if (p_msg->new_uri.s==0 || p_msg->new_uri.len==0)
 	if (p_msg->new_uri.s==0 || p_msg->new_uri.len==0)
 		uri = &(p_msg->first_line.u.request.uri);
 		uri = &(p_msg->first_line.u.request.uri);
 	else
 	else
 		uri = &(p_msg->new_uri);
 		uri = &(p_msg->new_uri);
-	/* extracts ip and port from uri */		
-	if ( get_ip_and_port_from_uri( uri , &ip, &port)<0 )
-	{
-		LOG( L_ERR , "ERROR: t_on_request_received_uri: unable"
-			" to extract ip and port from uri!\n" );
-		return -1;
-	}
-	return t_relay_to( p_msg , ( char *) ip , (char *) port );
-}
 
 
+	p=uri2proxy( uri );
+	if (p==0) return E_BAD_ADDRESS;
 
 
+	/* relay now */
+	ret=t_relay_to( p_msg, p );
+	free_proxy( p );
+	free( p );
+	return ret;
+}
 
 

+ 52 - 0
modules/tm/ut.h

@@ -0,0 +1,52 @@
+/*
+ * $Id$
+ *
+ * utilities
+ *
+ */
+
+#ifndef _TM_UT_H
+#define _TM_UT_H
+
+#include "../../dprint.h"
+#include "../../error.h"
+#include "../../ut.h"
+#include "../../str.h"
+#include "../../parser/msg_parser.h"
+
+inline static struct proxy_l *uri2proxy( str *uri )
+{
+	struct sip_uri  parsed_uri;
+	unsigned int  port; 
+	struct proxy_l *p;
+	int err;
+
+	if (parse_uri(uri->s, uri->len, &parsed_uri)<0) {
+		LOG(L_ERR, "ERROR: t_relay: bad_uri: %.*s\n",
+			uri->len, uri->s );
+		return 0;
+	}
+	if (parsed_uri.port.s){ 
+		port=str2s((unsigned char*)parsed_uri.port.s, parsed_uri.port.len, &err);
+		if (err){
+			LOG(L_ERR, "ERROR: t_relay: bad port in uri: <%.*s>\n",
+				parsed_uri.port.len, parsed_uri.port.s);
+			goto error;
+		}
+	} else port=SIP_PORT;
+	p=mk_proxy(parsed_uri.host.s, port);
+	if (p==0) {
+		LOG(L_ERR, "ERROR: t_relay: bad host name in URI <%.*s>\n",
+			uri->len, uri->s);
+		goto error;
+	}
+	free_uri( &parsed_uri );
+	return p;
+
+error:
+	free_uri( &parsed_uri );
+	return 0;
+	
+}
+
+#endif

+ 5 - 6
msg_translator.c

@@ -11,6 +11,7 @@
 
 
 #include "msg_translator.h"
 #include "msg_translator.h"
 #include "globals.h"
 #include "globals.h"
+#include "error.h"
 #include "mem/mem.h"
 #include "mem/mem.h"
 #include "dprint.h"
 #include "dprint.h"
 #include "config.h"
 #include "config.h"
@@ -84,12 +85,6 @@ int check_address(struct ip_addr* ip, char *name, int resolver)
 }
 }
 
 
 
 
-
-
-
-
-
-
 char* via_builder( struct sip_msg *msg , unsigned int *len, 
 char* via_builder( struct sip_msg *msg , unsigned int *len, 
 					struct socket_info* send_sock )
 					struct socket_info* send_sock )
 {
 {
@@ -101,6 +96,7 @@ char* via_builder( struct sip_msg *msg , unsigned int *len,
 
 
 	line_buf=pkg_malloc(sizeof(char)*MAX_VIA_LINE_SIZE);
 	line_buf=pkg_malloc(sizeof(char)*MAX_VIA_LINE_SIZE);
 	if (line_buf==0){
 	if (line_buf==0){
+		ser_error=E_OUT_OF_MEM;
 		LOG(L_ERR, "ERROR: via_builder: out of memory\n");
 		LOG(L_ERR, "ERROR: via_builder: out of memory\n");
 		goto error;
 		goto error;
 	}
 	}
@@ -162,6 +158,7 @@ char* via_builder( struct sip_msg *msg , unsigned int *len,
 	}else{
 	}else{
 		LOG(L_ERR, " ERROR: via_builder: via too long (%d)\n",
 		LOG(L_ERR, " ERROR: via_builder: via too long (%d)\n",
 				via_len);
 				via_len);
+		ser_error=E_BUG;
 		goto error;
 		goto error;
 	}
 	}
 
 
@@ -278,6 +275,7 @@ char * build_req_buf_from_sip_req( struct sip_msg* msg,
 	if (check_address(source_ip, msg->via1->host.s, received_dns)!=0){
 	if (check_address(source_ip, msg->via1->host.s, received_dns)!=0){
 		received_buf=pkg_malloc(sizeof(char)*MAX_RECEIVED_SIZE);
 		received_buf=pkg_malloc(sizeof(char)*MAX_RECEIVED_SIZE);
 		if (received_buf==0){
 		if (received_buf==0){
+			ser_error=E_OUT_OF_MEM;
 			LOG(L_ERR, "ERROR: build_req_buf_from_sip_req: out of memory\n");
 			LOG(L_ERR, "ERROR: build_req_buf_from_sip_req: out of memory\n");
 			goto error1;
 			goto error1;
 		}
 		}
@@ -390,6 +388,7 @@ char * build_req_buf_from_sip_req( struct sip_msg* msg,
 	}
 	}
 	new_buf=(char*)local_malloc(new_len+1);
 	new_buf=(char*)local_malloc(new_len+1);
 	if (new_buf==0){
 	if (new_buf==0){
+		ser_error=E_OUT_OF_MEM;
 		LOG(L_ERR, "ERROR: build_req_buf_from_sip_req: out of memory\n");
 		LOG(L_ERR, "ERROR: build_req_buf_from_sip_req: out of memory\n");
 		goto error;
 		goto error;
 	}
 	}

+ 15 - 11
parser/msg_parser.c

@@ -15,6 +15,8 @@
 #include "../dprint.h"
 #include "../dprint.h"
 #include "../data_lump_rpl.h"
 #include "../data_lump_rpl.h"
 #include "../mem/mem.h"
 #include "../mem/mem.h"
+#include "../error.h"
+#include "../globals.h"
 
 
 #ifdef DEBUG_DMALLOC
 #ifdef DEBUG_DMALLOC
 #include <mem/dmalloc.h>
 #include <mem/dmalloc.h>
@@ -422,13 +424,13 @@ int parse_uri(char *buf, int len, struct sip_uri* uri)
 	next=q_memchr(buf, ':',  len);
 	next=q_memchr(buf, ':',  len);
 	if ((next==0)||(strncmp(buf,"sip",next-buf)!=0)){
 	if ((next==0)||(strncmp(buf,"sip",next-buf)!=0)){
 		LOG(L_DBG, "ERROR: parse_uri: bad sip uri\n");
 		LOG(L_DBG, "ERROR: parse_uri: bad sip uri\n");
-		ret=E_UNSPEC;
+		ser_error=ret=E_BAD_URI;
 		goto error;
 		goto error;
 	}
 	}
 	buf=next+1; /* next char after ':' */
 	buf=next+1; /* next char after ':' */
 	if (buf>end){
 	if (buf>end){
 		LOG(L_DBG, "ERROR: parse_uri: uri too short\n");
 		LOG(L_DBG, "ERROR: parse_uri: uri too short\n");
-		ret=E_UNSPEC;
+		ser_error=ret=E_BAD_URI;
 		goto error;
 		goto error;
 	}
 	}
 	/*look for '@' */
 	/*look for '@' */
@@ -449,7 +451,7 @@ int parse_uri(char *buf, int len, struct sip_uri* uri)
 			uri->user.s=(char*)pkg_malloc(next-user+1);
 			uri->user.s=(char*)pkg_malloc(next-user+1);
 			if (uri->user.s==0){
 			if (uri->user.s==0){
 				LOG(L_ERR,"ERROR:parse_uri: memory allocation failure\n");
 				LOG(L_ERR,"ERROR:parse_uri: memory allocation failure\n");
-				ret=E_OUT_OF_MEM;
+				ser_error=ret=E_OUT_OF_MEM;
 				goto error;
 				goto error;
 			}
 			}
 			memcpy(uri->user.s, user, next-user);
 			memcpy(uri->user.s, user, next-user);
@@ -460,7 +462,7 @@ int parse_uri(char *buf, int len, struct sip_uri* uri)
 			uri->user.s=(char*)pkg_malloc(passwd-user+1);
 			uri->user.s=(char*)pkg_malloc(passwd-user+1);
 			if (uri->user.s==0){
 			if (uri->user.s==0){
 				LOG(L_ERR,"ERROR:parse_uri: memory allocation failure\n");
 				LOG(L_ERR,"ERROR:parse_uri: memory allocation failure\n");
-				ret=E_OUT_OF_MEM;
+				ser_error=ret=E_OUT_OF_MEM;
 				goto error;
 				goto error;
 			}
 			}
 			memcpy(uri->user.s, user, passwd-user);
 			memcpy(uri->user.s, user, passwd-user);
@@ -470,7 +472,7 @@ int parse_uri(char *buf, int len, struct sip_uri* uri)
 			uri->passwd.s=(char*)pkg_malloc(next-passwd+1);
 			uri->passwd.s=(char*)pkg_malloc(next-passwd+1);
 			if (uri->passwd.s==0){
 			if (uri->passwd.s==0){
 				LOG(L_ERR,"ERROR:parse_uri: memory allocation failure\n");
 				LOG(L_ERR,"ERROR:parse_uri: memory allocation failure\n");
-				ret=E_OUT_OF_MEM;
+				ser_error=ret=E_OUT_OF_MEM;
 				goto error;
 				goto error;
 			}
 			}
 			memcpy(uri->passwd.s, passwd, next-passwd);
 			memcpy(uri->passwd.s, passwd, next-passwd);
@@ -482,7 +484,7 @@ int parse_uri(char *buf, int len, struct sip_uri* uri)
 	/* try to find the rest */
 	/* try to find the rest */
 	if(host>=end){
 	if(host>=end){
 		LOG(L_DBG, "ERROR: parse_uri: missing hostport\n");
 		LOG(L_DBG, "ERROR: parse_uri: missing hostport\n");
-		ret=E_UNSPEC;
+		ser_error=ret=E_UNSPEC;
 		goto error;
 		goto error;
 	}
 	}
 	next=host;
 	next=host;
@@ -529,14 +531,14 @@ int parse_uri(char *buf, int len, struct sip_uri* uri)
 		if ( ((params) &&(params<port))||((headers) &&(headers<port)) ){
 		if ( ((params) &&(params<port))||((headers) &&(headers<port)) ){
 			/* error -> invalid uri we found ';' or '?' before ':' */
 			/* error -> invalid uri we found ';' or '?' before ':' */
 			LOG(L_DBG, "ERROR: parse_uri: malformed sip uri\n");
 			LOG(L_DBG, "ERROR: parse_uri: malformed sip uri\n");
-			ret=E_UNSPEC;
+			ser_error=ret=E_BAD_URI;
 			goto error;
 			goto error;
 		}
 		}
 		port_len=(params)?params-port:(headers)?headers-port:end-port;
 		port_len=(params)?params-port:(headers)?headers-port:end-port;
 		uri->port.s=pkg_malloc(port_len+1);
 		uri->port.s=pkg_malloc(port_len+1);
 		if (uri->port.s==0){
 		if (uri->port.s==0){
 			LOG(L_ERR, "ERROR: parse_uri: memory allocation error\n");
 			LOG(L_ERR, "ERROR: parse_uri: memory allocation error\n");
-			ret=E_OUT_OF_MEM;
+			ser_error=ret=E_OUT_OF_MEM;
 			goto error;
 			goto error;
 		}
 		}
 		memcpy(uri->port.s, port, port_len);
 		memcpy(uri->port.s, port, port_len);
@@ -549,14 +551,14 @@ int parse_uri(char *buf, int len, struct sip_uri* uri)
 		if ((headers) && (headers<params)){
 		if ((headers) && (headers<params)){
 			/* error -> invalid uri we found '?' or '?' before ';' */
 			/* error -> invalid uri we found '?' or '?' before ';' */
 			LOG(L_DBG, "ERROR: parse_uri: malformed sip uri\n");
 			LOG(L_DBG, "ERROR: parse_uri: malformed sip uri\n");
-			ret=E_UNSPEC;
+			ser_error=ret=E_BAD_URI;
 			goto error;
 			goto error;
 		}
 		}
 		params_len=(headers)?headers-params:end-params;
 		params_len=(headers)?headers-params:end-params;
 		uri->params.s=pkg_malloc(params_len+1);
 		uri->params.s=pkg_malloc(params_len+1);
 		if (uri->params.s==0){
 		if (uri->params.s==0){
 			LOG(L_ERR, "ERROR: parse_uri: memory allocation error\n");
 			LOG(L_ERR, "ERROR: parse_uri: memory allocation error\n");
-			ret=E_OUT_OF_MEM;
+			ser_error=ret=E_OUT_OF_MEM;
 			goto error;
 			goto error;
 		}
 		}
 		memcpy(uri->params.s, params, params_len);
 		memcpy(uri->params.s, params, params_len);
@@ -570,7 +572,7 @@ int parse_uri(char *buf, int len, struct sip_uri* uri)
 		uri->headers.s=pkg_malloc(headers_len+1);
 		uri->headers.s=pkg_malloc(headers_len+1);
 		if(uri->headers.s==0){
 		if(uri->headers.s==0){
 			LOG(L_ERR, "ERROR: parse_uri: memory allocation error\n");
 			LOG(L_ERR, "ERROR: parse_uri: memory allocation error\n");
-			ret=E_OUT_OF_MEM;
+			ser_error=ret=E_OUT_OF_MEM;
 			goto error;
 			goto error;
 		}
 		}
 		memcpy(uri->headers.s, headers, headers_len);
 		memcpy(uri->headers.s, headers, headers_len);
@@ -611,6 +613,7 @@ int parse_headers(struct sip_msg* msg, int flags)
 	while( tmp<end && (flags & msg->parsed_flag) != flags){
 	while( tmp<end && (flags & msg->parsed_flag) != flags){
 		hf=pkg_malloc(sizeof(struct hdr_field));
 		hf=pkg_malloc(sizeof(struct hdr_field));
 		if (hf==0){
 		if (hf==0){
+			ser_error=E_OUT_OF_MEM;
 			LOG(L_ERR, "ERROR:parse_headers: memory allocation error\n");
 			LOG(L_ERR, "ERROR:parse_headers: memory allocation error\n");
 			goto error;
 			goto error;
 		}
 		}
@@ -710,6 +713,7 @@ skip:
 	return 0;
 	return 0;
 
 
 error:
 error:
+	ser_error=E_BAD_REQ;
 	if (hf) pkg_free(hf);
 	if (hf) pkg_free(hf);
 	return -1;
 	return -1;
 }
 }

+ 1 - 0
parser/msg_parser.h

@@ -75,6 +75,7 @@ enum{
 #define INVITE "INVITE"
 #define INVITE "INVITE"
 
 
 /* convenience short-cut macros */
 /* convenience short-cut macros */
+#define REQ_LINE(_msg) ((_msg)->first_line.u.request)
 #define REQ_METHOD first_line.u.request.method_value
 #define REQ_METHOD first_line.u.request.method_value
 #define REPLY_STATUS first_line.u.reply.statuscode
 #define REPLY_STATUS first_line.u.reply.statuscode
 #define REPLY_CLASS(_reply) ((_reply)->REPLY_STATUS/100)
 #define REPLY_CLASS(_reply) ((_reply)->REPLY_STATUS/100)

+ 11 - 5
proxy.c

@@ -20,6 +20,7 @@
 
 
 #include "resolve.h"
 #include "resolve.h"
 #include "ip_addr.h"
 #include "ip_addr.h"
+#include "globals.h"
 
 
 #ifdef DEBUG_DMALLOC
 #ifdef DEBUG_DMALLOC
 #include <dmalloc.h>
 #include <dmalloc.h>
@@ -54,7 +55,7 @@ static int hostent_cpy(struct hostent *dst, struct hostent* src)
 	dst->h_name=(char*)malloc(sizeof(char) * len);
 	dst->h_name=(char*)malloc(sizeof(char) * len);
 	if (dst->h_name) strncpy(dst->h_name,src->h_name, len);
 	if (dst->h_name) strncpy(dst->h_name,src->h_name, len);
 	else{
 	else{
-		ret=E_OUT_OF_MEM;
+		ser_error=ret=E_OUT_OF_MEM;
 		goto error;
 		goto error;
 	}
 	}
 
 
@@ -62,7 +63,7 @@ static int hostent_cpy(struct hostent *dst, struct hostent* src)
 	for (len=0;src->h_aliases[len];len++);
 	for (len=0;src->h_aliases[len];len++);
 	dst->h_aliases=(char**)malloc(sizeof(char*)*(len+1));
 	dst->h_aliases=(char**)malloc(sizeof(char*)*(len+1));
 	if (dst->h_aliases==0){
 	if (dst->h_aliases==0){
-		ret=E_OUT_OF_MEM;
+		ser_error=ret=E_OUT_OF_MEM;
 		free(dst->h_name);
 		free(dst->h_name);
 		goto error;
 		goto error;
 	}
 	}
@@ -71,7 +72,7 @@ static int hostent_cpy(struct hostent *dst, struct hostent* src)
 		len2=strlen(src->h_aliases[i])+1;
 		len2=strlen(src->h_aliases[i])+1;
 		dst->h_aliases[i]=(char*)malloc(sizeof(char)*len2);
 		dst->h_aliases[i]=(char*)malloc(sizeof(char)*len2);
 		if (dst->h_aliases==0){
 		if (dst->h_aliases==0){
-			ret=E_OUT_OF_MEM;
+			ser_error=ret=E_OUT_OF_MEM;
 			free(dst->h_name);
 			free(dst->h_name);
 			for(r=0; r<i; r++)	free(dst->h_aliases[r]);
 			for(r=0; r<i; r++)	free(dst->h_aliases[r]);
 			free(dst->h_aliases);
 			free(dst->h_aliases);
@@ -83,7 +84,7 @@ static int hostent_cpy(struct hostent *dst, struct hostent* src)
 	for (len=0;src->h_addr_list[len];len++);
 	for (len=0;src->h_addr_list[len];len++);
 	dst->h_addr_list=(char**)malloc(sizeof(char*)*(len+1));
 	dst->h_addr_list=(char**)malloc(sizeof(char*)*(len+1));
 	if (dst->h_addr_list==0){
 	if (dst->h_addr_list==0){
-		ret=E_OUT_OF_MEM;
+		ser_error=ret=E_OUT_OF_MEM;
 		free(dst->h_name);
 		free(dst->h_name);
 		for(r=0; dst->h_aliases[r]; r++)	free(dst->h_aliases[r]);
 		for(r=0; dst->h_aliases[r]; r++)	free(dst->h_aliases[r]);
 		free(dst->h_aliases[r]);
 		free(dst->h_aliases[r]);
@@ -94,7 +95,7 @@ static int hostent_cpy(struct hostent *dst, struct hostent* src)
 	for (i=0;i<len;i++){
 	for (i=0;i<len;i++){
 		dst->h_addr_list[i]=(char*)malloc(sizeof(char)*src->h_length);
 		dst->h_addr_list[i]=(char*)malloc(sizeof(char)*src->h_length);
 		if (dst->h_addr_list[i]==0){
 		if (dst->h_addr_list[i]==0){
-			ret=E_OUT_OF_MEM;
+			ser_error=ret=E_OUT_OF_MEM;
 			free(dst->h_name);
 			free(dst->h_name);
 			for(r=0; dst->h_aliases[r]; r++)	free(dst->h_aliases[r]);
 			for(r=0; dst->h_aliases[r]; r++)	free(dst->h_aliases[r]);
 			free(dst->h_aliases[r]);
 			free(dst->h_aliases[r]);
@@ -170,6 +171,7 @@ struct proxy_l* mk_proxy(char* name, unsigned short port)
 
 
 	p=(struct proxy_l*) malloc(sizeof(struct proxy_l));
 	p=(struct proxy_l*) malloc(sizeof(struct proxy_l));
 	if (p==0){
 	if (p==0){
+		ser_error=E_OUT_OF_MEM;
 		LOG(L_CRIT, "ERROR: mk_proxy: memory allocation failure\n");
 		LOG(L_CRIT, "ERROR: mk_proxy: memory allocation failure\n");
 		goto error;
 		goto error;
 	}
 	}
@@ -186,6 +188,7 @@ struct proxy_l* mk_proxy(char* name, unsigned short port)
 		memcpy(p->host.h_name, name, len);
 		memcpy(p->host.h_name, name, len);
 		p->host.h_aliases=malloc(sizeof(char*));
 		p->host.h_aliases=malloc(sizeof(char*));
 		if (p->host.h_aliases==0) {
 		if (p->host.h_aliases==0) {
+			ser_error=E_OUT_OF_MEM;
 			free(p->host.h_name);
 			free(p->host.h_name);
 			goto error;
 			goto error;
 		}
 		}
@@ -194,6 +197,7 @@ struct proxy_l* mk_proxy(char* name, unsigned short port)
 		p->host.h_length=4;
 		p->host.h_length=4;
 		p->host.h_addr_list=malloc(2*sizeof(char*));
 		p->host.h_addr_list=malloc(2*sizeof(char*));
 		if (p->host.h_addr_list==0){
 		if (p->host.h_addr_list==0){
+			ser_error=E_OUT_OF_MEM;
 			free(p->host.h_name);
 			free(p->host.h_name);
 			free(p->host.h_aliases);
 			free(p->host.h_aliases);
 			goto error;
 			goto error;
@@ -201,6 +205,7 @@ struct proxy_l* mk_proxy(char* name, unsigned short port)
 		p->host.h_addr_list[1]=0;
 		p->host.h_addr_list[1]=0;
 		p->host.h_addr_list[0]=malloc(5);
 		p->host.h_addr_list[0]=malloc(5);
 		if (p->host.h_addr_list[0]==0){
 		if (p->host.h_addr_list[0]==0){
+			ser_error=E_OUT_OF_MEM;
 			free(p->host.h_name);
 			free(p->host.h_name);
 			free(p->host.h_aliases);
 			free(p->host.h_aliases);
 			free(p->host.h_addr_list);
 			free(p->host.h_addr_list);
@@ -216,6 +221,7 @@ struct proxy_l* mk_proxy(char* name, unsigned short port)
 
 
 	he=resolvehost(name);
 	he=resolvehost(name);
 	if (he==0){
 	if (he==0){
+		ser_error=E_BAD_ADDRESS;
 		LOG(L_CRIT, "ERROR: mk_proxy: could not resolve hostname:"
 		LOG(L_CRIT, "ERROR: mk_proxy: could not resolve hostname:"
 					" \"%s\"\n", name);
 					" \"%s\"\n", name);
 		free(p);
 		free(p);