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 "sr_module.h"
 #include "mem/mem.h"
+#include "globals.h"
 
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -48,6 +49,13 @@ int do_action(struct action* a, struct sip_msg* msg)
 	struct sip_uri uri;
 	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;
 	switch (a->type){
 		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;
 						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>,"
 								" dropping packet\n",tmp);
-					ret=E_UNSPEC;
 					break;
 				}
 				switch (a->p2_type){
@@ -80,7 +88,7 @@ int do_action(struct action* a, struct sip_msg* msg)
 											LOG(L_ERR, "ERROR: do_action: "
 												"forward: bad port in "
 												"uri: <%s>\n", uri.port.s);
-											ret=E_UNSPEC;
+											ret=E_BAD_URI;
 											goto error_fwd_uri;
 										}
 									}else port=SIP_PORT;

+ 5 - 1
data_lump.c

@@ -5,6 +5,8 @@
 #include "data_lump.h"
 #include "dprint.h"
 #include "mem/mem.h"
+#include "globals.h"
+#include "error.h"
 
 #include <stdlib.h>
 #include <string.h>
@@ -14,7 +16,6 @@
 #endif
 
 
-
 /* adds a header to the end
  * returns  pointer on success, 0 on error */
 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));
 	if (tmp==0){
+		ser_error=E_OUT_OF_MEM;
 		LOG(L_ERR, "ERROR: insert_new_lump_after: out of memory\n");
 		return 0;
 	}
@@ -99,6 +101,7 @@ struct lump* insert_new_lump_before( struct lump* before, char* new_hdr,
 
 	tmp=pkg_malloc(sizeof(struct lump));
 	if (tmp==0){
+		ser_error=E_OUT_OF_MEM;
 		LOG(L_ERR,"ERROR: insert_new_lump_before: out of memory\n");
 		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));
 	if (tmp==0){
+		ser_error=E_OUT_OF_MEM;
 		LOG(L_ERR, "ERROR: insert_new_lump_before: out of memory\n");
 		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_OUT_OF_MEM  -2
 #define E_BAD_RE      -3
-#define E_BAD_ADDRESS -4
+/* #define E_BAD_ADDRESS -4 */
 #define E_BUG         -5
 #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

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

+ 5 - 1
modules/tm/h_table.c

@@ -9,6 +9,8 @@
 #include "../../md5utils.h"
 /* bogdan test */
 #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 */
 	new_cell = (struct cell*)sh_malloc( sizeof( struct cell ) );
-	if  ( !new_cell )
+	if  ( !new_cell ) {
+		ser_error=E_OUT_OF_MEM;
 		return NULL;
+	}
 
 	/* filling with 0 */
 	memset( new_cell, 0, sizeof( struct cell ) );

+ 8 - 2
modules/tm/h_table.h

@@ -54,7 +54,11 @@ typedef struct retr_buf
 	char *cancel;
 	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;
 
 	/* 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;
 	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
 	/* MD5checksum */
 	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$
  *
+ * transaction maintenance functions
  */
 
-#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"
-
-
-
-#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;
 unsigned int     global_msg_id;
 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()
@@ -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  )
@@ -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 )
 {
@@ -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 "../../forward.h"
 #include "../../mem/mem.h"
-
 #include "../../md5utils.h"
+#include "../../ip_addr.h"
 
 #include "config.h"
 #include "lock.h"
 #include "timer.h"
+#include "sh_malloc.h"
+#include "sip_msg.h"
 
 
 struct s_table;
@@ -30,27 +32,10 @@ struct timer;
 struct entry;
 struct cell;
 
-struct fork
-{
-	unsigned int  ip,port;
-	unsigned char free_flag;
-	str           uri;
-
-};
-
-
 extern struct cell      *T;
 extern unsigned int     global_msg_id;
 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 )
@@ -66,17 +51,35 @@ extern unsigned int     nr_forks;
    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 ) \
 	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,
 	AIN_OLDACK, AIN_RTRACK } ;
+*/
 
 
 int   tm_startup();
