2 * Copyright (c) 1997, 2001 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 * $FreeBSD: src/usr.sbin/i4b/isdnd/timer.c,v 1.6.2.2 2001/08/10 23:17:32 obrien Exp $
31 * $DragonFly: src/usr.sbin/i4b/isdnd/timer.c,v 1.2 2003/06/17 04:29:54 dillon Exp $
33 * last edit-date: [Fri Jul 20 20:29:28 2001]
35 *---------------------------------------------------------------------------*/
39 static int hr_callgate(void);
40 static void handle_reserved(cfg_entry_t
*cep
, time_t now
);
41 static void handle_active(cfg_entry_t
*cep
, time_t now
);
42 static void recover_illegal(cfg_entry_t
*cep
);
44 /*---------------------------------------------------------------------------*
45 * recover from illegal state
46 *---------------------------------------------------------------------------*/
48 recover_illegal(cfg_entry_t
*cep
)
50 log(LL_ERR
, "recover_illegal: ERROR, entry %s attempting disconnect!", cep
->name
);
51 sendm_disconnect_req(cep
, (CAUSET_I4B
<< 8) | CAUSE_I4B_NORMAL
);
52 log(LL_ERR
, "recover_illegal: ERROR, entry %s - reset state/cdid!", cep
->name
);
54 cep
->cdid
= CDID_UNUSED
;
57 /*---------------------------------------------------------------------------*
59 *---------------------------------------------------------------------------*/
61 start_timer(cfg_entry_t
*cep
, int seconds
)
63 cep
->timerval
= cep
->timerremain
= seconds
;
66 /*---------------------------------------------------------------------------*
68 *---------------------------------------------------------------------------*/
70 stop_timer(cfg_entry_t
*cep
)
72 cep
->timerval
= cep
->timerremain
= 0;
75 /*---------------------------------------------------------------------------*
76 * callgate for handle_recovery()
77 *---------------------------------------------------------------------------*/
81 static int tv_first
= 1;
82 static struct timeval tv_last
;
83 struct timeval tv_now
;
85 /* there must be 1 sec minimum between calls to this section */
89 gettimeofday(&tv_last
, NULL
);
93 gettimeofday(&tv_now
, NULL
);
95 if((tv_now
.tv_sec
- tv_last
.tv_sec
) < 1)
98 DBGL(DL_TIME
, (log(LL_DBG
, "time < 1 - last %ld:%ld now %ld:%ld",
99 tv_last
.tv_sec
, tv_last
.tv_usec
,
100 tv_now
.tv_sec
, tv_now
.tv_usec
)));
103 else if((tv_now
.tv_sec
- tv_last
.tv_sec
) == 1)
105 if(((1000000 - tv_last
.tv_usec
) + tv_now
.tv_usec
) < 900000)
107 DBGL(DL_TIME
, (log(LL_DBG
, "time < 900000us - last %ld:%ld now %ld:%ld",
108 tv_last
.tv_sec
, tv_last
.tv_usec
,
109 tv_now
.tv_sec
, tv_now
.tv_usec
)));
114 DBGL(DL_TIME
, (log(LL_DBG
, "time OK! - last %ld:%ld now %ld:%ld",
115 tv_last
.tv_sec
, tv_last
.tv_usec
,
116 tv_now
.tv_sec
, tv_now
.tv_usec
)));
118 gettimeofday(&tv_last
, NULL
);
123 /*---------------------------------------------------------------------------*
124 * timeout, recovery and retry handling
125 *---------------------------------------------------------------------------*/
127 handle_recovery(void)
129 cfg_entry_t
*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(i
=0; i
< nentries
; i
++)
142 cep
= &cfg_entry_tab
[i
]; /* ptr to config entry */
144 if(cep
->budget_callbackperiod
&& cep
->budget_callbackncalls
)
146 if(cep
->budget_callbackperiod_time
<= now
)
148 DBGL(DL_BDGT
, (log(LL_DBG
, "%s: new cback-budget-period (%d s, %d left)",
149 cep
->name
, cep
->budget_callbackperiod
, cep
->budget_callbackncalls_cnt
)));
150 cep
->budget_callbackperiod_time
= now
+ cep
->budget_callbackperiod
;
151 cep
->budget_callbackncalls_cnt
= cep
->budget_callbackncalls
;
155 if(cep
->budget_calloutperiod
&& cep
->budget_calloutncalls
)
157 if(cep
->budget_calloutperiod_time
<= now
)
159 DBGL(DL_BDGT
, (log(LL_DBG
, "%s: new cout-budget-period (%d s, %d left)",
160 cep
->name
, cep
->budget_calloutperiod
, cep
->budget_calloutncalls_cnt
)));
161 cep
->budget_calloutperiod_time
= now
+ cep
->budget_calloutperiod
;
162 cep
->budget_calloutncalls_cnt
= cep
->budget_calloutncalls
;
168 case CDID_UNUSED
: /* entry unused */
172 case CDID_RESERVED
: /* entry reserved */
173 handle_reserved(cep
, now
);
176 default: /* entry in use */
177 handle_active(cep
, now
);
183 /*---------------------------------------------------------------------------*
184 * timeout, recovery and retry handling for active entry
185 *---------------------------------------------------------------------------*/
187 handle_active(cfg_entry_t
*cep
, time_t now
)
192 if(cep
->timerval
&& (--(cep
->timerremain
)) <= 0)
194 DBGL(DL_RCVRY
, (log(LL_DBG
, "handle_active: entry %s, TIMEOUT !!!", cep
->name
)));
195 cep
->timerval
= cep
->timerremain
= 0;
196 next_state(cep
, EV_TIMO
);
201 if(cep
->alert_time
> 0)
207 log(LL_CHD
, "%05d %s answering: incoming call from %s to %s",
208 cep
->cdid
, cep
->name
,
209 cep
->real_phone_incoming
,
210 cep
->local_phone_incoming
);
211 next_state(cep
, EV_MCI
);
216 recover_illegal(cep
);
220 /* check hangup flag: if active, close connection */
224 DBGL(DL_RCVRY
, (log(LL_DBG
, "handle_active: entry %s, hangup request!", cep
->name
)));
226 next_state(cep
, EV_DRQ
);
229 /* check maximum connect time reached */
231 if(cep
->maxconnecttime
> 0 && cep
->connect_time
> 0)
233 int connecttime
= (int)difftime(now
, cep
->connect_time
);
234 if(connecttime
> cep
->maxconnecttime
)
236 DBGL(DL_RCVRY
, (log(LL_DBG
,
237 "handle_active: entry %s, maxconnecttime %d reached!",
238 cep
->name
, cep
->maxconnecttime
)));
239 next_state(cep
, EV_DRQ
);
244 * if shorthold mode is rates based, check if
245 * we entered a time with a new unit length
248 if(cep
->unitlengthsrc
== ULSRC_RATE
)
250 int connecttime
= (int)difftime(now
, cep
->connect_time
);
252 if((connecttime
> 1) &&
255 int newrate
= get_current_rate(cep
, 0);
257 if(newrate
!= cep
->unitlength
)
259 DBGL(DL_MSG
, (log(LL_DBG
, "handle_active: rates unit length updated %d -> %d", cep
->unitlength
, newrate
)));
261 cep
->unitlength
= newrate
;
271 /*---------------------------------------------------------------------------*
272 * timeout, recovery and retry handling for reserved entry
273 *---------------------------------------------------------------------------*/
275 handle_reserved(cfg_entry_t
*cep
, time_t now
)
281 case ST_DIALRTMRCHD
: /* wait for dial retry time reached */
283 if(cep
->dialrandincr
)
284 waittime
= cep
->randomtime
;
286 waittime
= cep
->recoverytime
;
289 if(now
> (cep
->last_dial_time
+ waittime
))
291 DBGL(DL_RCVRY
, (log(LL_DBG
, "handle_reserved: entry %s, dial retry request!", cep
->name
)));
292 cep
->state
= ST_DIALRETRY
;
294 if((cep
->cdid
= get_cdid()) == 0)
296 log(LL_ERR
, "handle_reserved: dialretry get_cdid() returned 0!");
297 cep
->state
= ST_IDLE
;
298 cep
->cdid
= CDID_UNUSED
;
302 if((setup_dialout(cep
)) == GOOD
)
304 sendm_connect_req(cep
);
308 log(LL_ERR
, "handle_reserved: dialretry setup_dialout returned ERROR!");
309 cep
->state
= ST_IDLE
;
310 cep
->cdid
= CDID_UNUSED
;
317 case ST_ACB_WAITDIAL
: /* active callback wait for time between disconnect and dial */
319 if(now
> (cep
->last_release_time
+ cep
->callbackwait
))
321 DBGL(DL_RCVRY
, (log(LL_DBG
, "handle_reserved: entry %s, callback dial!", cep
->name
)));
322 cep
->state
= ST_ACB_DIAL
;
324 if((cep
->cdid
= get_cdid()) == 0)
326 log(LL_ERR
, "handle_reserved: callback get_cdid() returned 0!");
327 cep
->state
= ST_IDLE
;
328 cep
->cdid
= CDID_UNUSED
;
332 select_first_dialno(cep
);
334 if((setup_dialout(cep
)) == GOOD
)
336 sendm_connect_req(cep
);
340 log(LL_ERR
, "handle_reserved: callback setup_dialout returned ERROR!");
341 cep
->state
= ST_IDLE
;
342 cep
->cdid
= CDID_UNUSED
;
348 case ST_ACB_DIALFAIL
: /* callback to remote failed */
350 if(cep
->dialrandincr
)
351 waittime
= cep
->randomtime
+ cep
->recoverytime
;
353 waittime
= cep
->recoverytime
;
355 if(now
> (cep
->last_release_time
+ waittime
))
357 DBGL(DL_RCVRY
, (log(LL_DBG
, "handle_reserved: entry %s, callback dial retry request!", cep
->name
)));
358 cep
->state
= ST_ACB_DIAL
;
360 if((cep
->cdid
= get_cdid()) == 0)
362 log(LL_ERR
, "handle_reserved: callback dialretry get_cdid() returned 0!");
363 cep
->state
= ST_IDLE
;
364 cep
->cdid
= CDID_UNUSED
;
368 if((setup_dialout(cep
)) == GOOD
)
370 sendm_connect_req(cep
);
374 log(LL_ERR
, "handle_reserved: callback dialretry setup_dialout returned ERROR!");
375 cep
->state
= ST_IDLE
;
376 cep
->cdid
= CDID_UNUSED
;
382 case ST_PCB_WAITCALL
: /* wait for remote calling back */
384 if(now
> (cep
->last_release_time
+ cep
->calledbackwait
))
388 if(cep
->dial_count
< cep
->dialretries
)
390 /* inside normal retry cycle */
392 DBGL(DL_RCVRY
, (log(LL_DBG
, "handle_reserved: entry %s, retry calledback dial #%d!",
393 cep
->name
, cep
->dial_count
)));
394 cep
->state
= ST_PCB_DIAL
;
396 if((cep
->cdid
= get_cdid()) == 0)
398 log(LL_ERR
, "handle_reserved: calledback get_cdid() returned 0!");
399 cep
->state
= ST_IDLE
;
400 cep
->cdid
= CDID_UNUSED
;
403 select_next_dialno(cep
);
405 if((setup_dialout(cep
)) == GOOD
)
407 sendm_connect_req(cep
);
411 log(LL_ERR
, "handle_reserved: calledback setup_dialout returned ERROR!");
412 cep
->state
= ST_IDLE
;
413 cep
->cdid
= CDID_UNUSED
;
419 /* retries exhausted */
421 DBGL(DL_RCVRY
, (log(LL_DBG
, "handle_reserved: calledback dial retries exhausted")));
422 dialresponse(cep
, DSTAT_TFAIL
);
423 cep
->cdid
= CDID_UNUSED
;
425 cep
->state
= ST_IDLE
;
430 case ST_DOWN
: /* interface was taken down */
432 if(now
> (cep
->went_down_time
+ cep
->downtime
))
434 DBGL(DL_RCVRY
, (log(LL_DBG
, "handle_reserved: taking %s%d up", bdrivername(cep
->usrdevicename
), cep
->usrdeviceunit
)));
436 cep
->state
= ST_IDLE
;
437 cep
->cdid
= CDID_UNUSED
;
441 case ST_ILL
: /* illegal state reached, recover ! */
443 recover_illegal(cep
);