Browse Source

added WAIT protection, NEW_HNAME, memory command-line option, first
version of SRL

Jiri Kuthan 23 years ago
parent
commit
40a8d9dd85
18 changed files with 1707 additions and 322 deletions
  1. 12 4
      Makefile.defs
  2. 1 1
      config.h
  3. 2 0
      globals.h
  4. 21 1
      main.c
  5. 6 6
      mem/shm_mem.c
  6. 8 1
      modules/tm/h_table.h
  7. 43 1
      modules/tm/lock.c
  8. 23 289
      modules/tm/t_funcs.c
  9. 37 5
      modules/tm/t_funcs.h
  10. 15 11
      modules/tm/t_fwd.c
  11. 520 0
      modules/tm/t_reply.c
  12. 26 0
      modules/tm/timer.c
  13. 5 1
      modules/tm/tm.c
  14. 11 1
      msg_parser.h
  15. 4 0
      msg_translator.c
  16. 1 1
      parse_hname.c
  17. 741 0
      parse_hname2.c
  18. 231 0
      strs.h

+ 12 - 4
Makefile.defs

@@ -54,7 +54,9 @@ ARCH = $(shell uname -m |sed -e s/i.86/i386/ -e s/sun4u/sparc64/ )
 #		issues additional debugging information if lock/unlock is called
 # -DFAST_LOCK
 #		uses fast arhitecture specific locking (see the arh. specific section)
-#
+# -DNOISY_REPLIES
+#		turns on appending User-agent and Content-length:0 to ser-generated
+#		replies; 
 # -DBUSY_WAIT
 #		uses busy waiting on the lock
 # -DADAPTIVE_WAIT
@@ -66,21 +68,27 @@ ARCH = $(shell uname -m |sed -e s/i.86/i386/ -e s/sun4u/sparc64/ )
 # -DNOSMP
 #		don't use smp compliant locking (faster but won't work on SMP machines)
 #		(not yet enabled)
+# -DWAIT
+#		protection against race condiditions; turn off only for debugging;
+#       to become non-optional if stable
+# -DNEW_HNAME
+#		32-bit header name parsing; turn off for lower speed ;-) or debugging; to become non-optional if fast and stable
+# -DSRL Shortened Reply Lock -- moves more code, esp. "send" out
+#  of locks for greater speed; to become non-optional if fast and stable
 
 DEFS+= -DNAME='"$(NAME)"' -DVERSION='"$(RELEASE)"' -DARCH='"$(ARCH)"' \
 	 -DOS='"$(OS)"' -DCOMPILER='"$(CC_VER)"'\
 	 -DDNS_IP_HACK  -DPKG_MALLOC -DSHM_MEM  -DSHM_MMAP \
 	 -DF_MALLOC  -DUSE_SYNONIM\
 	 -DNO_DEBUG \
+	 -DWAIT -DNEW_HNAME -DNOISY_REPLIES -DSRL
 	 #-DADAPTIVE_WAIT -DADAPTIVE_WAIT_LOOPS=0 \
 	 #-DNOSMP \
 	 #-DEXTRA_DEBUG 
 	 #-DVQ_MALLOC  -DDBG_LOCK  #-DSTATS
 	 #-DDBG_QM_MALLOC #-DNO_DEBUG
-#-DEXTRA_DEBUG
 # -DUSE_SHM_MEM
 #-DNO_DEBUG
-#-DPKG_MALLOC
 #-DNO_DEBUG#-DSTATS -DNO_DEBUG
 #-DNO_LOG
 
@@ -235,7 +243,7 @@ ifeq  ($(OS), SunOS)
 
 	YACC=yacc
 	LIBS+=-L/usr/local/lib -lxnet -lrt # or -lnsl -lsocket or -lglibc ?
-	# -lrt needed for sched_yield
+	# -lrt needed for sched_yield; some systems may require -lposix4
 endif
 
 ifeq ($(OS), FreeBSD)

+ 1 - 1
config.h

@@ -55,7 +55,7 @@
 #define PKG_MEM_POOL_SIZE 1024*1024
 
 /*used if SH_MEM is defined*/
-#define SHM_MEM_SIZE 256*1024*1024
+#define SHM_MEM_SIZE 256
 
 #define TIMER_TICK 1
 #define LONG_SLEEP	3600

+ 2 - 0
globals.h

@@ -41,4 +41,6 @@ extern int *pids;
 extern int cfg_errors;
 extern unsigned int msg_no;
 
+extern unsigned int shm_mem_size;
+
 #endif

+ 21 - 1
main.c

@@ -30,6 +30,7 @@
 #endif
 #include "sr_module.h"
 #include "timer.h"
+#include "msg_parser.h"
 
 
 #include <signal.h>
@@ -126,6 +127,7 @@ Options:\n\
     -h           This help message\n\
     -b nr        Maximum receive buffer size which will not be exceeded by\n\
                  auto-probing procedure even if  OS allows\n\
+	-m nr        Size of shared memory allocated in Megabytes\n\
     -w  dir      change the working directory to \"dir\" (default \"/\")\n\
     -t  dir      chroot to \"dir\"\n\
     -u uid       change uid \n\
@@ -141,9 +143,11 @@ void print_ct_constants()
 #ifdef ADAPTIVE_WAIT
 	printf("ADAPTIVE_WAIT_LOOPS=%d, ", ADAPTIVE_WAIT_LOOPS);
 #endif
+/*
 #ifdef SHM_MEM
 	printf("SHM_MEM_SIZE=%d, ", SHM_MEM_SIZE);
 #endif
+*/
 	printf("MAX_RECV_BUFFER_SIZE %d, MAX_LISTEN %d,"
 			" MAX_URI_SIZE %d, MAX_PROCESSES %d\n",
 		MAX_RECV_BUFFER_SIZE, MAX_LISTEN, MAX_URI_SIZE, MAX_PROCESSES );
@@ -204,6 +208,9 @@ process_bm_t process_bit = 0;
 /* cfg parsing */
 int cfg_errors=0;
 
+/* shared memory (in MB) */
+unsigned int shm_mem_size=SHM_MEM_SIZE * 1024 * 1024;
+
 #define MAX_FD 32 /* maximum number of inherited open file descriptors,
 		    (normally it shouldn't  be bigger  than 3) */
 
@@ -483,7 +490,7 @@ int main(int argc, char** argv)
 #ifdef STATS
 	"s:"
 #endif
-	"f:p:b:l:n:rRvcdDEVhw:t:u:g:";
+	"f:p:m:b:l:n:rRvcdDEVhw:t:u:g:";
 	
 	while((c=getopt(argc,argv,options))!=-1){
 		switch(c){
@@ -503,6 +510,15 @@ int main(int argc, char** argv)
 					}
 					break;
 
+			case 'm':
+					shm_mem_size=strtol(optarg, &tmp, 10) * 1024 * 1024;
+					if (tmp &&(*tmp)){
+						fprintf(stderr, "bad shmem size number: -m %s\n", optarg);
+						goto error;
+					};
+					LOG(L_INFO, "ser: shared memory allocated: %d MByte\n", shm_mem_size );
+					break;
+
 			case 'b':
 					maxbuffer=strtol(optarg, &tmp, 10);
 					if (tmp &&(*tmp)){
@@ -619,6 +635,10 @@ int main(int argc, char** argv)
 		goto error;
 	}
 
+#ifdef NEW_HNAME
+    init_htable();
+#endif
+
 	/*init mallocs (before parsing cfg !)*/
 	if (init_mallocs()==-1)
 		goto error;

+ 6 - 6
mem/shm_mem.c

@@ -142,13 +142,13 @@ int shm_mem_init()
 				strerror(errno));
 		return -1;
 	}
