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 68
 # -DNOSMP
67 69
 #		don't use smp compliant locking (faster but won't work on SMP machines)
68 70
 #		(not yet enabled)
71
+# -DWAIT
72
+#		protection against race condiditions; turn off only for debugging;
73
+#       to become non-optional if stable
74
+# -DNEW_HNAME
75
+#		32-bit header name parsing; turn off for lower speed ;-) or debugging; to become non-optional if fast and stable
76
+# -DSRL Shortened Reply Lock -- moves more code, esp. "send" out
77
+#  of locks for greater speed; to become non-optional if fast and stable
69 78
 
70 79
 DEFS+= -DNAME='"$(NAME)"' -DVERSION='"$(RELEASE)"' -DARCH='"$(ARCH)"' \
71 80
 	 -DOS='"$(OS)"' -DCOMPILER='"$(CC_VER)"'\
72 81
 	 -DDNS_IP_HACK  -DPKG_MALLOC -DSHM_MEM  -DSHM_MMAP \
73 82
 	 -DF_MALLOC  -DUSE_SYNONIM\
74 83
 	 -DNO_DEBUG \
84
+	 -DWAIT -DNEW_HNAME -DNOISY_REPLIES -DSRL
75 85
 	 #-DADAPTIVE_WAIT -DADAPTIVE_WAIT_LOOPS=0 \
76 86
 	 #-DNOSMP \
77 87
 	 #-DEXTRA_DEBUG 
78 88
 	 #-DVQ_MALLOC  -DDBG_LOCK  #-DSTATS
79 89
 	 #-DDBG_QM_MALLOC #-DNO_DEBUG
80
-#-DEXTRA_DEBUG
81 90
 # -DUSE_SHM_MEM
82 91
 #-DNO_DEBUG
83
-#-DPKG_MALLOC
84 92
 #-DNO_DEBUG#-DSTATS -DNO_DEBUG
85 93
 #-DNO_LOG
86 94
 
... ...
@@ -235,7 +243,7 @@ ifeq  ($(OS), SunOS)
235 243
 
236 244
 	YACC=yacc
237 245
 	LIBS+=-L/usr/local/lib -lxnet -lrt # or -lnsl -lsocket or -lglibc ?
238
-	# -lrt needed for sched_yield
246
+	# -lrt needed for sched_yield; some systems may require -lposix4
239 247
 endif
240 248
 
241 249
 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 127
     -h           This help message\n\
127 128
     -b nr        Maximum receive buffer size which will not be exceeded by\n\
128 129
                  auto-probing procedure even if  OS allows\n\
130
+	-m nr        Size of shared memory allocated in Megabytes\n\
129 131
     -w  dir      change the working directory to \"dir\" (default \"/\")\n\
130 132
     -t  dir      chroot to \"dir\"\n\
131 133
     -u uid       change uid \n\
... ...
@@ -141,9 +143,11 @@ void print_ct_constants()
141 143
 #ifdef ADAPTIVE_WAIT
142 144
 	printf("ADAPTIVE_WAIT_LOOPS=%d, ", ADAPTIVE_WAIT_LOOPS);
143 145
 #endif
146
+/*
144 147
 #ifdef SHM_MEM
145 148
 	printf("SHM_MEM_SIZE=%d, ", SHM_MEM_SIZE);
146 149
 #endif
150
+*/
147 151
 	printf("MAX_RECV_BUFFER_SIZE %d, MAX_LISTEN %d,"
148 152
 			" MAX_URI_SIZE %d, MAX_PROCESSES %d\n",
149 153
 		MAX_RECV_BUFFER_SIZE, MAX_LISTEN, MAX_URI_SIZE, MAX_PROCESSES );
... ...
@@ -204,6 +208,9 @@ process_bm_t process_bit = 0;
204 208
 /* cfg parsing */
205 209
 int cfg_errors=0;
206 210
 
211
+/* shared memory (in MB) */
212
+unsigned int shm_mem_size=SHM_MEM_SIZE * 1024 * 1024;
213
+
207 214
 #define MAX_FD 32 /* maximum number of inherited open file descriptors,
