e7847d3d6b9c87fc90186bff857d8899b1a3e7a8
[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(rb)       ((rb)->my_T->rt_t1_timeout)
130 #define RT_T2_TIMEOUT(rb)       ((rb)->my_T->rt_t2_timeout)
131 #else
132 #define RT_T1_TIMEOUT(rb)       (cfg_get(tm, tm_cfg, rt_t1_timeout))
133 #define RT_T2_TIMEOUT(rb)       (cfg_get(tm, tm_cfg, rt_t2_timeout))
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;
146 extern struct msgid_var user_rt_t2_timeout;
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
170 ticks_t wait_handler(ticks_t t, struct timer_ln *tl, void* data);
171 ticks_t retr_buf_handler(ticks_t t, struct timer_ln *tl, void* data);
172
173
174 #define init_cell_timers(c) \
175         timer_init(&(c)->wait_timer, wait_handler, (c), F_TIMER_FAST) /* slow? */
176
177 #define init_rb_timers(rb) \
178         timer_init(&(rb)->timer, retr_buf_handler, \
179                                 (void*)(unsigned long)RT_T1_TIMEOUT(rb), 0)
180
181 /* set fr & retr timer
182  * rb  -  pointer to struct retr_buf
183  * retr - initial retr. in ticks (use (ticks_t)(-1) to disable)
184  * returns: -1 on error, 0 on success
185  */
186 #ifdef TIMER_DEBUG
187 inline static int _set_fr_retr(struct retr_buf* rb, ticks_t retr,
188                                                                 const char* file, const char* func,
189                                                                 unsigned line)
190 #else
191 inline static int _set_fr_retr(struct retr_buf* rb, ticks_t retr)
192 #endif
193 {
194         ticks_t timeout;
195         ticks_t ticks;
196         ticks_t eol;
197         int ret;
198         
199         ticks=get_ticks_raw();
200         timeout=rb->my_T->fr_timeout;
201         eol=rb->my_T->end_of_life;
202         rb->timer.data=(void*)(unsigned long)(2*retr); /* hack , next retr. int. */
203         rb->retr_expire=ticks+retr;
204         if (unlikely(rb->t_active)){
205                 /* we could have set_fr_retr called in the same time (acceptable 
206                  * race), we rely on timer_add adding it only once */
207 #ifdef TIMER_DEBUG
208                 LOG(L_WARN, "WARNING: _set_fr_timer called from: %s(%s):%d\n", 
209                                                 file, func, line);
210 #endif
211                 LOG(L_CRIT, "WARNING: -_set_fr_timer- already added: %p , tl=%p!!!\n",
212                                         rb, &rb->timer);
213         }
214         /* set active & if retr==-1 set disabled */
215         rb->flags|= (F_RB_RETR_DISABLED & -(retr==-1)); 
216 #ifdef TM_FAST_RETR_TIMER
217         /* set timer to fast if retr enabled (retr!=-1) */
218         rb->timer.flags|=(F_TIMER_FAST & -(retr!=-1));
219 #endif
220         /* adjust timeout to MIN(fr, maximum lifetime) if rb is a request
221          *  (for neg. replies we are force to wait for the ACK so use fr) */
222         if (unlikely ((rb->activ_type==TYPE_REQUEST) && 
223                 ((s_ticks_t)(eol-(ticks+timeout))<0)) ){ /* fr after end of life */
224                 timeout=(((s_ticks_t)(eol-ticks))>0)?(eol-ticks):1; /* expire now */ 
225         }
226         atomic_cmpxchg_int((void*)&rb->fr_expire, 0, (int)(ticks+timeout));
227         if (unlikely(rb->flags & F_RB_DEL_TIMER)){
228                 /* timer marked for deletion before we got a chance to add it
229                  * (e..g we got immediately a final reply before in another process)
230                  * => do nothing */
231                 DBG("_set_fr_timer: too late, timer already marked for deletion\n");
232                 return 0;
233         }
234 #ifdef TIMER_DEBUG
235         ret=timer_add_safe(&(rb)->timer, (timeout<retr)?timeout:retr,
236                                                         file, func, line);
237 #else
238         ret=timer_add(&(rb)->timer, (timeout<retr)?timeout:retr);
239 #endif
240         if (ret==0) rb->t_active=1;
241         membar_write_atomic_op(); /* make sure t_active will be commited to mem.
242                                                                  before the transaction would be deref. by the
243                                                                  current process */
244         return ret;
245 }
246
247
248
249 /* stop the timers assoc. with a retr. buf. */
250 #define stop_rb_timers(rb) \
251 do{ \
252         membar_depends(); \
253         (rb)->flags|=F_RB_DEL_TIMER; /* timer should be deleted */ \
254         if ((rb)->t_active){ \
255                 (rb)->t_active=0; \
256                 timer_del(&(rb)->timer); \
257         }\
258 }while(0)
259
260 /* one shot, once disabled it cannot be re-enabled */
261 #define stop_rb_retr(rb) \
262         ((rb)->flags|=F_RB_RETR_DISABLED)
263
264 /* reset retr. interval to t2 and restart retr. timer */
265 #define switch_rb_retr_to_t2(rb) \
266         do{ \
267                 (rb)->flags|=F_RB_T2; \
268                 (rb)->retr_expire=get_ticks_raw()+RT_T2_TIMEOUT(rb); \
269         }while(0)
270
271
272
273 inline static void restart_rb_fr(struct retr_buf* rb, ticks_t new_val)
274 {
275         ticks_t now;
276         struct cell* t;
277         
278         now=get_ticks_raw();
279         t=rb->my_T;
280         if (unlikely ((rb->activ_type==TYPE_REQUEST) &&
281                                         (((s_ticks_t)(t->end_of_life-(now+new_val)))<0)) )
282                 rb->fr_expire=t->end_of_life;
283         else
284                 rb->fr_expire=now+new_val;
285 }
286
287
288
289 /* change default & uac fr timers on-the-fly (if they are still running)
290  *  if timer value==0 => leave it unchanged
291  */
292 inline static void change_fr(struct cell* t, ticks_t fr_inv, ticks_t fr)
293 {
294         int i;
295         ticks_t fr_inv_expire, fr_expire, req_fr_expire;
296         
297         fr_expire=get_ticks_raw();
298         fr_inv_expire=fr_expire+fr_inv;
299         fr_expire+=fr;
300         req_fr_expire=((s_ticks_t)(t->end_of_life-fr_expire)<0)?
301                                                 t->end_of_life:fr_expire;
302         if (fr_inv) t->fr_inv_timeout=fr_inv;
303         if (fr) t->fr_timeout=fr;
304         for (i=0; i<t->nr_of_outgoings; i++){
305                 if (t->uac[i].request.t_active){ 
306                                 if ((t->uac[i].request.flags & F_RB_FR_INV) && fr_inv)
307                                         t->uac[i].request.fr_expire=fr_inv_expire;
308                                 else if (fr){
309                                         if (t->uac[i].request.activ_type==TYPE_REQUEST)
310                                                 t->uac[i].request.fr_expire=req_fr_expire;
311                                         else
312                                                 t->uac[i].request.fr_expire=fr_expire;
313                                 }
314                 }
315         }
316 }
317
318
319 #ifdef TM_DIFF_RT_TIMEOUT
320 /* change t1 & t2 retransmissions timers
321  * if now==1 try to change them almost on the fly 
322  *  (next retransmission either at rt_t1 or rt_t2)
323  * else only rt_t2 for running branches and both of them for new branches
324  *  if timer value==0 => leave it unchanged
325  */
326 inline static void change_retr(struct cell* t, int now,
327                                                                 ticks_t rt_t1, ticks_t rt_t2)
328 {
329         int i;
330
331         if (rt_t1) t->rt_t1_timeout=rt_t1;
332         if (rt_t2) t->rt_t2_timeout=rt_t2;
333         if (now){
334                 for (i=0; i<t->nr_of_outgoings; i++){
335                         if (t->uac[i].request.t_active){ 
336                                         if ((t->uac[i].request.flags & F_RB_T2) && rt_t2)
337                                                 /* not really needed (?) - if F_RB_T2 is set
338                                                  * t->rt_t2_timeout will be used anyway */
339                                                 t->uac[i].request.timer.data=
340                                                                         (void*)(unsigned long)rt_t2;
341                                         else if (rt_t1)
342                                                 t->uac[i].request.timer.data=
343                                                                         (void*)(unsigned long)rt_t1;
344                         }
345                 }
346         }
347 }
348 #endif /* TM_DIFF_RT_TIMEOUT */
349
350
351
352 /* set the maximum transaction lifetime (from the present moment)
353  * if adj is 1, adjust final response timeouts for all the req. branches such
354  * that they are all <= eol (note however that this will work only for
355  *  branches that still retransmit) */
356 inline static void change_end_of_life(struct cell* t, int adj, ticks_t eol)
357 {
358         int i;
359         
360         t->end_of_life=get_ticks_raw()+eol;
361         if (adj){
362                 for (i=0; i<t->nr_of_outgoings; i++){
363                         if (t->uac[i].request.t_active){ 
364                                         if ((t->uac[i].request.activ_type==TYPE_REQUEST) &&
365                                                         ((s_ticks_t)(t->end_of_life - 
366                                                                                 t->uac[i].request.fr_expire)<0))
367                                                 t->uac[i].request.fr_expire=t->end_of_life;
368                         }
369                 }
370         }
371 }
372
373 inline static void cleanup_localcancel_timers( struct cell *t )
374 {
375         int i;
376         for (i=0; i<t->nr_of_outgoings; i++ )
377                 stop_rb_timers(&t->uac[i].local_cancel);
378 }
379
380
381
382 inline static void unlink_timers( struct cell *t )
383 {
384         int i;
385
386         stop_rb_timers(&t->uas.response);
387         for (i=0; i<t->nr_of_outgoings; i++)
388                 stop_rb_timers(&t->uac[i].request);
389         cleanup_localcancel_timers(t);
390 }
391
392
393
394 #endif