performance and bug fixes
authorJiri Kuthan <jiri@iptel.org>
Mon, 7 Jan 2002 04:39:49 +0000 (04:39 +0000)
committerJiri Kuthan <jiri@iptel.org>
Mon, 7 Jan 2002 04:39:49 +0000 (04:39 +0000)
52 files changed:
Makefile
Makefile.defs
Makefile.sources
action.c
config.h
crc.c
crc.h [new file with mode: 0644]
data_lump.c
forward.c
main.c
md5utils.c
mem.h [deleted file]
mem/mem.c [new file with mode: 0644]
mem/mem.h [new file with mode: 0644]
mem/memtest.c [new file with mode: 0644]
mem/q_malloc.c [moved from q_malloc.c with 92% similarity]
mem/q_malloc.h [moved from q_malloc.h with 96% similarity]
mem/shm_mem.c [moved from shm_mem.c with 92% similarity]
mem/shm_mem.h [moved from shm_mem.h with 76% similarity]
mem/vq_malloc.c [new file with mode: 0644]
mem/vq_malloc.h [new file with mode: 0644]
modules/tm/TODO
modules/tm/config.h [new file with mode: 0644]
modules/tm/globals.h [deleted file]
modules/tm/h_table.c
modules/tm/h_table.h
modules/tm/hash_func.c
modules/tm/hash_func.h
modules/tm/lock.c
modules/tm/lock.h
modules/tm/sh_malloc.h
modules/tm/sip_msg.c
modules/tm/t_funcs.c
modules/tm/t_funcs.h
modules/tm/t_lookup.c [new file with mode: 0644]
modules/tm/timer.c
modules/tm/timer.h
modules/tm/tm.c
msg_parser.c
msg_parser.h
msg_translator.c
parse_fline.c
parse_via.c
receive.c
stats.h
test/tp.cfg
test/tx.cfg [moved from t_debug.cfg with 58% similarity]
test/xx.cfg [new file with mode: 0644]
test/xy.cfg [new file with mode: 0644]
timer.c
udp_server.c
ut.h

index 74a04d6..7485bb6 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -11,7 +11,7 @@ auto_gen=lex.yy.c cfg.tab.c   #lexx, yacc etc
 include Makefile.sources
 
 exclude_modules=CVS usrloc mysql auth
-static_modules=
+static_modules=tm
 static_modules_path=$(addprefix modules/, $(static_modules))
 extra_sources=$(wildcard $(addsuffix /*.c, $(static_modules_path)))
 extra_objs=$(extra_sources:.c=.o)
index 4bdf3de..399dd96 100644 (file)
@@ -44,8 +44,16 @@ ARCH = $(shell uname -s)
 #              extra error checking (trying to free the same pointer
 #              twice, trying to free a pointer alloc'ed with a different
 #              malloc etc.)
+# -DVQ_MALLOC
+#              additional option to PKG_MALLOC which utilizes a fater then
+#              qm version
+#
+
 DEFS+= -DNAME='"$(NAME)"' -DVERSION='"$(RELEASE)"' -DARCH='"$(ARCH)"' \
         -DDNS_IP_HACK  -DPKG_MALLOC -DSHM_MEM  -DSHM_MMAP \
+       -DEXTRA_DEBUG \
+       -DVQ_MALLOC 
+         #-DDBG_QM_MALLOC #-DVQ_MALLOC #-DNO_DEBUG
          #-DNO_DEBUG #-DDBG_QM_MALLOC
 #-DEXTRA_DEBUG
 # -DUSE_SHM_MEM
@@ -54,9 +62,9 @@ DEFS+= -DNAME='"$(NAME)"' -DVERSION='"$(RELEASE)"' -DARCH='"$(ARCH)"' \
 #-DNO_DEBUG#-DSTATS -DNO_DEBUG 
 #-DNO_LOG
 
-PROFILE=  #-pg #set this if you want profiling
-#mode = debug
-mode = release
+PROFILE=  -pg #set this if you want profiling
+mode = debug
+#mode = release
 
 # platform dependent settings
 
index ee950f3..fe542bc 100644 (file)
@@ -11,7 +11,7 @@
 # defines: sources, objs, depends
 #
 
-sources=$(filter-out $(auto_gen), $(wildcard *.c)) $(auto_gen)
+sources=$(filter-out $(auto_gen), $(wildcard *.c) $(wildcard mem/*.c) ) $(auto_gen)
 objs=$(sources:.c=.o)
 extra_objs=
 depends=$(sources:.c=.d)
index c32bd32..68fbebd 100644 (file)
--- a/action.c
+++ b/action.c
@@ -15,7 +15,7 @@
 #include "msg_parser.h"
 #include "ut.h"
 #include "sr_module.h"
-#include "mem.h"
+#include "mem/mem.h"
 
 #include <sys/types.h>
 #include <sys/socket.h>
index 710e4ca..b14386b 100644 (file)
--- a/config.h
+++ b/config.h
@@ -1,5 +1,5 @@
 /*
- *  $Id
+ *  $Id $
  */
 
 
@@ -12,8 +12,6 @@
 
 #define CFG_FILE "./ser.cfg"
 
-/* receive buffer size */
-#define BUF_SIZE 65507
 
 /* maximum number of addresses on which we will listen */
 #define MAX_LISTEN 16
 /*used only if PKG_MALLOC is defined*/
 #define PKG_MEM_POOL_SIZE 1024*1024
 
-/*used is SH_MEM is defined*/
+/*used if SH_MEM is defined*/
 #define SHM_MEM_SIZE 128*1024*1024
 
 #define TIMER_TICK 1
 #define LONG_SLEEP     3600
 
+/* dimensioning buckets in q_malloc */
+/* size of the size2bucket table; everything beyond that asks for
+   a variable-size kilo-bucket
+ */
+#define MAX_FIXED_BLOCK         3072
+/* distance of kilo-buckets */
+#define BLOCK_STEP                      512
+/* maximum number of possible buckets */
+#define MAX_BUCKET             15
+
+/* receive buffer size -- preferably set low to
+   avoid terror of excessively huge messages
+*/
+#define BUF_SIZE (MAX_FIXED_BLOCK-32)
+
+/* forwarding */
+#define MAX_VIA_LINE_SIZE      240
+#define MAX_RECEIVED_SIZE      57
 
 #endif
diff --git a/crc.c b/crc.c
index fd56f7f..1d5b686 100644 (file)
--- a/crc.c
+++ b/crc.c
@@ -1,8 +1,11 @@
 /*
+ * $Id$
+ *
  *  Crc - 32 + 16 BIT ANSI X3.66 + CCITT CRC checksum files
  */
 
 #include <stdio.h>
+#include "crc.h"
 
 #define OK 0
 #define ERROR (-1)
@@ -60,7 +63,7 @@
 /*     hardware you could probably optimize the shift in assembler by  */
 /*     using byte-swap instructions.                                   */
 
-static unsigned long int crc_32_tab[] = { /* CRC polynomial 0xedb88320 */
+unsigned long int crc_32_tab[] = { /* CRC polynomial 0xedb88320 */
 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
diff --git a/crc.h b/crc.h
new file mode 100644 (file)
index 0000000..958f7b3
--- /dev/null
+++ b/crc.h
@@ -0,0 +1,11 @@
+/* $Id$*/
+
+#ifndef _CRC_H_
+#define _CRC_H_
+
+extern unsigned long int crc_32_tab[];
+extern unsigned short int ccitt_tab[];
+extern unsigned short int crc_16_tab[];
+
+#endif
+
index c03f643..02f08ae 100644 (file)
@@ -4,7 +4,7 @@
 
 #include "data_lump.h"
 #include "dprint.h"
-#include "mem.h"
+#include "mem/mem.h"
 
 #include <stdlib.h>
 
index d78a840..51903e0 100644 (file)
--- a/forward.c
+++ b/forward.c
 #include "globals.h"
 #include "data_lump.h"
 #include "ut.h"
-#include "mem.h"
+#include "mem/mem.h"
 #include "msg_translator.h"
 #include "sr_module.h"
+#include "stats.h"
 
 #ifdef DEBUG_DMALLOC
 #include <dmalloc.h>
 #endif
 
-#define MAX_VIA_LINE_SIZE      240
-#define MAX_RECEIVED_SIZE  57
-
-#ifdef STATS
-#include "stats.h"
-#endif
-
 
 
 int forward_request( struct sip_msg* msg, struct proxy_l * p)
@@ -79,15 +73,11 @@ int forward_request( struct sip_msg* msg, struct proxy_l * p)
                                sizeof(struct sockaddr_in))==-1){
                        p->errors++;
                        p->ok=0;
-#ifdef STATS
-                       update_fail_on_send;
-#endif
+                       STATS_TX_DROPS;
                        goto error;
        }
-#ifdef STATS
        /* sent requests stats */
-       else update_sent_request( msg->first_line.u.request.method_value );
-#endif
+       else STATS_TX_REQUEST(  msg->first_line.u.request.method_value );
        free(buf);
        free(to);
        /* received_buf & line_buf will be freed in receiv_msg by free_lump_list*/
@@ -189,15 +179,10 @@ int forward_reply(struct sip_msg* msg)
        if (udp_send(new_buf,new_len, (struct sockaddr*) to,
                                        sizeof(struct sockaddr_in))==-1)
        {
-#ifdef STATS
-               update_fail_on_send;
-#endif
+               STATS_TX_DROPS;
                goto error;
        }
-#ifdef STATS
-       else update_sent_response(  msg->first_line.u.reply.statusclass );
-#endif
-
+       else STATS_TX_RESPONSE(  msg->first_line.u.reply.statusclass );
        free(new_buf);
        free(to);
 skip:
diff --git a/main.c b/main.c
index 1257c19..357b5be 100644 (file)
--- a/main.c
+++ b/main.c
@@ -23,9 +23,9 @@
 #include "route.h"
 #include "udp_server.h"
 #include "globals.h"
-#include "mem.h"
+#include "mem/mem.h"
 #ifdef SHM_MEM
-#include "shm_mem.h"
+#include "mem/shm_mem.h"
 #endif
 #include "sr_module.h"
 #include "timer.h"
@@ -33,9 +33,7 @@
 
 #include <signal.h>
 
-#ifdef STATS
 #include "stats.h"
-#endif
 
 #ifdef DEBUG_DMALLOC
 #include <dmalloc.h>
@@ -72,6 +70,9 @@ static char flags[]=
 #ifdef PKG_MALLOC
 ", PKG_MALLOC"
 #endif
+#ifdef VQ_MALLOC
+", VQ_MALLOC"
+#endif
 #ifdef USE_SHM_MEM
 ", USE_SHM_MEM"
 #endif
@@ -171,12 +172,6 @@ int process_no = 0;
 /* cfg parsing */
 int cfg_errors=0;
 
-#ifdef PKG_MALLOC
-char mem_pool[PKG_MEM_POOL_SIZE];
-struct qm_block* mem_block;
-#endif
-
-
 #define MAX_FD 32 /* maximum number of inherited open file descriptors,
                    (normally it shouldn't  be bigger  than 3) */
 
@@ -332,7 +327,7 @@ int main_loop()
 static void sig_usr(int signo)
 {
        DPrint("INT received, program terminates\n");
-       if (signo==SIGINT) {    /* exit gracefuly */
+       if (signo==SIGINT || signo==SIGPIPE) {  /* exit gracefuly */
 #ifdef STATS
                /* print statistics on exit only for the first process */
 
@@ -380,6 +375,7 @@ static void sig_usr(int signo)
 }
 
 
+void test();
 
 int main(int argc, char** argv)
 {
@@ -396,12 +392,20 @@ int main(int argc, char** argv)
                DPrint("ERROR: no SIGINT signal handler can be installed\n");
                goto error;
        }
+       /* if we debug and write to a pipe, we want to exit nicely too */
+       if (signal(SIGPIPE, sig_usr) == SIG_ERR ) {
+               DPrint("ERROR: no SIGINT signal handler can be installed\n");
+               goto error;
+       }
 
        if (signal(SIGUSR1, sig_usr)  == SIG_ERR ) {
                DPrint("ERROR: no SIGUSR1 signal handler can be installed\n");
                goto error;
        }
 
+       //memtest();
+       //hashtest();
+
 
        /* process command line (get port no, cfg. file path etc) */
        opterr=0;
@@ -522,21 +526,9 @@ int main(int argc, char** argv)
        }
 
        /*init mallocs (before parsing cfg !)*/
-#ifdef PKG_MALLOC
-       /*init mem*/
-       mem_block=qm_malloc_init(mem_pool, PKG_MEM_POOL_SIZE);
-       if (mem_block==0){
-               LOG(L_CRIT, "could not initialize memory pool\n");
+       if (init_mallocs()==-1)
                goto error;
-       }
-#endif
 
-#ifdef SHM_MEM
-       if (shm_mem_init()<0) {
-               LOG(L_CRIT, "could not initialize shared memory pool, exiting...\n");
-               goto error;
-       }
-#endif
        /*init timer, before parsing the cfg!*/
        if (init_timer()<0){
                LOG(L_CRIT, "could not initialize timer, exiting...\n");
@@ -641,3 +633,4 @@ error:
        return -1;
 
 }
+
index 3bdeddf..d6ab9f9 100644 (file)
@@ -28,8 +28,8 @@ jku: added support to deal with vectors
 #include "md5global.h"
 #include "md5.h"
 #include "md5utils.h"
-
 #include "dprint.h"
+#include "ut.h"
 
 
 static void MDString PROTO_LIST ((char *));
@@ -45,13 +45,38 @@ static void MDString PROTO_LIST ((char *));
  */
 void MDStringArray (char *dst, str src[], int size)
 {
-  MD_CTX context;
-  unsigned char digest[16];
-  int i;
+       MD_CTX context;
+       unsigned char digest[16];
+       int i;
+       int len;
+       char *s;
+
+/*
+#      ifdef EXTRA_DEBUG
+       int j;
+       int sum;
+#endif
+*/
 
-  MDInit (&context);
-  for (i=0; i<size; i++) {
-       MDUpdate (&context, src[i].s, src[i].len);
+       MDInit (&context);
+       for (i=0; i<size; i++) {
+               trim_len( len, s, src[i] );
+/*
+#              ifdef EXTRA_DEBUG
+               fprintf(stderr, "EXTRA_DEBUG: %d. (%d) {", i+1, len);
+               sum=0;
+               for (j=0; j<len; j++) {
+                       fprintf( stderr, "%c ", *(s+j));
+                       sum+=*(s+j);
+               }
+               for (j=0; j<len; j++) {
+                       fprintf( stderr, "%d ", *(s+j));
+                       sum+=*(s+j);
+               }
+               fprintf(stderr, " [%d]\n", sum );       
+#              endif
+*/
+               MDUpdate (&context, s, len);
   }
   MDFinal (digest, &context);
 
diff --git a/mem.h b/mem.h
deleted file mode 100644 (file)
index 120349c..0000000
--- a/mem.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/* $Id$
- *
- * memory related stuff (malloc & friends)
- * 
- */
-
-
-#ifndef mem_h
-#define mem_h
-#include "dprint.h"
-
-#ifdef PKG_MALLOC
-#include "q_malloc.h"
-
-extern struct qm_block* mem_block;
-
-
-#ifdef DBG_QM_MALLOC
-
-#define pkg_malloc(s) qm_malloc(mem_block, (s),__FILE__, __FUNCTION__, \
-                                                               __LINE__);
-#define pkg_free(p)   qm_free(mem_block, (p), __FILE__,  __FUNCTION__, \
-                                                               __LINE__);
-
-#else
-
-#define pkg_malloc(s) qm_malloc(mem_block, (s))
-#define pkg_free(p)   qm_free(mem_block, (p))
-
-#endif
-
-#define pkg_status()  qm_status(mem_block)
-
-#elif defined(SHM_MEM) && defined(USE_SHM_MEM)
-
-#include "shm_mem.h"
-
-#define pkg_malloc(s) shm_malloc((s))
-#define pkg_free(p)   shm_free((p))
-#define pkg_status()  shm_status()
-
-#else
-
-#include <stdlib.h>
-
-#define pkg_malloc(s) \
-       (  { void *v; v=malloc((s)); \
-          DBG("malloc %x size %d end %x\n", v, s, (unsigned int)v+(s));\
-          v; } )
-#define pkg_free(p)  do{ DBG("free %x\n", (p)); free((p)); }while(0);
-#define pkg_status()
-
-#endif
-
-
-#endif
diff --git a/mem/mem.c b/mem/mem.c
new file mode 100644 (file)
index 0000000..c6f48f4
--- /dev/null
+++ b/mem/mem.c
@@ -0,0 +1,51 @@
+/*
+ * $Id *
+ */
+
+#include "../config.h"
+#include "../dprint.h"
+#include "mem.h"
+
+#ifdef PKG_MALLOC
+#      ifdef VQ_MALLOC
+#              include "vq_malloc.h"
+#      else
+#              include "q_malloc.h"
+#      endif
+#endif
+
+#ifdef PKG_MALLOC
+       char mem_pool[PKG_MEM_POOL_SIZE];
+       #ifdef VQ_MALLOC
+               struct vqm_block* mem_block;
+       #else
+               struct qm_block* mem_block;
+       #endif
+#endif
+
+int init_mallocs()
+{
+#ifdef PKG_MALLOC
+        /*init mem*/
+       #ifdef VQ_MALLOC
+               mem_block=vqm_malloc_init(mem_pool, PKG_MEM_POOL_SIZE);
+       #else
+               mem_block=qm_malloc_init(mem_pool, PKG_MEM_POOL_SIZE);
+       #endif
+        if (mem_block==0){
+                LOG(L_CRIT, "could not initialize memory pool\n");
+               return -1;
+        }
+#endif
+
+#ifdef SHM_MEM
+        if (shm_mem_init()<0) {
+                LOG(L_CRIT, "could not initialize shared memory pool, exiting...\n");
+                return -1;
+        }
+#endif
+       return 0;
+
+}
+
+
diff --git a/mem/mem.h b/mem/mem.h
new file mode 100644 (file)
index 0000000..64615dc
--- /dev/null
+++ b/mem/mem.h
@@ -0,0 +1,68 @@
+/* $Id$
+ *
+ * memory related stuff (malloc & friends)
+ * 
+ */
+
+
+#ifndef mem_h
+#define mem_h
+#include "../config.h"
+#include "../dprint.h"
+
+#ifdef PKG_MALLOC
+#      ifdef VQ_MALLOC
+#              include "vq_malloc.h"
+               extern struct vqm_block* mem_block;
+#      else
+#              include "q_malloc.h"
+               extern struct qm_block* mem_block;
+#      endif
+
+       extern char mem_pool[PKG_MEM_POOL_SIZE];
+
+
+#      ifdef DBG_QM_MALLOC
+#              ifdef VQ_MALLOC
+#                      define pkg_malloc(s) vqm_malloc(mem_block, (s),__FILE__, \
+                               __FUNCTION__, __LINE__);
+#                      define pkg_free(p)   vqm_free(mem_block, (p), __FILE__,  \
+                               __FUNCTION__, __LINE__);
+#              else
+#                      define pkg_malloc(s) qm_malloc(mem_block, (s),__FILE__, \
+                               __FUNCTION__, __LINE__);
+#                      define pkg_free(p)   qm_free(mem_block, (p), __FILE__,  \
+                               __FUNCTION__, __LINE__);
+#              endif
+#      else
+#              ifdef VQ_MALLOC
+#                      define pkg_malloc(s) vqm_malloc(mem_block, (s))
+#                      define pkg_free(p)   vqm_free(mem_block, (p))
+#              else
+#                      define pkg_malloc(s) qm_malloc(mem_block, (s))
+#                      define pkg_free(p)   qm_free(mem_block, (p))
+#              endif
+#      endif
+#      ifdef VQ_MALLOC
+#              define pkg_status()  vqm_status(mem_block)
+#      else
+#              define pkg_status()  qm_status(mem_block)
+#      endif
+#elif defined(SHM_MEM) && defined(USE_SHM_MEM)
+#      include "shm_mem.h"
+#      define pkg_malloc(s) shm_malloc((s))
+#      define pkg_free(p)   shm_free((p))
+#      define pkg_status()  shm_status()
+#else
+#      include <stdlib.h>
+#      define pkg_malloc(s) \
+       (  { void *v; v=malloc((s)); \
+          DBG("malloc %x size %d end %x\n", v, s, (unsigned int)v+(s));\
+          v; } )
+#      define pkg_free(p)  do{ DBG("free %x\n", (p)); free((p)); }while(0);
+#      define pkg_status()
+#endif
+
+int init_mallocs();
+
+#endif
diff --git a/mem/memtest.c b/mem/memtest.c
new file mode 100644 (file)
index 0000000..64110d9
--- /dev/null
@@ -0,0 +1,133 @@
+#ifdef DBG_QM_MALLOC
+
+#include "../globals.h"
+#include "../config.h"
+
+#ifdef PKG_MALLOC
+#       ifdef VQ_MALLOC
+#               include "vq_malloc.h"
+#              define MY_MALLOC vqm_malloc
+#              define MY_FREE vqm_free
+#              define MY_INIT vqm_malloc_init
+#              define MY_BLOCK vqm_block
+#              define MY_STATUS vqm_status
+#       else
+#               include "q_malloc.h"
+#              define MY_MALLOC qm_malloc
+#              define MY_FREE qm_free
+#              define MY_INIT qm_malloc_init
+#              define MY_BLOCK qm_block
+#              define MY_STATUS qm_status
+#       endif
+#endif
+
+
+void memtest()
+{
+#define        TEST_SIZE 1024*1024
+#define        TEST_RUN 1024
+#define LONG_RUN 100000
+#define ma(s) MY_MALLOC(mem_block, (s),__FILE__, __FUNCTION__, \
+                                                                __LINE__);
+#define mf(p)   MY_FREE(mem_block, (p), __FILE__,  __FUNCTION__, \
+                                                                __LINE__);
+       char tst_mem[TEST_SIZE];
+       struct MY_BLOCK* mem_block;
+       char *p0,*p1,*p2,*p3,*p4,*p5,*p6,*p7,*p8,*p9;
+       int i, j, f;
+       char *p[TEST_RUN];
+       int t;
+
+       debug=7;
+       log_stderr=1;
+
+       printf("entering test\n");
+
+       mem_block=MY_INIT( tst_mem, TEST_SIZE );
+
+       /* coalesing test w/big fragments */
+       p0=ma(8194);
+       p1=ma(8194);
+       p2=ma(8194);
+       MY_STATUS(mem_block);
+       mf(p1);
+       mf(p0);
+       MY_STATUS(mem_block);
+       mf(p2);
+       MY_STATUS(mem_block);
+
+       /* reuse test w/big fragments */
+       p0=ma(8194);
+       p1=ma(4196);
+       mf(p0);
+       p0=ma(8190);
+       MY_STATUS(mem_block);
+       mf(p1);
+       mf(p0);
+       MY_STATUS(mem_block);
+
+
+       exit(0);
+
+       p0=ma(8);
+       p1=ma(24);
+       p2=ma(32);
+       p3=ma(32);
+       p4=ma(32);
+       p5=ma(1024);
+       p6=ma(2048);
+
+//     MY_STATUS(mem_block);
+
+//     *(p0+9)=0;
+       mf(p0);
+       mf(p2);
+       mf(p5);
+       mf(p6);
+       
+//     MY_STATUS(mem_block);
+
+       mf(p1);
+       mf(p4);
+       mf(p3);
+//     mf(p3);
+
+//     MY_STATUS(mem_block);
+
+       for (i=0;i<TEST_RUN;i++)
+               p[i]=ma( random() & 1023 );
+//     MY_STATUS(mem_block);
+       for (i=0;i<TEST_RUN;i++)
+               mf( p[i] );
+//     MY_STATUS(mem_block);
+
+       f = 0;
+#define GRANULARITY 100
+       for (j=0; j<LONG_RUN; j++) {
+               for (i=0;i<TEST_RUN;i++) {
+                       t=random() & 1023;
+                       if (! (t%24) ) t=(t+4096)*2;
+                       p[i]=ma( random() & 1023 );
+               }
+               for (i=TEST_RUN/3;i<2*TEST_RUN/3;i++)
+                       mf( p[i] );
+               for (i=TEST_RUN/3;i<2*TEST_RUN/3;i++) {
+                       t=random() & 1023;
+                       if (! (t%24) ) t=(t+4096)*2;
+                       p[i]=ma( random() & 1023 );
+               }
+               for (i=0;i<TEST_RUN;i++)
+                       mf( p[i] );
+               if ( GRANULARITY*j/LONG_RUN > f ) {
+                       f=GRANULARITY*j/LONG_RUN ;
+                       printf("%d%% done\n", f);
+               }
+       }
+       printf("now I'm really done\n");
+       MY_STATUS(mem_block);
+       printf("And I'm done with dumping final report too\n");
+       
+       exit(0);
+}
+
+#endif
similarity index 92%
rename from q_malloc.c
rename to mem/q_malloc.c
index 7708531..73aa478 100644 (file)
@@ -2,29 +2,29 @@
  *
  */
 
+#if !defined(q_malloc) && !(defined VQ_MALLOC)
 #define q_malloc
-#ifdef q_malloc
 
 #include "q_malloc.h"
