Browse code

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

Jiri Kuthan authored on 26/02/2002 00:04:05
Showing 18 changed files
... ...
@@ -54,7 +54,9 @@ ARCH = $(shell uname -m |sed -e s/i.86/i386/ -e s/sun4u/sparc64/ )
54 54
 #		issues additional debugging information if lock/unlock is called
55 55
 # -DFAST_LOCK
56 56
 #		uses fast arhitecture specific locking (see the arh. specific section)
57
-#
57
+# -DNOISY_REPLIES
58
+#		turns on appending User-agent and Content-length:0 to ser-generated
59
+#		replies; 
58 60
 # -DBUSY_WAIT
59 61
 #		uses busy waiting on the lock
60 62
 # -DADAPTIVE_WAIT
... ...
@@ -66,21 +68,27 @@ ARCH = $(shell uname -m |sed -e s/i.86/i386/ -e s/sun4u/sparc64/ )
66 66
 # -DNOSMP
67 67
 #		don't use smp compliant locking (faster but won't work on SMP machines)
68 68
 #		(not yet enabled)
69
+# -DWAIT
70
+#		protection against race condiditions; turn off only for debugging;
71
+#       to become non-optional if stable
72
+# -DNEW_HNAME
73
+#		32-bit header name parsing; turn off for lower speed ;-) or debugging; to become non-optional if fast and stable
74
+# -DSRL Shortened Reply Lock -- moves more code, esp. "send" out
75
+#  of locks for greater speed; to become non-optional if fast and stable
69 76
 
70 77
 DEFS+= -DNAME='"$(NAME)"' -DVERSION='"$(RELEASE)"' -DARCH='"$(ARCH)"' \
71 78
 	 -DOS='"$(OS)"' -DCOMPILER='"$(CC_VER)"'\
72 79
 	 -DDNS_IP_HACK  -DPKG_MALLOC -DSHM_MEM  -DSHM_MMAP \
73 80
 	 -DF_MALLOC  -DUSE_SYNONIM\
74 81
 	 -DNO_DEBUG \
82
+	 -DWAIT -DNEW_HNAME -DNOISY_REPLIES -DSRL
75 83
 	 #-DADAPTIVE_WAIT -DADAPTIVE_WAIT_LOOPS=0 \
76 84
 	 #-DNOSMP \
77 85
 	 #-DEXTRA_DEBUG 
78 86
 	 #-DVQ_MALLOC  -DDBG_LOCK  #-DSTATS
79 87
 	 #-DDBG_QM_MALLOC #-DNO_DEBUG
80
-#-DEXTRA_DEBUG
81 88
 # -DUSE_SHM_MEM
82 89
 #-DNO_DEBUG
83
-#-DPKG_MALLOC
84 90
 #-DNO_DEBUG#-DSTATS -DNO_DEBUG
85 91
 #-DNO_LOG
86 92
 
... ...
@@ -235,7 +243,7 @@ ifeq  ($(OS), SunOS)
235 235
 
236 236
 	YACC=yacc
237 237
 	LIBS+=-L/usr/local/lib -lxnet -lrt # or -lnsl -lsocket or -lglibc ?
238
-	# -lrt needed for sched_yield
238
+	# -lrt needed for sched_yield; some systems may require -lposix4
239 239
 endif
240 240
 
241 241
 ifeq ($(OS), FreeBSD)
... ...
@@ -55,7 +55,7 @@
55 55
 #define PKG_MEM_POOL_SIZE 1024*1024
56 56
 
57 57
 /*used if SH_MEM is defined*/
58
-#define SHM_MEM_SIZE 256*1024*1024
58
+#define SHM_MEM_SIZE 256
59 59
 
60 60
 #define TIMER_TICK 1
61 61
 #define LONG_SLEEP	3600
... ...
@@ -41,4 +41,6 @@ extern int *pids;
41 41
 extern int cfg_errors;
42 42
 extern unsigned int msg_no;
43 43
 
44
+extern unsigned int shm_mem_size;
45
+
44 46
 #endif
... ...
@@ -30,6 +30,7 @@
30 30
 #endif
31 31
 #include "sr_module.h"
32 32
 #include "timer.h"
33
+#include "msg_parser.h"
33 34
 
34 35
 
35 36
 #include <signal.h>
... ...
@@ -126,6 +127,7 @@ Options:\n\
126 126
     -h           This help message\n\
127 127
     -b nr        Maximum receive buffer size which will not be exceeded by\n\
128 128
                  auto-probing procedure even if  OS allows\n\
129
+	-m nr        Size of shared memory allocated in Megabytes\n\
129 130
     -w  dir      change the working directory to \"dir\" (default \"/\")\n\
130 131
     -t  dir      chroot to \"dir\"\n\
131 132
     -u uid       change uid \n\
... ...
@@ -141,9 +143,11 @@ void print_ct_constants()
141 141
 #ifdef ADAPTIVE_WAIT
142 142
 	printf("ADAPTIVE_WAIT_LOOPS=%d, ", ADAPTIVE_WAIT_LOOPS);
143 143
 #endif
144
+/*
144 145
 #ifdef SHM_MEM
145 146
 	printf("SHM_MEM_SIZE=%d, ", SHM_MEM_SIZE);
146 147
 #endif
148
+*/
147 149
 	printf("MAX_RECV_BUFFER_SIZE %d, MAX_LISTEN %d,"
148 150
 			" MAX_URI_SIZE %d, MAX_PROCESSES %d\n",
149 151
 		MAX_RECV_BUFFER_SIZE, MAX_LISTEN, MAX_URI_SIZE, MAX_PROCESSES );
... ...
@@ -204,6 +208,9 @@ process_bm_t process_bit = 0;
204 204
 /* cfg parsing */
205 205
 int cfg_errors=0;
206 206
 
207
+/* shared memory (in MB) */
208
+unsigned int shm_mem_size=SHM_MEM_SIZE * 1024 * 1024;
209
+
207 210
 #define MAX_FD 32 /* maximum number of inherited open file descriptors,
208 211
 		    (normally it shouldn't  be bigger  than 3) */
209 212
 
... ...
@@ -483,7 +490,7 @@ int main(int argc, char** argv)
483 483
 #ifdef STATS
484 484
 	"s:"
485 485
 #endif
486
-	"f:p:b:l:n:rRvcdDEVhw:t:u:g:";
486
+	"f:p:m:b:l:n:rRvcdDEVhw:t:u:g:";
487 487
 	
488 488
 	while((c=getopt(argc,argv,options))!=-1){
489 489
 		switch(c){
... ...
@@ -503,6 +510,15 @@ int main(int argc, char** argv)
503 503
 					}
504 504
 					break;
505 505
 
506
+			case 'm':
507
+					shm_mem_size=strtol(optarg, &tmp, 10) * 1024 * 1024;
508
+					if (tmp &&(*tmp)){
509
+						fprintf(stderr, "bad shmem size number: -m %s\n", optarg);
510
+						goto error;
511
+					};
512
+					LOG(L_INFO, "ser: shared memory allocated: %d MByte\n", shm_mem_size );
513
+					break;
514
+
506 515
 			case 'b':
507 516
 					maxbuffer=strtol(optarg, &tmp, 10);
508 517
 					if (tmp &&(*tmp)){
... ...
@@ -619,6 +635,10 @@ int main(int argc, char** argv)
619 619
 		goto error;
620 620
 	}
621 621
 
622
+#ifdef NEW_HNAME
623
+    init_htable();
624
+#endif
625
+
622 626
 	/*init mallocs (before parsing cfg !)*/
623 627
 	if (init_mallocs()==-1)
624 628
 		goto error;
... ...
@@ -142,13 +142,13 @@ int shm_mem_init()
142 142
 				strerror(errno));
143 143
 		return -1;
144 144
 	}
