MFC r1.6 r1.30 r1.28 (HEAD):
[dragonfly.git] / usr.sbin / i4b / isdnd / timer.c
blobc2a5881d0113e4b75fd6378cb864681832151f55
1 /*
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
6 * are met:
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
23 * SUCH DAMAGE.
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 *---------------------------------------------------------------------------*/
37 #include "isdnd.h"
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 *---------------------------------------------------------------------------*/
47 static void
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);
53 cep->state = ST_IDLE;
54 cep->cdid = CDID_UNUSED;
57 /*---------------------------------------------------------------------------*
58 * start the timer
59 *---------------------------------------------------------------------------*/
60 void
61 start_timer(cfg_entry_t *cep, int seconds)
63 cep->timerval = cep->timerremain = seconds;
66 /*---------------------------------------------------------------------------*
67 * stop the timer
68 *---------------------------------------------------------------------------*/
69 void
70 stop_timer(cfg_entry_t *cep)
72 cep->timerval = cep->timerremain = 0;
75 /*---------------------------------------------------------------------------*
76 * callgate for handle_recovery()
77 *---------------------------------------------------------------------------*/
78 static int
79 hr_callgate(void)
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 */
87 if(tv_first)
89 gettimeofday(&tv_last, NULL);
90 tv_first = 0;
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)));
101 return(1);
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)));
110 return(1);
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);
120 return(0);
123 /*---------------------------------------------------------------------------*
124 * timeout, recovery and retry handling
125 *---------------------------------------------------------------------------*/
126 void
127 handle_recovery(void)
129 cfg_entry_t *cep = NULL;
130 int i;
131 time_t now;
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;
166 switch(cep->cdid)
168 case CDID_UNUSED: /* entry unused */
169 continue;
170 break;
172 case CDID_RESERVED: /* entry reserved */
173 handle_reserved(cep, now);
174 break;
176 default: /* entry in use */
177 handle_active(cep, now);
178 break;
183 /*---------------------------------------------------------------------------*
184 * timeout, recovery and retry handling for active entry
185 *---------------------------------------------------------------------------*/
186 static void
187 handle_active(cfg_entry_t *cep, time_t now)
189 switch(cep->state)
191 case ST_ACCEPTED:
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);
198 break;
200 case ST_ALERT:
201 if(cep->alert_time > 0)
203 cep->alert_time--;
205 else
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);
213 break;
215 case ST_ILL:
216 recover_illegal(cep);
217 break;
219 default:
220 /* check hangup flag: if active, close connection */
222 if(cep->hangup)
224 DBGL(DL_RCVRY, (log(LL_DBG, "handle_active: entry %s, hangup request!", cep->name)));
225 cep->hangup = 0;
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) &&
253 (connecttime % 60))
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;
263 unitlen_chkupd(cep);
267 break;
271 /*---------------------------------------------------------------------------*
272 * timeout, recovery and retry handling for reserved entry
273 *---------------------------------------------------------------------------*/
274 static void
275 handle_reserved(cfg_entry_t *cep, time_t now)
277 time_t waittime;
279 switch(cep->state)
281 case ST_DIALRTMRCHD: /* wait for dial retry time reached */
283 if(cep->dialrandincr)
284 waittime = cep->randomtime;
285 else
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;
299 return;
302 if((setup_dialout(cep)) == GOOD)
304 sendm_connect_req(cep);
306 else
308 log(LL_ERR, "handle_reserved: dialretry setup_dialout returned ERROR!");
309 cep->state = ST_IDLE;
310 cep->cdid = CDID_UNUSED;
311 return;
314 break;
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;
329 return;
332 select_first_dialno(cep);
334 if((setup_dialout(cep)) == GOOD)
336 sendm_connect_req(cep);
338 else
340 log(LL_ERR, "handle_reserved: callback setup_dialout returned ERROR!");
341 cep->state = ST_IDLE;
342 cep->cdid = CDID_UNUSED;
343 return;
346 break;
348 case ST_ACB_DIALFAIL: /* callback to remote failed */
350 if(cep->dialrandincr)
351 waittime = cep->randomtime + cep->recoverytime;
352 else
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;
365 return;
368 if((setup_dialout(cep)) == GOOD)
370 sendm_connect_req(cep);
372 else
374 log(LL_ERR, "handle_reserved: callback dialretry setup_dialout returned ERROR!");
375 cep->state = ST_IDLE;
376 cep->cdid = CDID_UNUSED;
377 return;
380 break;
382 case ST_PCB_WAITCALL: /* wait for remote calling back */
384 if(now > (cep->last_release_time + cep->calledbackwait))
386 cep->dial_count++;
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;
401 return;
403 select_next_dialno(cep);
405 if((setup_dialout(cep)) == GOOD)
407 sendm_connect_req(cep);
409 else
411 log(LL_ERR, "handle_reserved: calledback setup_dialout returned ERROR!");
412 cep->state = ST_IDLE;
413 cep->cdid = CDID_UNUSED;
414 return;
417 else
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;
424 cep->dial_count = 0;
425 cep->state = ST_IDLE;
428 break;
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)));
435 if_up(cep);
436 cep->state = ST_IDLE;
437 cep->cdid = CDID_UNUSED;
439 break;
441 case ST_ILL: /* illegal state reached, recover ! */
443 recover_illegal(cep);
444 break;
448 /* EOF */