-#include "dprint.h"
+#include "../dprint.h"
 
 
-/*usefull macros*/
+/*useful macros*/
 #define FRAG_END(f)  \
-                       ((struct qm_frag_end*)((char*)(f)+sizeof(struct qm_frag)+ \
-                                                                  (f)->size))
+       ((struct qm_frag_end*)((char*)(f)+sizeof(struct qm_frag)+ \
+          (f)->size))
 
 #define FRAG_NEXT(f) \
-                       ((struct qm_frag*)((char*)(f)+sizeof(struct qm_frag)+(f)->size+ \
-                                                          sizeof(struct qm_frag_end)))
+       ((struct qm_frag*)((char*)(f)+sizeof(struct qm_frag)+(f)->size+ \
+          sizeof(struct qm_frag_end)))
                        
 #define FRAG_PREV(f) \
-               ( (struct qm_frag*) ( ((char*)(f)-sizeof(struct qm_frag_end))- \
-               ((struct qm_frag_end*)((char*)(f)-sizeof(struct qm_frag_end)))->size- \
-                       sizeof(struct qm_frag) ) )
+       ( (struct qm_frag*) ( ((char*)(f)-sizeof(struct qm_frag_end))- \
+       ((struct qm_frag_end*)((char*)(f)-sizeof(struct qm_frag_end)))->size- \
+          sizeof(struct qm_frag) ) )
 
 #define PREV_FRAG_END(f) \
-               ((struct qm_frag_end*)((char*)(f)-sizeof(struct qm_frag_end)))
+       ((struct qm_frag_end*)((char*)(f)-sizeof(struct qm_frag_end)))
 
 #ifdef DBG_QM_MALLOC
 #define ST_CHECK_PATTERN   0xf0f0f0f0
@@ -162,6 +162,9 @@ void* qm_malloc(struct qm_block* qm, unsigned int size)
        unsigned int overhead;
        
 #ifdef DBG_QM_MALLOC
+       unsigned int list_cntr;
+
+       list_cntr = 0;
        DBG("qm_malloc(%x, %d) called from %s: %s(%d)\n", qm, size, file, func,
                        line);
 #endif
@@ -171,6 +174,10 @@ void* qm_malloc(struct qm_block* qm, unsigned int size)
        if (qm->free_lst.u.nxt_free==&(qm->free_lst)) return 0;
        /*search for a suitable free frag*/
        for (f=qm->free_lst.u.nxt_free; f!=&(qm->free_lst); f=f->u.nxt_free){
+#ifdef DBG_QM_MALLOC
+               list_cntr++;
+#endif
+               
                if (f->size>=size){
                        /* we found it!*/
                        /*detach it from the free list*/
@@ -220,8 +227,8 @@ void* qm_malloc(struct qm_block* qm, unsigned int size)
                        f->check=ST_CHECK_PATTERN;
                /*  FRAG_END(f)->check1=END_CHECK_PATTERN1;
                        FRAG_END(f)->check2=END_CHECK_PATTERN2;*/
-       DBG("qm_malloc(%x, %d) returns address %x\n", qm, size,
-                       (char*)f+sizeof(struct qm_frag) );
+       DBG("qm_malloc(%x, %d) returns address %x on %d -th hit\n", qm, size,
+                       (char*)f+sizeof(struct qm_frag), list_cntr );
 #endif
                        return (char*)f+sizeof(struct qm_frag);
                }
@@ -318,6 +325,8 @@ void qm_status(struct qm_block* qm)
        int i;
 
        LOG(L_INFO, "qm_status (%x):\n", qm);
+       if (!qm) return;
+
        LOG(L_INFO, " heap size= %d\n", qm->size);
        LOG(L_INFO, " used= %d, used+overhead=%d, free=%d\n",
                        qm->used, qm->real_used, qm->size-qm->real_used);
similarity index 96%
rename from q_malloc.h
rename to mem/q_malloc.h
index 826983f..eaaa6fa 100644 (file)
@@ -3,7 +3,7 @@
  * simple & fast malloc library
  */
 
-#ifndef q_malloc_h
+#if !defined(q_malloc_h) && !defined(VQ_MALLOC)
 #define q_malloc_h
 
 
similarity index 92%
rename from shm_mem.c
rename to mem/shm_mem.c
index 8ce439b..c951d66 100644 (file)
--- a/shm_mem.c
@@ -6,7 +6,7 @@
 #ifdef SHM_MEM
 
 #include "shm_mem.h"
-#include "config.h"
+#include "../config.h"
 
 #ifdef  SHM_MMAP
 
 #ifndef SHM_MMAP
 static int shm_shmid=-1; /*shared memory id*/
 #endif
+
+
 int shm_semid=-1; /*semaphore id*/
 static void* shm_mempool=(void*)-1;
-struct qm_block* shm_block;
+#ifdef VQ_MALLOC
+       struct vqm_block* shm_block;
+#else
+       struct qm_block* shm_block;
+#endif
 
 
 
@@ -110,7 +116,11 @@ int shm_mem_init()
                return -1;
        }
        /* init it for malloc*/
-       shm_block=qm_malloc_init(shm_mempool, SHM_MEM_SIZE);
+#      ifdef VQ_MALLOC
+               shm_block=vqm_malloc_init(shm_mempool, SHM_MEM_SIZE);
+#      else
+               shm_block=qm_malloc_init(shm_mempool, SHM_MEM_SIZE);
+#      endif
        if (shm_block==0){
                LOG(L_CRIT, "ERROR: shm_mem_init: could not initialize shared"
                                " malloc\n");
similarity index 76%
rename from shm_mem.h
rename to mem/shm_mem.h
index 7abb3f7..f654923 100644 (file)
--- a/shm_mem.h
 
 
 
-#include "q_malloc.h"
-#include "dprint.h"
-
-extern struct qm_block* shm_block;
+#include "../dprint.h"
+
+#ifdef VQ_MALLOC
+#      include "vq_malloc.h"
+       extern struct vqm_block* shm_block;
+#      define MY_MALLOC vqm_malloc
+#      define MY_FREE vqm_free
+#      define MY_STATUS vqm_status
+#else
+#      include "q_malloc.h"
+       extern struct qm_block* shm_block;
+#      define MY_MALLOC qm_malloc
+#      define MY_FREE qm_free
+#      define MY_STATUS qm_status
+#endif
 extern int shm_semid;
 
 int shm_mem_init();
@@ -94,7 +105,7 @@ again:
        \
        /*if (shm_lock()==0){*/\
                shm_lock();\
-               p=qm_malloc(shm_block, (size), __FILE__, __FUNCTION__, __LINE__);\
+               p=MY_MALLOC(shm_block, (size), __FILE__, __FUNCTION__, __LINE__);\
                shm_unlock();\
        /* \
        }else{ \
@@ -108,7 +119,7 @@ again:
 #define shm_free(p) \
 do { \
                shm_lock(); \
-               qm_free(shm_block, (p), __FILE__, __FUNCTION__, __LINE__); \
+               MY_FREE(shm_block, (p), __FILE__, __FUNCTION__, __LINE__); \
                shm_unlock(); \
 }while(0)
 
@@ -122,7 +133,7 @@ do { \
        \
        /*if (shm_lock()==0){*/\
                shm_lock();\
-               p=qm_malloc(shm_block, (size));\
+               p=MY_MALLOC(shm_block, (size));\
                shm_unlock();\
        /* \
        }else{ \
@@ -136,7 +147,7 @@ do { \
 #define shm_free(p) \
 do { \
                shm_lock(); \
-               qm_free(shm_block, (p)); \
+               MY_FREE(shm_block, (p)); \
                shm_unlock(); \
 }while(0)
 
@@ -147,7 +158,7 @@ do { \
 #define shm_status() \
 do { \
                shm_lock(); \
-               qm_status(shm_block); \
+               MY_STATUS(shm_block); \
                shm_unlock(); \
 }while(0)
 
diff --git a/mem/vq_malloc.c b/mem/vq_malloc.c
new file mode 100644 (file)
index 0000000..ad25473
--- /dev/null
@@ -0,0 +1,438 @@
+/* $Id$
+ *
+ * History: 
+ * merged from Andrei's qmalloc and many fragments from Regents 
+ * University of California NetBSD malloc used; see
+ * http://www.ajk.tele.fi/libc/stdlib/malloc.c.html#malloc for more
+ * details including redistribution policy; this policy asks for
+ * displaying the copyright:
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ *
+ * About:
+ * aggressive, wasteful and very quick malloc library built for
+ * servers that continuously alocate and release chunks of only
+ * few sizes:
+ * - free lists are organized by size (which eliminates long list traversal 
+ *   thru short free chunks if a long one is asked)
+ * - quite a few sizes are supported --> this results in more waste
+ *    (unused place in a chunk) however memory can be well reused after
+ *    freeing
+ * - the last bucket holds unlikely, huge, variable length chunks;
+ *   they are maintained as stack growing from the opposite direction
+ *   of our heap; coalesing is enabled; stack-like first-fit used to
+ *   find free fragments
+ *
+ * TODO: possibly, some delayed coalescation wouldn't hurt; also, further
+ * optimization will certainly speed-up the entire process a lot; using
+ * knowledge of application as well as trying to make pipeline happy
+ * (from which I am sadly far away now)
+ * provides optimization space; trying to use other memory allocators
+ * to compare would be a great thing to do too;
+ *
+ * also, comparing to other memory allocaters (like Horde) would not
+ * be a bad idea: those folks have been doing that for ages and specifically
+ * Horde has been heavily optimized for multi-processor machines
+ *
+ * References:
+ *   - list of malloc implementations: http://www.cs.colorado.edu/~zorn/Malloc.html
+ *   - a white-paper: http://g.oswego.edu/dl/html/malloc.html
+ *   - Paul R. Wilson, Mark S. Johnstone, Michael Neely, and David Boles: 
+       ``Dynamic Storage Allocation: A Survey and Critical Review'' in International 
+       Workshop on Memory Management, September 1995, 
+       ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps
+ *   - ptmalloc: http://www.malloc.de/en/
+ *   - GNU C-lib malloc: http://www.gnu.org/manual/glibc-2.0.6/html_chapter/libc_3.html
+ *   - delorie malocs: http://www.delorie.com/djgpp/malloc/
+ */
+
+#ifdef VQ_MALLOC
+
+#include "../config.h"
+#include "../globals.h"
+#include "vq_malloc.h"
+#include "../dprint.h"
+
+#define BIG_BUCKET(_qm) ((_qm)->max_small_bucket+1)
+#define IS_BIGBUCKET(_qm, _bucket) ((_bucket)==BIG_BUCKET(_qm)) 
+
+#ifdef DBG_QM_MALLOC
+#define ASSERT(a)      \
+       my_assert(a, __LINE__, __FILE__, __FUNCTION__ )
+#else
+#define ASSERT(a)
+#endif
+
+#ifdef DBG_QM_MALLOC
+#      define MORE_CORE(_q,_b,_s) (more_core( (_q), (_b), (_s), file, func, line ))
+#else
+#      define MORE_CORE(_q,_b,_s) (more_core( (_q), (_b), (_s) ))
+#endif
+
+
+
+/* dimensioning buckets: define the step function constants for size2bucket */
+int s2b_step[] = {8, 16, 32, 64, 128, 256, 512, 1024, 1536, 2048, 2560, MAX_FIXED_BLOCK, EO_STEP };
+
+void my_assert( int assertation, int line, char *file, char *function )
+{
+       if (assertation) return;
+
+       LOG(L_CRIT,"CRIT: assertation failed in $s (%s:%d)\n",
+               function, file, line);
+       abort();
+}
+
+#ifdef DBG_QM_MALLOC
+static  void vqm_debug_frag(struct vqm_block* qm, struct vqm_frag* f)
+{
+
+       int r;
+
+       if (f->check!=ST_CHECK_PATTERN){
+               LOG(L_CRIT, "BUG: vqm_*: fragm. %x beginning overwritten(%x)!\n",
+                               f, f->check);
+               vqm_status(qm);
+               abort();
+       };
+       if (memcmp(f->end_check, END_CHECK_PATTERN, END_CHECK_PATTERN_LEN)!=0) {
+               LOG(L_CRIT, "BUG: vqm_*: fragm. %x end overwritten(%*s)!\n",
+                               f, END_CHECK_PATTERN_LEN, f->end_check );
+               vqm_status(qm);
+               abort();
+       }
+}
+#endif
+
+
+/* takes  demanded size without overhead as input, returns bucket number
+   and changed the demanded size to size really used including all
+   possible overhead
+ */
+unsigned char size2bucket( struct vqm_block* qm, int *size )
+{
+       unsigned char b;        
+       unsigned int real_size;
+       unsigned int exceeds;
+
+
+       real_size = *size+ sizeof(struct vqm_frag)+
+                       sizeof(struct vqm_frag_end);
+#ifdef DBG_QM_MALLOC
+       real_size+=END_CHECK_PATTERN_LEN;
+#endif
+       real_size+=((exceeds = (real_size % 8 )) ? 8 - exceeds : 0);
+       ASSERT( !(real_size%8) );
+       /* "small" chunk sizes <=1k translated using a table */
+       if ( real_size < MAX_FIXED_BLOCK ) {
+               b = qm->s2b[ real_size ];
+               *size = qm->s2s[ real_size ];
+       /* there might be various allocations slightly 1>1k, I still
+          don't want to be too agressive and increase useless 
+          allocations in small steps
+       */      
+       } else {
+               b = BIG_BUCKET(qm); 
+               *size = MAX_FIXED_BLOCK + 
+                       (real_size-MAX_FIXED_BLOCK+BLOCK_STEP) 
+                       / BLOCK_STEP * BLOCK_STEP;
+       }
+       /*size must be a multiple of 8*/
+       ASSERT( !(*size%8) );
+       return b;
+}
+
+
+/* init malloc and return a qm_block */
+struct vqm_block* vqm_malloc_init(char* address, unsigned int size)
+{
+       char* start;
+       struct vqm_block* qm;
+       unsigned int init_overhead;
+       unsigned char b;        /* bucket iterator */
+       unsigned int s;         /* size iterator */
+       char *end;
+       
+       /* make address and size multiple of 8*/
+       start=(char*)( ((unsigned int)address%8)?((unsigned int)address+8)/8*8:
+                       (unsigned int)address);
+       if (size<start-address) return 0;
+       size-=(start-address);
+       if (size <8) return 0;
+       size=(size%8)?(size-8)/8*8:size;
+
+       init_overhead=sizeof(struct vqm_block);
+       if (size < init_overhead)
+       {
+               /* not enough mem to create our control structures !!!*/
+               return 0;
+       }
+       end = start + size;
+       qm=(struct vqm_block*)start;
+       memset(qm, 0, sizeof(struct vqm_block));
+       size-=init_overhead;
+
+       /* definition of the size2bucket table */
+       for (s=0, b=0; s<MAX_FIXED_BLOCK ; s++) {
+               while (s>s2b_step[b]) b++;
+               if (b>MAX_BUCKET) {
+                       LOG(L_CRIT, "CRIT: vqm_malloc_init: attempt to install too many buckets,"
+                               "s2b_step > MAX_BUCKET\n");
+                       return 0;
+               }
+               qm->s2b[s] = b;
+               qm->s2s[s] = s2b_step[b];
+       }
+       qm->max_small_bucket = b;
+
+       /* from where we will draw memory */
+       qm->core = (char *) ( start + sizeof( struct vqm_block ) );
+       qm->free_core = size;
+       /* remember for bound checking */
+       qm->init_core = qm->core;
+       qm->core_end = end;
+       /* allocate big chunks from end */
+       qm->big_chunks = end;
+       
+       return qm;
+}
+
+
+
+struct vqm_frag *more_core(    struct vqm_block* qm, 
+                               unsigned char bucket, unsigned int size
+#ifdef DBG_QM_MALLOC
+                               , char *file, char *func, unsigned int line
+#endif
+                        ) 
+{
+       struct vqm_frag *new_chunk;
+       struct vqm_frag_end *end;
+
+       if (qm->free_core<size) return 0;
+
+       /* update core */
+       if (IS_BIGBUCKET(qm, bucket)) {
+               qm->big_chunks-=size;
+               new_chunk = (struct vqm_frag *) qm->big_chunks ;        
+       } else {
+               new_chunk = (struct vqm_frag *) qm->core;       
+               qm->core+=size;
+       }
+       qm->free_core-=size;
+
+       /* initialize the new fragment */
+       new_chunk->u.inuse.bucket = bucket;
+       new_chunk->size = size;
+
+       end=FRAG_END( new_chunk );
+       end->size=size;
+
+       return new_chunk;
+}
+
+static inline void vqm_detach_free( struct vqm_block* qm, struct vqm_frag* frag)
+{
+
+       struct vqm_frag *prev, *next;
+       struct vqm_frag_end *end;
+
+       prev=FRAG_END(frag)->prv_free; 
+       next=frag->u.nxt_free;
+
+       if (prev) prev->u.nxt_free=next; 
+       else qm->next_free[BIG_BUCKET(qm)]=next;
+
+       if (next) FRAG_END(next)->prv_free=prev; 
+        
+}
+
+
+#ifdef DBG_QM_MALLOC
+void* vqm_malloc(struct vqm_block* qm, unsigned int size, 
+       char* file, char* func, unsigned int line)
+#else
+void* vqm_malloc(struct vqm_block* qm, unsigned int size)
+#endif
+{
+       struct vqm_frag *new_chunk, *f;
+       unsigned char bucket;
+       
+#ifdef DBG_QM_MALLOC
+       unsigned int demanded_size;
+       DBG("vqm_malloc(%x, %d) called from %s: %s(%d)\n", qm, size, file, func,
+                       line);
+       demanded_size = size;
+#endif
+       new_chunk=0;
+       /* what's the bucket? what's the total size incl. overhead? */
+       bucket = size2bucket( qm, &size );
+
+       if (IS_BIGBUCKET(qm, bucket)) { /* the kilo-bucket uses first-fit */
+               DBG("vqm_malloc: processing a big fragment\n");
+               for (f=qm->next_free[bucket] ; f; f=f->u.nxt_free ) 
+                       if (f->size>=size) { /* first-fit */
+                               new_chunk=f;
+                               VQM_DEBUG_FRAG(qm, f);
+                               vqm_detach_free(qm,f);
+                               break;
+                       }
+       } else if (  (new_chunk=qm->next_free[ bucket ]) ) { /*fixed size bucket*/
+                       VQM_DEBUG_FRAG(qm, new_chunk);
+                       /*detach it from the head of bucket's free list*/
+                       qm->next_free[ bucket ] = new_chunk->u.nxt_free;
+       }
+
+       if (!new_chunk) { /* no chunk can be reused; slice one from the core */
+               new_chunk=MORE_CORE( qm, bucket, size );
+               if (!new_chunk) return 0;
+       }
+       new_chunk->u.inuse.magic = FR_USED;
+       new_chunk->u.inuse.bucket=bucket;
+#ifdef DBG_QM_MALLOC
+       new_chunk->file=file;
+       new_chunk->func=func;
+       new_chunk->line=line;
+       new_chunk->demanded_size=demanded_size;
+       qm->usage[ bucket ]++;
+       DBG("vqm_malloc( %x, %d ) returns address %x in bucket %d, real-size %d \n",
+               qm, demanded_size, (char*)new_chunk+sizeof(struct vqm_frag), 
+               bucket, size );
+
+       new_chunk->end_check=(char*)new_chunk+sizeof(struct vqm_frag)+demanded_size;
+       memcpy(  new_chunk->end_check, END_CHECK_PATTERN, END_CHECK_PATTERN_LEN );
+       new_chunk->check=ST_CHECK_PATTERN;
+#endif
+       return (char*)new_chunk+sizeof(struct vqm_frag);
+}
+
+
+
+
+#ifdef DBG_QM_MALLOC
+void vqm_free(struct vqm_block* qm, void* p, char* file, char* func, 
+                               unsigned int line)
+#else
+void vqm_free(struct vqm_block* qm, void* p)
+#endif
+{
+       struct vqm_frag *f, *next, *prev, *first_big;
+       unsigned char b;
+
+#ifdef DBG_QM_MALLOC
+       DBG("vqm_free(%x, %x), called from %s: %s(%d)\n", qm, p, file, func, line);
+       if (p>(void *)qm->core_end || p<(void*)qm->init_core){
+               LOG(L_CRIT, "BUG: vqm_free: bad pointer %x (out of memory block!) - "
+                               "aborting\n", p);
+               abort();
+       }
+#endif
+       if (p==0) {
+               DBG("WARNING:vqm_free: free(0) called\n");
+               return;
+       }
+       f=(struct  vqm_frag*) ((char*)p-sizeof(struct vqm_frag));
+       b=f->u.inuse.bucket;
+#ifdef DBG_QM_MALLOC
+       VQM_DEBUG_FRAG(qm, f);
+       if ( ! FRAG_ISUSED(f) ) {
+               LOG(L_CRIT, "BUG: vqm_free: freeing already freed pointer,"
+                               " first freed: %s: %s(%d) - aborting\n",
+                               f->file, f->func, f->line);
+               abort();
+       }
+       if ( b>MAX_BUCKET ) {
+               LOG(L_CRIT, "BUG: vqm_free: fragment with too high bucket nr: "
+                               "%d, allocated: %s: %s(%d) - aborting\n",
+                               b, f->file, f->func, f->line); 
+               abort();
+       }
+       DBG("vqm_free: freeing %d bucket block alloc'ed from %s: %s(%d)\n", 
+               f->u.inuse.bucket, f->file, f->func, f->line);
+       f->file=file; f->func=func; f->line=line;
+       qm->usage[ f->u.inuse.bucket ]--;
+#endif
+       if (IS_BIGBUCKET(qm,b)) {
+               next=FRAG_NEXT(f);
+               if  ((char *)next +sizeof( struct vqm_frag) < qm->core_end) {
+                       VQM_DEBUG_FRAG(qm, next);
+                       if (! FRAG_ISUSED(next)) { /* coalescate with next fragment */
+                               DBG("vqm_free: coalescated with next\n");
+                               vqm_detach_free(qm, next);
+                               f->size+=next->size;
+                               FRAG_END(f)->size=f->size;
+                       }
+               }
+               first_big = qm->next_free[b];
+               if (first_big &&  f>first_big) {
+                       prev=FRAG_PREV(f);
+                       VQM_DEBUG_FRAG(qm, prev);
+                       if (!FRAG_ISUSED(prev)) { /* coalescate with prev fragment */
+                               DBG("vqm_free: coalescated with prev\n");
+                               vqm_detach_free(qm, prev );
+                               prev->size+=f->size;
+                               f=prev;
+                               FRAG_END(f)->size=f->size;
+                       }
+               }
+               if ((char *)f==qm->big_chunks) { /* release unused core */
+                       DBG("vqm_free: big chunk released\n");
+                       qm->free_core+=f->size;
+                       qm->big_chunks+=f->size;
+                       return;
+               }               
+               first_big = qm->next_free[b];
+               /* fix reverse link (used only for BIG_BUCKET */
+               if (first_big) FRAG_END(first_big)->prv_free=f;
+               FRAG_END(f)->prv_free=0;
+       } else first_big = qm->next_free[b];
+       f->u.nxt_free = first_big; /* also clobbers magic */
+       qm->next_free[b] = f;
+}
+
+void dump_frag( struct vqm_frag* f, int i )
+{
+       LOG(L_INFO, "    %3d. address=%x  real size=%d bucket=%d\n", i, 
+               (char*)f+sizeof(struct vqm_frag), f->size, f->u.inuse.bucket);
+#ifdef DBG_QM_MALLOC
+       LOG(L_INFO, "            demanded size=%d\n", f->demanded_size );
+       LOG(L_INFO, "            alloc'd from %s: %s(%d)\n",
+               f->file, f->func, f->line);
+       LOG(L_INFO, "        start check=%x, end check= %*s\n",
+                       f->check, END_CHECK_PATTERN_LEN, f->end_check );
+#endif
+}
+
+void vqm_status(struct vqm_block* qm)
+{
+       struct vqm_frag* f;
+       unsigned int i,j,on_list;
+
+       LOG(L_INFO, "vqm_status (%x):\n", qm);
+       if (!qm) return;
+       LOG(L_INFO, " heap size= %d, available: %d\n", 
+               qm->core_end-qm->init_core, qm->free_core );
+       
+       LOG(L_INFO, "dumping unfreed fragments:\n");
+       for (f=(struct vqm_frag*)qm->init_core, i=0;(char*)f<(char*)qm->core;
+               f=FRAG_NEXT(f) ,i++) if ( FRAG_ISUSED(f) ) dump_frag(f, i);
+
+       LOG(L_INFO, "dumping unfreed big fragments:\n");
+    for (f=(struct vqm_frag*)qm->big_chunks,i=0;(char*)f<(char*)qm->core_end;
+               f=FRAG_NEXT(f) ,i++) if ( FRAG_ISUSED(f) ) dump_frag( f, i );
+
+#ifdef DBG_QM_MALLOC
+       DBG("dumping bucket statistics:\n");
+       for (i=0; i<=BIG_BUCKET(qm); i++) {
+               for(on_list=0, f=qm->next_free[i]; f; f=f->u.nxt_free ) on_list++;
+               LOG(L_DBG, "    %3d. bucket: in use: %d, on free list: %d\n", 
+                       i, qm->usage[i], on_list );
+       }
+#endif
+       LOG(L_INFO, "-----------------------------\n");
+}
+
+
+
+#endif
diff --git a/mem/vq_malloc.h b/mem/vq_malloc.h
new file mode 100644 (file)
index 0000000..2cb8aa4
--- /dev/null
@@ -0,0 +1,130 @@
+/* $Id$
+ *
+ */
+
+#if !defined(VQ_MALLOC_H) && defined(VQ_MALLOC)
+#define VQ_MALLOC_H
+
+#include "../config.h"
+
+
+/* indicates this fragment is not in use (must not be offset of valid
+   aligned fragment beginning
+*/
+#define        FR_USED         0xef
+
+/*useful macros*/
+#define FRAG_END(f)  \
+       ((struct vqm_frag_end*)((char*)(f)-sizeof(struct vqm_frag_end)+ \
+       (f)->size))
+
+#define FRAG_NEXT(f) \
+       ((struct vqm_frag*)((char*)(f)+(f)->size))
+
+#define PREV_FRAG_END(f) \
+       ((struct vqm_frag_end*)((char*)(f)-sizeof(struct vqm_frag_end)))
+
+#define FRAG_PREV(f) \
+       ( (struct vqm_frag*) ( (char*)(f) - PREV_FRAG_END(f)->size ))
+
+#define FRAG_ISUSED(f) \
+       ((f)->u.inuse.magic==FR_USED)
+
+/* just a bumper for the step function */
+#define EO_STEP                         -1
+
+
+#ifdef DBG_QM_MALLOC
+#define ST_CHECK_PATTERN       0xf0f0f0f0
+#define END_CHECK_PATTERN      "sExP"
+#define END_CHECK_PATTERN_LEN  4
+
+#define VQM_DEBUG_FRAG(qm, f) vqm_debug_frag( (qm), (f))
+#else
+#define VQM_DEBUG_FRAG(qm, f)
+#endif
+
+
+struct vqm_frag {
+       /* XXX */
+       /* total chunk size including all overhead/bellowfoot/roundings/etc */
+       /* useless as otherwise size implied by bucket (if I really want to save 
+       bytes, I'll remove it  from here */
+       unsigned int size;
+       union{
+               /* pointer to next chunk in a bucket if free */
+               struct vqm_frag* nxt_free; 
+               struct {   /* or bucket number if busy */
+                       unsigned char magic;
+                       unsigned char bucket;
+        } inuse;
+       } u;
+#ifdef DBG_QM_MALLOC
+       /* source code info */
+       char* file;
+       char* func;
+       unsigned int line;
+       /* your safety is important to us! safety signatures */
+       unsigned int check;
+       char *end_check;
+       /* the size user was originally asking for */
+       unsigned int demanded_size;
+#endif
+};
+
+struct vqm_frag_end{
+       /* total chunk size including all overhead/bellowfoot/roundings/etc */
+       unsigned int size; 
+       /* XXX */
+       /* used only for variable-size chunks; might have different
+           data structures for variable/fixed length chunks */
+       struct vqm_frag* prv_free;
+};
+
+
+struct vqm_block{
+       /* size to bucket table */
+       unsigned char s2b[ MAX_FIXED_BLOCK ];
+       /* size to rounded size */
+       unsigned short s2s[ MAX_FIXED_BLOCK ];
+       unsigned char max_small_bucket;
+
+       /* core gained on init ... */
+       char *core, *init_core, *core_end;
+       /* ... and its available net amount; note that there's lot of
+           free memory in buckets too -- this just tells about memory
+          which has not been assigned to chunks  */
+       unsigned int free_core;
+       /* we allocate huge chunks from the end on; this is the
+          pointer to big chunks
+    */
+       char *big_chunks;
+
+       struct vqm_frag* next_free[ MAX_BUCKET +1];
+#ifdef DBG_QM_MALLOC
+       unsigned long usage[ MAX_BUCKET +1];
+#endif
+};
+
+
+
+struct vqm_block* vqm_malloc_init(char* address, unsigned int size);
+
+#ifdef DBG_QM_MALLOC
+void* vqm_malloc(struct vqm_block*, unsigned int size, char* file, char* func, 
+                                       unsigned int line);
+#else
+void* vqm_malloc(struct vqm_block*, unsigned int size);
+#endif
+
+#ifdef DBG_QM_MALLOC
+void  vqm_free(struct vqm_block*, void* p, char* file, char* func, 
+                               unsigned int line);
+#else
+void  vqm_free(struct vqm_block*, void* p);
+#endif
+
+void  vqm_status(struct vqm_block*);
+
+
+#endif
index c5a2297..46b2cf9 100644 (file)
@@ -7,22 +7,9 @@ Things we have omitted for now:
 - no SIP-wise HF comparison within T-matching
   (just memcmp)
 - 6xx should be delayed indeed
+- relaying CANCEL should be delayed until a reply to
+  INVITE received if not yet
 - ACK of 2xx INV caching (avoid e2e retransmission
   of an ACK hit the proxy too)
-- timers (408)
 
-- Via:
-       - branch
-               - loop check
-               - hash table & index
-               - branch
-       - mid & response routing
-
-- T-language
-
-To improve:
-- too many memcpies
-- faster syncing
-
-Double-check: revire the T-state-machine
 To-do: semaphore clean-up on exit (even better: w/sibling check)
diff --git a/modules/tm/config.h b/modules/tm/config.h
new file mode 100644 (file)
index 0000000..8e9feed
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * $Id$
+ *
+ */
+
+#ifndef _TM_CONFIG_H
+#define _TM_CONFIG_H
+
+/* always use a power of 2 for hash table size */
+#define T_TABLE_POWER          10
+#define TABLE_ENTRIES                  (2 << (T_TABLE_POWER-1))
+
+/* maximum number of forks per transaction */
+#define MAX_FORK               2
+
+/* maximumum length of localy generated acknowledgement */
+#define MAX_ACK_LEN            1024
+
+/* FINAL_RESPONSE_TIMER ... tells how long should the transaction engine
+   wait if no final response comes back*/
+#define FR_TIME_OUT            16
+#define INV_FR_TIME_OUT        30
+
+/* WAIT timer ... tells how long state should persist in memory after
+   a transaction was finalized*/
+#define WT_TIME_OUT            5
+
+/* DELETE timer ... tells how long should the transaction persist in memory
+   after it was removed from the hash table and before it will be deleted */
+#define DEL_TIME_OUT           2
+/* retransmission timers */
+#define RETR_T1                1
+#define RETR_T2                4
+
+#endif
diff --git a/modules/tm/globals.h b/modules/tm/globals.h
deleted file mode 100644 (file)
index bb785f2..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * $Id$
- */
-
-
-
-#ifndef _H_GLOBALS
-#define _H_GLOBALS
-
-/* #define DBG( s ) printf( (s) ); */
-
-#endif
index 0192bde..7570a83 100644 (file)
@@ -2,7 +2,7 @@
  * $Id$
  */
 
-
+#include "hash_func.h"
 #include "h_table.h"
 #include "../../dprint.h"
 #include "sh_malloc.h"
   */
 void free_cell( struct cell* dead_cell )
 {
-   int i;
-   struct retrans_buff* rb;
-   char *b;
-
-   DBG("DEBUG: free_cell: start\n");
-   /* UA Server */
-   DBG("DEBUG: free_cell: inbound request %p\n",dead_cell->inbound_request);
-   if ( dead_cell->inbound_request )
-      sip_msg_free( dead_cell->inbound_request );
-   DBG("DEBUG: free_cell: outbound response %p\n",dead_cell->outbound_response);
-   if ( dead_cell->outbound_response )
-   {
-      b = dead_cell->outbound_response->retr_buffer ;
-      dead_cell->outbound_response->retr_buffer = NULL;
-      sh_free( b );
-
-      rb = dead_cell->outbound_response;
-      dead_cell->outbound_response = NULL;
-      sh_free( rb );
-
-   }
-
-  /* UA Clients */
-   for ( i =0 ; i<dead_cell->nr_of_outgoings;  i++ )
-   {
-      /* outbound requests*/
-      DBG("DEBUG: free_cell: outbound_request[%d] %p\n",i,dead_cell->outbound_request[i]);
-      if ( dead_cell->outbound_request[i] )
-      {
-        b = dead_cell->outbound_request[i]->retr_buffer;
-         dead_cell->outbound_request[i]->retr_buffer = NULL;
-         sh_free( b );
-
-        rb = dead_cell->outbound_request[i];
-        dead_cell->outbound_request[i] = NULL;
-         sh_free( rb );
-      }
-      /* outbound requests*/
-      DBG("DEBUG: free_cell: inbound_response[%d] %p\n",i,dead_cell->inbound_response[i]);
-      if ( dead_cell -> inbound_response[i] )
-         sip_msg_free( dead_cell->inbound_response[i] );
-   }
-   /* mutex */
-   release_cell_lock( dead_cell );
-   /* the cell's body */
-   sh_free( dead_cell );
-   DBG("DEBUG: free_cell: done\n");
+       int i;
+       struct retrans_buff* rb;
+       char *b;
+
+       DBG("DEBUG: free_cell: start\n");
+       /* UA Server */
+       DBG("DEBUG: free_cell: inbound request %p\n",dead_cell->inbound_request);
+       if ( dead_cell->inbound_request )
+               sip_msg_free( dead_cell->inbound_request );
+       DBG("DEBUG: free_cell: outbound response %p\n",dead_cell->outbound_response);
+       if (b=dead_cell->outbound_response.retr_buffer) sh_free( b );
+
+       /* UA Clients */
+       for ( i =0 ; i<dead_cell->nr_of_outgoings;  i++ )
+       {
+               /* outbound requests*/
+               DBG("DEBUG: free_cell: outbound_request[%d] %p\n",i,dead_cell->outbound_request[i]);
+               if ( rb=dead_cell->outbound_request[i] )
+               {
+                       if (rb->retr_buffer) sh_free( rb->retr_buffer );
+                       dead_cell->outbound_request[i] = NULL;
+                       sh_free( rb );
+               }
+               /* outbound requests*/
+               DBG("DEBUG: free_cell: inbound_response[%d] %p\n",i,dead_cell->inbound_response[i]);
+               if ( dead_cell -> inbound_response[i] )
+                       sip_msg_free( dead_cell->inbound_response[i] );
+       }
+       /* mutex */
+       /* release_cell_lock( dead_cell ); */
+       /* the cell's body */
+       sh_free( dead_cell );
+       DBG("DEBUG: free_cell: done\n");
 }
 
 
@@ -123,7 +109,7 @@ struct s_table* init_hash_table()
 
    /* inits the timers*/
    for(  i=0 ; i<NR_OF_TIMER_LISTS ; i++ )
-      init_timerlist_lock( hash_table, i );
+      init_timer_list( hash_table, i );
 
    return  hash_table;
 
@@ -182,7 +168,7 @@ struct cell*  build_cell( struct sip_msg* p_msg )
    new_cell->T_canceled  = T_UNDEFINED;
    new_cell->T_canceler  = T_UNDEFINED;
 
-   init_cell_lock(  new_cell );
+   /* init_cell_lock(  new_cell ); */
 
    DBG("DEBUG: build_cell : done\n");
    return new_cell;
index 0bdbdb3..f86550e 100644 (file)
@@ -12,6 +12,7 @@
 #include <arpa/inet.h>
 
 #include "../../msg_parser.h"
+#include "config.h"
 
 struct s_table;
 struct entry;
@@ -25,27 +26,10 @@ struct timer;
 #include "sip_msg.h"
 
 
-
-/* always use a power of 2 for hash table size */
-#define TABLE_ENTRIES  256
-#define MAX_FORK           20
-
-
 #define T_UNDEFINED    ( (struct cell*) -1 )
 #define T_NULL         ( (struct cell*) 0 )
 
 
-/* timer list: includes head, tail and protection semaphore */
-typedef struct  timer
-{
-   struct timer_link *first_tl;
-   struct timer_link *last_tl;
-   ser_lock_t             mutex;
-   void                      (*timeout_handler)(void*);
-} timer_type;
-
-
-
 
 typedef struct retrans_buff
 {
@@ -59,15 +43,22 @@ typedef struct retrans_buff
    size_t tolen;
 
    /* a message can be linked just to retransmission and FR list */
-   struct timer_link tl[2];
+   struct timer_link retr_timer;
+   struct timer_link fr_timer;
+/*
    unsigned int timeout_ceiling;
    unsigned int timeout_value;
+*/
 
    /*the cell that containes this retrans_buff*/
    struct cell* my_T;
+
+       enum lists retr_list;
+
 }retrans_buff_type;
 
 
+/* transaction context */
 
 typedef struct cell
 {
@@ -76,7 +67,9 @@ typedef struct cell
    struct cell*     prev_cell;
 
    /*sync data */
-   ser_lock_t   mutex;
+   /*
+       /* we use hash table mutexes now */
+   /* ser_lock_t   mutex; */
    int       ref_counter;
 
    /* cell payload data */
@@ -96,7 +89,7 @@ typedef struct cell
    /* usefull data */
    /* UA Server */
    struct sip_msg         *inbound_request;
-   struct retrans_buff   *outbound_response;
+   struct retrans_buff   outbound_response;
    unsigned int             status;
    str*                             tag;
    unsigned int             inbound_request_isACKed;
@@ -106,6 +99,11 @@ typedef struct cell
    struct retrans_buff   *outbound_request[ MAX_FORK ];
    struct sip_msg          *inbound_response[ MAX_FORK ];
    unsigned int             outbound_request_isACKed[MAX_FORK];
+
+#ifdef EXTRA_DEBUG
+       /* scheduled for deletion ? */
+       short damocles;
+#endif
 }cell_type;
 
 
@@ -123,7 +121,7 @@ typedef struct entry
 
 
 
-/* hash table */
+/* transaction table */
 struct s_table
 {
    /* table of hash entries; each of them is a list of synonyms  */
@@ -133,16 +131,11 @@ struct s_table
 };
 
 
-
-
-
 struct s_table* init_hash_table();
-void                  free_hash_table( struct s_table* hash_table );
-
-void             free_cell( struct cell* dead_cell );
+void free_hash_table( struct s_table* hash_table );
+void free_cell( struct cell* dead_cell );
 struct cell*  build_cell( struct sip_msg* p_msg );
-
-void remove_from_hash_table( struct s_table *hash_table,  struct cell * p_cell );
-void    insert_into_hash_table( struct s_table *hash_table,  struct cell * p_cell );
+void remove_from_hash_table( struct s_table *hash_table, struct cell * p_cell );
+void insert_into_hash_table( struct s_table *hash_table, struct cell * p_cell );
 
 #endif
index 21bbf5e..7315cd8 100644 (file)
@@ -3,11 +3,22 @@
  */
 
 
+#ifndef _CRC_H_
+#define _CRC_H_
+
+extern unsigned long int crc_32_tab[];
+extern unsigned short int ccitt_tab[];
+extern unsigned short int crc_16_tab[];
+
+#endif
+
 
 #include "hash_func.h"
 #include "../../dprint.h"
+#include "../../crc.h"
+#include "../../ut.h"
 
-int hash( str  call_id, str cseq_nr )
+int old_hash( str  call_id, str cseq_nr )
 {
    int  hash_code = 0;
    int  i;
@@ -19,3 +30,79 @@ int hash( str  call_id, str cseq_nr )
    return hash_code %= TABLE_ENTRIES;
 }
 
+int new_hash( str call_id, str cseq_nr )
+{
+       int hash_code = 0;
+       int i,j, k, third;
+       int ci_len, cs_len;
+       char c;
+       char *ci, *cs;
+
+       /* trim EoLs */
+/*
+       ci_len = call_id.len;
+       while (ci_len && ((c=call_id.s[ci_len-1])==0 || c=='\r' || c=='\n'))
+               ci_len--;
+       cs_len = cseq_nr.len;
+       while (cs_len && ((c=cseq_nr.s[cs_len-1])==0 || c=='\r' || c=='\n'))
+               cs_len--;
+*/
+       trim_len( ci_len, ci, call_id );
+       trim_len( cs_len, cs, cseq_nr );
+
+       /* run the cycle from the end ... we are interested in the
+          most-right digits ... and just take the %10 value of it
+       */
+       third=(ci_len-1)/3;
+       for ( i=ci_len-1, j=2*third, k=third;
+               k>0 ; i--, j--, k-- ) {
+               hash_code+=crc_16_tab[*(ci+i) /*+7*/ ]+
+                       ccitt_tab[*(ci+k)+63]+  
+                       ccitt_tab[*(ci+j)+13];
+       }
+       for( i=0 ; i<cs_len ; i++ )
+               //hash_code+=crc_32_tab[(cseq_nr.s[i]+hash_code)%243];
+               hash_code+=ccitt_tab[*(cs+i)+123];
+
+       hash_code %= (TABLE_ENTRIES-1);
+       return hash_code;
+}
+
+void hashtest_cycle( int hits[TABLE_ENTRIES], char *ip )
+{
+       long int i,j,k, l;
+       int len1, len2, hashv;
+       static char buf1[1024];
+       static char buf2[1024];
+       str call_id; 
+       str cseq;
+
+       call_id.s=buf1;
+       cseq.s=buf2;
+
+       for (i=987654328;i<987654328+10;i++)
+               for (j=85296341;j<85296341+10;j++)
+                       for (k=987654;k<=987654+10;k++)
+                               for (l=101;l<201;l++) {
+                                       call_id.len=sprintf( buf1, "%d-%d-%d@%s", i,j,k, ip );
+                                       cseq.len=sprintf( buf2, "%d", l );
+                                       printf("%s\t%s\n", buf1, buf2 );
+                                       hashv=hash( call_id, cseq );
+                                       hits[ hashv ]++;
+                               }
+}
+
+void hashtest()
+{
+       int hits[TABLE_ENTRIES];
+       int i;
+       
+       memset( hits, 0, sizeof hits );
+       hashtest_cycle( hits, "192.168.99.100" );
+       hashtest_cycle( hits, "172.168.99.100" );
+       hashtest_cycle( hits, "142.168.99.100" );
+       for (i=0; i<TABLE_ENTRIES; i++)
+               printf("[%d. %d]\n", i, hits[i] );
+       exit(0);
+}
+
index ef6b915..c31c7ad 100644 (file)
@@ -6,10 +6,12 @@
 #ifndef _HASH_H
 #define _HASH_H
 
-#include "globals.h"
 #include "../../str.h"
 #include "h_table.h"
 
-int hash( str  call_id, str cseq_nr );
+int new_hash( str  call_id, str cseq_nr );
+int old_hash( str  call_id, str cseq_nr );
+
+#define hash( cid, cseq) new_hash( cid, cseq )
 
 #endif
index ca7b7fd..ad206bb 100644 (file)
@@ -6,7 +6,6 @@
 #include <errno.h>
 
 #include "lock.h"
-#include "globals.h"
 #include "timer.h"
 #include "../../dprint.h"
 
@@ -209,19 +208,22 @@ tryagain:
     }
    return r;
 }
