static ticks_t timer_handler(ticks_t ticks, struct timer_ln* tl, void* data) { /*?min length of first line of message is 16 char!?*/ #define MSG "GET /timer HTTP/0.9\n\n" struct sip_msg* msg; struct timer_action *a; struct run_act_ctx ra_ctx; a = data; if (!a->disable_itself) { DEBUG(MODULE_NAME": handler: called at %d ticks, timer: '%s', pid:%d\n", ticks, a->timer_name, getpid()); if (a->route_no >= main_rt.idx) { BUG(MODULE_NAME": invalid routing table number #%d of %d\n", a->route_no, main_rt.idx); goto err2; } if (!main_rt.rlist[a->route_no]) { WARN(MODULE_NAME": route not declared (hash:%d)\n", a->route_no); goto err2; } msg=pkg_malloc(sizeof(struct sip_msg)); if (msg==0) { ERR(MODULE_NAME": handler: no mem for sip_msg\n"); goto err2; } timer_msg_no++; memset(msg, 0, sizeof(struct sip_msg)); /* init everything to 0 */ msg->buf=MSG; msg->len=sizeof(MSG)-1; msg->rcv= rcv_info; msg->id=timer_msg_no; msg->set_global_address=default_global_address; msg->set_global_port=default_global_port; if (parse_msg(msg->buf, msg->len, msg)!=0){ ERR(MODULE_NAME": handler: parse_msg failed\n"); goto err; } /* ... clear branches from previous message */ clear_branches(); reset_static_buffer(); if (exec_pre_req_cb(msg)==0 ) goto end; /* drop the request */ /* exec the routing script */ timer_executed = a; init_run_actions_ctx(&ra_ctx); run_actions(&ra_ctx, main_rt.rlist[a->route_no], msg); timer_executed = 0; /* execute post request-script callbacks */ exec_post_req_cb(msg); end: reset_avps(); DEBUG(MODULE_NAME": handler: cleaning up\n"); err: free_sip_msg(msg); pkg_free(msg); err2: ; } /* begin critical section */ if (a->disable_itself) { timer_allow_del(a->link); timer_del(a->link); timer_reinit(a->link); a->disable_itself = 0; /* end critical section */ return 0; /* do no call more */ } else return (ticks_t)(-1); /* periodical */ }
/* the following assumption are made (to avoid deleting/re-adding the timer): * retr_buf->retr_interval < ( 1<<((sizeof(ticks_t)*8-1) ) * if retr_buf->retr_interval==0 => timer disabled * ==(ticks_t) -1 => retr. disabled (fr working) * retr_buf->retr_interval & (1 <<(sizeof(ticks_t)*8-1) => retr. & fr reset * (we never reset only retr, it's either reset both of them or retr * disabled & reset fr). In this case the fr_origin will contain the * "time" of the reset and next retr should occur at * fr->origin+retr_interval (we also assume that we'll never reset retr * to a lower value then the current one) */ ticks_t retr_buf_handler(ticks_t ticks, struct timer_ln *tl, void *p) { struct retr_buf *rbuf; ticks_t fr_remainder; ticks_t retr_remainder; ticks_t retr_interval; unsigned long new_retr_interval_ms; unsigned long crt_retr_interval_ms; struct cell *t; rbuf = (struct retr_buf *)((void *)tl - (void *)(&((struct retr_buf *)0)->timer)); membar_depends(); /* to be on the safe side */ t = rbuf->my_T; #ifdef TIMER_DEBUG LM_DBG("timer retr_buf_handler @%d (%p -> %p -> %p)\n", ticks, tl, rbuf, t); #endif if(unlikely(rbuf->flags & F_RB_DEL_TIMER)) { /* timer marked for deletion */ rbuf->t_active = 0; /* mark it as removed */ /* a membar is not really needed, in the very unlikely case that * another process will see old t_active's value and will try to * delete the timer again, but since timer_del it's safe in this cases * it will be a no-op */ return 0; } /* overflow safe check (should work ok for fr_intervals < max ticks_t/2) */ if((s_ticks_t)(rbuf->fr_expire - ticks) <= 0) { /* final response */ rbuf->t_active = 0; /* mark the timer as removed (both timers disabled) a little race risk, but nothing bad would happen */ rbuf->flags |= F_RB_TIMEOUT; /* WARNING: the next line depends on taking care not to start the * wait timer before finishing with t (if this is not * guaranteed then comment the timer_allow_del() line) */ timer_allow_del(); /* [optional] allow timer_dels, since we're done and there is no race risk */ final_response_handler(rbuf, t); return 0; } else { /* 4 possible states running (t1), t2, paused, disabled */ if((s_ticks_t)(rbuf->retr_expire - ticks) <= 0) { if(rbuf->flags & F_RB_RETR_DISABLED) goto disabled; crt_retr_interval_ms = (unsigned long)p; /* get the current interval from timer param. */ if(unlikely((rbuf->flags & F_RB_T2) || (crt_retr_interval_ms > RT_T2_TIMEOUT_MS(rbuf)))) { retr_interval = MS_TO_TICKS(RT_T2_TIMEOUT_MS(rbuf)); new_retr_interval_ms = RT_T2_TIMEOUT_MS(rbuf); } else { retr_interval = MS_TO_TICKS(crt_retr_interval_ms); new_retr_interval_ms = crt_retr_interval_ms << 1; } #ifdef TIMER_DEBUG LM_DBG("new interval %ld ms / %d ticks" " (max %d ms)\n", new_retr_interval_ms, retr_interval, RT_T2_TIMEOUT_MS(rbuf)); #endif /* we could race with the reply_received code, but the * worst thing that can happen is to delay a reset_to_t2 * for crt_interval and send an extra retr.*/ rbuf->retr_expire = ticks + retr_interval; /* set new interval to -1 on error, or retr_int. on success */ retr_remainder = retransmission_handler(rbuf) | retr_interval; /* store the next retr. interval in ms inside the timer struct, * in the data member */ tl->data = (void *)(new_retr_interval_ms); } else { retr_remainder = rbuf->retr_expire - ticks; LM_DBG("retr - nothing to do, expire in %d\n", retr_remainder); } } /* skip: */ /* return minimum of the next retransmission handler and the * final response (side benefit: it properly cancels timer if ret==0 and * sleeps for fr_remainder if retr. is canceled [==(ticks_t)-1]) */ fr_remainder = rbuf->fr_expire - ticks; /* to be more precise use get_ticks_raw() instead of ticks (but make sure that crt. ticks < fr_expire */ #ifdef TIMER_DEBUG LM_DBG("timer retr_buf_handler @%d (%p ->%p->%p) exiting min (%d, %d)\n", ticks, tl, rbuf, t, retr_remainder, fr_remainder); #endif #ifdef EXTRA_DEBUG if(retr_remainder == 0 || fr_remainder == 0) { LM_BUG("0 remainder => disabling timer!: " "retr_remainder=%d, fr_remainder=%d\n", retr_remainder, fr_remainder); } #endif if(retr_remainder < fr_remainder) return retr_remainder; else { /* hack to switch to the slow timer */ #ifdef TM_FAST_RETR_TIMER tl->flags &= ~F_TIMER_FAST; #endif return fr_remainder; } disabled: return rbuf->fr_expire - ticks; }