@@ -165,8 +169,10 @@ int t_check( struct sip_msg* , int *branch , int* is_cancel);
  *       1 - forward successfull
  *      -1 - error during forward
  */
+/* v6; -jiri
 int t_forward( struct sip_msg* p_msg , unsigned int dst_ip ,
 										unsigned int dst_port);
+*/
 
 
 
@@ -175,7 +181,9 @@ int t_forward( struct sip_msg* p_msg , unsigned int dst_ip ,
  *       1 - forward successfull
  *      -1 - error during forward
  */
+/* v6; -jiri
 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 ,
 	unsigned int dest_port_param );
 int t_forward_ack( struct sip_msg* p_msg , unsigned int dest_ip_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);
 struct cell* t_lookupOriginalT(  struct s_table* hash_table,
 	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);
 char *build_ack( struct sip_msg* rpl, struct cell *trans, int branch ,
 	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");
 }
 
+void delete_cell( struct cell *p_cell );
 
+int t_newtran( struct sip_msg* p_msg );
 
 #endif
 

+ 102 - 39
modules/tm/t_fwd.c

@@ -3,13 +3,14 @@
  *
  */
 
-#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 "hash_func.h"
+#include "t_funcs.h"
+#include "t_fork.h"
 
 #include "t_hooks.h"
 
@@ -29,8 +30,11 @@
  *       1 - forward successfull
  *      -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 )
+*/
 {
 	int          branch;
 	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 lump  *a,*b,*b1,*c;
 	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;
 	shbuf  = 0;
 	backup_uri.s = p_msg->new_uri.s;
 	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? */
@@ -61,9 +63,32 @@ int t_forward_nonack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
 		   somewhere else */
 		LOG( L_CRIT, "ERROR: t_forward_nonack: attempt to rewrite"
 			" request structures\n");
+		ser_error=E_BUG;
 		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");
 	/* special case : 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"
 						": sending CANCEL for it\n",nr_forks);
+					/* v6; -jiri
 					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->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->T_canceled->uac[nr_forks].uri.len;
 					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 */
 					DBG("DEBUG: t_forward_nonack: branch %d finalized"
 						": no CANCEL sent here\n",nr_forks);
+					/* -v6; -jiri
 					t_forks[nr_forks].ip = 0;
+					*/
+					t_forks[nr_forks].inactive= 1;
 				}
 			}
 #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*/
 
 #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;
 #endif
 
 	DBG("DEBUG: t_forward_nonack: nr_forks=%d\n",nr_forks);
 	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;
 		DBG("DEBUG: t_forward_nonack: branch = %d\n",branch);
 		/*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*/
 		p_msg->new_uri.s = t_forks[branch].uri.s;
 		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;
+		}
+		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 */
 		DBG("DEBUG: t_forward_nonack: building outbound request"
 			" 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)
 		{
 			LOG(L_ERR, "ERROR: t_forward_nonack: out of shmem buffer\n");
+			ser_error=ret=E_OUT_OF_MEM;
 			goto error;
 		}
 		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)
 			:(p_msg->first_line.u.request.uri.len);
 		/* send the request */
+		/* v6; -jiri
 		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_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 ) ;
 		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 
 	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;
+		/* v6; -jiri
 		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 = t_forks[NO_RPL_BRANCH].to;
+
 		T->uac[branch].uri.s = t_forks[NO_RPL_BRANCH].uri.s;
 		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.len = backup_uri.len;
 	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;
 	unsigned int len;
 	char *buf, *ack;
-#ifdef _DONT_USE
-	struct sockaddr_in to_sock;
-#endif
-
 
 	/* drop local ACKs */
 	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 );
 	callback_event( TMCB_E2EACK, p_msg );
 	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
-}
 
 
 
@@ -298,6 +350,8 @@ int forward_serial_branch(struct cell* Trans,int branch)
 	unsigned int     len;
 	char             *buf=0, *shbuf=0;
 	str              backup_uri;