208 215
 		    (normally it shouldn't  be bigger  than 3) */
209 216
 
... ...
@@ -483,7 +490,7 @@ int main(int argc, char** argv)
483 490
 #ifdef STATS
484 491
 	"s:"
485 492
 #endif
486
-	"f:p:b:l:n:rRvcdDEVhw:t:u:g:";
493
+	"f:p:m:b:l:n:rRvcdDEVhw:t:u:g:";
487 494
 	
488 495
 	while((c=getopt(argc,argv,options))!=-1){
489 496
 		switch(c){
... ...
@@ -503,6 +510,15 @@ int main(int argc, char** argv)
503 510
 					}
504 511
 					break;
505 512
 
513
+			case 'm':
514
+					shm_mem_size=strtol(optarg, &tmp, 10) * 1024 * 1024;
515
+					if (tmp &&(*tmp)){
516
+						fprintf(stderr, "bad shmem size number: -m %s\n", optarg);
517
+						goto error;
518
+					};
519
+					LOG(L_INFO, "ser: shared memory allocated: %d MByte\n", shm_mem_size );
520
+					break;
521
+
506 522
 			case 'b':
507 523
 					maxbuffer=strtol(optarg, &tmp, 10);
508 524
 					if (tmp &&(*tmp)){
... ...
@@ -619,6 +635,10 @@ int main(int argc, char** argv)
619 635
 		goto error;
620 636
 	}
621 637
 
638
+#ifdef NEW_HNAME
639
+    init_htable();
640
+#endif
641
+
622 642
 	/*init mallocs (before parsing cfg !)*/
623 643
 	if (init_mallocs()==-1)
624 644
 		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 117
 	/* scheduled for deletion ? */
112 118
 	short damocles;
113 119
 #endif
120
+
114 121
 }cell_type;
115 122
 
116 123
 
... ...
@@ -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 169
 			semctl(reply_semaphore, 0 , IPC_RMID , 0 );
167 170
 		if (ack_semaphore>0)
168 171
 			semctl(reply_semaphore, 0 , IPC_RMID , 0 );
172
+#ifdef WAIT
173
+		if (wait_semaphore>0)
174
+			semctl(wait_semaphore, 0 , IPC_RMID , 0 );
175
+#endif
176
+
169 177
 
170 178
 		if (i==0){
171 179
 			LOG(L_CRIT, "lock_initialize: could not allocate semaphore"
... ...
@@ -236,6 +244,23 @@ again:
236 244
 		}
237 245
 	}
238 246
 
247
+#ifdef WAIT
248
+	if ((wait_semaphore=init_semaphore_set(sem_nr))<0){
249
+		if (errno==EINVAL || errno==ENOSPC ) {
250
+			DBG( "DEBUG:lock_initialize: wait semaphore initialization"
251
+				" failure: %s\n", strerror(errno));
252
+			probe_run==1;
253
+			i--;
254
+			goto again;
255
+		}else{
256
+			LOG(L_CRIT, "ERROR:lock_initialize: wait semaphore initialization"
257
+				" failure: %s\n", strerror(errno));
258
+			goto error;
259
+		}
260
+	}
261
+#endif
262
+
263
+
239 264
 
240 265
 
241 266
 	/* return success */
... ...
@@ -280,8 +305,18 @@ void lock_cleanup()
280 305
 	if (ack_semaphore > 0 &&
281 306
 	    semctl( ack_semaphore, 0 , IPC_RMID , 0 )==-1)
282 307
 		LOG(L_ERR, "ERROR: lock_cleanup, ack_semaphore cleanup failed\n");
308
+#ifdef WAIT
309
+	if (wait_semaphore > 0 &&
310
+		semctl( wait_semaphore, 0 , IPC_RMID , 0 )==-1)
311
+		LOG(L_ERR, "ERROR: lock_cleanup, wait_semaphore cleanup failed\n");
312
+#endif
313
+
283 314
 
284 315
 	entry_semaphore = timer_semaphore = reply_semaphore = ack_semaphore = 0;
316
+#ifdef WAIT
317
+	wait_semaphore = 0;
318
+#endif
319
+
285 320
 
286 321
 }
287 322
 #endif /*FAST_LOCK*/
... ...
@@ -329,13 +364,20 @@ int init_cell_lock( struct cell *cell )
329 364
 #ifdef FAST_LOCK
330 365
 	init_lock(cell->reply_mutex);
331 366
 	init_lock(cell->ack_mutex);
367
+#ifdef WAIT
368
+	init_lock(cell->wait_mutex);
369
+#endif
332 370
 	return 0;
333 371
 #else
334 372
 	cell->reply_mutex.semaphore_set=reply_semaphore;
335 373
 	cell->reply_mutex.semaphore_index = cell->hash_index % sem_nr;
336 374
 	cell->ack_mutex.semaphore_set=ack_semaphore;
337 375
 	cell->ack_mutex.semaphore_index = cell->hash_index % sem_nr;
338
-#endif
376
+#ifdef WAIT
377
+	cell->wait_mutex.semaphore_set=wait_semaphore;
378
+	cell->wait_mutex.semaphore_index = cell->hash_index % sem_nr;
379
+#endif /* WAIT */
380
+#endif /* FAST_LOCK */
339 381
 	return 0;
340 382
 }
341 383
 
... ...
@@ -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 511
 
613 512
 
614 513
 
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 514
 
640 515
 
641 516
 
... ...
@@ -651,170 +526,6 @@ int t_unref( /* struct sip_msg* p_msg */ )
651 526
 
