Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / usr.sbin / i4b / isdnd / timer.c
1 /*
2  * Copyright (c) 1997, 2001 Hellmuth Michaelis. All rights reserved.
3  *
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.
12  *
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.
24  *
25  *---------------------------------------------------------------------------
26  *
27  *      i4b daemon - timer/timing support routines
28  *      ------------------------------------------
29  *
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 $
32  *
33  *      last edit-date: [Fri Jul 20 20:29:28 2001]
34  *
35  *---------------------------------------------------------------------------*/
36
37 #include "isdnd.h"
38
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);
43
44 /*---------------------------------------------------------------------------*
45  *      recover from illegal state
46  *---------------------------------------------------------------------------*/
47 static void
48 recover_illegal(cfg_entry_t *cep)
49 {
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;
55 }
56
57 /*---------------------------------------------------------------------------*
58  *      start the timer
59  *---------------------------------------------------------------------------*/
60 void
61 start_timer(cfg_entry_t *cep, int seconds)
62 {
63         cep->timerval = cep->timerremain = seconds;
64 }
65
66 /*---------------------------------------------------------------------------*
67  *      stop the timer
68  *---------------------------------------------------------------------------*/
69 void
70 stop_timer(cfg_entry_t *cep)
71 {
72         cep->timerval = cep->timerremain = 0;   
73 }
74
75 /*---------------------------------------------------------------------------*
76  *      callgate for handle_recovery()
77  *---------------------------------------------------------------------------*/
78 static int
79 hr_callgate(void)
80 {
81         static int tv_first = 1;
82         static struct timeval tv_last;
83         struct timeval tv_now;
84         
85         /* there must be 1 sec minimum between calls to this section */
86         
87         if(tv_first)
88         {
89                 gettimeofday(&tv_last, NULL);
90                 tv_first = 0;
91         }
92         
93         gettimeofday(&tv_now, NULL);
94         
95         if((tv_now.tv_sec - tv_last.tv_sec) < 1)
96         {
97         
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);
102         }
103         else if((tv_now.tv_sec - tv_last.tv_sec) == 1)
104         {
105                 if(((1000000 - tv_last.tv_usec) + tv_now.tv_usec) < 900000)
106                 {
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);
111                 }
112         }
113         
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)));
117         
118         gettimeofday(&tv_last, NULL);
119         
120         return(0);
121 }        
122
123 /*---------------------------------------------------------------------------*
124  *      timeout, recovery and retry handling
125  *---------------------------------------------------------------------------*/
126 void
127 handle_recovery(void)
128 {
129         cfg_entry_t *cep = NULL;
130         int i;
131         time_t now;
132         
133         if(hr_callgate())       /* last call to handle_recovery < 1 sec ? */
134                 return;         /* yes, exit */
135         
136         now = time(NULL);       /* get current time */
137         
138         /* walk thru all entries, look for work to do */
139         
140         for(i=0; i < nentries; i++)
141         {
142                 cep = &cfg_entry_tab[i];        /* ptr to config entry */
143         
144                 if(cep->budget_callbackperiod && cep->budget_callbackncalls)
145                 {
146                         if(cep->budget_callbackperiod_time <= now)
147                         {
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;
152                         }
153                 }
154
155                 if(cep->budget_calloutperiod && cep->budget_calloutncalls)
156                 {
157                         if(cep->budget_calloutperiod_time <= now)
158                         {
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;
163                         }
164                 }
165
166                 switch(cep->cdid)
167                 {
168                         case CDID_UNUSED:               /* entry unused */
169                                 continue;
170                                 break;
171         
172                         case CDID_RESERVED:             /* entry reserved */
173                                 handle_reserved(cep, now);
174                                 break;
175         
176                         default:                        /* entry in use */
177                                 handle_active(cep, now);
178                                 break;
179                 }
180         }
181 }               
182
183 /*---------------------------------------------------------------------------*
184  *      timeout, recovery and retry handling for active entry
185  *---------------------------------------------------------------------------*/
186 static void
187 handle_active(cfg_entry_t *cep, time_t now)
188 {
189         switch(cep->state)
190         {
191                 case ST_ACCEPTED:
192                         if(cep->timerval && (--(cep->timerremain)) <= 0)
193                         {
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);
197                         }
198                         break;
199                         
200                 case ST_ALERT:
201                         if(cep->alert_time > 0)
202                         {
203                                 cep->alert_time--;
204                         }
205                         else
206                         {
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);
212                         }
213                         break;
214                                 
215                 case ST_ILL:
216                         recover_illegal(cep);
217                         break;
218                         
219                 default:
220                         /* check hangup flag: if active, close connection */
221
222                         if(cep->hangup)
223                         {
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);
227                         }
228
229                         /* check maximum connect time reached */
230
231                         if(cep->maxconnecttime > 0 && cep->connect_time > 0)
232                         {
233                                 int connecttime = (int)difftime(now, cep->connect_time);
234                                 if(connecttime > cep->maxconnecttime)
235                                 {
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);
240                                 }
241                         }
242
243                         /*
244                          * if shorthold mode is rates based, check if
245                          * we entered a time with a new unit length
246                          */
247
248                         if(cep->unitlengthsrc == ULSRC_RATE)
249                         {
250                                 int connecttime = (int)difftime(now, cep->connect_time);
251
252                                 if((connecttime > 1) &&
253                                    (connecttime % 60))
254                                 {
255                                         int newrate = get_current_rate(cep, 0);
256         
257                                         if(newrate != cep->unitlength)
258                                         {
259                                                 DBGL(DL_MSG, (log(LL_DBG, "handle_active: rates unit length updated %d -> %d", cep->unitlength, newrate)));
260                         
261                                                 cep->unitlength = newrate;
262         
263                                                 unitlen_chkupd(cep);
264                                         }
265                                 }
266                         }
267                         break;
268         }
269 }
270
271 /*---------------------------------------------------------------------------*
272  *      timeout, recovery and retry handling for reserved entry
273  *---------------------------------------------------------------------------*/
274 static void
275 handle_reserved(cfg_entry_t *cep, time_t now)
276 {
277         time_t waittime;
278         
279         switch(cep->state)
280         {       
281                 case ST_DIALRTMRCHD:    /* wait for dial retry time reached */
282         
283                         if(cep->dialrandincr)
284                                 waittime = cep->randomtime;
285                         else
286                                 waittime = cep->recoverytime;
287         
288                                         
289                         if(now > (cep->last_dial_time + waittime))
290                         {
291                                 DBGL(DL_RCVRY, (log(LL_DBG, "handle_reserved: entry %s, dial retry request!", cep->name)));
292                                 cep->state = ST_DIALRETRY;
293         
294                                 if((cep->cdid = get_cdid()) == 0)
295                                 {
296                                         log(LL_ERR, "handle_reserved: dialretry get_cdid() returned 0!");
297                                         cep->state = ST_IDLE;
298                                         cep->cdid = CDID_UNUSED;
299                                         return;
300                                 }
301
302                                 if((setup_dialout(cep)) == GOOD)
303                                 {
304                                         sendm_connect_req(cep);
305                                 }
306                                 else
307                                 {
308                                         log(LL_ERR, "handle_reserved: dialretry setup_dialout returned ERROR!");
309                                         cep->state = ST_IDLE;
310                                         cep->cdid = CDID_UNUSED;
311                                         return;
312                                 }                                       
313                         }
314                         break;
315                         
316                 
317                 case ST_ACB_WAITDIAL:   /* active callback wait for time between disconnect and dial */
318         
319                         if(now > (cep->last_release_time + cep->callbackwait))
320                         {
321                                 DBGL(DL_RCVRY, (log(LL_DBG, "handle_reserved: entry %s, callback dial!", cep->name)));
322                                 cep->state = ST_ACB_DIAL;
323         
324                                 if((cep->cdid = get_cdid()) == 0)
325                                 {
326                                         log(LL_ERR, "handle_reserved: callback get_cdid() returned 0!");
327                                         cep->state = ST_IDLE;
328                                         cep->cdid = CDID_UNUSED;
329                                         return;
330                                 }
331
332                                 select_first_dialno(cep);
333
334                                 if((setup_dialout(cep)) == GOOD)
335                                 {
336                                         sendm_connect_req(cep);
337                                 }
338                                 else
339                                 {
340                                         log(LL_ERR, "handle_reserved: callback setup_dialout returned ERROR!");
341                                         cep->state = ST_IDLE;
342                                         cep->cdid = CDID_UNUSED;
343                                         return;
344                                 }                                       
345                         }
346                         break;
347         
348                 case ST_ACB_DIALFAIL:   /* callback to remote failed */
349         
350                         if(cep->dialrandincr)
351                                 waittime = cep->randomtime + cep->recoverytime;
352                         else
353                                 waittime = cep->recoverytime;
354         
355                         if(now > (cep->last_release_time + waittime))
356                         {
357                                 DBGL(DL_RCVRY, (log(LL_DBG, "handle_reserved: entry %s, callback dial retry request!", cep->name)));
358                                 cep->state = ST_ACB_DIAL;
359         
360                                 if((cep->cdid = get_cdid()) == 0)
361                                 {
362                                         log(LL_ERR, "handle_reserved: callback dialretry get_cdid() returned 0!");
363                                         cep->state = ST_IDLE;
364                                         cep->cdid = CDID_UNUSED;
365                                         return;
366                                 }
367
368                                 if((setup_dialout(cep)) == GOOD)
369                                 {
370                                         sendm_connect_req(cep);
371                                 }
372                                 else
373                                 {
374                                         log(LL_ERR, "handle_reserved: callback dialretry setup_dialout returned ERROR!");
375                                         cep->state = ST_IDLE;
376                                         cep->cdid = CDID_UNUSED;
377                                         return;
378                                 }                                       
379                         }
380                         break;
381         
382                 case ST_PCB_WAITCALL:   /* wait for remote calling back */
383
384                         if(now > (cep->last_release_time + cep->calledbackwait))
385                         {
386                                 cep->dial_count++;
387         
388                                 if(cep->dial_count < cep->dialretries)
389                                 {
390                                         /* inside normal retry cycle */
391         
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;
395         
396                                         if((cep->cdid = get_cdid()) == 0)
397                                         {
398                                                 log(LL_ERR, "handle_reserved: calledback get_cdid() returned 0!");
399                                                 cep->state = ST_IDLE;
400                                                 cep->cdid = CDID_UNUSED;
401                                                 return;
402                                         }
403                                         select_next_dialno(cep);
404
405                                         if((setup_dialout(cep)) == GOOD)
406                                         {
407                                                 sendm_connect_req(cep);
408                                         }
409                                         else
410                                         {
411                                                 log(LL_ERR, "handle_reserved: calledback setup_dialout returned ERROR!");
412                                                 cep->state = ST_IDLE;
413                                                 cep->cdid = CDID_UNUSED;
414                                                 return;
415                                         }                                       
416                                 }
417                                 else
418                                 {
419                                         /* retries exhausted */
420         
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;
426                                 }
427                         }
428                         break;
429                         
430                 case ST_DOWN:   /* interface was taken down */
431
432                         if(now > (cep->went_down_time + cep->downtime))
433                         {
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;
438                         }
439                         break;
440                         
441                 case ST_ILL:    /* illegal state reached, recover ! */
442                 
443                         recover_illegal(cep);
444                         break;
445         }
446 }
447
448 /* EOF */