-	shm_mempool=mmap(0, SHM_MEM_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED,
+	shm_mempool=mmap(0, /* SHM_MEM_SIZE */ shm_mem_size, PROT_READ|PROT_WRITE, MAP_SHARED,
 						fd ,0);
 	/* close /dev/zero */
 	close(fd);
 #else
 	
-	shm_shmid=shmget(IPC_PRIVATE, SHM_MEM_SIZE, 0700);
+	shm_shmid=shmget(IPC_PRIVATE, /* SHM_MEM_SIZE */ shm_mem_size , 0700);
 	if (shm_shmid==-1){
 		LOG(L_CRIT, "ERROR: shm_mem_init: could not allocate shared memory"
 				" segment: %s\n", strerror(errno));
@@ -185,11 +185,11 @@ int shm_mem_init()
 #endif
 	/* init it for malloc*/
 #	ifdef VQ_MALLOC
-		shm_block=vqm_malloc_init(shm_mempool, SHM_MEM_SIZE);
+		shm_block=vqm_malloc_init(shm_mempool, /* SHM_MEM_SIZE */ shm_mem_size );
 	#elif defined F_MALLOC
-		shm_block=fm_malloc_init(shm_mempool, SHM_MEM_SIZE);
+		shm_block=fm_malloc_init(shm_mempool, /* SHM_MEM_SIZE */ shm_mem_size );
 #	else
-		shm_block=qm_malloc_init(shm_mempool, SHM_MEM_SIZE);
+		shm_block=qm_malloc_init(shm_mempool, /* SHM_MEM_SIZE */ shm_mem_size );
 #	endif
 	if (shm_block==0){
 		LOG(L_CRIT, "ERROR: shm_mem_init: could not initialize shared"
@@ -218,7 +218,7 @@ void shm_mem_destroy()
 	DBG("shm_mem_destroy\n");
 	if (shm_mempool && (shm_mempool!=(void*)-1)) {
 #ifdef SHM_MMAP
-		munmap(shm_mempool, SHM_MEM_SIZE);
+		munmap(shm_mempool, /* SHM_MEM_SIZE */ shm_mem_size );
 #else
 		shmdt(shm_mempool);
 #endif

+ 8 - 1
modules/tm/h_table.h

@@ -97,7 +97,13 @@ typedef struct cell
 	/* protection against concurrent reply processing */
 	ser_lock_t   reply_mutex;
 	/* protection against concurrent ACK processing */
-	ser_lock_t   ack_mutex;
+	ser_lock_t	ack_mutex;
+#ifdef WAIT
+	/* protection against reentering WAIT state */
+	ser_lock_t	wait_mutex;
+	/* has the transaction been put on wait status ? */
+	int on_wait;
+#endif
 
 	/* this is where destination is stored for picked branch;
 	good if a need to forward ACK later on */
@@ -111,6 +117,7 @@ typedef struct cell
 	/* scheduled for deletion ? */
 	short damocles;
 #endif
+
 }cell_type;
 
 

+ 43 - 1
modules/tm/lock.c

@@ -51,6 +51,9 @@ static int
 	timer_semaphore=0, 
 	reply_semaphore=0,
 	ack_semaphore=0;
+#ifdef WAIT
+static int  wait_semaphore=0;
+#endif
 /* and the maximum number of semaphores in the entry_semaphore set */
 static int sem_nr;
 /* timer group locks */
@@ -166,6 +169,11 @@ again:
 			semctl(reply_semaphore, 0 , IPC_RMID , 0 );
 		if (ack_semaphore>0)
 			semctl(reply_semaphore, 0 , IPC_RMID , 0 );
+#ifdef WAIT
+		if (wait_semaphore>0)
+			semctl(wait_semaphore, 0 , IPC_RMID , 0 );
+#endif
+
 
 		if (i==0){
 			LOG(L_CRIT, "lock_initialize: could not allocate semaphore"
@@ -236,6 +244,23 @@ again:
 		}
 	}
 
+#ifdef WAIT
+	if ((wait_semaphore=init_semaphore_set(sem_nr))<0){
+		if (errno==EINVAL || errno==ENOSPC ) {
+			DBG( "DEBUG:lock_initialize: wait semaphore initialization"
+				" failure: %s\n", strerror(errno));
+			probe_run==1;
+			i--;
+			goto again;
+		}else{
+			LOG(L_CRIT, "ERROR:lock_initialize: wait semaphore initialization"
+				" failure: %s\n", strerror(errno));
+			goto error;
+		}
+	}
+#endif
+
+
 
 
 	/* return success */
@@ -280,8 +305,18 @@ void lock_cleanup()
 	if (ack_semaphore > 0 &&
 	    semctl( ack_semaphore, 0 , IPC_RMID , 0 )==-1)
 		LOG(L_ERR, "ERROR: lock_cleanup, ack_semaphore cleanup failed\n");
+#ifdef WAIT
+	if (wait_semaphore > 0 &&
+		semctl( wait_semaphore, 0 , IPC_RMID , 0 )==-1)
+		LOG(L_ERR, "ERROR: lock_cleanup, wait_semaphore cleanup failed\n");
+#endif
+
 
 	entry_semaphore = timer_semaphore = reply_semaphore = ack_semaphore = 0;
+#ifdef WAIT
+	wait_semaphore = 0;
+#endif
+
 
 }
 #endif /*FAST_LOCK*/
@@ -329,13 +364,20 @@ int init_cell_lock( struct cell *cell )
 #ifdef FAST_LOCK
 	init_lock(cell->reply_mutex);
 	init_lock(cell->ack_mutex);
+#ifdef WAIT
+	init_lock(cell->wait_mutex);
+#endif
 	return 0;
 #else
 	cell->reply_mutex.semaphore_set=reply_semaphore;
 	cell->reply_mutex.semaphore_index = cell->hash_index % sem_nr;
 	cell->ack_mutex.semaphore_set=ack_semaphore;
 	cell->ack_mutex.semaphore_index = cell->hash_index % sem_nr;
-#endif
+#ifdef WAIT
+	cell->wait_mutex.semaphore_set=wait_semaphore;
+	cell->wait_mutex.semaphore_index = cell->hash_index % sem_nr;
+#endif /* WAIT */
+#endif /* FAST_LOCK */
 	return 0;
 }
 

+ 23 - 289
modules/tm/t_funcs.c

@@ -408,107 +408,6 @@ int t_forward_uri( struct sip_msg* p_msg  )
 #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
-  *              1 - core router relay statelessly
-  */
-int t_on_reply_received( struct sip_msg  *p_msg )
-{
-	unsigned int  branch,len, msg_status, msg_class, save_clone;
-	struct sip_msg *clone, *backup;
-	int relay;
-	int start_fr;
-	int is_invite;
-	struct retrans_buff *rb;
-
-
-	/* make sure we know the assosociated tranaction ... */
-	if (t_check( p_msg  , &branch )==-1) return 1;
-	/* ... if there is no such, tell the core router to forward statelessly */
-	if ( T<=0 ) return 1;
-
-	DBG("DEBUG: t_on_reply_received: Original status =%d\n",T->status);
-
-	/* it can take quite long -- better do it now than later 
-	   inside a reply_lock */
-	if (!(clone=sip_msg_cloner( p_msg ))) {
-		goto error;
-	}
-	msg_status=p_msg->REPLY_STATUS;
-	msg_class=REPLY_CLASS(p_msg);
-	is_invite= T->inbound_request->REQ_METHOD==METHOD_INVITE;
-
-	/* *** stop timers *** */
-	rb=T->outbound_request[branch];
-	/* stop retransmission */
-	reset_timer( hash_table, &(rb->retr_timer));
-	/* stop final response timer only if I got a final response */
-	if ( msg_class>1 )
-		reset_timer( hash_table, &(rb->fr_timer));
-
-	LOCK_REPLIES( T );
-   	/* if a got the first prov. response for an INVITE ->
-	   change FR_TIME_OUT to INV_FR_TIME_UT */
-	start_fr = !T->inbound_response[branch] && msg_class==1 && is_invite;
-
-	/* *** store and relay message as needed *** */
-	relay = t_should_relay_response( T , msg_status, branch, &save_clone );
-
-	if (save_clone) {
-		/* release previously hold message */
-		backup = T->inbound_response[branch];
-		T->inbound_response[branch] = clone;
-		T->tag=&(get_to(clone)->tag_value);
-	} else {
-		backup = NULL;
-		sip_msg_free( clone );
-	}
-
-	if (relay>=0 &&  push_reply_from_uac_to_uas( T, relay)==-1 ) {
-		/* restore original state first */
-		if (save_clone) T->inbound_response[branch] = backup;
-		/* restart FR */
-		start_fr=1;
-		goto cleanup;
-	}
-
-
-	/* *** ACK handling *** */
-	if ( is_invite )
-	{
-		if ( T->outbound_ack[branch] )
-		{   /*retransmit*/
-			SEND_BUFFER( T->outbound_ack[branch] );
-		} else if (msg_class>2 ) {   /*on a non-200 reply to INVITE*/
-           		DBG("DEBUG: t_on_reply_received: >=3xx reply to INVITE: send ACK\n");
-           		if ( t_build_and_send_ACK( T , branch , p_msg )==-1)
-           		{
-               		LOG( L_ERR , "ERROR: t_on_reply_received: unable to send ACK\n" );
-					/* restart FR */
-					start_fr=1;
-           		}
-       		}
-   	}
-cleanup:
-	UNLOCK_REPLIES( T );
-	if (backup) sip_msg_free(backup);
-	if (start_fr) set_timer( hash_table, &(rb->fr_timer), FR_INV_TIMER_LIST );
-   	/* restart retransmission if a provisional response came for 
-	   a non_INVITE -> retrasmit at RT_T2*/
-	if ( msg_class==1 && !is_invite )
-	{
-		rb->retr_list = RT_T2;
-		set_timer( hash_table, &(rb->retr_timer), RT_T2 );
-	}
-error:
-	T_UNREF( T );
-	/* don't try to relay statelessly on error; on troubles, simply do nothing;
-           that will make the other party to retransmit; hopefuly, we'll then 
-           be better off */
-	return 0;
-}
-
 #ifdef _OBSOLETED_TM
 int t_on_request_received( struct sip_msg  *p_msg , 
 	unsigned int ip , unsigned int port)
@@ -612,30 +511,6 @@ int t_release_transaction( struct sip_msg* p_msg)
 
 
 
-/* Retransmits the last sent inbound reply.
-
-  * input: p_msg==request for which I want to retransmit an associated
-    reply
-  * Returns  -1 -error
-  *                1 - OK
-  */
-int t_retransmit_reply( struct sip_msg* p_msg   )
-{
-/*	if (t_check( p_msg  , 0 )==-1) return 1; */
-
-   /* if no transaction exists or no reply to be resend -> out */
-/*   if ( T ) */
-   {
-	LOCK_REPLIES( T );
-	SEND_BUFFER( & T->outbound_response );
-	UNLOCK_REPLIES( T );
-	return 1;
-   }
-
-  /* no transaction found */
-/*   return -1; */
-}
-
 
 
 
@@ -651,170 +526,6 @@ int t_unref( /* struct sip_msg* p_msg */ )
 
 
 
-/* Force a new response into inbound response buffer.
-  * returns 1 if everything was OK or -1 for erro
-  */
-int t_send_reply(  struct sip_msg* p_msg , unsigned int code , char * text )
-{
-	unsigned int len, buf_len;
-	char * buf, *shbuf;
-	struct retrans_buff *rb;
-
-	DBG("DEBUG: t_send_reply: entered\n");
-	/* if (t_check( p_msg , 0 )==-1) return -1;
-
-	if (!T)
-	{
-		LOG(L_ERR, "ERROR: t_send_reply: cannot send a t_reply to a message "
-			"for which no T-state has been established\n");
-		return -1;
-	}
-	*/
-
-	buf = build_res_buf_from_sip_req(code,text,0,0,T->inbound_request,&len);
-	DBG("DEBUG: t_send_reply: buffer computed\n");
-	if (!buf)
-	{
-		DBG("DEBUG: t_send_reply: response building failed\n");
-		goto error;
-	}
-
-	LOCK_REPLIES( T );
-
-	rb = & T->outbound_response;
-	if (!rb->retr_buffer) {
-		/* initialize retransmission structure */
-		memset( rb , 0 , sizeof (struct retrans_buff) );
-		if (update_sock_struct_from_via(  &(rb->to),  p_msg->via1 )==-1)
-		{
-			LOG(L_ERR, "ERROR: t_send_reply: cannot lookup reply dst: %s\n",
-				p_msg->via1->host.s );
-			goto error2;
-		}
-
-		rb->retr_timer.tg=TG_RT;
-		rb->fr_timer.tg=TG_FR;
-		rb->retr_timer.payload = rb;
-		rb->fr_timer.payload = rb;
-		rb->to.sin_family = AF_INET;
-		rb->my_T = T;
-		rb->reply = code;
-	}
-
-
-	/* if this is a first reply (?100), longer replies will probably follow;
-	   try avoiding shm_resize by higher buffer size */
-	buf_len = rb->retr_buffer ? len : len + REPLY_OVERBUFFER_LEN;
-
-	if (! (rb->retr_buffer = (char*)shm_resize( rb->retr_buffer, buf_len )))
-	{
-		LOG(L_ERR, "ERROR: t_send_reply: cannot allocate shmem buffer\n");
-		goto error2;
-	}
-	rb->bufflen = len ;
-	memcpy( rb->retr_buffer , buf , len );
-	T->status = code;
-	SEND_BUFFER( rb );
-	/* needs to be protected too because what timers are set depends
-	   on current transactions status
-	*/
-	t_update_timers_after_sending_reply( rb );
-	UNLOCK_REPLIES( T );
-
-	free( buf ) ;
-	/* start/stops the proper timers*/
-
-	DBG("DEBUG: t_send_reply: finished\n");
-
-	return 1;
-
-error2:
-	free ( buf );
-error:
-	return -1;
-}
-
-
-
-/* Push a previously stored reply from UA Client to UA Server
-  * and send it out
-  */
-static int push_reply_from_uac_to_uas( struct cell* trans , unsigned int branch )
-{
-	char *buf;
-	unsigned int len, buf_len;
-	struct retrans_buff *rb;
-
-	DBG("DEBUG: push_reply_from_uac_to_uas: start\n");
-	rb= & trans->outbound_response;
-	/* if there is a reply, release the buffer (everything else stays same) */
-	if ( ! rb->retr_buffer ) {
-		/*init retrans buffer*/
-		memset( rb , 0 , sizeof (struct retrans_buff) );
-		if (update_sock_struct_from_via(  &(rb->to),
-			trans->inbound_response[branch]->via2 )==-1) {
-				LOG(L_ERR, "ERROR: push_reply_from_uac_to_uas: "
-					"cannot lookup reply dst: %s\n",
-				trans->inbound_response[branch]->via2->host.s );
-				goto error;
-		}
-		rb->retr_timer.tg=TG_RT;
-		rb->fr_timer.tg=TG_FR;
-		rb->retr_timer.payload = rb;
-		rb->fr_timer.payload =  rb;
-		rb->to.sin_family = AF_INET;
-		rb->my_T = trans;
-		rb->reply = trans->inbound_response[branch]->REPLY_STATUS;
-
-	} else {
-		reset_timer( hash_table, &(rb->retr_timer));
-		reset_timer( hash_table, &(rb->fr_timer));
-	}
-
-	/*  generate the retrans buffer */
-	buf = build_res_buf_from_sip_res ( trans->inbound_response[branch], &len);
-	if (!buf) {
-		LOG(L_ERR, "ERROR: push_reply_from_uac_to_uas: "
-			"no shmem for outbound reply buffer\n");
-		goto error;
-	}
-
-	/* if this is a first reply (?100), longer replies will probably follow;
-	try avoiding shm_resize by higher buffer size */
-	buf_len = rb->retr_buffer ? len : len + REPLY_OVERBUFFER_LEN;
-	if (! (rb->retr_buffer = (char*)shm_resize( rb->retr_buffer, buf_len )))
-	{
-		LOG(L_ERR, "ERROR: t_send_reply: cannot allocate shmem buffer\n");
-		goto error1;
-	}
-	rb->bufflen = len ;
-	memcpy( rb->retr_buffer , buf , len );
-	free( buf ) ;
-
-	/* update the status*/
-	trans->status = trans->inbound_response[branch]->REPLY_STATUS;
-	if ( trans->inbound_response[branch]->REPLY_STATUS>=200 &&
-		trans->relaied_reply_branch==-1 ) {
-
-		memcpy( & trans->ack_to, & trans->outbound_request[ branch ]->to,
-			sizeof( struct sockaddr_in ) );
-		trans->relaied_reply_branch = branch;
-	}
-
-	/* start/stops the proper timers*/
-	t_update_timers_after_sending_reply( rb );
-
-	/*send the reply*/
-	SEND_BUFFER( rb );
-	return 1;
-
-error1:
-	free( buf );
-error:
-	return -1;
-}
-
-
 
 
 
@@ -941,11 +652,30 @@ int t_put_on_wait(  struct cell  *Trans  )
 	unsigned int i;
 	struct retrans_buff* rb;
 
+#ifndef WAIT
 	if (is_in_timer_list2( &(Trans->wait_tl)))
   	{
 		DBG("DEBUG: t_put_on_wait: already on wait\n");
 		return 1;
 	}
+#else
+	/* have some race conditons occured and we already
+	  entered/passed the wait status previously?
+	  if so, exit now
+	*/
+
+	LOCK_WAIT(T);
+	if (Trans->on_wait)
+	{
+		DBG("DEBUG: t_put_on_wait: already on wait\n");
+		UNLOCK_WAIT(T);
+		return 1;
+	} else {
+		Trans->on_wait=1;
+		UNLOCK_WAIT(T);
+	};
+#endif
+
 
 	/* remove from  retranssmision  and  final response   list */
 	DBG("DEBUG: t_put_on_wait: stopping timers (FR and RETR)\n");
@@ -1402,9 +1132,13 @@ void retransmission_handler( void *attr)
 	/* retransmision */
 	DBG("DEBUG: retransmission_handler : resending (t=%p)\n", r_buf->my_T);
 	if (r_buf->reply) {
+		T=r_buf->my_T;
+/*
 		LOCK_REPLIES( r_buf->my_T );
 		SEND_BUFFER( r_buf );
 		UNLOCK_REPLIES( r_buf->my_T );
+*/
+		t_retransmit_reply();
 	}else{
 		SEND_BUFFER( r_buf );
 	}

+ 37 - 5
modules/tm/t_funcs.h

@@ -33,16 +33,35 @@ extern struct s_table*  hash_table;
 #include "sip_msg.h"
 
 
-#define LOCK_REPLIES(_t) lock(&((_t)->reply_mutex) )
-#define UNLOCK_REPLIES(_t) unlock(&((_t)->reply_mutex) )
-#define LOCK_ACK(_t) lock(&((_t)->ack_mutex) )
-#define UNLOCK_ACK(_t) unlock(&((_t)->ack_mutex) )
+#define LOCK_REPLIES(_t) lock(&(_t)->reply_mutex )
+#define UNLOCK_REPLIES(_t) unlock(&(_t)->reply_mutex )
+#define LOCK_ACK(_t) lock(&(_t)->ack_mutex )
+#define UNLOCK_ACK(_t) unlock(&(_t)->ack_mutex )
+#define LOCK_WAIT(_t) lock(&(_t)->wait_mutex )
+#define UNLOCK_WAIT(_t) unlock(&(_t)->wait_mutex )
 
 
 /* convenience short-cut macros */
 #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)
+
+/* send a private buffer: utilize a retransmission structure
+   but take a separate buffer not refered by it; healthy
+   for reducing time spend in REPLIES locks
+*/
+
+#define SEND_PR_BUFFER(_rb,_bf,_le ) ({ if ((_rb)->retr_buffer) \
+	{ udp_send( (_bf), (_le), (struct sockaddr*)&((_rb)->to) , \
+	   sizeof(struct sockaddr_in) ); \
+	} else { \
+	DBG("ERROR: attempt to send an empty buffer from %s (%d)", \
+	__FUNCTION__, __LINE__ ); }})
+
+#define SEND_BUFFER( _rb ) SEND_PR_BUFFER( \
+	_rb,(_rb)->retr_buffer, (_rb)->bufflen )
+
+/*
 #define SEND_BUFFER( _rb ) ({ if ((_rb)->retr_buffer) \
 	{ udp_send( (_rb)->retr_buffer, \
 	  (_rb)->bufflen, (struct sockaddr*)&((_rb)->to) , \
@@ -50,6 +69,7 @@ extern struct s_table*  hash_table;
 	} else \
 	DBG("ERROR: attempt to send an empty buffer from %s (%d)", \
 	__FUNCTION__, __LINE__ ); })
+*/
 
 
 /* 
@@ -165,7 +185,12 @@ int t_forward_uri( struct sip_msg* p_msg  );
   *  Returns :   0 - core router stops
   *                    1 - core router relay statelessly
   */
