2
0
Эх сурвалжийг харах

performance and bug fixes

Jiri Kuthan 24 жил өмнө
parent
commit
dda9dab1f8
52 өөрчлөгдсөн 2495 нэмэгдсэн , 1261 устгасан
  1. 1 1
      Makefile
  2. 11 3
      Makefile.defs
  3. 1 1
      Makefile.sources
  4. 1 1
      action.c
  5. 20 4
      config.h
  6. 4 1
      crc.c
  7. 11 0
      crc.h
  8. 1 1
      data_lump.c
  9. 6 21
      forward.c
  10. 17 24
      main.c
  11. 32 7
      md5utils.c
  12. 0 56
      mem.h
  13. 51 0
      mem/mem.c
  14. 68 0
      mem/mem.h
  15. 133 0
      mem/memtest.c
  16. 22 13
      mem/q_malloc.c
  17. 1 1
      mem/q_malloc.h
  18. 13 3
      mem/shm_mem.c
  19. 20 9
      mem/shm_mem.h
  20. 438 0
      mem/vq_malloc.c
  21. 130 0
      mem/vq_malloc.h
  22. 2 15
      modules/tm/TODO
  23. 36 0
      modules/tm/config.h
  24. 0 12
      modules/tm/globals.h
  25. 36 50
      modules/tm/h_table.c
  26. 23 30
      modules/tm/h_table.h
  27. 88 1
      modules/tm/hash_func.c
  28. 4 2
      modules/tm/hash_func.h
  29. 9 2
      modules/tm/lock.c
  30. 2 2
      modules/tm/lock.h
  31. 2 2
      modules/tm/sh_malloc.h
  32. 1 18
      modules/tm/sip_msg.c
  33. 458 670
      modules/tm/t_funcs.c
  34. 41 6
      modules/tm/t_funcs.h
  35. 380 0
      modules/tm/t_lookup.c
  36. 138 158
      modules/tm/timer.c
  37. 37 35
      modules/tm/timer.h
  38. 12 9
      modules/tm/tm.c
  39. 10 6
      msg_parser.c
  40. 1 1
      msg_parser.h
  41. 5 3
      msg_translator.c
  42. 1 1
      parse_fline.c
  43. 1 1
      parse_via.c
  44. 8 21
      receive.c
  45. 52 38
      stats.h
  46. 2 2
      test/tp.cfg
  47. 27 24
      test/tx.cfg
  48. 53 0
      test/xx.cfg
  49. 51 0
      test/xy.cfg
  50. 2 1
      timer.c
  51. 13 5
      udp_server.c
  52. 19 0
      ut.h

+ 1 - 1
Makefile

@@ -11,7 +11,7 @@ auto_gen=lex.yy.c cfg.tab.c   #lexx, yacc etc
 include Makefile.sources
 include Makefile.sources
 
 
 exclude_modules=CVS usrloc mysql auth
 exclude_modules=CVS usrloc mysql auth
