1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 package org.metricshub.wbem.sblim.cimclient.internal.http;
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 import java.io.IOException;
60 import java.net.InetAddress;
61 import java.net.ServerSocket;
62 import java.net.Socket;
63 import java.net.SocketException;
64 import java.net.UnknownHostException;
65 import java.util.concurrent.ArrayBlockingQueue;
66 import java.util.concurrent.BlockingQueue;
67 import java.util.concurrent.TimeUnit;
68 import java.util.logging.Level;
69 import javax.net.ssl.SSLContext;
70 import javax.net.ssl.SSLServerSocket;
71 import org.metricshub.wbem.sblim.cimclient.internal.logging.LogAndTraceBroker;
72 import org.metricshub.wbem.sblim.cimclient.internal.util.ThreadPool;
73 import org.metricshub.wbem.sblim.cimclient.internal.util.Util;
74 import org.metricshub.wbem.sblim.cimclient.internal.util.WBEMConfiguration;
75
76
77
78
79
80
81
82 public class HttpServerConnection implements Runnable {
83 private int iPort;
84
85 private ServerSocket iServerSocket;
86
87 private HttpConnectionHandler iHandler;
88
89 private HttpConnectionDispatcher iDispatcher;
90
91 private volatile boolean iClose = true;
92
93 private String iServerName;
94
95 private boolean iSsl;
96
97 private Thread iRunner;
98
99 private WBEMConfiguration iSessionProperties;
100
101 private final int iTimeout;
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119 public HttpServerConnection(
120 HttpConnectionHandler pHandler,
121 String pLocalAddress,
122 int pPort,
123 boolean pSsl,
124 WBEMConfiguration pProperties
125 )
126 throws IOException {
127 final LogAndTraceBroker logger = LogAndTraceBroker.getBroker();
128 logger.entry();
129
130 this.iPort = pPort;
131 this.iHandler = pHandler;
132 this.iSsl = pSsl;
133 this.iServerName = pSsl ? "HTTPS Server" : "HTTP Server";
134 this.iSessionProperties = (pProperties != null) ? pProperties : WBEMConfiguration.getGlobalConfiguration();
135 SSLContext sslContext = pSsl ? HttpSocketFactory.getInstance().getServerSSLContext(this.iSessionProperties) : null;
136 this.iServerSocket =
137 (pLocalAddress != null && pLocalAddress.length() > 0)
138 ? HttpSocketFactory
139 .getInstance()
140 .getServerSocketFactory(sslContext)
141 .createServerSocket(pPort, 50, InetAddress.getByName(pLocalAddress))
142 : HttpSocketFactory.getInstance().getServerSocketFactory(sslContext).createServerSocket(pPort);
143 if (this.iServerSocket instanceof SSLServerSocket) {
144 if (this.iSessionProperties.getSslListenerPeerVerification().equalsIgnoreCase("ignore")) {
145 logger.trace(Level.FINER, "Listener peer verification: ignore");
146 ((SSLServerSocket) this.iServerSocket).setNeedClientAuth(false);
147 } else if (this.iSessionProperties.getSslListenerPeerVerification().equalsIgnoreCase("accept")) {
148 logger.trace(Level.FINER, "Listener peer verification: accept");
149 ((SSLServerSocket) this.iServerSocket).setWantClientAuth(true);
150 } else {
151 logger.trace(Level.FINER, "Listener peer verification: require");
152 ((SSLServerSocket) this.iServerSocket).setNeedClientAuth(true);
153 }
154
155 String disableCipherSuites = this.iSessionProperties.getSslListenerCipherSuitesToDisable();
156 if (disableCipherSuites != null) {
157 SSLServerSocket sslSock = (SSLServerSocket) this.iServerSocket;
158 String[] currentCipherSuites = sslSock.getEnabledCipherSuites();
159 String[] updatedCipherSuites = Util.getFilteredStringArray(currentCipherSuites, disableCipherSuites);
160 sslSock.setEnabledCipherSuites(updatedCipherSuites);
161 int before = currentCipherSuites.length;
162 int after = updatedCipherSuites.length;
163 if (before > 0 && after == 0) logger.trace(Level.WARNING, "All cipher suites disabled for listener!"); else if (
164 before > after
165 ) logger.trace(Level.FINE, "Some (" + (before - after) + ") cipher suites disabled for listener"); else if (
166 before == after
167 ) logger.trace(Level.FINER, "No cipher suites disabled for listener");
168 }
169 }
170 this.iTimeout = this.iSessionProperties.getListenerHttpTimeout();
171 logger.exit();
172 }
173
174
175
176
177
178
179
180 public void setName(String pName) {
181 if (this.iRunner != null) this.iRunner.setName(pName);
182 }
183
184
185
186
187
188
189 public int getPort() {
190 return this.iServerSocket.getLocalPort();
191 }
192
193
194
195
196
197
198
199 public String getLocalIp() throws UnknownHostException {
200 String ip = this.iServerSocket.getInetAddress().getHostAddress();
201 String localhost = InetAddress.getLocalHost().getHostAddress();
202 return "0.0.0.0".equals(ip) ? localhost : ip;
203 }
204
205
206
207
208
209
210
211 public String getLocalHostName() throws UnknownHostException {
212 String ip = this.iServerSocket.getInetAddress().getHostName();
213 String localhost = InetAddress.getLocalHost().getHostName();
214 return "0.0.0.0".equals(ip) ? localhost : ip;
215 }
216
217
218
219
220
221
222 public boolean isSSL() {
223 return this.iSsl;
224 }
225
226
227
228
229 public void start() {
230 if (this.iClose) {
231 this.iClose = false;
232 ThreadGroup group = new ThreadGroup("CIMListener on port " + String.valueOf(this.iPort));
233 this.iDispatcher =
234 new HttpConnectionDispatcher(
235 group,
236 this.iHandler,
237 new ThreadPool(
238 this.iSessionProperties.getListenerMinPoolSize(),
239 this.iSessionProperties.getListenerMaxPoolSize(),
240 this.iSessionProperties.getListenerBacklog(),
241 this.iSessionProperties.getListenerMaxIdle(),
242 group,
243 "Handler "
244 ),
245 this.iSessionProperties.getListenerMaxQueueSize()
246 );
247 this.iDispatcher.start();
248 this.iRunner = new Thread(group, this, this.iServerName);
249 this.iRunner.setDaemon(true);
250
251 this.iRunner.start();
252 }
253 }
254
255 public void run() {
256 while (!this.iClose) {
257 try {
258 Socket socket = this.iServerSocket.accept();
259 try {
260 socket.setTcpNoDelay(true);
261 socket.setSoTimeout(this.iTimeout);
262 } catch (IOException e) {
263 LogAndTraceBroker.getBroker().trace(Level.FINE, "Exception while adjusting socket options", e);
264 }
265 boolean dispatched = this.iDispatcher.dispatch(socket);
266 if (!dispatched) {
267 MessageWriter writer = new MessageWriter(socket.getOutputStream(), false, false);
268 try {
269 writer.setMethod(new HttpServerMethod(1, 1, 503, "Service temporarily overloaded"));
270 writer.getHeader().addField("Retry-After", "10");
271 writer.close();
272 } catch (IOException e) {
273 LogAndTraceBroker.getBroker().trace(Level.FINE, "Exception while sending HTTP 503", e);
274 } finally {
275 socket.close();
276 }
277 LogAndTraceBroker
278 .getBroker()
279 .trace(Level.FINE, "HttpServerConnection failed to dispatch incoming connection, sent 503");
280 } else {
281 LogAndTraceBroker.getBroker().trace(Level.FINE, "HttpServerConnection dispatched incoming connection");
282 }
283 } catch (Throwable t) {
284 if (t instanceof SocketException && this.iClose) {
285 break;
286 }
287 try {
288 LogAndTraceBroker.getBroker().trace(Level.FINE, "Exception while waiting for incoming http connections");
289 } catch (Throwable t2) {
290
291 }
292 }
293 }
294
295
296
297 try {
298 LogAndTraceBroker.getBroker().trace(Level.FINE, "Shutting down CIMListener on port " + this.iPort);
299 } catch (Throwable t) {
300
301 }
302 try {
303
304
305 Thread.sleep(5000);
306 } catch (InterruptedException e) {
307
308 }
309 try {
310 this.iDispatcher.close();
311 } catch (Exception e) {
312 LogAndTraceBroker.getBroker().trace(Level.FINE, "Exception while closing http connection dispatcher", e);
313 }
314 this.iDispatcher = null;
315 this.iRunner = null;
316 }
317
318
319
320
321 public void close() {
322 if (!this.iClose) {
323 this.iClose = true;
324 try {
325 this.iServerSocket.close();
326 this.iServerSocket = null;
327 } catch (Exception e) {
328 LogAndTraceBroker.getBroker().trace(Level.FINE, "Exception while closing server socket", e);
329 }
330 }
331 }
332
333
334
335
336
337
338
339
340 private static class HttpConnectionDispatcher extends Thread {
341 private BlockingQueue<Socket> iConnectionPool;
342
343 private volatile boolean iAlive = true;
344
345 private HttpConnectionHandler iHandler;
346
347 private ThreadPool iThreadPool;
348
349
350
351
352
353
354
355
356
357
358
359
360
361 public HttpConnectionDispatcher(
362 ThreadGroup pGroup,
363 HttpConnectionHandler pHandler,
364 ThreadPool pPool,
365 int pQueueSize
366 ) {
367 super(pGroup, "Connection Dispatcher");
368 setDaemon(true);
369 this.iConnectionPool = new ArrayBlockingQueue<Socket>(pQueueSize > 0 ? pQueueSize : 1);
370 this.iHandler = pHandler;
371 this.iThreadPool = pPool;
372 }
373
374
375
376
377
378
379
380
381 public boolean dispatch(Socket pSocket) {
382 try {
383 return this.iConnectionPool.offer(pSocket, 20, TimeUnit.MILLISECONDS);
384 } catch (InterruptedException e) {
385
386 }
387 return false;
388 }
389
390
391
392
393
394
395 public Socket getConnection() {
396 try {
397 return this.iConnectionPool.poll(100, TimeUnit.MILLISECONDS);
398 } catch (InterruptedException e) {
399
400 }
401 return null;
402 }
403
404 @Override
405 public void run() {
406 while (this.iAlive) {
407 try {
408 Socket socket = getConnection();
409 if (socket != null) {
410 this.iThreadPool.execute(new HttpServerWorker(this.iHandler, socket));
411 }
412 } catch (Throwable t) {
413 try {
414 LogAndTraceBroker.getBroker().trace(Level.FINE, "Exception while submitting worker to thread pool", t);
415 } catch (Throwable t1) {
416
417 }
418 }
419 }
420 try {
421 this.iHandler.close();
422 } catch (Exception e) {
423 LogAndTraceBroker.getBroker().trace(Level.FINE, "Exception while closing http connection handler", e);
424 }
425 try {
426 this.iThreadPool.shutdown();
427 } catch (Exception e) {
428 LogAndTraceBroker.getBroker().trace(Level.FINE, "Exception during shut down of thread pool", e);
429 }
430 }
431
432
433
434
435 public void close() {
436 this.iAlive = false;
437 }
438 }
439 }