145
-	shm_mempool=mmap(0, SHM_MEM_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED,
145
+	shm_mempool=mmap(0, /* SHM_MEM_SIZE */ shm_mem_size, PROT_READ|PROT_WRITE, MAP_SHARED,
146 146
 						fd ,0);
147 147
 	/* close /dev/zero */
148 148
 	close(fd);
149 149
 #else
150 150
 	
151
-	shm_shmid=shmget(IPC_PRIVATE, SHM_MEM_SIZE, 0700);
151
+	shm_shmid=shmget(IPC_PRIVATE, /* SHM_MEM_SIZE */ shm_mem_size , 0700);
152 152
 	if (shm_shmid==-1){
153 153
 		LOG(L_CRIT, "ERROR: shm_mem_init: could not allocate shared memory"
154 154
 				" segment: %s\n", strerror(errno));
... ...
@@ -185,11 +185,11 @@ int shm_mem_init()
185 185
 #endif
186 186
 	/* init it for malloc*/
187 187
 #	ifdef VQ_MALLOC
188
-		shm_block=vqm_malloc_init(shm_mempool, SHM_MEM_SIZE);
188
+		shm_block=vqm_malloc_init(shm_mempool, /* SHM_MEM_SIZE */ shm_mem_size );
189 189
 	#elif defined F_MALLOC
190
-		shm_block=fm_malloc_init(shm_mempool, SHM_MEM_SIZE);
190
+		shm_block=fm_malloc_init(shm_mempool, /* SHM_MEM_SIZE */ shm_mem_size );
191 191
 #	else
192
-		shm_block=qm_malloc_init(shm_mempool, SHM_MEM_SIZE);
192
+		shm_block=qm_malloc_init(shm_mempool, /* SHM_MEM_SIZE */ shm_mem_size );
193 193
 #	endif
194 194
 	if (shm_block==0){
195 195
 		LOG(L_CRIT, "ERROR: shm_mem_init: could not initialize shared"
... ...
@@ -218,7 +218,7 @@ void shm_mem_destroy()
218 218
 	DBG("shm_mem_destroy\n");
219 219
 	if (shm_mempool && (shm_mempool!=(void*)-1)) {
220 220
 #ifdef SHM_MMAP
221
-		munmap(shm_mempool, SHM_MEM_SIZE);
221
+		munmap(shm_mempool, /* SHM_MEM_SIZE */ shm_mem_size );
222 222
 #else
223 223
 		shmdt(shm_mempool);
224 224
 #endif
... ...
@@ -97,7 +97,13 @@ typedef struct cell
97 97
 	/* protection against concurrent reply processing */
98 98
 	ser_lock_t   reply_mutex;
99 99
 	/* protection against concurrent ACK processing */
100
-	ser_lock_t   ack_mutex;
100
+	ser_lock_t	ack_mutex;
101
+#ifdef WAIT
102
+	/* protection against reentering WAIT state */
103
+	ser_lock_t	wait_mutex;
104
+	/* has the transaction been put on wait status ? */
105
+	int on_wait;
106
+#endif
101 107
 
102 108
 	/* this is where destination is stored for picked branch;
103 109
 	good if a need to forward ACK later on */
... ...
@@ -111,6 +117,7 @@ typedef struct cell
111 111
 	/* scheduled for deletion ? */
112 112
 	short damocles;
113 113
 #endif
114
+
114 115
 }cell_type;
115 116
 
116 117
 
... ...
@@ -51,6 +51,9 @@ static int
51 51
 	timer_semaphore=0, 
52 52
 	reply_semaphore=0,
53 53
 	ack_semaphore=0;
54
+#ifdef WAIT
55
+static int  wait_semaphore=0;
56
+#endif
54 57
 /* and the maximum number of semaphores in the entry_semaphore set */
55 58
 static int sem_nr;
56 59
 /* timer group locks */
... ...
@@ -166,6 +169,11 @@ again:
166 166
 			semctl(reply_semaphore, 0 , IPC_RMID , 0 );
167 167
 		if (ack_semaphore>0)
168 168
 			semctl(reply_semaphore, 0 , IPC_RMID , 0 );
169
+#ifdef WAIT
170
+		if (wait_semaphore>0)
171
+			semctl(wait_semaphore, 0 , IPC_RMID , 0 );
172
+#endif
173
+
169 174
 
170 175
 		if (i==0){
171 176
 			LOG(L_CRIT, "lock_initialize: could not allocate semaphore"
... ...
@@ -236,6 +244,23 @@ again:
236 236
 		}
237 237
 	}
238 238
 
239
+#ifdef WAIT
240
+	if ((wait_semaphore=init_semaphore_set(sem_nr))<0){
241
+		if (errno==EINVAL || errno==ENOSPC ) {
242
+			DBG( "DEBUG:lock_initialize: wait semaphore initialization"
243
+				" failure: %s\n", strerror(errno));
244
+			probe_run==1;
245
+			i--;
246
+			goto again;
247
+		}else{
248
+			LOG(L_CRIT, "ERROR:lock_initialize: wait semaphore initialization"
249
+				" failure: %s\n", strerror(errno));
250
+			goto error;
251
+		}
252
+	}
253
+#endif
254
+
255
+
239 256
 
240 257
 
241 258
 	/* return success */
... ...
@@ -280,8 +305,18 @@ void lock_cleanup()
280 280
 	if (ack_semaphore > 0 &&
281 281
 	    semctl( ack_semaphore, 0 , IPC_RMID , 0 )==-1)
282 282
 		LOG(L_ERR, "ERROR: lock_cleanup, ack_semaphore cleanup failed\n");
283
+#ifdef WAIT
284
+	if (wait_semaphore > 0 &&
285
+		semctl( wait_semaphore, 0 , IPC_RMID , 0 )==-1)
286
+		LOG(L_ERR, "ERROR: lock_cleanup, wait_semaphore cleanup failed\n");
287
+#endif
288
+
283 289
 
284 290
 	entry_semaphore = timer_semaphore = reply_semaphore = ack_semaphore = 0;
291
+#ifdef WAIT
292
+	wait_semaphore = 0;
293
+#endif
294
+
285 295
 
286 296
 }
287 297
 #endif /*FAST_LOCK*/
... ...
@@ -329,13 +364,20 @@ int init_cell_lock( struct cell *cell )
329 329
 #ifdef FAST_LOCK
330 330
 	init_lock(cell->reply_mutex);
331 331
 	init_lock(cell->ack_mutex);
332
+#ifdef WAIT
333
+	init_lock(cell->wait_mutex);
334
+#endif
332 335
 	return 0;
333 336
 #else
334 337
 	cell->reply_mutex.semaphore_set=reply_semaphore;
335 338
 	cell->reply_mutex.semaphore_index = cell->hash_index % sem_nr;
336 339
 	cell->ack_mutex.semaphore_set=ack_semaphore;
337 340
 	cell->ack_mutex.semaphore_index = cell->hash_index % sem_nr;
338
-#endif
341
+#ifdef WAIT
342
+	cell->wait_mutex.semaphore_set=wait_semaphore;
343
+	cell->wait_mutex.semaphore_index = cell->hash_index % sem_nr;
344
+#endif /* WAIT */
345
+#endif /* FAST_LOCK */
339 346
 	return 0;
340 347
 }
341 348
 
... ...
@@ -408,107 +408,6 @@ int t_forward_uri( struct sip_msg* p_msg  )
408 408
 #endif
409 409
 
410 410
 
411
-/*  This function is called whenever a reply for our module is received; 
412
-  * we need to register  this function on module initialization;
413
-  *  Returns :   0 - core router stops
414
-  *              1 - core router relay statelessly
415
-  */
416
-int t_on_reply_received( struct sip_msg  *p_msg )
417
-{
418
-	unsigned int  branch,len, msg_status, msg_class, save_clone;
419
-	struct sip_msg *clone, *backup;
420
-	int relay;
421
-	int start_fr;
422
-	int is_invite;
423
-	struct retrans_buff *rb;
424
-
425
-
426
-	/* make sure we know the assosociated tranaction ... */
427
-	if (t_check( p_msg  , &branch )==-1) return 1;
428
-	/* ... if there is no such, tell the core router to forward statelessly */
429
-	if ( T<=0 ) return 1;
430
-
431
-	DBG("DEBUG: t_on_reply_received: Original status =%d\n",T->status);
432
-
433
-	/* it can take quite long -- better do it now than later 
434
-	   inside a reply_lock */
435
-	if (!(clone=sip_msg_cloner( p_msg ))) {
436
-		goto error;
437
-	}
438
-	msg_status=p_msg->REPLY_STATUS;
439
-	msg_class=REPLY_CLASS(p_msg);
440
-	is_invite= T->inbound_request->REQ_METHOD==METHOD_INVITE;
441
-
442
-	/* *** stop timers *** */
443
-	rb=T->outbound_request[branch];
444
-	/* stop retransmission */
445
-	reset_timer( hash_table, &(rb->retr_timer));
446
-	/* stop final response timer only if I got a final response */
447
-	if ( msg_class>1 )
448
-		reset_timer( hash_table, &(rb->fr_timer));
449
-
450
-	LOCK_REPLIES( T );
451
-   	/* if a got the first prov. response for an INVITE ->
452
-	   change FR_TIME_OUT to INV_FR_TIME_UT */
453
-	start_fr = !T->inbound_response[branch] && msg_class==1 && is_invite;
454
-
455
-	/* *** store and relay message as needed *** */
456
-	relay = t_should_relay_response( T , msg_status, branch, &save_clone );
457
-
458
-	if (save_clone) {
459
-		/* release previously hold message */
460
-		backup = T->inbound_response[branch];
461
-		T->inbound_response[branch] = clone;
462
-		T->tag=&(get_to(clone)->tag_value);
463
-	} else {
464
-		backup = NULL;
465
-		sip_msg_free( clone );
466
-	}
467
-
468
-	if (relay>=0 &&  push_reply_from_uac_to_uas( T, relay)==-1 ) {
469
-		/* restore original state first */
470
-		if (save_clone) T->inbound_response[branch] = backup;
471
-		/* restart FR */
472
-		start_fr=1;
473
-		goto cleanup;
474
-	}
475
-
476
-
477
-	/* *** ACK handling *** */
478
-	if ( is_invite )
479
-	{
480
-		if ( T->outbound_ack[branch] )
481
-		{   /*retransmit*/
482
-			SEND_BUFFER( T->outbound_ack[branch] );
483
-		} else if (msg_class>2 ) {   /*on a non-200 reply to INVITE*/
484
-           		DBG("DEBUG: t_on_reply_received: >=3xx reply to INVITE: send ACK\n");
485
-           		if ( t_build_and_send_ACK( T , branch , p_msg )==-1)
486
-           		{
487
-               		LOG( L_ERR , "ERROR: t_on_reply_received: unable to send ACK\n" );
488
-					/* restart FR */
489
-					start_fr=1;
490
-           		}
491
-       		}
492
-   	}
493
-cleanup:
494
-	UNLOCK_REPLIES( T );
495
-	if (backup) sip_msg_free(backup);
496
-	if (start_fr) set_timer( hash_table, &(rb->fr_timer), FR_INV_TIMER_LIST );
497
-   	/* restart retransmission if a provisional response came for 
498
-	   a non_INVITE -> retrasmit at RT_T2*/
499
-	if ( msg_class==1 && !is_invite )
500
-	{
501
-		rb->retr_list = RT_T2;
502
-		set_timer( hash_table, &(rb->retr_timer), RT_T2 );
503
-	}
504
-error:
505
-	T_UNREF( T );
506
-	/* don't try to relay statelessly on error; on troubles, simply do nothing;
507
-           that will make the other party to retransmit; hopefuly, we'll then 
508
-           be better off */
509
-	return 0;
510
-}
511
-
512 411
 #ifdef _OBSOLETED_TM
513 412
 int t_on_request_received( struct sip_msg  *p_msg , 
514 413
 	unsigned int ip , unsigned int port)
... ...
@@ -612,30 +511,6 @@ int t_release_transaction( struct sip_msg* p_msg)
612 612
 
613 613
 
614 614
 
615
-/* Retransmits the last sent inbound reply.
616
-
617
-  * input: p_msg==request for which I want to retransmit an associated
618
-    reply
619
-  * Returns  -1 -error
620
-  *                1 - OK
621
-  */
622
-int t_retransmit_reply( struct sip_msg* p_msg   )
623
-{
624
-/*	if (t_check( p_msg  , 0 )==-1) return 1; */
625
-
626
-   /* if no transaction exists or no reply to be resend -> out */
627
-/*   if ( T ) */
628
-   {
629
-	LOCK_REPLIES( T );
630
-	SEND_BUFFER( & T->outbound_response );
631
-	UNLOCK_REPLIES( T );
632
-	return 1;
633
-   }
634
-
635
-  /* no transaction found */
636
-/*   return -1; */
637
-}
638
-
639 615
 
640 616
 
641 617
 
... ...
@@ -651,170 +526,6 @@ int t_unref( /* struct sip_msg* p_msg */ )
651 651
 
652 652
 
653 653
 
654
-/* Force a new response into inbound response buffer.
655
-  * returns 1 if everything was OK or -1 for erro
656
-  */
657
-int t_send_reply(  struct sip_msg* p_msg , unsigned int code , char * text )
658
-{
659
-	unsigned int len, buf_len;
660
-	char * buf, *shbuf;
661
-	struct retrans_buff *rb;
662
-
663
-	DBG("DEBUG: t_send_reply: entered\n");
664
-	/* if (t_check( p_msg , 0 )==-1) return -1;
665
-
666
-	if (!T)
667
-	{
668
-		LOG(L_ERR, "ERROR: t_send_reply: cannot send a t_reply to a message "
669
-			"for which no T-state has been established\n");
670
-		return -1;
671
-	}
672
-	*/
673
-
674
-	buf = build_res_buf_from_sip_req(code,text,0,0,T->inbound_request,&len);
675
-	DBG("DEBUG: t_send_reply: buffer computed\n");
676
-	if (!buf)
677
-	{
678
-		DBG("DEBUG: t_send_reply: response building failed\n");
679
-		goto error;
680
-	}
681
-
682
-	LOCK_REPLIES( T );
683
-
684
-	rb = & T->outbound_response;
685
-	if (!rb->retr_buffer) {
686
-		/* initialize retransmission structure */
687
-		memset( rb , 0 , sizeof (struct retrans_buff) );
688
-		if (update_sock_struct_from_via(  &(rb->to),  p_msg->via1 )==-1)
689
-		{
690
-			LOG(L_ERR, "ERROR: t_send_reply: cannot lookup reply dst: %s\n",
691
-				p_msg->via1->host.s );
692
-			goto error2;
693
-		}
694
-
695
-		rb->retr_timer.tg=TG_RT;
696
-		rb->fr_timer.tg=TG_FR;
697
-		rb->retr_timer.payload = rb;
698
-		rb->fr_timer.payload = rb;
699
-		rb->to.sin_family = AF_INET;
700
-		rb->my_T = T;
701
-		rb->reply = code;
702
-	}
703
-
704
-
705
-	/* if this is a first reply (?100), longer replies will probably follow;
706
-	   try avoiding shm_resize by higher buffer size */
707
-	buf_len = rb->retr_buffer ? len : len + REPLY_OVERBUFFER_LEN;
708
-
709
-	if (! (rb->retr_buffer = (char*)shm_resize( rb->retr_buffer, buf_len )))
710
-	{
711
-		LOG(L_ERR, "ERROR: t_send_reply: cannot allocate shmem buffer\n");
712
-		goto error2;
713
-	}
714
-	rb->bufflen = len ;
715
-	memcpy( rb->retr_buffer , buf , len );
716
-	T->status = code;
717
-	SEND_BUFFER( rb );
718
-	/* needs to be protected too because what timers are set depends
719
-	   on current transactions status
720
-	*/
721
-	t_update_timers_after_sending_reply( rb );
722
-	UNLOCK_REPLIES( T );
723
-
724
-	free( buf ) ;
725
-	/* start/stops the proper timers*/
726
-
727
-	DBG("DEBUG: t_send_reply: finished\n");
728
-
729
-	return 1;
730
-
731
-error2:
732
-	free ( buf );
733
-error:
734
-	return -1;
735
-}
736
-
737
-
738
-
739
-/* Push a previously stored reply from UA Client to UA Server
740
-  * and send it out
741
-  */
742
-static int push_reply_from_uac_to_uas( struct cell* trans , unsigned int branch )
743
-{
744
-	char *buf;
745
-	unsigned int len, buf_len;
746
-	struct retrans_buff *rb;
747
-
748
-	DBG("DEBUG: push_reply_from_uac_to_uas: start\n");
749
-	rb= & trans->outbound_response;
750
-	/* if there is a reply, release the buffer (everything else stays same) */
751
-	if ( ! rb->retr_buffer ) {
752
-		/*init retrans buffer*/
753
-		memset( rb , 0 , sizeof (struct retrans_buff) );
754
-		if (update_sock_struct_from_via(  &(rb->to),
755
-			trans->inbound_response[branch]->via2 )==-1) {
756
-				LOG(L_ERR, "ERROR: push_reply_from_uac_to_uas: "
757
-					"cannot lookup reply dst: %s\n",
758
-				trans->inbound_response[branch]->via2->host.s );
759
-				goto error;
760
-		}
761
-		rb->retr_timer.tg=TG_RT;
762
-		rb->fr_timer.tg=TG_FR;
763
-		rb->retr_timer.payload = rb;
764
-		rb->fr_timer.payload =  rb;
765
-		rb->to.sin_family = AF_INET;
766
-		rb->my_T = trans;
767
-		rb->reply = trans->inbound_response[branch]->REPLY_STATUS;
768
-
769
-	} else {
770
-		reset_timer( hash_table, &(rb->retr_timer));
771
-		reset_timer( hash_table, &(rb->fr_timer));
772
-	}
773
-
774
-	/*  generate the retrans buffer */
775
-	buf = build_res_buf_from_sip_res ( trans->inbound_response[branch], &len);
776
-	if (!buf) {
777
-		LOG(L_ERR, "ERROR: push_reply_from_uac_to_uas: "
778
-			"no shmem for outbound reply buffer\n");
779
-		goto error;
780
-	}
781
-
782
-	/* if this is a first reply (?100), longer replies will probably follow;
783
-	try avoiding shm_resize by higher buffer size */
784
-	buf_len = rb->retr_buffer ? len : len + REPLY_OVERBUFFER_LEN;
785
-	if (! (rb->retr_buffer = (char*)shm_resize( rb->retr_buffer, buf_len )))
786
-	{
787
-		LOG(L_ERR, "ERROR: t_send_reply: cannot allocate shmem buffer\n");
788
-		goto error1;
789
-	}
790
-	rb->bufflen = len ;
791
-	memcpy( rb->retr_buffer , buf , len );
792
-	free( buf ) ;
793
-
794
-	/* update the status*/
795
-	trans->status = trans->inbound_response[branch]->REPLY_STATUS;
796
-	if ( trans->inbound_response[branch]->REPLY_STATUS>=200 &&
797
-		trans->relaied_reply_branch==-1 ) {
798
-
799
-		memcpy( & trans->ack_to, & trans->outbound_request[ branch ]->to,
800
-			sizeof( struct sockaddr_in ) );
801
-		trans->relaied_reply_branch = branch;
802
-	}
803
-
804
-	/* start/stops the proper timers*/
805
-	t_update_timers_after_sending_reply( rb );
806
-
807
-	/*send the reply*/
808
-	SEND_BUFFER( rb );
809
-	return 1;
810
-
811
-error1:
812
-	free( buf );
813
-error:
814
-	return -1;
815
-}
816
-
817
-
818 654
 
819 655
 
820 656
 
... ...
@@ -941,11 +652,30 @@ int t_put_on_wait(  struct cell  *Trans  )
941 941
 	unsigned int i;
942 942
 	struct retrans_buff* rb;
943 943
 
944
+#ifndef WAIT
944 945
 	if (is_in_timer_list2( &(Trans->wait_tl)))
945 946
   	{
946 947
 		DBG("DEBUG: t_put_on_wait: already on wait\n");
947 948
 		return 1;
948 949
 	}
950
+#else
951
+	/* have some race conditons occured and we already
952
+	  entered/passed the wait status previously?
953
+	  if so, exit now
954
+	*/
955
+
956
+	LOCK_WAIT(T);
957
+	if (Trans->on_wait)
958
+	{
959
+		DBG("DEBUG: t_put_on_wait: already on wait\n");
960
+		UNLOCK_WAIT(T);
961
+		return 1;
962
+	} else {
963
+		Trans->on_wait=1;
964
+		UNLOCK_WAIT(T);
965
+	};
966
+#endif
967
+
949 968
 
950 969
 	/* remove from  retranssmision  and  final response   list */
951 970
 	DBG("DEBUG: t_put_on_wait: stopping timers (FR and RETR)\n");
... ...
@@ -1402,9 +1132,13 @@ void retransmission_handler( void *attr)
1402 1402
 	/* retransmision */
1403 1403
 	DBG("DEBUG: retransmission_handler : resending (t=%p)\n", r_buf->my_T);
1404 1404
 	if (r_buf->reply) {
1405
+		T=r_buf->my_T;
1406
+/*
1405 1407
 		LOCK_REPLIES( r_buf->my_T );
1406 1408
 		SEND_BUFFER( r_buf );
1407 1409
 		UNLOCK_REPLIES( r_buf->my_T );
1410
+*/
1411
+		t_retransmit_reply();
1408 1412
 	}else{
1409 1413
 		SEND_BUFFER( r_buf );
1410 1414
 	}
... ...
@@ -33,16 +33,35 @@ extern struct s_table*  hash_table;
33 33
 #include "sip_msg.h"
34 34
 
35 35
 
36
-#define LOCK_REPLIES(_t) lock(&((_t)->reply_mutex) )
37
-#define UNLOCK_REPLIES(_t) unlock(&((_t)->reply_mutex) )
38
-#define LOCK_ACK(_t) lock(&((_t)->ack_mutex) )
39
-#define UNLOCK_ACK(_t) unlock(&((_t)->ack_mutex) )
36
+#define LOCK_REPLIES(_t) lock(&(_t)->reply_mutex )
37
+#define UNLOCK_REPLIES(_t) unlock(&(_t)->reply_mutex )
38
+#define LOCK_ACK(_t) lock(&(_t)->ack_mutex )
39
+#define UNLOCK_ACK(_t) unlock(&(_t)->ack_mutex )
40
+#define LOCK_WAIT(_t) lock(&(_t)->wait_mutex )
41
+#define UNLOCK_WAIT(_t) unlock(&(_t)->wait_mutex )
40 42
 
41 43
 
42 44
 /* convenience short-cut macros */
43 45
 #define REQ_METHOD first_line.u.request.method_value
44 46
 #define REPLY_STATUS first_line.u.reply.statuscode
45 47
 #define REPLY_CLASS(_reply) ((_reply)->REPLY_STATUS/100)
48
+
49
+/* send a private buffer: utilize a retransmission structure
50
+   but take a separate buffer not refered by it; healthy
51
+   for reducing time spend in REPLIES locks
52
+*/
53
+
54
+#define SEND_PR_BUFFER(_rb,_bf,_le ) ({ if ((_rb)->retr_buffer) \
55
+	{ udp_send( (_bf), (_le), (struct sockaddr*)&((_rb)->to) , \
56
+	   sizeof(struct sockaddr_in) ); \
57
+	} else { \
58
+	DBG("ERROR: attempt to send an empty buffer from %s (%d)", \
59
+	__FUNCTION__, __LINE__ ); }})
60
+
61
+#define SEND_BUFFER( _rb ) SEND_PR_BUFFER( \
62
+	_rb,(_rb)->retr_buffer, (_rb)->bufflen )
63
+
64
+/*
46 65
 #define SEND_BUFFER( _rb ) ({ if ((_rb)->retr_buffer) \
47 66
 	{ udp_send( (_rb)->retr_buffer, \
48 67
 	  (_rb)->bufflen, (struct sockaddr*)&((_rb)->to) , \
... ...
@@ -50,6 +69,7 @@ extern struct s_table*  hash_table;
50 50
 	} else \
51 51
 	DBG("ERROR: attempt to send an empty buffer from %s (%d)", \
52 52
 	__FUNCTION__, __LINE__ ); })
53
+*/
53 54
 