-
+/*
 int init_cell_lock( struct cell *cell )
 {
+*/
        /* just advice which of the available semaphores to use;
                shared with the lock belonging to the next hash entry lock
             (so that there are no collisions if one wants to try to
              lock on a cell as well as its list)
 
         */
+/*
        cell->mutex.semaphore_set=entry_semaphore,
        cell->mutex.semaphore_index=(cell->hash_index % sem_nr + 1)%sem_nr;
 
 }
+*/
 
 int init_entry_lock( struct s_table* hash_table, struct entry *entry )
 {
@@ -249,13 +251,18 @@ int init_retr_timer_lock( struct s_table* hash_table, enum retransmission_lists
 }
 */
 
+/*
 int release_cell_lock( struct cell *cell )
 {
+*/
        /* don't do anything here -- the init_*_lock procedures
           just advised on usage of shared semaphores but did not
           generate them
        */
+/*
 }
+*/
+
 int release_entry_lock( struct entry *entry )
 {
        /* the same as above */
index 3be5999..95b338e 100644 (file)
@@ -10,7 +10,6 @@
 #include <sys/ipc.h>
 #include <sys/sem.h>
 
-#include "globals.h"
 
 /* typedef to structure we use for mutexing;
    currently, index to a semaphore set identifier now */
@@ -21,6 +20,7 @@ typedef struct {
 
 
 #include "h_table.h"
+#include "timer.h"
 
 /* Uni*x permissions for IPC */
 #define IPC_PERMISSIONS 0666
@@ -36,7 +36,7 @@ int change_semaphore( ser_lock_t s  , int val );
 
 int init_cell_lock( struct cell *cell );
 int init_entry_lock( struct s_table* hash_table, struct entry *entry );
-int init_timerlist_lock( struct s_table* hash_table, enum lists timerlist_id);
+// int init_timerlist_lock( struct s_table* hash_table, enum lists timerlist_id);
 //int init_retr_timer_lock( struct s_table* hash_table, enum retransmission_lists list_id );
 
 int release_cell_lock( struct cell *cell );
index b3f8dc1..97098aa 100644 (file)
@@ -6,11 +6,11 @@
 #ifndef _SH_MALLOC_H
 #define _SH_MALLOC_H
 
-#include "../../shm_mem.h"
+#include "../../mem/shm_mem.h"
 
 #if defined SHM_MEM
 
-#include "../../shm_mem.h"
+#include "../../mem/shm_mem.h"
 
 #define sh_malloc(size)                shm_malloc((size))
 #define sh_free(ptr)           shm_free((ptr))
index 60daf0d..3a67e2e 100644 (file)
@@ -5,7 +5,7 @@
 
 #include "sip_msg.h"
 #include "../../dprint.h"
-#include "../../mem.h"
+#include "../../mem/mem.h"
 
 char*   translate_pointer( char* new_buf , char *org_buf , char* p);
 struct via_body* via_body_cloner( char* new_buf , char *org_buf , struct via_body *org_via);
@@ -445,7 +445,6 @@ void sh_free_hdr_field_lst(struct hdr_field* hf)
 
 
 
-/*only the content*/
 void sip_msg_free_1(struct sip_msg* msg)
 {
    if (!msg) return;
@@ -694,23 +693,7 @@ struct via_body* via_body_cloner_2( char* new_buf , char *org_buf , struct via_b
    return new_via;
 }
 
-
-
-
-
-
-
 void sip_msg_free_2(struct sip_msg* msg)
 {
    sh_free( (char*)msg );
 }
-
-
-
-
-
-
-
-
-
-
index fb50841..15cdabb 100644 (file)
@@ -1,3 +1,9 @@
+/*
+ * $Id$
+ *
+ */
+
+#include "hash_func.h"
 #include "t_funcs.h"
 #include "../../dprint.h"
 #include "../../config.h"
 #include "../../ut.h"
 #include "../../timer.h"
 
-#define stop_RETR_and_FR_timers(h_table,p_cell)    \
-       { int ijk; \
-               DBG("DEBUG:stop_RETR_and_FR_timers : start \n");\
-               if ( (p_cell)->outbound_response )  {  \
-                       remove_from_timer_list( (h_table) , \
-                               (&((p_cell)->outbound_response->tl[RETRASMISSIONS_LIST])), \
-                               RETRASMISSIONS_LIST ); \
-                       remove_from_timer_list( (h_table), \
-                               (&((p_cell)->outbound_response->tl[FR_TIMER_LIST])), \
-                               FR_TIMER_LIST );\
-               } \
-               DBG("DEBUG:stop_RETR_and_FR_timers : %d \n",(p_cell)->nr_of_outgoings);\
-               for( ijk=0 ; ijk<(p_cell)->nr_of_outgoings ; ijk++ )  { \
-                       DBG("DEBUG:stop_RETR_and_FR_timers : branch[%d] RETR\n",ijk);\
-                       remove_from_timer_list( (h_table) , \
-                               (&((p_cell)->outbound_request[ijk]->tl[RETRASMISSIONS_LIST])),\
-                               RETRASMISSIONS_LIST ); \
-                       DBG("DEBUG:stop_RETR_and_FR_timers : branch[%d] FR\n",ijk);\
-                       remove_from_timer_list( (h_table) , \
-                               (&((p_cell)->outbound_request[ijk]->tl[FR_TIMER_LIST])), \
-                               FR_TIMER_LIST ); \
-                       DBG("DEBUG:stop_RETR_and_FR_timers : branch]%d] done\n",ijk);\
-               } \
-               DBG("DEBUG:stop_RETR_and_FR_timers : stop\n");\
-       }
-
 
-#define insert_into_timer(hash_table,new_tl,list_id,time_out) \
-       insert_into_timer_list((hash_table), (new_tl), (list_id), \
-                       (get_ticks()+(time_out)))
-
-#define add_to_tail_of_timer(hash_table,new_tl,list_id,time_out) \
-       add_to_tail_of_timer_list((hash_table), (new_tl), (list_id), \
-                       (get_ticks()+(time_out)))
-
-#define remove_from_timer(hash_table,tl,list_id) \
-       remove_from_timer_list( (hash_table), (tl) , (list_id))
-
-#define unref_T(T_cell) \
-       do{\
-               lock( hash_table->entrys[T_cell->hash_index].mutex );\
-               T_cell->ref_counter--;\
-               DBG("DEBUG: XXXXXXXXXXXXXXXXXXXXX unref_T : T=%p , ref=%d\n",T_cell,T_cell->ref_counter);\
-               unlock( hash_table->entrys[T_cell->hash_index].mutex );\
-       }while(0);
+struct cell         *T;
+unsigned int     global_msg_id;
+struct s_table*  hash_table;
 
 
 
+/* determine timer length and put on a correct timer list */
+static inline void set_timer( struct s_table *hash_table, 
+       struct timer_link *new_tl, enum lists list_id )
+{
+       unsigned int timeout;
+       static enum lists to_table[NR_OF_TIMER_LISTS] =
+               {       FR_TIME_OUT, INV_FR_TIME_OUT, WT_TIME_OUT, DEL_TIME_OUT,
+                       RETR_T1, RETR_T1 << 1,  RETR_T1 << 2, RETR_T2 };
+
+       if (list_id<FR_TIMER_LIST || list_id>=NR_OF_TIMER_LISTS) {
+               LOG(L_CRIT, "ERROR: set_timer: unkown list: %d\n", list_id);
+#ifdef EXTRA_DEBUG
+               abort();
+#endif
+               return;
+       }
+       timeout = to_table[ list_id ];
+       add_to_tail_of_timer_list( &(hash_table->timers[ list_id ]), 
+               new_tl,get_ticks()+timeout);
+}
 
-struct cell         *T;
-unsigned int     global_msg_id;
-struct s_table*  hash_table;
+/* remove from timer list */
+static inline void reset_timer( struct s_table *hash_table,
+       struct timer_link* tl )
+{
+       remove_from_timer_list( tl );
+}
 
+static inline void reset_retr_timers( struct s_table *h_table,
+       struct cell *p_cell )
+{
+       int ijk; 
+       struct retrans_buff *rb;
+
+       DBG("DEBUG:stop_RETR_and_FR_timers : start \n");
+       reset_timer( h_table, &(p_cell->outbound_response.retr_timer));
+       reset_timer( h_table, &(p_cell->outbound_response.fr_timer));
+
+       for( ijk=0 ; ijk<(p_cell)->nr_of_outgoings ; ijk++ )  { 
+                       if ( rb = p_cell->outbound_request[ijk] ) {
+                               reset_timer(h_table, &(rb->retr_timer));
+                               reset_timer(h_table, &(rb->fr_timer));
+                       }
+               } 
+       DBG("DEBUG:stop_RETR_and_FR_timers : stop\n");
+}
 
 int tm_startup()
 {
@@ -66,11 +72,18 @@ int tm_startup()
    if (!hash_table)
       return -1;
 
-   /* installing handlers for timers */
-   hash_table->timers[RETRASMISSIONS_LIST].timeout_handler = retransmission_handler;
-   hash_table->timers[FR_TIMER_LIST].timeout_handler = final_response_handler;
-   hash_table->timers[WT_TIMER_LIST].timeout_handler = wait_handler;
-   hash_table->timers[DELETE_LIST].timeout_handler = delete_handler;
+#define init_timer(_id,_handler) \
+       hash_table->timers[(_id)].timeout_handler=(_handler); \
+       hash_table->timers[(_id)].id=(_id);
+
+   init_timer( RT_T1_TO_1, retransmission_handler );
+   init_timer( RT_T1_TO_2, retransmission_handler );
+   init_timer( RT_T1_TO_3, retransmission_handler );
+   init_timer( RT_T2, retransmission_handler );
+   init_timer( FR_TIMER_LIST, final_response_handler );
+   init_timer( FR_INV_TIMER_LIST, final_response_handler );
+   init_timer( WT_TIMER_LIST, wait_handler );
+   init_timer( DELETE_LIST, delete_handler );
 
    /* register the timer function */
    register_timer( timer_routine , hash_table , 1 );
@@ -87,24 +100,28 @@ int tm_startup()
 
 void tm_shutdown()
 {
-    struct timer_link  *tl, *tmp;
+    struct timer_link  *tl, *end, *tmp;
     int i;
 
     DBG("DEBUG: tm_shutdown : start\n");
     /*remember the DELETE LIST */
-    tl = hash_table->timers[DELETE_LIST].first_tl;
-
-    DBG("DEBUG: tm_shutdown : empting DELETE list\n");
+    tl = hash_table->timers[DELETE_LIST].first_tl.next_tl;
+       end = & hash_table->timers[DELETE_LIST].last_tl;
     /*unlink the lists*/
     for( i=0; i<NR_OF_TIMER_LISTS ; i++ )
     {
        //lock( hash_table->timers[i].mutex );
-       hash_table->timers[ i ].first_tl = hash_table->timers[ i ].last_tl = 0;
+               reset_timer_list( hash_table, i );
        //unlock( hash_table->timers[i].mutex );
     }
 
+    DBG("DEBUG: tm_shutdown : empting DELETE list\n");
     /* deletes all cells from DELETE_LIST list (they are no more accessible from enrys) */
-    for(   ;  tl  ;  tmp=tl->next_tl , free_cell((struct cell*)tl->payload) , tl=tmp );
+       while (tl!=end) {
+               tmp=tl->next_tl;
+               free_cell((struct cell*)tl->payload);
+                tl=tmp;
+       }
 
     /* destroy the hash table */
     DBG("DEBUG: tm_shutdown : empting hash table\n");
@@ -128,7 +145,7 @@ int t_add_transaction( struct sip_msg* p_msg, char* foo, char* bar )
    DBG("DEBUG: t_add_transaction: adding......\n");
 
    /* sanity check: ACKs can never establish a transaction */
-   if ( p_msg->first_line.u.request.method_value==METHOD_ACK )
+   if ( p_msg->REQ_METHOD==METHOD_ACK )
    {
        LOG(L_ERR, "ERROR: add_transaction: ACK can't be used to add transaction\n");
       return -1;
@@ -165,240 +182,159 @@ int t_add_transaction( struct sip_msg* p_msg, char* foo, char* bar )
 
 
 /* function returns:
- *      -1 - transaction wasn't found
- *       1  - transaction found
- */
-int t_lookup_request( struct sip_msg* p_msg )
-{
-   struct cell      *p_cell;
-   struct cell      *tmp_cell;
-   unsigned int  hash_index=0;
-   unsigned int  isACK = 0;
-
-   DBG("t_lookup_request: start searching\n");
-
-   /* parse all*/
-   if (check_transaction_quadruple(p_msg)==0)
-   {
-      LOG(L_ERR, "ERROR: TM module: t_lookup_request: too few headers\n");
-      T=0;
-      return -1;
-   }
-
-   /* start searching into the table */
-   hash_index = hash( p_msg->callid->body , get_cseq(p_msg)->number ) ;
-   if ( p_msg->first_line.u.request.method_value==METHOD_ACK  )
-      isACK = 1;
-   DBG("t_lookup_request: continue searching;  hash=%d, isACK=%d\n",hash_index,isACK);
-
-   /* lock the hole entry*/
-   lock( hash_table->entrys[hash_index].mutex );
-
-   /* all the transactions from the entry are compared */
-   p_cell     = hash_table->entrys[hash_index].first_cell;
-   tmp_cell = 0;
-   while( p_cell )
-   {
-      /* is it the wanted transaction ? */
-      if ( !isACK )
-      { /* is not an ACK request */
-         /* first only the length are checked */
-         if ( /*from length*/ p_cell->inbound_request->from->body.len == p_msg->from->body.len )
-            if ( /*to length*/ p_cell->inbound_request->to->body.len == p_msg->to->body.len )
-               if ( /*callid length*/ p_cell->inbound_request->callid->body.len == p_msg->callid->body.len )
-                  if ( /*cseq length*/ p_cell->inbound_request->cseq->body.len == p_msg->cseq->body.len )
-                     /* so far the lengths are the same -> let's check the contents */
-                        if ( /*from*/ !memcmp( p_cell->inbound_request->from->body.s , p_msg->from->body.s , p_msg->from->body.len ) )
-                           if ( /*to*/ !memcmp( p_cell->inbound_request->to->body.s , p_msg->to->body.s , p_msg->to->body.len)  )
-                               if ( /*callid*/ !memcmp( p_cell->inbound_request->callid->body.s , p_msg->callid->body.s , p_msg->callid->body.len ) )
-                                  if ( /*cseq*/ !memcmp( p_cell->inbound_request->cseq->body.s , p_msg->cseq->body.s , p_msg->cseq->body.len ) )
-                                     { /* WE FOUND THE GOLDEN EGG !!!! */
-                                        T = p_cell;
-                                        T->ref_counter ++;
-                                        DBG("DEBUG:XXXXXXXXXXXXXXXXXXXXX t_lookup_request: non-ACK found ( T=%p , ref=%d)\n",T,T->ref_counter);
-                                        unlock( hash_table->entrys[hash_index].mutex );
-                                        return 1;
-                                     }
-      }
-      else
-      { /* it's a ACK request*/
-         /* first only the length are checked */
-         if ( /*from length*/ p_cell->inbound_request->from->body.len == p_msg->from->body.len )
-            //if ( /*to length*/ p_cell->inbound_request->to->body.len == p_msg->to->body.len )
-               if ( /*callid length*/ p_cell->inbound_request->callid->body.len == p_msg->callid->body.len )
-                  if ( /*cseq_nr length*/ get_cseq(p_cell->inbound_request)->number.len == get_cseq(p_msg)->number.len )
-                      if ( /*cseq_method type*/ p_cell->inbound_request->first_line.u.request.method_value == METHOD_INVITE  )
-                         //if ( /*tag length*/ p_cell->tag &&  p_cell->tag->len==p_msg->tag->body.len )
-                            /* so far the lengths are the same -> let's check the contents */
-                            if ( /*from*/ !memcmp( p_cell->inbound_request->from->body.s , p_msg->from->body.s , p_msg->from->body.len ) )
-                               //if ( /*to*/ !memcmp( p_cell->inbound_request->to->body.s , p_msg->to->body.s , p_msg->to->body.len)  )
-                                  //if ( /*tag*/ !memcmp( p_cell->tag->s , p_msg->tag->body.s , p_msg->tag->body.len ) )
-                                     if ( /*callid*/ !memcmp( p_cell->inbound_request->callid->body.s , p_msg->callid->body.s , p_msg->callid->body.len ) )
-                                        if ( /*cseq_nr*/ !memcmp( get_cseq(p_cell->inbound_request)->number.s , get_cseq(p_msg)->number.s , get_cseq(p_msg)->number.len ) )
-                                           { /* WE FOUND THE GOLDEN EGG !!!! */
-                                              T = p_cell;
-                                              T->ref_counter ++;
-                                              DBG("DEBUG:XXXXXXXXXXXXXXXXXXXXX t_lookup_request: ACK found ( T=%p , ref=%d)\n",T,T->ref_counter);
-                                              unlock( hash_table->entrys[hash_index].mutex );
-                                               return 1;
-                                           }
-      } /* end if is ACK or not*/
-      /* next transaction */
-      tmp_cell = p_cell;
-      p_cell = p_cell->next_cell;
-   }
-
-   /* no transaction found */
-   T = 0;
-   unlock( hash_table->entrys[hash_index].mutex );
-   DBG("DEBUG: t_lookup_request: no transaction found\n");
-   return -1;
-}
-
-
-
-
-/* function returns:
  *       1 - forward successfull
  *      -1 - error during forward
  */
 int t_forward( struct sip_msg* p_msg , unsigned int dest_ip_param , unsigned int dest_port_param )
 {
-   unsigned int dest_ip     = dest_ip_param;
-   unsigned int dest_port  = dest_port_param;
-   int branch;
-   unsigned int len;
-   char               *buf;
+       unsigned int dest_ip     = dest_ip_param;
+       unsigned int dest_port  = dest_port_param;
+       int     branch;
+       unsigned int len;
+       char               *buf;
+       struct retrans_buff *rb;
 
-   buf=NULL;
-   branch = 0; /* we don't do any forking right now */
+       buf=NULL;
+       branch = 0;     /* we don't do any forking right now */
 
-   /* it's about the same transaction or not? */
-   t_check( p_msg  , 0 );
+       /* it's about the same transaction or not? */
+       t_check( p_msg  , 0 );
 
-   /*if T hasn't been found after all -> return not found (error) */
-   if ( !T )
-   {
-      DBG("DEBUG: t_forward: no transaction found in order  to forward the request\n");
-      return -1;
-   }
+       /*if T hasn't been found after all -> return not found (error) */
+       if ( !T )
+       {
+               DBG("DEBUG: t_forward: no transaction found for request forwarding\n");
+               return -1;
+       }
 
-   /*if it's an ACK and the status is not final or is final, but error the ACK is not forwarded*/
-   if ( p_msg->first_line.u.request.method_value==METHOD_ACK  && (T->status/100)!=2 ) {
-      DBG("DEBUG: t_forward: local ACK; don't forward\n");
-      return 1;
-   }
+       /*if it's an ACK and the status is not final or is final, but error the 
+     ACK is not forwarded*/
+       if ( p_msg->REQ_METHOD==METHOD_ACK  && (T->status/100)!=2 ) {
+               DBG("DEBUG: t_forward: local ACK; don't forward\n");
+               return 1;
+       }
 
-   /* if it's forwarded for the first time ; else the request is retransmited from the transaction buffer
-     * when forwarding an ACK, this condition will br all the time false because
-     * the forwarded INVITE is in the retransmission buffer */
-   if ( T->outbound_request[branch]==NULL )
-   {
-      DBG("DEBUG: t_forward: first time forwarding\n");
-      /* special case : CANCEL */
-      if ( p_msg->first_line.u.request.method_value==METHOD_CANCEL  )
-      {
-         DBG("DEBUG: t_forward: 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 )
-            T->T_canceled = t_lookupOriginalT( hash_table , p_msg );
-         /* if found */
-         if ( T->T_canceled!=T_NULL )
-         {
-            T->T_canceled->T_canceler = T;
-            /* 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 to the same place where INVITE went\n");
-               dest_ip    = T->T_canceled->outbound_request[branch]->to.sin_addr.s_addr;
-               dest_port = T->T_canceled->outbound_request[branch]->to.sin_port;
-            }
-            else
-            {
-               /* transaction exists, but nothing to cancel */
-               DBG("DEBUG: t_forward: it's CANCEL but I have nothing to cancel here\n");
-               return 1;
-            }
-         }
-         else
-         {
-            /* transaction doesnot exists  */
-            DBG("DEBUG: t_forward: canceled request not found! nothing to CANCEL\n");
-            return 1;
-         }
-      }/* end special case CANCEL*/
-
-      /* allocates a new retrans_buff for the outbound request */
-      DBG("DEBUG: t_forward: building outbound request\n");
-      T->outbound_request[branch] = (struct retrans_buff*)sh_malloc( sizeof(struct retrans_buff) );
-      if (!T->outbound_request[branch])
-      {
-        LOG(L_ERR, "ERROR: t_forward: out of shmem\n");
-       goto error;
-      }
-      memset( T->outbound_request[branch] , 0 , sizeof (struct retrans_buff) );
-      T->outbound_request[branch]->tl[RETRASMISSIONS_LIST].payload =  T->outbound_request[branch];
-      T->outbound_request[branch]->tl[FR_TIMER_LIST].payload =  T->outbound_request[branch];
-      T->outbound_request[branch]->to.sin_family = AF_INET;
-      T->outbound_request[branch]->my_T =  T;
-      T->nr_of_outgoings = 1;
-
-      if ( add_branch_label( T, T->inbound_request , branch )==-1) return -1;
-      if ( add_branch_label( T, p_msg , branch )==-1) return -1;
-      if ( !(buf = build_req_buf_from_sip_req  ( p_msg, &len))) goto error;
-      T->outbound_request[branch]->bufflen = len ;
-      if ( !(T->outbound_request[branch]->retr_buffer   = (char*)sh_malloc( len ))) {
-       LOG(L_ERR, "ERROR: t_forward: shmem allocation failed\n");
-       goto error;
-      }
-      memcpy( T->outbound_request[branch]->retr_buffer , buf , len );
-      free( buf ) ; buf=NULL;
-
-      DBG("DEBUG: t_forward: starting timers (retrans and FR) %d\n",get_ticks() );
-      /*sets and starts the FINAL RESPONSE timer */
-      insert_into_timer( hash_table , (&(T->outbound_request[branch]->tl[FR_TIMER_LIST])) , FR_TIMER_LIST, FR_TIME_OUT );
-
-      /* sets and starts the RETRANS timer */
-      T->outbound_request[branch]->timeout_ceiling  = RETR_T2;
-      T->outbound_request[branch]->timeout_value    = RETR_T1;
-      insert_into_timer( hash_table , (&(T->outbound_request[branch]->tl[RETRASMISSIONS_LIST])), RETRASMISSIONS_LIST , RETR_T1 );
-   }/* end for the first time */
-
-   /* if we are forwarding an ACK*/
-   if (  p_msg->first_line.u.request.method_value==METHOD_ACK &&
-   T->relaied_reply_branch>=0 && T->relaied_reply_branch<=T->nr_of_outgoings)
-   {
-      DBG("DEBUG: t_forward: forwarding ACK [%d]\n",T->relaied_reply_branch);
-      t_build_and_send_ACK( T, branch , T->inbound_response[T->relaied_reply_branch] );
-      T->inbound_request_isACKed = 1;
-     return 1;
-   } else /* if we are forwarding a CANCEL*/
-   if (  p_msg->first_line.u.request.method_value==METHOD_CANCEL )
-   {
-      DBG("DEBUG: t_forward: forwarding CANCEL\n");
-       /* if no transaction to CANCEL */
+       /* if it's forwarded for the first time ; else the request is retransmited 
+        * from the transaction buffer
+        * when forwarding an ACK, this condition will br all the time false because
+        * the forwarded INVITE is in the retransmission buffer */
+       if ( T->outbound_request[branch]==NULL )
+       {
+               DBG("DEBUG: t_forward: first time forwarding\n");
+               /* special case : CANCEL */
+               if ( p_msg->REQ_METHOD==METHOD_CANCEL  )
+               {
+                       DBG("DEBUG: t_forward: 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 )
+                               T->T_canceled = t_lookupOriginalT( hash_table , p_msg );
+                       /* if found */
+                       if ( T->T_canceled!=T_NULL )
+                       {
+                               T->T_canceled->T_canceler = T;
+                               /* 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 "
+                                               "to the same place where INVITE went\n");
+                                       dest_ip=T->T_canceled->outbound_request[branch]->
+                                               to.sin_addr.s_addr;
+                                       dest_port = T->T_canceled->outbound_request[branch]->
+                                               to.sin_port;
+                               } else { /* transaction exists, but nothing to cancel */
+                                               DBG("DEBUG: t_forward: it's CANCEL but "
+                                               "I have nothing to cancel here\n");
+                                       /* continue forwarding CANCEL as a stand-alone transaction */
+                                       /*      return 1; */
+                               }
+                       } else { /* transaction doesnot exists  */
+                               DBG("DEBUG: t_forward: canceled request not found! "
+                               "nothing to CANCEL\n");
+                               return 1;
+                       }
+               }/* end special case CANCEL*/
+
+               /* allocates a new retrans_buff for the outbound request */
+               DBG("DEBUG: t_forward: building outbound request\n");
+               T->outbound_request[branch] = rb = 
+                       (struct retrans_buff*)sh_malloc( sizeof(struct retrans_buff) );
+               if (!rb)
+               {
+                       LOG(L_ERR, "ERROR: t_forward: out of shmem\n");
+                       goto error;
+               }
+               memset( rb , 0 , sizeof (struct retrans_buff) );
+               rb->retr_timer.payload =  rb;
+               rb->fr_timer.payload =  rb;
+               rb->to.sin_family = AF_INET;
+               rb->my_T =  T;
+               T->nr_of_outgoings = 1;
+
+               if ( add_branch_label( T, T->inbound_request , branch )==-1) 
+                       goto error;
+               if ( add_branch_label( T, p_msg , branch )==-1) 
+                       goto error;
+               if ( !(buf = build_req_buf_from_sip_req  ( p_msg, &len))) 
+                       goto error;
+               rb->bufflen = len ;
+               if ( !(rb->retr_buffer = (char*)sh_malloc( len ))) 
+               {
+                       LOG(L_ERR, "ERROR: t_forward: shmem allocation failed\n");
+                       goto error;
+               }
+               memcpy( rb->retr_buffer , buf , len );
+               free( buf ) ; buf=NULL;
+
+               DBG("DEBUG: t_forward: starting timers (retrans and FR) %d\n",get_ticks() );
+               /*sets and starts the FINAL RESPONSE timer */
+               set_timer( hash_table, &(rb->fr_timer), FR_TIMER_LIST );
+
+               /* sets and starts the RETRANS timer */
+               rb->retr_list = RT_T1_TO_1;
+               set_timer( hash_table, &(rb->retr_timer), RT_T1_TO_1 );
+       }/* end for the first time */
+
+       /* if we are forwarding an ACK*/
+       if (  p_msg->REQ_METHOD==METHOD_ACK &&
+               T->relaied_reply_branch>=0 && 
+               T->relaied_reply_branch<=T->nr_of_outgoings)
+       {
+               DBG("DEBUG: t_forward: forwarding ACK [%d]\n",T->relaied_reply_branch);
+               t_build_and_send_ACK( T, branch , 
+                       T->inbound_response[T->relaied_reply_branch] );
+               T->inbound_request_isACKed = 1;
+               return 1;
+       } else /* if we are forwarding a CANCEL*/
+       if (  p_msg->REQ_METHOD==METHOD_CANCEL )
+       {
+               DBG("DEBUG: t_forward: 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)
-       {
-           remove_from_timer( hash_table , (&(T->outbound_request[branch]->tl[FR_TIMER_LIST])) , FR_TIMER_LIST);
-           remove_from_timer( hash_table , (&(T->outbound_request[branch]->tl[RETRASMISSIONS_LIST])), RETRASMISSIONS_LIST );
-           return 1;
-       }
-   }
-
-   /* send the request */
-   /* known to be in network order */
-   T->outbound_request[branch]->to.sin_port     =  dest_port;
-   T->outbound_request[branch]->to.sin_addr.s_addr =  dest_ip;
-   T->outbound_request[branch]->to.sin_family = AF_INET;
-
-   udp_send( T->outbound_request[branch]->retr_buffer , T->outbound_request[branch]->bufflen ,
-                    (struct sockaddr*)&(T->outbound_request[branch]->to) , sizeof(struct sockaddr_in) );
+               if ( T->T_canceled==T_NULL || T->T_canceled->status>=200)
+               {
+                       reset_timer( hash_table, &(rb->fr_timer ));
+                       reset_timer( hash_table, &(rb->retr_timer ));
+                       return 1;
+                       }
+       }
+
+       /* send the request */
+       /* known to be in network order */
+       rb->to.sin_port     =  dest_port;
+       rb->to.sin_addr.s_addr =  dest_ip;
+       rb->to.sin_family = AF_INET;
+
+       SEND_BUFFER( rb );
 
    return 1;
 
 error:
-       if (T->outbound_request[branch]) sh_free(T->outbound_request[branch]);
+       if ( rb && rb->retr_buffer) sh_free( rb->retr_buffer );
+       if (rb) {
+               sh_free(rb);
+               T->outbound_request[branch]=NULL;
+       }
        if (buf) free( buf );
 
        return -1;
@@ -406,8 +342,6 @@ error:
 }
 
 
-
-
 /* Forwards the inbound request to dest. from via.  Returns:
  *       1 - forward successfull
  *      -1 - error during forward
@@ -444,7 +378,8 @@ int t_forward_uri( struct sip_msg* p_msg, char* foo, char* bar  )
    }
 
    /* getting host address*/
-   nhost = gethostbyname( parsed_uri.host.s );
+   nhost = gethostbyname( parsed_uri.host.s ); 
+
    if ( !nhost )
    {
       LOG(L_ERR, "ERROR: t_forward_uri: cannot resolve host\n");
@@ -481,110 +416,117 @@ int t_forward_uri( struct sip_msg* p_msg, char* foo, char* bar  )
   */
 int t_on_reply_received( struct sip_msg  *p_msg )
 {
-   unsigned int  branch,len;
-   struct sip_msg *clone;
-   int relay;
-
-   clone=NULL;
-
-   /* parse_headers( p_msg , HDR_EOH ); */ /*????*/
-   /* this might be good enough -- is not like with
-      generating own responses where I have to
-      parse all vias to copy them
-
-   /* if a reply received which has not all fields we might want to
-      have for stateul forwarding, give the stateless router
-      a chance for minimum routing
-   */
-   if ( parse_headers(p_msg, HDR_VIA1|HDR_VIA2|HDR_TO|HDR_CSEQ )==-1 ||
-        !p_msg->via1 || !p_msg->via2 || !p_msg->to || !p_msg->cseq )
+       unsigned int  branch,len, msg_status, msg_class;
+       struct sip_msg *clone;
+       int relay;
+       struct retrans_buff *rb;
+
+       clone=NULL;
+
+       /* if a reply received which has not all fields we might want to
+          have for stateul forwarding, give the stateless router
+          a chance for minimum routing; parse only what's needed
+          for MPLS-ize reply matching
+       */
+       if ( parse_headers(p_msg, HDR_VIA1|HDR_VIA2|HDR_TO|HDR_CSEQ )==-1 ||
+               !p_msg->via1 || !p_msg->via2 || !p_msg->to || !p_msg->cseq )
        return 1;
 
-   /* we use label-matching to lookup for T */
-   t_check( p_msg , &branch );
+       /* we use label-matching to lookup for T */
+       t_check( p_msg , &branch );
+
+       /* if no T found ->tell the core router to forward statelessly */
+       if ( T<=0 )
+               return 1;
+       DBG("DEBUG: t_on_reply_received: Original status =%d\n",T->status);
+
+       /* we were not able to process the response due to memory
+          shortage; simply drop it; hopefuly, we will have more
+           memory on the next try 
+       */
+       msg_status=p_msg->REPLY_STATUS;
+       msg_class=REPLY_CLASS(p_msg);
+       relay = t_should_relay_response( T , msg_status );
+       if (relay && !(clone=sip_msg_cloner( p_msg ))) {
+               t_unref( p_msg, NULL, NULL );
+               return 0;
+       }
 
-   /* if no T found ->tell the core router to forward statelessly */
-   if ( T<=0 )
-      return 1;
-   DBG("DEBUG: t_on_reply_received: Original status =%d\n",T->status);
-
-   /* we were not able to process the response due to memory
-      shortage; simply drop it; hopefuly, we will have more
-      memory on the next try */
-   relay = t_should_relay_response( T , p_msg->first_line.u.reply.statuscode );
-   if (relay && !(clone=sip_msg_cloner( p_msg )))
-     return 0;
-
-   /* stop retransmission */
-   remove_from_timer( hash_table , (&(T->outbound_request[branch]->tl[RETRASMISSIONS_LIST])) , RETRASMISSIONS_LIST );
-   /* stop final response timer only if I got a final response */
-   if ( p_msg->first_line.u.reply.statusclass>1 )
-      remove_from_timer( hash_table , (&(T->outbound_request[branch]->tl[FR_TIMER_LIST])) , FR_TIMER_LIST );
-   /* if a got the first prov. response for an INVITE -> change FR_TIME_OUT to INV_FR_TIME_UT */
-   if ( !T->inbound_response[branch] && p_msg->first_line.u.reply.statusclass==1 && T->inbound_request->first_line.u.request.method_value==METHOD_INVITE )
-      insert_into_timer( hash_table , (&(T->outbound_request[branch]->tl[FR_TIMER_LIST])) , FR_TIMER_LIST , INV_FR_TIME_OUT);
-
-   /* get response for INVITE */
-   if ( T->inbound_request->first_line.u.request.method_value==METHOD_INVITE )
-   {
-       if ( T->outbound_request_isACKed[branch] )
-       {   /*retransmit*/
-           udp_send( T->outbound_request[branch]->retr_buffer, T->outbound_request[branch]->bufflen,
-             (struct sockaddr*)&(T->outbound_request[branch]->to) , sizeof(struct sockaddr_in) );
-       }
-       else if (p_msg->first_line.u.reply.statusclass>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" );
-               return 0;
-           }
-       }
-   }
+       rb=T->outbound_request[branch];
 
-   #ifdef FORKING
-   /* skipped for the moment*/
-   #endif
+       /* stop retransmission */
+       reset_timer( hash_table, &(rb->retr_timer));
 
-   /* if the incoming response code is not reliable->drop it*/
-   if (!relay)
-       return 0;
+       /* stop final response timer only if I got a final response */
+       if ( msg_class>1 )
+               reset_timer( hash_table, &(rb->fr_timer));
+       /* if a got the first prov. response for an INVITE -> 
+          change FR_TIME_OUT to INV_FR_TIME_UT */
+       if (!T->inbound_response[branch] && msg_class==1
+        && T->inbound_request->REQ_METHOD==METHOD_INVITE )
+               set_timer( hash_table, &(rb->fr_timer), FR_INV_TIMER_LIST );
 
-   /* restart retransmission if provisional response came for a non_INVITE -> retrasmit at RT_T2*/
-   if ( p_msg->first_line.u.reply.statusclass==1 && T->inbound_request->first_line.u.request.method_value!=METHOD_INVITE )
-   {
-      T->outbound_request[branch]->timeout_value = RETR_T2;
-      insert_into_timer( hash_table , (&(T->outbound_request[branch]->tl[RETRASMISSIONS_LIST])) , RETRASMISSIONS_LIST , RETR_T2 );
-   }
+       /* get response for INVITE */
+       if ( T->inbound_request->REQ_METHOD==METHOD_INVITE )
+       {
+               if ( T->outbound_request_isACKed[branch] )
+               {   /*retransmit*/
+                       SEND_BUFFER( T->outbound_request[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" );
+                                               if (clone ) sip_msg_free( clone );
+                                               t_unref( p_msg, NULL, NULL );
+                                       return 0;
+                       }
+                       }
+       }
+
+#      ifdef FORKING
+       /* skipped for the moment*/
+#      endif
+
+       /* if the incoming response code is not reliable->drop it*/
+       if (!relay) {
+               t_unref( p_msg, NULL, NULL );
+               return 0;
+       }
 
-   /*store the inbound reply - if there is a previous reply, replace it */
-   if ( T->inbound_response[branch] ) {
-      sip_msg_free( T->inbound_response[branch] ) ;
-      DBG("DEBUG: t_store_incoming_reply: previous inbound reply freed....\n");
-   }
-   T->inbound_response[branch] = clone;
+       /* restart retransmission if provisional response came for a non_INVITE -> 
+               retrasmit at RT_T2*/
+       if ( msg_class==1 && T->inbound_request->REQ_METHOD!=METHOD_INVITE )
+       {
+               rb->retr_list = RT_T2;
+               set_timer( hash_table, &(rb->retr_timer), RT_T2 );
+       }
 
-   if ( p_msg->first_line.u.reply.statusclass>=3 && p_msg->first_line.u.reply.statusclass<=5 )
-   {
-      if ( t_all_final(T) && relay_lowest_reply_upstream( T , p_msg )==-1 && clone )
-      {
-        T->inbound_response[branch]=NULL;
-        sip_msg_free( clone );
-        return -1;
-      }
-   }
-   else
-   {
-      if (push_reply_from_uac_to_uas( T , branch )==-1 && clone ) {
+       /*store the inbound reply - if there is a previous reply, replace it */
+       if ( T->inbound_response[branch] ) {
+               sip_msg_free( T->inbound_response[branch] ) ;
+               DBG("DEBUG: t_store_incoming_reply: previous inbound reply freed....\n");
+       }
+       T->inbound_response[branch] = clone;
+
+       if ( msg_class>=3 && msg_class<=5 )
+       {
+               if ( t_all_final(T) && relay_lowest_reply_upstream( T , p_msg )==-1 && clone )
+                       goto error;
+       } else {
+               if (push_reply_from_uac_to_uas( T , branch )==-1 && clone ) 
+                       goto error;
+       }
+
+       /* nothing to do for the ser core */
+       t_unref( p_msg, NULL, NULL );
+       return 0;
+
+error:
+       t_unref( p_msg, NULL, NULL );
        T->inbound_response[branch]=NULL;
        sip_msg_free( clone );
        return -1;
-      }
-   }
-
-   /* nothing to do for the ser core */
-   return 0;
 }
 
 
@@ -617,17 +559,25 @@ int t_retransmit_reply( struct sip_msg* p_msg, char* foo, char* bar  )
    t_check( p_msg , 0 );
 
    /* if no transaction exists or no reply to be resend -> out */
-   if ( T  && T->outbound_response )
+   if ( T )
    {
-      udp_send( T->outbound_response->retr_buffer , T->outbound_response->bufflen ,
-       (struct sockaddr*)&(T->outbound_response->to) , sizeof(struct sockaddr_in) );
-      return 1;
+       SEND_BUFFER( & T->outbound_response );
+       return 1;
    }
 
   /* no transaction found */
    return -1;
 }
 
+int t_unref( struct sip_msg* p_msg, char* foo, char* bar )
+{
+       if (T==T_UNDEFINED || T==T_NULL)
+               return -1;
+       unref_T(T);
+       T=T_UNDEFINED;
+       return 1;
+}
+
 
 
 
@@ -636,323 +586,161 @@ int t_retransmit_reply( struct sip_msg* p_msg, char* foo, char* bar  )
   */
 int t_send_reply(  struct sip_msg* p_msg , unsigned int code , char * text )
 {
-   unsigned int len;
-   char * buf = NULL;
-   struct hostent  *nhost;
-   unsigned int      ip, port;
-   char foo;
-   int err;
-   struct retrans_buff* rb = NULL;
-   char *b;
+       unsigned int len;
+       char * buf;
+       struct retrans_buff *rb;
+       char *b;
 
-   DBG("DEBUG: t_send_reply: entered\n");
-   t_check( p_msg , 0 );
+       DBG("DEBUG: t_send_reply: entered\n");
+       t_check( p_msg , 0 );
 
-   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;
-   }
-
-   /* if the incoming response code is not reliable->drop it*/
-   if ( !t_should_relay_response( T , code ) )
-      return 1;
-
-   if ( T->outbound_response)
-   {
-      if (  T->outbound_response->retr_buffer )
-       {
-         b = T->outbound_response->retr_buffer;
-          T->outbound_response->retr_buffer = NULL;
-          sh_free( b );
-         rb = NULL;
-       }
-   }
-   else
-   {
-      rb = (struct retrans_buff*)sh_malloc( sizeof(struct retrans_buff) );
-     if (!rb)
-      {
-        LOG(L_ERR, "ERROR: t_send_reply: cannot allocate shmem for retransmission buffer\n");
-       goto error;
-      }
-      T->outbound_response = rb;
-      memset( T->outbound_response , 0 , sizeof (struct retrans_buff) );
-
-      /* initialize retransmission structure */
-     if (update_sock_struct_from_via(  &(T->outbound_response->to),  p_msg->via1 )==-1)
-      {
-         LOG(L_ERR, "ERROR: t_send_reply: cannot lookup reply dst: %s\n",
-                  p_msg->via1->host.s );
-        goto error;
-      }
-
-      T->outbound_response->tl[RETRASMISSIONS_LIST].payload = T->outbound_response;
-      T->outbound_response->tl[FR_TIMER_LIST].payload = T->outbound_response;
-      T->outbound_response->to.sin_family = AF_INET;
-      T->outbound_response->my_T = T;
-   }
-
-   buf = build_res_buf_from_sip_req( code , text , 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;
-   }
+       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;
+       }
 
-   T->outbound_response->bufflen = len ;
-   T->outbound_response->retr_buffer   = (char*)sh_malloc( len );
-   if (!T->outbound_response->retr_buffer)
-   {
-      LOG(L_ERR, "ERROR: t_send_reply: cannot allocate shmem buffer\n");
-     goto error;
-   }
-   memcpy( T->outbound_response->retr_buffer , buf , len );
-   free( buf ) ;
-   T->status = code;
+       /* if the incoming response code is not reliable->drop it*/
+       /*
+       if ( !t_should_relay_response( T , code ) )
+               return 1;
+       */
+
+       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 error;
+               }
+
+               rb->retr_timer.payload = rb;
+               rb->fr_timer.payload = rb;
+               rb->to.sin_family = AF_INET;
+               rb->my_T = T;
+       }
 
-   /* start/stops the proper timers*/
-   DBG("DEBUG: t_send_reply: update timers\n");
-   t_update_timers_after_sending_reply( T->outbound_response );
+       buf = build_res_buf_from_sip_req( code , text , 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;
+       }
 
-   DBG("DEBUG: t_send_reply: send reply\n");
-   t_retransmit_reply( p_msg, 0 , 0);
+       if (! (b = (char*)sh_malloc( len )))
+       {
+               LOG(L_ERR, "ERROR: t_send_reply: cannot allocate shmem buffer\n");
+               goto error2;
+       }
+       /* if present, remove previous message */
+       if (  rb->retr_buffer)
+               sh_free( rb->retr_buffer );
+       rb->retr_buffer   = b;
+       rb->bufflen = len ;
+       memcpy( rb->retr_buffer , buf , len );
+       free( buf ) ;
+       T->status = code;
+
+       /* start/stops the proper timers*/
+       DBG("DEBUG: t_send_reply: update timers\n");
+       t_update_timers_after_sending_reply( rb );
+
+       DBG("DEBUG: t_send_reply: send reply\n");
+       /* t_retransmit_reply( p_msg, 0 , 0); */
+       SEND_BUFFER( rb );
 
-   return 1;
+       return 1;
 
+error2:
+       free ( buf );
 error:
-   if (rb) { sh_free(rb); T->outbound_response = rb = NULL;}
-   if ( buf ) free ( buf );
-   return -1;
-}
-
-
-
-
-
-
-
-
-/* ----------------------------HELPER FUNCTIONS-------------------------------- */
-
-
-/* function returns:
- *       0 - transaction wasn't found
- *       T - transaction found
- */
-struct cell* t_lookupOriginalT(  struct s_table* hash_table , struct sip_msg* p_msg )
-{
-   struct cell      *p_cell;
-   struct cell      *tmp_cell;
-   unsigned int  hash_index=0;
-
-   /* it's a CANCEL request for sure */
-
-   /* start searching into the table */
-   hash_index = hash( p_msg->callid->body , get_cseq(p_msg)->number  ) ;
-   DBG("DEBUG: t_lookupOriginalT: searching on hash entry %d\n",hash_index );
-
-   /* all the transactions from the entry are compared */
-   p_cell     = hash_table->entrys[hash_index].first_cell;
-   tmp_cell = 0;
-   while( p_cell )
-   {
-      /* is it the wanted transaction ? */
-      /* first only the length are checked */
-      if ( /*from length*/ p_cell->inbound_request->from->body.len == p_msg->from->body.len )
-         if ( /*to length*/ p_cell->inbound_request->to->body.len == p_msg->to->body.len )
-            //if ( /*tag length*/ (!p_cell->inbound_request->tag && !p_msg->tag) || (p_cell->inbound_request->tag && p_msg->tag && p_cell->inbound_request->tag->body.len == p_msg->tag->body.len) )
-               if ( /*callid length*/ p_cell->inbound_request->callid->body.len == p_msg->callid->body.len )
-                  if ( /*cseq_nr length*/ get_cseq(p_cell->inbound_request)->number.len == get_cseq(p_msg)->number.len )
-                      if ( /*cseq_method type*/ p_cell->inbound_request->first_line.u.request.method_value!=METHOD_CANCEL )
-                         if ( /*req_uri length*/ p_cell->inbound_request->first_line.u.request.uri.len == p_msg->first_line.u.request.uri.len )
-                             /* so far the lengths are the same -> let's check the contents */
-                             if ( /*from*/ !memcmp( p_cell->inbound_request->from->body.s , p_msg->from->body.s , p_msg->from->body.len ) )
-                                if ( /*to*/ !memcmp( p_cell->inbound_request->to->body.s , p_msg->to->body.s , p_msg->to->body.len)  )
-                                   //if ( /*tag*/ (!p_cell->inbound_request->tag && !p_msg->tag) || (p_cell->inbound_request->tag && p_msg->tag && !memcmp( p_cell->inbound_request->tag->body.s , p_msg->tag->body.s , p_msg->tag->body.len )) )
-                                      if ( /*callid*/ !memcmp( p_cell->inbound_request->callid->body.s , p_msg->callid->body.s , p_msg->callid->body.len ) )
-                                          if ( /*cseq_nr*/ !memcmp( get_cseq(p_cell->inbound_request)->number.s , get_cseq(p_msg)->number.s , get_cseq(p_msg)->number.len ) )
-                                             if ( /*req_uri*/ !memcmp( p_cell->inbound_request->first_line.u.request.uri.s , p_msg->first_line.u.request.uri.s , p_msg->first_line.u.request.uri.len ) )
-                                             { /* WE FOUND THE GOLDEN EGG !!!! */
-                                                return p_cell;
-                                             }
-      /* next transaction */
-      tmp_cell = p_cell;
-      p_cell = p_cell->next_cell;
-   }
-
-   /* no transaction found */
-   T = 0;
-   return 0;
-
-
-   return 0;
+       return -1;
 }
 
 
 
-
-/* converts a string with positive hexadecimal number to an integer;
-   if a non-hexadecimal character encountered within 'len', -1 is
-   returned
-*/
-int str_unsigned_hex_2_int( char *c, int len )
+/* Push a previously stored reply from UA Client to UA Server
+  * and send it out
+  */
+int push_reply_from_uac_to_uas( struct cell* trans , unsigned int branch )
 {
-       int r=0;
-       int i;
-       int d;
+       char *buf;
+       unsigned int len;
+       struct retrans_buff *rb;
+       char *b;
+
+       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.payload = rb;
+               rb->fr_timer.payload =  rb;
+               rb->to.sin_family = AF_INET;
+               rb->my_T = trans;
 
-       for (i=0; i<len; i++ ) {
-               if (c[i]>='0' && c[i]<='9') d=c[i]-'0'; else
-               if (c[i]>='a' && c[i]<='f') d=c[i]-'a'+10; else
-               if (c[i]>='A' && c[i]<='F') d=c[i]-'A'+10; else
-               return -1;
-               r = (r<<4) + d;
+       } else {
+               reset_timer( hash_table, &(rb->retr_timer));
+               reset_timer( hash_table, &(rb->fr_timer));
        }
-       return r;
-}
-
-
 
+       /*  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 ( !(b = (char*)sh_malloc( len ))) {
+               LOG(L_ERR, "ERROR: push_reply_from_uac_to_uas: "
+                       "no memory to allocate retr_buffer\n");
+               goto error1;
+       }
+       if (  rb->retr_buffer ) 
+               sh_free(  rb->retr_buffer ) ;  
+       rb->retr_buffer = b;
+       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 )
+                       trans->relaied_reply_branch = branch;
 
-/* Returns 0 - nothing found
-  *              1  - T found
-  */
-int t_reply_matching( struct sip_msg *p_msg , unsigned int *p_branch )
-{
-   struct cell*  p_cell;
-   struct cell* tmp_cell;
-   unsigned int hash_index = 0;
-   unsigned int entry_label  = 0;
-   unsigned int branch_id    = 0;
-   char  *hashi, *syni, *branchi, *p, *n;
-   int hashl, synl, branchl;
-   int scan_space;
-
-   /* split the branch into pieces: loop_detection_check(ignored),
-      hash_table_id, synonym_id, branch_id*/
-
-   if (! ( p_msg->via1 && p_msg->via1->branch && p_msg->via1->branch->value.s) )
-       goto nomatch;
-
-   p=p_msg->via1->branch->value.s;
-   scan_space=p_msg->via1->branch->value.len;
-
-   /* loop detection ... ignore */
-   n=eat_token2_end( p, p+scan_space, '.');
-   scan_space-=n-p;
-   if (n==p || scan_space<2 || *n!='.') goto nomatch;
-   p=n+1; scan_space--;
-
-   /* hash_id */
-   n=eat_token2_end( p, p+scan_space, '.');
-   hashl=n-p;
-   scan_space-=hashl;
-   if (!hashl || scan_space<2 || *n!='.') goto nomatch;
-   hashi=p;
-   p=n+1;scan_space--;
-
-
-   /* sequence id */
-   n=eat_token2_end( p, p+scan_space, '.');
-   synl=n-p;
-   scan_space-=synl;
-   if (!synl || scan_space<2 || *n!='.') goto nomatch;
-   syni=p;
-   p=n+1;scan_space--;
-
-   /* branch id */  /*  should exceed the scan_space */
-   n=eat_token_end( p, p+scan_space );
-   branchl=n-p;
-   if (!branchl ) goto nomatch;
-   branchi=p;
-
-
-   hash_index=str_unsigned_hex_2_int(hashi, hashl);
-   entry_label=str_unsigned_hex_2_int(syni, synl);
-   branch_id=str_unsigned_hex_2_int(branchi, branchl);
-
-   DBG("DEBUG: t_reply_matching: hash %d label %d branch %d\n",
-       hash_index, entry_label, branch_id );
-
-   /* sanity check */
-   if (hash_index<0 || hash_index >=TABLE_ENTRIES ||
-       entry_label<0 || branch_id<0 || branch_id>=MAX_FORK )
-          goto nomatch;
-
-   /* lock the hole entry*/
-   lock( hash_table->entrys[hash_index].mutex );
-
-   /*all the cells from the entry are scan to detect an entry_label matching */
-   p_cell     = hash_table->entrys[hash_index].first_cell;
-   tmp_cell = 0;
-   while( p_cell )
-   {
-      /* is it the cell with the wanted entry_label? */
-      if ( p_cell->label == entry_label )
-      /* has the transaction the wanted branch? */
-      if ( p_cell->nr_of_outgoings>branch_id && p_cell->outbound_request[branch_id] )
-      {/* WE FOUND THE GOLDEN EGG !!!! */
-          T = p_cell;
-          *p_branch = branch_id;
-          T->ref_counter ++;
-          unlock( hash_table->entrys[hash_index].mutex );
-          DBG("DEBUG:XXXXXXXXXXXXXXXXXXXXX t_reply_matching: reply matched (T=%p, ref=%d)!\n",T,T->ref_counter);
-        return 1;
-      }
-      /* next cell */
-      tmp_cell = p_cell;
-      p_cell = p_cell->next_cell;
-
-   } /* while p_cell */
+       /* start/stops the proper timers*/
+       t_update_timers_after_sending_reply( rb );
 
-   /* nothing found */
-   DBG("DEBUG: t_reply_matching: no matching transaction exists\n");
+       /*send the reply*/
+       /* t_retransmit_reply( trans->inbound_response[branch], 0 , 0 ); */
+       SEND_BUFFER( rb );
+       return 1;
 
-nomatch:
-   DBG("DEBUG: t_reply_matching: failure to match a transaction\n");
-   *p_branch = -1;
-   T = 0;
-   unlock( hash_table->entrys[hash_index].mutex );
-   return -1;
+error1:
+       free( buf );
+error:
+       return -1;
 }
 
 
 
 
-/* Functions update T (T gets either a valid pointer in it or it equals zero) if no transaction
-  * for current message exists;
-  */
-int t_check( struct sip_msg* p_msg , int *param_branch)
-{
-   int local_branch;
-
-   /* is T still up-to-date ? */
-   DBG("DEBUG: t_check : msg id=%d , global msg id=%d , T=%p\n", p_msg->id,global_msg_id,T);
-   if ( p_msg->id != global_msg_id || T==T_UNDEFINED )
-   {
-      global_msg_id = p_msg->id;
-      if ( T && T!=T_UNDEFINED )
-         unref_T(T);
-      T = T_UNDEFINED;
-      /* transaction lookup */
-     if ( p_msg->first_line.type==SIP_REQUEST )
-         t_lookup_request( p_msg );
-     else
-         t_reply_matching( p_msg , ((param_branch!=0)?(param_branch):(&local_branch)) );
-   }
-   else
-   {
-      if (T)
-         DBG("DEBUG: t_check: T alredy found!\n");
-      else
-          DBG("DEBUG: t_check: T previously sought and not found\n");
-   }
 
-   return ((T)?1:-1) ;
-}
+/* ----------------------------HELPER FUNCTIONS-------------------------------- */
 
 
 
@@ -966,7 +754,8 @@ int t_all_final( struct cell *Trans )
    unsigned int i;
 
    for( i=0 ; i<Trans->nr_of_outgoings ; i++  )
-      if (  !Trans->inbound_response[i] ||  Trans->inbound_response[i]->first_line.u.reply.statuscode<=200 )
+      if (  !Trans->inbound_response[i] ||  
+                       Trans->inbound_response[i]->REPLY_STATUS<=200 )
          return 0;
 
   DBG("DEBUG: t_all_final: final state!!!!:)) \n");
@@ -987,11 +776,11 @@ int relay_lowest_reply_upstream( struct cell *Trans , struct sip_msg *p_msg )
 
    for(  ; i<T->nr_of_outgoings ; i++ )
       if ( T->inbound_response[i] &&
-          T->inbound_response[i]->first_line.u.reply.statuscode>=200 &&
-          T->inbound_response[i]->first_line.u.reply.statuscode<lowest_v )
+          T->inbound_response[i]->REPLY_STATUS>=200 &&
+          T->inbound_response[i]->REPLY_STATUS<lowest_v )
       {
          lowest_i =i;
-         lowest_v = T->inbound_response[i]->first_line.u.reply.statuscode;
+         lowest_v = T->inbound_response[i]->REPLY_STATUS;
       }
 
    DBG("DEBUG: relay_lowest_reply_upstream: lowest reply [%d]=%d\n",lowest_i,lowest_v);
@@ -1005,146 +794,86 @@ int relay_lowest_reply_upstream( struct cell *Trans , struct sip_msg *p_msg )
 
 
 
-/* Push a previously stored reply from UA Client to UA Server
-  * and send it out
-  */
-int push_reply_from_uac_to_uas( struct cell* trans , unsigned int branch )
-{
-   char *buf;
-   unsigned int len;
-
-   DBG("DEBUG: push_reply_from_uac_to_uas: start\n");
-   /* if there is a reply, release the buffer (everything else stays same) */
-   if ( trans->outbound_response )
-   {
-      sh_free( trans->outbound_response->retr_buffer );
-      remove_from_timer( hash_table , (&(trans->outbound_response->tl[RETRASMISSIONS_LIST])) , RETRASMISSIONS_LIST );
-      remove_from_timer( hash_table , (&(trans->outbound_response->tl[FR_TIMER_LIST])) , FR_TIMER_LIST );
-   }
-   else
-   {
-      struct hostent  *nhost;
-     char foo;
-
-      trans->outbound_response = (struct retrans_buff*)sh_malloc( sizeof(struct retrans_buff) );
-      if (!trans->outbound_response) {
-       LOG(L_ERR, "ERROR: push_reply_from_uac_to_uas: no more shmem\n");
-       trans->outbound_response = NULL;
-       return -1;
-      }
-      /*init retrans buffer*/
-      memset( trans->outbound_response , 0 , sizeof (struct retrans_buff) );
-      trans->outbound_response->tl[RETRASMISSIONS_LIST].payload = trans->outbound_response;
-      trans->outbound_response->tl[FR_TIMER_LIST].payload = trans->outbound_response;
-      trans->outbound_response->to.sin_family = AF_INET;
-      trans->outbound_response->my_T = trans;
-
-      if (update_sock_struct_from_via(  &(trans->outbound_response->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 );
-       sh_free(  T->outbound_response );
-       T->outbound_response = NULL;
-       return -1;
-      }
-   }
-
-   /*  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");
-        return -1;
-   }
-   trans->outbound_response->bufflen = len ;
-   trans->outbound_response->retr_buffer   = (char*)sh_malloc( len );
-   if (! trans->outbound_response->retr_buffer ) {
-       LOG(L_ERR, "ERROR: push_reply_from_uac_to_uas: no memory to allocate retr_buffer\n");
-       free( buf );
-       return -1;
-   }
-   memcpy( trans->outbound_response->retr_buffer , buf , len );
-   free( buf ) ;
-
-   /* update the status*/
-   trans->status = trans->inbound_response[branch]->first_line.u.reply.statuscode;
-   if ( trans->inbound_response[branch]->first_line.u.reply.statuscode>=200 &&
-         trans->relaied_reply_branch==-1 )
-       trans->relaied_reply_branch = branch;
-
-    /* start/stops the proper timers*/
-   t_update_timers_after_sending_reply( T->outbound_response );
-
-   /*send the reply*/
-   t_retransmit_reply( trans->inbound_response[branch], 0 , 0 );
-   return 1;
-}
-
-
-
-
 /*
   */
 int t_update_timers_after_sending_reply( struct retrans_buff *rb )
 {
-   struct cell *Trans = rb->my_T;
+       struct cell *Trans = rb->my_T;
 
-   /* make sure that if we send something final upstream, everything else will be cancelled */
-   if ( Trans->status>=300 &&  Trans->inbound_request->first_line.u.request.method_value==METHOD_INVITE )
-   {
-            rb->timeout_ceiling  = RETR_T2;
-            rb->timeout_value    = RETR_T1;
-            insert_into_timer( hash_table , (&(rb->tl[RETRASMISSIONS_LIST])) , RETRASMISSIONS_LIST , RETR_T1 );
-            insert_into_timer( hash_table , (&(rb->tl[FR_TIMER_LIST])) , FR_TIMER_LIST , FR_TIME_OUT );
-   }
-   else if ( Trans->inbound_request->first_line.u.request.method_value==METHOD_CANCEL )
-   {
-      if ( Trans->T_canceled==T_UNDEFINED )
-            Trans->T_canceled = t_lookupOriginalT( hash_table , Trans->inbound_request );
-      if ( Trans->T_canceled==T_NULL )
-            return 1;
-      Trans->T_canceled->T_canceler = Trans;
-     /* put CANCEL transaction on wait only if canceled transaction already
-        is in final status and there is nothing to cancel; 
-     */
-     if ( Trans->T_canceled->status>=200)
-            t_put_on_wait( Trans );
-   }
-   else if (Trans->status>=200)
+       /* make sure that if we send something final upstream, everything else 
+          will be cancelled */
+       if (Trans->status>=300 && Trans->inbound_request->REQ_METHOD==METHOD_INVITE )
+       {
+               rb->retr_list = RT_T1_TO_1;
+               set_timer( hash_table, &(rb->retr_timer), RT_T1_TO_1 );
+               set_timer( hash_table, &(rb->fr_timer), FR_TIMER_LIST );
+       } else if ( Trans->inbound_request->REQ_METHOD==METHOD_CANCEL ) {
+               if ( Trans->T_canceled==T_UNDEFINED )
+                       Trans->T_canceled = t_lookupOriginalT( hash_table , 
+                               Trans->inbound_request );
+               if ( Trans->T_canceled==T_NULL )
+                       return 1;
+               Trans->T_canceled->T_canceler = Trans;
+               /* put CANCEL transaction on wait only if canceled transaction already
+                  is in final status and there is nothing to cancel; 
+               */
+               if ( Trans->T_canceled->status>=200)
+                       t_put_on_wait( Trans );
+       } else if (Trans->status>=200)
             t_put_on_wait( Trans );
-
    return 1;
 }
 
 
 
 
-/* Checks if the new reply (with new_code status) should be sent or not based on the current
-  * transactin status. Returns 1 - the response can be sent
-  *                                            0 - is not indicated to sent
+/* Checks if the new reply (with new_code status) should be sent or not 
+ *  based on the current
+  * transactin status. 
+  * Returns 1 - the response can be sent
+  *         0 - is not indicated to sent
   */
 int t_should_relay_response( struct cell *Trans , int new_code )
 {
-   int T_code;
+       int T_code;
+
+       T_code = Trans->status;
+
+       if ( T_code >= 200 ) { /* if final response sent out ... */
+               if (new_code>=200 && new_code < 300  && /* relay only 2xx */
+                       Trans->inbound_request->REQ_METHOD==METHOD_INVITE) {
+                       DBG("DBG: t_should_relay: 200 INV after final sent\n");
+                       return 1;
+               }
+       } else { /* no final response sent yet */
+               if (new_code!=100) { /* all but "100 trying" */
+                       DBG("DBG: t_should_relay: !=100 -> relay\n");
+                       return 1;
+               } 
+       }
+       DBG("DBG: t_should_relay: not to be relayed\n");
+       return 0;
 
-   T_code = Trans->status;
 
-   /* have we already sent something? */
-   if ( !Trans->outbound_response )
+/*
+   // have we already sent something? 
+   if ( !Trans->outbound_response.retr_buffer )
    {
       DBG("DEBUG: t_should_relay_response: %d response relayed (no previous response sent)\n",new_code);
       return 1;
    }
 
-   /* have we sent a final response? */
+   // have we sent a final response? 
    if ( (T_code/100)>1 )
-   {  /*final response was sent*/
-      if ( new_code==200 && Trans->inbound_request->first_line.u.request.method_value==METHOD_INVITE )
+   {  //final response was sent
+      if ( new_code==200 && Trans->inbound_request->REQ_METHOD==METHOD_INVITE )
       {
          DBG("DEBUG: t_should_relay_response: %d response relayed (final satus, but 200 to an INVITE)\n",new_code);
          return 0;
       }
    }
    else
-   { /* provisional response was sent */
+   { // provisional response was sent 
       if ( new_code>T_code )
       {
          DBG("DEBUG: t_should_relay_response: %d response relayed (higher provisional response)\n",new_code);
@@ -1154,6 +883,7 @@ int t_should_relay_response( struct cell *Trans , int new_code )
 
    DBG("DEBUG: t_should_relay_response: %d response not relayed\n",new_code);
    return 0;
+*/
 }
 
 
@@ -1163,27 +893,27 @@ int t_should_relay_response( struct cell *Trans , int new_code )
   */
 int t_put_on_wait(  struct cell  *Trans  )
 {
-   struct timer_link *tl;
-   unsigned int i;
+       struct timer_link *tl;
+       unsigned int i;
+       if (is_in_timer_list2( &(Trans->wait_tl)))
+       {
+               DBG("DEBUG: t_put_on_wait: already on wait\n");
+               return 1;
+       }
 
-  if ( is_in_timer_list( (&(Trans->wait_tl)) , WT_TIMER_LIST) )
-  {
-     DBG("DEBUG: t_put_on_wait: already on wait\n");
-     return 1;
-  }
-
-   DBG("DEBUG: t_put_on_wait: stopping timers (FR and RETR)\n");
-   /**/
-   for( i=0 ; i<Trans->nr_of_outgoings ; i++ )
-      if ( Trans->inbound_response[i] && Trans->inbound_response[i]->first_line.u.reply.statusclass==1)
-          t_cancel_branch(i);
-
-   /* make double-sure we have finished everything */
-   /* remove from  retranssmision  and  final response   list */
-   stop_RETR_and_FR_timers(hash_table,Trans) ;
-   /* adds to Wait list*/
-   add_to_tail_of_timer( hash_table, (&(Trans->wait_tl)), WT_TIMER_LIST, WT_TIME_OUT );
-   return 1;
+       DBG("DEBUG: t_put_on_wait: stopping timers (FR and RETR)\n");
+       /**/
+       for( i=0 ; i<Trans->nr_of_outgoings ; i++ )
+               if ( Trans->inbound_response[i] && 
+               REPLY_CLASS(Trans->inbound_response[i])==1)
+               t_cancel_branch(i);
+
+       /* make double-sure we have finished everything */
+       /* remove from  retranssmision  and  final response   list */
+       reset_retr_timers(hash_table,Trans) ;
+       /* adds to Wait list*/
+       set_timer( hash_table, &(Trans->wait_tl), WT_TIMER_LIST );
+       return 1;
 }
 
 
@@ -1236,12 +966,12 @@ int t_build_and_send_ACK( struct cell *Trans, unsigned int branch, struct sip_ms
     /*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 ) ;
+                 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 ) ;
+                 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;
+   /* CSEQ method : from INVITE-> ACK, don't count CRLF twice*/
+   len -= 3 + 2 ;
    /* end of message */
    len += CRLF_LEN; /*new line*/
 
@@ -1282,12 +1012,16 @@ int t_build_and_send_ACK( struct cell *Trans, unsigned int branch, struct sip_ms
                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 )
        {
@@ -1319,26 +1053,36 @@ error:
 
 
 
-/*---------------------------------TIMEOUT HANDLERS--------------------------------------*/
+/*---------------------TIMEOUT HANDLERS--------------------------*/
 
 
 void retransmission_handler( void *attr)
 {
-   struct retrans_buff* r_buf = (struct retrans_buff*)attr;
+       struct retrans_buff* r_buf ;
+       enum lists id;
+
+       r_buf = (struct retrans_buff*)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 the timer */
+       /*the transaction is already removed from RETRANSMISSION_LIST by timer*/
 
-   /* computs the new timeout. */
-   if ( r_buf->timeout_value<r_buf->timeout_ceiling )
-      r_buf->timeout_value *=2;
+       /* retransmision */
+       DBG("DEBUG: retransmission_handler : resending (t=%p)\n", r_buf->my_T);
+       SEND_BUFFER( r_buf );
 
-   /* retransmision */
-   DBG("DEBUG: retransmission_handler : resending\n");
-   udp_send( r_buf->retr_buffer, r_buf->bufflen, (struct sockaddr*)&(r_buf->to) , sizeof(struct sockaddr_in) );
+       id = r_buf->retr_list;
+       r_buf->retr_list = id < RT_T2 ? id + 1 : RT_T2;
 
-   /* re-insert into RETRASMISSIONS_LIST */
-   insert_into_timer( hash_table , (&(r_buf->tl[RETRASMISSIONS_LIST])) , RETRASMISSIONS_LIST , r_buf->timeout_value );
-   DBG("DEBUG: retransmission_handler : done\n");
+       set_timer( hash_table, &(r_buf->retr_timer), id < RT_T2 ? id + 1 : RT_T2 );
+
+       DBG("DEBUG: retransmission_handler : done\n");
 }
 
 
@@ -1346,23 +1090,40 @@ void retransmission_handler( void *attr)
 
 void final_response_handler( void *attr)
 {
-   struct retrans_buff* r_buf = (struct retrans_buff*)attr;
-
-   /* the transaction is already removed from FR_LIST by the timer */
-   /* send a 408 */
-   if ( r_buf->my_T->status<200)
-   {
-      DBG("DEBUG: final_response_handler : stop retransmission and send 408\n");
-      remove_from_timer( hash_table , (&(r_buf->tl[RETRASMISSIONS_LIST])) , RETRASMISSIONS_LIST );
-      t_send_reply( r_buf->my_T->inbound_request , 408 , "Request Timeout" );
-   }
-   else
-   {
-      /* put it on WT_LIST - transaction is over */
-      DBG("DEBUG: final_response_handler : cansel transaction->put on wait\n");
-      t_put_on_wait(  r_buf->my_T );
-   }
-   DBG("DEBUG: final_response_handler : done\n");
+       struct retrans_buff* r_buf = (struct retrans_buff*)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 */
+       /* send a 408 */
+       if ( r_buf->my_T->status<200)
+       {
+               DBG("DEBUG: final_response_handler:stop retransmission and send 408 (t=%p)\n", r_buf->my_T);
+               reset_timer( hash_table, &(r_buf->retr_timer) );
+               /* 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->inbound_request->id;
+
+               t_send_reply( r_buf->my_T->inbound_request , 408 , "Request Timeout" );
+       } else {
+               /* put it on WT_LIST - transaction is over */
+               DBG("DEBUG: final_response_handler:cancel transaction->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");
 }
 
 
@@ -1370,17 +1131,28 @@ void final_response_handler( void *attr)
 
 void wait_handler( void *attr)
 {
-   struct cell *p_cell = (struct cell*)attr;
-
-   /* the transaction is already removed from WT_LIST by the timer */
-   /* the cell is removed from the hash table */
-   DBG("DEBUG: wait_handler : removing from table \n");
-   remove_from_hash_table( hash_table, p_cell );
-   DBG("DEBUG: wait_handler : stopping all timers\n");
-   stop_RETR_and_FR_timers(hash_table,p_cell) ;
-   /* put it on DEL_LIST - sch for del */
-    add_to_tail_of_timer( hash_table, (&(p_cell->dele_tl)), DELETE_LIST, DEL_TIME_OUT );
-   DBG("DEBUG: wait_handler : done\n");
+       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 );
+       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
+       set_timer( hash_table, &(p_cell->dele_tl), DELETE_LIST );
+       DBG("DEBUG: wait_handler : done\n");
 }
 
 
@@ -1388,50 +1160,66 @@ void wait_handler( void *attr)
 
 void delete_handler( void *attr)
 {
-   struct cell *p_cell = (struct cell*)attr;
-
-   /* the transaction is already removed from DEL_LIST by the timer */
-    /* if is not refenceted -> is deleted*/
-    if ( p_cell->ref_counter==0 )
-    {
-       DBG("DEBUG: delete_handler : delete transaction\n");
-       free_cell( p_cell );
-    }
-    else
-    {
-       DBG("DEBUG: delete_handler : re post for delete (%d)\n",p_cell->ref_counter);
-       /* else it's readded to del list for future del */
-       add_to_tail_of_timer( hash_table, (&(p_cell->dele_tl)), DELETE_LIST, DEL_TIME_OUT );
-    }
-    DBG("DEBUG: delete_handler : done\n");
-}
-
+       struct cell *p_cell = (struct cell*)attr;
 
+#ifdef EXTRA_DEBUG
+       int i;
+       if (p_cell->damocles==0) {
+               LOG( L_ERR, "ERROR: transaction %p not scheduled for deletion and called from DELETE timer\n",
+                       p_cell);
+               abort();
+       }       
+       if (is_in_timer_list2(& p_cell->wait_tl )) {
+               LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and still on WAIT\n",
+                       p_cell);
+               abort();
+       }
+       if (is_in_timer_list2(& p_cell->outbound_response.retr_timer )) {
+               LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and still on RETR (rep)\n",
+                       p_cell);
+               abort();
+       }
+       if (is_in_timer_list2(& p_cell->outbound_response.fr_timer )) {
+               LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and still on FR (rep)\n",
+                       p_cell);
+               abort();
+       }
+       for (i=0; i<p_cell->nr_of_outgoings; i++) {
+               if (is_in_timer_list2(& p_cell->outbound_request[i]->retr_timer)) {
+                       LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and still on RETR (req %d)\n",
+                       p_cell, i);
+                       abort();
+               }
+               if (is_in_timer_list2(& p_cell->outbound_request[i]->fr_timer)) {
+                       LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and still on FR (req %d)\n",
+                       p_cell, i);
+                       abort();
+               }
+       }
 
+#endif
 
-/* append appropriate branch labels for fast reply-transaction matching
-   to outgoing requests
-*/
-int add_branch_label( struct cell *trans, struct sip_msg *p_msg, int branch )
-{
-       char *c;
-       short n;
-
-       n=snprintf( p_msg->add_to_branch_s+p_msg->add_to_branch_len,
-                 MAX_BRANCH_PARAM_LEN - p_msg->add_to_branch_len,
-                ".%x.%x.%x",
-                trans->hash_index, trans->label, branch );
-       if (n==-1) {
-               LOG(L_ERR, "ERROR: add_branch_label: too small branch buffer\n");
-               return -1;
+       /* the transaction is already removed from DEL_LIST by the timer */
+       /* if is not refenceted -> is deleted*/
+       if ( p_cell->ref_counter==0 )
+       {
+               DBG("DEBUG: delete_handler : delete transaction %p\n", p_cell );
+               free_cell( p_cell );
        } else {
-               p_msg->add_to_branch_len += n;
-               DBG("DEBUG: XXX branch label created now: %*s (%d)\n", p_msg->add_to_branch_len,
-                       p_msg->add_to_branch_s );
-               return 0;
-       }
+#ifdef EXTRA_DEBUG
+               if (p_cell->ref_counter>1) {
+                       DBG("DEBUG: while debugging with a single process, ref_count > 1\n");
+                       DBG("DEBUG: transaction =%p\n", p_cell );
+                       abort();
+               }
+#endif
+               DBG("DEBUG: delete_handler: t=%p post for delete (%d)\n",
+                       p_cell,p_cell->ref_counter);
+               /* else it's readded to del list for future del */
+               set_timer( hash_table, &(p_cell->dele_tl), DELETE_LIST );
+    }
+    DBG("DEBUG: delete_handler : done\n");
 }
 
 
 
-
index 4ccbf42..5c4a2ce 100644 (file)
 #include "../../globals.h"
 #include "../../udp_server.h"
 #include "../../msg_translator.h"
-#include "../../mem.h"
+#include "../../mem/mem.h"
 
 struct s_table;
 struct timer;
 struct entry;
 struct cell;
 
+extern struct cell         *T;
+extern unsigned int     global_msg_id;
+extern struct s_table*  hash_table;
+
+
 #include "sh_malloc.h"
 
 #include "timer.h"
@@ -27,12 +32,41 @@ struct cell;
 #include "sip_msg.h"
 
 
-/* already defined in msg_parser.h
-#define get_cseq( p_msg)    ((struct cseq_body*)p_msg->cseq->parsed)
+
+/* 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)
+#define SEND_BUFFER( _rb ) ({ if ((_rb)->retr_buffer) \
+       { udp_send( (_rb)->retr_buffer, \
+         (_rb)->bufflen, (struct sockaddr*)&((_rb)->to) , \
+         sizeof(struct sockaddr_in) ); \
+       } else \
+       DBG("ERROR: attempt to send an empty buffer from %s (%d)", \
+       __FUNCTION__, __LINE__ ); })
+
+
+/* to avoid too many locks/unlocks, we gave up using separate locks
+   for cells and use those of transaction table entries
 */
 
-/* maximumum length of localy generated acknowledgement */
-#define MAX_ACK_LEN 1024
+#define DBG_REF(_action, _t) DBG("DEBUG: XXXXX %s (%s:%d): T=%p , ref=%d\n",\
+                       (_action), __FUNCTION__, __LINE__, (_t),(_t)->ref_counter);
+
+#define unref_T(_T_cell) \
+       ( {\
+               lock( hash_table->entrys[(_T_cell)->hash_index].mutex );\
+               (_T_cell)->ref_counter--;\
+               DBG_REF("unref", (_T_cell)); \
+               unlock( hash_table->entrys[(_T_cell)->hash_index].mutex );\
+       } );
+
+/* we assume that ref_T is only called from places where
+   the associated locks are set up and we don't need to
+   lock/unlock
+*/
+#define ref_T(_T_cell) ({ ((_T_cell)->ref_counter++); \
+               DBG_REF("ref", (_T_cell));      })
 
 
 int   tm_startup();
@@ -107,7 +141,8 @@ int t_retransmit_reply( struct sip_msg *, char* , char* );
 int t_send_reply( struct sip_msg * , unsigned int , char *  );
 
 
-
+/* releases T-context */
+int t_unref( struct sip_msg* p_msg, char* foo, char* bar );
 
 
 
diff --git a/modules/tm/t_lookup.c b/modules/tm/t_lookup.c
new file mode 100644 (file)
index 0000000..da6eaac
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * $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"
+
+static int reverse_hex2int( char *c, int len )
+{
+       char *pc;
+       int r;
+       char mychar;
+
+       r=0;
+       for (pc=c+len-1; len>0; pc--, len--) {
+               r <<= 4 ;
+               mychar=*pc;
+               if ( mychar >='0' && mychar <='9') r+=mychar -'0';
+               else if (mychar >='a' && mychar <='f') r+=mychar -'a'+10;
+               else if (mychar  >='A' && mychar <='F') r+=mychar -'A'+10;
+               else return -1;
+       }
+       return r;
+}
+
+inline static int int2reverse_hex( char **c, int *size, int nr )
+{
+       unsigned short digit;
+
+       if (*size && nr==0) {
+               **c = '0';
+               (*c)++;
+               (*size)--;
+               return 1;
+       }
+
+       while (*size && nr ) {
+               digit = nr & 0xf ;
+               **c= digit >= 10 ? digit + 'a' - 10 : digit + '0';
+               nr >>= 4;
+               (*c)++;
+               (*size)--;
+       }
+       return nr ? -1 /* number not processed; too little space */ : 1;
+}
+
+/* function returns:
+ *      -1 - transaction wasn't found
+ *       1  - transaction found
+ */
+int t_lookup_request( struct sip_msg* p_msg )
+{
+   struct cell      *p_cell;
+   struct cell      *tmp_cell;
+   unsigned int  hash_index=0;
+   unsigned int  isACK;
+   struct sip_msg      *t_msg;
+
+   DBG("t_lookup_request: start searching\n");
+
+   /* parse all*/
+   if (check_transaction_quadruple(p_msg)==0)
+   {
+      LOG(L_ERR, "ERROR: TM module: t_lookup_request: too few headers\n");
+      T=0;
+      return -1;
+   }
+
+   /* start searching into the table */
+   hash_index = hash( p_msg->callid->body , get_cseq(p_msg)->number ) ;
+   isACK = p_msg->REQ_METHOD==METHOD_ACK;
+   DBG("t_lookup_request: continue searching;  hash=%d, isACK=%d\n",hash_index,isACK);
+
+   /* lock the hole entry*/
+   lock( hash_table->entrys[hash_index].mutex );
+
+   /* all the transactions from the entry are compared */
+   p_cell     = hash_table->entrys[hash_index].first_cell;
+   tmp_cell = 0;
+   while( p_cell )
+   {
+               int abba;
+
+               t_msg = p_cell->inbound_request;
+
+#define EQ_LEN(_hf) (t_msg->_hf->body.len==p_msg->_hf->body.len)
+#define EQ_STR(_hf) (memcmp(t_msg->_hf->body.s, p_msg->_hf->body.s, \
+               p_msg->_hf->body.len)==0)
+
+
+               if ( EQ_LEN(from) && EQ_LEN(callid) &&
+                 EQ_STR(callid) && EQ_STR(callid) &&
+                 /* we compare only numerical parts of CSEQ ...
+                    the method name should be the same as in first line */
+                 memcmp( get_cseq(t_msg)->number.s , get_cseq(p_msg)->number.s , 
+                               get_cseq(p_msg)->number.len ) ==0 )
+               {
+                       if (!isACK) {
+                               if (t_msg->REQ_METHOD == p_msg->REQ_METHOD &&
+                                       EQ_LEN(to) && EQ_STR(to))
+                                       goto found;
+                       } else { /* ACK */
+                               if (t_msg->REQ_METHOD == METHOD_INVITE  &&
+                                       //p_cell->tag &&  p_cell->tag->len==p_msg->tag->body.len &&
+                       //if ( /*tag*/ memcmp( p_cell->tag->s , p_msg->tag->body.s , 
+                                       // p_msg->tag->body.len ) ==0 )
+                                       EQ_STR( to ) ) {
+                                       goto found;
+                               }
+                       } /* ACK */
+               } /* common HFs equal */
+
+      /* next transaction */
+      tmp_cell = p_cell;
+      p_cell = p_cell->next_cell;
+   } /* synonym loop */
+
+   /* no transaction found */
+   T = 0;
+   unlock( hash_table->entrys[hash_index].mutex );
+   DBG("DEBUG: t_lookup_request: no transaction found\n");
+   return -1;
+
+found:
+       T=p_cell;
+       ref_T( T );
+       DBG("DEBUG:XXXXXXXXXXXXXXXXXXXXX t_lookup_request: "
+                       "transaction found ( T=%p , ref=%d)\n",T,T->ref_counter);
+       unlock( hash_table->entrys[hash_index].mutex );
+       return 1;
+}
+
+
+
+
+/* function returns:
+ *       0 - transaction wasn't found
+ *       T - transaction found
+ */
+struct cell* t_lookupOriginalT(  struct s_table* hash_table , struct sip_msg* p_msg )
+{
+   struct cell      *p_cell;
+   struct cell      *tmp_cell;
+   unsigned int  hash_index=0;
+
+   /* it's a CANCEL request for sure */
+
+   /* start searching into the table */
+   hash_index = hash( p_msg->callid->body , get_cseq(p_msg)->number  ) ;
+   DBG("DEBUG: t_lookupOriginalT: searching on hash entry %d\n",hash_index );
+
+   /* all the transactions from the entry are compared */
+   p_cell     = hash_table->entrys[hash_index].first_cell;
+   tmp_cell = 0;
+   while( p_cell )
+   {
+      /* is it the wanted transaction ? */
+      /* first only the length are checked */
+      if ( /*from length*/ p_cell->inbound_request->from->body.len == p_msg->from->body.len )
+         if ( /*to length*/ p_cell->inbound_request->to->body.len == p_msg->to->body.len )
+            //if ( /*tag length*/ (!p_cell->inbound_request->tag && !p_msg->tag) || (p_cell->inbound_request->tag && p_msg->tag && p_cell->inbound_request->tag->body.len == p_msg->tag->body.len) )
+               if ( /*callid length*/ p_cell->inbound_request->callid->body.len == p_msg->callid->body.len )
+                  if ( /*cseq_nr length*/ get_cseq(p_cell->inbound_request)->number.len == get_cseq(p_msg)->number.len )
+                      if ( /*cseq_method type*/ p_cell->inbound_request->REQ_METHOD!=METHOD_CANCEL )
+                         if ( /*req_uri length*/ p_cell->inbound_request->first_line.u.request.uri.len == p_msg->first_line.u.request.uri.len )
+                             /* so far the lengths are the same -> let's check the contents */
+                             if ( /*from*/ memcmp( p_cell->inbound_request->from->body.s , p_msg->from->body.s , p_msg->from->body.len )==0 )
+                                if ( /*to*/ memcmp( p_cell->inbound_request->to->body.s , p_msg->to->body.s , p_msg->to->body.len)==0  )
+                                   //if ( /*tag*/ (!p_cell->inbound_request->tag && !p_msg->tag) || (p_cell->inbound_request->tag && p_msg->tag && memcmp( p_cell->inbound_request->tag->body.s , p_msg->tag->body.s , p_msg->tag->body.len )==0) )
+                                      if ( /*callid*/ memcmp( p_cell->inbound_request->callid->body.s , p_msg->callid->body.s , p_msg->callid->body.len )==0 )
+                                          if ( /*cseq_nr*/ memcmp( get_cseq(p_cell->inbound_request)->number.s , get_cseq(p_msg)->number.s , get_cseq(p_msg)->number.len )==0 )
+                                             if ( /*req_uri*/ memcmp( p_cell->inbound_request->first_line.u.request.uri.s , p_msg->first_line.u.request.uri.s , p_msg->first_line.u.request.uri.len )==0 )
+                                             { /* WE FOUND THE GOLDEN EGG !!!! */
+                                                return p_cell;
+                                             }
+      /* next transaction */
+      tmp_cell = p_cell;
+      p_cell = p_cell->next_cell;
+   }
+
+   /* no transaction found */
+   T = 0;
+   return 0;
+
+
+   return 0;
+}
+
+
+
+
+/* Returns 0 - nothing found
+  *              1  - T found
+  */
+int t_reply_matching( struct sip_msg *p_msg , unsigned int *p_branch )
+{
+   struct cell*  p_cell;
+   struct cell* tmp_cell;
+   unsigned int hash_index = 0;
+   unsigned int entry_label  = 0;
+   unsigned int branch_id    = 0;
+   char  *hashi, *syni, *branchi, *p, *n;
+   int hashl, synl, branchl;
+   int scan_space;
+
+   /* split the branch into pieces: loop_detection_check(ignored),
+      hash_table_id, synonym_id, branch_id*/
+
+   if (! ( p_msg->via1 && p_msg->via1->branch && p_msg->via1->branch->value.s) )
+       goto nomatch2;
+
+   p=p_msg->via1->branch->value.s;
+   scan_space=p_msg->via1->branch->value.len;
+
+   /* loop detection ... ignore */
+   n=eat_token2_end( p, p+scan_space, '.');
+   scan_space-=n-p;
+   if (n==p || scan_space<2 || *n!='.') goto nomatch2;
+   p=n+1; scan_space--;
+
+   /* hash_id */
+   n=eat_token2_end( p, p+scan_space, '.');
+   hashl=n-p;
+   scan_space-=hashl;
+   if (!hashl || scan_space<2 || *n!='.') goto nomatch2;
+   hashi=p;
+   p=n+1;scan_space--;
+
+
+   /* sequence id */
+   n=eat_token2_end( p, p+scan_space, '.');
+   synl=n-p;
+   scan_space-=synl;
+   if (!synl || scan_space<2 || *n!='.') goto nomatch2;
+   syni=p;
+   p=n+1;scan_space--;
+
+   /* branch id */  /*  should exceed the scan_space */
+   n=eat_token_end( p, p+scan_space );
+   branchl=n-p;
+   if (!branchl ) goto nomatch2;
+   branchi=p;
+
+
+   hash_index=reverse_hex2int(hashi, hashl);
+   entry_label=reverse_hex2int(syni, synl);
+   branch_id=reverse_hex2int(branchi, branchl);
+       if (hash_index==-1 || entry_label==-1 || branch_id==-1) {
+               DBG("DEBUG: t_reply_matching: poor reply lables %d label %d branch %d\n",
+                       hash_index, entry_label, branch_id );
+               goto nomatch2;
+       }
+
+
+   DBG("DEBUG: t_reply_matching: hash %d label %d branch %d\n",
+       hash_index, entry_label, branch_id );
+
+   /* sanity check */
+   if (hash_index<0 || hash_index >=TABLE_ENTRIES ||
+       entry_label<0 || branch_id<0 || branch_id>=MAX_FORK ) {
+                       DBG("DBG: t_reply_matching: snaity check failed\n");
+               goto nomatch2;
+       }
+
+   /* lock the hole entry*/
+   lock( hash_table->entrys[hash_index].mutex );
+
+   /*all the cells from the entry are scan to detect an entry_label matching */
+   p_cell     = hash_table->entrys[hash_index].first_cell;
+   tmp_cell = 0;
+   while( p_cell )
+   {
+      /* is it the cell with the wanted entry_label? */
+      if ( p_cell->label == entry_label )
+      /* has the transaction the wanted branch? */
+      if ( p_cell->nr_of_outgoings>branch_id && p_cell->outbound_request[branch_id] )
+      {/* WE FOUND THE GOLDEN EGG !!!! */
+          T = p_cell;
+          *p_branch = branch_id;
+          /* T->ref_counter ++; */
+                 ref_T( T );
+          unlock( hash_table->entrys[hash_index].mutex );
+          DBG("DEBUG:XXXXXXXXXXXXXXXXXXXXX t_reply_matching: reply matched (T=%p, ref=%d)!\n",T,T->ref_counter);
+        return 1;
+      }
+      /* next cell */
+      tmp_cell = p_cell;
+      p_cell = p_cell->next_cell;
+
+   } /* while p_cell */
+
+   /* nothing found */
+   DBG("DEBUG: t_reply_matching: no matching transaction exists\n");
+
+nomatch:
+   unlock( hash_table->entrys[hash_index].mutex );
+nomatch2:
+   DBG("DEBUG: t_reply_matching: failure to match a transaction\n");
+   *p_branch = -1;
+   T = 0;
+   return -1;
+}
+
+
+
+
+/* Functions update T (T gets either a valid pointer in it or it equals zero) if no transaction
+  * for current message exists;
+  */
+int t_check( struct sip_msg* p_msg , int *param_branch)
+{
+   int local_branch;
+
+   /* is T still up-to-date ? */
+   DBG("DEBUG: t_check : msg id=%d , global msg id=%d , T=%p\n", p_msg->id,global_msg_id,T);
+   if ( p_msg->id != global_msg_id || T==T_UNDEFINED )
+   {
+      global_msg_id = p_msg->id;
+      if ( T && T!=T_UNDEFINED )
+         unref_T(T);
+      T = T_UNDEFINED;
+      /* transaction lookup */
+     if ( p_msg->first_line.type==SIP_REQUEST )
+         t_lookup_request( p_msg );
+     else
+         t_reply_matching( p_msg , ((param_branch!=0)?(param_branch):(&local_branch)) );
+#ifdef EXTRA_DEBUG
+       if ( T && T!=T_UNDEFINED && T->damocles) {
+               LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and called from t_check\n", T);
+               abort();
+       }
+#endif
+
+   }
+   else
+   {
+      if (T)
+         DBG("DEBUG: t_check: T alredy found!\n");
+      else
+          DBG("DEBUG: t_check: T previously sought and not found\n");
+   }
+
+   return ((T)?1:-1) ;
+}
+
+
+
+/* append appropriate branch labels for fast reply-transaction matching
+   to outgoing requests
+*/
+int add_branch_label( struct cell *trans, struct sip_msg *p_msg, int branch )
+{
+       char *c;
+
+       char *begin;
+       unsigned int size, orig_size, n;
+
+       begin=p_msg->add_to_branch_s+p_msg->add_to_branch_len;
+       orig_size = size=MAX_BRANCH_PARAM_LEN - p_msg->add_to_branch_len;
+
+       if (size) { *begin='.'; begin++; size--; } else return -1;
+       if (int2reverse_hex( &begin, &size, trans->hash_index)==-1) return -1;
+       if (size) { *begin='.'; begin++; size--; } else return -1;
+       if (int2reverse_hex( &begin, &size, trans->label)==-1) return -1;
+       if (size) { *begin='.'; begin++; size--; } else return -1;
+       if (int2reverse_hex( &begin, &size, branch)==-1) return -1;
+
+       p_msg->add_to_branch_len+=(orig_size-size);
+       DBG("DEBUG: XXX branch label created now: %*s (%d)\n",
+               p_msg->add_to_branch_len, p_msg->add_to_branch_s );
+       return 0;
+
+}
+
index 65526f1..2582d89 100644 (file)
  */
 
 
