1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */

17 package org.apache.tomcat.util.net;
18
19 import org.apache.juli.logging.Log;
20 import org.apache.juli.logging.LogFactory;
21 import org.apache.tomcat.jni.Error;
22 import org.apache.tomcat.util.ExceptionUtils;
23 import org.apache.tomcat.util.res.StringManager;
24
25 public class Acceptor<U> implements Runnable {
26
27     private static final Log log = LogFactory.getLog(Acceptor.class);
28     private static final StringManager sm = StringManager.getManager(Acceptor.class);
29
30     private static final int INITIAL_ERROR_DELAY = 50;
31     private static final int MAX_ERROR_DELAY = 1600;
32
33     private final AbstractEndpoint<?,U> endpoint;
34     private String threadName;
35     protected volatile AcceptorState state = AcceptorState.NEW;
36
37
38     public Acceptor(AbstractEndpoint<?,U> endpoint) {
39         this.endpoint = endpoint;
40     }
41
42
43     public final AcceptorState getState() {
44         return state;
45     }
46
47
48     final void setThreadName(final String threadName) {
49         this.threadName = threadName;
50     }
51
52
53     final String getThreadName() {
54         return threadName;
55     }
56
57
58     @Override
59     public void run() {
60
61         int errorDelay = 0;
62
63         // Loop until we receive a shutdown command
64         while (endpoint.isRunning()) {
65
66             // Loop if endpoint is paused
67             while (endpoint.isPaused() && endpoint.isRunning()) {
68                 state = AcceptorState.PAUSED;
69                 try {
70                     Thread.sleep(50);
71                 } catch (InterruptedException e) {
72                     // Ignore
73                 }
74             }
75
76             if (!endpoint.isRunning()) {
77                 break;
78             }
79             state = AcceptorState.RUNNING;
80
81             try {
82                 //if we have reached max connections, wait
83                 endpoint.countUpOrAwaitConnection();
84
85                 // Endpoint might have been paused while waiting for latch
86                 // If that is the case, don't accept new connections
87                 if (endpoint.isPaused()) {
88                     continue;
89                 }
90
91                 U socket = null;
92                 try {
93                     // Accept the next incoming connection from the server
94                     // socket
95                     socket = endpoint.serverSocketAccept();
96                 } catch (Exception ioe) {
97                     // We didn't get a socket
98                     endpoint.countDownConnection();
99                     if (endpoint.isRunning()) {
100                         // Introduce delay if necessary
101                         errorDelay = handleExceptionWithDelay(errorDelay);
102                         // re-throw
103                         throw ioe;
104                     } else {
105                         break;
106                     }
107                 }
108                 // Successful accept, reset the error delay
109                 errorDelay = 0;
110
111                 // Configure the socket
112                 if (endpoint.isRunning() && !endpoint.isPaused()) {
113                     // setSocketOptions() will hand the socket off to
114                     // an appropriate processor if successful
115                     if (!endpoint.setSocketOptions(socket)) {
116                         endpoint.closeSocket(socket);
117                     }
118                 } else {
119                     endpoint.destroySocket(socket);
120                 }
121             } catch (Throwable t) {
122                 ExceptionUtils.handleThrowable(t);
123                 String msg = sm.getString("endpoint.accept.fail");
124                 // APR specific.
125                 // Could push this down but not sure it is worth the trouble.
126                 if (t instanceof Error) {
127                     Error e = (Error) t;
128                     if (e.getError() == 233) {
129                         // Not an error on HP-UX so log as a warning
130                         // so it can be filtered out on that platform
131                         // See bug 50273
132                         log.warn(msg, t);
133                     } else {
134                         log.error(msg, t);
135                     }
136                 } else {
137                         log.error(msg, t);
138                 }
139             }
140         }
141         state = AcceptorState.ENDED;
142     }
143
144
145     /**
146      * Handles exceptions where a delay is required to prevent a Thread from
147      * entering a tight loop which will consume CPU and may also trigger large
148      * amounts of logging. For example, this can happen if the ulimit for open
149      * files is reached.
150      *
151      * @param currentErrorDelay The current delay being applied on failure
152      * @return  The delay to apply on the next failure
153      */

154     protected int handleExceptionWithDelay(int currentErrorDelay) {
155         // Don't delay on first exception
156         if (currentErrorDelay > 0) {
157             try {
158                 Thread.sleep(currentErrorDelay);
159             } catch (InterruptedException e) {
160                 // Ignore
161             }
162         }
163
164         // On subsequent exceptions, start the delay at 50ms, doubling the delay
165         // on every subsequent exception until the delay reaches 1.6 seconds.
166         if (currentErrorDelay == 0) {
167             return INITIAL_ERROR_DELAY;
168         } else if (currentErrorDelay < MAX_ERROR_DELAY) {
169             return currentErrorDelay * 2;
170         } else {
171             return MAX_ERROR_DELAY;
172         }
173     }
174
175
176     public enum AcceptorState {
177         NEW, RUNNING, PAUSED, ENDED
178     }
179 }
180