fixes init script for non ipv6 enabled systems #472755
[packages/xinetd.git] / xinetd / retry.c
1 /*
2  * (c) Copyright 1992 by Panagiotis Tsirigotis
3  * (c) Sections Copyright 1998-2001 by Rob Braun
4  * All rights reserved.  The file named COPYRIGHT specifies the terms 
5  * and conditions for redistribution.
6  */
7
8
9 #include "config.h"
10 #include <sys/time.h>
11 #include <syslog.h>
12
13 #include "pset.h"
14 #include "retry.h"
15 #include "state.h"
16 #include "main.h"
17 #include "server.h"
18 #include "service.h"
19 #include "connection.h"
20 #include "xconfig.h"
21 #include "msg.h"
22 #include "sconf.h"
23 #include "xtimer.h"
24
25 static int retry_timer_running ;
26 static void cancel_retry(struct server * serp );
27 static void stop_retry_timer(void) ;
28 static void start_retry_timer(void) ;
29
30
31 /*
32  * Attempt to start all servers in the retry table
33  */
34 static void server_retry(void)
35 {
36    unsigned          servers_started = 0 ;
37    unsigned          u ;
38    const char       *func = "server_retry" ;
39
40    for ( u = 0 ; u < pset_count( RETRIES( ps ) ) ; u++ )
41    {
42       struct server *retry = SERP( pset_pointer( RETRIES( ps ), u ) ) ;
43       struct service *sp = SERVER_SERVICE( retry ) ;
44       connection_s *cp = SERVER_CONNECTION( retry ) ;
45
46       /*
47        * Drop the retry if access control fails or we have
48        * a memory allocation problem
49        */
50       if ( svc_parent_access_control( sp, cp ) == FAILED ||
51          svc_child_access_control (sp, cp) == FAILED ||
52          pset_add( SERVERS( ps ), retry ) == NULL )
53       {
54          cancel_retry( retry ) ;
55          pset_pointer( RETRIES( ps ), u ) = NULL ;
56          continue ;
57       }
58
59       if ( server_start( retry ) == OK )
60       {
61          servers_started++ ;
62          SVC_DEC_RETRIES( sp ) ;
63          if ( !SVC_WAITS( sp ) )
64             CONN_CLOSE( cp ) ;
65          pset_pointer( RETRIES( ps ), u ) = NULL ;
66          continue ;
67       }
68       else
69       {
70          pset_remove( SERVERS( ps ), retry ) ;
71          if ( SERVER_FORKLIMIT( retry ) )
72          {
73             /*
74              * give up retrying
75              */
76             msg( LOG_ERR, func,
77                "service %s: too many consecutive fork failures", SVC_ID(sp) ) ;
78             svc_log_failure( sp, cp, AC_FORK ) ;
79             cancel_retry( retry ) ;
80             pset_pointer( RETRIES( ps ), u ) = NULL ;
81             continue ;
82          }
83          else
84          {
85             if ( debug.on )
86                msg( LOG_DEBUG, func,
87                   "fork failed for service %s. Retrying...", SVC_ID( sp ) ) ;
88          }
89       }
90    }
91
92    pset_compact( RETRIES( ps ) ) ;
93
94    if ( debug.on )
95       msg( LOG_DEBUG, func,
96          "%d servers started, %d left to retry",
97             servers_started, pset_count( RETRIES( ps ) ) ) ;
98
99    /* If there's more, start another callback */
100    if ( pset_count( RETRIES( ps ) ) > 0 ) {
101       if ((retry_timer_running=xtimer_add(server_retry, RETRY_INTERVAL)) == -1)
102       {
103          msg( LOG_ERR, func, "xtimer_add: %m" ) ;
104          retry_timer_running = 0;
105       }
106    }
107    else
108       retry_timer_running = 0;
109 }
110
111
112 /*
113  * Schedule a retry by inserting the struct server in the retry table
114  * and starting the timer if necessary
115  */
116 status_e schedule_retry( struct server *serp )
117 {
118    struct service *sp = SERVER_SERVICE( serp ) ;
119    const char *func = "schedule_retry" ;
120
121    if ( pset_add( RETRIES( ps ), serp ) == NULL )
122    {
123       out_of_memory( func ) ;
124       return( FAILED ) ;
125    }
126    SVC_INC_RETRIES( sp ) ;
127    start_retry_timer() ;
128    if ( debug.on )
129       msg( LOG_DEBUG, func, "Scheduled retry attempt for %s", SVC_ID( sp ) ) ;
130    return( OK ) ;
131 }
132
133
134 /*
135  * This function should not be called for servers that correspond to
136  * services not in the service table because server_release will result
137  * in releasing all memory associated with the service (since the ref
138  * count will drop to 0).
139  */
140 static void cancel_retry( struct server *serp )
141 {
142    struct service *sp = SERVER_SERVICE( serp ) ;
143
144    conn_free( SERVER_CONNECTION( serp ), 1 ) ;
145    SVC_DEC_RETRIES( sp ) ;
146    server_release( serp ) ;
147 }
148
149
150
151 /*
152  * Cancel all retry attempts for the specified service
153  */
154 void cancel_service_retries( struct service *sp )
155 {
156    unsigned u ;
157    const char *func = "cancel_service_retries" ;
158
159    if ( SVC_RETRIES( sp ) == 0 )
160       return ;
161
162    u = 0 ;
163    while ( u < pset_count( RETRIES( ps ) ) )
164    {
165       struct server *serp ;
166
167       serp = SERP( pset_pointer( RETRIES( ps ), u ) ) ;
168       if ( SERVER_SERVICE( serp ) == sp )
169       {
170          msg( LOG_NOTICE, func,
171             "dropping retry attempt for service %s", SVC_ID( sp ) ) ;
172          cancel_retry( serp ) ;
173          pset_remove_index( RETRIES( ps ), u ) ;
174          continue ;
175       }
176       u++ ;
177    }
178
179    if ( pset_count( RETRIES( ps ) ) == 0 )
180       stop_retry_timer() ;
181 }
182
183
184 static void start_retry_timer(void)
185 {
186    const char *func = "start_retry_timer" ;
187
188    /*
189     * Enable timer if necessary.
190     */
191
192    if ( retry_timer_running == 0 )
193       if((retry_timer_running=xtimer_add(server_retry, RETRY_INTERVAL)) == -1 ){
194          msg( LOG_ERR, func, "xtimer_add: %m" ) ;
195          retry_timer_running = 0;
196       }
197 }
198
199
200 static void stop_retry_timer(void)
201 {
202    if ( retry_timer_running != 0)
203    {
204       xtimer_remove(retry_timer_running);
205       retry_timer_running = 0 ;
206    }
207 }
208