]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/i4b/isdnd/timer.c
This commit was generated by cvs2svn to compensate for changes in r56160,
[FreeBSD/FreeBSD.git] / usr.sbin / i4b / isdnd / timer.c
1 /*
2  * Copyright (c) 1997, 1999 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  *      $Id: timer.c,v 1.19 1999/12/13 21:25:25 hm Exp $ 
31  *
32  * $FreeBSD$
33  *
34  *      last edit-date: [Mon Dec 13 21:49:13 1999]
35  *
36  *---------------------------------------------------------------------------*/
37
38 #include "isdnd.h"
39
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);
44
45 /*---------------------------------------------------------------------------*
46  *      recover from illegal state
47  *---------------------------------------------------------------------------*/
48 static void
49 recover_illegal(cfg_entry_t *cep)
50 {
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);
54         cep->state = ST_IDLE;
55         cep->cdid = CDID_UNUSED;
56 }
57
58 /*---------------------------------------------------------------------------*
59  *      start the timer
60  *---------------------------------------------------------------------------*/
61 void
62 start_timer(cfg_entry_t *cep, int seconds)
63 {
64         cep->timerval = cep->timerremain = seconds;
65 }
66
67 /*---------------------------------------------------------------------------*
68  *      stop the timer
69  *---------------------------------------------------------------------------*/
70 void
71 stop_timer(cfg_entry_t *cep)
72 {
73         cep->timerval = cep->timerremain = 0;   
74 }
75
76 /*---------------------------------------------------------------------------*
77  *      callgate for handle_recovery()
78  *---------------------------------------------------------------------------*/
79 static int
80 hr_callgate(void)
81 {
82         static int tv_first = 1;
83         static struct timeval tv_last;
84         struct timeval tv_now;
85         
86         /* there must be 1 sec minimum between calls to this section */
87         
88         if(tv_first)
89         {
90                 gettimeofday(&tv_last, NULL);
91                 tv_first = 0;
92         }
93         
94         gettimeofday(&tv_now, NULL);
95         
96         if((tv_now.tv_sec - tv_last.tv_sec) < 1)
97         {
98         
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)));
102                 return(1);
103         }
104         else if((tv_now.tv_sec - tv_last.tv_sec) == 1)
105         {
106                 if(((1000000 - tv_last.tv_usec) + tv_now.tv_usec) < 900000)
107                 {
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)));
111                         return(1);
112                 }
113         }
114         
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)));
118         
119         gettimeofday(&tv_last, NULL);
120         
121         return(0);
122 }        
123
124 /*---------------------------------------------------------------------------*
125  *      timeout, recovery and retry handling
126  *---------------------------------------------------------------------------*/
127 void
128 handle_recovery(void)
129 {
130         cfg_entry_t *cep = NULL;
131         int i;
132         time_t now;
133         
134         if(hr_callgate())       /* last call to handle_recovery < 1 sec ? */
135                 return;         /* yes, exit */
136         
137         now = time(NULL);       /* get current time */
138         
139         /* walk thru all entries, look for work to do */
140         
141         for(i=0; i < nentries; i++)
142         {
143                 cep = &cfg_entry_tab[i];        /* ptr to config entry */
144         
145                 switch(cep->cdid)
146                 {
147                         case CDID_UNUSED:               /* entry unused */
148                                 continue;
149                                 break;
150         
151                         case CDID_RESERVED:             /* entry reserved */
152                                 handle_reserved(cep, now);
153                                 break;
154         
155                         default:                        /* entry in use */
156                                 handle_active(cep, now);
157                                 break;
158                 }
159         }
160 }               
161
162 /*---------------------------------------------------------------------------*
163  *      timeout, recovery and retry handling for active entry
164  *---------------------------------------------------------------------------*/
165 static void
166 handle_active(cfg_entry_t *cep, time_t now)
167 {
168         switch(cep->state)
169         {
170                 case ST_ACCEPTED:
171                         if(cep->timerval && (--(cep->timerremain)) <= 0)
172                         {
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);
176                         }
177                         break;
178                         
179                 case ST_ALERT:
180                         if(cep->alert_time > 0)
181                         {
182                                 cep->alert_time--;
183                         }
184                         else
185                         {
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);
191                         }
192                         break;
193                                 
194                 case ST_ILL:
195                         recover_illegal(cep);
196                         break;
197                         
198                 default:
199                         /* check hangup flag: if active, close connection */
200
201                         if(cep->hangup)
202                         {
203                                 DBGL(DL_RCVRY, (log(LL_DBG, "handle_active: entry %s, hangup request!", cep->name)));
204                                 cep->hangup = 0;
205                                 next_state(cep, EV_DRQ);
206                         }
207
208                         /*
209                          * if shorthold mode is rates based, check if
210                          * we entered a time with a new unit length
211                          */
212
213                         if(cep->unitlengthsrc == ULSRC_RATE)
214                         {
215                                 int connecttime = (int)difftime(now, cep->connect_time);
216
217                                 if((connecttime > 1) &&
218                                    (connecttime % 60))
219                                 {
220                                         int newrate = get_current_rate(cep, 0);
221         
222                                         if(newrate != cep->unitlength)
223                                         {
224                                                 DBGL(DL_MSG, (log(LL_DBG, "handle_active: rates unit length updated %d -> %d", cep->unitlength, newrate)));
225                         
226                                                 cep->unitlength = newrate;
227         
228                                                 unitlen_chkupd(cep);
229                                         }
230                                 }
231                         }
232                         break;
233         }
234 }
235
236 /*---------------------------------------------------------------------------*
237  *      timeout, recovery and retry handling for reserved entry
238  *---------------------------------------------------------------------------*/
239 static void
240 handle_reserved(cfg_entry_t *cep, time_t now)
241 {
242         time_t waittime;
243         
244         switch(cep->state)
245         {       
246                 case ST_DIALRTMRCHD:    /* wait for dial retry time reached */
247         
248                         if(cep->dialrandincr)
249                                 waittime = cep->randomtime;
250                         else
251                                 waittime = cep->recoverytime;
252         
253                                         
254                         if(now > (cep->last_dial_time + waittime))
255                         {
256                                 DBGL(DL_RCVRY, (log(LL_DBG, "handle_reserved: entry %s, dial retry request!", cep->name)));
257                                 cep->state = ST_DIALRETRY;
258         
259                                 if((cep->cdid = get_cdid()) == 0)
260                                 {
261                                         log(LL_ERR, "handle_reserved: dialretry get_cdid() returned 0!");
262                                         cep->state = ST_IDLE;
263                                         cep->cdid = CDID_UNUSED;
264                                         return;
265                                 }
266
267                                 if((setup_dialout(cep)) == GOOD)
268                                 {
269                                         sendm_connect_req(cep);
270                                 }
271                                 else
272                                 {
273                                         log(LL_ERR, "handle_reserved: dialretry setup_dialout returned ERROR!");
274                                         cep->state = ST_IDLE;
275                                         cep->cdid = CDID_UNUSED;
276                                         return;
277                                 }                                       
278                         }
279                         break;
280                         
281                 
282                 case ST_ACB_WAITDIAL:   /* active callback wait for time between disconnect and dial */
283         
284                         if(now > (cep->last_release_time + cep->callbackwait))
285                         {
286                                 DBGL(DL_RCVRY, (log(LL_DBG, "handle_reserved: entry %s, callback dial!", cep->name)));
287                                 cep->state = ST_ACB_DIAL;
288         
289                                 if((cep->cdid = get_cdid()) == 0)
290                                 {
291                                         log(LL_ERR, "handle_reserved: callback get_cdid() returned 0!");
292                                         cep->state = ST_IDLE;
293                                         cep->cdid = CDID_UNUSED;
294                                         return;
295                                 }
296
297                                 select_first_dialno(cep);
298
299                                 if((setup_dialout(cep)) == GOOD)
300                                 {
301                                         sendm_connect_req(cep);
302                                 }
303                                 else
304                                 {
305                                         log(LL_ERR, "handle_reserved: callback setup_dialout returned ERROR!");
306                                         cep->state = ST_IDLE;
307                                         cep->cdid = CDID_UNUSED;
308                                         return;
309                                 }                                       
310                         }
311                         break;
312         
313                 case ST_ACB_DIALFAIL:   /* callback to remote failed */
314         
315                         if(cep->dialrandincr)
316                                 waittime = cep->randomtime + cep->recoverytime;
317                         else
318                                 waittime = cep->recoverytime;
319         
320                         if(now > (cep->last_release_time + waittime))
321                         {
322                                 DBGL(DL_RCVRY, (log(LL_DBG, "handle_reserved: entry %s, callback dial retry request!", cep->name)));
323                                 cep->state = ST_ACB_DIAL;
324         
325                                 if((cep->cdid = get_cdid()) == 0)
326                                 {
327                                         log(LL_ERR, "handle_reserved: callback dialretry get_cdid() returned 0!");
328                                         cep->state = ST_IDLE;
329                                         cep->cdid = CDID_UNUSED;
330                                         return;
331                                 }
332
333                                 if((setup_dialout(cep)) == GOOD)
334                                 {
335                                         sendm_connect_req(cep);
336                                 }
337                                 else
338                                 {
339                                         log(LL_ERR, "handle_reserved: callback dialretry setup_dialout returned ERROR!");
340                                         cep->state = ST_IDLE;
341                                         cep->cdid = CDID_UNUSED;
342                                         return;
343                                 }                                       
344                         }
345                         break;
346         
347                 case ST_PCB_WAITCALL:   /* wait for remote calling back */
348
349                         if(now > (cep->last_release_time + cep->calledbackwait))
350                         {
351                                 cep->dial_count++;
352         
353                                 if(cep->dial_count < cep->dialretries)
354                                 {
355                                         /* inside normal retry cycle */
356         
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;
360         
361                                         if((cep->cdid = get_cdid()) == 0)
362                                         {
363                                                 log(LL_ERR, "handle_reserved: calledback get_cdid() returned 0!");
364                                                 cep->state = ST_IDLE;
365                                                 cep->cdid = CDID_UNUSED;
366                                                 return;
367                                         }
368                                         select_next_dialno(cep);
369
370                                         if((setup_dialout(cep)) == GOOD)
371                                         {
372                                                 sendm_connect_req(cep);
373                                         }
374                                         else
375                                         {
376                                                 log(LL_ERR, "handle_reserved: calledback setup_dialout returned ERROR!");
377                                                 cep->state = ST_IDLE;
378                                                 cep->cdid = CDID_UNUSED;
379                                                 return;
380                                         }                                       
381                                 }
382                                 else
383                                 {
384                                         /* retries exhausted */
385         
386                                         DBGL(DL_RCVRY, (log(LL_DBG, "handle_reserved: calledback dial retries exhausted")));
387                                         dialresponse(cep, DSTAT_TFAIL);
388                                         cep->cdid = CDID_UNUSED;
389                                         cep->dial_count = 0;
390                                         cep->state = ST_IDLE;
391                                 }
392                         }
393                         break;
394                         
395                 case ST_DOWN:   /* interface was taken down */
396
397                         if(now > (cep->went_down_time + cep->downtime))
398                         {
399                                 DBGL(DL_RCVRY, (log(LL_DBG, "handle_reserved: taking %s%d up", bdrivername(cep->usrdevicename), cep->usrdeviceunit)));
400                                 if_up(cep);
401                                 cep->state = ST_IDLE;
402                                 cep->cdid = CDID_UNUSED;
403                         }
404                         break;
405                         
406                 case ST_ILL:    /* illegal state reached, recover ! */
407                 
408                         recover_illegal(cep);
409                         break;
410         }
411 }
412
413 /* EOF */