-static_modules=
+static_modules=tm
 static_modules_path=$(addprefix modules/, $(static_modules))
 static_modules_path=$(addprefix modules/, $(static_modules))
 extra_sources=$(wildcard $(addsuffix /*.c, $(static_modules_path)))
 extra_sources=$(wildcard $(addsuffix /*.c, $(static_modules_path)))
 extra_objs=$(extra_sources:.c=.o)
 extra_objs=$(extra_sources:.c=.o)

+ 11 - 3
Makefile.defs

@@ -44,8 +44,16 @@ ARCH = $(shell uname -s)
 #		extra error checking (trying to free the same pointer
 #		extra error checking (trying to free the same pointer
 #		twice, trying to free a pointer alloc'ed with a different
 #		twice, trying to free a pointer alloc'ed with a different
 #		malloc etc.)
 #		malloc etc.)
+# -DVQ_MALLOC
+#		additional option to PKG_MALLOC which utilizes a fater then
+#		qm version
+#
+
 DEFS+= -DNAME='"$(NAME)"' -DVERSION='"$(RELEASE)"' -DARCH='"$(ARCH)"' \
 DEFS+= -DNAME='"$(NAME)"' -DVERSION='"$(RELEASE)"' -DARCH='"$(ARCH)"' \
 	 -DDNS_IP_HACK  -DPKG_MALLOC -DSHM_MEM  -DSHM_MMAP \
 	 -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
 	  #-DNO_DEBUG #-DDBG_QM_MALLOC
 #-DEXTRA_DEBUG
 #-DEXTRA_DEBUG
 # -DUSE_SHM_MEM
 # -DUSE_SHM_MEM
@@ -54,9 +62,9 @@ DEFS+= -DNAME='"$(NAME)"' -DVERSION='"$(RELEASE)"' -DARCH='"$(ARCH)"' \
 #-DNO_DEBUG#-DSTATS -DNO_DEBUG 
 #-DNO_DEBUG#-DSTATS -DNO_DEBUG 
 #-DNO_LOG
 #-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
 # platform dependent settings
 
 

+ 1 - 1
Makefile.sources

@@ -11,7 +11,7 @@
 # defines: sources, objs, depends
 # 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)
 objs=$(sources:.c=.o)
 extra_objs=
 extra_objs=
 depends=$(sources:.c=.d)
 depends=$(sources:.c=.d)

+ 1 - 1
action.c

@@ -15,7 +15,7 @@
 #include "msg_parser.h"
 #include "msg_parser.h"
 #include "ut.h"
 #include "ut.h"
 #include "sr_module.h"
 #include "sr_module.h"
-#include "mem.h"
+#include "mem/mem.h"
 
 
 #include <sys/types.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/socket.h>

+ 20 - 4
config.h

@@ -1,5 +1,5 @@
 /*
 /*
- *  $Id
+ *  $Id $
  */
  */
 
 
 
 
@@ -12,8 +12,6 @@
 
 
 #define CFG_FILE "./ser.cfg"
 #define CFG_FILE "./ser.cfg"
 
 
-/* receive buffer size */
-#define BUF_SIZE 65507
 
 
 /* maximum number of addresses on which we will listen */
 /* maximum number of addresses on which we will listen */
 #define MAX_LISTEN 16
 #define MAX_LISTEN 16
@@ -47,11 +45,29 @@
 /*used only if PKG_MALLOC is defined*/
 /*used only if PKG_MALLOC is defined*/
 #define PKG_MEM_POOL_SIZE 1024*1024
 #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 SHM_MEM_SIZE 128*1024*1024
 
 
 #define TIMER_TICK 1
 #define TIMER_TICK 1
 #define LONG_SLEEP	3600
 #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
 #endif

+ 4 - 1
crc.c

@@ -1,8 +1,11 @@
 /*
 /*
+ * $Id$
+ *
  *  Crc - 32 + 16 BIT ANSI X3.66 + CCITT CRC checksum files
  *  Crc - 32 + 16 BIT ANSI X3.66 + CCITT CRC checksum files
  */
  */
 
 
 #include <stdio.h>
 #include <stdio.h>
+#include "crc.h"
 
 
 #define OK 0
 #define OK 0
 #define ERROR (-1)
 #define ERROR (-1)
@@ -60,7 +63,7 @@
 /*     hardware you could probably optimize the shift in assembler by  */
 /*     hardware you could probably optimize the shift in assembler by  */
 /*     using byte-swap instructions.                                   */
 /*     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,
 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,

+ 11 - 0
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
+

+ 1 - 1
data_lump.c

@@ -4,7 +4,7 @@
 
 
 #include "data_lump.h"
 #include "data_lump.h"
 #include "dprint.h"
 #include "dprint.h"
-#include "mem.h"
+#include "mem/mem.h"
 
 
 #include <stdlib.h>
 #include <stdlib.h>
 
 

+ 6 - 21
forward.c

@@ -21,21 +21,15 @@
 #include "globals.h"
 #include "globals.h"
 #include "data_lump.h"
 #include "data_lump.h"
 #include "ut.h"
 #include "ut.h"
-#include "mem.h"
+#include "mem/mem.h"
 #include "msg_translator.h"
 #include "msg_translator.h"
 #include "sr_module.h"
 #include "sr_module.h"
+#include "stats.h"
 
 
 #ifdef DEBUG_DMALLOC
 #ifdef DEBUG_DMALLOC
 #include <dmalloc.h>
 #include <dmalloc.h>
 #endif
 #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)
 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){
 				sizeof(struct sockaddr_in))==-1){
 			p->errors++;
 			p->errors++;
 			p->ok=0;
 			p->ok=0;
-#ifdef STATS
-			update_fail_on_send;
-#endif
+			STATS_TX_DROPS;
 			goto error;
 			goto error;
 	}
 	}
-#ifdef STATS
 	/* sent requests 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(buf);
 	free(to);
 	free(to);
 	/* received_buf & line_buf will be freed in receiv_msg by free_lump_list*/
 	/* 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,
 	if (udp_send(new_buf,new_len, (struct sockaddr*) to,
 					sizeof(struct sockaddr_in))==-1)
 					sizeof(struct sockaddr_in))==-1)
 	{
 	{
-#ifdef STATS
-		update_fail_on_send;
-#endif
+		STATS_TX_DROPS;
 		goto error;
 		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(new_buf);
 	free(to);
 	free(to);
 skip:
 skip:

+ 17 - 24
main.c

@@ -23,9 +23,9 @@
 #include "route.h"
 #include "route.h"
 #include "udp_server.h"
 #include "udp_server.h"
 #include "globals.h"
 #include "globals.h"
-#include "mem.h"
+#include "mem/mem.h"
 #ifdef SHM_MEM
 #ifdef SHM_MEM
-#include "shm_mem.h"
+#include "mem/shm_mem.h"
 #endif
 #endif
 #include "sr_module.h"
 #include "sr_module.h"
 #include "timer.h"
 #include "timer.h"
@@ -33,9 +33,7 @@
 
 
 #include <signal.h>
 #include <signal.h>
 
 
-#ifdef STATS
 #include "stats.h"
 #include "stats.h"
-#endif
 
 
 #ifdef DEBUG_DMALLOC
 #ifdef DEBUG_DMALLOC
 #include <dmalloc.h>
 #include <dmalloc.h>
@@ -72,6 +70,9 @@ static char flags[]=
 #ifdef PKG_MALLOC
 #ifdef PKG_MALLOC
 ", PKG_MALLOC"
 ", PKG_MALLOC"
 #endif
 #endif
+#ifdef VQ_MALLOC
+", VQ_MALLOC"
+#endif
 #ifdef USE_SHM_MEM
 #ifdef USE_SHM_MEM
 ", USE_SHM_MEM"
 ", USE_SHM_MEM"
 #endif
 #endif
@@ -171,12 +172,6 @@ int process_no = 0;
 /* cfg parsing */
 /* cfg parsing */
 int cfg_errors=0;
 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,
 #define MAX_FD 32 /* maximum number of inherited open file descriptors,
 		    (normally it shouldn't  be bigger  than 3) */
 		    (normally it shouldn't  be bigger  than 3) */
 
 
@@ -332,7 +327,7 @@ int main_loop()
 static void sig_usr(int signo)
 static void sig_usr(int signo)
 {
 {
 	DPrint("INT received, program terminates\n");
 	DPrint("INT received, program terminates\n");
-	if (signo==SIGINT) {	/* exit gracefuly */
+	if (signo==SIGINT || signo==SIGPIPE) {	/* exit gracefuly */
 #ifdef STATS
 #ifdef STATS
 		/* print statistics on exit only for the first process */
 		/* 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)
 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");
 		DPrint("ERROR: no SIGINT signal handler can be installed\n");
 		goto error;
 		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 ) {
 	if (signal(SIGUSR1, sig_usr)  == SIG_ERR ) {
 		DPrint("ERROR: no SIGUSR1 signal handler can be installed\n");
 		DPrint("ERROR: no SIGUSR1 signal handler can be installed\n");
 		goto error;
 		goto error;
 	}
 	}
 
 
+	//memtest();
+	//hashtest();
+
 
 
 	/* process command line (get port no, cfg. file path etc) */
 	/* process command line (get port no, cfg. file path etc) */
 	opterr=0;
 	opterr=0;
@@ -522,21 +526,9 @@ int main(int argc, char** argv)
 	}
 	}
 
 
 	/*init mallocs (before parsing cfg !)*/
 	/*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;
 		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!*/
 	/*init timer, before parsing the cfg!*/
 	if (init_timer()<0){
 	if (init_timer()<0){
 		LOG(L_CRIT, "could not initialize timer, exiting...\n");
 		LOG(L_CRIT, "could not initialize timer, exiting...\n");
@@ -641,3 +633,4 @@ error:
 	return -1;
 	return -1;
 
 
 }
 }
+

+ 32 - 7
md5utils.c

@@ -28,8 +28,8 @@ jku: added support to deal with vectors
 #include "md5global.h"
 #include "md5global.h"
 #include "md5.h"
 #include "md5.h"
 #include "md5utils.h"
 #include "md5utils.h"
-
 #include "dprint.h"
 #include "dprint.h"
+#include "ut.h"
 
 
 
 
 static void MDString PROTO_LIST ((char *));
 static void MDString PROTO_LIST ((char *));
@@ -45,13 +45,38 @@ static void MDString PROTO_LIST ((char *));
  */
  */
 void MDStringArray (char *dst, str src[], int size)
 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);
   MDFinal (digest, &context);
 
 

+ 0 - 56
mem.h

@@ -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

+ 51 - 0
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;
+
+}
+
+

+ 68 - 0
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

+ 133 - 0
mem/memtest.c

@@ -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

+ 22 - 13
q_malloc.c → mem/q_malloc.c

@@ -2,29 +2,29 @@
  *
  *
  */
  */
 
 
+#if !defined(q_malloc) && !(defined VQ_MALLOC)
 #define q_malloc
 #define q_malloc
-#ifdef q_malloc
 
 
 #include "q_malloc.h"
 #include "q_malloc.h"
-#include "dprint.h"
+#include "../dprint.h"
 
 
 
 
-/*usefull macros*/
+/*useful macros*/
 #define FRAG_END(f)  \
 #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) \
 #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) \
 #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) \
 #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
 #ifdef DBG_QM_MALLOC
 #define ST_CHECK_PATTERN   0xf0f0f0f0
 #define ST_CHECK_PATTERN   0xf0f0f0f0
@@ -162,6 +162,9 @@ void* qm_malloc(struct qm_block* qm, unsigned int size)
 	unsigned int overhead;
 	unsigned int overhead;
 	
 	
 #ifdef DBG_QM_MALLOC
 #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,
 	DBG("qm_malloc(%x, %d) called from %s: %s(%d)\n", qm, size, file, func,
 			line);
 			line);
 #endif
 #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;
 	if (qm->free_lst.u.nxt_free==&(qm->free_lst)) return 0;
 	/*search for a suitable free frag*/
 	/*search for a suitable free frag*/
 	for (f=qm->free_lst.u.nxt_free; f!=&(qm->free_lst); f=f->u.nxt_free){
 	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){
 		if (f->size>=size){
 			/* we found it!*/
 			/* we found it!*/
 			/*detach it from the free list*/
 			/*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;
 			f->check=ST_CHECK_PATTERN;
 		/*  FRAG_END(f)->check1=END_CHECK_PATTERN1;
 		/*  FRAG_END(f)->check1=END_CHECK_PATTERN1;
 			FRAG_END(f)->check2=END_CHECK_PATTERN2;*/
 			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
 #endif
 			return (char*)f+sizeof(struct qm_frag);
 			return (char*)f+sizeof(struct qm_frag);
 		}
 		}
@@ -318,6 +325,8 @@ void qm_status(struct qm_block* qm)
 	int i;
 	int i;
 
 
 	LOG(L_INFO, "qm_status (%x):\n", qm);
 	LOG(L_INFO, "qm_status (%x):\n", qm);
+	if (!qm) return;
+
 	LOG(L_INFO, " heap size= %d\n", qm->size);
 	LOG(L_INFO, " heap size= %d\n", qm->size);
 	LOG(L_INFO, " used= %d, used+overhead=%d, free=%d\n",
 	LOG(L_INFO, " used= %d, used+overhead=%d, free=%d\n",
 			qm->used, qm->real_used, qm->size-qm->real_used);
 			qm->used, qm->real_used, qm->size-qm->real_used);

+ 1 - 1
q_malloc.h → mem/q_malloc.h

@@ -3,7 +3,7 @@
  * simple & fast malloc library
  * simple & fast malloc library
  */
  */
 
 
-#ifndef q_malloc_h
+#if !defined(q_malloc_h) && !defined(VQ_MALLOC)
 #define q_malloc_h
 #define q_malloc_h
 
 
 
 

+ 13 - 3
shm_mem.c → mem/shm_mem.c

@@ -6,7 +6,7 @@
 #ifdef SHM_MEM
 #ifdef SHM_MEM
 
 
 #include "shm_mem.h"
 #include "shm_mem.h"
-#include "config.h"
+#include "../config.h"
 
 
 #ifdef  SHM_MMAP
 #ifdef  SHM_MMAP
 
 
@@ -37,9 +37,15 @@
 #ifndef SHM_MMAP
 #ifndef SHM_MMAP
 static int shm_shmid=-1; /*shared memory id*/
 static int shm_shmid=-1; /*shared memory id*/
 #endif
 #endif
+
+
 int shm_semid=-1; /*semaphore id*/
 int shm_semid=-1; /*semaphore id*/
 static void* shm_mempool=(void*)-1;
 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;
 		return -1;
 	}
 	}
 	/* init it for malloc*/
 	/* 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){
 	if (shm_block==0){
 		LOG(L_CRIT, "ERROR: shm_mem_init: could not initialize shared"
 		LOG(L_CRIT, "ERROR: shm_mem_init: could not initialize shared"
 				" malloc\n");
 				" malloc\n");

+ 20 - 9
shm_mem.h → mem/shm_mem.h

@@ -25,10 +25,21 @@
 
 
 
 
 
 
-#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;
 extern int shm_semid;
 
 
 int shm_mem_init();
 int shm_mem_init();
@@ -94,7 +105,7 @@ again:
 	\
 	\
 	/*if (shm_lock()==0){*/\
 	/*if (shm_lock()==0){*/\
 		shm_lock();\
 		shm_lock();\
-		p=qm_malloc(shm_block, (size), __FILE__, __FUNCTION__, __LINE__);\
+		p=MY_MALLOC(shm_block, (size), __FILE__, __FUNCTION__, __LINE__);\
 		shm_unlock();\
 		shm_unlock();\
 	/* \
 	/* \
 	}else{ \
 	}else{ \
@@ -108,7 +119,7 @@ again:
 #define shm_free(p) \
 #define shm_free(p) \
 do { \
 do { \
 		shm_lock(); \
 		shm_lock(); \
-		qm_free(shm_block, (p), __FILE__, __FUNCTION__, __LINE__); \
+		MY_FREE(shm_block, (p), __FILE__, __FUNCTION__, __LINE__); \
 		shm_unlock(); \
 		shm_unlock(); \
 }while(0)
 }while(0)
 
 
@@ -122,7 +133,7 @@ do { \
 	\
 	\
 	/*if (shm_lock()==0){*/\
 	/*if (shm_lock()==0){*/\
 		shm_lock();\
 		shm_lock();\
-		p=qm_malloc(shm_block, (size));\
+		p=MY_MALLOC(shm_block, (size));\
 		shm_unlock();\
 		shm_unlock();\
 	/* \
 	/* \
 	}else{ \
 	}else{ \
@@ -136,7 +147,7 @@ do { \
 #define shm_free(p) \
 #define shm_free(p) \
 do { \
 do { \
 		shm_lock(); \
 		shm_lock(); \
-		qm_free(shm_block, (p)); \
+		MY_FREE(shm_block, (p)); \
 		shm_unlock(); \
 		shm_unlock(); \
 }while(0)
 }while(0)
 
 
@@ -147,7 +158,7 @@ do { \
 #define shm_status() \
 #define shm_status() \
 do { \
 do { \
 		shm_lock(); \
 		shm_lock(); \
-		qm_status(shm_block); \
+		MY_STATUS(shm_block); \
 		shm_unlock(); \
 		shm_unlock(); \
 }while(0)
 }while(0)
 
 

+ 438 - 0
mem/vq_malloc.c

@@ -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

+ 130 - 0
mem/vq_malloc.h

@@ -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

+ 2 - 15
modules/tm/TODO

@@ -7,22 +7,9 @@ Things we have omitted for now:
 - no SIP-wise HF comparison within T-matching
 - no SIP-wise HF comparison within T-matching
   (just memcmp)
   (just memcmp)
 - 6xx should be delayed indeed
 - 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
 - ACK of 2xx INV caching (avoid e2e retransmission
   of an ACK hit the proxy too)
   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)
 To-do: semaphore clean-up on exit (even better: w/sibling check)

+ 36 - 0
modules/tm/config.h

@@ -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

+ 0 - 12
modules/tm/globals.h

@@ -1,12 +0,0 @@
-/*
- * $Id$
- */
-
-
-
-#ifndef _H_GLOBALS
-#define _H_GLOBALS
-
-/* #define DBG( s ) printf( (s) ); */
-
-#endif

+ 36 - 50
modules/tm/h_table.c

@@ -2,7 +2,7 @@
  * $Id$
  * $Id$
  */
  */
 
 
-
+#include "hash_func.h"
 #include "h_table.h"
 #include "h_table.h"
 #include "../../dprint.h"
 #include "../../dprint.h"
 #include "sh_malloc.h"
 #include "sh_malloc.h"
@@ -12,53 +12,39 @@
   */
   */
 void free_cell( struct cell* dead_cell )
 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*/
    /* inits the timers*/
    for(  i=0 ; i<NR_OF_TIMER_LISTS ; i++ )
    for(  i=0 ; i<NR_OF_TIMER_LISTS ; i++ )
-      init_timerlist_lock( hash_table, i );
+      init_timer_list( hash_table, i );
 
 
    return  hash_table;
    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_canceled  = T_UNDEFINED;
    new_cell->T_canceler  = T_UNDEFINED;
    new_cell->T_canceler  = T_UNDEFINED;
 
 
-   init_cell_lock(  new_cell );
+   /* init_cell_lock(  new_cell ); */
 
 
    DBG("DEBUG: build_cell : done\n");
    DBG("DEBUG: build_cell : done\n");
    return new_cell;
    return new_cell;

+ 23 - 30
modules/tm/h_table.h

@@ -12,6 +12,7 @@
 #include <arpa/inet.h>
 #include <arpa/inet.h>
 
 
 #include "../../msg_parser.h"
 #include "../../msg_parser.h"
+#include "config.h"
 
 
 struct s_table;
 struct s_table;
 struct entry;
 struct entry;
@@ -25,27 +26,10 @@ struct timer;
 #include "sip_msg.h"
 #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_UNDEFINED 	( (struct cell*) -1 )
 #define T_NULL		( (struct cell*) 0 )
 #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
 typedef struct retrans_buff
 {
 {
@@ -59,15 +43,22 @@ typedef struct retrans_buff
    size_t tolen;
    size_t tolen;
 
 
    /* a message can be linked just to retransmission and FR list */
    /* a message can be linked just to retransmission and FR list */
-   struct timer_link tl[2];
+   struct timer_link retr_timer;
+   struct timer_link fr_timer;
+/*
    unsigned int timeout_ceiling;
    unsigned int timeout_ceiling;
    unsigned int timeout_value;
    unsigned int timeout_value;
+*/
 
 
    /*the cell that containes this retrans_buff*/
    /*the cell that containes this retrans_buff*/
    struct cell* my_T;
    struct cell* my_T;
+
+	enum lists retr_list;
+
 }retrans_buff_type;
 }retrans_buff_type;
 
 
 
 
+/* transaction context */
 
 
 typedef struct cell
 typedef struct cell
 {
 {
@@ -76,7 +67,9 @@ typedef struct cell
    struct cell*     prev_cell;
    struct cell*     prev_cell;
 
 
    /*sync data */
    /*sync data */
-   ser_lock_t   mutex;
+   /*
+	/* we use hash table mutexes now */
+   /* ser_lock_t   mutex; */
    int       ref_counter;
    int       ref_counter;
 
 
    /* cell payload data */
    /* cell payload data */
@@ -96,7 +89,7 @@ typedef struct cell
    /* usefull data */
    /* usefull data */
    /* UA Server */
    /* UA Server */
    struct sip_msg         *inbound_request;
    struct sip_msg         *inbound_request;
-   struct retrans_buff   *outbound_response;
+   struct retrans_buff   outbound_response;
    unsigned int             status;
    unsigned int             status;
    str*                             tag;
    str*                             tag;
    unsigned int             inbound_request_isACKed;
    unsigned int             inbound_request_isACKed;
@@ -106,6 +99,11 @@ typedef struct cell
    struct retrans_buff   *outbound_request[ MAX_FORK ];
    struct retrans_buff   *outbound_request[ MAX_FORK ];
    struct sip_msg          *inbound_response[ MAX_FORK ];
    struct sip_msg          *inbound_response[ MAX_FORK ];
    unsigned int             outbound_request_isACKed[MAX_FORK];
    unsigned int             outbound_request_isACKed[MAX_FORK];
+
+#ifdef	EXTRA_DEBUG
+	/* scheduled for deletion ? */
+	short damocles;
+#endif
 }cell_type;
 }cell_type;
 
 
 
 
@@ -123,7 +121,7 @@ typedef struct entry
 
 
 
 
 
 
-/* hash table */
+/* transaction table */
 struct s_table
 struct s_table
 {
 {
    /* table of hash entries; each of them is a list of synonyms  */
    /* 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();
 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 );
 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
 #endif

+ 88 - 1
modules/tm/hash_func.c

@@ -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 "hash_func.h"
 #include "../../dprint.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  hash_code = 0;
    int  i;
    int  i;
@@ -19,3 +30,79 @@ int hash( str  call_id, str cseq_nr )
    return hash_code %= TABLE_ENTRIES;
    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);
+}
+

+ 4 - 2
modules/tm/hash_func.h

@@ -6,10 +6,12 @@
 #ifndef _HASH_H
 #ifndef _HASH_H
 #define _HASH_H
 #define _HASH_H
 
 
-#include "globals.h"
 #include "../../str.h"
 #include "../../str.h"
 #include "h_table.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
 #endif

+ 9 - 2
modules/tm/lock.c

@@ -6,7 +6,6 @@
 #include <errno.h>
 #include <errno.h>
 
 
 #include "lock.h"
 #include "lock.h"
-#include "globals.h"
 #include "timer.h"
 #include "timer.h"
 #include "../../dprint.h"
 #include "../../dprint.h"
 
 
@@ -209,19 +208,22 @@ tryagain:
     }
     }
    return r;
    return r;
 }
 }
-
+/*
 int init_cell_lock( struct cell *cell )
 int init_cell_lock( struct cell *cell )
 {
 {
+*/
 	/* just advice which of the available semaphores to use;
 	/* just advice which of the available semaphores to use;
 		shared with the lock belonging to the next hash entry lock
 		shared with the lock belonging to the next hash entry lock
             (so that there are no collisions if one wants to try to
             (so that there are no collisions if one wants to try to
              lock on a cell as well as its list)
              lock on a cell as well as its list)
 
 
         */
         */
+/*
 	cell->mutex.semaphore_set=entry_semaphore,
 	cell->mutex.semaphore_set=entry_semaphore,
 	cell->mutex.semaphore_index=(cell->hash_index % sem_nr + 1)%sem_nr;
 	cell->mutex.semaphore_index=(cell->hash_index % sem_nr + 1)%sem_nr;
 
 
 }
 }
+*/
 
 
 int init_entry_lock( struct s_table* hash_table, struct entry *entry )
 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 )
 int release_cell_lock( struct cell *cell )
 {
 {
+*/
 	/* don't do anything here -- the init_*_lock procedures
 	/* don't do anything here -- the init_*_lock procedures
 	   just advised on usage of shared semaphores but did not
 	   just advised on usage of shared semaphores but did not
 	   generate them
 	   generate them
 	*/
 	*/
+/*
 }
 }
+*/
+
 int release_entry_lock( struct entry *entry )
 int release_entry_lock( struct entry *entry )
 {
 {
 	/* the same as above */
 	/* the same as above */

+ 2 - 2
modules/tm/lock.h

@@ -10,7 +10,6 @@
 #include <sys/ipc.h>
 #include <sys/ipc.h>
 #include <sys/sem.h>
 #include <sys/sem.h>
 
 
-#include "globals.h"
 
 
 /* typedef to structure we use for mutexing;
 /* typedef to structure we use for mutexing;
    currently, index to a semaphore set identifier now */
    currently, index to a semaphore set identifier now */
@@ -21,6 +20,7 @@ typedef struct {
 
 
 
 
 #include "h_table.h"
 #include "h_table.h"
+#include "timer.h"
 
 
 /* Uni*x permissions for IPC */
 /* Uni*x permissions for IPC */
 #define IPC_PERMISSIONS 0666
 #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_cell_lock( struct cell *cell );
 int init_entry_lock( struct s_table* hash_table, struct entry *entry );
 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 init_retr_timer_lock( struct s_table* hash_table, enum retransmission_lists list_id );
 
 
 int release_cell_lock( struct cell *cell );
 int release_cell_lock( struct cell *cell );

+ 2 - 2
modules/tm/sh_malloc.h

@@ -6,11 +6,11 @@
 #ifndef _SH_MALLOC_H
 #ifndef _SH_MALLOC_H
 #define _SH_MALLOC_H
 #define _SH_MALLOC_H
 
 
-#include "../../shm_mem.h"
+#include "../../mem/shm_mem.h"
 
 
 #if defined SHM_MEM
 #if defined SHM_MEM
 
 
-#include "../../shm_mem.h"
+#include "../../mem/shm_mem.h"
 
 
 #define sh_malloc(size)		shm_malloc((size))
 #define sh_malloc(size)		shm_malloc((size))
 #define sh_free(ptr)		shm_free((ptr))
 #define sh_free(ptr)		shm_free((ptr))

+ 1 - 18
modules/tm/sip_msg.c

@@ -5,7 +5,7 @@
 
 
 #include "sip_msg.h"
 #include "sip_msg.h"
 #include "../../dprint.h"
 #include "../../dprint.h"
-#include "../../mem.h"
+#include "../../mem/mem.h"
 
 
 char*   translate_pointer( char* new_buf , char *org_buf , char* p);
 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);
 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)
 void sip_msg_free_1(struct sip_msg* msg)
 {
 {
    if (!msg) return;
    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;
    return new_via;
 }
 }
 
 
-
-
-
-
-
-
 void sip_msg_free_2(struct sip_msg* msg)
 void sip_msg_free_2(struct sip_msg* msg)
 {
 {
    sh_free( (char*)msg );
    sh_free( (char*)msg );
 }
 }
-
-
-
-
-
-
-
-
-
-

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 458 - 670
modules/tm/t_funcs.c


+ 41 - 6
modules/tm/t_funcs.h

@@ -13,13 +13,18 @@
 #include "../../globals.h"
 #include "../../globals.h"
 #include "../../udp_server.h"
 #include "../../udp_server.h"
 #include "../../msg_translator.h"
 #include "../../msg_translator.h"
-#include "../../mem.h"
+#include "../../mem/mem.h"
 
 
 struct s_table;
 struct s_table;
 struct timer;
 struct timer;
 struct entry;
 struct entry;
 struct cell;
 struct cell;
 
 
+extern struct cell         *T;
+extern unsigned int     global_msg_id;
+extern struct s_table*  hash_table;
+
+
 #include "sh_malloc.h"
 #include "sh_malloc.h"
 
 
 #include "timer.h"
 #include "timer.h"
@@ -27,12 +32,41 @@ struct cell;
 #include "sip_msg.h"
 #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();
 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 *  );
 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 );
 
 
 
 
 
 

+ 380 - 0
modules/tm/t_lookup.c

@@ -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;
+
+}
+

+ 138 - 158
modules/tm/timer.c

@@ -3,115 +3,196 @@
  */
  */
 
 
 
 
+#include "config.h"
+#include "h_table.h"
 #include "timer.h"
 #include "timer.h"
 #include "../../dprint.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* timer_list=&(hash_table->timers[ list_id ]);
    struct timer_link *tl ;
    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);
       DBG("DEBUG: print_timer_list[%d]: %p, next=%p \n",list_id, tl, tl->next_tl);
       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->next_tl = 0;
     tl->prev_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 */
    /* give the list lock away */
    unlock( timer_list->mutex );
    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          *timer_list = &(hash_table->timers[ list_id ]);
    struct timer_link  *tl;
    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 );
    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)  )
    if ( is_in_timer_list( new_tl,list_id)  )
       remove_from_timer_list_dummy( hash_table , new_tl , list_id);
       remove_from_timer_list_dummy( hash_table , new_tl , list_id);
 
 
    new_tl->time_out = time_out ;
    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 );
    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 )
     if ( tl )