+	union sockaddr_union *to;
+	struct socket_info* send_sock;
 
 	backup_uri.s = p_msg->new_uri.s;
 	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*/
 	p_msg->new_uri.s = Trans->uac[branch].uri.s;
 	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;
 	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);
 	Trans->nr_of_outgoings++ ;
 	/* 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) );
 
 	pkg_free( buf ) ;

+ 1 - 1
modules/tm/t_hooks.h

@@ -8,7 +8,7 @@
 #include "h_table.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 );
 

+ 218 - 1
modules/tm/t_lookup.c

@@ -37,6 +37,7 @@
 #include "t_funcs.h"
 #include "config.h"
 #include "sip_msg.h"
+#include "t_hooks.h"
 
 
 #define EQ_LEN(_hf) (t_msg->_hf->body.len==p_msg->_hf->body.len)
@@ -60,6 +61,144 @@
 	)==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:
  *      -1 - transaction wasn't found
@@ -213,6 +352,7 @@ found:
 	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:
 	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)
 {
-	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 );
 		return -1;
@@ -59,16 +59,17 @@ int t_retransmit_reply( /* struct sip_msg* p_msg    */ )
 /* Force a new response into inbound response buffer.
   * 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;
 	char * buf;
 	struct retr_buf *rb;
 	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");
 	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 );
 				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;
 			buf_len = len + REPLY_OVERBUFFER_LEN;
 		}else{
@@ -195,7 +204,6 @@ error:
 #endif
 
 
-
 /*  This function is called whenever a reply for our module is received; 
   * we need to register  this function on module initialization;
   *  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 */
 	unsigned int alloc_len;
 	str *str_foo;
+	struct socket_info* send_sock;
 
 
 	/* 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);
 	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;
 	sometimes it will result in useless CPU cycles
 	but mostly the assumption holds and allows the
@@ -263,6 +273,7 @@ int t_on_reply( struct sip_msg  *p_msg )
 			goto error;
 		}
 	}
+#endif
 
 	/* *** stop timers *** */
 	/* stop retransmission */
@@ -317,6 +328,17 @@ int t_on_reply( struct sip_msg  *p_msg )
 
 	rb = & T->uas.response;
 	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)
 		{
 			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 );
 				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;
 			/* allocate something more for the first message;
 			   subsequent messages will be longer and buffer
@@ -419,3 +450,88 @@ error:
 	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_hooks.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);
 
@@ -51,7 +64,10 @@ struct module_exports exports= {
 	"tm",
 	/* -------- exported functions ----------- */
 	(char*[]){			
+/*		- obsoleted by atomic t_newtran 
 				"t_add_transaction",
+*/
+				"t_newtran",
 				"t_lookup_request",
 				"t_send_reply",
 				"t_retransmit_reply",
@@ -60,7 +76,9 @@ struct module_exports exports= {
 				"t_relay_to",
 				"t_relay",
 				"t_forward_nonack",
+/*
 				"t_forward_ack",
+*/
 				"t_fork_to_ip",
 				"t_fork_to_uri",
 				"t_clear_forks",
@@ -69,16 +87,20 @@ struct module_exports exports= {
 				"load_tm"
 			},
 	(cmd_function[]){
+/*
 					w_t_add_transaction,
+*/					w_t_newtran,
 					w_t_check,
 					w_t_send_reply,
 					w_t_retransmit_reply,
 					w_t_release,
 					w_t_unref,
-					t_relay_to,
+					w_t_relay_to,
 					t_relay,
 					w_t_forward_nonack,
+/*
 					w_t_forward_ack,
+*/
 					w_t_add_fork_ip,
 					w_t_add_fork_uri,
 					w_t_clear_forks,
@@ -87,7 +109,7 @@ struct module_exports exports= {
 					(cmd_function) load_tm
 					},
 	(int[]){
-				0, /* t_add_transaction */
+				0, /* t_newtran */
 				0, /* t_lookup_request */
 				2, /* t_send_reply */
 				0, /* t_retransmit_reply */
@@ -96,7 +118,8 @@ struct module_exports exports= {
 				2, /* t_relay_to */
 				0, /* t_relay */
 				2, /* t_forward_nonack */
-				2, /* t_forward_ack */
+/* 				2,*/ /* t_forward_ack */
+
 				2, /* t_fork_to_ip */
 				1, /* t_fork_to_uri */
 				0, /* t_clear_forks */
@@ -105,25 +128,25 @@ struct module_exports exports= {
 				1 /* load_tm */
 			},
 	(fixup_function[]){
-				0,						/* t_add_transaction */
+				0,						/* t_newtran */
 				0,						/* t_lookup_request */
 				fixup_t_send_reply,		/* t_send_reply */
 				0,						/* t_retransmit_reply */
 				0,						/* t_release */
 				0,						/* t_unref */
-				fixup_t_forward,		/* t_relay_to */
+				fixup_hostport2proxy,	/* t_relay_to */
 				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 */
-				fixup_t_add_fork_uri,	/* t_add_fork_on_no_response */
+				fixup_uri2fork,		/* t_add_fork_on_no_response */
 				0,						/* register_tmcb */
 				0						/* load_tm */
 	
 		},
-	16,
+	15,
 
 	/* ------------ exported variables ---------- */
 	(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;
+	char *host;
 	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);
 	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;
 		}
-		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;
-	}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;
 	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;
 }
 
 
 
-
-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) {
 		DBG("DEBUG: t_forward_ack: no transaction found \n");
 		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) {
 		DBG("DEBUG: t_forward_nonack: no transaction found\n");
 		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) {
@@ -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 && 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)
 		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) 
 		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) {
 		LOG(L_ERR,"ERROR: t_add_transaction: won't add a retransmission\n");
 		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 proxy_l *p;
 
 	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.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();
 }
 
 
