modules/tm/timer.h

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001-2003 FhG Fokus
00003  *
00004  * This file is part of ser, a free SIP server.
00005  *
00006  * ser is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version
00010  *
00011  * For a license to use the ser software under conditions
00012  * other than those described here, or to purchase support for this
00013  * software, please contact iptel.org by e-mail at the following addresses:
00014  *    info@iptel.org
00015  *
00016  * ser is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License 
00022  * along with this program; if not, write to the Free Software 
00023  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024  */
00025 
00026 /*
00027  * History:
00028  * --------
00029  *  2003-09-12  timer_link.tg exists only if EXTRA_DEBUG (andrei)
00030  *  2004-02-13  timer_link.payload removed (bogdan)
00031  *  2005-11-03  rewritten to use the new timers (andrei)
00032  *  2007-06-01  support for different retr. intervals per transaction;
00033  *              added maximum inv. and non-inv. transaction life time (andrei)
00034  *  2007-06-09  wait timers and retr. timers (if TM_FAST_RETR_TIMER is defined)
00035  *               are run in a fast timer context switching to SLOW timer
00036  *               automatically for FR (andrei)
00037  */
00038 
00110 #ifndef _TM_TIMER_H
00111 #define _TM_TIMER_H
00112 
00113 #include "defs.h"
00114 
00115 #include "../../compiler_opt.h"
00116 #include "lock.h"
00117 
00118 #include "../../timer.h"
00119 #include "h_table.h"
00120 #include "config.h"
00121 
00125 #define TM_FAST_RETR_TIMER
00126 
00127 
00128 #ifdef  TM_DIFF_RT_TIMEOUT
00129 #define RT_T1_TIMEOUT_MS(rb)    ((rb)->my_T->rt_t1_timeout_ms)
00130 #define RT_T2_TIMEOUT_MS(rb)    ((rb)->my_T->rt_t2_timeout_ms)
00131 #else
00132 #define RT_T1_TIMEOUT_MS(rb)    (cfg_get(tm, tm_cfg, rt_t1_timeout_ms))
00133 #define RT_T2_TIMEOUT_MS(rb)    (cfg_get(tm, tm_cfg, rt_t2_timeout_ms))
00134 #endif
00135 
00136 #define TM_REQ_TIMEOUT(t) \
00137         (is_invite(t)? \
00138                 cfg_get(tm, tm_cfg, tm_max_inv_lifetime): \
00139                 cfg_get(tm, tm_cfg, tm_max_noninv_lifetime))
00140 
00141 
00142 extern struct msgid_var user_fr_timeout;
00143 extern struct msgid_var user_fr_inv_timeout;
00144 #ifdef TM_DIFF_RT_TIMEOUT
00145 extern struct msgid_var user_rt_t1_timeout_ms;
00146 extern struct msgid_var user_rt_t2_timeout_ms;
00147 #endif
00148 extern struct msgid_var user_inv_max_lifetime;
00149 extern struct msgid_var user_noninv_max_lifetime;
00150 
00151 
00155 extern int tm_init_timers(void);
00156 
00168 int timer_fixup(void *handle, str *gname, str *name, void **val);
00169 int timer_fixup_ms(void *handle, str *gname, str *name, void **val);
00170 
00171 ticks_t wait_handler(ticks_t t, struct timer_ln *tl, void* data);
00172 ticks_t retr_buf_handler(ticks_t t, struct timer_ln *tl, void* data);
00173 
00174 
00175 #define init_cell_timers(c) \
00176         timer_init(&(c)->wait_timer, wait_handler, (c), F_TIMER_FAST) /* slow? */
00177 
00178 #define init_rb_timers(rb) \
00179         timer_init(&(rb)->timer, retr_buf_handler, \
00180                                 (void*)(unsigned long)(RT_T1_TIMEOUT_MS(rb)), 0)
00181 
00182 /* set fr & retr timer
00183  * rb  -  pointer to struct retr_buf
00184  * retr - initial retr. in ticks (use (ticks_t)(-1) to disable)
00185  * returns: -1 on error, 0 on success
00186  */
00187 #ifdef TIMER_DEBUG
00188 inline static int _set_fr_retr(struct retr_buf* rb, unsigned retr_ms,
00189                                                                 const char* file, const char* func,
00190                                                                 unsigned line)
00191 #else
00192 inline static int _set_fr_retr(struct retr_buf* rb, unsigned retr_ms)
00193 #endif
00194 {
00195         ticks_t timeout;
00196         ticks_t ticks;
00197         ticks_t eol;
00198         ticks_t retr_ticks;
00199         int ret;
00200         
00201         ticks=get_ticks_raw();
00202         timeout=rb->my_T->fr_timeout;
00203         eol=rb->my_T->end_of_life;
00204         retr_ticks = (retr_ms != (unsigned)(-1))?MS_TO_TICKS(retr_ms):retr_ms;
00205         /* hack , next retr. int. */
00206         rb->timer.data=(void*)(unsigned long)(2*retr_ms);
00207         rb->retr_expire=ticks + retr_ticks;
00208         if (unlikely(rb->t_active)){
00209                 /* we could have set_fr_retr called in the same time (acceptable 
00210                  * race), we rely on timer_add adding it only once */
00211 #ifdef TIMER_DEBUG
00212                 LOG(L_WARN, "WARNING: _set_fr_timer called from: %s(%s):%d\n", 
00213                                                 file, func, line);
00214 #endif
00215                 LOG(L_CRIT, "WARNING: -_set_fr_timer- already added: %p , tl=%p!!!\n",
00216                                         rb, &rb->timer);
00217         }
00218         /* set active & if retr_ms==-1 set disabled */
00219         rb->flags|= (F_RB_RETR_DISABLED & -(retr_ms==(unsigned)-1));
00220 #ifdef TM_FAST_RETR_TIMER
00221         /* set timer to fast if retr enabled (retr_ms!=-1) */
00222         rb->timer.flags|=(F_TIMER_FAST & -(retr_ms!=(unsigned)-1));
00223 #endif
00224         /* adjust timeout to MIN(fr, maximum lifetime) if rb is a request
00225          *  (for neg. replies we are force to wait for the ACK so use fr) */
00226         if (unlikely ((rb->activ_type==TYPE_REQUEST) && 
00227                 ((s_ticks_t)(eol-(ticks+timeout))<0)) ){ /* fr after end of life */
00228                 timeout=(((s_ticks_t)(eol-ticks))>0)?(eol-ticks):1; /* expire now */ 
00229         }
00230         atomic_cmpxchg_int((void*)&rb->fr_expire, 0, (int)(ticks+timeout));
00231         if (unlikely(rb->flags & F_RB_DEL_TIMER)){
00232                 /* timer marked for deletion before we got a chance to add it
00233                  * (e..g we got immediately a final reply before in another process)
00234                  * => do nothing */
00235                 DBG("_set_fr_timer: too late, timer already marked for deletion\n");
00236                 return 0;
00237         }
00238 #ifdef TIMER_DEBUG
00239         ret=timer_add_safe(&(rb)->timer, (timeout<retr_ticks)?timeout:retr_ticks,
00240                                                         file, func, line);
00241 #else
00242         ret=timer_add(&(rb)->timer, (timeout<retr_ticks)?timeout:retr_ticks);
00243 #endif
00244         if (ret==0) rb->t_active=1;
00245         membar_write_atomic_op(); /* make sure t_active will be commited to mem.
00246                                                                  before the transaction would be deref. by the
00247                                                                  current process */
00248         return ret;
00249 }
00250 
00251 
00252 
00253 /* stop the timers assoc. with a retr. buf. */
00254 #define stop_rb_timers(rb) \
00255 do{ \
00256         membar_depends(); \
00257         (rb)->flags|=F_RB_DEL_TIMER; /* timer should be deleted */ \
00258         if ((rb)->t_active){ \
00259                 (rb)->t_active=0; \
00260                 timer_del(&(rb)->timer); \
00261         }\
00262 }while(0)
00263 
00264 /* one shot, once disabled it cannot be re-enabled */
00265 #define stop_rb_retr(rb) \
00266         ((rb)->flags|=F_RB_RETR_DISABLED)
00267 
00268 /* reset retr. interval to t2 and restart retr. timer */
00269 #define switch_rb_retr_to_t2(rb) \
00270         do{ \
00271                 (rb)->flags|=F_RB_T2; \
00272                 (rb)->retr_expire=get_ticks_raw()+MS_TO_TICKS(RT_T2_TIMEOUT_MS(rb)); \
00273         }while(0)
00274 
00275 
00276 
00277 inline static void restart_rb_fr(struct retr_buf* rb, ticks_t new_val)
00278 {
00279         ticks_t now;
00280         struct cell* t;
00281         
00282         now=get_ticks_raw();
00283         t=rb->my_T;
00284         if (unlikely ((rb->activ_type==TYPE_REQUEST) &&
00285                                         (((s_ticks_t)(t->end_of_life-(now+new_val)))<0)) )
00286                 rb->fr_expire=t->end_of_life;
00287         else
00288                 rb->fr_expire=now+new_val;
00289 }
00290 
00291 
00292 
00293 /* change default & uac fr timers on-the-fly (if they are still running)
00294  *  if timer value==0 => leave it unchanged
00295  */
00296 inline static void change_fr(struct cell* t, ticks_t fr_inv, ticks_t fr)
00297 {
00298         int i;
00299         ticks_t fr_inv_expire, fr_expire, req_fr_expire;
00300         
00301         fr_expire=get_ticks_raw();
00302         fr_inv_expire=fr_expire+fr_inv;
00303         fr_expire+=fr;
00304         req_fr_expire=((s_ticks_t)(t->end_of_life-fr_expire)<0)?
00305                                                 t->end_of_life:fr_expire;
00306         if (fr_inv) t->fr_inv_timeout=fr_inv;
00307         if (fr) t->fr_timeout=fr;
00308         for (i=0; i<t->nr_of_outgoings; i++){
00309                 if (t->uac[i].request.t_active){ 
00310                                 if ((t->uac[i].request.flags & F_RB_FR_INV) && fr_inv)
00311                                         t->uac[i].request.fr_expire=fr_inv_expire;
00312                                 else if (fr){
00313                                         if (t->uac[i].request.activ_type==TYPE_REQUEST)
00314                                                 t->uac[i].request.fr_expire=req_fr_expire;
00315                                         else
00316                                                 t->uac[i].request.fr_expire=fr_expire;
00317                                 }
00318                 }
00319         }
00320 }
00321 
00322 
00323 #ifdef TM_DIFF_RT_TIMEOUT
00324 /* change t1 & t2 retransmissions timers
00325  * if now==1 try to change them almost on the fly 
00326  *  (next retransmission either at rt_t1 or rt_t2)
00327  * else only rt_t2 for running branches and both of them for new branches
00328  *  if timer value==0 => leave it unchanged
00329  */
00330 inline static void change_retr(struct cell* t, int now,
00331                                                                 unsigned rt_t1_ms, unsigned rt_t2_ms)
00332 {
00333         int i;
00334 
00335         if (rt_t1_ms) t->rt_t1_timeout_ms=rt_t1_ms;
00336         if (rt_t2_ms) t->rt_t2_timeout_ms=rt_t2_ms;
00337         if (now){
00338                 for (i=0; i<t->nr_of_outgoings; i++){
00339                         if (t->uac[i].request.t_active){
00340                                         if ((t->uac[i].request.flags & F_RB_T2) && rt_t2_ms)
00341                                                 /* not really needed (?) - if F_RB_T2 is set
00342                                                  * t->rt_t2_timeout will be used anyway */
00343                                                 t->uac[i].request.timer.data =
00344                                                         (void*)(unsigned long)rt_t2_ms;
00345                                         else if (rt_t1_ms)
00346                                                 t->uac[i].request.timer.data =
00347                                                         (void*)(unsigned long)rt_t1_ms;
00348                         }
00349                 }
00350         }
00351 }
00352 #endif /* TM_DIFF_RT_TIMEOUT */
00353 
00354 
00355 
00356 /* set the maximum transaction lifetime (from the present moment)
00357  * if adj is 1, adjust final response timeouts for all the req. branches such
00358  * that they are all <= eol (note however that this will work only for
00359  *  branches that still retransmit) */
00360 inline static void change_end_of_life(struct cell* t, int adj, ticks_t eol)
00361 {
00362         int i;
00363         
00364         t->end_of_life=get_ticks_raw()+eol;
00365         if (adj){
00366                 for (i=0; i<t->nr_of_outgoings; i++){
00367                         if (t->uac[i].request.t_active){ 
00368                                         if ((t->uac[i].request.activ_type==TYPE_REQUEST) &&
00369                                                         ((s_ticks_t)(t->end_of_life - 
00370                                                                                 t->uac[i].request.fr_expire)<0))
00371                                                 t->uac[i].request.fr_expire=t->end_of_life;
00372                         }
00373                 }
00374         }
00375 }
00376 
00377 inline static void cleanup_localcancel_timers( struct cell *t )
00378 {
00379         int i;
00380         for (i=0; i<t->nr_of_outgoings; i++ )
00381                 stop_rb_timers(&t->uac[i].local_cancel);
00382 }
00383 
00384 
00385 
00386 inline static void unlink_timers( struct cell *t )
00387 {
00388         int i;
00389 
00390         stop_rb_timers(&t->uas.response);
00391         for (i=0; i<t->nr_of_outgoings; i++)
00392                 stop_rb_timers(&t->uac[i].request);
00393         cleanup_localcancel_timers(t);
00394 }
00395 
00396 
00397 
00398 #endif