-    {  /* insert before tl*/
+    {  // insert before tl
        new_tl->prev_tl = tl->prev_tl;
        new_tl->prev_tl = tl->prev_tl;
        tl->prev_tl = new_tl;
        tl->prev_tl = new_tl;
     }
     }
    else
    else
-    {  /* at the end or empty list */
+    {  // at the end or empty list 
        new_tl->prev_tl = timer_list->last_tl;
        new_tl->prev_tl = timer_list->last_tl;
        timer_list->last_tl = new_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
     else
        timer_list->first_tl = new_tl;
        timer_list->first_tl = new_tl;
     new_tl->next_tl = tl;
     new_tl->next_tl = tl;
+	tl->list_id = list_id;
 
 
    //print_timer_list(hash_table, 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;
-      }
-   }
-}
-
-
-

+ 37 - 35
modules/tm/timer.h

@@ -2,58 +2,60 @@
  * $Id$
  * $Id$
  */
  */
 
 
-
 #ifndef _TIMER_H
 #ifndef _TIMER_H
 #define _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:
 /* all you need to put a cell in a timer list:
    links to neighbours and timer value         */
    links to neighbours and timer value         */
 typedef struct timer_link
 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 ;
 }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
 #endif

+ 12 - 9
modules/tm/tm.c