54 55
 
55 56
 /* 
... ...
@@ -165,7 +185,12 @@ int t_forward_uri( struct sip_msg* p_msg  );
165 165
   *  Returns :   0 - core router stops
166 166
   *                    1 - core router relay statelessly
167 167
   */
168
+
169
+#ifdef SRL
170
+int t_on_reply( struct sip_msg  *p_msg ) ;
171
+#else
168 172
 int t_on_reply_received( struct sip_msg  *p_msg ) ;
173
+#endif
169 174
 
170 175
 
171 176
 
... ...
@@ -201,7 +226,7 @@ int t_release_transaction( struct sip_msg* );
201 201
   * Returns  -1 -error
202 202
   *                1 - OK
203 203
   */
204
-int t_retransmit_reply( struct sip_msg *  );
204
+int t_retransmit_reply( /* struct sip_msg * */  );
205 205
 
206 206
 
207 207
 
... ...
@@ -234,7 +259,14 @@ int t_should_relay_response( struct cell *Trans, int new_code, int branch, int *
234 234
 int t_update_timers_after_sending_reply( struct retrans_buff *rb );
235 235
 int t_put_on_wait(  struct cell  *Trans  );
236 236
 int relay_lowest_reply_upstream( struct cell *Trans , struct sip_msg *p_msg );
237
+
238
+#ifdef SRL
239
+static int push_reply( struct cell* trans , unsigned int branch , 
240
+    char *buf, unsigned int len);
241
+#else
237 242
 static int push_reply_from_uac_to_uas( struct cell* Trans , unsigned int );
243
+#endif
244
+
238 245
 int add_branch_label( struct cell *Trans, struct sip_msg *p_msg , int branch );
239 246
 int get_ip_and_port_from_uri( struct sip_msg* p_msg , unsigned int *param_ip, unsigned int *param_port);
240 247
 
... ...
@@ -33,11 +33,11 @@ int t_forward_nonack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
33 33
 
34 34
 	if ( T->outbound_request[branch]==NULL )
35 35
 	{
36
-		DBG("DEBUG: t_forward: first time forwarding\n");
36
+		DBG("DEBUG: t_forward_nonack: first time forwarding\n");
37 37
 		/* special case : CANCEL */
38 38
 		if ( p_msg->REQ_METHOD==METHOD_CANCEL  )
39 39
 		{
40
-			DBG("DEBUG: t_forward: it's CANCEL\n");
40
+			DBG("DEBUG: t_forward_nonack: it's CANCEL\n");
41 41
 			/* find original cancelled transaction; if found, use its
42 42
 			   next-hops; otherwise use those passed by script */
43 43
 			if ( T->T_canceled==T_UNDEFINED )
... ...
@@ -48,7 +48,7 @@ int t_forward_nonack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
48 48
 				/* if in 1xx status, send to the same destination */
49 49
 				if ( (T->T_canceled->status/100)==1 )
50 50
 				{
51
-					DBG("DEBUG: t_forward: it's CANCEL and I will send "
51
+					DBG("DEBUG: t_forward_nonack: it's CANCEL and I will send "
52 52
 						"to the same place where INVITE went\n");
53 53
 					dest_ip=T->T_canceled->outbound_request[branch]->
54 54
 						to.sin_addr.s_addr;
... ...
@@ -59,12 +59,12 @@ int t_forward_nonack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
59 59
 					T->label  = T->T_canceled->label;
60 60
 #endif
61 61
 				} else { /* transaction exists, but nothing to cancel */
62
-					DBG("DEBUG: t_forward: it's CANCEL but "
62
+					DBG("DEBUG: t_forward_nonack: it's CANCEL but "
63 63
 						"I have nothing to cancel here\n");
64 64
 					/* forward CANCEL as a stand-alone transaction */
65 65
 				}
66 66
 			} else { /* transaction doesnot exists  */
67
-				DBG("DEBUG: t_forward: canceled request not found! "
67
+				DBG("DEBUG: t_forward_nonack: canceled request not found! "
68 68
 				"nothing to CANCEL\n");
69 69
 			}
70 70
 		}/* end special case CANCEL*/
... ...
@@ -77,19 +77,19 @@ int t_forward_nonack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
77 77
 			goto error;
78 78
 
79 79
 		/* allocates a new retrans_buff for the outbound request */
80
-		DBG("DEBUG: t_forward: building outbound request\n");
80
+		DBG("DEBUG: t_forward_nonack: building outbound request\n");
81 81
 		shm_lock();
82 82
 		rb = (struct retrans_buff*) shm_malloc_unsafe( sizeof(struct retrans_buff)  );
83 83
 		if (!rb)
84 84
 		{
85
-			LOG(L_ERR, "ERROR: t_forward: out of shmem\n");
85
+			LOG(L_ERR, "ERROR: t_forward_nonack: out of shmem\n");
86 86
 			shm_unlock();
87 87
 			goto error;
88 88
 		}
89 89
 		shbuf = (char *) shm_malloc_unsafe( len );
90 90
 		if (!shbuf)
91 91
 		{
92
-			LOG(L_ERR, "ERROR: t_forward: out of shmem buffer\n");
92
+			LOG(L_ERR, "ERROR: t_forward_nonack: out of shmem buffer\n");
93 93
 			shm_unlock();
94 94
 			goto error;
95 95
 		}
... ...
@@ -114,9 +114,11 @@ int t_forward_nonack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
114 114
 		/* link the retransmission buffer to our structures when the job is done */
115 115
 		free( buf ) ; buf=NULL;
116 116
 
117
-		DBG("DEBUG: t_forward: starting timers (retrans and FR) %d\n",get_ticks() );
117
+		DBG("DEBUG: t_forward_nonack: starting timers (retrans and FR) %d\n",get_ticks() );
118 118
 		/*sets and starts the FINAL RESPONSE timer */
119
+#ifdef FR
119 120
 		set_timer( hash_table, &(rb->fr_timer), FR_TIMER_LIST );
121
+#endif
120 122
 
121 123
 		/* sets and starts the RETRANS timer */
122 124
 		rb->retr_list = RT_T1_TO_1;
... ...
@@ -132,12 +134,14 @@ int t_forward_nonack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
132 132
 
133 133
 	if (  p_msg->REQ_METHOD==METHOD_CANCEL )
134 134
 	{
135
-		DBG("DEBUG: t_forward: forwarding CANCEL\n");
135
+		DBG("DEBUG: t_forward_nonack: forwarding CANCEL\n");
136 136
 		/* if no transaction to CANCEL */
137 137
 		/* or if the canceled transaction has a final status -> drop the CANCEL*/
138 138
 		if ( T->T_canceled!=T_NULL && T->T_canceled->status>=200)
139 139
 		{
140
+#ifdef FR
140 141
 			reset_timer( hash_table, &(rb->fr_timer ));
142
+#endif
141 143
 			reset_timer( hash_table, &(rb->retr_timer ));
142 144
 			return 1;
143 145
 		}
... ...
@@ -182,7 +186,7 @@ int t_forward_ack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
182 182
 		return -1;
183 183
 	}
184 184
 
185
-	DBG("DEBUG: t_forward: forwarding ACK [%d]\n",branch);
185
+	DBG("DEBUG: t_forward_ack: forwarding ACK [%d]\n",branch);
186 186
 	/* not able to build branch -- then better give up */
187 187
 	if ( add_branch_label( T, p_msg , branch )==-1) {
188 188
 		LOG( L_ERR, "ERROR: t_forward_ack failed to add branch label\n" );
189 189
new file mode 100644
... ...
@@ -0,0 +1,520 @@
0
+/*
1
+ * $Id$
2
+ *
3
+ */
4
+
5
+
6
+#include "hash_func.h"
7
+#include "t_funcs.h"
8
+#include "../../dprint.h"
9
+#include "../../config.h"
10
+#include "../../parser_f.h"
11
+#include "../../ut.h"
12
+#include "../../timer.h"
13
+
14
+#ifndef SRL
15
+/*  This function is called whenever a reply for our module is received; 
16
+  * we need to register  this function on module initialization;
17
+  *  Returns :   0 - core router stops
18
+  *              1 - core router relay statelessly
19
+  */
20
+int t_on_reply_received( struct sip_msg  *p_msg )
21
+{
22
+	unsigned int  branch,len, msg_status, msg_class, save_clone;
23
+	struct sip_msg *clone, *backup;
24
+	int relay;
25
+	int start_fr;
26
+	int is_invite;
27
+	struct retrans_buff *rb;
28
+
29
+
30
+	/* make sure we know the assosociated tranaction ... */
31
+	if (t_check( p_msg  , &branch )==-1) return 1;
32
+	/* ... if there is no such, tell the core router to forward statelessly */
33
+	if ( T<=0 ) return 1;
34
+
35
+	DBG("DEBUG: t_on_reply_received: Original status =%d\n",T->status);
36
+
37
+	/* it can take quite long -- better do it now than later 
38
+	   inside a reply_lock */
39
+	if (!(clone=sip_msg_cloner( p_msg ))) {
40
+		goto error;
41
+	}
42
+	msg_status=p_msg->REPLY_STATUS;
43
+	msg_class=REPLY_CLASS(p_msg);
44
+	is_invite= T->inbound_request->REQ_METHOD==METHOD_INVITE;
45
+
46
+	/* *** stop timers *** */
47
+	rb=T->outbound_request[branch];
48
+	/* stop retransmission */
49
+	reset_timer( hash_table, &(rb->retr_timer));
50
+	/* stop final response timer only if I got a final response */
51
+	if ( msg_class>1 )
52
+		reset_timer( hash_table, &(rb->fr_timer));
53
+
54
+	LOCK_REPLIES( T );
55
+   	/* if a got the first prov. response for an INVITE ->
56
+	   change FR_TIME_OUT to INV_FR_TIME_UT */
57
+	start_fr = !T->inbound_response[branch] && msg_class==1 && is_invite;
58
+
59
+	/* *** store and relay message as needed *** */
60
+	relay = t_should_relay_response( T , msg_status, branch, &save_clone );
61
+
62
+	if (save_clone) {
63
+		/* release previously hold message */
64
+		backup = T->inbound_response[branch];
65
+		T->inbound_response[branch] = clone;
66
+		T->tag=&(get_to(clone)->tag_value);
67
+	} else {
68
+		backup = NULL;
69
+		sip_msg_free( clone );
70
+	}
71
+
72
+	if (relay>=0 &&  
73
+	push_reply_from_uac_to_uas( T, relay  ) == -1 ) {
74
+		/* restore original state first */
75
+		if (save_clone) T->inbound_response[branch] = backup;
76
+		/* restart FR */
77
+		start_fr=1;
78
+		goto cleanup;
79
+	}
80
+
81
+
82
+	/* *** ACK handling *** */
83
+	if ( is_invite )
84
+	{
85
+		if ( T->outbound_ack[branch] )
86
+		{   /*retransmit*/
87
+			SEND_BUFFER( T->outbound_ack[branch] );
88
+		} else if (msg_class>2 ) {   /*on a non-200 reply to INVITE*/
89
+           		DBG("DEBUG: t_on_reply_received: >=3xx reply to INVITE: send ACK\n");
90
+           		if ( t_build_and_send_ACK( T , branch , p_msg )==-1)
91
+           		{
92
+               		LOG( L_ERR , "ERROR: t_on_reply_received: unable to send ACK\n" );
93
+					/* restart FR */
94
+					start_fr=1;
95
+           		}
96
+       		}
97
+   	}
98
+cleanup:
99
+	UNLOCK_REPLIES( T );
100
+	if (backup) sip_msg_free(backup);
101
+	if (start_fr) set_timer( hash_table, &(rb->fr_timer), FR_INV_TIMER_LIST );
102
+   	/* restart retransmission if a provisional response came for 
103
+	   a non_INVITE -> retrasmit at RT_T2*/
104
+	if ( msg_class==1 && !is_invite )
105
+	{
106
+		rb->retr_list = RT_T2;
107
+		set_timer( hash_table, &(rb->retr_timer), RT_T2 );
108
+	}
109
+error:
110
+	T_UNREF( T );
111
+	/* don't try to relay statelessly on error; on troubles, simply do nothing;
112
+           that will make the other party to retransmit; hopefuly, we'll then 
113
+           be better off */
114
+	return 0;
115
+}
116
+#endif
117
+
118
+
119
+
120
+/* Retransmits the last sent inbound reply.
121
+
122
+  * input: p_msg==request for which I want to retransmit an associated
123
+    reply
124
+  * Returns  -1 -error
125
+  *                1 - OK
126
+  */
127
+int t_retransmit_reply( /* struct sip_msg* p_msg    */ )
128
+{
129
+
130
+#ifdef SRL
131
+	void *b;
132
+	int len;
133
+#endif
134
+	LOCK_REPLIES( T );
135
+
136
+#ifdef SRL
137
+	if (!(b=pkg_malloc( len=T->outbound_response.bufflen ))) {
138
+		UNLOCK_REPLIES( T );
139
+		return -1;
140
+	};
141
+	memcpy( b, T->outbound_response.retr_buffer, len );
142
+#else
143
+	SEND_BUFFER( & T->outbound_response );
144
+#endif
145
+	UNLOCK_REPLIES( T );
146
+
147
+#ifdef SRL
148
+	SEND_PR_BUFFER( & T->outbound_response, b, len );
149
+	pkg_free( b );
150
+#endif
151
+	return 1;
152
+}
153
+
154
+/* Force a new response into inbound response buffer.
155
+  * returns 1 if everything was OK or -1 for erro
156
+  */
157
+int t_send_reply(  struct sip_msg* p_msg , unsigned int code , char * text )
158
+{
159
+	unsigned int len, buf_len;
160
+	char * buf, *shbuf;
161
+	struct retrans_buff *rb;
162
+
163
+	DBG("DEBUG: t_send_reply: entered\n");
164
+
165
+	buf = build_res_buf_from_sip_req(code,text,0,0,T->inbound_request,&len);
166
+	DBG("DEBUG: t_send_reply: buffer computed\n");
167
+	if (!buf)
168
+	{
169
+		DBG("DEBUG: t_send_reply: response building failed\n");
170
+		goto error;
171
+	}
172
+
173
+	LOCK_REPLIES( T );
174
+
175
+	rb = & T->outbound_response;
176
+	if (!rb->retr_buffer) {
177
+		/* initialize retransmission structure */
178
+		memset( rb , 0 , sizeof (struct retrans_buff) );
179
+		if (update_sock_struct_from_via(  &(rb->to),  p_msg->via1 )==-1)
180
+		{
181
+			UNLOCK_REPLIES( T );
182
+			LOG(L_ERR, "ERROR: t_send_reply: cannot lookup reply dst: %s\n",
183
+				p_msg->via1->host.s );
184
+			goto error2;
185
+		}
186
+
187
+		rb->retr_timer.tg=TG_RT;
188
+		rb->fr_timer.tg=TG_FR;
189
+		rb->retr_timer.payload = rb;
190
+		rb->fr_timer.payload = rb;
191
+		rb->to.sin_family = AF_INET;
192
+		rb->my_T = T;
193
+		rb->reply = code;
194
+	}
195
+
196
+
197
+	/* if this is a first reply (?100), longer replies will probably follow;
198
+	   try avoiding shm_resize by higher buffer size */
199
+	buf_len = rb->retr_buffer ? len : len + REPLY_OVERBUFFER_LEN;
200
+
201
+	if (! (rb->retr_buffer = (char*)shm_resize( rb->retr_buffer, buf_len )))
202
+	{
203
+		UNLOCK_REPLIES( T );
204
+		LOG(L_ERR, "ERROR: t_send_reply: cannot allocate shmem buffer\n");
205
+		goto error2;
206
+	}
207
+	rb->bufflen = len ;
208
+	memcpy( rb->retr_buffer , buf , len );
209
+	T->status = code;
210
+#ifndef SRL
211
+	SEND_BUFFER( rb );
212
+#endif
213
+	/* needs to be protected too because what timers are set depends
214
+	   on current transactions status
215
+	*/
216
+	t_update_timers_after_sending_reply( rb );
217
+	UNLOCK_REPLIES( T );
218
+
219
+#ifdef SRL
220
+	SEND_PR_BUFFER( rb, buf, len );
221
+#endif
222
+
223
+	free( buf ) ;
224
+	/* start/stops the proper timers*/
225
+
226
+	DBG("DEBUG: t_send_reply: finished\n");
227
+
228
+	return 1;
229
+
230
+error2:
231
+	free ( buf );
232
+error:
233
+	return -1;
234
+}
235
+
236
+
237
+
238
+
239
+/* Push a previously stored reply from UA Client to UA Server
240
+  * and send it out
241
+  */
242
+static int push_reply_from_uac_to_uas( struct cell* trans , unsigned int branch 
243
+#ifdef SRL
244
+	, char *buf, unsigned int len
245
+#endif
246
+	)
247
+{
248
+	unsigned int buf_len;
249
+	struct retrans_buff *rb;
250
+#ifndef SRL
251
+	char *buf;
252
+	unsigned int len;
253
+#endif
254
+
255
+	DBG("DEBUG: push_reply_from_uac_to_uas: start\n");
256
+	rb= & trans->outbound_response;
257
+	/* if there is a reply, release the buffer (everything else stays same) */
258
+	if ( ! rb->retr_buffer ) {
259
+		/*init retrans buffer*/
260
+		memset( rb , 0 , sizeof (struct retrans_buff) );
261
+		if (update_sock_struct_from_via(  &(rb->to),
262
+			trans->inbound_response[branch]->via2 )==-1) {
263
+				LOG(L_ERR, "ERROR: push_reply_from_uac_to_uas: "
264
+					"cannot lookup reply dst: %s\n",
265
+				trans->inbound_response[branch]->via2->host.s );
266
+				goto error;
267
+		}
268
+		rb->retr_timer.tg=TG_RT;
269
+		rb->fr_timer.tg=TG_FR;
270
+		rb->retr_timer.payload = rb;
271
+		rb->fr_timer.payload =  rb;
272
+		rb->to.sin_family = AF_INET;
273
+		rb->my_T = trans;
274
+		rb->reply = trans->inbound_response[branch]->REPLY_STATUS;
275
+
276
+	} else {
277
+#ifndef SRL
278
+		reset_timer( hash_table, &(rb->retr_timer));
279
+		reset_timer( hash_table, &(rb->fr_timer));
280
+#endif
281
+	}
282
+
283
+#ifndef SRL
284
+	/*  generate the retrans buffer */
285
+	buf = build_res_buf_from_sip_res ( trans->inbound_response[branch], &len);
286
+	if (!buf) {
287
+		LOG(L_ERR, "ERROR: push_reply_from_uac_to_uas: "
288
+			"no shmem for outbound reply buffer\n");
289
+		goto error;
290
+	}
291
+#endif
292
+
293
+	/* if this is a first reply (?100), longer replies will probably follow;
294
+	try avoiding shm_resize by higher buffer size */
295
+	buf_len = rb->retr_buffer ? len : len + REPLY_OVERBUFFER_LEN;
296
+	if (! (rb->retr_buffer = (char*)shm_resize( rb->retr_buffer, buf_len )))
297
+	{
298
+		LOG(L_ERR, "ERROR: t_push: cannot allocate shmem buffer\n");
299
+		goto error1;
300
+	}
301
+	rb->bufflen = len ;
302
+	memcpy( rb->retr_buffer , buf , len );
303
+#ifndef SRL
304
+	free( buf ) ;
305
+#endif
306
+
307
+	/* update the status*/
308
+	trans->status = trans->inbound_response[branch]->REPLY_STATUS;
309
+	if ( trans->inbound_response[branch]->REPLY_STATUS>=200 &&
310
+		trans->relaied_reply_branch==-1 ) {
311
+
312
+		memcpy( & trans->ack_to, & trans->outbound_request[ branch ]->to,
313
+			sizeof( struct sockaddr_in ) );
314
+		trans->relaied_reply_branch = branch;
315
+	}
316
+
317
+#ifndef SRL
318
+	/* start/stops the proper timers*/
319
+	t_update_timers_after_sending_reply( rb );
320
+#endif
321
+
322
+	/*send the reply*/
323
+	SEND_BUFFER( rb );
324
+	return 1;
325
+
326
+error1:
327
+#ifndef SRL
328
+	free( buf );
329
+#endif
330
+error:
331
+	return -1;
332
+}
333
+
334
+/* Push a previously stored reply from UA Client to UA Server
335
+  * and send it out
336
+  */
337
+static int push_reply( struct cell* trans , unsigned int branch , 
338
+	char *buf, unsigned int len)
339
+{
340
+	unsigned int buf_len;
341
+	struct retrans_buff *rb;
342
+
343
+	DBG("DEBUG: push_reply_from_uac_to_uas: start\n");
344
+	rb= & trans->outbound_response;
345
+	/* if there is a reply, release the buffer (everything else stays same) */
346
+	if ( ! rb->retr_buffer ) {
347
+		/*init retrans buffer*/
348
+		memset( rb , 0 , sizeof (struct retrans_buff) );
349
+		if (update_sock_struct_from_via(  &(rb->to),
350
+			trans->inbound_response[branch]->via2 )==-1) {
351
+				LOG(L_ERR, "ERROR: push_reply_from_uac_to_uas: "
352
+					"cannot lookup reply dst: %s\n",
353
+				trans->inbound_response[branch]->via2->host.s );
354
+				goto error;
355
+		}
356
+		rb->retr_timer.tg=TG_RT;
357
+		rb->fr_timer.tg=TG_FR;
358
+		rb->retr_timer.payload = rb;
359
+		rb->fr_timer.payload =  rb;
360
+		rb->to.sin_family = AF_INET;
361
+		rb->my_T = trans;
362
+		rb->reply = trans->inbound_response[branch]->REPLY_STATUS;
363
+	};
364
+
365
+	/* if this is a first reply (?100), longer replies will probably follow;
366
+	try avoiding shm_resize by higher buffer size */
367
+	buf_len = rb->retr_buffer ? len : len + REPLY_OVERBUFFER_LEN;
368
+	if (! (rb->retr_buffer = (char*)shm_resize( rb->retr_buffer, buf_len )))
369
+	{
370
+		LOG(L_ERR, "ERROR: t_push: cannot allocate shmem buffer\n");
371
+		goto error1;
372
+	}
373
+	rb->bufflen = len ;
374
+	memcpy( rb->retr_buffer , buf , len );
375
+
376
+	/* update the status*/
377
+	trans->status = trans->inbound_response[branch]->REPLY_STATUS;
378
+	if ( trans->inbound_response[branch]->REPLY_STATUS>=200 &&
379
+		trans->relaied_reply_branch==-1 ) {
380
+
381
+		memcpy( & trans->ack_to, & trans->outbound_request[ branch ]->to,
382
+			sizeof( struct sockaddr_in ) );
383
+		trans->relaied_reply_branch = branch;
384
+	}
385
+
386
+	/*send the reply*/
387
+	SEND_BUFFER( rb );
388
+	return 1;
389
+
390
+error1:
391
+error:
392
+	return -1;
393
+}
394
+
395
+#ifdef SRL
396
+/*  This function is called whenever a reply for our module is received; 
397
+  * we need to register  this function on module initialization;
398
+  *  Returns :   0 - core router stops
399
+  *              1 - core router relay statelessly
400
+  */
401
+int t_on_reply( struct sip_msg  *p_msg )
402
+{
403
+	unsigned int  branch,len, msg_status, msg_class, save_clone;
404
+	struct sip_msg *clone, *backup;
405
+	int relay;
406
+	int start_fr;
407
+	int is_invite;
408
+	struct retrans_buff *rb;
409
+	char *buf;
410
+	unsigned int buf_len;
411
+
412
+
413
+	/* make sure we know the assosociated tranaction ... */
414
+	if (t_check( p_msg  , &branch )==-1) return 1;
415
+	/* ... if there is no such, tell the core router to forward statelessly */
416
+	if ( T<=0 ) return 1;
417
+
418
+	DBG("DEBUG: t_on_reply_received: Original status =%d\n",T->status);
419
+
420
+	/* it can take quite long -- better do it now than later 
421
+	   inside a reply_lock */
422
+	if (!(clone=sip_msg_cloner( p_msg ))) {
423
+		goto error;
424
+	}
425
+	msg_status=p_msg->REPLY_STATUS;
426
+	msg_class=REPLY_CLASS(p_msg);
427
+	is_invite= T->inbound_request->REQ_METHOD==METHOD_INVITE;
428
+
429
+    /*  generate the retrans buffer, make a simplified
430
+	    assumption everything but 100 will be fwd-ed;
431
+		sometimes it will result in useless CPU cycles
432
+		but mostly the assumption holds and allows the
433
+		work to be done out of criticial lock region
434
+	 */
435
+	if (msg_status==100) buf=0;
436
+	else {
437
+		buf = build_res_buf_from_sip_res ( p_msg, &buf_len);
438
+		if (!buf) {
439
+			LOG(L_ERR, "ERROR: t_on_reply_received: "
440
+			"no mem for outbound reply buffer\n");
441
+			sip_msg_free( clone );
442
+			goto error;
443
+		}
444
+	}
445
+
446
+	/* *** stop timers *** */
447
+	rb=T->outbound_request[branch];
448
+	/* stop retransmission */
449
+	reset_timer( hash_table, &(rb->retr_timer));
450
+	/* stop final response timer only if I got a final response */
451
+	if ( msg_class>1 )
452
+		reset_timer( hash_table, &(rb->fr_timer));
453
+
454
+	LOCK_REPLIES( T );
455
+   	/* if a got the first prov. response for an INVITE ->
456
+	   change FR_TIME_OUT to INV_FR_TIME_UT */
457
+	start_fr = !T->inbound_response[branch] && msg_class==1 && is_invite;
458
+
459
+	/* *** store and relay message as needed *** */
460
+	relay = t_should_relay_response( T , msg_status, branch, &save_clone );
461
+
462
+	if (save_clone) {
463
+		/* release previously hold message */
464
+		backup = T->inbound_response[branch];
465
+		T->inbound_response[branch] = clone;
466
+		T->tag=&(get_to(clone)->tag_value);
467
+	} else {
468
+		backup = NULL;
469
+		sip_msg_free( clone );
470
+	}
471
+
472
+	if (relay>=0 &&  
473
+	push_reply( T, relay , buf, buf_len ) == -1 ) {
474
+		/* restore original state first */
475
+		if (save_clone) T->inbound_response[branch] = backup;
476
+		/* restart FR */
477
+		start_fr=1;
478
+		goto cleanup;
479
+	}
480
+
481
+
482
+	/* *** ACK handling *** */
483
+	if ( is_invite )
484
+	{
485
+		if ( T->outbound_ack[branch] )
486
+		{   /*retransmit*/
487
+			SEND_BUFFER( T->outbound_ack[branch] );
488
+		} else if (msg_class>2 ) {   /*on a non-200 reply to INVITE*/
489
+           		DBG("DEBUG: t_on_reply_received: >=3xx reply to INVITE: send ACK\n");
490
+           		if ( t_build_and_send_ACK( T , branch , p_msg )==-1)
491
+           		{
492
+               		LOG( L_ERR , "ERROR: t_on_reply_received: unable to send ACK\n" );
493
+					/* restart FR */
494
+					start_fr=1;
495
+           		}
496
+       		}
497
+   	}
498
+cleanup:
499
+	UNLOCK_REPLIES( T );
500
+	if (backup) sip_msg_free(backup);
501
+	if (buf) free( buf );
502
+	t_update_timers_after_sending_reply( rb );
503
+	if (start_fr) set_timer( hash_table, &(rb->fr_timer), FR_INV_TIMER_LIST );
504
+   	/* restart retransmission if a provisional response came for 
505
+	   a non_INVITE -> retrasmit at RT_T2*/
506
+	if ( msg_class==1 && !is_invite )
507
+	{
508
+		rb->retr_list = RT_T2;
509
+		set_timer( hash_table, &(rb->retr_timer), RT_T2 );
510
+	}
511
+error:
512
+	T_UNREF( T );
513
+	/* don't try to relay statelessly on error; on troubles, simply do nothing;
514
+           that will make the other party to retransmit; hopefuly, we'll then 
515
+           be better off */
516
+	return 0;
517
+}
518
+
519
+#endif
... ...
@@ -46,6 +46,16 @@ void print_timer_list(struct s_table* hash_table, enum lists list_id)
46 46
 /* static void remove_from_timer_list_dummy(  struct timer_link* tl ) */
47 47
 void remove_timer_unsafe(  struct timer_link* tl )
48 48
 {
49
+#ifdef EXTRA_DEBUG
50
+	if (tl && tl->timer_list &&
51
+		tl->timer_list->last_tl.prev_tl==0) {
52
+		LOG( L_CRIT,
53
+		"CRITICAL : Oh no, zero link in trailing timer element\n");
54
+		abort();
55
+	};
56
+#endif
57
+
58
+
49 59
 	if (is_in_timer_list2( tl )) {
50 60
 		tl->prev_tl->next_tl = tl->next_tl;
51 61
 		tl->next_tl->prev_tl = tl->prev_tl;
... ...
@@ -61,6 +71,14 @@ void remove_timer_unsafe(  struct timer_link* tl )
61 61
 void add_timer_unsafe( struct timer *timer_list,
62 62
 	struct timer_link *tl, unsigned int time_out )
63 63
 {
64
+#ifdef EXTRA_DEBUG
65
+	if (timer_list->last_tl.prev_tl==0) {
66
+	LOG( L_CRIT,
67
+		"CRITICAL : Oh no, zero link in trailing timer element\n");
68
+		abort();
69
+	};
70
+#endif
71
+
64 72
 	/*	remove_from_timer_list( tl ); */
65 73
 	/* the entire timer list is locked now -- noone else can manipulate it */
66 74
 	/* lock( timer_list->mutex ); */
... ...
@@ -116,6 +134,14 @@ struct timer_link  *check_and_split_time_list( struct timer *timer_list, int tim
116 116
 		timer_list->first_tl.next_tl = tl;	
117 117
 		tl->prev_tl = & timer_list->first_tl;
118 118
 	}
119
+#ifdef EXTRA_DEBUG
120
+	if (timer_list->last_tl.prev_tl==0) {
121
+		LOG( L_CRIT,
122
+		"CRITICAL : Oh no, zero link in trailing timer element\n");
123
+		abort();
124
+	};
125
+#endif
126
+
119 127
 
120 128
    /* give the list lock away */
121 129
    unlock(timer_list->mutex);
... ...
@@ -129,7 +129,11 @@ static struct module_exports nm_exports= {
129 129
 #else
130 130
 	10,
131 131
 #endif
132
+#ifdef SRL
133
+	(response_function) t_on_reply,
134
+#else
132 135
 	(response_function) t_on_reply_received,
136
+#endif
133 137
 	(destroy_function) tm_shutdown,
134 138
 	w_onbreak
135 139
 };
... ...
@@ -358,7 +362,7 @@ static int w_t_unref( struct sip_msg* p_msg, char* foo, char* bar )
358 358
 static w_t_retransmit_reply( struct sip_msg* p_msg, char* foo, char* bar  )
359 359
 {
360 360
 	if (t_check( p_msg  , 0 )==-1) return 1;
361
-	if (T) return t_retransmit_reply( p_msg );
361
+	if (T) return t_retransmit_reply( /* p_msg */ );
362 362
 	else return -1;
363 363
 }
364 364
 
... ...
@@ -30,6 +30,7 @@
30 30
 #define HDR_RECORDROUTE  512
31 31
 #define HDR_OTHER       65536 /*unknown header type*/
32 32
 
33
+
33