tm: keep internal retr. intervals in ms
[sip-router] / modules / tm / timer.h
1 /*
2  * Copyright (C) 2001-2003 FhG Fokus
3  *
4  * This file is part of ser, a free SIP server.
5  *
6  * ser is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version
10  *
11  * For a license to use the ser software under conditions
12  * other than those described here, or to purchase support for this
13  * software, please contact iptel.org by e-mail at the following addresses:
14  *    info@iptel.org
15  *
16  * ser is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License 
22  * along with this program; if not, write to the Free Software 
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  */
25
26 /*
27  * History:
28  * --------
29  *  2003-09-12  timer_link.tg exists only if EXTRA_DEBUG (andrei)
30  *  2004-02-13  timer_link.payload removed (bogdan)
31  *  2005-11-03  rewritten to use the new timers (andrei)
32  *  2007-06-01  support for different retr. intervals per transaction;
33  *              added maximum inv. and non-inv. transaction life time (andrei)
34  *  2007-06-09  wait timers and retr. timers (if TM_FAST_RETR_TIMER is defined)
35  *               are run in a fast timer context switching to SLOW timer
36  *               automatically for FR (andrei)
37  */
38
39 /**
40  * \file
41  * \brief TM :: timer support
42  * 
43  * TM timer support. It has been designed for high performance using
44  * some techniques of which timer users need to be aware.
45  * - One technique is "fixed-timer-length". We maintain separate 
46  * timer lists, all of them include elements of the same time
47  * to fire. That allows *appending* new events to the list as
48  * opposed to inserting them by time, which is costly due to
49  * searching time spent in a mutex. The performance benefit is
50  * noticeable. The limitation is you need a new timer list for
51  * each new timer length.
52  * - Another technique is the timer process slices off expired elements
53  * from the list in a mutex, but executes the timer after the mutex
54  * is left. That saves time greatly as whichever process wants to
55  * add/remove a timer, it does not have to wait until the current
56  * list is processed. However, be aware the timers may hit in a delayed
57  * manner; you have no guarantee in your process that after resetting a timer, 
58  * it will no more hit. It might have been removed by timer process,
59  * and is waiting to be executed.
60  * 
61  * The following example shows it:
62  * 
63  *              PROCESS1                                TIMER PROCESS
64  * 
65  * -    0.                                              timer hits, it is removed from queue and
66  *                                                      about to be executed
67  * -    1.      process1 decides to
68  *              reset the timer 
69  * -    2.                                              timer is executed now
70  * -    3.      if the process1 naively
71  *              thinks the timer could not 
72  *              have been executed after 
73  *              resetting the timer, it is
74  *              WRONG -- it was (step 2.)
75  * 
76  * So be careful when writing the timer handlers. Currently defined timers 
77  * don't hurt if they hit delayed, I hope at least. Retransmission timer 
78  * may results in a useless retransmission -- not too bad. FR timer not too
79  * bad either as timer processing uses a REPLY mutex making it safe to other
80  * processing affecting transaction state. Wait timer not bad either -- processes
81  * putting a transaction on wait don't do anything with it anymore.
82  * 
83  *      Example when it does not hurt:
84  * 
85  *              PROCESS1                                TIMER PROCESS
86  * 
87  * -    0.                                              RETR timer removed from list and
88  *                                                      scheduled for execution
89  * -    1. 200/BYE received->
90  *         reset RETR, put_on_wait
91  * -    2.                                              RETR timer executed -- too late but it does
92  *                                                      not hurt
93  * -    3.                                              WAIT handler executed
94  *
95  * The rule of thumb is don't touch data you put under a timer. Create data,
96  * put them under a timer, and let them live until they are safely destroyed from
97  * wait/delete timer.  The only safe place to manipulate the data is 
98  * from timer process in which delayed timers cannot hit (all timers are
99  * processed sequentially).
100  * 
101  * A "bad example" -- rewriting content of retransmission buffer
102  * in an unprotected way is bad because a delayed retransmission timer might 
103  * hit. Thats why our reply retransmission procedure is enclosed in 
104  * a REPLY_LOCK.
105  * \ingroup tm
106  */
107
108
109
110 #ifndef _TM_TIMER_H
111 #define _TM_TIMER_H
112
113 #include "defs.h"
114
115 #include "../../compiler_opt.h"
116 #include "lock.h"
117
118 #include "../../timer.h"
119 #include "h_table.h"
120 #include "config.h"
121
122 /**
123  * \brief try to do fast retransmissions (but fall back to slow timer for FR
124  */
125 #define TM_FAST_RETR_TIMER
126
127
128 #ifdef  TM_DIFF_RT_TIMEOUT
129 #define RT_T1_TIMEOUT_MS(rb)    ((rb)->my_T->rt_t1_timeout_ms)
130 #define RT_T2_TIMEOUT_MS(rb)    ((rb)->my_T->rt_t2_timeout_ms)
131 #else
132 #define RT_T1_TIMEOUT_MS(rb)    (cfg_get(tm, tm_cfg, rt_t1_timeout_ms))
133 #define RT_T2_TIMEOUT_MS(rb)    (cfg_get(tm, tm_cfg, rt_t2_timeout_ms))
134 #endif
135
136 #define TM_REQ_TIMEOUT(t) \
137         (is_invite(t)? \
138                 cfg_get(tm, tm_cfg, tm_max_inv_lifetime): \
139                 cfg_get(tm, tm_cfg, tm_max_noninv_lifetime))
140
141
142 extern struct msgid_var user_fr_timeout;
143 extern struct msgid_var user_fr_inv_timeout;
144 #ifdef TM_DIFF_RT_TIMEOUT
145 extern struct msgid_var user_rt_t1_timeout_ms;
146 extern struct msgid_var user_rt_t2_timeout_ms;
147 #endif
148 extern struct msgid_var user_inv_max_lifetime;
149 extern struct msgid_var user_noninv_max_lifetime;
150
151
152 /**
153  * \brief fix timer values to ticks
154  */
155 extern int tm_init_timers(void);
156
157 /**
158  * \brief Fixup function for the timer values
159  * 
160  * Fixup function for the timer values, (called by the
161  * configuration framework)
162  * \param handle not used
163  * \param gname not used
164  * \param name not used
165  * \param val fixed timer value
166  * \return 0 on success, -1 on error
167  */
168 int timer_fixup(void *handle, str *gname, str *name, void **val);
169 int timer_fixup_ms(void *handle, str *gname, str *name, void **val);
170
171 ticks_t wait_handler(ticks_t t, struct timer_ln *tl, void* data);
172 ticks_t retr_buf_handler(ticks_t t, struct timer_ln *tl, void* data);
173
174
175 #define init_cell_timers(c) \
176         timer_init(&(c)->wait_timer, wait_handler, (c), F_TIMER_FAST) /* slow? */
177
178 #define init_rb_timers(rb) \
179         timer_init(&(rb)->timer, retr_buf_handler, \
180                                 (void*)(unsigned long)(RT_T1_TIMEOUT_MS(rb)), 0)
181
182 /* set fr & retr timer
183  * rb  -  pointer to struct retr_buf
184  * retr - initial retr. in ticks (use (ticks_t)(-1) to disable)
185  * returns: -1 on error, 0 on success
186  */
187 #ifdef TIMER_DEBUG
188 inline static int _set_fr_retr(struct retr_buf* rb, unsigned retr_ms,
189                                                                 const char* file, const char* func,
190                                                                 unsigned line)
191 #else
192 inline static int _set_fr_retr(struct retr_buf* rb, unsigned retr_ms)
193 #endif
194 {
195         ticks_t timeout;
196         ticks_t ticks;
197         ticks_t eol;
198         ticks_t retr_ticks;
199         int ret;
200         
201         ticks=get_ticks_raw();
202         timeout=rb->my_T->fr_timeout;
203         eol=rb->my_T->end_of_life;
204         /* hack , next retr. int. */
205         retr_ticks = MS_TO_TICKS(retr_ms);
206         rb->timer.data=(void*)(unsigned long)(2*retr_ms);
207         rb->retr_expire=ticks + retr_ticks;
208         if (unlikely(rb->t_active)){
209                 /* we could have set_fr_retr called in the same time (acceptable 
210                  * race), we rely on timer_add adding it only once */
211 #ifdef TIMER_DEBUG
212                 LOG(L_WARN, "WARNING: _set_fr_timer called from: %s(%s):%d\n", 
213                                                 file, func, line);
214 #endif
215                 LOG(L_CRIT, "WARNING: -_set_fr_timer- already added: %p , tl=%p!!!\n",
216                                         rb, &rb->timer);
217         }
218         /* set active & if retr_ms==-1 set disabled */
219         rb->flags|= (F_RB_RETR_DISABLED & -(retr_ms==(unsigned)-1));
220 #ifdef TM_FAST_RETR_TIMER
221         /* set timer to fast if retr enabled (retr_ms!=-1) */
222         rb->timer.flags|=(F_TIMER_FAST & -(retr_ms!=(unsigned)-1));
223 #endif
224         /* adjust timeout to MIN(fr, maximum lifetime) if rb is a request
225          *  (for neg. replies we are force to wait for the ACK so use fr) */
226         if (unlikely ((rb->activ_type==TYPE_REQUEST) && 
227                 ((s_ticks_t)(eol-(ticks+timeout))<0)) ){ /* fr after end of life */
228                 timeout=(((s_ticks_t)(eol-ticks))>0)?(eol-ticks):1; /* expire now */ 
229         }
230         atomic_cmpxchg_int((void*)&rb->fr_expire, 0, (int)(ticks+timeout));
231         if (unlikely(rb->flags & F_RB_DEL_TIMER)){
232                 /* timer marked for deletion before we got a chance to add it
233                  * (e..g we got immediately a final reply before in another process)
234                  * => do nothing */
235                 DBG("_set_fr_timer: too late, timer already marked for deletion\n");
236                 return 0;
237         }
238 #ifdef TIMER_DEBUG
239         ret=timer_add_safe(&(rb)->timer, (timeout<retr_ticks)?timeout:retr_ticks,
240                                                         file, func, line);
241 #else
242         ret=timer_add(&(rb)->timer, (timeout<retr_ticks)?timeout:retr_ticks);
243 #endif
244         if (ret==0) rb->t_active=1;
245         membar_write_atomic_op(); /* make sure t_active will be commited to mem.
246                                                                  before the transaction would be deref. by the
247                                                                  current process */
248         return ret;
249 }
250
251
252
253 /* stop the timers assoc. with a retr. buf. */
254 #define stop_rb_timers(rb) \
255 do{ \
256         membar_depends(); \
257         (rb)->flags|=F_RB_DEL_TIMER; /* timer should be deleted */ \
258         if ((rb)->t_active){ \
259                 (rb)->t_active=0; \
260                 timer_del(&(rb)->timer); \
261         }\
262 }while(0)
263
264 /* one shot, once disabled it cannot be re-enabled */
265 #define stop_rb_retr(rb) \
266         ((rb)->flags|=F_RB_RETR_DISABLED)
267
268 /* reset retr. interval to t2 and restart retr. timer */
269 #define switch_rb_retr_to_t2(rb) \
270         do{ \
271                 (rb)->flags|=F_RB_T2; \
272                 (rb)->retr_expire=get_ticks_raw()+MS_TO_TICKS(RT_T2_TIMEOUT_MS(rb)); \
273         }while(0)
274
275
276
277 inline static void restart_rb_fr(struct retr_buf* rb, ticks_t new_val)
278 {
279         ticks_t now;
280         struct cell* t;
281         
282         now=get_ticks_raw();
283         t=rb->my_T;
284         if (unlikely ((rb->activ_type==TYPE_REQUEST) &&
285                                         (((s_ticks_t)(t->end_of_life-(now+new_val)))<0)) )
286                 rb->fr_expire=t->end_of_life;
287         else
288                 rb->fr_expire=now+new_val;
289 }
290
291
292
293 /* change default & uac fr timers on-the-fly (if they are still running)
294  *  if timer value==0 => leave it unchanged
295  */
296 inline static void change_fr(struct cell* t, ticks_t fr_inv, ticks_t fr)
297 {
298         int i;
299         ticks_t fr_inv_expire, fr_expire, req_fr_expire;
300         
301         fr_expire=get_ticks_raw();
302         fr_inv_expire=fr_expire+fr_inv;
303         fr_expire+=fr;
304         req_fr_expire=((s_ticks_t)(t->end_of_life-fr_expire)<0)?
305                                                 t->end_of_life:fr_expire;
306         if (fr_inv) t->fr_inv_timeout=fr_inv;
307         if (fr) t->fr_timeout=fr;
308         for (i=0; i<t->nr_of_outgoings; i++){
309                 if (t->uac[i].request.t_active){ 
310                                 if ((t->uac[i].request.flags & F_RB_FR_INV) && fr_inv)
311                                         t->uac[i].request.fr_expire=fr_inv_expire;
312                                 else if (fr){
313                                         if (t->uac[i].request.activ_type==TYPE_REQUEST)
314                                                 t->uac[i].request.fr_expire=req_fr_expire;
315                                         else
316                                                 t->uac[i].request.fr_expire=fr_expire;
317                                 }
318                 }
319         }
320 }
321
322
323 #ifdef TM_DIFF_RT_TIMEOUT
324 /* change t1 & t2 retransmissions timers
325  * if now==1 try to change them almost on the fly 
326  *  (next retransmission either at rt_t1 or rt_t2)
327  * else only rt_t2 for running branches and both of them for new branches
328  *  if timer value==0 => leave it unchanged
329  */
330 inline static void change_retr(struct cell* t, int now,
331                                                                 unsigned rt_t1_ms, unsigned rt_t2_ms)
332 {
333         int i;
334
335         if (rt_t1_ms) t->rt_t1_timeout_ms=rt_t1_ms;
336         if (rt_t2_ms) t->rt_t2_timeout_ms=rt_t2_ms;
337         if (now){
338                 for (i=0; i<t->nr_of_outgoings; i++){
339                         if (t->uac[i].request.t_active){
340                                         if ((t->uac[i].request.flags & F_RB_T2) && rt_t2_ms)
341                                                 /* not really needed (?) - if F_RB_T2 is set
342                                                  * t->rt_t2_timeout will be used anyway */
343                                                 t->uac[i].request.timer.data =
344                                                         (void*)(unsigned long)rt_t2_ms;
345                                         else if (rt_t1_ms)
346                                                 t->uac[i].request.timer.data =
347                                                         (void*)(unsigned long)rt_t1_ms;
348                         }
349                 }
350         }
351 }
352 #endif /* TM_DIFF_RT_TIMEOUT */
353
354
355
356 /* set the maximum transaction lifetime (from the present moment)
357  * if adj is 1, adjust final response timeouts for all the req. branches such
358  * that they are all <= eol (note however that this will work only for
359  *  branches that still retransmit) */
360 inline static void change_end_of_life(struct cell* t, int adj, ticks_t eol)
361 {
362         int i;
363         
364         t->end_of_life=get_ticks_raw()+eol;
365         if (adj){
366                 for (i=0; i<t->nr_of_outgoings; i++){
367                         if (t->uac[i].request.t_active){ 
368                                         if ((t->uac[i].request.activ_type==TYPE_REQUEST) &&
369                                                         ((s_ticks_t)(t->end_of_life - 
370                                                                                 t->uac[i].request.fr_expire)<0))
371                                                 t->uac[i].request.fr_expire=t->end_of_life;
372                         }
373                 }
374         }
375 }
376
377 inline static void cleanup_localcancel_timers( struct cell *t )
378 {
379         int i;
380         for (i=0; i<t->nr_of_outgoings; i++ )
381                 stop_rb_timers(&t->uac[i].local_cancel);
382 }
383
384
385
386 inline static void unlink_timers( struct cell *t )
387 {
388         int i;
389
390         stop_rb_timers(&t->uas.response);
391         for (i=0; i<t->nr_of_outgoings; i++)
392                 stop_rb_timers(&t->uac[i].request);
393         cleanup_localcancel_timers(t);
394 }
395
396
397
398 #endif