+#include "config.h"
+#include "h_table.h"
 #include "timer.h"
 #include "../../dprint.h"
 
+void reset_timer_list( struct s_table* hash_table, enum lists list_id)
+{
+       hash_table->timers[ list_id ].first_tl.next_tl = & (hash_table->timers[ list_id ].last_tl );
+       hash_table->timers[ list_id ].last_tl.prev_tl = & (hash_table->timers[ list_id ].first_tl );
+       hash_table->timers[ list_id ].first_tl.prev_tl = 
+               hash_table->timers[ list_id ].last_tl.next_tl = NULL;
+       hash_table->timers[ list_id ].last_tl.time_out = -1;
+}
 
-void print_timer_list(struct s_table* hash_table, int list_id)
+void init_timer_list( struct s_table* hash_table, enum lists list_id)
+{
+       reset_timer_list( hash_table, list_id );
+       init_timerlist_lock( hash_table, list_id );
+}
+
+void print_timer_list(struct s_table* hash_table, enum lists list_id)
 {
    struct timer* timer_list=&(hash_table->timers[ list_id ]);
    struct timer_link *tl ;
 
-   tl = timer_list->first_tl;
-   while (tl)
+   tl = timer_list->first_tl.next_tl;
+   while (tl!=& timer_list->last_tl)
    {
       DBG("DEBUG: print_timer_list[%d]: %p, next=%p \n",list_id, tl, tl->next_tl);
       tl = tl->next_tl;
    }
 }
 
