2 * Copyright (c) 1997, 1999 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.19 1999/12/13 21:25:25 hm Exp $
34 * last edit-date: [Mon Dec 13 21:49:13 1999]
36 *---------------------------------------------------------------------------*/
40 static int hr_callgate(void);
41 static void handle_reserved(cfg_entry_t *cep, time_t now);
42 static void handle_active(cfg_entry_t *cep, time_t now);
43 static void recover_illegal(cfg_entry_t *cep);
45 /*---------------------------------------------------------------------------*
46 * recover from illegal state
47 *---------------------------------------------------------------------------*/
49 recover_illegal(cfg_entry_t *cep)
51 log(LL_ERR, "recover_illegal: ERROR, entry %s attempting disconnect!", cep->name);
52 sendm_disconnect_req(cep, (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL);
53 log(LL_ERR, "recover_illegal: ERROR, entry %s - reset state/cdid!", cep->name);
55 cep->cdid = CDID_UNUSED;
58 /*---------------------------------------------------------------------------*
60 *---------------------------------------------------------------------------*/
62 start_timer(cfg_entry_t *cep, int seconds)
64 cep->timerval = cep->timerremain = seconds;
67 /*---------------------------------------------------------------------------*
69 *---------------------------------------------------------------------------*/
71 stop_timer(cfg_entry_t *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, (log(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, (log(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, (log(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 cfg_entry_t *cep = NULL;
134 if(hr_callgate()) /* last call to handle_recovery < 1 sec ? */
135 return; /* yes, exit */
137 now = time(NULL); /* get current time */
139 /* walk thru all entries, look for work to do */
141 for(i=0; i < nentries; i++)
143 cep = &cfg_entry_tab[i]; /* ptr to config entry */
147 case CDID_UNUSED: /* entry unused */
151 case CDID_RESERVED: /* entry reserved */
152 handle_reserved(cep, now);
155 default: /* entry in use */
156 handle_active(cep, now);
162 /*---------------------------------------------------------------------------*
163 * timeout, recovery and retry handling for active entry
164 *---------------------------------------------------------------------------*/
166 handle_active(cfg_entry_t *cep, time_t now)
171 if(cep->timerval && (--(cep->timerremain)) <= 0)
173 DBGL(DL_RCVRY, (log(LL_DBG, "handle_active: entry %s, TIMEOUT !!!", cep->name)));
174 cep->timerval = cep->timerremain = 0;
175 next_state(cep, EV_TIMO);
180 if(cep->alert_time > 0)
186 log(LL_CHD, "%05d %s answering: incoming call from %s to %s",
187 cep->cdid, cep->name,
188 cep->real_phone_incoming,
189 cep->local_phone_incoming);
190 next_state(cep, EV_MCI);
195 recover_illegal(cep);
199 /* check hangup flag: if active, close connection */
203 DBGL(DL_RCVRY, (log(LL_DBG, "handle_active: entry %s, hangup request!", cep->name)));
205 next_state(cep, EV_DRQ);
209 * if shorthold mode is rates based, check if
210 * we entered a time with a new unit length
213 if(cep->unitlengthsrc == ULSRC_RATE)
215 int connecttime = (int)difftime(now, cep->connect_time);
217 if((connecttime > 1) &&
220 int newrate = get_current_rate(cep, 0);
222 if(newrate != cep->unitlength)
224 DBGL(DL_MSG, (log(LL_DBG, "handle_active: rates unit length updated %d -> %d", cep->unitlength, newrate)));
226 cep->unitlength = newrate;
236 /*---------------------------------------------------------------------------*
237 * timeout, recovery and retry handling for reserved entry
238 *---------------------------------------------------------------------------*/
240 handle_reserved(cfg_entry_t *cep, time_t now)
246 case ST_DIALRTMRCHD: /* wait for dial retry time reached */
248 if(cep->dialrandincr)
249 waittime = cep->randomtime;
251 waittime = cep->recoverytime;
254 if(now > (cep->last_dial_time + waittime))
256 DBGL(DL_RCVRY, (log(LL_DBG, "handle_reserved: entry %s, dial retry request!", cep->name)));
257 cep->state = ST_DIALRETRY;
259 if((cep->cdid = get_cdid()) == 0)
261 log(LL_ERR, "handle_reserved: dialretry get_cdid() returned 0!");
262 cep->state = ST_IDLE;
263 cep->cdid = CDID_UNUSED;
267 if((setup_dialout(cep)) == GOOD)
269 sendm_connect_req(cep);
273 log(LL_ERR, "handle_reserved: dialretry setup_dialout returned ERROR!");
274 cep->state = ST_IDLE;
275 cep->cdid = CDID_UNUSED;
282 case ST_ACB_WAITDIAL: /* active callback wait for time between disconnect and dial */
284 if(now > (cep->last_release_time + cep->callbackwait))
286 DBGL(DL_RCVRY, (log(LL_DBG, "handle_reserved: entry %s, callback dial!", cep->name)));
287 cep->state = ST_ACB_DIAL;
289 if((cep->cdid = get_cdid()) == 0)
291 log(LL_ERR, "handle_reserved: callback get_cdid() returned 0!");
292 cep->state = ST_IDLE;
293 cep->cdid = CDID_UNUSED;
297 select_first_dialno(cep);
299 if((setup_dialout(cep)) == GOOD)
301 sendm_connect_req(cep);
305 log(LL_ERR, "handle_reserved: callback setup_dialout returned ERROR!");
306 cep->state = ST_IDLE;
307 cep->cdid = CDID_UNUSED;
313 case ST_ACB_DIALFAIL: /* callback to remote failed */
315 if(cep->dialrandincr)
316 waittime = cep->randomtime + cep->recoverytime;
318 waittime = cep->recoverytime;
320 if(now > (cep->last_release_time + waittime))
322 DBGL(DL_RCVRY, (log(LL_DBG, "handle_reserved: entry %s, callback dial retry request!", cep->name)));
323 cep->state = ST_ACB_DIAL;
325 if((cep->cdid = get_cdid()) == 0)
327 log(LL_ERR, "handle_reserved: callback dialretry get_cdid() returned 0!");
328 cep->state = ST_IDLE;
329 cep->cdid = CDID_UNUSED;
333 if((setup_dialout(cep)) == GOOD)
335 sendm_connect_req(cep);
339 log(LL_ERR, "handle_reserved: callback dialretry setup_dialout returned ERROR!");
340 cep->state = ST_IDLE;
341 cep->cdid = CDID_UNUSED;
347 case ST_PCB_WAITCALL: /* wait for remote calling back */
349 if(now > (cep->last_release_time + cep->calledbackwait))
353 if(cep->dial_count < cep->dialretries)
355 /* inside normal retry cycle */
357 DBGL(DL_RCVRY, (log(LL_DBG, "handle_reserved: entry %s, retry calledback dial #%d!",
358 cep->name, cep->dial_count)));
359 cep->state = ST_PCB_DIAL;
361 if((cep->cdid = get_cdid()) == 0)
363 log(LL_ERR, "handle_reserved: calledback get_cdid() returned 0!");
364 cep->state = ST_IDLE;
365 cep->cdid = CDID_UNUSED;
368 select_next_dialno(cep);
370 if((setup_dialout(cep)) == GOOD)
372 sendm_connect_req(cep);
376 log(LL_ERR, "handle_reserved: calledback setup_dialout returned ERROR!");
377 cep->state = ST_IDLE;
378 cep->cdid = CDID_UNUSED;
384 /* retries exhausted */
386 DBGL(DL_RCVRY, (log(LL_DBG, "handle_reserved: calledback dial retries exhausted")));
387 dialresponse(cep, DSTAT_TFAIL);
388 cep->cdid = CDID_UNUSED;
390 cep->state = ST_IDLE;
395 case ST_DOWN: /* interface was taken down */
397 if(now > (cep->went_down_time + cep->downtime))
399 DBGL(DL_RCVRY, (log(LL_DBG, "handle_reserved: taking %s%d up", bdrivername(cep->usrdevicename), cep->usrdeviceunit)));
401 cep->state = ST_IDLE;
402 cep->cdid = CDID_UNUSED;
406 case ST_ILL: /* illegal state reached, recover ! */
408 recover_illegal(cep);