2 * Copyright (c) 1997, 2002 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 * ------------------------------------------
32 * last edit-date: [Sat May 13 13:13:13 2006]
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 llog(LL_ERR, "recover_illegal: ERROR, entry %s attempting disconnect!", cep->name);
50 sendm_disconnect_req(cep, (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL);
51 llog(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, (llog(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, (llog(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, (llog(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 */
143 if(cep->budget_callbackperiod && cep->budget_callbackncalls)
145 if(cep->budget_callbackperiod_time <= now)
147 DBGL(DL_BDGT, (llog(LL_DBG, "%s: new cback-budget-period (%d s, %d left)",
148 cep->name, cep->budget_callbackperiod, cep->budget_callbackncalls_cnt)));
149 cep->budget_callbackperiod_time = now + cep->budget_callbackperiod;
150 cep->budget_callbackncalls_cnt = cep->budget_callbackncalls;
154 if(cep->budget_calloutperiod && cep->budget_calloutncalls)
156 if(cep->budget_calloutperiod_time <= now)
158 DBGL(DL_BDGT, (llog(LL_DBG, "%s: new cout-budget-period (%d s, %d left)",
159 cep->name, cep->budget_calloutperiod, cep->budget_calloutncalls_cnt)));
160 cep->budget_calloutperiod_time = now + cep->budget_calloutperiod;
161 cep->budget_calloutncalls_cnt = cep->budget_calloutncalls;
167 case CDID_UNUSED: /* entry unused */
171 case CDID_RESERVED: /* entry reserved */
172 handle_reserved(cep, now);
175 default: /* entry in use */
176 handle_active(cep, now);
182 /*---------------------------------------------------------------------------*
183 * timeout, recovery and retry handling for active entry
184 *---------------------------------------------------------------------------*/
186 handle_active(cfg_entry_t *cep, time_t now)
191 if(cep->timerval && (--(cep->timerremain)) <= 0)
193 DBGL(DL_RCVRY, (llog(LL_DBG, "handle_active: entry %s, TIMEOUT !!!", cep->name)));
194 cep->timerval = cep->timerremain = 0;
195 next_state(cep, EV_TIMO);
200 if(cep->alert_time > 0)
206 llog(LL_CHD, "%05d %s answering: incoming call from %s to %s",
207 cep->cdid, cep->name,
208 cep->real_phone_incoming.number,
209 cep->local_phone_incoming.number);
210 next_state(cep, EV_MCI);
215 recover_illegal(cep);
219 /* check hangup flag: if active, close connection */
223 DBGL(DL_RCVRY, (llog(LL_DBG, "handle_active: entry %s, hangup request!", cep->name)));
225 next_state(cep, EV_DRQ);
228 /* check maximum connect time reached */
230 if(cep->maxconnecttime > 0 && cep->connect_time > 0)
232 int connecttime = (int)difftime(now, cep->connect_time);
233 if(connecttime > cep->maxconnecttime)
235 DBGL(DL_RCVRY, (llog(LL_DBG,
236 "handle_active: entry %s, maxconnecttime %d reached!",
237 cep->name, cep->maxconnecttime)));
238 next_state(cep, EV_DRQ);
243 * if shorthold mode is rates based, check if
244 * we entered a time with a new unit length
247 if(cep->unitlengthsrc == ULSRC_RATE)
249 int connecttime = (int)difftime(now, cep->connect_time);
251 if((connecttime > 1) &&
254 int newrate = get_current_rate(cep, 0);
256 if(newrate != cep->unitlength)
258 DBGL(DL_MSG, (llog(LL_DBG, "handle_active: rates unit length updated %d -> %d", cep->unitlength, newrate)));
260 cep->unitlength = newrate;
270 /*---------------------------------------------------------------------------*
271 * timeout, recovery and retry handling for reserved entry
272 *---------------------------------------------------------------------------*/
274 handle_reserved(cfg_entry_t *cep, time_t now)
280 case ST_DIALRTMRCHD: /* wait for dial retry time reached */
282 if(cep->dialrandincr)
283 waittime = cep->randomtime;
285 waittime = cep->recoverytime;
288 if(now > (cep->last_dial_time + waittime))
290 DBGL(DL_RCVRY, (llog(LL_DBG, "handle_reserved: entry %s, dial retry request!", cep->name)));
291 cep->state = ST_DIALRETRY;
293 if((cep->cdid = get_cdid()) == 0)
295 llog(LL_ERR, "handle_reserved: dialretry get_cdid() returned 0!");
296 cep->state = ST_IDLE;
297 cep->cdid = CDID_UNUSED;
301 if((setup_dialout(cep)) == GOOD)
303 sendm_connect_req(cep);
307 llog(LL_ERR, "handle_reserved: dialretry setup_dialout returned ERROR!");
308 cep->state = ST_IDLE;
309 cep->cdid = CDID_UNUSED;
316 case ST_ACB_WAITDIAL: /* active callback wait for time between disconnect and dial */
318 if(now > (cep->last_release_time + cep->callbackwait))
320 DBGL(DL_RCVRY, (llog(LL_DBG, "handle_reserved: entry %s, callback dial!", cep->name)));
321 cep->state = ST_ACB_DIAL;
323 if((cep->cdid = get_cdid()) == 0)
325 llog(LL_ERR, "handle_reserved: callback get_cdid() returned 0!");
326 cep->state = ST_IDLE;
327 cep->cdid = CDID_UNUSED;
331 select_first_dialno(cep);
333 if((setup_dialout(cep)) == GOOD)
335 sendm_connect_req(cep);
339 llog(LL_ERR, "handle_reserved: callback setup_dialout returned ERROR!");
340 cep->state = ST_IDLE;
341 cep->cdid = CDID_UNUSED;
347 case ST_ACB_DIALFAIL: /* callback to remote failed */
349 if(cep->dialrandincr)
350 waittime = cep->randomtime + cep->recoverytime;
352 waittime = cep->recoverytime;
354 if(now > (cep->last_release_time + waittime))
356 DBGL(DL_RCVRY, (llog(LL_DBG, "handle_reserved: entry %s, callback dial retry request!", cep->name)));
357 cep->state = ST_ACB_DIAL;
359 if((cep->cdid = get_cdid()) == 0)
361 llog(LL_ERR, "handle_reserved: callback dialretry get_cdid() returned 0!");
362 cep->state = ST_IDLE;
363 cep->cdid = CDID_UNUSED;
367 if((setup_dialout(cep)) == GOOD)
369 sendm_connect_req(cep);
373 llog(LL_ERR, "handle_reserved: callback dialretry setup_dialout returned ERROR!");
374 cep->state = ST_IDLE;
375 cep->cdid = CDID_UNUSED;
381 case ST_PCB_WAITCALL: /* wait for remote calling back */
383 if(now > (cep->last_release_time + cep->calledbackwait))
387 if(cep->dial_count < cep->dialretries)
389 /* inside normal retry cycle */
391 DBGL(DL_RCVRY, (llog(LL_DBG, "handle_reserved: entry %s, retry calledback dial #%d!",
392 cep->name, cep->dial_count)));
393 cep->state = ST_PCB_DIAL;
395 if((cep->cdid = get_cdid()) == 0)
397 llog(LL_ERR, "handle_reserved: calledback get_cdid() returned 0!");
398 cep->state = ST_IDLE;
399 cep->cdid = CDID_UNUSED;
402 select_next_dialno(cep);
404 if((setup_dialout(cep)) == GOOD)
406 sendm_connect_req(cep);
410 llog(LL_ERR, "handle_reserved: calledback setup_dialout returned ERROR!");
411 cep->state = ST_IDLE;
412 cep->cdid = CDID_UNUSED;
418 /* retries exhausted */
420 DBGL(DL_RCVRY, (llog(LL_DBG, "handle_reserved: calledback dial retries exhausted")));
421 dialresponse(cep, DSTAT_TFAIL);
422 cep->cdid = CDID_UNUSED;
424 cep->state = ST_IDLE;
429 case ST_DOWN: /* interface was taken down */
431 if(now > (cep->went_down_time + cep->downtime))
433 DBGL(DL_RCVRY, (llog(LL_DBG, "handle_reserved: taking %s%d up", bdrivername(cep->usrdevicename), cep->usrdeviceunit)));
435 cep->state = ST_IDLE;
436 cep->cdid = CDID_UNUSED;
440 case ST_ILL: /* illegal state reached, recover ! */
442 recover_illegal(cep);