-
-void remove_from_timer_list_dummy( struct s_table* hash_table , struct timer_link* tl , int list_id)
+static void remove_from_timer_list_dummy(  struct timer_link* tl )
 {
-   struct timer* timer_list=&(hash_table->timers[ list_id ]);
-   DBG("DEBUG: remove_from_timer[%d]: %d, %p \n",list_id,tl->time_out,tl);
-
-   if ( tl->prev_tl )
-       tl->prev_tl->next_tl = tl->next_tl;
-    else
-         timer_list->first_tl = tl->next_tl;
-
-   if ( tl->next_tl )
-         tl->next_tl->prev_tl = tl->prev_tl;
-    else
-         timer_list->last_tl = tl->prev_tl;
-
+       DBG("DEBUG: remove_from_timer[%d]: %p \n",tl->list->id,tl);
+       tl->prev_tl->next_tl = tl->next_tl;
+       tl->next_tl->prev_tl = tl->prev_tl;
     tl->next_tl = 0;
     tl->prev_tl = 0;
+       tl->list = NULL;
 }
 
+/* put a new cell into a list nr. list_id within a hash_table;
+  * set initial timeout
+  */
+void add_to_tail_of_timer_list( struct timer *timer_list, 
+       struct timer_link *tl, unsigned int time_out )
+{
+       remove_from_timer_list( tl );
+       /* the entire timer list is locked now -- noone else can manipulate it */
+       lock( timer_list->mutex );
+       tl->time_out = time_out;
+       tl->prev_tl = timer_list->last_tl.prev_tl;
+       tl->next_tl = & timer_list->last_tl;
+       timer_list->last_tl.prev_tl = tl;
+       tl->prev_tl->next_tl = tl;
+       tl->list = timer_list;
+       //print_timer_list(hash_table, list_id);
+       /* give the list lock away */
+       unlock( timer_list->mutex );
+       DBG("DEBUG: add_to_tail_of_timer[%d]: %p\n",timer_list->id,tl);
+}
 
 
 
 
 