@@ -5,17 +5,16 @@
  *
  *
  */
  */
 
 
-
+#include <stdio.h>
+#include <string.h>
+#include <netdb.h>
 
 
 #include "../../sr_module.h"
 #include "../../sr_module.h"
 #include "../../dprint.h"
 #include "../../dprint.h"
 #include "../../error.h"
 #include "../../error.h"
 #include "../../ut.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 "h_table.h"
 #include "t_funcs.h"
 #include "t_funcs.h"
 
 
@@ -40,7 +39,8 @@ static struct module_exports nm_exports= {
 				"t_forward_uri",
 				"t_forward_uri",
 				"t_send_reply",
 				"t_send_reply",
 				"t_retransmit_reply",
 				"t_retransmit_reply",
-				"t_release"
+				"t_release",
+				"t_unref"
 			},
 			},
 	(cmd_function[]){
 	(cmd_function[]){
 					t_add_transaction,
 					t_add_transaction,
@@ -50,7 +50,8 @@ static struct module_exports nm_exports= {
 					t_forward_uri,
 					t_forward_uri,
 					w_t_send_reply,
 					w_t_send_reply,
 					t_retransmit_reply,
 					t_retransmit_reply,
-					w_t_release
+					w_t_release,
+					t_unref
 					},
 					},
 	(int[]){
 	(int[]){
 				0,
 				0,
@@ -60,6 +61,7 @@ static struct module_exports nm_exports= {
 				0,
 				0,
 				2,
 				2,
 				0,
 				0,
+				0,
 				0
 				0
 			},
 			},
 	(fixup_function[]){
 	(fixup_function[]){
@@ -70,9 +72,10 @@ static struct module_exports nm_exports= {
 				0,
 				0,
 				fixup_t_send_reply,
 				fixup_t_send_reply,
 				0,
 				0,
-				0
+				0,
+				0,
 		},
 		},
-	8,
+	9,
 	(response_function) t_on_reply_received,
 	(response_function) t_on_reply_received,
 	(destroy_function) tm_shutdown
 	(destroy_function) tm_shutdown
 };
 };

+ 10 - 6
msg_parser.c

@@ -13,10 +13,10 @@
 #include "ut.h"
 #include "ut.h"
 #include "error.h"
 #include "error.h"
 #include "dprint.h"
 #include "dprint.h"
-#include "mem.h"
+#include "mem/mem.h"
 
 
 #ifdef DEBUG_DMALLOC
 #ifdef DEBUG_DMALLOC
-#include <dmalloc.h>
+#include <mem/dmalloc.h>
 #endif
 #endif
 
 
 
 
@@ -54,7 +54,7 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl)
 	   token 
 	   token 
         */
         */
 	if (len <=16 ) {
 	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;
 		goto error1;
 	}
 	}
 
 