-
-
-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 );
 			/* look at ret for better debugging output ... */
 			if (ret>0) DBG("DEBUG: reply retransmitted (status %d)\n", ret);
 			else if (ret==-1) DBG("DEBUG: no reply to retransmit; "
 				"probably a non-INVITE transaction which was not replied\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;
-			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");
-				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 */
 				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 {
 					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) {
 		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;
+	struct proxy_l *p;
+	int ret;
 
 	/* the original uri has been changed? */
 	if (p_msg->new_uri.s==0 || p_msg->new_uri.len==0)
 		uri = &(p_msg->first_line.u.request.uri);
 	else
 		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 "globals.h"
+#include "error.h"
 #include "mem/mem.h"
 #include "dprint.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, 
 					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);
 	if (line_buf==0){
+		ser_error=E_OUT_OF_MEM;
 		LOG(L_ERR, "ERROR: via_builder: out of memory\n");
 		goto error;
 	}
@@ -162,6 +158,7 @@ char* via_builder( struct sip_msg *msg , unsigned int *len,
 	}else{
 		LOG(L_ERR, " ERROR: via_builder: via too long (%d)\n",
 				via_len);
+		ser_error=E_BUG;
 		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){
 		received_buf=pkg_malloc(sizeof(char)*MAX_RECEIVED_SIZE);
 		if (received_buf==0){
+			ser_error=E_OUT_OF_MEM;
 			LOG(L_ERR, "ERROR: build_req_buf_from_sip_req: out of memory\n");
 			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);
 	if (new_buf==0){
+		ser_error=E_OUT_OF_MEM;
 		LOG(L_ERR, "ERROR: build_req_buf_from_sip_req: out of memory\n");
 		goto error;
 	}

+ 15 - 11
parser/msg_parser.c

@@ -15,6 +15,8 @@
 #include "../dprint.h"
 #include "../data_lump_rpl.h"
 #include "../mem/mem.h"
+#include "../error.h"
+#include "../globals.h"
 
 #ifdef DEBUG_DMALLOC
 #include <mem/dmalloc.h>
@@ -422,13 +424,13 @@ int parse_uri(char *buf, int len, struct sip_uri* uri)
 	next=q_memchr(buf, ':',  len);
 	if ((next==0)||(strncmp(buf,"sip",next-buf)!=0)){
 		LOG(L_DBG, "ERROR: parse_uri: bad sip uri\n");
-		ret=E_UNSPEC;
+		ser_error=ret=E_BAD_URI;
 		goto error;
 	}
 	buf=next+1; /* next char after ':' */
 	if (buf>end){
 		LOG(L_DBG, "ERROR: parse_uri: uri too short\n");
-		ret=E_UNSPEC;
+		ser_error=ret=E_BAD_URI;
 		goto error;
 	}
 	/*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);
 			if (uri->user.s==0){
 				LOG(L_ERR,"ERROR:parse_uri: memory allocation failure\n");
-				ret=E_OUT_OF_MEM;
+				ser_error=ret=E_OUT_OF_MEM;
 				goto error;
 			}
 			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);
 			if (uri->user.s==0){
 				LOG(L_ERR,"ERROR:parse_uri: memory allocation failure\n");
-				ret=E_OUT_OF_MEM;
+				ser_error=ret=E_OUT_OF_MEM;
 				goto error;
 			}
 			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);
 			if (uri->passwd.s==0){
 				LOG(L_ERR,"ERROR:parse_uri: memory allocation failure\n");
-				ret=E_OUT_OF_MEM;
+				ser_error=ret=E_OUT_OF_MEM;
 				goto error;
 			}
 			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 */
 	if(host>=end){
 		LOG(L_DBG, "ERROR: parse_uri: missing hostport\n");
-		ret=E_UNSPEC;
+		ser_error=ret=E_UNSPEC;
 		goto error;
 	}
 	next=host;
@@ -529,14 +531,14 @@ int parse_uri(char *buf, int len, struct sip_uri* uri)
 		if ( ((params) &&(params<port))||((headers) &&(headers<port)) ){
 			/* error -> invalid uri we found ';' or '?' before ':' */
 			LOG(L_DBG, "ERROR: parse_uri: malformed sip uri\n");
-			ret=E_UNSPEC;
+			ser_error=ret=E_BAD_URI;
 			goto error;
 		}
 		port_len=(params)?params-port:(headers)?headers-port:end-port;
 		uri->port.s=pkg_malloc(port_len+1);
 		if (uri->port.s==0){
 			LOG(L_ERR, "ERROR: parse_uri: memory allocation error\n");
-			ret=E_OUT_OF_MEM;
+			ser_error=ret=E_OUT_OF_MEM;
 			goto error;
 		}
 		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)){
 			/* error -> invalid uri we found '?' or '?' before ';' */
 			LOG(L_DBG, "ERROR: parse_uri: malformed sip uri\n");
-			ret=E_UNSPEC;
+			ser_error=ret=E_BAD_URI;
 			goto error;
 		}
 		params_len=(headers)?headers-params:end-params;
 		uri->params.s=pkg_malloc(params_len+1);
 		if (uri->params.s==0){
 			LOG(L_ERR, "ERROR: parse_uri: memory allocation error\n");
-			ret=E_OUT_OF_MEM;
+			ser_error=ret=E_OUT_OF_MEM;
 			goto error;
 		}
 		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);
 		if(uri->headers.s==0){
 			LOG(L_ERR, "ERROR: parse_uri: memory allocation error\n");
-			ret=E_OUT_OF_MEM;
+			ser_error=ret=E_OUT_OF_MEM;
 			goto error;
 		}
 		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){
 		hf=pkg_malloc(sizeof(struct hdr_field));
 		if (hf==0){
+			ser_error=E_OUT_OF_MEM;
 			LOG(L_ERR, "ERROR:parse_headers: memory allocation error\n");
 			goto error;
 		}
@@ -710,6 +713,7 @@ skip:
 	return 0;
 
 error:
+	ser_error=E_BAD_REQ;
 	if (hf) pkg_free(hf);
 	return -1;
 }

+ 1 - 0
parser/msg_parser.h

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

+ 11 - 5
proxy.c

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