-
-
-/* put a new cell into a list nr. list_id within a hash_table;
-  * set initial timeout
-  */
-void add_to_tail_of_timer_list( struct s_table* hash_table , struct timer_link* tl, int list_id , unsigned int time_out )
+/* remove a cell from a list nr. list_id within a hash_table;
+*/
+void remove_from_timer_list( struct timer_link* tl)
 {
-   struct timer* timer_list = &(hash_table->timers[ list_id ]);
+       ser_lock_t      m;
+
+       if (is_in_timer_list2( tl )) {
+               m=tl->list->mutex;
+               /* the entire timer list is locked now -- noone else can manipulate it */
+               lock( m );
+               if ( is_in_timer_list2( tl )  ) remove_from_timer_list_dummy( tl );
+               //print_timer_list(hash_table, list_id);
+               /* give the list lock away */
+               unlock( m );
+       }
+}
 
-   /* the entire timer list is locked now -- noone else can manipulate it */
-   lock( timer_list->mutex );
 
-   /* if the element is already in list->first remove it */
-   if ( is_in_timer_list( tl,list_id)  )
-      remove_from_timer_list_dummy( hash_table , tl , list_id);
 
-   tl->time_out = time_out;
-   tl->next_tl= 0;
 
-   DBG("DEBUG: add_to_tail_of_timer[%d]: %d, %p\n",list_id,tl->time_out,tl);
-   /* link it into list */
-   if (timer_list->last_tl)
-   {
-       tl->prev_tl=timer_list->last_tl;
-       timer_list->last_tl->next_tl = tl;
-       timer_list->last_tl = tl ;
-   } else {
-       tl->prev_tl = 0;
-       timer_list->first_tl = tl;
-       timer_list->last_tl = tl;
-   }
+/*
+       detach items passed by the time from timer list
+*/
+struct timer_link  *check_and_split_time_list( struct timer *timer_list, int time )
+
+{
+       struct timer_link *tl , *tmp , *end, *ret;
+
+       //DBG("DEBUG : check_and_split_time_list: start\n");
+       /* the entire timer list is locked now -- noone else can manipulate it */
+       lock( timer_list->mutex );
+
+       end = &timer_list->last_tl;
+       tl = timer_list->first_tl.next_tl;
+       while( tl!=end && tl->time_out <= time) tl=tl->next_tl;
+
+       /* nothing to delete found */
+       if (tl->prev_tl==&(timer_list->first_tl)) {
+               ret = NULL;
+       } else { /* we did find timers to be fired! */
+               /* the detached list begins with current beginning */
+               ret = timer_list->first_tl.next_tl;
+               /* and we mark the end of the split list */
+               tl->prev_tl->next_tl = NULL;
+               /* the shortened list starts from where we suspended */
+               timer_list->first_tl.next_tl = tl;      
+               tl->prev_tl = & timer_list->first_tl;
+       }
 
-   //print_timer_list(hash_table, list_id);
    /* give the list lock away */
    unlock( timer_list->mutex );
+
+   //DBG("DEBUG : check_and_split_time_list: done, returns %p\n",tl);
+   //print_timer_list(hash_table, list_id);
+   return ret;
 }
 
 
 
 
