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