2 * Copyright (c) 1997, 2000 Hellmuth Michaelis. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 *---------------------------------------------------------------------------
27 * i4b daemon - timer/timing support routines
28 * ------------------------------------------
30 * $Id: timer.c,v 1.4 2003/10/06 09:43:27 itojun Exp $
34 * last edit-date: [Tue May 2 15:58:31 2000]
36 *---------------------------------------------------------------------------*/
40 static int hr_callgate(void);
41 static void handle_reserved(struct cfg_entry
*cep
, time_t now
);
42 static void handle_active(struct cfg_entry
*cep
, time_t now
);
43 static void recover_illegal(struct cfg_entry
*cep
);
45 /*---------------------------------------------------------------------------*
46 * recover from illegal state
47 *---------------------------------------------------------------------------*/
49 recover_illegal(struct cfg_entry
*cep
)
51 logit(LL_ERR
, "recover_illegal: ERROR, entry %s attempting disconnect!", cep
->name
);
52 sendm_disconnect_req(cep
, (CAUSET_I4B
<< 8) | CAUSE_I4B_NORMAL
);
53 logit(LL_ERR
, "recover_illegal: ERROR, entry %s - reset state/cdid!", cep
->name
);
55 cep
->cdid
= CDID_UNUSED
;
58 /*---------------------------------------------------------------------------*
60 *---------------------------------------------------------------------------*/
62 start_timer(struct cfg_entry
*cep
, int seconds
)
64 cep
->timerval
= cep
->timerremain
= seconds
;
67 /*---------------------------------------------------------------------------*
69 *---------------------------------------------------------------------------*/
71 stop_timer(struct cfg_entry
*cep
)
73 cep
->timerval
= cep
->timerremain
= 0;
76 /*---------------------------------------------------------------------------*
77 * callgate for handle_recovery()
78 *---------------------------------------------------------------------------*/
82 static int tv_first
= 1;
83 static struct timeval tv_last
;
84 struct timeval tv_now
;
86 /* there must be 1 sec minimum between calls to this section */
90 gettimeofday(&tv_last
, NULL
);
94 gettimeofday(&tv_now
, NULL
);
96 if ((tv_now
.tv_sec
- tv_last
.tv_sec
) < 1)
99 DBGL(DL_TIME
, (logit(LL_DBG
, "time < 1 - last %ld:%ld now %ld:%ld",
100 tv_last
.tv_sec
, tv_last
.tv_usec
,
101 tv_now
.tv_sec
, tv_now
.tv_usec
)));
104 else if ((tv_now
.tv_sec
- tv_last
.tv_sec
) == 1)
106 if (((1000000 - tv_last
.tv_usec
) + tv_now
.tv_usec
) < 900000)
108 DBGL(DL_TIME
, (logit(LL_DBG
, "time < 900000us - last %ld:%ld now %ld:%ld",
109 tv_last
.tv_sec
, tv_last
.tv_usec
,
110 tv_now
.tv_sec
, tv_now
.tv_usec
)));
115 DBGL(DL_TIME
, (logit(LL_DBG
, "time OK! - last %ld:%ld now %ld:%ld",
116 tv_last
.tv_sec
, tv_last
.tv_usec
,
117 tv_now
.tv_sec
, tv_now
.tv_usec
)));
119 gettimeofday(&tv_last
, NULL
);
124 /*---------------------------------------------------------------------------*
125 * timeout, recovery and retry handling
126 *---------------------------------------------------------------------------*/
128 handle_recovery(void)
130 struct cfg_entry
*cep
= NULL
;
133 if (hr_callgate()) /* last call to handle_recovery < 1 sec ? */
134 return; /* yes, exit */
136 now
= time(NULL
); /* get current time */
138 /* walk thru all entries, look for work to do */
140 for (cep
= get_first_cfg_entry(); cep
; cep
= NEXT_CFE(cep
)) {
142 if (cep
->budget_callbackperiod
&& cep
->budget_callbackncalls
)
144 if (cep
->budget_callbackperiod_time
<= now
)
146 DBGL(DL_BDGT
, (logit(LL_DBG
, "%s: new cback-budget-period (%d s, %d left)",
147 cep
->name
, cep
->budget_callbackperiod
, cep
->budget_callbackncalls_cnt
)));
148 cep
->budget_callbackperiod_time
= now
+ cep
->budget_callbackperiod
;
149 cep
->budget_callbackncalls_cnt
= cep
->budget_callbackncalls
;
153 if (cep
->budget_calloutperiod
&& cep
->budget_calloutncalls
)
155 if (cep
->budget_calloutperiod_time
<= now
)
157 DBGL(DL_BDGT
, (logit(LL_DBG
, "%s: new cout-budget-period (%d s, %d left)",
158 cep
->name
, cep
->budget_calloutperiod
, cep
->budget_calloutncalls_cnt
)));
159 cep
->budget_calloutperiod_time
= now
+ cep
->budget_calloutperiod
;
160 cep
->budget_calloutncalls_cnt
= cep
->budget_calloutncalls
;
166 case CDID_UNUSED
: /* entry unused */
170 case CDID_RESERVED
: /* entry reserved */
171 handle_reserved(cep
, now
);
174 default: /* entry in use */
175 handle_active(cep
, now
);
181 /*---------------------------------------------------------------------------*
182 * timeout, recovery and retry handling for active entry
183 *---------------------------------------------------------------------------*/
185 handle_active(struct cfg_entry
*cep
, time_t now
)
190 if (cep
->timerval
&& (--(cep
->timerremain
)) <= 0)
192 DBGL(DL_RCVRY
, (logit(LL_DBG
, "handle_active: entry %s, TIMEOUT !!!", cep
->name
)));
193 cep
->timerval
= cep
->timerremain
= 0;
194 next_state(cep
, EV_TIMO
);
199 if (cep
->alert_time
> 0)
205 logit(LL_CHD
, "%05d %s answering: incoming call from %s to %s",
206 cep
->cdid
, cep
->name
,
207 cep
->real_phone_incoming
,
208 cep
->local_phone_incoming
);
209 next_state(cep
, EV_MCI
);
214 recover_illegal(cep
);
218 /* check hangup flag: if active, close connection */
222 DBGL(DL_RCVRY
, (logit(LL_DBG
, "handle_active: entry %s, hangup request!", cep
->name
)));
224 next_state(cep
, EV_DRQ
);
228 * if shorthold mode is rates based, check if
229 * we entered a time with a new unit length
232 if (cep
->unitlengthsrc
== ULSRC_RATE
)
234 int connecttime
= (int)difftime(now
, cep
->connect_time
);
236 if ((connecttime
> 1) &&
239 int newrate
= get_current_rate(cep
, 0);
241 if (newrate
!= cep
->unitlength
)
243 DBGL(DL_MSG
, (logit(LL_DBG
, "handle_active: rates unit length updated %d -> %d", cep
->unitlength
, newrate
)));
245 cep
->unitlength
= newrate
;
255 /*---------------------------------------------------------------------------*
256 * timeout, recovery and retry handling for reserved entry
257 *---------------------------------------------------------------------------*/
259 handle_reserved(struct cfg_entry
*cep
, time_t now
)
265 case ST_DIALRTMRCHD
: /* wait for dial retry time reached */
267 if (cep
->dialrandincr
)
268 waittime
= cep
->randomtime
;
270 waittime
= cep
->recoverytime
;
273 if (now
> (cep
->last_dial_time
+ waittime
))
275 DBGL(DL_RCVRY
, (logit(LL_DBG
, "handle_reserved: entry %s, dial retry request!", cep
->name
)));
276 cep
->state
= ST_DIALRETRY
;
278 if ((cep
->cdid
= get_cdid()) == 0)
280 logit(LL_ERR
, "handle_reserved: dialretry get_cdid() returned 0!");
281 cep
->state
= ST_IDLE
;
282 cep
->cdid
= CDID_UNUSED
;
286 if ((setup_dialout(cep
)) == GOOD
)
288 sendm_connect_req(cep
);
292 logit(LL_ERR
, "handle_reserved: dialretry setup_dialout returned ERROR!");
293 cep
->state
= ST_IDLE
;
294 cep
->cdid
= CDID_UNUSED
;
301 case ST_ACB_WAITDIAL
: /* active callback wait for time between disconnect and dial */
303 if (now
> (cep
->last_release_time
+ cep
->callbackwait
))
305 DBGL(DL_RCVRY
, (logit(LL_DBG
, "handle_reserved: entry %s, callback dial!", cep
->name
)));
306 cep
->state
= ST_ACB_DIAL
;
308 if ((cep
->cdid
= get_cdid()) == 0)
310 logit(LL_ERR
, "handle_reserved: callback get_cdid() returned 0!");
311 cep
->state
= ST_IDLE
;
312 cep
->cdid
= CDID_UNUSED
;
316 select_first_dialno(cep
);
318 if ((setup_dialout(cep
)) == GOOD
)
320 sendm_connect_req(cep
);
324 logit(LL_ERR
, "handle_reserved: callback setup_dialout returned ERROR!");
325 cep
->state
= ST_IDLE
;
326 cep
->cdid
= CDID_UNUSED
;
332 case ST_ACB_DIALFAIL
: /* callback to remote failed */
334 if (cep
->dialrandincr
)
335 waittime
= cep
->randomtime
+ cep
->recoverytime
;
337 waittime
= cep
->recoverytime
;
339 if (now
> (cep
->last_release_time
+ waittime
))
341 DBGL(DL_RCVRY
, (logit(LL_DBG
, "handle_reserved: entry %s, callback dial retry request!", cep
->name
)));
342 cep
->state
= ST_ACB_DIAL
;
344 if ((cep
->cdid
= get_cdid()) == 0)
346 logit(LL_ERR
, "handle_reserved: callback dialretry get_cdid() returned 0!");
347 cep
->state
= ST_IDLE
;
348 cep
->cdid
= CDID_UNUSED
;
352 if ((setup_dialout(cep
)) == GOOD
)
354 sendm_connect_req(cep
);
358 logit(LL_ERR
, "handle_reserved: callback dialretry setup_dialout returned ERROR!");
359 cep
->state
= ST_IDLE
;
360 cep
->cdid
= CDID_UNUSED
;
366 case ST_PCB_WAITCALL
: /* wait for remote calling back */
368 if (now
> (cep
->last_release_time
+ cep
->calledbackwait
))
372 if (cep
->dial_count
< cep
->dialretries
)
374 /* inside normal retry cycle */
376 DBGL(DL_RCVRY
, (logit(LL_DBG
, "handle_reserved: entry %s, retry calledback dial #%d!",
377 cep
->name
, cep
->dial_count
)));
378 cep
->state
= ST_PCB_DIAL
;
380 if ((cep
->cdid
= get_cdid()) == 0)
382 logit(LL_ERR
, "handle_reserved: calledback get_cdid() returned 0!");
383 cep
->state
= ST_IDLE
;
384 cep
->cdid
= CDID_UNUSED
;
387 select_next_dialno(cep
);
389 if ((setup_dialout(cep
)) == GOOD
)
391 sendm_connect_req(cep
);
395 logit(LL_ERR
, "handle_reserved: calledback setup_dialout returned ERROR!");
396 cep
->state
= ST_IDLE
;
397 cep
->cdid
= CDID_UNUSED
;
403 /* retries exhausted */
405 DBGL(DL_RCVRY
, (logit(LL_DBG
, "handle_reserved: calledback dial retries exhausted")));
406 dialresponse(cep
, DSTAT_TFAIL
);
407 cep
->cdid
= CDID_UNUSED
;
409 cep
->state
= ST_IDLE
;
414 case ST_DOWN
: /* interface was taken down */
416 if (now
> (cep
->went_down_time
+ cep
->downtime
))
418 DBGL(DL_RCVRY
, (logit(LL_DBG
, "handle_reserved: taking %s%d up", cep
->usrdevicename
, cep
->usrdeviceunit
)));
420 cep
->state
= ST_IDLE
;
421 cep
->cdid
= CDID_UNUSED
;
425 case ST_ILL
: /* illegal state reached, recover ! */
427 recover_illegal(cep
);