-/*
+
+void timer_routine(unsigned int ticks , void * attr)
+{
+       struct s_table       *hash_table = (struct s_table *)attr;
+       struct timer*          timers= hash_table->timers;
+       struct timer_link  *tl, *tmp_tl;
+       int                           id;
+
+       DBG("%d\n", ticks);
+
+       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 */
+               while (tl)
+               {
+                       /* reset the timer list linkage */
+                       tmp_tl = tl->next_tl;
+                       tl->next_tl = tl->prev_tl =0 ; 
+                       tl->list = NULL;
+                       DBG("DEBUG: timer routine: timer[%d] , tl=%p next=%p\n",id,tl,tmp_tl);
+                       timers[id].timeout_handler( tl->payload );
+                       tl = tmp_tl;
+               }
+       }
+}
+
+
+
+/* deprecated -- too CPU expensive 
   */
-void insert_into_timer_list( struct s_table* hash_table , struct timer_link* new_tl, int list_id , unsigned int time_out )
+/*
+void insert_into_timer_list( struct s_table* hash_table , 
+       struct timer_link* new_tl, enum lists list_id , unsigned int time_out )
 {
    struct timer          *timer_list = &(hash_table->timers[ list_id ]);
    struct timer_link  *tl;
 
-   /* the entire timer list is locked now -- noone else can manipulate it */
+   // the entire timer list is locked now -- noone else can manipulate it 
    lock( timer_list->mutex );
 
-   /* if the element is already in list->first remove it */
+   // if the element is already in list->first remove it 
    if ( is_in_timer_list( new_tl,list_id)  )
       remove_from_timer_list_dummy( hash_table , new_tl , list_id);
 
    new_tl->time_out = time_out ;
-   DBG("DEBUG: insert_into_timer[%d]: %d, %p\n",list_id,new_tl->time_out,new_tl);
-    /*seeks the position for insertion */
+   DBG("DEBUG: insert_into_timer[%d]:%d, %p\n",list_id,new_tl->time_out,new_tl);
+    // seeks the position for insertion 
    for( tl=timer_list->first_tl ; tl && tl->time_out<new_tl->time_out ; tl=tl->next_tl );
 
-   /* link it into list */
+   // link it into list
     if ( tl )
-    {  /* insert before tl*/
+    {  // insert before tl
        new_tl->prev_tl = tl->prev_tl;
        tl->prev_tl = new_tl;
     }
    else
-    {  /* at the end or empty list */
+    {  // at the end or empty list 
        new_tl->prev_tl = timer_list->last_tl;
        timer_list->last_tl = new_tl;
     }
@@ -120,114 +201,13 @@ void insert_into_timer_list( struct s_table* hash_table , struct timer_link* new
     else
        timer_list->first_tl = new_tl;
     new_tl->next_tl = tl;
+       tl->list_id = list_id;
 
    //print_timer_list(hash_table, list_id);
-   /* give the list lock away */
-    unlock( timer_list->mutex );
-}
-
-
-
+    // give the list lock away 
 
-/* remove a cell from a list nr. list_id within a hash_table;
-*/
-void remove_from_timer_list( struct s_table* hash_table , struct timer_link* tl , int list_id)
-{
-   struct timer* timer_list=&(hash_table->timers[ list_id ]);
-
-   /* the entire timer list is locked now -- noone else can manipulate it */
-   lock( timer_list->mutex );
-
-   /* if the element is already in list->first remove it */
-   if ( is_in_timer_list( tl,list_id)  )
-   {
-      remove_from_timer_list_dummy( hash_table , tl , list_id);
-   }
-
-   //print_timer_list(hash_table, list_id);
-   /* give the list lock away */
-   unlock( timer_list->mutex );
+    unlock( timer_list->mutex );
 }
 
 
-
-
-/*
 */
-struct timer_link  *check_and_split_time_list( struct s_table* hash_table, int list_id ,int time)
-{
-   struct timer* timer_list=&(hash_table->timers[ list_id ]);
-   struct timer_link *tl , *tmp;
-
-   //DBG("DEBUG : check_and_split_time_list: start\n");
-   /* the entire timer list is locked now -- noone else can manipulate it */
-   lock( timer_list->mutex );
-
-   tl = timer_list->first_tl;
-   if ( !tl )
-      goto exit;
-
-   for(  ; tl && tl->time_out <= time ; tl = tl->next_tl );
-
-    /*if I don't have to remove anything*/
-    if ( tl==timer_list->first_tl )
-    {
-      tl =0;
-      goto exit;
-    }
-
-    /*if I have to remove everything*/
-    if (tl==0)
-    {
-      tl = timer_list->first_tl;
-      timer_list->first_tl = timer_list->last_tl = 0;
-      //DBG("DEBUG : check_and_split_time_list: done, EVERY returns %p , list=%p\n",tl,timer_list->first_tl);
-      goto exit;
-    }
-
-    /*I have to split it somewhere in the middle */
-    tl->prev_tl->next_tl=0;
-    tl->prev_tl = 0;
-    tmp = timer_list->first_tl;
-    timer_list->first_tl = tl;
-    tl = tmp;
-   //DBG("DEBUG : check_and_split_time_list: done, SPLIT returns %p , list=%p\n",tl,timer_list->first_tl);
-
-exit:
-   /* give the list lock away */
-   unlock( timer_list->mutex );
-
-   //DBG("DEBUG : check_and_split_time_list: done, returns %p\n",tl);
-   //print_timer_list(hash_table, list_id);
-   return tl;
-}
-
-
-
-
-
-void timer_routine(unsigned int ticks , void * attr)
-{
-   struct s_table       *hash_table = (struct s_table *)attr;
-   struct timer*          timers= hash_table->timers;
-   struct timer_link  *tl, *tmp_tl;
-   int                           id;
-
-   DBG("%d\n", ticks);
-
-   for( id=0 ; id<NR_OF_TIMER_LISTS ; id++ )
-   {
-      tl = check_and_split_time_list( hash_table, id , ticks );
-      while (tl)
-      {
-         tmp_tl = tl->next_tl;
-         tl->next_tl = tl->prev_tl =0 ;
-         DBG("DEBUG: timer routine: timer[%d] , tl=%p next=%p\n",id,tl,tmp_tl);
-         timers[id].timeout_handler( tl->payload );
-         tl = tmp_tl;
-      }
-   }
-}
-
-
-
index d7e6ab7..e0ccfb0 100644 (file)
@@ -2,58 +2,60 @@
  * $Id$
  */
 
-
 #ifndef _TIMER_H
 #define _TIMER_H
 
-enum lists { RETRASMISSIONS_LIST, FR_TIMER_LIST, WT_TIMER_LIST, DELETE_LIST, NR_OF_TIMER_LISTS };
+#include "lock.h"
 
-/* we maintain separate retransmission lists for each of retransmission
-   periods; that allows us to keep the lists ordered while just adding
-   new items to list's tail (FIFO)
+/* identifiers of timer lists; 
 */
-//enum retransmission_lists { RT_T1_TO1, RT_T1_TO_2, RT_T1_TO_3, RT_T2, NR_OF_RT_LISTS };
-
-
-/* FINAL_RESPONSE_TIMER ... tells how long should the transaction engine
-   wait if no final response comes back*/
-#define FR_TIME_OUT            16
-#define INV_FR_TIME_OUT     30
-
-/* WAIT timer ... tells how long state should persist in memory after
-   a transaction was finalized*/
-#define WT_TIME_OUT      5
-
-/* DELETE timer ... tells how long should the transaction persist in memory
-   after it was removed from the hash table and before it will be deleted */
-#define DEL_TIME_OUT      2
-
+enum lists {   FR_TIMER_LIST, FR_INV_TIMER_LIST,
+                               WT_TIMER_LIST, DELETE_LIST, 
+                               /* fixed-timer retransmission lists (benefit: fixed timer
+                                  length allows for appending new items to the list as
+                                       opposed to inserting them which is costly */
+                               RT_T1_TO_1, RT_T1_TO_2, RT_T1_TO_3, RT_T2, 
+                               NR_OF_TIMER_LISTS };
 
-#define RETR_T1  1
-#define RETR_T2  4
+#define is_in_timer_list2(_tl) ( (_tl)->list )
 
 
-#define is_in_timer_list(tl,id)  \
-             (tl->next_tl || tl->prev_tl || (!tl->next_tl && !tl->prev_tl && tl==hash_table->timers[id].first_tl) )
-
+struct timer;
 
 /* all you need to put a cell in a timer list:
    links to neighbours and timer value         */
 typedef struct timer_link
 {
-   struct timer_link *next_tl;
-   struct timer_link *prev_tl;
-   unsigned int        time_out;
-   void                      *payload;
+       struct timer_link       *next_tl;
+       struct timer_link       *prev_tl;
+       unsigned int            time_out;
+       void                            *payload;
+       struct timer            *list;
 }timer_link_type ;
 
-#include "h_table.h"
 
+/* timer list: includes head, tail and protection semaphore */
+typedef struct  timer
+{
+   struct timer_link first_tl;
+   struct timer_link last_tl;
+   ser_lock_t             mutex;
+   enum lists id;
+   void                      (*timeout_handler)(void*);
+} timer_type;
+
+void init_timer_list( struct s_table* hash_table, enum lists list_id);
+void reset_timer_list( struct s_table* hash_table, enum lists list_id);
 
-void                        add_to_tail_of_timer_list( struct s_table* hash_table , struct timer_link * tl , int list_id, unsigned int time_out );
-void                        insert_into_timer_list( struct s_table* hash_table , struct timer_link* tl, int list_id , unsigned int time_out );
-void                        remove_from_timer_list( struct s_table* hash_table , struct timer_link* tl , int list_id);
-void                        timer_routine(unsigned int, void *);
+void add_to_tail_of_timer_list( struct timer *timer_list, 
+       struct timer_link *tl, unsigned int time_out );
+void remove_from_timer_list( struct timer_link *tl);
+void timer_routine(unsigned int, void *);
 
 
+/* deprecated -- too expensive -- use appending instead 
+void insert_into_timer_list( struct s_table* hash_table , 
+       struct timer_link* tl, enum lists list_id , unsigned int time_out );
+*/
+
 #endif
index 735209e..ba40f53 100644 (file)
@@ -5,17 +5,16 @@
  *
  */
 
-
+#include <stdio.h>
+#include <string.h>
+#include <netdb.h>
 
 #include "../../sr_module.h"
 #include "../../dprint.h"
 #include "../../error.h"
 #include "../../ut.h"
-#include "sip_msg.h"
-#include <stdio.h>
-#include <string.h>
-#include <netdb.h>
 
+#include "sip_msg.h"
 #include "h_table.h"
 #include "t_funcs.h"
 
@@ -40,7 +39,8 @@ static struct module_exports nm_exports= {
                                "t_forward_uri",
                                "t_send_reply",
                                "t_retransmit_reply",
-                               "t_release"
+                               "t_release",
+                               "t_unref"
                        },
        (cmd_function[]){
                                        t_add_transaction,
@@ -50,7 +50,8 @@ static struct module_exports nm_exports= {
                                        t_forward_uri,
                                        w_t_send_reply,
                                        t_retransmit_reply,
-                                       w_t_release
+                                       w_t_release,
+                                       t_unref
                                        },
        (int[]){
                                0,
@@ -60,6 +61,7 @@ static struct module_exports nm_exports= {
                                0,
                                2,
                                0,
+                               0,
                                0
                        },
        (fixup_function[]){
@@ -70,9 +72,10 @@ static struct module_exports nm_exports= {
                                0,
                                fixup_t_send_reply,
                                0,
-                               0
+                               0,
+                               0,
                },
-       8,
+       9,
        (response_function) t_on_reply_received,
        (destroy_function) tm_shutdown
 };
index 59e4fd7..6d0bf43 100644 (file)
 #include "ut.h"
 #include "error.h"
 #include "dprint.h"
-#include "mem.h"
+#include "mem/mem.h"
 
 #ifdef DEBUG_DMALLOC
-#include <dmalloc.h>
+#include <mem/dmalloc.h>
 #endif
 
 
@@ -54,7 +54,7 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl)
           token 
         */
        if (len <=16 ) {
-               LOG(L_INFO, "ERROR: parse_first_line: message too short\n");
+               LOG(L_INFO, "ERROR: parse_first_line: message too short: %d\n", len);
                goto error1;
        }
 
@@ -131,8 +131,7 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl)
                if (s1>='0' && s1<='9' && 
                    s2>='0' && s2<='9' &&
                    s3>='0' && s3<='9' ) {
-                       fl->u.reply.statusclass=s1-'0';
-                       fl->u.reply.statuscode=fl->u.reply.statusclass*100+10*(s2-'0')+(s3-'0');
+                       fl->u.reply.statuscode=(s1-'0')*100+10*(s2-'0')+(s3-'0');
                } else {
                        LOG(L_INFO, "ERROR:parse_first_line: status_code non-numerical: %s\n",
                                second );
@@ -278,6 +277,8 @@ char* get_hdr_field(char* buf, char* end, struct hdr_field* hdr)
                        goto error;
        }
 
+       /* jku: if \r covered by current length, shrink it */
+       trim_r( hdr->body );
        return tmp;
 error:
        DBG("get_hdr_field: error exit\n");
@@ -806,7 +807,10 @@ void free_sip_msg(struct sip_msg* msg)
        if (msg->add_rm)      free_lump_list(msg->add_rm);
        if (msg->repl_add_rm) free_lump_list(msg->repl_add_rm);
        pkg_free(msg->orig);
-       pkg_free(msg->buf);
+       /* don't free anymore -- now a pointer to a static buffer */
+#      ifdef DYN_BUF
+       pkg_free(msg->buf); */
+#      endif
 }
 
 
index 6949dbd..4db7f3e 100644 (file)
@@ -84,7 +84,7 @@ struct msg_start{
                        str version;
                        str status;
                        str reason;
-                       unsigned short statusclass, statuscode;
+                       unsigned short /* statusclass,*/ statuscode;
                }reply;
        }u;
 };