@@ -131,8 +131,7 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl)
 		if (s1>='0' && s1<='9' && 
 		if (s1>='0' && s1<='9' && 
 		    s2>='0' && s2<='9' &&
 		    s2>='0' && s2<='9' &&
 		    s3>='0' && s3<='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 {
 		} else {
 			LOG(L_INFO, "ERROR:parse_first_line: status_code non-numerical: %s\n",
 			LOG(L_INFO, "ERROR:parse_first_line: status_code non-numerical: %s\n",
 				second );
 				second );
@@ -278,6 +277,8 @@ char* get_hdr_field(char* buf, char* end, struct hdr_field* hdr)
 			goto error;
 			goto error;
 	}
 	}
 
 
+	/* jku: if \r covered by current length, shrink it */
+	trim_r( hdr->body );
 	return tmp;
 	return tmp;
 error:
 error:
 	DBG("get_hdr_field: error exit\n");
 	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->add_rm)      free_lump_list(msg->add_rm);
 	if (msg->repl_add_rm) free_lump_list(msg->repl_add_rm);
 	if (msg->repl_add_rm) free_lump_list(msg->repl_add_rm);
 	pkg_free(msg->orig);
 	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
 }
 }
 
 
 
 

+ 1 - 1
msg_parser.h

@@ -84,7 +84,7 @@ struct msg_start{
 			str version;
 			str version;
 			str status;
 			str status;
 			str reason;
 			str reason;
-			unsigned short statusclass, statuscode;
+			unsigned short /* statusclass,*/ statuscode;
 		}reply;
 		}reply;
 	}u;
 	}u;
 };
 };