652 527
 
653 528
 
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 529
 
819 530
 
820 531
 
... ...
@@ -941,11 +652,30 @@ int t_put_on_wait(  struct cell  *Trans  )
941 652
 	unsigned int i;
942 653
 	struct retrans_buff* rb;
943 654
 
655
+#ifndef WAIT
944 656
 	if (is_in_timer_list2( &(Trans->wait_tl)))
945 657
   	{
946 658
 		DBG("DEBUG: t_put_on_wait: already on wait\n");
947 659
 		return 1;
948 660
 	}
661
+#else
662
+	/* have some race conditons occured and we already
663
+	  entered/passed the wait status previously?
664
+	  if so, exit now
665
+	*/
666
+
667
+	LOCK_WAIT(T);
668
+	if (Trans->on_wait)
669
+	{
670
+		DBG("DEBUG: t_put_on_wait: already on wait\n");
671
+		UNLOCK_WAIT(T);
672
+		return 1;
673
+	} else {
674
+		Trans->on_wait=1;
675
+		UNLOCK_WAIT(T);
676
+	};
677
+#endif
678
+
949 679
 
950 680
 	/* remove from  retranssmision  and  final response   list */
951 681
 	DBG("DEBUG: t_put_on_wait: stopping timers (FR and RETR)\n");
... ...
@@ -1402,9 +1132,13 @@ void retransmission_handler( void *attr)
1402 1132
 	/* retransmision */
1403 1133
 	DBG("DEBUG: retransmission_handler : resending (t=%p)\n", r_buf->my_T);
1404 1134
 	if (r_buf->reply) {
1135
+		T=r_buf->my_T;
1136
+/*
1405 1137
 		LOCK_REPLIES( r_buf->my_T );
1406 1138
 		SEND_BUFFER( r_buf );
1407 1139
 		UNLOCK_REPLIES( r_buf->my_T );
1140
+*/
1141
+		t_retransmit_reply();
1408 1142
 	}else{
1409 1143
 		SEND_BUFFER( r_buf );
1410 1144
 	}
... ...
@@ -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 69
 	} else \
51 70
 	DBG("ERROR: attempt to send an empty buffer from %s (%d)", \
52 71
 	__FUNCTION__, __LINE__ ); })
72
+*/
53 73
 
54 74
 
55 75
 /* 
... ...
@@ -165,7 +185,12 @@ int t_forward_uri( struct sip_msg* p_msg  );
165 185
   *  Returns :   0 - core router stops
166 186
   *                    1 - core router relay statelessly
167 187
   */
188
+
189
+#ifdef SRL
190
+int t_on_reply( struct sip_msg  *p_msg ) ;
191
+#else
168 192
 int t_on_reply_received( struct sip_msg  *p_msg ) ;
193
+#endif
169 194
 
170 195
 
171 196
 
... ...
@@ -201,7 +226,7 @@ int t_release_transaction( struct sip_msg* );
201 226
   * Returns  -1 -error
202 227
   *                1 - OK
203 228
   */
204
-int t_retransmit_reply( struct sip_msg *  );
229
+int t_retransmit_reply( /* struct sip_msg * */  );
205 230
 
206 231
 
207 232
 
... ...
@@ -234,7 +259,14 @@ int t_should_relay_response( struct cell *Trans, int new_code, int branch, int *
234 259
 int t_update_timers_after_sending_reply( struct retrans_buff *rb );
235 260
 int t_put_on_wait(  struct cell  *Trans  );
236 261
 int relay_lowest_reply_upstream( struct cell *Trans , struct sip_msg *p_msg );
262
+
263
+#ifdef SRL
264
+static int push_reply( struct cell* trans , unsigned int branch , 
265
+    char *buf, unsigned int len);
266
+#else
237 267
 static int push_reply_from_uac_to_uas( struct cell* Trans , unsigned int );
268
+#endif
269
+
238 270
 int add_branch_label( struct cell *Trans, struct sip_msg *p_msg , int branch );
239 271
 int get_ip_and_port_from_uri( struct sip_msg* p_msg , unsigned int *param_ip, unsigned int *param_port);
240 272
 
... ...
@@ -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 134
 
133 135
 	if (  p_msg->REQ_METHOD==METHOD_CANCEL )
134 136
 	{
135
-		DBG("DEBUG: t_forward: forwarding CANCEL\n");
137
+		DBG("DEBUG: t_forward_nonack: forwarding CANCEL\n");
136 138
 		/* if no transaction to CANCEL */
137 139
 		/* or if the canceled transaction has a final status -> drop the CANCEL*/
138 140
 		if ( T->T_canceled!=T_NULL && T->T_canceled->status>=200)
139 141
 		{
142
+#ifdef FR
140 143
 			reset_timer( hash_table, &(rb->fr_timer ));
144
+#endif
141 145
 			reset_timer( hash_table, &(rb->retr_timer ));
142 146
 			return 1;
143 147
 		}
... ...
@@ -182,7 +186,7 @@ int t_forward_ack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
182 186
 		return -1;
183 187
 	}
184 188
 
185
-	DBG("DEBUG: t_forward: forwarding ACK [%d]\n",branch);
189
+	DBG("DEBUG: t_forward_ack: forwarding ACK [%d]\n",branch);
186 190
 	/* not able to build branch -- then better give up */
187 191
 	if ( add_branch_label( T, p_msg , branch )==-1) {
188 192
 		LOG( L_ERR, "ERROR: t_forward_ack failed to add branch label\n" );
189 193
new file mode 100644
... ...
@@ -0,0 +1,520 @@
1
+/*
2
+ * $Id$
3
+ *
4
+ */
5
+
6
+
7
+#include "hash_func.h"
8
+#include "t_funcs.h"
9
+#include "../../dprint.h"
10
+#include "../../config.h"
11
+#include "../../parser_f.h"
12
+#include "../../ut.h"
13
+#include "../../timer.h"
14
+
15
+#ifndef SRL
16
+/*  This function is called whenever a reply for our module is received; 
17
+  * we need to register  this function on module initialization;
18
+  *  Returns :   0 - core router stops
19
+  *              1 - core router relay statelessly
20
+  */
21
+int t_on_reply_received( struct sip_msg  *p_msg )
22
+{
23
+	unsigned int  branch,len, msg_status, msg_class, save_clone;
24
+	struct sip_msg *clone, *backup;
25
+	int relay;
26
+	int start_fr;
27
+	int is_invite;
28
+	struct retrans_buff *rb;
29
+
30
+
31
+	/* make sure we know the assosociated tranaction ... */
32
+	if (t_check( p_msg  , &branch )==-1) return 1;
33
+	/* ... if there is no such, tell the core router to forward statelessly */
34
+	if ( T<=0 ) return 1;
35
+
36
+	DBG("DEBUG: t_on_reply_received: Original status =%d\n",T->status);
37
+
38
+	/* it can take quite long -- better do it now than later 
39
+	   inside a reply_lock */
40
+	if (!(clone=sip_msg_cloner( p_msg ))) {
41
+		goto error;
42
+	}
43
+	msg_status=p_msg->REPLY_STATUS;
44
+	msg_class=REPLY_CLASS(p_msg);
45
+	is_invite= T->inbound_request->REQ_METHOD==METHOD_INVITE;
46
+
47
+	/* *** stop timers *** */
48
+	rb=T->outbound_request[branch];
49
+	/* stop retransmission */
50
+	reset_timer( hash_table, &(rb->retr_timer));
51
+	/* stop final response timer only if I got a final response */
52
+	if ( msg_class>1 )
53
+		reset_timer( hash_table, &(rb->fr_timer));
54
+
55
+	LOCK_REPLIES( T );
56
+   	/* if a got the first prov. response for an INVITE ->
57
+	   change FR_TIME_OUT to INV_FR_TIME_UT */
58
+	start_fr = !T->inbound_response[branch] && msg_class==1 && is_invite;
59
+
60
+	/* *** store and relay message as needed *** */
61
+	relay = t_should_relay_response( T , msg_status, branch, &save_clone );
62
+
63
+	if (save_clone) {
64
+		/* release previously hold message */
65
+		backup = T->inbound_response[branch];
66
+		T->inbound_response[branch] = clone;
67
+		T->tag=&(get_to(clone)->tag_value);
68
+	} else {
69
+		backup = NULL;
70
+		sip_msg_free( clone );
71
+	}
72
+
73
+	if (relay>=0 &&  
74
+	push_reply_from_uac_to_uas( T, relay  ) == -1 ) {
75
+		/* restore original state first */
76
+		if (save_clone) T->inbound_response[branch] = backup;
77
+		/* restart FR */
78
+		start_fr=1;
79
+		goto cleanup;
80
+	}
81
+
82
+
83
+	/* *** ACK handling *** */
84
+	if ( is_invite )
85
+	{
86
+		if ( T->outbound_ack[branch] )
87
+		{   /*retransmit*/
88
+			SEND_BUFFER( T->outbound_ack[branch] );
89
+		} else if (msg_class>2 ) {   /*on a non-200 reply to INVITE*/
90
+           		DBG("DEBUG: t_on_reply_received: >=3xx reply to INVITE: send ACK\n");
91
+           		if ( t_build_and_send_ACK( T , branch , p_msg )==-1)
92
+           		{
93
+               		LOG( L_ERR , "ERROR: t_on_reply_received: unable to send ACK\n" );
94
+					/* restart FR */
95
+					start_fr=1;
96
+           		}
97
+       		}
98
+   	}
99
+cleanup:
100
+	UNLOCK_REPLIES( T );
101
+	if (backup) sip_msg_free(backup);
102
+	if (start_fr) set_timer( hash_table, &(rb->fr_timer), FR_INV_TIMER_LIST );
103
+   	/* restart retransmission if a provisional response came for 
104
+	   a non_INVITE -> retrasmit at RT_T2*/
105
+	if ( msg_class==1 && !is_invite )
106
+	{
107
+		rb->retr_list = RT_T2;
108
+		set_timer( hash_table, &(rb->retr_timer), RT_T2 );
109
+	}
110
+error:
111
+	T_UNREF( T );
112
+	/* don't try to relay statelessly on error; on troubles, simply do nothing;
113
+           that will make the other party to retransmit; hopefuly, we'll then 
114
+           be better off */
115
+	return 0;
116
+}
117
+#endif
118
+
119
+
120
+
121
+/* Retransmits the last sent inbound reply.
122
+
123
+  * input: p_msg==request for which I want to retransmit an associated
124
+    reply
125
+  * Returns  -1 -error
126
+  *                1 - OK
127
+  */
128
+int t_retransmit_reply( /* struct sip_msg* p_msg    */ )
129
+{
130
+
131
+#ifdef SRL
132
+	void *b;
133
+	int len;
134
+#endif
135
+	LOCK_REPLIES( T );
136
+
137
+#ifdef SRL
138
+	if (!(b=pkg_malloc( len=T->outbound_response.bufflen ))) {
139
+		UNLOCK_REPLIES( T );
140
+		return -1;
141
+	};
142
+	memcpy( b, T->outbound_response.retr_buffer, len );
143
+#else
144
+	SEND_BUFFER( & T->outbound_response );
145
+#endif
146
+	UNLOCK_REPLIES( T );
147
+
148
+#ifdef SRL
149
+	SEND_PR_BUFFER( & T->outbound_response, b, len );
150
+	pkg_free( b );
151
+#endif
152
+	return 1;
153
+}
154
+
155
+/* Force a new response into inbound response buffer.
156
+  * returns 1 if everything was OK or -1 for erro
157
+  */
158
+int t_send_reply(  struct sip_msg* p_msg , unsigned int code , char * text )
159
+{
160
+	unsigned int len, buf_len;
161
+	char * buf, *shbuf;
162
+	struct retrans_buff *rb;
163
+
164
+	DBG("DEBUG: t_send_reply: entered\n");
165
+
166
+	buf = build_res_buf_from_sip_req(code,text,0,0,T->inbound_request,&len);
167
+	DBG("DEBUG: t_send_reply: buffer computed\n");
168
+	if (!buf)
169
+	{
170
+		DBG("DEBUG: t_send_reply: response building failed\n");
171
+		goto error;
172
+	}
173
+
174
+	LOCK_REPLIES( T );
175
+
176
+	rb = & T->outbound_response;
177
+	if (!rb->retr_buffer) {
178
+		/* initialize retransmission structure */
179
+		memset( rb , 0 , sizeof (struct retrans_buff) );
180
+		if (update_sock_struct_from_via(  &(rb->to),  p_msg->via1 )==-1)
181
+		{
182
+			UNLOCK_REPLIES( T );
183
+			LOG(L_ERR, "ERROR: t_send_reply: cannot lookup reply dst: %s\n",
184
+				p_msg->via1->host.s );
185
+			goto error2;
186
+		}
187
+
188
+		rb->retr_timer.tg=TG_RT;
189
+		rb->fr_timer.tg=TG_FR;
190
+		rb->retr_timer.payload = rb;
191
+		rb->fr_timer.payload = rb;
192
+		rb->to.sin_family = AF_INET;
193
+		rb->my_T = T;
194
+		rb->reply = code;
195
+	}
196
+
197
+
198
+	/* if this is a first reply (?100), longer replies will probably follow;
199
+	   try avoiding shm_resize by higher buffer size */
200
+	buf_len = rb->retr_buffer ? len : len + REPLY_OVERBUFFER_LEN;
201
+
202
+	if (! (rb->retr_buffer = (char*)shm_resize( rb->retr_buffer, buf_len )))
203
+	{
204
+		UNLOCK_REPLIES( T );
205
+		LOG(L_ERR, "ERROR: t_send_reply: cannot allocate shmem buffer\n");
206
+		goto error2;
207
+	}
208
+	rb->bufflen = len ;
209
+	memcpy( rb->retr_buffer , buf , len );
210
+	T->status = code;
211
+#ifndef SRL
212
+	SEND_BUFFER( rb );
213
+#endif
214
+	/* needs to be protected too because what timers are set depends
215
+	   on current transactions status
216
+	*/
217
+	t_update_timers_after_sending_reply( rb );
218
+	UNLOCK_REPLIES( T );
219
+
220
+#ifdef SRL
221
+	SEND_PR_BUFFER( rb, buf, len );
222
+#endif
223
+
224
+	free( buf ) ;
225
+	/* start/stops the proper timers*/
226
+
227
+	DBG("DEBUG: t_send_reply: finished\n");
228
+
229
+	return 1;
230
+
231
+error2:
232
+	free ( buf );
233
+error:
234
+	return -1;
235
+}
236
+
237
+
238
+
239
+
240
+/* Push a previously stored reply from UA Client to UA Server
241
+  * and send it out
242
+  */
243
+static int push_reply_from_uac_to_uas( struct cell* trans , unsigned int branch 
244
+#ifdef SRL
245
+	, char *buf, unsigned int len
246
+#endif
247
+	)
248
+{
249
+	unsigned int buf_len;
250
+	struct retrans_buff *rb;
251
+#ifndef SRL
252
+	char *buf;
253
+	unsigned int len;
254
+#endif
255
+
256
+	DBG("DEBUG: push_reply_from_uac_to_uas: start\n");
257
+	rb= & trans->outbound_response;
258
+	/* if there is a reply, release the buffer (everything else stays same) */
259
+	if ( ! rb->retr_buffer ) {
260
+		/*init retrans buffer*/
261
+		memset( rb , 0 , sizeof (struct retrans_buff) );
262
+		if (update_sock_struct_from_via(  &(rb->to),
263
+			trans->inbound_response[branch]->via2 )==-1) {
264
+				LOG(L_ERR, "ERROR: push_reply_from_uac_to_uas: "
265
+					"cannot lookup reply dst: %s\n",
266
+				trans->inbound_response[branch]->via2->host.s );
267
+				goto error;
268
+		}
269
+		rb->retr_timer.tg=TG_RT;
270
+		rb->fr_timer.tg=TG_FR;
271
+		rb->retr_timer.payload = rb;
272
+		rb->fr_timer.payload =  rb;
273
+		rb->to.sin_family = AF_INET;
274
+		rb->my_T = trans;
275
+		rb->reply = trans->inbound_response[branch]->REPLY_STATUS;
276
+
277
+	} else {
278
+#ifndef SRL
279
+		reset_timer( hash_table, &(rb->retr_timer));
280
+		reset_timer( hash_table, &(rb->fr_timer));
281
+#endif
282
+	}
283
+
284
+#ifndef SRL
285
+	/*  generate the retrans buffer */
286
+	buf = build_res_buf_from_sip_res ( trans->inbound_response[branch], &len);
287
+	if (!buf) {
288
+		LOG(L_ERR, "ERROR: push_reply_from_uac_to_uas: "
289
+			"no shmem for outbound reply buffer\n");
290
+		goto error;
291
+	}
292
+#endif
293
+
294
+	/* if this is a first reply (?100), longer replies will probably follow;
295
+	try avoiding shm_resize by higher buffer size */
296
+	buf_len = rb->retr_buffer ? len : len + REPLY_OVERBUFFER_LEN;
297
+	if (! (rb->retr_buffer = (char*)shm_resize( rb->retr_buffer, buf_len )))
298
+	{
299
+		LOG(L_ERR, "ERROR: t_push: cannot allocate shmem buffer\n");
300
+		goto error1;
301
+	}
302
+	rb->bufflen = len ;
303
+	memcpy( rb->retr_buffer , buf , len );
304
+#ifndef SRL
305
+	free( buf ) ;
306
+#endif
307
+
308
+	/* update the status*/
309
+	trans->status = trans->inbound_response[branch]->REPLY_STATUS;
310
+	if ( trans->inbound_response[branch]->REPLY_STATUS>=200 &&
311
+		trans->relaied_reply_branch==-1 ) {
312
+
313
+		memcpy( & trans->ack_to, & trans->outbound_request[ branch ]->to,
314
+			sizeof( struct sockaddr_in ) );
315
+		trans->relaied_reply_branch = branch;
316
+	}
317
+
318
+#ifndef SRL
319
+	/* start/stops the proper timers*/
320
+	t_update_timers_after_sending_reply( rb );
321
+#endif
322
+
323
+	/*send the reply*/
324
+	SEND_BUFFER( rb );
325
+	return 1;
326
+
327
+error1:
328
+#ifndef SRL
329
+	free( buf );
330
+#endif
331
+error:
332
+	return -1;
333
+}
334
+
335
+/* Push a previously stored reply from UA Client to UA Server
336
+  * and send it out
337
+  */
338
+static int push_reply( struct cell* trans , unsigned int branch , 
339
+	char *buf, unsigned int len)
340
+{
341
+	unsigned int buf_len;
342
+	struct retrans_buff *rb;
343
+
344
+	DBG("DEBUG: push_reply_from_uac_to_uas: start\n");
345
+	rb= & trans->outbound_response;
346
+	/* if there is a reply, release the buffer (everything else stays same) */
347
+	if ( ! rb->retr_buffer ) {
348
+		/*init retrans buffer*/
349
+		memset( rb , 0 , sizeof (struct retrans_buff) );
350
+		if (update_sock_struct_from_via(  &(rb->to),
351
+			trans->inbound_response[branch]->via2 )==-1) {
352
+				LOG(L_ERR, "ERROR: push_reply_from_uac_to_uas: "
353
+					"cannot lookup reply dst: %s\n",
354
+				trans->inbound_response[branch]->via2->host.s );
355
+				goto error;
356
+		}
357
+		rb->retr_timer.tg=TG_RT;
358
+		rb->fr_timer.tg=TG_FR;
359
+		rb->retr_timer.payload = rb;
360
+		rb->fr_timer.payload =  rb;
361
+		rb->to.sin_family = AF_INET;
362
+		rb->my_T = trans;
363
+		rb->reply = trans->inbound_response[branch]->REPLY_STATUS;
364
+	};
365
+
366
+	/* if this is a first reply (?100), longer replies will probably follow;
367
+	try avoiding shm_resize by higher buffer size */
368
+	buf_len = rb->retr_buffer ? len : len + REPLY_OVERBUFFER_LEN;
369
+	if (! (rb->retr_buffer = (char*)shm_resize( rb->retr_buffer, buf_len )))
370
+	{
371
+		LOG(L_ERR, "ERROR: t_push: cannot allocate shmem buffer\n");
372
+		goto error1;
373
+	}
374
+	rb->bufflen = len ;
375
+	memcpy( rb->retr_buffer , buf , len );
376
+
377
+	/* update the status*/
378
+	trans->status = trans->inbound_response[branch]->REPLY_STATUS;
379
+	if ( trans->inbound_response[branch]->REPLY_STATUS>=200 &&
380
+		trans->relaied_reply_branch==-1 ) {
381
+
382
+		memcpy( & trans->ack_to, & trans->outbound_request[ branch ]->to,
383
+			sizeof( struct sockaddr_in ) );
384
+		trans->relaied_reply_branch = branch;
385
+	}
386
+
387
+	/*send the reply*/
388
+	SEND_BUFFER( rb );
389
+	return 1;
390
+
391
+error1:
392
+error:
393
+	return -1;
394
+}
395
+
396
+#ifdef SRL
397
+/*  This function is called whenever a reply for our module is received; 
398
+  * we need to register  this function on module initialization;
399
+  *  Returns :   0 - core router stops
400
+  *              1 - core router relay statelessly
401
+  */
402
+int t_on_reply( struct sip_msg  *p_msg )
403
+{
404
+	unsigned int  branch,len, msg_status, msg_class, save_clone;
405
+	struct sip_msg *clone, *backup;
406
+	int relay;
407
+	int start_fr;
408
+	int is_invite;
409
+	struct retrans_buff *rb;
410
+	char *buf;
411
+	unsigned int buf_len;
412
+
413
+
414
+	/* make sure we know the assosociated tranaction ... */
415
+	if (t_check( p_msg  , &branch )==-1) return 1;
416
+	/* ... if there is no such, tell the core router to forward statelessly */
417
+	if ( T<=0 ) return 1;
418
+
419
+	DBG("DEBUG: t_on_reply_received: Original status =%d\n",T->status);
420
+
421
+	/* it can take quite long -- better do it now than later 
422
+	   inside a reply_lock */
423
+	if (!(clone=sip_msg_cloner( p_msg ))) {
424
+		goto error;
425
+	}
426
+	msg_status=p_msg->REPLY_STATUS;
427
+	msg_class=REPLY_CLASS(p_msg);
428
+	is_invite= T->inbound_request->REQ_METHOD==METHOD_INVITE;
429
+
430
+    /*  generate the retrans buffer, make a simplified
431
+	    assumption everything but 100 will be fwd-ed;
432
+		sometimes it will result in useless CPU cycles
433
+		but mostly the assumption holds and allows the
434
+		work to be done out of criticial lock region
435
+	 */
436
+	if (msg_status==100) buf=0;
437
+	else {
438
+		buf = build_res_buf_from_sip_res ( p_msg, &buf_len);
439
+		if (!buf) {
440
+			LOG(L_ERR, "ERROR: t_on_reply_received: "
441
+			"no mem for outbound reply buffer\n");
442
+			sip_msg_free( clone );
443
+			goto error;
444
+		}
445
+	}
446
+
447
+	/* *** stop timers *** */
448
+	rb=T->outbound_request[branch];
449
+	/* stop retransmission */
450
+	reset_timer( hash_table, &(rb->retr_timer));
451
+	/* stop final response timer only if I got a final response */
452
+	if ( msg_class>1 )
453
+		reset_timer( hash_table, &(rb->fr_timer));
454
+
455
+	LOCK_REPLIES( T );
456
+   	/* if a got the first prov. response for an INVITE ->
457
+	   change FR_TIME_OUT to INV_FR_TIME_UT */
458
+	start_fr = !T->inbound_response[branch] && msg_class==1 && is_invite;
459
+
460
+	/* *** store and relay message as needed *** */
461
+	relay = t_should_relay_response( T , msg_status, branch, &save_clone );
462
+
463
+	if (save_clone) {
464
+		/* release previously hold message */
465
+		backup = T->inbound_response[branch];
466
+		T->inbound_response[branch] = clone;
467
+		T->tag=&(get_to(clone)->tag_value);
468
+	} else {
469
+		backup = NULL;
470
+		sip_msg_free( clone );
471
+	}
472
+
473
+	if (relay>=0 &&  
474
+	push_reply( T, relay , buf, buf_len ) == -1 ) {
475
+		/* restore original state first */
476
+		if (save_clone) T->inbound_response[branch] = backup;
477
+		/* restart FR */
478
+		start_fr=1;
479
+		goto cleanup;
480
+	}
481
+
482
+
483
+	/* *** ACK handling *** */
484
+	if ( is_invite )
485
+	{
486
+		if ( T->outbound_ack[branch] )
487
+		{   /*retransmit*/
488
+			SEND_BUFFER( T->outbound_ack[branch] );
489
+		} else if (msg_class>2 ) {   /*on a non-200 reply to INVITE*/
490
+           		DBG("DEBUG: t_on_reply_received: >=3xx reply to INVITE: send ACK\n");
491
+           		if ( t_build_and_send_ACK( T , branch , p_msg )==-1)
492
+           		{
493
+               		LOG( L_ERR , "ERROR: t_on_reply_received: unable to send ACK\n" );
494
+					/* restart FR */
495
+					start_fr=1;
496
+           		}
497
+       		}
498
+   	}
499
+cleanup:
500
+	UNLOCK_REPLIES( T );
501
+	if (backup) sip_msg_free(backup);
502
+	if (buf) free( buf );
503
+	t_update_timers_after_sending_reply( rb );
504
+	if (start_fr) set_timer( hash_table, &(rb->fr_timer), FR_INV_TIMER_LIST );
505
+   	/* restart retransmission if a provisional response came for 
506
+	   a non_INVITE -> retrasmit at RT_T2*/
507
+	if ( msg_class==1 && !is_invite )
508
+	{
509
+		rb->retr_list = RT_T2;
510
+		set_timer( hash_table, &(rb->retr_timer), RT_T2 );
511
+	}
512
+error:
513
+	T_UNREF( T );
514
+	/* don't try to relay statelessly on error; on troubles, simply do nothing;
515
+           that will make the other party to retransmit; hopefuly, we'll then 
516
+           be better off */
517
+	return 0;
518
+}
519
+
520
+#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 71
 void add_timer_unsafe( struct timer *timer_list,
62 72
 	struct timer_link *tl, unsigned int time_out )
63 73
 {
74
+#ifdef EXTRA_DEBUG
75
+	if (timer_list->last_tl.prev_tl==0) {
76
+	LOG( L_CRIT,
77
+		"CRITICAL : Oh no, zero link in trailing timer element\n");
78
+		abort();
79
+	};
80
+#endif
81
+
64 82
 	/*	remove_from_timer_list( tl ); */
65 83
 	/* the entire timer list is locked now -- noone else can manipulate it */
66 84
 	/* lock( timer_list->mutex ); */
... ...
@@ -116,6 +134,14 @@ struct timer_link  *check_and_split_time_list( struct timer *timer_list, int tim
116 134
 		timer_list->first_tl.next_tl = tl;	
117 135
 		tl->prev_tl = & timer_list->first_tl;
118 136
 	}
137
+#ifdef EXTRA_DEBUG
138
+	if (timer_list->last_tl.prev_tl==0) {
139
+		LOG( L_CRIT,
140
+		"CRITICAL : Oh no, zero link in trailing timer element\n");
141
+		abort();
142
+	};
143
+#endif
144
+
119 145
 
120 146
    /* give the list lock away */
121 147
    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 362
 static w_t_retransmit_reply( struct sip_msg* p_msg, char* foo, char* bar  )
359 363
 {
360 364
 	if (t_check( p_msg  , 0 )==-1) return 1;
361
-	if (T) return t_retransmit_reply( p_msg );
365
+	if (T) return t_retransmit_reply( /* p_msg */ );
362 366
 	else return -1;
363 367
 }
364 368
 
... ...
@@ -30,6 +30,7 @@
30 30
 #define HDR_RECORDROUTE  512
31 31
 #define HDR_OTHER       65536 /*unknown header type*/
32 32