index 207e59c..5a25eef 100644 (file)
@@ -6,7 +6,7 @@
 #include <sys/socket.h>
 
 #include "msg_translator.h"
-#include "mem.h"
+#include "mem/mem.h"
 #include "dprint.h"
 #include "config.h"
 #include "md5utils.h"
@@ -556,7 +556,7 @@ char * build_res_buf_from_sip_req(  unsigned int code ,
                if ( hdr->type==HDR_VIA || hdr->type==HDR_FROM ||
                                hdr->type==HDR_CALLID || hdr->type==HDR_TO ||
                                hdr->type==HDR_CSEQ )
-                       len += ((hdr->body.s+hdr->body.len ) - hdr->name.s ) ;
+                       len += ((hdr->body.s+hdr->body.len ) - hdr->name.s ) + CRLF_LEN;
        /* end of message */
        len += CRLF_LEN; /*new line*/
 
@@ -592,7 +592,9 @@ char * build_res_buf_from_sip_req(  unsigned int code ,
                        memcpy( p , msg->orig+(hdr->name.s-msg->buf) ,
                                        ((hdr->body.s+hdr->body.len ) -
                                        hdr->name.s ) );
-                       p += ((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;
                }
 
        memcpy( p, CRLF, CRLF_LEN );
index 2d10a1c..402946a 100644 (file)
@@ -1123,7 +1123,7 @@ char* parse_fline(char* buffer, char* end, struct msg_start* fl)
 skip:
        if (fl->type==SIP_REPLY){
                fl->u.reply.statuscode=stat;
-               fl->u.reply.statusclass=stat/100;
+               /* fl->u.reply.statusclass=stat/100; */
        }
        return tmp;
        
index cfdb015..3008b93 100644 (file)
@@ -21,7 +21,7 @@
 #include "dprint.h"
 #include "msg_parser.h"
 #include "ut.h"
-#include "mem.h"
+#include "mem/mem.h"
 
 
 
index 2c7e7e1..593f0aa 100644 (file)
--- a/receive.c
+++ b/receive.c
 #include "msg_parser.h"
 #include "forward.h"
 #include "action.h"
-#include "mem.h"
+#include "mem/mem.h"
+#include "stats.h"
 
 
 #ifdef DEBUG_DMALLOC
-#include <dmalloc.h>
-#endif
-
-#ifdef STATS
-#include "stats.h"
+#include <mem/dmalloc.h>
 #endif
 
 unsigned int msg_no=0;
@@ -78,10 +75,7 @@ int receive_msg(char* buf, unsigned int len, unsigned long src_ip)
                        goto error;
                }
                DBG("succesfully ran routing scripts...\n");
-#ifdef STATS
-               /* jku -- update request statistics  */
-               else update_received_request(msg->first_line.u.request.method_value );
-#endif
+               STATS_RX_REQUEST( msg->first_line.u.request.method_value );
        }else if (msg->first_line.type==SIP_REPLY){
                DBG("msg= reply\n");
                /* sanity checks */
@@ -97,10 +91,7 @@ int receive_msg(char* buf, unsigned int len, unsigned long src_ip)
                }
                /* check if via1 == us */
 
-#ifdef STATS
-               /* jku -- update statistics  */
-               update_received_response( msg->first_line.u.reply.statusclass );
-#endif
+               STATS_RX_RESPONSE ( msg->first_line.u.reply.statusclass );
                
                /* send the msg */
                if (forward_reply(msg)==0){
@@ -120,23 +111,19 @@ skip:
        free_sip_msg(msg);
        pkg_free(msg);
 #ifdef STATS
-       if (skipped) update_received_drops;
+       if (skipped) STATS_RX_DROPS;
 #endif
        return 0;
 error:
        DBG("error:...\n");
        free_sip_msg(msg);
        pkg_free(msg);
-#ifdef STATS
-       update_received_drops;
-#endif
+       STATS_RX_DROPS;
        return -1;
 error1:
        if (msg) pkg_free(msg);
        pkg_free(buf);
-#ifdef STATS
-       update_received_drops;
-#endif
+       STATS_RX_DROPS;
        return -1;
 }
 
diff --git a/stats.h b/stats.h
index 153fe9b..111619c 100644 (file)
--- a/stats.h
+++ b/stats.h
 #include <errno.h>
 
 
+#define _update_request( method, dir )                 \
+       { if (stat_file!=NULL) switch( method ) {       \
+               case METHOD_INVITE: stats->dir##_requests_inv++; break; \
+               case METHOD_ACK: stats->dir##_requests_ack++; break;            \
+               case METHOD_CANCEL: stats->dir##_requests_cnc++; break; \
+               case METHOD_BYE: stats->dir##_requests_bye++; break;            \
+               case METHOD_OTHER: stats->dir##_requests_other++; break;        \
+               default: LOG(L_ERR, "ERROR: unknown method in rq stats (%s)\n", #dir);  \
+               }       \
+        }
+
+
+/*
+#define update_received_request( method ) _update_request( method, received )
+#define update_sent_request( method ) _update_request( method, sent )
+
+#define update_received_response( statusclass ) _update_response( statusclass, received )
+#define update_sent_response( statusclass ) _update_response( statusclass, sent )
+#define update_received_drops  {  stats->received_drops++; }
+#define update_fail_on_send    {  stats->failed_on_send++; }
+*/
+
+#define         _statusline(class, dir )       case class: stats->dir##_responses_##class++; break;
+
+#define _update_response( statusclass, dir )           \
+        { if (stat_file!=NULL)                          \
+                switch( statusclass ) {                 \
+                        _statusline(1, dir)                   \
+                        _statusline(2, dir)                   \
+                        _statusline(3, dir)                   \
+                        _statusline(4, dir)                   \
+                        _statusline(5, dir)                   \
+                        _statusline(6, dir)                   \
+                        default: LOG(L_INFO, "ERROR: unusual status code received in stats (%s)\n", #dir);    \
+                }       \
+        }
+
+#ifdef STATS
+#      define STATS_RX_REQUEST(method) _update_request(method, received)
+#      define STATS_TX_REQUEST(method) _update_request(method, sent )
+#      define STATS_RX_RESPONSE(class) _update_response( class, received )
+#      define STATS_TX_RESPONSE(class) _update_response( class, sent )
+#      define STATS_RX_DROPS {  stats->received_drops++; }
+#      define STATS_TX_DROPS {  stats->failed_on_send++; }
+#else
+#      define STATS_RX_REQUEST(method)
+#      define STATS_TX_REQUEST(method)
+#      define STATS_RX_RESPONSE(class) 
+#      define STATS_TX_RESPONSE(class) 
+#      define STATS_RX_DROPS 
+#      define STATS_TX_DROPS 
+#endif
 
 #ifdef STATS
 
@@ -76,44 +128,6 @@ void dump_statistic( FILE *fp, struct stats_s *istats );
 int dump_all_statistic();
 int init_stats( int nr_of_processes );
 
-#define _update_request( method, dir )                 \
-       { if (stat_file!=NULL) switch( method ) {       \
-               case METHOD_INVITE: stats->dir##_requests_inv++; break; \
-               case METHOD_ACK: stats->dir##_requests_ack++; break;            \
-               case METHOD_CANCEL: stats->dir##_requests_cnc++; break; \
-               case METHOD_BYE: stats->dir##_requests_bye++; break;            \
-               case METHOD_OTHER: stats->dir##_requests_other++; break;        \
-               default: LOG(L_ERR, "ERROR: unknown method in rq stats (%s)\n", #dir);  \
-               }       \
-        }
-
-#define update_received_request( method ) _update_request( method, received )
-#define update_sent_request( method ) _update_request( method, sent )
-
-#define         _statusline(class, dir )       case class: stats->dir##_responses_##class++; break;
-/*
-#define                statusline( class )     _statusline( class, received )
-#define                statusline2( class )    _statusline( class, sent )
-*/
-
-#define _update_response( statusclass, dir )           \
-        { if (stat_file!=NULL)                          \
-                switch( statusclass ) {                 \
-                        _statusline(1, dir)                   \
-                        _statusline(2, dir)                   \
-                        _statusline(3, dir)                   \
-                        _statusline(4, dir)                   \
-                        _statusline(5, dir)                   \
-                        _statusline(6, dir)                   \
-                        default: LOG(L_INFO, "ERROR: unusual status code received in stats (%s)\n", #dir);    \
-                }       \
-        }
-
-#define update_received_response( statusclass ) _update_response( statusclass, received )
-#define update_sent_response( statusclass ) _update_response( statusclass, sent )
-
-#define update_received_drops  {  stats->received_drops++; }
-#define update_fail_on_send    {  stats->failed_on_send++; }
 
 
 #endif
index c2c7f31..ee6098b 100644 (file)
@@ -1,4 +1,4 @@
-debug=2          # debug level (cmd line: -dddddddddd)
+debug=9          # debug level (cmd line: -dddddddddd)
 log_stderror=yes # (cmd line: -E)
 check_via=yes     # (cmd. line: -v)
 dns=on           # (cmd. line: -r)
@@ -11,7 +11,7 @@ loop_checks=1
 
 #modules
 loadmodule "modules/print/print.so"
-loadmodule "modules/tm/tm.so"
+#loadmodule "modules/tm/tm.so"
 
 route{
        if ( t_lookup_request()) {
similarity index 58%
rename from t_debug.cfg
rename to test/tx.cfg
index 94c378e..034fa2e 100644 (file)
@@ -1,24 +1,32 @@
-debug=9          # debug level (cmd line: -dddddddddd)
+#
+# configuration for TurboSIP testing
+#
+# $ID: $
+#
+
+debug=1          # debug level (cmd line: -dddddddddd)
 check_via=yes     # (cmd. line: -v)
 dns=on           # (cmd. line: -r)
 rev_dns=yes      # (cmd. line: -R)
-fork=no          # (cmd. line: -D)
-children=10
-log_stderror=yes # (cmd line: -E)
-#port=5080
+fork=yes          # (cmd. line: -D)
+children=16
+#log_stderror=yes # (cmd line: -E)
+log_stderror=no        # (cmd line: -E)
+port=5080
 #listen=127.0.0.1
+listen=192.168.99.100
 loop_checks=1
 # for more info: sip_router -h
 
 #modules
 loadmodule "modules/print/print.so"
-loadmodule "modules/tm/tm.so"
+#loadmodule "modules/tm/tm.so"
 
 route{
        if ( t_lookup_request()) {
                if ( method=="ACK" )    {
                        log("SER: ACK received -> t_release\n");
-                       if (! t_forward("iptel.org", "5060" )) {
+                       if (! t_forward("bat.iptel.org", "5090" )) {
                                log("SER: WARNING: bad forward\n");
                        };
                        if (! t_release()) {
@@ -30,15 +38,17 @@ route{
                        };
                        log("SER: yet another annoying retranmission\n");
                };
+               t_unref();
        } else {
-               if (! t_add_transaction()){
-                       log("ERROR in ser: t_add_transaction\n");
-                       if (method=="BYE") {
-                               forward("iptel.org", 5060);
-                       }else{
-                               forward("iptel.org", 5060 );
-                       };
+               if (method=="ACK") {
+                       # no established transaction ... forward ACK just statelessly
+                       forward("bat.iptel.org", 5090);
                } else {
+                       # establish transaction
+                       if (! t_add_transaction()){
+                               log("ERROR in ser: t_add_transaction\n");
+                       };
+                       # reply
                        if (method=="CANCEL") {
                                log("SER: new CANCEL\n");
                                if (! t_send_reply( "200", "glad to cancel")){
@@ -51,17 +61,10 @@ route{
                                        log("SER: ERROR: t_send_reply (100)\n");
                                };
                        };
-                       if (method=="BYE") {
-                               log("SER: BYE received, HACK: forwarding to client\n");
-                               if (! t_forward("iptel.org", "5060")){
-                                       log("SER:ERROR: t_forward (..., 5555)\n");
-                               };
-                       }else{
-                               if (! t_forward("iptel.org", "5060" )){
-                                       log("SER:ERROR: t_forward (..., 6666)\n");
-                               };
+                       if (! t_forward("bat.iptel.org", "5090")){
+                               log("SER:ERROR: t_forward (..., 5555)\n");
                        };
+                       t_unref();
                };
        };
-
 }
diff --git a/test/xx.cfg b/test/xx.cfg
new file mode 100644 (file)
index 0000000..c048bc0
--- /dev/null
@@ -0,0 +1,53 @@
+# forwarding to Cisco phone
+#
+# $Id$
+#
+
+
+debug=9          # debug level (cmd line: -dddddddddd)
+log_stderror=yes # (cmd line: -E)
+check_via=yes     # (cmd. line: -v)
+dns=on           # (cmd. line: -r)
+rev_dns=yes      # (cmd. line: -R)
+fork=no          # (cmd. line: -D)
+port=5080
+#listen=127.0.0.1
+listen=192.168.99.100
+loop_checks=1
+# for more info: sip_router -h
+
+#modules
+loadmodule "modules/print/print.so"
+#loadmodule "modules/tm/tm.so"
+
+route{
+       if ( t_lookup_request()) {
+               if ( method=="ACK" )    {
+                       t_release();
+#                      forward(195.37.77.100, 5090 );
+#                      forward(195.37.78.146, 5060 );
+# once it supports ACK too
+#                      t_forward(195.37.77.100, 5090 );
+                       t_forward("195.37.78.146", "5060" );
+               } else {
+                       t_retransmit_reply();
+               };
+               t_unref();
+       } else {
+               if (method=="ACK") {
+#                      forward(195.37.77.100, 5090 );
+                       forward(195.37.78.146, 5060 );
+               } else {
+                       t_add_transaction();
+                       if (method=="CANCEL") {
+                               t_send_reply( "200", "glad to cancel");
+                       } else {
+                               t_send_reply("100", "trying -- your call is important to us");
+                       };
+#                      t_forward("195.37.77.100", "5090" );
+                       t_forward("195.37.78.146", "5060" );
+                       t_unref();
+               };
+       };
+               
+}
diff --git a/test/xy.cfg b/test/xy.cfg
new file mode 100644 (file)
index 0000000..b6899ae
--- /dev/null
@@ -0,0 +1,51 @@
+# forwarding to a fixed non-responding destination
+#
+# $Id$
+#
+
+debug=9          # debug level (cmd line: -dddddddddd)
+log_stderror=yes # (cmd line: -E)
+check_via=yes     # (cmd. line: -v)
+dns=on           # (cmd. line: -r)
+rev_dns=yes      # (cmd. line: -R)
+fork=no          # (cmd. line: -D)
+port=5080
+#listen=127.0.0.1
+listen=192.168.99.100
+loop_checks=1
+# for more info: sip_router -h
+
+#modules
+loadmodule "modules/print/print.so"
+#loadmodule "modules/tm/tm.so"
+
+route{
+       if ( t_lookup_request()) {
+               if ( method=="ACK" )    {
+                       t_release();
+#                      forward(195.37.77.100, 5090 );
+                       forward(195.37.78.146, 5030 );
+# once it supports ACK too
+#                      t_forward(195.37.77.100, 5090 );
+               } else {
+                       t_retransmit_reply();
+               };
+               t_unref();
+       } else {
+               if (method=="ACK") {
+#                      forward(195.37.77.100, 5090 );
+                       forward(195.37.78.146, 5030 );
+               } else {
+                       t_add_transaction();
+                       if (method=="CANCEL") {
+                               t_send_reply( "200", "glad to cancel");
+                       } else {
+                               t_send_reply("100", "trying -- your call is important to us");
+                       };
+#                      t_forward("195.37.77.100", "5090" );
+                       t_forward("195.37.78.146", "5030" );
+                       t_unref();
+               };
+       };
+               
+}
diff --git a/timer.c b/timer.c
index dc865df..20d2ddb 100644 (file)
--- a/timer.c
+++ b/timer.c
@@ -6,8 +6,9 @@
 #include "dprint.h"
 #include "error.h"
 #include "config.h"
+#include "mem/mem.h"
 #ifdef SHM_MEM
-#include "shm_mem.h"
+#include "mem/shm_mem.h"
 #endif
 
 #include <stdlib.h>
index 68d9443..7ded288 100644 (file)
 #include "config.h"
 #include "dprint.h"
 #include "receive.h"
-#include "mem.h"
+#include "mem/mem.h"
 
 #ifdef DEBUG_DMALLOC
-#include <dmalloc.h>
+#include <mem/dmalloc.h>
 #endif
 
 int udp_sock;
@@ -151,10 +151,16 @@ error:
 int udp_rcv_loop()
 {
        unsigned len;
+#ifdef DYN_BUF
        char* buf;
+#else
+       char buf [BUF_SIZE+1];
+#endif
+
        struct sockaddr* from;
        int fromlen;
 
+
        from=(struct sockaddr*) malloc(sizeof(struct sockaddr));
        if (from==0){
                LOG(L_ERR, "ERROR: udp_rcv_loop: out of memory\n");
@@ -162,12 +168,14 @@ int udp_rcv_loop()
        }
 
        for(;;){
+#ifdef DYN_BUF
                buf=pkg_malloc(BUF_SIZE+1);
                if (buf==0){
                        LOG(L_ERR, "ERROR: udp_rcv_loop: could not allocate receive"
                                         " buffer\n");
                        goto error;
                }
+#endif
                fromlen=sizeof(struct sockaddr);
                len=recvfrom(udp_sock, buf, BUF_SIZE, 0, from, &fromlen);
                if (len==-1){
@@ -203,7 +211,6 @@ int udp_send(char *buf, unsigned len, struct sockaddr*  to, unsigned tolen)
        int n;
 
 /*     struct sockaddr_in a2;*/
-/*
 #ifndef NO_DEBUG
 #define MAX_IP_LENGTH 18
        char ip_txt[MAX_IP_LENGTH];
@@ -227,8 +234,9 @@ int udp_send(char *buf, unsigned len, struct sockaddr*  to, unsigned tolen)
 
        DBG(" destination: IP=%s, port=%u; packet:\n", ip_txt, p);
        DBG(" destination (hex): IP=%x, port=%x;\n", a->sin_addr.s_addr, a->sin_port );
-       DBG("%*s\n", len, buf );
-#endif*/
+       DBG(" packet: {%*s...}\n", 24, buf );
+       /* DBG("%*s\n", len, buf ); */
+#endif
 /*
        memset(&a2, 0, sizeof(struct sockaddr_in));
        a2.sin_family = a->sin_family;
diff --git a/ut.h b/ut.h
index df2707f..233ce24 100644 (file)
--- a/ut.h
+++ b/ut.h
@@ -9,6 +9,25 @@
 
 #include "dprint.h"
 
+/* returns string beginning and length without insignificant chars */
+#define trim_len( _len, _begin, _mystr ) \
+       ({      static char _c; \
+               (_len)=(_mystr).len; \
+               while ((_len) && ((_c=(_mystr).s[(_len)-1])==0 || _c=='\r' || _c=='\n' || _c==' ' || _c=='\t' )) \
+                       (_len)--; \
+               (_begin)=(_mystr).s; \
+               while ((_len) && ((_c=*(_begin))==' ' || _c=='\t')) { \
+                       (_len)--;\
+                       (_begin)++; \
+               } \
+       })
+
+#define trim_r( _mystr ) \
+       ({      static _c; \
+               while( ((_mystr).len) && ((_c=(_mystr).s[(_mystr).len-1]))==0 || _c=='\r' || _c=='\n') \
+                       (_mystr).len--; \
+       })
+
 /* converts a str to an u. short, returns the u. short and sets *err on 
  * error and if err!=null
  * */