+ 5 - 3
msg_translator.c

@@ -6,7 +6,7 @@
 #include <sys/socket.h>
 #include <sys/socket.h>
 
 
 #include "msg_translator.h"
 #include "msg_translator.h"
-#include "mem.h"
+#include "mem/mem.h"
 #include "dprint.h"
 #include "dprint.h"
 #include "config.h"
 #include "config.h"
 #include "md5utils.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 ||
 		if ( hdr->type==HDR_VIA || hdr->type==HDR_FROM ||
 				hdr->type==HDR_CALLID || hdr->type==HDR_TO ||
 				hdr->type==HDR_CALLID || hdr->type==HDR_TO ||
 				hdr->type==HDR_CSEQ )
 				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 */
 	/* end of message */
 	len += CRLF_LEN; /*new line*/
 	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) ,
 			memcpy( p , msg->orig+(hdr->name.s-msg->buf) ,
 					((hdr->body.s+hdr->body.len ) -
 					((hdr->body.s+hdr->body.len ) -
 					hdr->name.s ) );
 					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 );
 	memcpy( p, CRLF, CRLF_LEN );

+ 1 - 1
parse_fline.c

@@ -1123,7 +1123,7 @@ char* parse_fline(char* buffer, char* end, struct msg_start* fl)
 skip:
 skip:
 	if (fl->type==SIP_REPLY){
 	if (fl->type==SIP_REPLY){
 		fl->u.reply.statuscode=stat;
 		fl->u.reply.statuscode=stat;
-		fl->u.reply.statusclass=stat/100;
+		/* fl->u.reply.statusclass=stat/100; */
 	}
 	}
 	return tmp;
 	return tmp;
 	
 	

