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.17 1999/02/14 09:44:57 hm Exp $
32 * last edit-date: [Sun Feb 14 10:12:32 1999]
34 *---------------------------------------------------------------------------*/
38 static int hr_callgate(void);
39 static void handle_reserved(cfg_entry_t *cep, time_t now);
40 static void handle_active(cfg_entry_t *cep, time_t now);
41 static void recover_illegal(cfg_entry_t *cep);
43 /*---------------------------------------------------------------------------*
44 * recover from illegal state
45 *---------------------------------------------------------------------------*/
47 recover_illegal(cfg_entry_t *cep)
49 log(LL_ERR, "recover_illegal: ERROR, entry %s attempting disconnect!", cep->name);
50 sendm_disconnect_req(cep, (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL);
51 log(LL_ERR, "recover_illegal: ERROR, entry %s - reset state/cdid!", cep->name);
53 cep->cdid = CDID_UNUSED;
56 /*---------------------------------------------------------------------------*
58 *---------------------------------------------------------------------------*/
60 start_timer(cfg_entry_t *cep, int seconds)
62 cep->timerval = cep->timerremain = seconds;
65 /*---------------------------------------------------------------------------*
67 *---------------------------------------------------------------------------*/
69 stop_timer(cfg_entry_t *cep)
71 cep->timerval = cep->timerremain = 0;
74 /*---------------------------------------------------------------------------*
75 * callgate for handle_recovery()
76 *---------------------------------------------------------------------------*/
80 static int tv_first = 1;
81 static struct timeval tv_last;
82 struct timeval tv_now;
84 /* there must be 1 sec minimum between calls to this section */
88 gettimeofday(&tv_last, NULL);
92 gettimeofday(&tv_now, NULL);
94 if((tv_now.tv_sec - tv_last.tv_sec) < 1)
97 DBGL(DL_TIME, (log(LL_DBG, "time < 1 - last %ld:%ld now %ld:%ld",
98 tv_last.tv_sec, tv_last.tv_usec,
99 tv_now.tv_sec, tv_now.tv_usec)));
102 else if((tv_now.tv_sec - tv_last.tv_sec) == 1)
104 if(((1000000 - tv_last.tv_usec) + tv_now.tv_usec) < 900000)
106 DBGL(DL_TIME, (log(LL_DBG, "time < 900000us - last %ld:%ld now %ld:%ld",
107 tv_last.tv_sec, tv_last.tv_usec,
108 tv_now.tv_sec, tv_now.tv_usec)));
113 DBGL(DL_TIME, (log(LL_DBG, "time OK! - last %ld:%ld now %ld:%ld",
114 tv_last.tv_sec, tv_last.tv_usec,
115 tv_now.tv_sec, tv_now.tv_usec)));
117 gettimeofday(&tv_last, NULL);
122 /*---------------------------------------------------------------------------*
123 * timeout, recovery and retry handling
124 *---------------------------------------------------------------------------*/
126 handle_recovery(void)
128 cfg_entry_t *cep = NULL;
132 if(hr_callgate()) /* last call to handle_recovery < 1 sec ? */
133 return; /* yes, exit */
135 now = time(NULL); /* get current time */
137 /* walk thru all entries, look for work to do */
139 for(i=0; i < nentries; i++)
141 cep = &cfg_entry_tab[i]; /* ptr to config entry */
145 case CDID_UNUSED: /* entry unused */
149 case CDID_RESERVED: /* entry reserved */
150 handle_reserved(cep, now);
153 default: /* entry in use */
154 handle_active(cep, now);
160 /*---------------------------------------------------------------------------*
161 * timeout, recovery and retry handling for active entry
162 *---------------------------------------------------------------------------*/
164 handle_active(cfg_entry_t *cep, time_t now)
169 if(cep->timerval && (--(cep->timerremain)) <= 0)
171 DBGL(DL_RCVRY, (log(LL_DBG, "handle_active: entry %s, TIMEOUT !!!", cep->name)));
172 cep->timerval = cep->timerremain = 0;
173 next_state(cep, EV_TIMO);
178 if(cep->alert_time > 0)
184 log(LL_CHD, "%05d %s answering: incoming call from %s to %s",
185 cep->cdid, cep->name,
186 cep->real_phone_incoming,
187 cep->local_phone_incoming);
188 next_state(cep, EV_MCI);
193 recover_illegal(cep);
197 /* check hangup flag: if active, close connection */
201 DBGL(DL_RCVRY, (log(LL_DBG, "handle_active: entry %s, hangup request!", cep->name)));
203 next_state(cep, EV_DRQ);
207 * if shorthold mode is rates based, check if
208 * we entered a time with a new unit length
211 if(cep->unitlengthsrc == ULSRC_RATE)
213 int connecttime = (int)difftime(now, cep->connect_time);
215 if((connecttime > 1) &&
218 int newrate = get_current_rate(cep, 0);
220 if(newrate != cep->unitlength)
222 DBGL(DL_MSG, (log(LL_DBG, "handle_active: rates unit length updated %d -> %d", cep->unitlength, newrate)));
224 cep->unitlength = newrate;
234 /*---------------------------------------------------------------------------*
235 * timeout, recovery and retry handling for reserved entry
236 *---------------------------------------------------------------------------*/
238 handle_reserved(cfg_entry_t *cep, time_t now)
244 case ST_DIALRTMRCHD: /* wait for dial retry time reached */
246 if(cep->dialrandincr)
247 waittime = cep->randomtime;
249 waittime = cep->recoverytime;
252 if(now > (cep->last_dial_time + waittime))
254 DBGL(DL_RCVRY, (log(LL_DBG, "handle_reserved: entry %s, dial retry request!", cep->name)));
255 cep->state = ST_DIALRETRY;
257 if((cep->cdid = get_cdid()) == 0)
259 log(LL_ERR, "handle_reserved: dialretry get_cdid() returned 0!");
260 cep->state = ST_IDLE;
261 cep->cdid = CDID_UNUSED;
265 if((setup_dialout(cep)) == GOOD)
267 sendm_connect_req(cep);
271 log(LL_ERR, "handle_reserved: dialretry setup_dialout returned ERROR!");
272 cep->state = ST_IDLE;
273 cep->cdid = CDID_UNUSED;
280 case ST_ACB_WAITDIAL: /* active callback wait for time between disconnect and dial */
282 if(now > (cep->last_release_time + cep->callbackwait))
284 DBGL(DL_RCVRY, (log(LL_DBG, "handle_reserved: entry %s, callback dial!", cep->name)));
285 cep->state = ST_ACB_DIAL;
287 if((cep->cdid = get_cdid()) == 0)
289 log(LL_ERR, "handle_reserved: callback get_cdid() returned 0!");
290 cep->state = ST_IDLE;
291 cep->cdid = CDID_UNUSED;
295 select_first_dialno(cep);
297 if((setup_dialout(cep)) == GOOD)
299 sendm_connect_req(cep);
303 log(LL_ERR, "handle_reserved: callback setup_dialout returned ERROR!");
304 cep->state = ST_IDLE;
305 cep->cdid = CDID_UNUSED;
311 case ST_ACB_DIALFAIL: /* callback to remote failed */
313 if(cep->dialrandincr)
314 waittime = cep->randomtime + cep->recoverytime;
316 waittime = cep->recoverytime;
318 if(now > (cep->last_release_time + waittime))
320 DBGL(DL_RCVRY, (log(LL_DBG, "handle_reserved: entry %s, callback dial retry request!", cep->name)));
321 cep->state = ST_ACB_DIAL;
323 if((cep->cdid = get_cdid()) == 0)
325 log(LL_ERR, "handle_reserved: callback dialretry get_cdid() returned 0!");
326 cep->state = ST_IDLE;
327 cep->cdid = CDID_UNUSED;
331 if((setup_dialout(cep)) == GOOD)
333 sendm_connect_req(cep);
337 log(LL_ERR, "handle_reserved: callback dialretry setup_dialout returned ERROR!");
338 cep->state = ST_IDLE;
339 cep->cdid = CDID_UNUSED;
345 case ST_PCB_WAITCALL: /* wait for remote calling back */
347 if(now > (cep->last_release_time + cep->calledbackwait))
351 if(cep->dial_count < cep->dialretries)
353 /* inside normal retry cycle */
355 DBGL(DL_RCVRY, (log(LL_DBG, "handle_reserved: entry %s, retry calledback dial #%d!",
356 cep->name, cep->dial_count)));
357 cep->state = ST_PCB_DIAL;
359 if((cep->cdid = get_cdid()) == 0)
361 log(LL_ERR, "handle_reserved: calledback get_cdid() returned 0!");
362 cep->state = ST_IDLE;
363 cep->cdid = CDID_UNUSED;
366 select_next_dialno(cep);
368 if((setup_dialout(cep)) == GOOD)
370 sendm_connect_req(cep);
374 log(LL_ERR, "handle_reserved: calledback setup_dialout returned ERROR!");
375 cep->state = ST_IDLE;
376 cep->cdid = CDID_UNUSED;
382 /* retries exhausted */
384 DBGL(DL_RCVRY, (log(LL_DBG, "handle_reserved: calledback dial retries exhausted")));
385 dialresponse(cep, DSTAT_TFAIL);
386 cep->cdid = CDID_UNUSED;
388 cep->state = ST_IDLE;
393 case ST_DOWN: /* interface was taken down */
395 if(now > (cep->went_down_time + cep->downtime))
397 DBGL(DL_RCVRY, (log(LL_DBG, "handle_reserved: taking %s%d up", bdrivername(cep->usrdevicename), cep->usrdeviceunit)));
399 cep->state = ST_IDLE;
400 cep->cdid = CDID_UNUSED;
404 case ST_ILL: /* illegal state reached, recover ! */
406 recover_illegal(cep);