+
+#ifdef SRL
+int t_on_reply( struct sip_msg  *p_msg ) ;
+#else
 int t_on_reply_received( struct sip_msg  *p_msg ) ;
+#endif
 
 
 
@@ -201,7 +226,7 @@ int t_release_transaction( struct sip_msg* );
   * Returns  -1 -error
   *                1 - OK
   */
-int t_retransmit_reply( struct sip_msg *  );
+int t_retransmit_reply( /* struct sip_msg * */  );
 
 
 
@@ -234,7 +259,14 @@ int t_should_relay_response( struct cell *Trans, int new_code, int branch, int *
 int t_update_timers_after_sending_reply( struct retrans_buff *rb );
 int t_put_on_wait(  struct cell  *Trans  );
 int relay_lowest_reply_upstream( struct cell *Trans , struct sip_msg *p_msg );
+
+#ifdef SRL
+static int push_reply( struct cell* trans , unsigned int branch , 
+    char *buf, unsigned int len);
+#else
 static int push_reply_from_uac_to_uas( struct cell* Trans , unsigned int );
+#endif
+
 int add_branch_label( struct cell *Trans, struct sip_msg *p_msg , int branch );
 int get_ip_and_port_from_uri( struct sip_msg* p_msg , unsigned int *param_ip, unsigned int *param_port);
 

+ 15 - 11
modules/tm/t_fwd.c

@@ -33,11 +33,11 @@ int t_forward_nonack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
 
 	if ( T->outbound_request[branch]==NULL )
 	{
-		DBG("DEBUG: t_forward: first time forwarding\n");
+		DBG("DEBUG: t_forward_nonack: first time forwarding\n");
 		/* special case : CANCEL */
 		if ( p_msg->REQ_METHOD==METHOD_CANCEL  )
 		{
-			DBG("DEBUG: t_forward: it's CANCEL\n");
+			DBG("DEBUG: t_forward_nonack: it's CANCEL\n");
 			/* find original cancelled transaction; if found, use its
 			   next-hops; otherwise use those passed by script */
 			if ( T->T_canceled==T_UNDEFINED )
@@ -48,7 +48,7 @@ int t_forward_nonack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
 				/* if in 1xx status, send to the same destination */
 				if ( (T->T_canceled->status/100)==1 )
 				{
-					DBG("DEBUG: t_forward: it's CANCEL and I will send "
+					DBG("DEBUG: t_forward_nonack: it's CANCEL and I will send "
 						"to the same place where INVITE went\n");
 					dest_ip=T->T_canceled->outbound_request[branch]->
 						to.sin_addr.s_addr;
@@ -59,12 +59,12 @@ int t_forward_nonack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
 					T->label  = T->T_canceled->label;
 #endif
 				} else { /* transaction exists, but nothing to cancel */
-					DBG("DEBUG: t_forward: it's CANCEL but "
+					DBG("DEBUG: t_forward_nonack: it's CANCEL but "
 						"I have nothing to cancel here\n");
 					/* forward CANCEL as a stand-alone transaction */
 				}
 			} else { /* transaction doesnot exists  */
-				DBG("DEBUG: t_forward: canceled request not found! "
+				DBG("DEBUG: t_forward_nonack: canceled request not found! "
 				"nothing to CANCEL\n");
 			}
 		}/* end special case CANCEL*/
@@ -77,19 +77,19 @@ int t_forward_nonack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
 			goto error;
 
 		/* allocates a new retrans_buff for the outbound request */
-		DBG("DEBUG: t_forward: building outbound request\n");
+		DBG("DEBUG: t_forward_nonack: building outbound request\n");
 		shm_lock();
 		rb = (struct retrans_buff*) shm_malloc_unsafe( sizeof(struct retrans_buff)  );
 		if (!rb)
 		{
-			LOG(L_ERR, "ERROR: t_forward: out of shmem\n");
+			LOG(L_ERR, "ERROR: t_forward_nonack: out of shmem\n");
 			shm_unlock();
 			goto error;
 		}
 		shbuf = (char *) shm_malloc_unsafe( len );
 		if (!shbuf)
 		{
-			LOG(L_ERR, "ERROR: t_forward: out of shmem buffer\n");
+			LOG(L_ERR, "ERROR: t_forward_nonack: out of shmem buffer\n");
 			shm_unlock();
 			goto error;
 		}
@@ -114,9 +114,11 @@ int t_forward_nonack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
 		/* link the retransmission buffer to our structures when the job is done */
 		free( buf ) ; buf=NULL;
 
-		DBG("DEBUG: t_forward: starting timers (retrans and FR) %d\n",get_ticks() );
+		DBG("DEBUG: t_forward_nonack: starting timers (retrans and FR) %d\n",get_ticks() );
 		/*sets and starts the FINAL RESPONSE timer */
+#ifdef FR
 		set_timer( hash_table, &(rb->fr_timer), FR_TIMER_LIST );
+#endif
 
 		/* sets and starts the RETRANS timer */
 		rb->retr_list = RT_T1_TO_1;
@@ -132,12 +134,14 @@ int t_forward_nonack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
 
 	if (  p_msg->REQ_METHOD==METHOD_CANCEL )
 	{
-		DBG("DEBUG: t_forward: forwarding CANCEL\n");
+		DBG("DEBUG: t_forward_nonack: forwarding CANCEL\n");
 		/* if no transaction to CANCEL */
 		/* or if the canceled transaction has a final status -> drop the CANCEL*/
 		if ( T->T_canceled!=T_NULL && T->T_canceled->status>=200)
 		{
+#ifdef FR
 			reset_timer( hash_table, &(rb->fr_timer ));
+#endif
 			reset_timer( hash_table, &(rb->retr_timer ));
 			return 1;
 		}
@@ -182,7 +186,7 @@ int t_forward_ack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
 		return -1;
 	}
 
-	DBG("DEBUG: t_forward: forwarding ACK [%d]\n",branch);
+	DBG("DEBUG: t_forward_ack: forwarding ACK [%d]\n",branch);
 	/* not able to build branch -- then better give up */
 	if ( add_branch_label( T, p_msg , branch )==-1) {
 		LOG( L_ERR, "ERROR: t_forward_ack failed to add branch label\n" );

+ 520 - 0
modules/tm/t_reply.c

@@ -0,0 +1,520 @@
+/*
+ * $Id$
+ *
+ */
+
+
+#include "hash_func.h"
+#include "t_funcs.h"
+#include "../../dprint.h"
+#include "../../config.h"
+#include "../../parser_f.h"
+#include "../../ut.h"
+#include "../../timer.h"
+
+#ifndef SRL
+/*  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
+  *              1 - core router relay statelessly
+  */
+int t_on_reply_received( struct sip_msg  *p_msg )
+{
+	unsigned int  branch,len, msg_status, msg_class, save_clone;
+	struct sip_msg *clone, *backup;
+	int relay;
+	int start_fr;
+	int is_invite;
+	struct retrans_buff *rb;
+
+
+	/* make sure we know the assosociated tranaction ... */
+	if (t_check( p_msg  , &branch )==-1) return 1;
+	/* ... if there is no such, tell the core router to forward statelessly */
+	if ( T<=0 ) return 1;
+
+	DBG("DEBUG: t_on_reply_received: Original status =%d\n",T->status);
+
+	/* it can take quite long -- better do it now than later 
+	   inside a reply_lock */
+	if (!(clone=sip_msg_cloner( p_msg ))) {
+		goto error;
+	}
+	msg_status=p_msg->REPLY_STATUS;
+	msg_class=REPLY_CLASS(p_msg);
+	is_invite= T->inbound_request->REQ_METHOD==METHOD_INVITE;
+
+	/* *** stop timers *** */
+	rb=T->outbound_request[branch];
+	/* stop retransmission */
+	reset_timer( hash_table, &(rb->retr_timer));
+	/* stop final response timer only if I got a final response */
+	if ( msg_class>1 )
+		reset_timer( hash_table, &(rb->fr_timer));
+
+	LOCK_REPLIES( T );
+   	/* if a got the first prov. response for an INVITE ->
+	   change FR_TIME_OUT to INV_FR_TIME_UT */
+	start_fr = !T->inbound_response[branch] && msg_class==1 && is_invite;
+
+	/* *** store and relay message as needed *** */
+	relay = t_should_relay_response( T , msg_status, branch, &save_clone );
+
+	if (save_clone) {
+		/* release previously hold message */
+		backup = T->inbound_response[branch];
+		T->inbound_response[branch] = clone;
+		T->tag=&(get_to(clone)->tag_value);
+	} else {
+		backup = NULL;
+		sip_msg_free( clone );
+	}
+
+	if (relay>=0 &&  
+	push_reply_from_uac_to_uas( T, relay  ) == -1 ) {
+		/* restore original state first */
+		if (save_clone) T->inbound_response[branch] = backup;
+		/* restart FR */
+		start_fr=1;
+		goto cleanup;
+	}
+
+
+	/* *** ACK handling *** */
+	if ( is_invite )
+	{
+		if ( T->outbound_ack[branch] )
+		{   /*retransmit*/
+			SEND_BUFFER( T->outbound_ack[branch] );
+		} else if (msg_class>2 ) {   /*on a non-200 reply to INVITE*/
+           		DBG("DEBUG: t_on_reply_received: >=3xx reply to INVITE: send ACK\n");
+           		if ( t_build_and_send_ACK( T , branch , p_msg )==-1)
+           		{
+               		LOG( L_ERR , "ERROR: t_on_reply_received: unable to send ACK\n" );
+					/* restart FR */
+					start_fr=1;
+           		}
+       		}
+   	}
+cleanup:
+	UNLOCK_REPLIES( T );
+	if (backup) sip_msg_free(backup);
+	if (start_fr) set_timer( hash_table, &(rb->fr_timer), FR_INV_TIMER_LIST );
+   	/* restart retransmission if a provisional response came for 
+	   a non_INVITE -> retrasmit at RT_T2*/
+	if ( msg_class==1 && !is_invite )
+	{
+		rb->retr_list = RT_T2;
+		set_timer( hash_table, &(rb->retr_timer), RT_T2 );
+	}
+error:
+	T_UNREF( T );
+	/* don't try to relay statelessly on error; on troubles, simply do nothing;
+           that will make the other party to retransmit; hopefuly, we'll then 
+           be better off */
+	return 0;
+}
+#endif
+
+
+
+/* Retransmits the last sent inbound reply.
+
+  * input: p_msg==request for which I want to retransmit an associated
+    reply
+  * Returns  -1 -error
+  *                1 - OK
+  */
+int t_retransmit_reply( /* struct sip_msg* p_msg    */ )
+{
+
+#ifdef SRL
+	void *b;
+	int len;
+#endif
+	LOCK_REPLIES( T );
+
+#ifdef SRL
+	if (!(b=pkg_malloc( len=T->outbound_response.bufflen ))) {
+		UNLOCK_REPLIES( T );
+		return -1;
+	};
+	memcpy( b, T->outbound_response.retr_buffer, len );
+#else
+	SEND_BUFFER( & T->outbound_response );
+#endif
+	UNLOCK_REPLIES( T );
+
+#ifdef SRL
+	SEND_PR_BUFFER( & T->outbound_response, b, len );
+	pkg_free( b );
+#endif
+	return 1;
+}
+
+/* Force a new response into inbound response buffer.
+  * returns 1 if everything was OK or -1 for erro
+  */
+int t_send_reply(  struct sip_msg* p_msg , unsigned int code , char * text )
+{
+	unsigned int len, buf_len;
+	char * buf, *shbuf;
+	struct retrans_buff *rb;
+
+	DBG("DEBUG: t_send_reply: entered\n");
+
+	buf = build_res_buf_from_sip_req(code,text,0,0,T->inbound_request,&len);
+	DBG("DEBUG: t_send_reply: buffer computed\n");
+	if (!buf)
+	{
+		DBG("DEBUG: t_send_reply: response building failed\n");
+		goto error;
+	}
+
+	LOCK_REPLIES( T );
+
+	rb = & T->outbound_response;
+	if (!rb->retr_buffer) {
+		/* initialize retransmission structure */
+		memset( rb , 0 , sizeof (struct retrans_buff) );
+		if (update_sock_struct_from_via(  &(rb->to),  p_msg->via1 )==-1)
+		{
+			UNLOCK_REPLIES( T );
+			LOG(L_ERR, "ERROR: t_send_reply: cannot lookup reply dst: %s\n",
+				p_msg->via1->host.s );
+			goto error2;
+		}
+
+		rb->retr_timer.tg=TG_RT;
+		rb->fr_timer.tg=TG_FR;
+		rb->retr_timer.payload = rb;
+		rb->fr_timer.payload = rb;
+		rb->to.sin_family = AF_INET;
+		rb->my_T = T;
+		rb->reply = code;
+	}
+
+
+	/* if this is a first reply (?100), longer replies will probably follow;
+	   try avoiding shm_resize by higher buffer size */
+	buf_len = rb->retr_buffer ? len : len + REPLY_OVERBUFFER_LEN;
+
+	if (! (rb->retr_buffer = (char*)shm_resize( rb->retr_buffer, buf_len )))
+	{
+		UNLOCK_REPLIES( T );
+		LOG(L_ERR, "ERROR: t_send_reply: cannot allocate shmem buffer\n");
+		goto error2;
+	}
+	rb->bufflen = len ;
+	memcpy( rb->retr_buffer , buf , len );
+	T->status = code;
+#ifndef SRL
+	SEND_BUFFER( rb );
+#endif
+	/* needs to be protected too because what timers are set depends
+	   on current transactions status
+	*/
+	t_update_timers_after_sending_reply( rb );
+	UNLOCK_REPLIES( T );
+
+#ifdef SRL
+	SEND_PR_BUFFER( rb, buf, len );
+#endif
+
+	free( buf ) ;
+	/* start/stops the proper timers*/
+
+	DBG("DEBUG: t_send_reply: finished\n");
+
+	return 1;
+
+error2:
+	free ( buf );
+error:
+	return -1;
+}
+
+
+
+
+/* Push a previously stored reply from UA Client to UA Server
+  * and send it out
+  */
+static int push_reply_from_uac_to_uas( struct cell* trans , unsigned int branch 
+#ifdef SRL
+	, char *buf, unsigned int len
+#endif
+	)
+{
+	unsigned int buf_len;
+	struct retrans_buff *rb;
+#ifndef SRL
+	char *buf;
+	unsigned int len;
+#endif
+
+	DBG("DEBUG: push_reply_from_uac_to_uas: start\n");
+	rb= & trans->outbound_response;
+	/* if there is a reply, release the buffer (everything else stays same) */
+	if ( ! rb->retr_buffer ) {
+		/*init retrans buffer*/
+		memset( rb , 0 , sizeof (struct retrans_buff) );
+		if (update_sock_struct_from_via(  &(rb->to),
+			trans->inbound_response[branch]->via2 )==-1) {
+				LOG(L_ERR, "ERROR: push_reply_from_uac_to_uas: "
+					"cannot lookup reply dst: %s\n",
+				trans->inbound_response[branch]->via2->host.s );
+				goto error;
+		}
+		rb->retr_timer.tg=TG_RT;
+		rb->fr_timer.tg=TG_FR;
+		rb->retr_timer.payload = rb;
+		rb->fr_timer.payload =  rb;
+		rb->to.sin_family = AF_INET;
+		rb->my_T = trans;
+		rb->reply = trans->inbound_response[branch]->REPLY_STATUS;
+
+	} else {
+#ifndef SRL
+		reset_timer( hash_table, &(rb->retr_timer));
+		reset_timer( hash_table, &(rb->fr_timer));
+#endif
+	}
+
+#ifndef SRL
+	/*  generate the retrans buffer */
+	buf = build_res_buf_from_sip_res ( trans->inbound_response[branch], &len);
+	if (!buf) {
+		LOG(L_ERR, "ERROR: push_reply_from_uac_to_uas: "
+			"no shmem for outbound reply buffer\n");
+		goto error;
+	}
+#endif
+
+	/* if this is a first reply (?100), longer replies will probably follow;
+	try avoiding shm_resize by higher buffer size */
+	buf_len = rb->retr_buffer ? len : len + REPLY_OVERBUFFER_LEN;
+	if (! (rb->retr_buffer = (char*)shm_resize( rb->retr_buffer, buf_len )))
+	{
+		LOG(L_ERR, "ERROR: t_push: cannot allocate shmem buffer\n");
+		goto error1;
+	}
+	rb->bufflen = len ;
+	memcpy( rb->retr_buffer , buf , len );
+#ifndef SRL
+	free( buf ) ;
+#endif
+
+	/* update the status*/
+	trans->status = trans->inbound_response[branch]->REPLY_STATUS;
+	if ( trans->inbound_response[branch]->REPLY_STATUS>=200 &&
+		trans->relaied_reply_branch==-1 ) {
+
+		memcpy( & trans->ack_to, & trans->outbound_request[ branch ]->to,
+			sizeof( struct sockaddr_in ) );
+		trans->relaied_reply_branch = branch;
+	}
+
+#ifndef SRL
+	/* start/stops the proper timers*/
+	t_update_timers_after_sending_reply( rb );
+#endif
+
+	/*send the reply*/
+	SEND_BUFFER( rb );
+	return 1;
+
+error1:
+#ifndef SRL
+	free( buf );
+#endif
+error:
+	return -1;
+}
+
+/* Push a previously stored reply from UA Client to UA Server
+  * and send it out
+  */
+static int push_reply( struct cell* trans , unsigned int branch , 
+	char *buf, unsigned int len)
+{
+	unsigned int buf_len;
+	struct retrans_buff *rb;
+
+	DBG("DEBUG: push_reply_from_uac_to_uas: start\n");
+	rb= & trans->outbound_response;
+	/* if there is a reply, release the buffer (everything else stays same) */
+	if ( ! rb->retr_buffer ) {
+		/*init retrans buffer*/
+		memset( rb , 0 , sizeof (struct retrans_buff) );
+		if (update_sock_struct_from_via(  &(rb->to),
+			trans->inbound_response[branch]->via2 )==-1) {
+				LOG(L_ERR, "ERROR: push_reply_from_uac_to_uas: "
+					"cannot lookup reply dst: %s\n",
+				trans->inbound_response[branch]->via2->host.s );
+				goto error;
+		}
+		rb->retr_timer.tg=TG_RT;
+		rb->fr_timer.tg=TG_FR;
+		rb->retr_timer.payload = rb;
+		rb->fr_timer.payload =  rb;
+		rb->to.sin_family = AF_INET;
+		rb->my_T = trans;
+		rb->reply = trans->inbound_response[branch]->REPLY_STATUS;
+	};
+
+	/* if this is a first reply (?100), longer replies will probably follow;
+	try avoiding shm_resize by higher buffer size */
+	buf_len = rb->retr_buffer ? len : len + REPLY_OVERBUFFER_LEN;
+	if (! (rb->retr_buffer = (char*)shm_resize( rb->retr_buffer, buf_len )))
+	{
+		LOG(L_ERR, "ERROR: t_push: cannot allocate shmem buffer\n");
+		goto error1;
+	}
+	rb->bufflen = len ;
+	memcpy( rb->retr_buffer , buf , len );
+
+	/* update the status*/
+	trans->status = trans->inbound_response[branch]->REPLY_STATUS;
+	if ( trans->inbound_response[branch]->REPLY_STATUS>=200 &&
+		trans->relaied_reply_branch==-1 ) {
+
+		memcpy( & trans->ack_to, & trans->outbound_request[ branch ]->to,
+			sizeof( struct sockaddr_in ) );
+		trans->relaied_reply_branch = branch;
+	}
+
+	/*send the reply*/
+	SEND_BUFFER( rb );
+	return 1;
+
+error1:
+error:
+	return -1;
+}
+
+#ifdef SRL
+/*  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
+  *              1 - core router relay statelessly
+  */
+int t_on_reply( struct sip_msg  *p_msg )
+{
+	unsigned int  branch,len, msg_status, msg_class, save_clone;
+	struct sip_msg *clone, *backup;
+	int relay;
+	int start_fr;
+	int is_invite;
+	struct retrans_buff *rb;
+	char *buf;
+	unsigned int buf_len;
+
+
+	/* make sure we know the assosociated tranaction ... */
+	if (t_check( p_msg  , &branch )==-1) return 1;
+	/* ... if there is no such, tell the core router to forward statelessly */
+	if ( T<=0 ) return 1;
+
+	DBG("DEBUG: t_on_reply_received: Original status =%d\n",T->status);
+
+	/* it can take quite long -- better do it now than later 
+	   inside a reply_lock */
+	if (!(clone=sip_msg_cloner( p_msg ))) {
+		goto error;
+	}
+	msg_status=p_msg->REPLY_STATUS;
+	msg_class=REPLY_CLASS(p_msg);
+	is_invite= T->inbound_request->REQ_METHOD==METHOD_INVITE;
+
+    /*  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
+		work to be done out of criticial lock region
+	 */
+	if (msg_status==100) buf=0;
+	else {
+		buf = build_res_buf_from_sip_res ( p_msg, &buf_len);
+		if (!buf) {
+			LOG(L_ERR, "ERROR: t_on_reply_received: "
+			"no mem for outbound reply buffer\n");
+			sip_msg_free( clone );
+			goto error;
+		}
+	}
+
+	/* *** stop timers *** */
+	rb=T->outbound_request[branch];
+	/* stop retransmission */
+	reset_timer( hash_table, &(rb->retr_timer));
+	/* stop final response timer only if I got a final response */
+	if ( msg_class>1 )
+		reset_timer( hash_table, &(rb->fr_timer));
+
+	LOCK_REPLIES( T );
+   	/* if a got the first prov. response for an INVITE ->
+	   change FR_TIME_OUT to INV_FR_TIME_UT */
+	start_fr = !T->inbound_response[branch] && msg_class==1 && is_invite;
+
+	/* *** store and relay message as needed *** */
+	relay = t_should_relay_response( T , msg_status, branch, &save_clone );
+
+	if (save_clone) {
+		/* release previously hold message */
+		backup = T->inbound_response[branch];
+		T->inbound_response[branch] = clone;
+		T->tag=&(get_to(clone)->tag_value);
+	} else {
+		backup = NULL;
+		sip_msg_free( clone );
+	}
+
+	if (relay>=0 &&  
+	push_reply( T, relay , buf, buf_len ) == -1 ) {
+		/* restore original state first */
+		if (save_clone) T->inbound_response[branch] = backup;
+		/* restart FR */
+		start_fr=1;
+		goto cleanup;
+	}
+
+
+	/* *** ACK handling *** */
+	if ( is_invite )
+	{
+		if ( T->outbound_ack[branch] )
+		{   /*retransmit*/
+			SEND_BUFFER( T->outbound_ack[branch] );
+		} else if (msg_class>2 ) {   /*on a non-200 reply to INVITE*/
+           		DBG("DEBUG: t_on_reply_received: >=3xx reply to INVITE: send ACK\n");
+           		if ( t_build_and_send_ACK( T , branch , p_msg )==-1)
+           		{
+               		LOG( L_ERR , "ERROR: t_on_reply_received: unable to send ACK\n" );
+					/* restart FR */
+					start_fr=1;
+           		}
+       		}
+   	}
+cleanup:
+	UNLOCK_REPLIES( T );
+	if (backup) sip_msg_free(backup);
+	if (buf) free( buf );
+	t_update_timers_after_sending_reply( rb );
+	if (start_fr) set_timer( hash_table, &(rb->fr_timer), FR_INV_TIMER_LIST );
+   	/* restart retransmission if a provisional response came for 
+	   a non_INVITE -> retrasmit at RT_T2*/
+	if ( msg_class==1 && !is_invite )
+	{
+		rb->retr_list = RT_T2;
+		set_timer( hash_table, &(rb->retr_timer), RT_T2 );
+	}
+error:
+	T_UNREF( T );
+	/* don't try to relay statelessly on error; on troubles, simply do nothing;
+           that will make the other party to retransmit; hopefuly, we'll then 
+           be better off */
+	return 0;
+}
+
+#endif

+ 26 - 0
modules/tm/timer.c

@@ -46,6 +46,16 @@ void print_timer_list(struct s_table* hash_table, enum lists list_id)
 /* static void remove_from_timer_list_dummy(  struct timer_link* tl ) */
 void remove_timer_unsafe(  struct timer_link* tl )
 {
+#ifdef EXTRA_DEBUG
+	if (tl && tl->timer_list &&
+		tl->timer_list->last_tl.prev_tl==0) {
+		LOG( L_CRIT,
+		"CRITICAL : Oh no, zero link in trailing timer element\n");
+		abort();
+	};
+#endif
+
+
 	if (is_in_timer_list2( tl )) {
 		tl->prev_tl->next_tl = tl->next_tl;
 		tl->next_tl->prev_tl = tl->prev_tl;
@@ -61,6 +71,14 @@ void remove_timer_unsafe(  struct timer_link* tl )
 void add_timer_unsafe( struct timer *timer_list,
 	struct timer_link *tl, unsigned int time_out )
 {
+#ifdef EXTRA_DEBUG
+	if (timer_list->last_tl.prev_tl==0) {
+	LOG( L_CRIT,
+		"CRITICAL : Oh no, zero link in trailing timer element\n");
+		abort();
+	};
+#endif
+
 	/*	remove_from_timer_list( tl ); */
 	/* the entire timer list is locked now -- noone else can manipulate it */
 	/* lock( timer_list->mutex ); */
@@ -116,6 +134,14 @@ struct timer_link  *check_and_split_time_list( struct timer *timer_list, int tim
 		timer_list->first_tl.next_tl = tl;	
 		tl->prev_tl = & timer_list->first_tl;
 	}
+#ifdef EXTRA_DEBUG
+	if (timer_list->last_tl.prev_tl==0) {
+		LOG( L_CRIT,
+		"CRITICAL : Oh no, zero link in trailing timer element\n");
+		abort();
+	};
+#endif
+
 
    /* give the list lock away */
    unlock(timer_list->mutex);

+ 5 - 1
modules/tm/tm.c

@@ -129,7 +129,11 @@ static struct module_exports nm_exports= {
 #else
 	10,
 #endif
+#ifdef SRL
+	(response_function) t_on_reply,
+#else
 	(response_function) t_on_reply_received,
+#endif
 	(destroy_function) tm_shutdown,
 	w_onbreak
 };
@@ -358,7 +362,7 @@ static int w_t_unref( struct sip_msg* p_msg, char* foo, char* bar )
 static w_t_retransmit_reply( struct sip_msg* p_msg, char* foo, char* bar  )
 {
 	if (t_check( p_msg  , 0 )==-1) return 1;
-	if (T) return t_retransmit_reply( p_msg );
+	if (T) return t_retransmit_reply( /* p_msg */ );
 	else return -1;
 }
 

+ 11 - 1
msg_parser.h

@@ -30,6 +30,7 @@
 #define HDR_RECORDROUTE  512
 #define HDR_OTHER       65536 /*unknown header type*/
 
+
 /* maximum length of values appended to Via-branch parameter */
 #ifdef USE_SYNONIM
 #define MAX_BRANCH_PARAM_LEN  22
@@ -52,6 +53,12 @@ enum{
 #define get_cseq( p_msg)  ((struct cseq_body*)(p_msg)->cseq->parsed)
 #define get_to( p_msg)      ((struct to_body*)(p_msg)->to->parsed)
 
+#ifdef NEW_HNAME
+#	define parse_hname(_b,_e,_h) parse_hname2((_b),(_e),(_h))
+	void init_htable(void);
+#else
+#	define parse_hname(_b,_e,_h) parse_hname1((_b),(_e),(_h))
+#endif
 
 
 #define INVITE_LEN	6
@@ -233,7 +240,10 @@ int parse_headers(struct sip_msg* msg, int flags);
 void free_uri(struct sip_uri* u);
 
 
-char* parse_hname(char* buf, char* end, struct hdr_field* hdr);
+/* char* parse_hname(char* buf, char* end, struct hdr_field* hdr); */
+char* parse_hname1(char* buf, char* end, struct hdr_field* hdr);
+char* parse_hname2(char* buf, char* end, struct hdr_field* hdr);
+
 char* parse_via(char* buffer, char* end, struct via_body *vb);
 char* parse_to(char* buffer, char* end, struct to_body *to_b);
 char* parse_cseq(char* buffer, char* end, struct cseq_body *cb);

+ 4 - 0
msg_translator.c

@@ -587,10 +587,12 @@ char * build_res_buf_from_sip_req(	unsigned int code ,
 	/*lumps length*/
 	for(lump=msg->reply_lump;lump;lump=lump->next)
 		len += lump->text.len;
+#ifdef NOISY_REPLIES
 	/*user agent header*/
 	len += USER_AGENT_LEN + CRLF_LEN;
 	/*content length header*/
 	len +=CONTENT_LEN_LEN + CRLF_LEN;
+#endif
 	/* end of message */
 	len += CRLF_LEN; /*new line*/
 	/*allocating mem*/
@@ -658,6 +660,7 @@ char * build_res_buf_from_sip_req(	unsigned int code ,
 		p += lump->text.len;
 	}
 	/*user agent header*/
+#ifdef NOISY_REPLIES
 	memcpy( p, USER_AGENT , USER_AGENT_LEN );
 	p+=USER_AGENT_LEN;
 	memcpy( p, CRLF, CRLF_LEN );
@@ -667,6 +670,7 @@ char * build_res_buf_from_sip_req(	unsigned int code ,
 	p+=CONTENT_LEN_LEN;
 	memcpy( p, CRLF, CRLF_LEN );
 	p+=CRLF_LEN;
+#endif
 	/*end of message*/
 	memcpy( p, CRLF, CRLF_LEN );
 	p+=CRLF_LEN;

+ 1 - 1
parse_hname.c

@@ -45,7 +45,7 @@ enum { INITIAL=0,
 
 
 /* returns end or pointer to next elem*/
-char* parse_hname(char* p, char* end, struct hdr_field* hdr)
+char* parse_hname1(char* p, char* end, struct hdr_field* hdr)
 {
 
 	char* t;

+ 741 - 0
parse_hname2.c

@@ -0,0 +1,741 @@
+/* 
+ * TODO: Optimize short variants of headers
+ *       Test, Test, Test....
+ *       Hardwire into ser core
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "msg_parser.h"
+#include "strs.h"
+#include "dprint.h"
+
+/*
+ * Size of hash table, this is magic value
+ * that ensures, that there are no synonyms for
+ * frequently used keys (frequently used keys are
+ * 4-byte parts of message headers we recognize)
+ * WARNING ! This value MUST be recalculated if you want
+ * a new header to be recognized
+ */
+#define HASH_TABLE_SIZE 1471
+
+
+
+
+/*
+ * Hash function
+ */
+#define HASH_FUNC(val) ((val) % HASH_TABLE_SIZE)
+
+
+/*
+ * This constants marks empty hash table element
+ */
+#define HASH_EMPTY 0x2d2d2d2d
+
+
+/*
+ * Hash table entry
+ */
+struct ht_entry {
+	unsigned int key;
+	unsigned int value;
+};
+
+/*
+hash_table = (struct ht_entry*)malloc(HASH_TABLE_SIZE 
+	* sizeof(struct ht_entry));
+*/
+
+static struct ht_entry hash_table[ HASH_TABLE_SIZE ];
+
+/*
+ * Pointer to the hash table
+ */
+/*
+static struct ht_entry *hash_table;
+*/
+
+
+/*
+ * Declarations
+ */
+static inline char* q_memchr    (char* p, int c, unsigned int size);
+static inline char* skip_ws     (char* p, unsigned int size);
+void         init_htable (void);
+static void         set_entry   (unsigned int key, unsigned int val);
+static inline int   unify       (int key);
+
+/*
+ * Fast replacement of standard memchr function
+ */
+static inline char* q_memchr(char* p, int c, unsigned int size)
+{
+	char* end;
+
+	end=p+size;
+	for(;p<end;p++){
+		if (*p==(unsigned char)c) return p;
+	}
+	return 0;
+}
+
+
+/*
+ * Skip all whitechars and return position of the first
+ * non-white char
+ */
+static inline char* skip_ws(char* p, unsigned int size)
+{
+	char* end;
+	
+	end = p + size;
+	for(; p < end; p++) {
+		if ((*p != ' ') && (*p != '\t')) return p;
+	}
+	return p;
+}
+	
+
+/*
+ * Used to initialize hash table
+ */
+static void set_entry(unsigned int key, unsigned int val)
+{
+	hash_table[HASH_FUNC(key)].key = key;
+	hash_table[HASH_FUNC(key)].value = val;
+}
+
+
+/*
+ * cSeQ -> CSeq and so on...
+ */ 
+static inline int unify(int key)
+{
+	register struct ht_entry* en;
+
+	en = &hash_table[HASH_FUNC(key)];
+	if (en->key == key) {
+		return en->value;
+	} else {
+		return key;
+	}
+}
+
+
+#define Via1_CASE         \
+     hdr->type = HDR_VIA; \
+     hdr->name.len = 3;   \
+     *(p + 3) = '\0';     \
+     return p + 4        
+
+
+#define From_CASE          \
+     hdr->type = HDR_FROM; \
+     p += 4;               \
+     goto dc_end          
+                                                             
+
+#define To12_CASE        \
+     hdr->type = HDR_TO; \
+     hdr->name.len = 2;  \
+     *(p + 2) = '\0';    \
+     return (p + 3)
+
+
+#define CSeq_CASE          \
+     hdr->type = HDR_CSEQ; \
+     p += 4;               \
+     goto dc_end
+
+
+#define Call_CASE                      \
+     p += 4;                           \
+     val = READ(p);                    \
+     switch(val) {                     \
+     case _ID1:                        \
+	     hdr->type = HDR_CALLID;   \
+	     hdr->name.len = 7;        \
+	     *(p + 3) = '\0';          \
+	     return (p + 4);           \
+	                               \
+     case _ID2:                        \
+	     hdr->type = HDR_CALLID;   \
+	     p += 4;                   \
+	     goto dc_end;              \
+     }                                 \
+                                       \
+     val = unify(val);                 \
+     switch(val) {                     \
+     case _ID1:                        \
+	     hdr->type = HDR_CALLID;   \
+	     hdr->name.len = 7;        \
+	     *(p + 3) = '\0';          \
+	     return (p + 4);           \
+	                               \
+     case _ID2:                        \
+	     hdr->type = HDR_CALLID;   \
+	     p += 4;                   \
+	     goto dc_end;              \
+                                       \
+     default: goto other;              \
+     }                                 \
+     break
+
+
+#define Cont_CASE                     \
+     p += 4;                          \
+     val = READ(p);                   \
+     switch(val) {                    \
+     case act1:                       \
+	     hdr->type = HDR_CONTACT; \
+	     hdr->name.len = 7;       \
+	     *(p + 3) = '\0';         \
+	     return (p + 7);          \
+	                              \
+     case act2:                       \
+	     hdr->type = HDR_CONTACT; \
+	     p += 4;                  \
+	     goto dc_end;             \
+     }                                \
+                                      \
+     val = unify(val);                \
+     switch(val) {                    \
+     case act1:                       \
+	     hdr->type = HDR_CONTACT; \
+	     hdr->name.len = 7;       \
+	     *(p + 3) = '\0';         \
+	     return (p + 4);          \
+	                              \
+     case act2:                       \
+	     hdr->type = HDR_CONTACT; \
+	     p += 4;                  \
+	     goto dc_end;             \
+                                      \
+     default: goto other;             \
+     }                                \
+     break
+
+
+#define Rout_CASE                   \
+     p += 4;                        \
+     switch(*p) {                   \
+     case 'e':                      \
+     case 'E':                      \
+	     hdr->type = HDR_ROUTE; \
+	     p++;                   \
+	     goto dc_end;           \
+                                    \
+     default:                       \
+	     goto other;            \
+     }                              \
+     break
+
+
+#define Max_CASE                                   \
+     p += 4;                                       \
+     val = READ(p);                                \
+     switch(val) {                                 \
+     case Forw:                                    \
+	     p += 4;                               \
+	     val = READ(p);                        \
+	     if (val == ards) {                    \
+		     hdr->type = HDR_MAXFORWARDS;  \
+		     p += 4;                       \
+		     goto dc_end;                  \
+	     }                                     \
+                                                   \
+	     val = unify(val);                     \
+	     if (val == ards) {                    \
+		     hdr->type = HDR_MAXFORWARDS;  \
+		     p += 4;                       \
+		     goto dc_end;                  \
+	     }                                     \
+	     goto other;                           \
+     }                                             \
+                                                   \
+     val = unify(val);                             \
+     switch(val) {                                 \
+     case Forw:                                    \
+	     p += 4;                               \
+	     val = READ(p);                        \
+	     if (val == ards) {                    \
+		     hdr->type = HDR_MAXFORWARDS;  \
+		     p += 4;                       \
+		     goto dc_end;                  \
+	     }                                     \
+                                                   \
+	     val = unify(val);                     \
+	     if (val == ards) {                    \
+		     hdr->type = HDR_MAXFORWARDS;  \
+		     p += 4;                       \
+		     goto dc_end;                  \
+	     }                                     \
+     default: goto other;                          \
+     }                                             \
+                                                   \
+     break
+
+
+#define Reco_CASE                                 \
+     p += 4;                                      \
+     val = READ(p);                               \
+     switch(val) {                                \
+     case rd_R:                                   \
+	     p += 4;                              \
+	     val = READ(p);                       \
+	     if (val == oute) {                   \
+		     hdr->type = HDR_RECORDROUTE; \
+		     p += 4;                      \
+		     goto dc_end;                 \
+	     }                                    \
+                                                  \
+	     val = unify(val);                    \
+	     if (val == oute) {                   \
+		     hdr->type = HDR_RECORDROUTE; \
+		     p += 4;                      \
+		     goto dc_end;                 \
+	     }                                    \
+	     goto other;                          \
+     }                                            \
+                                                  \
+     val = unify(val);                            \
+     switch(val) {                                \
+     case rd_R:                                   \
+	     p += 4;                              \
+	     val = READ(p);                       \
+	     if (val == oute) {                   \
+		     hdr->type = HDR_RECORDROUTE; \
+		     p += 4;                      \
+		     goto dc_end;                 \
+	     }                                    \
+                                                  \
+	     val = unify(val);                    \
+	     if (val == oute) {                   \
+		     hdr->type = HDR_RECORDROUTE; \
+		     p += 4;                      \
+		     goto dc_end;                 \
+	     }                                    \
+     default: goto other;                         \
+     }                                            \
+     break
+
+
+#define Via2_CASE         \
+     hdr->type = HDR_VIA; \
+     p += 4;              \
+     goto dc_end
+
+
+#define READ(val) \
+(*(val + 0) + (*(val + 1) << 8) + (*(val + 2) << 16) + (*(val + 3) << 24))
+
+/*
+ * Yet another parse_hname - Ultra Fast version :-)
+ */
+char* parse_hname2(char* begin, char* end, struct hdr_field* hdr)
+{
+	register char* p;
+	register int val;
+
+	DBG("DEBUG: parse_hname2 entered\n");
+
+	p = begin;
+	val = READ(p);
+	hdr->name.s = begin;
+
+	if ((end - begin) < 4) {
+		hdr->type = HDR_ERROR;
+		return begin;
+	}
+
+	switch(val) {
+	case Via1: Via1_CASE;
+	case From: From_CASE;
+	case To12: To12_CASE;
+	case CSeq: CSeq_CASE;                                                             
+	case Call: Call_CASE;
+        case Cont: Cont_CASE;
+	case Rout: Rout_CASE;                                                             
+	case Max_: Max_CASE;
+	case Reco: Reco_CASE;
+        case Via2: Via2_CASE;
+
+	default:
+		switch(*p) {
+		case 'T':
+		case 't':
+			switch(*(p + 1)) {
+			case 'o':
+			case 'O':
+			case ' ':   /* Short form */
+				hdr->type = HDR_TO;
+				p += 2;
+				goto dc_end;
+
+			case ':':
+				hdr->type = HDR_TO;
+				hdr->name.len = 1;
+				*(p + 1) = '\0';
+				return (p + 2);
+			}
+
+		case 'V':
+		case 'v':
+			switch(*(p + 1)) {
+			case ' ':
+				hdr->type = HDR_VIA;
+				p += 2;
+				goto dc_end;
+				
+			case ':':
+				hdr->type = HDR_VIA;
+				hdr->name.len = 1;
+				*(p + 1) = '\0';
+				return (p + 2);
+			}
+			break;
+
+		case 'F':
+		case 'f':
+			switch(*(p + 1)) {
+			case ' ':
+				hdr->type = HDR_FROM;
+				p += 2;
+				goto dc_end;
+				
+			case ':':
+				hdr->type = HDR_FROM;
+				hdr->name.len = 1;
+				*(p + 1)= '\0';
+				return (p + 2);
+			}
+			break;
+
+		case 'I':
+		case 'i':
+			switch(*(p + 1)) {
+			case ' ':
+				hdr->type = HDR_CALLID;
+				p += 2;
+				goto dc_end;
+				
+			case ':':
+				hdr->type = HDR_CALLID;
+				hdr->name.len = 1;
+				*(p + 1) = '\0';
+				return (p + 2);
+			}
+			break;
+
+		case 'M':
+		case 'm':
+			switch(*(p + 1)) {
+			case ' ':
+				hdr->type = HDR_CONTACT;
+				p += 2;
+				goto dc_end;
+				
+			case ':':
+				hdr->type = HDR_CONTACT;
+				hdr->name.len = 1;
+				*(p + 1) = '\0';
+				return (p + 2);
+			}
+			break;
+		}
+		
+		val = unify(val);
+		switch(val) {
+		case Via1: Via1_CASE;
+		case From: From_CASE;
+		case To12: To12_CASE;
+		case CSeq: CSeq_CASE;                                                             
+		case Call: Call_CASE;
+		case Cont: Cont_CASE;
+		case Rout: Rout_CASE;                                                             
+		case Max_: Max_CASE;
+		case Reco: Reco_CASE;
+		case Via2: Via2_CASE;
+		default: goto other;
+		}
+        }
+
+	     /* Double colon hasn't been found yet */
+ dc_end:
+       	p = skip_ws(p, end - p);
+	if (*p != ':') {   
+	        goto other;
+	} else {
+		hdr->name.len = p - hdr->name.s;
+		*p = '\0';
+		return (p + 1);
+	}
+
+	     /* Unknown header type */
+ other:    
+	p = q_memchr(p, ':', end - p);
+	if (!p) {        /* No double colon found, error.. */
+		hdr->type = HDR_ERROR;
+		hdr->name.s = NULL;
+		hdr->name.len = 0;
+		return NULL;
+	} else {
+		hdr->type = HDR_OTHER;
+		*p = '\0';
+		hdr->name.len = p - hdr->name.s;
+		return (p + 1);
+	}
+}
+
+
+void init_htable(void)
+{
+	int i;
+
+	     /*
+	      * Create hash table array
+	      */
+
+/*
+	hash_table = (struct ht_entry*)malloc(HASH_TABLE_SIZE * sizeof(struct ht_entry));
+
+*/
+	     /*
+	      * Mark all elements as empty
+	      */
+	for(i = 0; i < HASH_TABLE_SIZE; i++) {
+		set_entry(HASH_EMPTY, HASH_EMPTY);
+	}
+
+        set_entry(via1, Via1);
+	set_entry(viA1, Via1);
+	set_entry(vIa1, Via1);
+        set_entry(vIA1, Via1);
+        set_entry(Via1, Via1);
+        set_entry(ViA1, Via1);
+	set_entry(VIa1, Via1);
+	set_entry(VIA1, Via1);
+	
+        set_entry(via2, Via2);
+	set_entry(viA2, Via2);
+	set_entry(vIa2, Via2);
+	set_entry(vIA2, Via2);
+	set_entry(Via2, Via2);
+	set_entry(ViA2, Via2);
+	set_entry(VIa2, Via2);
+	set_entry(VIA2, Via2);
+	
+	set_entry(from, From);
+	set_entry(froM, From);
+	set_entry(frOm, From);
+	set_entry(frOM, From);
+	set_entry(fRom, From);
+	set_entry(fRoM, From);
+	set_entry(fROm, From);
+	set_entry(fROM, From);
+	set_entry(From, From);
+	set_entry(FroM, From);
+	set_entry(FrOm, From);
+	set_entry(FrOM, From);
+	set_entry(FRom, From);
+	set_entry(FRoM, From);
+	set_entry(FROm, From);
+	set_entry(FROM, From);
+	
+	set_entry(to12, To12);
+	set_entry(tO12, To12);
+	set_entry(To12, To12);
+	set_entry(TO12, To12);
+
+	set_entry(to21, To21);
+	set_entry(tO21, To21);
+	set_entry(To21, To21);
+	set_entry(TO21, To21);
+
+	set_entry(cseq, CSeq);
+	set_entry(cseQ, CSeq);
+	set_entry(csEq, CSeq);
+	set_entry(csEQ, CSeq);
+	set_entry(cSeq, CSeq);
+	set_entry(cSeQ, CSeq);
+	set_entry(cSEq, CSeq);
+	set_entry(cSEQ, CSeq);
+	set_entry(Cseq, CSeq);
+	set_entry(CseQ, CSeq);
+	set_entry(CsEq, CSeq);
+	set_entry(CsEQ, CSeq);
+	set_entry(CSeq, CSeq);
+	set_entry(CSeQ, CSeq);
+	set_entry(CSEq, CSeq);
+	set_entry(CSEQ, CSeq);
+	
+	set_entry(call, Call);
+	set_entry(calL, Call);
+	set_entry(caLl, Call);
+	set_entry(caLL, Call);
+	set_entry(cAll, Call);
+	set_entry(cAlL, Call);
+	set_entry(cALl, Call);
+	set_entry(cALL, Call);
+	set_entry(Call, Call);
+	set_entry(CalL, Call);
+	set_entry(CaLl, Call);
+	set_entry(CaLL, Call);
+	set_entry(CAll, Call);
+	set_entry(CAlL, Call);
+	set_entry(CALl, Call);
+	set_entry(CALL, Call);
+
+	set_entry(_id1, _ID1);
+	set_entry(_iD1, _ID1);
+	set_entry(_Id1, _ID1);
+	set_entry(_ID1, _ID1);
+
+	set_entry(_id2, _ID2);
+	set_entry(_iD2, _ID2);
+	set_entry(_Id2, _ID2);
+	set_entry(_ID2, _ID2);
+
+	set_entry(cont, Cont);
+	set_entry(conT, Cont);
+	set_entry(coNt, Cont);
+	set_entry(coNT, Cont);
+	set_entry(cOnt, Cont);
+	set_entry(cOnT, Cont);
+	set_entry(cONt, Cont);
+	set_entry(cONT, Cont);
+	set_entry(Cont, Cont);
+	set_entry(ConT, Cont);
+	set_entry(CoNt, Cont);
+	set_entry(CoNT, Cont);
+	set_entry(COnt, Cont);
+	set_entry(COnT, Cont);
+	set_entry(CONt, Cont);
+	set_entry(CONT, Cont);
+
+	set_entry(act1, act1);
+	set_entry(acT1, act1);
+	set_entry(aCt1, act1);
+	set_entry(aCT1, act1);
+	set_entry(Act1, act1);
+	set_entry(AcT1, act1);
+	set_entry(ACt1, act1);
+	set_entry(ACT1, act1);
+
+	set_entry(act2, act2);
+	set_entry(acT2, act2);
+	set_entry(aCt2, act2);
+	set_entry(aCT2, act2);
+	set_entry(Act2, act2);
+	set_entry(AcT2, act2);
+	set_entry(ACt2, act2);
+	set_entry(ACT2, act2);
+
+	set_entry(max_, Max_);
+	set_entry(maX_, Max_);
+	set_entry(mAx_, Max_);
+	set_entry(mAX_, Max_);
+	set_entry(Max_, Max_);
+	set_entry(MaX_, Max_);
+	set_entry(MAx_, Max_);
+	set_entry(MAX_, Max_);
+
+	set_entry(forw, Forw);
+	set_entry(forW, Forw);
+	set_entry(foRw, Forw);
+	set_entry(foRW, Forw);
+	set_entry(fOrw, Forw);
+	set_entry(fOrW, Forw);
+	set_entry(fORw, Forw);
+	set_entry(fORW, Forw);
+	set_entry(Forw, Forw);
+	set_entry(ForW, Forw);
+	set_entry(FoRw, Forw);
+	set_entry(FoRW, Forw);
+	set_entry(FOrw, Forw);
+	set_entry(FOrW, Forw);
+	set_entry(FORw, Forw);
+	set_entry(FORW, Forw);
+
+	set_entry(ards, ards);
+	set_entry(ardS, ards);
+	set_entry(arDs, ards);
+	set_entry(arDS, ards);
+	set_entry(aRds, ards);
+	set_entry(aRdS, ards);
+	set_entry(aRDs, ards);
+	set_entry(aRDS, ards);
+	set_entry(Ards, ards);
+	set_entry(ArdS, ards);
+	set_entry(ArDs, ards);
+	set_entry(ArDS, ards);
+	set_entry(ARds, ards);
+	set_entry(ARdS, ards);
+	set_entry(ARDs, ards);
+	set_entry(ARDS, ards);
+
+	set_entry(rout, Rout);
+	set_entry(rouT, Rout);
+	set_entry(roUt, Rout);
+	set_entry(roUT, Rout);
+	set_entry(rOut, Rout);
+	set_entry(rOuT, Rout);
+	set_entry(rOUt, Rout);
+	set_entry(rOUT, Rout);
+	set_entry(Rout, Rout);
+	set_entry(RouT, Rout);
+	set_entry(RoUt, Rout);
+	set_entry(RoUT, Rout);
+	set_entry(ROut, Rout);
+	set_entry(ROuT, Rout);
+	set_entry(ROUt, Rout);
+	set_entry(ROUT, Rout);
+
+	set_entry(reco, Reco);
+	set_entry(recO, Reco);
+	set_entry(reCo, Reco);
+	set_entry(reCO, Reco);
+	set_entry(rEco, Reco);
+	set_entry(rEcO, Reco);
+	set_entry(rECo, Reco);
+	set_entry(rECO, Reco);
+	set_entry(Reco, Reco);
+	set_entry(RecO, Reco);
+	set_entry(ReCo, Reco);
+	set_entry(ReCO, Reco);
+	set_entry(REco, Reco);
+	set_entry(REcO, Reco);
+	set_entry(RECo, Reco);
+	set_entry(RECO, Reco);
+
+	set_entry(rd_r, rd_R);
+	set_entry(rd_R, rd_R);
+	set_entry(rD_r, rd_R);
+	set_entry(rD_R, rd_R);
+	set_entry(Rd_r, rd_R);
+	set_entry(Rd_R, rd_R);
+	set_entry(RD_r, rd_R);
+	set_entry(RD_R, rd_R);
+
+	set_entry(oute, oute);
+	set_entry(outE, oute);
+	set_entry(ouTe, oute);
+	set_entry(ouTE, oute);
+	set_entry(oUte, oute);
+	set_entry(oUtE, oute);
+	set_entry(oUTe, oute);
+	set_entry(oUTE, oute);
+	set_entry(Oute, oute);
+	set_entry(OutE, oute);
+	set_entry(OuTe, oute);
+	set_entry(OuTE, oute);
+	set_entry(OUte, oute);
+	set_entry(OUtE, oute);
+	set_entry(OUTe, oute);
+	set_entry(OUTE, oute);
+}
+
+

+ 231 - 0
strs.h

@@ -0,0 +1,231 @@
+#ifndef STRS_H
+#define STRS_H
+
+#define via1 0x3a616976   /* "via:" */
+#define viA1 0x3a416976   /* "viA:" */
+#define vIa1 0x3a614976   /* "vIa:" */
+#define vIA1 0x3a414976   /* "vIA:" */
+#define Via1 0x3a616956   /* "Via:" */
+#define ViA1 0x3a416956   /* "ViA:" */
+#define VIa1 0x3a614956   /* "VIa:" */
+#define VIA1 0x3a414956   /* "VIA:" */
+
+#define via2 0x20616976   /* "via " */
+#define viA2 0x20416976   /* "viA " */
+#define vIa2 0x20614976   /* "vIa " */
+#define vIA2 0x20414976   /* "vIA " */
+#define Via2 0x20616956   /* "Via " */
+#define ViA2 0x20416956   /* "ViA " */
+#define VIa2 0x20614956   /* "VIa " */
+#define VIA2 0x20414956   /* "VIA " */
+
+#define from 0x6d6f7266   /* "from" */
+#define froM 0x4d6f7266   /* "froM" */
+#define frOm 0x6d4f7266   /* "frOm" */
+#define frOM 0x4d4f7266   /* "frOM" */
+#define fRom 0x6d6f5266   /* "fRom" */
+#define fRoM 0x4d6f5266   /* "fRoM" */
+#define fROm 0x6d4f5266   /* "fROm" */
+#define fROM 0x4d4f5266   /* "fROM" */
+#define From 0x6d6f7246   /* "From" */
+#define FroM 0x4d6f7246   /* "FroM" */
+#define FrOm 0x6d4f7246   /* "FrOm" */
+#define FrOM 0x4d4f7246   /* "FrOM" */
+#define FRom 0x6d6f5246   /* "FRom" */
+#define FRoM 0x4d6f5246   /* "FRoM" */
+#define FROm 0x6d4f5246   /* "FROm" */
+#define FROM 0x4d4f5246   /* "FROM" */
+
+#define to12 0x203a6f74   /* "to: " */
+#define tO12 0x203a4f74   /* "tO: " */
+#define To12 0x203a6f54   /* "To: " */
+#define TO12 0x203a4f54   /* "TO: " */
+
+#define to21 0x3a206f74   /* "to :" */
+#define tO21 0x3a204f74   /* "tO :" */
+#define To21 0x3a206f54   /* "To :" */
+#define TO21 0x3a204f54   /* "TO :" */
+
+#define cseq 0x71657363   /* "cseq" */
+#define cseQ 0x51657363   /* "cseQ" */
+#define csEq 0x71457363   /* "csEq" */
+#define csEQ 0x51457363   /* "csEQ" */
+#define cSeq 0x71655363   /* "cSeq" */
+#define cSeQ 0x51655363   /* "cSeQ" */
+#define cSEq 0x71455363   /* "cSEq" */
+#define cSEQ 0x51455363   /* "cSEQ" */
+#define Cseq 0x71657343   /* "Cseq" */
+#define CseQ 0x51657343   /* "CseQ" */
+#define CsEq 0x71457343   /* "CsEq" */
+#define CsEQ 0x51457343   /* "CsEQ" */
+#define CSeq 0x71655343   /* "CSeq" */
+#define CSeQ 0x51655343   /* "CSeQ" */
+#define CSEq 0x71455343   /* "CSEq" */
+#define CSEQ 0x51455343   /* "CSEQ" */
+
+#define call 0x6c6c6163   /* "call" */
+#define calL 0x4c6c6163   /* "calL" */
+#define caLl 0x6c4c6163   /* "caLl" */
+#define caLL 0x4c4c6163   /* "caLL" */
+#define cAll 0x6c6c4163   /* "cAll" */
+#define cAlL 0x4c6c4163   /* "cAlL" */
+#define cALl 0x6c4c4163   /* "cALl" */
+#define cALL 0x4c4c4163   /* "cALL" */
+#define Call 0x6c6c6143   /* "Call" */
+#define CalL 0x4c6c6143   /* "CalL" */
+#define CaLl 0x6c4c6143   /* "CaLl" */
+#define CaLL 0x4c4c6143   /* "CaLL" */
+#define CAll 0x6c6c4143   /* "CAll" */
+#define CAlL 0x4c6c4143   /* "CAlL" */
+#define CALl 0x6c4c4143   /* "CALl" */
+#define CALL 0x4c4c4143   /* "CALL" */
+
+#define _id1 0x3a64692d   /* "-id:" */
+#define _iD1 0x3a44692d   /* "-iD:" */
+#define _Id1 0x3a64492d   /* "-Id:" */
+#define _ID1 0x3a44492d   /* "-ID:" */
+
+#define _id2 0x2064692d   /* "-id " */
+#define _iD2 0x2044692d   /* "-iD " */
+#define _Id2 0x2064492d   /* "-Id " */
+#define _ID2 0x2044492d   /* "-ID " */
+
+#define cont 0x746e6f63   /* "cont" */
+#define conT 0x546e6f63   /* "conT" */
+#define coNt 0x744e6f63   /* "coNt" */
+#define coNT 0x544e6f63   /* "coNT" */
+#define cOnt 0x746e4f63   /* "cOnt" */
+#define cOnT 0x546e4f63   /* "cOnT" */
+#define cONt 0x744e4f63   /* "cONt" */
+#define cONT 0x544e4f63   /* "cONT" */
+#define Cont 0x746e6f43   /* "Cont" */
+#define ConT 0x546e6f43   /* "ConT" */
+#define CoNt 0x744e6f43   /* "CoNt" */
+#define CoNT 0x544e6f43   /* "CoNT" */
+#define COnt 0x746e4f43   /* "COnt" */
+#define COnT 0x546e4f43   /* "COnT" */
+#define CONt 0x744e4f43   /* "CONt" */
+#define CONT 0x544e4f43   /* "CONT" */
+
+#define act1 0x3a746361   /* "act:" */
+#define acT1 0x3a546361   /* "acT:" */
+#define aCt1 0x3a744361   /* "aCt:" */
+#define aCT1 0x3a544361   /* "aCT:" */
+#define Act1 0x3a746341   /* "Act:" */
+#define AcT1 0x3a546341   /* "AcT:" */
+#define ACt1 0x3a744341   /* "ACt:" */
+#define ACT1 0x3a544341   /* "ACT:" */
+
+#define act2 0x20746361   /* "act " */
+#define acT2 0x20546361   /* "acT " */
+#define aCt2 0x20744361   /* "aCt " */
+#define aCT2 0x20544361   /* "aCT " */
+#define Act2 0x20746341   /* "Act " */
+#define AcT2 0x20546341   /* "AcT " */
+#define ACt2 0x20744341   /* "ACt " */
+#define ACT2 0x20544341   /* "ACT " */
+
+#define max_ 0x2d78616d   /* "max-" */
+#define maX_ 0x2d58616d   /* "maX-" */
+#define mAx_ 0x2d78416d   /* "mAx-" */
+#define mAX_ 0x2d58416d   /* "mAX-" */
+#define Max_ 0x2d78614d   /* "Max-" */
+#define MaX_ 0x2d58614d   /* "MaX-" */
+#define MAx_ 0x2d78414d   /* "MAx-" */
+#define MAX_ 0x2d58414d   /* "MAX-" */
+
+#define forw 0x77726f66   /* "forw" */
+#define forW 0x57726f66   /* "forW" */
+#define foRw 0x77526f66   /* "foRw" */
+#define foRW 0x57526f66   /* "foRW" */
+#define fOrw 0x77724f66   /* "fOrw" */
+#define fOrW 0x57724f66   /* "fOrW" */
+#define fORw 0x77524f66   /* "fORw" */
+#define fORW 0x57524f66   /* "fORW" */
+#define Forw 0x77726f46   /* "Forw" */
+#define ForW 0x57726f46   /* "ForW" */
+#define FoRw 0x77526f46   /* "FoRw" */
+#define FoRW 0x57526f46   /* "FoRW" */
+#define FOrw 0x77724f46   /* "FOrw" */
+#define FOrW 0x57724f46   /* "FOrW" */
+#define FORw 0x77524f46   /* "FORw" */
+#define FORW 0x57524f46   /* "FORW" */
+
+#define ards 0x73647261   /* "ards" */
+#define ardS 0x53647261   /* "ardS" */
+#define arDs 0x73447261   /* "arDs" */
+#define arDS 0x53447261   /* "arsd" */
+#define aRds 0x73645261   /* "aRds" */
+#define aRdS 0x53645261   /* "aRdS" */
+#define aRDs 0x73445261   /* "aRDs" */
+#define aRDS 0x53445261   /* "aRDS" */
+#define Ards 0x73647241   /* "Ards" */
+#define ArdS 0x53647241   /* "ArdS" */
+#define ArDs 0x73447241   /* "ArDs" */
+#define ArDS 0x53447241   /* "ArDS" */
+#define ARds 0x73645241   /* "ARds" */
+#define ARdS 0x53645241   /* "ARdS" */
+#define ARDs 0x73445241   /* "ARDs" */
+#define ARDS 0x53445241   /* "ARDS" */
+
+#define rout 0x74756f72   /* "rout" */
+#define rouT 0x54756f72   /* "rouT" */
+#define roUt 0x74556f72   /* "roUt" */
+#define roUT 0x54556f72   /* "roUT" */
+#define rOut 0x74754f72   /* "rOut" */
+#define rOuT 0x54754f72   /* "rOuT" */
+#define rOUt 0x74554f72   /* "rOUt" */
+#define rOUT 0x54554f72   /* "rOUT" */
+#define Rout 0x74756f52   /* "Rout" */
+#define RouT 0x54756f52   /* "RouT" */
+#define RoUt 0x74556f52   /* "RoUt" */
+#define RoUT 0x54556f52   /* "RoUT" */
+#define ROut 0x74754f52   /* "ROut" */
+#define ROuT 0x54754f52   /* "ROuT" */
+#define ROUt 0x74554f52   /* "ROUt" */
+#define ROUT 0x54554f52   /* "ROUT" */
+
+#define reco 0x6f636572   /* "reco" */
+#define recO 0x4f636572   /* "recO" */
+#define reCo 0x6f436572   /* "reCo" */
+#define reCO 0x4f436572   /* "reCO" */
+#define rEco 0x6f634572   /* "rEco" */
+#define rEcO 0x4f634572   /* "rEcO" */
+#define rECo 0x6f434572   /* "rECo" */
+#define rECO 0x4f434572   /* "rECO" */
+#define Reco 0x6f636552   /* "Reco" */
+#define RecO 0x4f636552   /* "RecO" */
+#define ReCo 0x6f436552   /* "ReCo" */
+#define ReCO 0x4f436552   /* "ReCO" */
+#define REco 0x6f634552   /* "REco" */
+#define REcO 0x4f634552   /* "REcO" */
+#define RECo 0x6f434552   /* "RECo" */
+#define RECO 0x4f434552   /* "RECO" */
+
+#define rd_r 0x722d6472   /* "rd-r" */
+#define rd_R 0x522d6472   /* "rd-R" */
+#define rD_r 0x722d4472   /* "rD-r" */
+#define rD_R 0x522d4472   /* "rD-R" */
+#define Rd_r 0x722d6452   /* "Rd-r" */
+#define Rd_R 0x522d6452   /* "Rd-R" */
+#define RD_r 0x722d4452   /* "RD-r" */
+#define RD_R 0x522d4452   /* "RD-R" */
+
+#define oute 0x6574756f   /* "oute" */
+#define outE 0x4574756f   /* "outE" */
+#define ouTe 0x6554756f   /* "ouTe" */
+#define ouTE 0x4554756f   /* "ouTE" */
+#define oUte 0x6574556f   /* "oUte" */
+#define oUtE 0x4574556f   /* "oUtE" */
+#define oUTe 0x6554556f   /* "oUTe" */
+#define oUTE 0x4554556f   /* "oUTE" */
+#define Oute 0x6574754f   /* "Oute" */
+#define OutE 0x4574754f   /* "OutE" */
+#define OuTe 0x6554754f   /* "OuTe" */
+#define OuTE 0x4554754f   /* "OuTE" */
+#define OUte 0x6574554f   /* "OUte" */
+#define OUtE 0x4574554f   /* "OUtE" */
+#define OUTe 0x6554554f   /* "OUTe" */
+#define OUTE 0x4554554f   /* "OUTE" */
+
+#endif