+ 1 - 1
parse_via.c

@@ -21,7 +21,7 @@
 #include "dprint.h"
 #include "dprint.h"
 #include "msg_parser.h"
 #include "msg_parser.h"
 #include "ut.h"
 #include "ut.h"
-#include "mem.h"
+#include "mem/mem.h"
 
 
 
 
 
 

+ 8 - 21
receive.c

@@ -11,15 +11,12 @@
 #include "msg_parser.h"
 #include "msg_parser.h"
 #include "forward.h"
 #include "forward.h"
 #include "action.h"
 #include "action.h"
-#include "mem.h"
+#include "mem/mem.h"
+#include "stats.h"
 
 
 
 
 #ifdef DEBUG_DMALLOC
 #ifdef DEBUG_DMALLOC
-#include <dmalloc.h>
-#endif
-
-#ifdef STATS
-#include "stats.h"
+#include <mem/dmalloc.h>
 #endif
 #endif
 
 
 unsigned int msg_no=0;
 unsigned int msg_no=0;
@@ -78,10 +75,7 @@ int receive_msg(char* buf, unsigned int len, unsigned long src_ip)
 			goto error;
 			goto error;
 		}
 		}
 		DBG("succesfully ran routing scripts...\n");
 		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){
 	}else if (msg->first_line.type==SIP_REPLY){
 		DBG("msg= reply\n");
 		DBG("msg= reply\n");
 		/* sanity checks */
 		/* sanity checks */
@@ -97,10 +91,7 @@ int receive_msg(char* buf, unsigned int len, unsigned long src_ip)
 		}
 		}
 		/* check if via1 == us */
 		/* 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 */
 		/* send the msg */
 		if (forward_reply(msg)==0){
 		if (forward_reply(msg)==0){
@@ -120,23 +111,19 @@ skip:
 	free_sip_msg(msg);
 	free_sip_msg(msg);
 	pkg_free(msg);
 	pkg_free(msg);
 #ifdef STATS
 #ifdef STATS
-	if (skipped) update_received_drops;
+	if (skipped) STATS_RX_DROPS;
 #endif
 #endif
 	return 0;
 	return 0;
 error:
 error:
 	DBG("error:...\n");
 	DBG("error:...\n");
 	free_sip_msg(msg);
 	free_sip_msg(msg);
 	pkg_free(msg);
 	pkg_free(msg);
-#ifdef STATS
-	update_received_drops;
-#endif
+	STATS_RX_DROPS;
 	return -1;
 	return -1;
 error1:
 error1:
 	if (msg) pkg_free(msg);
 	if (msg) pkg_free(msg);
 	pkg_free(buf);
 	pkg_free(buf);
-#ifdef STATS
-	update_received_drops;
-#endif
+	STATS_RX_DROPS;
 	return -1;
 	return -1;
 }
 }
 
 

+ 52 - 38
stats.h

@@ -12,6 +12,58 @@
 #include <errno.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
 #ifdef STATS
 
 
@@ -76,44 +128,6 @@ void dump_statistic( FILE *fp, struct stats_s *istats );
 int dump_all_statistic();
 int dump_all_statistic();
 int init_stats( int nr_of_processes );
 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
 #endif

+ 2 - 2
test/tp.cfg

@@ -1,4 +1,4 @@
-debug=2          # debug level (cmd line: -dddddddddd)
+debug=9          # debug level (cmd line: -dddddddddd)
 log_stderror=yes # (cmd line: -E)
 log_stderror=yes # (cmd line: -E)
 check_via=yes     # (cmd. line: -v)
 check_via=yes     # (cmd. line: -v)
 dns=on           # (cmd. line: -r)
 dns=on           # (cmd. line: -r)
