Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

timer.c

Go to the documentation of this file.
00001 /*
00002  * $Id: timer.c,v 1.86 2009/04/08 11:44:23 tirpi Exp $
00003  *
00004  *
00005  * Copyright (C) 2001-2003 FhG Fokus
00006  *
00007  * This file is part of ser, a free SIP server.
00008  *
00009  * ser is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version
00013  *
00014  * For a license to use the ser software under conditions
00015  * other than those described here, or to purchase support for this
00016  * software, please contact iptel.org by e-mail at the following addresses:
00017  *    info@iptel.org
00018  *
00019  * ser is distributed in the hope that it will be useful,
00020  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022  * GNU General Public License for more details.
00023  *
00024  * You should have received a copy of the GNU General Public License 
00025  * along with this program; if not, write to the Free Software 
00026  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00027  */
00028 
00029 
00030 /* 
00031   timer.c is where we implement TM timers. It has been designed
00032   for high performance using some techniques of which timer users
00033   need to be aware.
00034 
00035         One technique is "fixed-timer-length". We maintain separate 
00036         timer lists, all of them include elements of the same time
00037         to fire. That allows *appending* new events to the list as
00038         opposed to inserting them by time, which is costly due to
00039         searching time spent in a mutex. The performance benefit is
00040         noticeable. The limitation is you need a new timer list for
00041         each new timer length.
00042 
00043         Another technique is the timer process slices off expired elements
00044         from the list in a mutex, but executes the timer after the mutex
00045         is left. That saves time greatly as whichever process wants to
00046         add/remove a timer, it does not have to wait until the current
00047         list is processed. However, be aware the timers may hit in a delayed
00048         manner; you have no guarantee in your process that after resetting a timer, 
00049         it will no more hit. It might have been removed by timer process,
00050     and is waiting to be executed.  The following example shows it:
00051 
00052                         PROCESS1                                TIMER PROCESS
00053 
00054         0.                                                              timer hits, it is removed from queue and
00055                                                                         about to be executed
00056         1.      process1 decides to
00057                 reset the timer 
00058         2.                                                              timer is executed now
00059         3.      if the process1 naively
00060                 thinks the timer could not 
00061                 have been executed after 
00062                 resetting the timer, it is
00063                 WRONG -- it was (step 2.)
00064 
00065         So be careful when writing the timer handlers. Currently defined timers 
00066         don't hurt if they hit delayed, I hope at least. Retransmission timer 
00067         may results in a useless retransmission -- not too bad. FR timer not too
00068         bad either as timer processing uses a REPLY mutex making it safe to other
00069         processing affecting transaction state. Wait timer not bad either -- processes
00070         putting a transaction on wait don't do anything with it anymore.
00071 
00072                 Example when it does not hurt:
00073 
00074                         P1                                              TIMER
00075         0.                                                              RETR timer removed from list and
00076                                                                         scheduled for execution
00077         1. 200/BYE received->
00078            reset RETR, put_on_wait
00079         2.                                                              RETR timer executed -- too late but it does
00080                                                                         not hurt
00081         3.                                                              WAIT handler executed
00082 
00083         The rule of thumb is don't touch data you put under a timer. Create data,
00084     put them under a timer, and let them live until they are safely destroyed from
00085     wait/delete timer.  The only safe place to manipulate the data is 
00086     from timer process in which delayed timers cannot hit (all timers are
00087     processed sequentially).
00088 
00089         A "bad example" -- rewriting content of retransmission buffer
00090         in an unprotected way is bad because a delayed retransmission timer might 
00091         hit. Thats why our reply retransmission procedure is enclosed in 
00092         a REPLY_LOCK.
00093 
00094 */
00095 /*
00096  * History:
00097  * --------
00098  *  2003-06-27  timers are not unlinked if timerlist is 0 (andrei)
00099  *  2004-02-13  t->is_invite, t->local, t->noisy_ctimer replaced;
00100  *              timer_link.payload removed (bogdan)
00101  *  2005-10-03  almost completely rewritten to use the new timers (andrei)
00102  *  2005-12-12  on final response marked the rb as removed to avoid deleting
00103  *              it from the timer handle; timer_allow_del()  (andrei)
00104  *  2006-08-11  final_response_handler dns failover support for timeout-ed
00105  *              invites (andrei)
00106  *  2006-09-28  removed the 480 on fr_inv_timeout reply: on timeout always 
00107  *               return a 408
00108  *              set the corresponding "faked" failure route sip_msg->msg_flags 
00109  *               on timeout or if the branch received a reply (andrei)
00110  *  2007-03-15  TMCB_ONSEND callbacks support (andrei)
00111  *  2007-05-29  delete on transaction ref_count==0 : removed the delete timer
00112  *               (andrei)
00113  * 2007-06-01  support for different retransmissions intervals per transaction;
00114  *             added maximum inv. and non-inv. transaction life time (andrei)
00115  */
00116 
00117 #include "defs.h"
00118 
00119 
00120 
00121 #include "config.h"
00122 #include "h_table.h"
00123 #include "timer.h"
00124 #include "../../dprint.h"
00125 #include "lock.h"
00126 #include "t_stats.h"
00127 
00128 #include "../../hash_func.h"
00129 #include "../../dprint.h"
00130 #include "../../config.h"
00131 #include "../../parser/parser_f.h"
00132 #include "../../ut.h"
00133 #include "../../timer_ticks.h"
00134 #include "../../compiler_opt.h"
00135 #include "t_funcs.h"
00136 #include "t_reply.h"
00137 #include "t_cancel.h"
00138 #include "t_hooks.h"
00139 #ifdef USE_DNS_FAILOVER
00140 #include "t_fwd.h" /* t_send_branch */
00141 #include "../../cfg_core.h" /* cfg_get(core, core_cfg, use_dns_failover) */
00142 #endif
00143 #ifdef USE_DST_BLACKLIST
00144 #include "../../dst_blacklist.h"
00145 #endif
00146 
00147 
00148 
00149 struct msgid_var user_fr_timeout;
00150 struct msgid_var user_fr_inv_timeout;
00151 #ifdef TM_DIFF_RT_TIMEOUT
00152 struct msgid_var user_rt_t1_timeout;
00153 struct msgid_var user_rt_t2_timeout;
00154 #endif
00155 struct msgid_var user_inv_max_lifetime;
00156 struct msgid_var user_noninv_max_lifetime;
00157 
00158 
00159 /* internal use, val should be unsigned or positive
00160  *  <= instead of < to get read of gcc warning when 
00161  *  sizeof(cell_member)==sizeof(val) (Note that this limits
00162  *  maximum value to max. type -1) */
00163 #define SIZE_FIT_CHECK(cell_member, val, cfg_name) \
00164         if (MAX_UVAR_VALUE(((struct cell*)0)->cell_member) <= (val)){ \
00165                 ERR("tm_init_timers: " cfg_name " too big: %lu (%lu ticks) " \
00166                                 "- max %lu (%lu ticks) \n", TICKS_TO_MS((unsigned long)(val)),\
00167                                 (unsigned long)(val), \
00168                                 TICKS_TO_MS(MAX_UVAR_VALUE(((struct cell*)0)->cell_member)), \
00169                                 MAX_UVAR_VALUE(((struct cell*)0)->cell_member)); \
00170                 goto error; \
00171         } 
00172 
00173 /* fix timer values to ticks */
00174 int tm_init_timers()
00175 {
00176         default_tm_cfg.fr_timeout=MS_TO_TICKS(default_tm_cfg.fr_timeout); 
00177         default_tm_cfg.fr_inv_timeout=MS_TO_TICKS(default_tm_cfg.fr_inv_timeout);
00178         default_tm_cfg.wait_timeout=MS_TO_TICKS(default_tm_cfg.wait_timeout);
00179         default_tm_cfg.delete_timeout=MS_TO_TICKS(default_tm_cfg.delete_timeout);
00180         default_tm_cfg.rt_t1_timeout=MS_TO_TICKS(default_tm_cfg.rt_t1_timeout);
00181         default_tm_cfg.rt_t2_timeout=MS_TO_TICKS(default_tm_cfg.rt_t2_timeout);
00182         default_tm_cfg.tm_max_inv_lifetime=MS_TO_TICKS(default_tm_cfg.tm_max_inv_lifetime);
00183         default_tm_cfg.tm_max_noninv_lifetime=MS_TO_TICKS(default_tm_cfg.tm_max_noninv_lifetime);
00184         /* fix 0 values to 1 tick (minimum possible wait time ) */
00185         if (default_tm_cfg.fr_timeout==0) default_tm_cfg.fr_timeout=1;
00186         if (default_tm_cfg.fr_inv_timeout==0) default_tm_cfg.fr_inv_timeout=1;
00187         if (default_tm_cfg.wait_timeout==0) default_tm_cfg.wait_timeout=1;
00188         if (default_tm_cfg.delete_timeout==0) default_tm_cfg.delete_timeout=1;
00189         if (default_tm_cfg.rt_t2_timeout==0) default_tm_cfg.rt_t2_timeout=1;
00190         if (default_tm_cfg.rt_t1_timeout==0) default_tm_cfg.rt_t1_timeout=1;
00191         if (default_tm_cfg.tm_max_inv_lifetime==0) default_tm_cfg.tm_max_inv_lifetime=1;
00192         if (default_tm_cfg.tm_max_noninv_lifetime==0) default_tm_cfg.tm_max_noninv_lifetime=1;
00193         
00194         /* size fit checks */
00195         SIZE_FIT_CHECK(fr_timeout, default_tm_cfg.fr_timeout, "fr_timer");
00196         SIZE_FIT_CHECK(fr_inv_timeout, default_tm_cfg.fr_inv_timeout, "fr_inv_timer");
00197 #ifdef TM_DIFF_RT_TIMEOUT
00198         SIZE_FIT_CHECK(rt_t1_timeout, default_tm_cfg.rt_t1_timeout, "retr_timer1");
00199         SIZE_FIT_CHECK(rt_t2_timeout, default_tm_cfg.rt_t2_timeout, "retr_timer2");
00200 #endif
00201         SIZE_FIT_CHECK(end_of_life, default_tm_cfg.tm_max_inv_lifetime, "max_inv_lifetime");
00202         SIZE_FIT_CHECK(end_of_life, default_tm_cfg.tm_max_noninv_lifetime, "max_noninv_lifetime");
00203         
00204         memset(&user_fr_timeout, 0, sizeof(user_fr_timeout));
00205         memset(&user_fr_inv_timeout, 0, sizeof(user_fr_inv_timeout));
00206 #ifdef TM_DIFF_RT_TIMEOUT
00207         memset(&user_rt_t1_timeout, 0, sizeof(user_rt_t1_timeout));
00208         memset(&user_rt_t2_timeout, 0, sizeof(user_rt_t2_timeout));
00209 #endif
00210         memset(&user_inv_max_lifetime, 0, sizeof(user_inv_max_lifetime));
00211         memset(&user_noninv_max_lifetime, 0, sizeof(user_noninv_max_lifetime));
00212         
00213         DBG("tm: tm_init_timers: fr=%d fr_inv=%d wait=%d delete=%d t1=%d t2=%d"
00214                         " max_inv_lifetime=%d max_noninv_lifetime=%d\n",
00215                         default_tm_cfg.fr_timeout, default_tm_cfg.fr_inv_timeout,
00216                         default_tm_cfg.wait_timeout, default_tm_cfg.delete_timeout,
00217                         default_tm_cfg.rt_t1_timeout, default_tm_cfg.rt_t2_timeout,
00218                         default_tm_cfg.tm_max_inv_lifetime, default_tm_cfg.tm_max_noninv_lifetime);
00219         return 0;
00220 error:
00221         return -1;
00222 }
00223 
00224 /* internal macro for timer_fixup()
00225  * performs size fit check if the timer name matches
00226  */
00227 #define IF_IS_TIMER_NAME(cell_member, cfg_name) \
00228         if ((name->len == sizeof(cfg_name)-1) && \
00229                 (memcmp(name->s, cfg_name, sizeof(cfg_name)-1)==0)) { \
00230                         SIZE_FIT_CHECK(cell_member, t, cfg_name); \
00231         }
00232 
00233 /* fixup function for the timer values
00234  * (called by the configuration framework)
00235  */
00236 int timer_fixup(void *handle, str *gname, str *name, void **val)
00237 {
00238         ticks_t t;
00239 
00240         t = MS_TO_TICKS((unsigned int)(long)(*val));
00241         /* fix 0 values to 1 tick (minimum possible wait time ) */
00242         if (t == 0) t = 1;
00243 
00244         /* size fix checks */
00245         IF_IS_TIMER_NAME(fr_timeout, "fr_timer")
00246         else IF_IS_TIMER_NAME(fr_inv_timeout, "fr_inv_timer")
00247 #ifdef TM_DIFF_RT_TIMEOUT
00248         else IF_IS_TIMER_NAME(rt_t1_timeout, "retr_timer1")
00249         else IF_IS_TIMER_NAME(rt_t2_timeout, "retr_timer2")
00250 #endif
00251         else IF_IS_TIMER_NAME(end_of_life, "max_inv_lifetime")
00252         else IF_IS_TIMER_NAME(end_of_life, "max_noninv_lifetime")
00253 
00254         *val = (void *)(long)t;
00255         return 0;
00256 
00257 error:
00258         return -1;
00259 }
00260 
00261 /******************** handlers ***************************/
00262 
00263 
00264 #ifndef TM_DEL_UNREF
00265 /* returns number of ticks before retrying the del, or 0 if the del.
00266  * was succesfull */
00267 inline static ticks_t  delete_cell( struct cell *p_cell, int unlock )
00268 {
00269         /* there may still be FR/RETR timers, which have been reset
00270            (i.e., time_out==TIMER_DELETED) but are stilled linked to
00271            timer lists and must be removed from there before the
00272            structures are released
00273         */
00274         unlink_timers( p_cell );
00275         /* still in use ... don't delete */
00276         if ( IS_REFFED_UNSAFE(p_cell) ) {
00277                 if (unlock) UNLOCK_HASH(p_cell->hash_index);
00278                 DBG("DEBUG: delete_cell %p: can't delete -- still reffed (%d)\n",
00279                                 p_cell, p_cell->ref_count);
00280                 /* delay the delete */
00281                 /* TODO: change refcnts and delete on refcnt==0 */
00282                 return cfg_get(tm, tm_cfg, delete_timeout);
00283         } else {
00284                 if (unlock) UNLOCK_HASH(p_cell->hash_index);
00285 #ifdef EXTRA_DEBUG
00286                 DBG("DEBUG: delete transaction %p\n", p_cell );
00287 #endif
00288                 free_cell( p_cell );
00289                 return 0;
00290         }
00291 }
00292 #endif /* TM_DEL_UNREF */
00293 
00294 
00295 
00296 
00297 /* generate a fake reply
00298  * it assumes the REPLY_LOCK is already held and returns unlocked */
00299 static void fake_reply(struct cell *t, int branch, int code )
00300 {
00301         branch_bm_t cancel_bitmap;
00302         short do_cancel_branch;
00303         enum rps reply_status;
00304 
00305         do_cancel_branch = is_invite(t) && should_cancel_branch(t, branch, 0);
00306         /* mark branch as canceled */
00307         t->uac[branch].request.flags|=F_RB_CANCELED;
00308         if ( is_local(t) ) {
00309                 reply_status=local_reply( t, FAKED_REPLY, branch, 
00310                                           code, &cancel_bitmap );
00311         } else {
00312                 /* rely reply, but don't put on wait, we still need t
00313                  * to send the cancels */
00314                 reply_status=relay_reply( t, FAKED_REPLY, branch, code,
00315                                           &cancel_bitmap, 0 );
00316         }
00317         /* now when out-of-lock do the cancel I/O */
00318         if (do_cancel_branch) cancel_branch(t, branch, 0);
00319         /* it's cleaned up on error; if no error occurred and transaction
00320            completed regularly, I have to clean-up myself
00321         */
00322         if (reply_status == RPS_COMPLETED)
00323                 put_on_wait(t);
00324 }
00325 
00326 
00327 
00328 /* return (ticks_t)-1 on error/disable and 0 on success */
00329 inline static ticks_t retransmission_handler( struct retr_buf *r_buf )
00330 {
00331 #ifdef EXTRA_DEBUG
00332         if (r_buf->my_T->flags & T_IN_AGONY) {
00333                 LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and"
00334                         " called from RETR timer (flags %x)\n",
00335                         r_buf->my_T, r_buf->my_T->flags );
00336                 abort();
00337         }       
00338 #endif
00339         if ( r_buf->activ_type==TYPE_LOCAL_CANCEL 
00340                 || r_buf->activ_type==TYPE_REQUEST ) {
00341 #ifdef EXTRA_DEBUG
00342                         DBG("DEBUG: retransmission_handler : "
00343                                 "request resending (t=%p, %.9s ... )\n", 
00344                                 r_buf->my_T, r_buf->buffer);
00345 #endif
00346                         if (SEND_BUFFER( r_buf )==-1) {
00347                                 /* disable retr. timers => return -1 */
00348                                 fake_reply(r_buf->my_T, r_buf->branch, 503 );
00349                                 return (ticks_t)-1;
00350                         }
00351 #ifdef TMCB_ONSEND
00352                         if (unlikely(has_tran_tmcbs(r_buf->my_T, TMCB_REQUEST_SENT))) 
00353                                 run_onsend_callbacks(TMCB_REQUEST_SENT, r_buf, 
00354                                                                                 0, 0, TMCB_RETR_F);
00355 #endif
00356         } else {
00357 #ifdef EXTRA_DEBUG
00358                         DBG("DEBUG: retransmission_handler : "
00359                                 "reply resending (t=%p, %.9s ... )\n", 
00360                                 r_buf->my_T, r_buf->buffer);
00361 #endif
00362                         t_retransmit_reply(r_buf->my_T);
00363         }
00364         
00365         return 0;
00366 }
00367 
00368 
00369 
00370 inline static void final_response_handler(      struct retr_buf* r_buf,
00371                                                                                         struct cell* t)
00372 {
00373         int silent;
00374 #ifdef USE_DNS_FAILOVER
00375         /*int i; 
00376         int added_branches;
00377         */
00378         int branch_ret;
00379         int prev_branch;
00380         ticks_t now;
00381 #endif
00382 
00383 #       ifdef EXTRA_DEBUG
00384         if (t->flags & T_IN_AGONY) 
00385         {
00386                 LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and"
00387                         " called from FR timer (flags %x)\n", t, t->flags);
00388                 abort();
00389         }
00390 #       endif
00391         /* FR for local cancels.... */
00392         if (r_buf->activ_type==TYPE_LOCAL_CANCEL)
00393         {
00394 #ifdef TIMER_DEBUG
00395                 DBG("DEBUG: final_response_handler: stop retr for Local Cancel\n");
00396 #endif
00397                 return;
00398         }
00399         /* FR for replies (negative INVITE replies) */
00400         if (r_buf->activ_type>0) {
00401 #               ifdef EXTRA_DEBUG
00402                 if (t->uas.request->REQ_METHOD!=METHOD_INVITE
00403                         || t->uas.status < 200 ) {
00404                         LOG(L_CRIT, "BUG: final_response_handler: unknown type reply"
00405                                         " buffer\n");
00406                         abort();
00407                 }
00408 #               endif
00409                 put_on_wait( t );
00410                 return;
00411         };
00412 
00413         /* lock reply processing to determine how to proceed reliably */
00414         LOCK_REPLIES( t );
00415         /* now it can be only a request retransmission buffer;
00416            try if you can simply discard the local transaction 
00417            state without compellingly removing it from the
00418            world */
00419         silent=
00420                 /* don't go silent if disallowed globally ... */
00421                 cfg_get(tm, tm_cfg, noisy_ctimer)==0
00422                 /* ... or for this particular transaction */
00423                 && has_noisy_ctimer(t) == 0
00424                 /* not for UACs */
00425                 && !is_local(t)
00426                 /* invites only */
00427                 && is_invite(t)
00428                 /* parallel forking does not allow silent state discarding */
00429                 && t->nr_of_outgoings==1
00430                 /* on_negativ reply handler not installed -- serial forking 
00431                  * could occur otherwise */
00432                 && t->on_negative==0
00433                 /* the same for FAILURE callbacks */
00434                 && !has_tran_tmcbs( t, TMCB_ON_FAILURE_RO|TMCB_ON_FAILURE) 
00435                 /* something received -- we will not be silent on error */
00436                 && t->uac[r_buf->branch].last_received==0;
00437         
00438         if (silent) {
00439                 UNLOCK_REPLIES(t);
00440 #ifdef EXTRA_DEBUG
00441                 DBG("DEBUG: final_response_handler: transaction silently dropped (%p)"
00442                                 ", branch %d, last_received %d\n",t, r_buf->branch,
00443                                  t->uac[r_buf->branch].last_received);
00444 #endif
00445                 put_on_wait( t );
00446                 return;
00447         }
00448 #ifdef EXTRA_DEBUG
00449         DBG("DEBUG: final_response_handler:stop retr. and send CANCEL (%p)\n", t);
00450 #endif
00451         if ((r_buf->branch < MAX_BRANCHES) && /* r_buf->branch is always >=0 */
00452                         (t->uac[r_buf->branch].last_received==0) &&
00453                         (t->uac[r_buf->branch].request.buffer!=NULL) /* not a blind UAC */
00454         ){
00455                 /* no reply received */
00456 #ifdef USE_DST_BLACKLIST
00457                 if (cfg_get(core, core_cfg, use_dst_blacklist)
00458                         && r_buf->my_T
00459                         && r_buf->my_T->uas.request
00460                         && (r_buf->my_T->uas.request->REQ_METHOD & cfg_get(tm, tm_cfg, tm_blst_methods_add))
00461                 )
00462                         dst_blacklist_add( BLST_ERR_TIMEOUT, &r_buf->dst,
00463                                                 r_buf->my_T->uas.request);
00464 #endif
00465 #ifdef USE_DNS_FAILOVER
00466                 /* if this is an invite, the destination resolves to more ips, and
00467                  *  it still hasn't passed more than fr_inv_timeout since we
00468                  *  started, add another branch/uac */
00469                 if (cfg_get(core, core_cfg, use_dns_failover)){
00470                         now=get_ticks_raw();
00471                         if ((s_ticks_t)(t->end_of_life-now)>0){
00472                                 branch_ret=add_uac_dns_fallback(t, t->uas.request,
00473                                                                                                         &t->uac[r_buf->branch], 0);
00474                                 prev_branch=-1;
00475                                 while((branch_ret>=0) &&(branch_ret!=prev_branch)){
00476                                         prev_branch=branch_ret;
00477                                         branch_ret=t_send_branch(t, branch_ret, t->uas.request , 
00478                                                                                                 0, 0);
00479                                 }
00480                         }
00481                 }
00482 #endif
00483         }
00484         fake_reply(t, r_buf->branch, 408);
00485 }
00486 
00487 
00488 
00489 /* handles retransmissions and fr timers */
00490 /* the following assumption are made (to avoid deleting/re-adding the timer):
00491  *  retr_buf->retr_interval < ( 1<<((sizeof(ticks_t)*8-1) )
00492  *  if retr_buf->retr_interval==0 => timer disabled
00493  *                            ==(ticks_t) -1 => retr. disabled (fr working)
00494  *     retr_buf->retr_interval & (1 <<(sizeof(ticks_t)*8-1) => retr. & fr reset
00495  *     (we never reset only retr, it's either reset both of them or retr 
00496  *      disabled & reset fr). In this case the fr_origin will contain the 
00497  *      "time" of the reset and next retr should occur at 
00498  *      fr->origin+retr_interval (we also assume that we'll never reset retr
00499  *      to a lower value then the current one)
00500  */
00501 ticks_t retr_buf_handler(ticks_t ticks, struct timer_ln* tl, void *p)
00502 {
00503         struct retr_buf* rbuf ;
00504         ticks_t fr_remainder;
00505         ticks_t retr_remainder;
00506         ticks_t retr_interval;
00507         ticks_t new_retr_interval;
00508         struct cell *t;
00509 
00510         rbuf=(struct  retr_buf*)
00511                         ((void*)tl-(void*)(&((struct retr_buf*)0)->timer));
00512         membar_depends(); /* to be on the safe side */
00513         t=rbuf->my_T;
00514         
00515 #ifdef TIMER_DEBUG
00516         DBG("tm: timer retr_buf_handler @%d (%p -> %p -> %p)\n",
00517                         ticks, tl, rbuf, t);
00518 #endif
00519         if (unlikely(rbuf->flags & F_RB_DEL_TIMER)){
00520                 /* timer marked for deletion */
00521                 rbuf->t_active=0; /* mark it as removed */
00522                 /* a membar is not really needed, in the very unlikely case that 
00523                  * another process will see old t_active's value and will try to 
00524                  * delete the timer again, but since timer_del it's safe in this cases
00525                  * it will be a no-op */
00526                 return 0;
00527         }
00528         /* overflow safe check (should work ok for fr_intervals < max ticks_t/2) */
00529         if ((s_ticks_t)(rbuf->fr_expire-ticks)<=0){
00530                 /* final response */
00531                 rbuf->t_active=0; /* mark the timer as removed 
00532                                                          (both timers disabled)
00533                                                           a little race risk, but
00534                                                           nothing bad would happen */
00535                 rbuf->flags|=F_RB_TIMEOUT;
00536                 /* WARNING:  the next line depends on taking care not to start the 
00537                  *           wait timer before finishing with t (if this is not 
00538                  *           guaranteed then comment the timer_allow_del() line) */
00539                 timer_allow_del(); /* [optional] allow timer_dels, since we're done
00540                                                           and there is no race risk */
00541                 final_response_handler(rbuf, t);
00542                 return 0;
00543         }else{
00544                 /*  4 possible states running (t1), t2, paused, disabled */
00545                         if ((s_ticks_t)(rbuf->retr_expire-ticks)<=0){
00546                                 if (rbuf->flags & F_RB_RETR_DISABLED)
00547                                         goto disabled;
00548                                 /* retr_interval= min (2*ri, rt_t2) , *p==2*ri*/
00549                                 /* no branch version: 
00550                                         #idef CC_SIGNED_RIGHT_SHIFT
00551                                                 ri=  rt_t2+((2*ri-rt_t2) & 
00552                                                 ((signed)(2*ri-rt_t2)>>(sizeof(ticks_t)*8-1));
00553                                         #else
00554                                                 ri=rt_t2+((2*ri-rt_t2)& -(2*ri<rt_t2));
00555                                         #endif
00556                                 */
00557                                 
00558                                 /* get the  current interval from timer param. */
00559                                 if ((rbuf->flags & F_RB_T2) || 
00560                                                 (((ticks_t)(unsigned long)p)>RT_T2_TIMEOUT(rbuf))){
00561                                         retr_interval=RT_T2_TIMEOUT(rbuf);
00562                                         new_retr_interval=RT_T2_TIMEOUT(rbuf);
00563                                 }else{
00564                                         retr_interval=(ticks_t)(unsigned long)p;
00565                                         new_retr_interval=retr_interval<<1;
00566                                 }
00567 #ifdef TIMER_DEBUG
00568                                 DBG("tm: timer: retr: new interval %d (max %d)\n", 
00569                                                 retr_interval, RT_T2_TIMEOUT(rbuf));
00570 #endif
00571                                 /* we could race with the reply_received code, but the 
00572                                  * worst thing that can happen is to delay a reset_to_t2
00573                                  * for crt_interval and send an extra retr.*/
00574                                 rbuf->retr_expire=ticks+retr_interval;
00575                                 /* set new interval to -1 on error, or retr_int. on success */
00576                                 retr_remainder=retransmission_handler(rbuf) | retr_interval;
00577                                 /* store the next retr. interval inside the timer struct,
00578                                  * in the data member */
00579                                 tl->data=(void*)(unsigned long)(new_retr_interval);
00580                         }else{
00581                                 retr_remainder= rbuf->retr_expire-ticks;
00582                                 DBG("tm: timer: retr: nothing to do, expire in %d\n", 
00583                                                 retr_remainder);
00584                         }
00585         }
00586 /* skip: */
00587         /* return minimum of the next retransmission handler and the 
00588          * final response (side benefit: it properly cancels timer if ret==0 and
00589          *  sleeps for fr_remainder if retr. is canceled [==(ticks_t)-1]) */
00590         fr_remainder=rbuf->fr_expire-ticks; /* to be more precise use
00591                                                                                         get_ticks_raw() instead of ticks
00592                                                                                         (but make sure that 
00593                                                                                         crt. ticks < fr_expire */
00594 #ifdef TIMER_DEBUG
00595         DBG("tm: timer retr_buf_handler @%d (%p ->%p->%p) exiting min (%d, %d)\n",
00596                         ticks, tl, rbuf, t, retr_remainder, fr_remainder);
00597 #endif
00598 #ifdef EXTRA_DEBUG
00599         if  (retr_remainder==0 || fr_remainder==0){
00600                 BUG("tm: timer retr_buf_handler: 0 remainder => disabling timer!: "
00601                                 "retr_remainder=%d, fr_remainder=%d\n", retr_remainder,
00602                                 fr_remainder);
00603         }
00604 #endif
00605         if (retr_remainder<fr_remainder)
00606                 return retr_remainder;
00607         else{
00608                 /* hack to switch to the slow timer */
00609 #ifdef TM_FAST_RETR_TIMER
00610                 tl->flags&=~F_TIMER_FAST;
00611 #endif
00612                 return fr_remainder;
00613         }
00614 disabled:
00615         return rbuf->fr_expire-ticks;
00616 }
00617 
00618 
00619 
00620 ticks_t wait_handler(ticks_t ti, struct timer_ln *wait_tl, void* data)
00621 {
00622         struct cell *p_cell;
00623         ticks_t ret;
00624 
00625         p_cell=(struct cell*)data;
00626 #ifdef TIMER_DEBUG
00627         DBG("DEBUG: WAIT timer hit @%d for %p (timer_lm %p)\n", 
00628                         ti, p_cell, wait_tl);
00629 #endif
00630 
00631 #ifdef TM_DEL_UNREF
00632         /* stop cancel timers if any running */
00633         if ( is_invite(p_cell) ) cleanup_localcancel_timers( p_cell );
00634         /* remove the cell from the hash table */
00635         LOCK_HASH( p_cell->hash_index );
00636         remove_from_hash_table_unsafe(  p_cell );
00637         UNLOCK_HASH( p_cell->hash_index );
00638         p_cell->flags |= T_IN_AGONY;
00639         UNREF_FREE(p_cell);
00640         ret=0;
00641 #else /* TM_DEL_UNREF */
00642         if (p_cell->flags & T_IN_AGONY){
00643                 /* delayed delete */
00644                 /* we call delete now without any locking on hash/ref_count;
00645                    we can do that because delete_handler is only entered after
00646                    the delete timer was installed from wait_handler, which
00647                    removed transaction from hash table and did not destroy it
00648                    because some processes were using it; that means that the
00649                    processes currently using the transaction can unref and no
00650                    new processes can ref -- we can wait until ref_count is
00651                    zero safely without locking
00652                 */
00653                 ret=delete_cell( p_cell, 0 /* don't unlock on return */ );
00654         }else {
00655                 /* stop cancel timers if any running */
00656                 if ( is_invite(p_cell) ) cleanup_localcancel_timers( p_cell );
00657                 /* remove the cell from the hash table */
00658                 LOCK_HASH( p_cell->hash_index );
00659                 remove_from_hash_table_unsafe(  p_cell );
00660                 p_cell->flags |= T_IN_AGONY;
00661                 /* delete (returns with UNLOCK-ed_HASH) */
00662                 ret=delete_cell( p_cell, 1 /* unlock on return */ );
00663         }
00664 #endif /* TM_DEL_UNREF */
00665         return ret;
00666 }
00667 

Generated on Thu Sep 9 04:15:55 2010 for SIPExpressRouter by  doxygen 1.3.9.1