Browse Source

- fix for free_rdata_list() which used to access the "next" pointer after
freeing the current elements (ported from Ottendorf)
Credits & patch: Jan Andres <[email protected]>

Andrei Pelinescu-Onciul 19 years ago
parent
commit
5fbf103fd7
7 changed files with 45 additions and 9 deletions
  1. 1 1
      modules/tm/t_cancel.c
  2. 1 1
      modules/tm/t_funcs.c
  3. 1 1
      modules/tm/t_fwd.c
  4. 4 3
      modules/tm/t_reply.c
  5. 31 2
      modules/tm/timer.c
  6. 2 0
      modules/tm/timer.h
  7. 5 1
      resolve.c

+ 1 - 1
modules/tm/t_cancel.c

@@ -147,7 +147,7 @@ static void cancel_all_branches(struct cell *t)
 	    
 	    /* stop_rb_timers(&t->uac[i].request); */
 	    reset_timer( &t->uac[i].request.retr_timer );
-	    reset_timer( &t->uac[i].request.fr_timer );
+	    del_fr_timer( &t->uac[i].request.fr_timer );
 	}
 	else {
 

+ 1 - 1
modules/tm/t_funcs.c

@@ -133,7 +133,7 @@ int t_release_transaction( struct cell *trans )
 {
 	set_kr(REQ_RLSD);
 
-	reset_timer( & trans->uas.response.fr_timer );
+	del_fr_timer( & trans->uas.response.fr_timer );
 	reset_timer( & trans->uas.response.retr_timer );
 
 	cleanup_uac_timers( trans );

+ 1 - 1
modules/tm/t_fwd.c

@@ -349,7 +349,7 @@ void e2e_cancel( struct sip_msg *cancel_msg,
 				      * retransmission timers
 				      */
 				reset_timer(&t_invite->uac[i].request.retr_timer);
-				reset_timer(&t_invite->uac[i].request.fr_timer);
+				del_fr_timer(&t_invite->uac[i].request.fr_timer);
 
 				/* Generate faked reply */
 				LOCK_REPLIES(t_invite);

+ 4 - 3
modules/tm/t_reply.c

@@ -66,6 +66,7 @@
  *              the request (bogdan)
  *  2005-09-01  reverted to the old way of checking response.dst.send_sock
  *               in t_retransmit_reply & reply_light (andrei)
+ *  2006-12-27  replaced reset(fr_timer) with del_fr_timer(...)  (andrei)
  */
 
 
@@ -954,7 +955,7 @@ void cleanup_uac_timers( struct cell *t )
 	/* reset FR/retransmission timers */
 	for (i=0; i<t->nr_of_outgoings; i++ )  {
 		reset_timer( &t->uac[i].request.retr_timer );
-		reset_timer( &t->uac[i].request.fr_timer );
+		del_fr_timer( &t->uac[i].request.fr_timer );
 	}
 	DBG("DEBUG: cleanup_uac_timers: RETR/FR timers reset\n");
 }
@@ -1282,7 +1283,7 @@ int reply_received( struct sip_msg  *p_msg )
 		     /* ... then just stop timers */
 		reset_timer( &uac->local_cancel.retr_timer);
 		if ( msg_status >= 200 ) {
-				reset_timer( &uac->local_cancel.fr_timer);
+				del_fr_timer( &uac->local_cancel.fr_timer);
 		}
 		DBG("DEBUG: reply to local CANCEL processed\n");
 		goto done;
@@ -1294,7 +1295,7 @@ int reply_received( struct sip_msg  *p_msg )
 	
 	     /* stop final response timer only if I got a final response */
 	if ( msg_status >= 200 ) {
-		reset_timer( &uac->request.fr_timer);
+		del_fr_timer(&uac->request.fr_timer);
 	}
 
 	     /* acknowledge negative INVITE replies (do it before detailed

+ 31 - 2
modules/tm/timer.c

@@ -98,6 +98,8 @@
  *  2003-06-27  timers are not unlinked if timerlist is 0 (andrei)
  *  2004-02-13  t->is_invite, t->local, t->noisy_ctimer replaced;
  *              timer_link.payload removed (bogdan)
+ *  2006-11-27  added del_fr_timer(): fr timers are immediately removed
+ *              from the FR* lists (andrei)
  */
 
 #include "defs.h"
@@ -322,7 +324,7 @@ inline static void retransmission_handler( struct timer_link *retr_tl )
 				"request resending (t=%p, %.9s ... )\n", 
 				r_buf->my_T, r_buf->buffer);
 			if (SEND_BUFFER( r_buf )==-1) {
-				reset_timer( &r_buf->fr_timer );
+				del_fr_timer( &r_buf->fr_timer );
 				fake_reply(r_buf->my_T, r_buf->branch, 503 );
 				return;
 			}
@@ -436,7 +438,7 @@ void cleanup_localcancel_timers( struct cell *t )
 	int i;
 	for (i=0; i<t->nr_of_outgoings; i++ )  {
 		reset_timer(  &t->uac[i].local_cancel.retr_timer );
-		reset_timer(  &t->uac[i].local_cancel.fr_timer );
+		del_fr_timer(  &t->uac[i].local_cancel.fr_timer );
 	}
 }
 
@@ -778,6 +780,33 @@ void reset_timer( struct timer_link* tl )
 
 
 
+/* remove a timer from the FR_TIMER_LIST or FR_INV_TIMER_LIST
+ *  (it allows immediate delete of a fr timer => solves the race with
+ *   variables timers inserted after longer deleted timers)
+ * WARNING: - don't try to use it to "move" a timer from one list
+ *            to another, you'll run into races
+ */
+void del_fr_timer( struct timer_link *tl)
+{
+	/* the FR lock is common/shared by both FR_INV_TIMER_LIST 
+	 * and FR_TIMER_LIST, so we must lock only one of them */
+	lock(timertable->timers[FR_TIMER_LIST].mutex);
+	/* check first if we  are on  the "detached" timer_routine list (the fr
+	 * handle is executing or  timer_routine prepares to execute it).
+	 * if so do nothing, except reseting the timer to TIMER_DELETED
+	 *  (just to give us a change at racing with timer_routine, if 
+	 *  TIMER_DELETED is set and the fr handle is not already executing =>
+	 *   it will not be called anymore)
+	 */
+	if (tl->timer_list!=DETACHED_LIST){
+		remove_timer_unsafe(tl); /* safe to call for null list */
+	}else{
+		reset_timer(tl);
+	}
+	unlock(timertable->timers[FR_TIMER_LIST].mutex);
+}
+
+
 
 /* determine timer length and put on a correct timer list
  * WARNING: - don't try to use it to "move" a timer from one list

+ 2 - 0
modules/tm/timer.h

@@ -109,6 +109,8 @@ struct timer_link  *check_and_split_time_list( struct timer*, int);
 */
 
 void reset_timer( struct timer_link* tl );
+/* remove a timer from FR_TIMER_LIST or FR_INV_TIMER_LIST */
+void del_fr_timer( struct timer_link *tl);
 /* determine timer length and put on a correct timer list */
 void set_timer( struct timer_link *new_tl, enum lists list_id, unsigned int* ext_timeout );
 /* similar to set_timer, except it allows only one-time

+ 5 - 1
resolve.c

@@ -264,10 +264,14 @@ error:
 void free_rdata_list(struct rdata* head)
 {
 	struct rdata* l;
-	for(l=head; l; l=l->next){
+	struct rdata* next_l;
+	l=head;
+	while (l != 0) {
+		next_l = l->next;
 		/* free the parsed rdata*/
 		if (l->rdata) local_free(l->rdata);
 		local_free(l);
+		l = next_l;
 	}
 }