@@ -11,7 +11,7 @@ loop_checks=1
 
 
 #modules
 #modules
 loadmodule "modules/print/print.so"
 loadmodule "modules/print/print.so"
-loadmodule "modules/tm/tm.so"
+#loadmodule "modules/tm/tm.so"
 
 
 route{
 route{
 	if ( t_lookup_request()) {
 	if ( t_lookup_request()) {

+ 27 - 24
t_debug.cfg → test/tx.cfg

@@ -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)
 check_via=yes     # (cmd. line: -v)
 dns=on           # (cmd. line: -r)
 dns=on           # (cmd. line: -r)
 rev_dns=yes      # (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=127.0.0.1
+listen=192.168.99.100
 loop_checks=1
 loop_checks=1
 # for more info: sip_router -h
 # for more info: sip_router -h
 
 
 #modules
 #modules
 loadmodule "modules/print/print.so"
 loadmodule "modules/print/print.so"
-loadmodule "modules/tm/tm.so"
+#loadmodule "modules/tm/tm.so"
 
 
 route{
 route{
 	if ( t_lookup_request()) {
 	if ( t_lookup_request()) {
 		if ( method=="ACK" )	{
 		if ( method=="ACK" )	{
 			log("SER: ACK received -> t_release\n");
 			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");
 				log("SER: WARNING: bad forward\n");
 			};
 			};
 			if (! t_release()) {
 			if (! t_release()) {
@@ -30,15 +38,17 @@ route{
 			};
 			};
 			log("SER: yet another annoying retranmission\n");
 			log("SER: yet another annoying retranmission\n");
 		};
 		};
+		t_unref();
 	} else {
 	} 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 {
 		} else {
+			# establish transaction
+			if (! t_add_transaction()){
+				log("ERROR in ser: t_add_transaction\n");
+			};
+			# reply
 			if (method=="CANCEL") {
 			if (method=="CANCEL") {
 				log("SER: new CANCEL\n");
 				log("SER: new CANCEL\n");
 				if (! t_send_reply( "200", "glad to cancel")){
 				if (! t_send_reply( "200", "glad to cancel")){
@@ -51,17 +61,10 @@ route{
 					log("SER: ERROR: t_send_reply (100)\n");
 					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();
 		};
 		};
 	};
 	};
-
 }
 }

+ 53 - 0
test/xx.cfg

@@ -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();
+		};
+	};
+		
+}

+ 51 - 0
test/xy.cfg

@@ -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();
+		};
+	};
+		
+}

+ 2 - 1
timer.c

@@ -6,8 +6,9 @@
 #include "dprint.h"
 #include "dprint.h"
 #include "error.h"
 #include "error.h"
 #include "config.h"
 #include "config.h"
+#include "mem/mem.h"
 #ifdef SHM_MEM
 #ifdef SHM_MEM
-#include "shm_mem.h"
+#include "mem/shm_mem.h"
 #endif
 #endif
 
 
 #include <stdlib.h>
 #include <stdlib.h>

+ 13 - 5
udp_server.c

@@ -15,10 +15,10 @@
 #include "config.h"
 #include "config.h"
 #include "dprint.h"
 #include "dprint.h"
 #include "receive.h"
 #include "receive.h"
-#include "mem.h"
+#include "mem/mem.h"
 
 
 #ifdef DEBUG_DMALLOC
 #ifdef DEBUG_DMALLOC
-#include <dmalloc.h>
+#include <mem/dmalloc.h>
 #endif
 #endif
 
 
 int udp_sock;
 int udp_sock;
@@ -151,10 +151,16 @@ error:
 int udp_rcv_loop()
 int udp_rcv_loop()
 {
 {
 	unsigned len;
 	unsigned len;
+#ifdef DYN_BUF
 	char* buf;
 	char* buf;
+#else
+	char buf [BUF_SIZE+1];
+#endif
+
 	struct sockaddr* from;
 	struct sockaddr* from;
 	int fromlen;
 	int fromlen;
 
 
+
 	from=(struct sockaddr*) malloc(sizeof(struct sockaddr));
 	from=(struct sockaddr*) malloc(sizeof(struct sockaddr));
 	if (from==0){
 	if (from==0){
 		LOG(L_ERR, "ERROR: udp_rcv_loop: out of memory\n");
 		LOG(L_ERR, "ERROR: udp_rcv_loop: out of memory\n");
@@ -162,12 +168,14 @@ int udp_rcv_loop()
 	}
 	}
 
 
 	for(;;){
 	for(;;){
+#ifdef DYN_BUF
 		buf=pkg_malloc(BUF_SIZE+1);
 		buf=pkg_malloc(BUF_SIZE+1);
 		if (buf==0){
 		if (buf==0){
 			LOG(L_ERR, "ERROR: udp_rcv_loop: could not allocate receive"
 			LOG(L_ERR, "ERROR: udp_rcv_loop: could not allocate receive"
 					 " buffer\n");
 					 " buffer\n");
 			goto error;
 			goto error;
 		}
 		}
+#endif
 		fromlen=sizeof(struct sockaddr);
 		fromlen=sizeof(struct sockaddr);
 		len=recvfrom(udp_sock, buf, BUF_SIZE, 0, from, &fromlen);
 		len=recvfrom(udp_sock, buf, BUF_SIZE, 0, from, &fromlen);
 		if (len==-1){
 		if (len==-1){
@@ -203,7 +211,6 @@ int udp_send(char *buf, unsigned len, struct sockaddr*  to, unsigned tolen)
 	int n;
 	int n;
 
 
 /*	struct sockaddr_in a2;*/
 /*	struct sockaddr_in a2;*/
-/*
 #ifndef NO_DEBUG
 #ifndef NO_DEBUG
 #define MAX_IP_LENGTH 18
 #define MAX_IP_LENGTH 18
 	char ip_txt[MAX_IP_LENGTH];
 	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: 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(" 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));
 	memset(&a2, 0, sizeof(struct sockaddr_in));
 	a2.sin_family = a->sin_family;
 	a2.sin_family = a->sin_family;

+ 19 - 0
ut.h

@@ -9,6 +9,25 @@
 
 
 #include "dprint.h"
 #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 
 /* converts a str to an u. short, returns the u. short and sets *err on 
  * error and if err!=null
  * error and if err!=null
  * */
  * */

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно