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 java.io.IOException;
20 import java.io.OutputStreamWriter;
21 import java.net.InetAddress;
22 import java.net.InetSocketAddress;
23 import java.net.NetworkInterface;
24 import java.net.SocketException;
25 import java.util.ArrayList;
26 import java.util.Enumeration;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Set;
32 import java.util.concurrent.ConcurrentHashMap;
33 import java.util.concurrent.ConcurrentMap;
34 import java.util.concurrent.Executor;
35 import java.util.concurrent.RejectedExecutionException;
36 import java.util.concurrent.ScheduledExecutorService;
37 import java.util.concurrent.ScheduledThreadPoolExecutor;
38 import java.util.concurrent.TimeUnit;
39
40 import javax.management.MalformedObjectNameException;
41 import javax.management.ObjectName;
42
43 import org.apache.juli.logging.Log;
44 import org.apache.tomcat.util.ExceptionUtils;
45 import org.apache.tomcat.util.IntrospectionUtils;
46 import org.apache.tomcat.util.collections.SynchronizedStack;
47 import org.apache.tomcat.util.modeler.Registry;
48 import org.apache.tomcat.util.net.Acceptor.AcceptorState;
49 import org.apache.tomcat.util.res.StringManager;
50 import org.apache.tomcat.util.threads.LimitLatch;
51 import org.apache.tomcat.util.threads.ResizableExecutor;
52 import org.apache.tomcat.util.threads.TaskQueue;
53 import org.apache.tomcat.util.threads.TaskThreadFactory;
54 import org.apache.tomcat.util.threads.ThreadPoolExecutor;
55
56 /**
57  * @param <S> The type used by the socket wrapper associated with this endpoint.
58  *            May be the same as U.
59  * @param <U> The type of the underlying socket used by this endpoint. May be
60  *            the same as S.
61  *
62  * @author Mladen Turk
63  * @author Remy Maucherat
64  */

65 public abstract class AbstractEndpoint<S,U> {
66
67     // -------------------------------------------------------------- Constants
68
69     protected static final StringManager sm = StringManager.getManager(AbstractEndpoint.class);
70
71     public static interface Handler<S> {
72
73         /**
74          * Different types of socket states to react upon.
75          */

76         public enum SocketState {
77             // TODO Add a new state to the AsyncStateMachine and remove
78             //      ASYNC_END (if possible)
79             OPEN, CLOSED, LONG, ASYNC_END, SENDFILE, UPGRADING, UPGRADED, SUSPENDED
80         }
81
82
83         /**
84          * Process the provided socket with the given current status.
85          *
86          * @param socket The socket to process
87          * @param status The current socket status
88          *
89          * @return The state of the socket after processing
90          */

91         public SocketState process(SocketWrapperBase<S> socket,
92                 SocketEvent status);
93
94
95         /**
96          * Obtain the GlobalRequestProcessor associated with the handler.
97          *
98          * @return the GlobalRequestProcessor
99          */

100         public Object getGlobal();
101
102
103         /**
104          * Obtain the currently open sockets.
105          *
106          * @return The sockets for which the handler is tracking a currently
107          *         open connection
108          * @deprecated Unused, will be removed in Tomcat 10, replaced
109          *         by AbstractEndpoint.getConnections
110          */

111         @Deprecated
112         public Set<S> getOpenSockets();
113
114         /**
115          * Release any resources associated with the given SocketWrapper.
116          *
117          * @param socketWrapper The socketWrapper to release resources for
118          */

119         public void release(SocketWrapperBase<S> socketWrapper);
120
121
122         /**
123          * Inform the handler that the endpoint has stopped accepting any new
124          * connections. Typically, the endpoint will be stopped shortly
125          * afterwards but it is possible that the endpoint will be resumed so
126          * the handler should not assume that a stop will follow.
127          */

128         public void pause();
129
130
131         /**
132          * Recycle resources associated with the handler.
133          */

134         public void recycle();
135     }
136
137     protected enum BindState {
138         UNBOUND, BOUND_ON_INIT, BOUND_ON_START, SOCKET_CLOSED_ON_STOP
139     }
140
141
142     public static long toTimeout(long timeout) {
143         // Many calls can't do infinite timeout so use Long.MAX_VALUE if timeout is <= 0
144         return (timeout > 0) ? timeout : Long.MAX_VALUE;
145     }
146
147     // ----------------------------------------------------------------- Fields
148
149     /**
150      * Running state of the endpoint.
151      */

152     protected volatile boolean running = false;
153
154
155     /**
156      * Will be set to true whenever the endpoint is paused.
157      */

158     protected volatile boolean paused = false;
159
160     /**
161      * Are we using an internal executor
162      */

163     protected volatile boolean internalExecutor = true;
164
165
166     /**
167      * counter for nr of connections handled by an endpoint
168      */

169     private volatile LimitLatch connectionLimitLatch = null;
170
171     /**
172      * Socket properties
173      */

174     protected final SocketProperties socketProperties = new SocketProperties();
175     public SocketProperties getSocketProperties() {
176         return socketProperties;
177     }
178
179     /**
180      * Thread used to accept new connections and pass them to worker threads.
181      */

182     protected Acceptor<U> acceptor;
183
184     /**
185      * Cache for SocketProcessor objects
186      */

187     protected SynchronizedStack<SocketProcessorBase<S>> processorCache;
188
189     private ObjectName oname = null;
190
191     /**
192      * Map holding all current connections keyed with the sockets.
193      */

194     protected Map<U, SocketWrapperBase<S>> connections = new ConcurrentHashMap<>();
195
196     /**
197      * Get a set with the current open connections.
198      * @return A set with the open socket wrappers
199      */

200     public Set<SocketWrapperBase<S>> getConnections() {
201         return new HashSet<>(connections.values());
202     }
203
204     // ----------------------------------------------------------------- Properties
205
206     private String defaultSSLHostConfigName = SSLHostConfig.DEFAULT_SSL_HOST_NAME;
207     public String getDefaultSSLHostConfigName() {
208         return defaultSSLHostConfigName;
209     }
210     public void setDefaultSSLHostConfigName(String defaultSSLHostConfigName) {
211         this.defaultSSLHostConfigName = defaultSSLHostConfigName;
212     }
213
214
215     protected ConcurrentMap<String,SSLHostConfig> sslHostConfigs = new ConcurrentHashMap<>();
216     /**
217      * Add the given SSL Host configuration.
218      *
219      * @param sslHostConfig The configuration to add
220      *
221      * @throws IllegalArgumentException If the host name is not valid or if a
222      *                                  configuration has already been provided
223      *                                  for that host
224      */

225     public void addSslHostConfig(SSLHostConfig sslHostConfig) throws IllegalArgumentException {
226         addSslHostConfig(sslHostConfig, false);
227     }
228     /**
229      * Add the given SSL Host configuration, optionally replacing the existing
230      * configuration for the given host.
231      *
232      * @param sslHostConfig The configuration to add
233      * @param replace       If {@code true} replacement of an existing
234      *                      configuration is permitted, otherwise any such
235      *                      attempted replacement will trigger an exception
236      *
237      * @throws IllegalArgumentException If the host name is not valid or if a
238      *                                  configuration has already been provided
239      *                                  for that host and replacement is not
240      *                                  allowed
241      */

242     public void addSslHostConfig(SSLHostConfig sslHostConfig, boolean replace) throws IllegalArgumentException {
243         String key = sslHostConfig.getHostName();
244         if (key == null || key.length() == 0) {
245             throw new IllegalArgumentException(sm.getString("endpoint.noSslHostName"));
246         }
247         if (bindState != BindState.UNBOUND && bindState != BindState.SOCKET_CLOSED_ON_STOP &&
248                 isSSLEnabled()) {
249             try {
250                 createSSLContext(sslHostConfig);
251             } catch (Exception e) {
252                 throw new IllegalArgumentException(e);
253             }
254         }
255         if (replace) {
256             SSLHostConfig previous = sslHostConfigs.put(key, sslHostConfig);
257             if (previous != null) {
258                 unregisterJmx(sslHostConfig);
259             }
260             registerJmx(sslHostConfig);
261
262             // Do not release any SSLContexts associated with a replaced
263             // SSLHostConfig. They may still be in used by existing connections
264             // and releasing them would break the connection at best. Let GC
265             // handle the clean up.
266         } else {
267             SSLHostConfig duplicate = sslHostConfigs.putIfAbsent(key, sslHostConfig);
268             if (duplicate != null) {
269                 releaseSSLContext(sslHostConfig);
270                 throw new IllegalArgumentException(sm.getString("endpoint.duplicateSslHostName", key));
271             }
272             registerJmx(sslHostConfig);
273         }
274     }
275     /**
276      * Removes the SSL host configuration for the given host name, if such a
277      * configuration exists.
278      *
279      * @param hostName  The host name associated with the SSL host configuration
280      *                  to remove
281      *
282      * @return  The SSL host configuration that was removed, if any
283      */

284     public SSLHostConfig removeSslHostConfig(String hostName) {
285         if (hostName == null) {
286             return null;
287         }
288         // Host names are case insensitive
289         if (hostName.equalsIgnoreCase(getDefaultSSLHostConfigName())) {
290             throw new IllegalArgumentException(
291                     sm.getString("endpoint.removeDefaultSslHostConfig", hostName));
292         }
293         SSLHostConfig sslHostConfig = sslHostConfigs.remove(hostName);
294         unregisterJmx(sslHostConfig);
295         return sslHostConfig;
296     }
297     /**
298      * Re-read the configuration files for the SSL host and replace the existing
299      * SSL configuration with the updated settings. Note this replacement will
300      * happen even if the settings remain unchanged.
301      *
302      * @param hostName The SSL host for which the configuration should be
303      *                 reloaded. This must match a current SSL host
304      */

305     public void reloadSslHostConfig(String hostName) {
306         SSLHostConfig sslHostConfig = sslHostConfigs.get(hostName);
307         if (sslHostConfig == null) {
308             throw new IllegalArgumentException(
309                     sm.getString("endpoint.unknownSslHostName", hostName));
310         }
311         addSslHostConfig(sslHostConfig, true);
312     }
313     /**
314      * Re-read the configuration files for all SSL hosts and replace the
315      * existing SSL configuration with the updated settings. Note this
316      * replacement will happen even if the settings remain unchanged.
317      */

318     public void reloadSslHostConfigs() {
319         for (String hostName : sslHostConfigs.keySet()) {
320             reloadSslHostConfig(hostName);
321         }
322     }
323     public SSLHostConfig[] findSslHostConfigs() {
324         return sslHostConfigs.values().toArray(new SSLHostConfig[0]);
325     }
326
327     /**
328      * Create the SSLContextfor the the given SSLHostConfig.
329      *
330      * @param sslHostConfig The SSLHostConfig for which the SSLContext should be
331      *                      created
332      * @throws Exception If the SSLContext cannot be created for the given
333      *                   SSLHostConfig
334      */

335     protected abstract void createSSLContext(SSLHostConfig sslHostConfig) throws Exception;
336
337
338     protected void destroySsl() throws Exception {
339         if (isSSLEnabled()) {
340             for (SSLHostConfig sslHostConfig : sslHostConfigs.values()) {
341                 releaseSSLContext(sslHostConfig);
342             }
343         }
344     }
345
346
347     /**
348      * Release the SSLContext, if any, associated with the SSLHostConfig.
349      *
350      * @param sslHostConfig The SSLHostConfig for which the SSLContext should be
351      *                      released
352      */

353     protected void releaseSSLContext(SSLHostConfig sslHostConfig) {
354         for (SSLHostConfigCertificate certificate : sslHostConfig.getCertificates(true)) {
355             if (certificate.getSslContext() != null) {
356                 SSLContext sslContext = certificate.getSslContext();
357                 if (sslContext != null) {
358                     sslContext.destroy();
359                 }
360             }
361         }
362     }
363
364
365
366     protected SSLHostConfig getSSLHostConfig(String sniHostName) {
367         SSLHostConfig result = null;
368
369         if (sniHostName != null) {
370             // First choice - direct match
371             result = sslHostConfigs.get(sniHostName);
372             if (result != null) {
373                 return result;
374             }
375             // Second choice, wildcard match
376             int indexOfDot = sniHostName.indexOf('.');
377             if (indexOfDot > -1) {
378                 result = sslHostConfigs.get("*" + sniHostName.substring(indexOfDot));
379             }
380         }
381
382         // Fall-back. Use the default
383         if (result == null) {
384             result = sslHostConfigs.get(getDefaultSSLHostConfigName());
385         }
386         if (result == null) {
387             // Should never happen.
388             throw new IllegalStateException();
389         }
390         return result;
391     }
392
393
394     /**
395      * Has the user requested that send file be used where possible?
396      */

397     private boolean useSendfile = true;
398     public boolean getUseSendfile() {
399         return useSendfile;
400     }
401     public void setUseSendfile(boolean useSendfile) {
402         this.useSendfile = useSendfile;
403     }
404
405
406     /**
407      * Time to wait for the internal executor (if used) to terminate when the
408      * endpoint is stopped in milliseconds. Defaults to 5000 (5 seconds).
409      */

410     private long executorTerminationTimeoutMillis = 5000;
411
412     public long getExecutorTerminationTimeoutMillis() {
413         return executorTerminationTimeoutMillis;
414     }
415
416     public void setExecutorTerminationTimeoutMillis(
417             long executorTerminationTimeoutMillis) {
418         this.executorTerminationTimeoutMillis = executorTerminationTimeoutMillis;
419     }
420
421
422     /**
423      * Acceptor thread count.
424      */

425     protected int acceptorThreadCount = 1;
426
427     /**
428      * NO-OP.
429      *
430      * @param acceptorThreadCount Unused
431      *
432      * @deprecated Will be removed in Tomcat 10.
433      */

434     @Deprecated
435     public void setAcceptorThreadCount(int acceptorThreadCount) {}
436
437     /**
438      * Always returns 1.
439      *
440      * @return Always 1.
441      *
442      * @deprecated Will be removed in Tomcat 10.
443      */

444     @Deprecated
445     public int getAcceptorThreadCount() { return 1; }
446
447
448     /**
449      * Priority of the acceptor threads.
450      */

451     protected int acceptorThreadPriority = Thread.NORM_PRIORITY;
452     public void setAcceptorThreadPriority(int acceptorThreadPriority) {
453         this.acceptorThreadPriority = acceptorThreadPriority;
454     }
455     public int getAcceptorThreadPriority() { return acceptorThreadPriority; }
456
457
458     private int maxConnections = 8*1024;
459     public void setMaxConnections(int maxCon) {
460         this.maxConnections = maxCon;
461         LimitLatch latch = this.connectionLimitLatch;
462         if (latch != null) {
463             // Update the latch that enforces this
464             if (maxCon == -1) {
465                 releaseConnectionLatch();
466             } else {
467                 latch.setLimit(maxCon);
468             }
469         } else if (maxCon > 0) {
470             initializeConnectionLatch();
471         }
472     }
473     public int getMaxConnections() { return this.maxConnections; }
474
475     /**
476      * Return the current count of connections handled by this endpoint, if the
477      * connections are counted (which happens when the maximum count of
478      * connections is limited), or <code>-1</code> if they are not. This
479      * property is added here so that this value can be inspected through JMX.
480      * It is visible on "ThreadPool" MBean.
481      *
482      * <p>The count is incremented by the Acceptor before it tries to accept a
483      * new connection. Until the limit is reached and thus the count cannot be
484      * incremented,  this value is more by 1 (the count of acceptors) than the
485      * actual count of connections that are being served.
486      *
487      * @return The count
488      */

489     public long getConnectionCount() {
490         LimitLatch latch = connectionLimitLatch;
491         if (latch != null) {
492             return latch.getCount();
493         }
494         return -1;
495     }
496
497     /**
498      * External Executor based thread pool.
499      */

500     private Executor executor = null;
501     public void setExecutor(Executor executor) {
502         this.executor = executor;
503         this.internalExecutor = (executor == null);
504     }
505     public Executor getExecutor() { return executor; }
506
507
508     /**
509      * External Executor based thread pool for utility tasks.
510      */

511     private ScheduledExecutorService utilityExecutor = null;
512     public void setUtilityExecutor(ScheduledExecutorService utilityExecutor) {
513         this.utilityExecutor = utilityExecutor;
514     }
515     public ScheduledExecutorService getUtilityExecutor() {
516         if (utilityExecutor == null) {
517             getLog().warn(sm.getString("endpoint.warn.noUtilityExecutor"));
518             utilityExecutor = new ScheduledThreadPoolExecutor(1);
519         }
520         return utilityExecutor;
521     }
522
523
524     /**
525      * Server socket port.
526      */

527     private int port = -1;
528     public int getPort() { return port; }
529     public void setPort(int port ) { this.port=port; }
530
531
532     private int portOffset = 0;
533     public int getPortOffset() { return portOffset; }
534     public void setPortOffset(int portOffset ) {
535         if (portOffset < 0) {
536             throw new IllegalArgumentException(
537                     sm.getString("endpoint.portOffset.invalid", Integer.valueOf(portOffset)));
538         }
539         this.portOffset = portOffset;
540     }
541
542
543     public int getPortWithOffset() {
544         // Zero is a special case and negative values are invalid
545         int port = getPort();
546         if (port > 0) {
547             return port + getPortOffset();
548         }
549         return port;
550     }
551
552
553     public final int getLocalPort() {
554         try {
555             InetSocketAddress localAddress = getLocalAddress();
556             if (localAddress == null) {
557                 return -1;
558             }
559             return localAddress.getPort();
560         } catch (IOException ioe) {
561             return -1;
562         }
563     }
564
565
566     /**
567      * Address for the server socket.
568      */

569     private InetAddress address;
570     public InetAddress getAddress() { return address; }
571     public void setAddress(InetAddress address) { this.address = address; }
572
573
574     /**
575      * Obtain the network address the server socket is bound to. This primarily
576      * exists to enable the correct address to be used when unlocking the server
577      * socket since it removes the guess-work involved if no address is
578      * specifically set.
579      *
580      * @return The network address that the server socket is listening on or
581      *         null if the server socket is not currently bound.
582      *
583      * @throws IOException If there is a problem determining the currently bound
584      *                     socket
585      */

586     protected abstract InetSocketAddress getLocalAddress() throws IOException;
587
588
589     /**
590      * Allows the server developer to specify the acceptCount (backlog) that
591      * should be used for server sockets. By defaultthis value
592      * is 100.
593      */

594     private int acceptCount = 100;
595     public void setAcceptCount(int acceptCount) { if (acceptCount > 0) this.acceptCount = acceptCount; }
596     public int getAcceptCount() { return acceptCount; }
597
598     /**
599      * Controls when the Endpoint binds the port. <code>true</code>, the default
600      * binds the port on {@link #init()} and unbinds it on {@link #destroy()}.
601      * If set to <code>false</code> the port is bound on {@link #start()} and
602      * unbound on {@link #stop()}.
603      */

604     private boolean bindOnInit = true;
605     public boolean getBindOnInit() { return bindOnInit; }
606     public void setBindOnInit(boolean b) { this.bindOnInit = b; }
607     private volatile BindState bindState = BindState.UNBOUND;
608
609     /**
610      * Keepalive timeout, if not set the soTimeout is used.
611      */

612     private Integer keepAliveTimeout = null;
613     public int getKeepAliveTimeout() {
614         if (keepAliveTimeout == null) {
615             return getConnectionTimeout();
616         } else {
617             return keepAliveTimeout.intValue();
618         }
619     }
620     public void setKeepAliveTimeout(int keepAliveTimeout) {
621         this.keepAliveTimeout = Integer.valueOf(keepAliveTimeout);
622     }
623
624
625     /**
626      * Socket TCP no delay.
627      *
628      * @return The current TCP no delay setting for sockets created by this
629      *         endpoint
630      */

631     public boolean getTcpNoDelay() { return socketProperties.getTcpNoDelay();}
632     public void setTcpNoDelay(boolean tcpNoDelay) { socketProperties.setTcpNoDelay(tcpNoDelay); }
633
634
635     /**
636      * Socket linger.
637      *
638      * @return The current socket linger time for sockets created by this
639      *         endpoint
640      */

641     public int getConnectionLinger() { return socketProperties.getSoLingerTime(); }
642     public void setConnectionLinger(int connectionLinger) {
643         socketProperties.setSoLingerTime(connectionLinger);
644         socketProperties.setSoLingerOn(connectionLinger>=0);
645     }
646
647
648     /**
649      * Socket timeout.
650      *
651      * @return The current socket timeout for sockets created by this endpoint
652      */

653     public int getConnectionTimeout() { return socketProperties.getSoTimeout(); }
654     public void setConnectionTimeout(int soTimeout) { socketProperties.setSoTimeout(soTimeout); }
655
656     /**
657      * SSL engine.
658      */

659     private boolean SSLEnabled = false;
660     public boolean isSSLEnabled() { return SSLEnabled; }
661     public void setSSLEnabled(boolean SSLEnabled) { this.SSLEnabled = SSLEnabled; }
662
663     /**
664      * Identifies if the endpoint supports ALPN. Note that a return value of
665      * <code>true</code> implies that {@link #isSSLEnabled()} will also return
666      * <code>true</code>.
667      *
668      * @return <code>true</code> if the endpoint supports ALPN in its current
669      *         configuration, otherwise <code>false</code>.
670      */

671     public abstract boolean isAlpnSupported();
672
673     private int minSpareThreads = 10;
674     public void setMinSpareThreads(int minSpareThreads) {
675         this.minSpareThreads = minSpareThreads;
676         Executor executor = this.executor;
677         if (internalExecutor && executor instanceof java.util.concurrent.ThreadPoolExecutor) {
678             // The internal executor should always be an instance of
679             // j.u.c.ThreadPoolExecutor but it may be null if the endpoint is
680             // not running.
681             // This check also avoids various threading issues.
682             ((java.util.concurrent.ThreadPoolExecutor) executor).setCorePoolSize(minSpareThreads);
683         }
684     }
685     public int getMinSpareThreads() {
686         return Math.min(getMinSpareThreadsInternal(), getMaxThreads());
687     }
688     private int getMinSpareThreadsInternal() {
689         if (internalExecutor) {
690             return minSpareThreads;
691         } else {
692             return -1;
693         }
694     }
695
696
697     /**
698      * Maximum amount of worker threads.
699      */

700     private int maxThreads = 200;
701     public void setMaxThreads(int maxThreads) {
702         this.maxThreads = maxThreads;
703         Executor executor = this.executor;
704         if (internalExecutor && executor instanceof java.util.concurrent.ThreadPoolExecutor) {
705             // The internal executor should always be an instance of
706             // j.u.c.ThreadPoolExecutor but it may be null if the endpoint is
707             // not running.
708             // This check also avoids various threading issues.
709             ((java.util.concurrent.ThreadPoolExecutor) executor).setMaximumPoolSize(maxThreads);
710         }
711     }
712     public int getMaxThreads() {
713         if (internalExecutor) {
714             return maxThreads;
715         } else {
716             return -1;
717         }
718     }
719
720
721     /**
722      * Priority of the worker threads.
723      */

724     protected int threadPriority = Thread.NORM_PRIORITY;
725     public void setThreadPriority(int threadPriority) {
726         // Can't change this once the executor has started
727         this.threadPriority = threadPriority;
728     }
729     public int getThreadPriority() {
730         if (internalExecutor) {
731             return threadPriority;
732         } else {
733             return -1;
734         }
735     }
736
737
738     /**
739      * Max keep alive requests
740      */

741     private int maxKeepAliveRequests=100; // as in Apache HTTPD server
742     public int getMaxKeepAliveRequests() {
743         return maxKeepAliveRequests;
744     }
745     public void setMaxKeepAliveRequests(int maxKeepAliveRequests) {
746         this.maxKeepAliveRequests = maxKeepAliveRequests;
747     }
748
749
750     /**
751      * Name of the thread pool, which will be used for naming child threads.
752      */

753     private String name = "TP";
754     public void setName(String name) { this.name = name; }
755     public String getName() { return name; }
756
757
758     /**
759      * Name of domain to use for JMX registration.
760      */

761     private String domain;
762     public void setDomain(String domain) { this.domain = domain; }
763     public String getDomain() { return domain; }
764
765
766     /**
767      * The default is true - the created threads will be
768      *  in daemon mode. If set to false, the control thread
769      *  will not be daemon - and will keep the process alive.
770      */

771     private boolean daemon = true;
772     public void setDaemon(boolean b) { daemon = b; }
773     public boolean getDaemon() { return daemon; }
774
775
776     /**
777      * Expose asynchronous IO capability.
778      */

779     private boolean useAsyncIO = true;
780     public void setUseAsyncIO(boolean useAsyncIO) { this.useAsyncIO = useAsyncIO; }
781     public boolean getUseAsyncIO() { return useAsyncIO; }
782
783
784     protected abstract boolean getDeferAccept();
785
786
787     protected final List<String> negotiableProtocols = new ArrayList<>();
788     public void addNegotiatedProtocol(String negotiableProtocol) {
789         negotiableProtocols.add(negotiableProtocol);
790     }
791     public boolean hasNegotiableProtocols() {
792         return (negotiableProtocols.size() > 0);
793     }
794
795
796     /**
797      * Handling of accepted sockets.
798      */

799     private Handler<S> handler = null;
800     public void setHandler(Handler<S> handler ) { this.handler = handler; }
801     public Handler<S> getHandler() { return handler; }
802
803
804     /**
805      * Attributes provide a way for configuration to be passed to sub-components
806      * without the {@link org.apache.coyote.ProtocolHandler} being aware of the
807      * properties available on those sub-components.
808      */

809     protected HashMap<String, Object> attributes = new HashMap<>();
810
811     /**
812      * Generic property setter called when a property for which a specific
813      * setter already exists within the
814      * {@link org.apache.coyote.ProtocolHandler} needs to be made available to
815      * sub-components. The specific setter will call this method to populate the
816      * attributes.
817      *
818      * @param name  Name of property to set
819      * @param value The value to set the property to
820      */

821     public void setAttribute(String name, Object value) {
822         if (getLog().isTraceEnabled()) {
823             getLog().trace(sm.getString("endpoint.setAttribute", name, value));
824         }
825         attributes.put(name, value);
826     }
827     /**
828      * Used by sub-components to retrieve configuration information.
829      *
830      * @param key The name of the property for which the value should be
831      *            retrieved
832      *
833      * @return The value of the specified property
834      */

835     public Object getAttribute(String key) {
836         Object value = attributes.get(key);
837         if (getLog().isTraceEnabled()) {
838             getLog().trace(sm.getString("endpoint.getAttribute", key, value));
839         }
840         return value;
841     }
842
843
844
845     public boolean setProperty(String name, String value) {
846         setAttribute(name, value);
847         final String socketName = "socket.";
848         try {
849             if (name.startsWith(socketName)) {
850                 return IntrospectionUtils.setProperty(socketProperties, name.substring(socketName.length()), value);
851             } else {
852                 return IntrospectionUtils.setProperty(this,name,value,false);
853             }
854         }catch ( Exception x ) {
855             getLog().error(sm.getString("endpoint.setAttributeError", name, value), x);
856             return false;
857         }
858     }
859     public String getProperty(String name) {
860         String value = (String) getAttribute(name);
861         final String socketName = "socket.";
862         if (value == null && name.startsWith(socketName)) {
863             Object result = IntrospectionUtils.getProperty(socketProperties, name.substring(socketName.length()));
864             if (result != null) {
865                 value = result.toString();
866             }
867         }
868         return value;
869     }
870
871     /**
872      * Return the amount of threads that are managed by the pool.
873      *
874      * @return the amount of threads that are managed by the pool
875      */

876     public int getCurrentThreadCount() {
877         Executor executor = this.executor;
878         if (executor != null) {
879             if (executor instanceof ThreadPoolExecutor) {
880                 return ((ThreadPoolExecutor) executor).getPoolSize();
881             } else if (executor instanceof ResizableExecutor) {
882                 return ((ResizableExecutor) executor).getPoolSize();
883             } else {
884                 return -1;
885             }
886         } else {
887             return -2;
888         }
889     }
890
891     /**
892      * Return the amount of threads that are in use
893      *
894      * @return the amount of threads that are in use
895      */

896     public int getCurrentThreadsBusy() {
897         Executor executor = this.executor;
898         if (executor != null) {
899             if (executor instanceof ThreadPoolExecutor) {
900                 return ((ThreadPoolExecutor) executor).getActiveCount();
901             } else if (executor instanceof ResizableExecutor) {
902                 return ((ResizableExecutor) executor).getActiveCount();
903             } else {
904                 return -1;
905             }
906         } else {
907             return -2;
908         }
909     }
910
911     public boolean isRunning() {
912         return running;
913     }
914
915     public boolean isPaused() {
916         return paused;
917     }
918
919
920     public void createExecutor() {
921         internalExecutor = true;
922         TaskQueue taskqueue = new TaskQueue();
923         TaskThreadFactory tf = new TaskThreadFactory(getName() + "-exec-", daemon, getThreadPriority());
924         executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), 60, TimeUnit.SECONDS,taskqueue, tf);
925         taskqueue.setParent( (ThreadPoolExecutor) executor);
926     }
927
928     public void shutdownExecutor() {
929         Executor executor = this.executor;
930         if (executor != null && internalExecutor) {
931             this.executor = null;
932             if (executor instanceof ThreadPoolExecutor) {
933                 //this is our internal one, so we need to shut it down
934                 ThreadPoolExecutor tpe = (ThreadPoolExecutor) executor;
935                 tpe.shutdownNow();
936                 long timeout = getExecutorTerminationTimeoutMillis();
937                 if (timeout > 0) {
938                     try {
939                         tpe.awaitTermination(timeout, TimeUnit.MILLISECONDS);
940                     } catch (InterruptedException e) {
941                         // Ignore
942                     }
943                     if (tpe.isTerminating()) {
944                         getLog().warn(sm.getString("endpoint.warn.executorShutdown", getName()));
945                     }
946                 }
947                 TaskQueue queue = (TaskQueue) tpe.getQueue();
948                 queue.setParent(null);
949             }
950         }
951     }
952
953     /**
954      * Unlock the server socket acceptor threads using bogus connections.
955      */

956     private void unlockAccept() {
957         // Only try to unlock the acceptor if it is necessary
958         if (acceptor == null || acceptor.getState() != AcceptorState.RUNNING) {
959             return;
960         }
961
962         InetSocketAddress unlockAddress = null;
963         InetSocketAddress localAddress = null;
964         try {
965             localAddress = getLocalAddress();
966         } catch (IOException ioe) {
967             getLog().debug(sm.getString("endpoint.debug.unlock.localFail", getName()), ioe);
968         }
969         if (localAddress == null) {
970             getLog().warn(sm.getString("endpoint.debug.unlock.localNone", getName()));
971             return;
972         }
973
974         try {
975             unlockAddress = getUnlockAddress(localAddress);
976
977             try (java.net.Socket s = new java.net.Socket()) {
978                 int stmo = 2 * 1000;
979                 int utmo = 2 * 1000;
980                 if (getSocketProperties().getSoTimeout() > stmo)
981                     stmo = getSocketProperties().getSoTimeout();
982                 if (getSocketProperties().getUnlockTimeout() > utmo)
983                     utmo = getSocketProperties().getUnlockTimeout();
984                 s.setSoTimeout(stmo);
985                 s.setSoLinger(getSocketProperties().getSoLingerOn(),getSocketProperties().getSoLingerTime());
986                 if (getLog().isDebugEnabled()) {
987                     getLog().debug("About to unlock socket for:" + unlockAddress);
988                 }
989                 s.connect(unlockAddress,utmo);
990                 if (getDeferAccept()) {
991                     /*
992                      * In the case of a deferred accept / accept filters we need to
993                      * send data to wake up the accept. Send OPTIONS * to bypass
994                      * even BSD accept filters. The Acceptor will discard it.
995                      */

996                     OutputStreamWriter sw;
997
998                     sw = new OutputStreamWriter(s.getOutputStream(), "ISO-8859-1");
999                     sw.write("OPTIONS * HTTP/1.0\r\n" +
1000                             "User-Agent: Tomcat wakeup connection\r\n\r\n");
1001                     sw.flush();
1002                 }
1003                 if (getLog().isDebugEnabled()) {
1004                     getLog().debug("Socket unlock completed for:" + unlockAddress);
1005                 }
1006             }
1007             // Wait for upto 1000ms acceptor threads to unlock
1008             long waitLeft = 1000;
1009             while (waitLeft > 0 &&
1010                     acceptor.getState() == AcceptorState.RUNNING) {
1011                 Thread.sleep(5);
1012                 waitLeft -= 5;
1013             }
1014         } catch(Throwable t) {
1015             ExceptionUtils.handleThrowable(t);
1016             if (getLog().isDebugEnabled()) {
1017                 getLog().debug(sm.getString(
1018                         "endpoint.debug.unlock.fail", String.valueOf(getPortWithOffset())), t);
1019             }
1020         }
1021     }
1022
1023
1024     private static InetSocketAddress getUnlockAddress(InetSocketAddress localAddress) throws SocketException {
1025         if (localAddress.getAddress().isAnyLocalAddress()) {
1026             // Need a local address of the same type (IPv4 or IPV6) as the
1027             // configured bind address since the connector may be configured
1028             // to not map between types.
1029             InetAddress loopbackUnlockAddress = null;
1030             InetAddress linkLocalUnlockAddress = null;
1031
1032             Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
1033             while (networkInterfaces.hasMoreElements()) {
1034                 NetworkInterface networkInterface = networkInterfaces.nextElement();
1035                 Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
1036                 while (inetAddresses.hasMoreElements()) {
1037                     InetAddress inetAddress = inetAddresses.nextElement();
1038                     if (localAddress.getAddress().getClass().isAssignableFrom(inetAddress.getClass())) {
1039                         if (inetAddress.isLoopbackAddress()) {
1040                             if (loopbackUnlockAddress == null) {
1041                                 loopbackUnlockAddress = inetAddress;
1042                             }
1043                         } else if (inetAddress.isLinkLocalAddress()) {
1044                             if (linkLocalUnlockAddress == null) {
1045                                 linkLocalUnlockAddress = inetAddress;
1046                             }
1047                         } else {
1048                             // Use a non-link local, non-loop back address by default
1049                             return new InetSocketAddress(inetAddress, localAddress.getPort());
1050                         }
1051                     }
1052                 }
1053             }
1054             // Prefer loop back over link local since on some platforms (e.g.
1055             // OSX) some link local addresses are not included when listening on
1056             // all local addresses.
1057             if (loopbackUnlockAddress != null) {
1058                 return new InetSocketAddress(loopbackUnlockAddress, localAddress.getPort());
1059             }
1060             if (linkLocalUnlockAddress != null) {
1061                 return new InetSocketAddress(linkLocalUnlockAddress, localAddress.getPort());
1062             }
1063             // Fallback
1064             return new InetSocketAddress("localhost", localAddress.getPort());
1065         } else {
1066             return localAddress;
1067         }
1068     }
1069
1070
1071     // ---------------------------------------------- Request processing methods
1072
1073     /**
1074      * Process the given SocketWrapper with the given status. Used to trigger
1075      * processing as if the Poller (for those endpoints that have one)
1076      * selected the socket.
1077      *
1078      * @param socketWrapper The socket wrapper to process
1079      * @param event         The socket event to be processed
1080      * @param dispatch      Should the processing be performed on a new
1081      *                          container thread
1082      *
1083      * @return if processing was triggered successfully
1084      */

1085     public boolean processSocket(SocketWrapperBase<S> socketWrapper,
1086             SocketEvent event, boolean dispatch) {
1087         try {
1088             if (socketWrapper == null) {
1089                 return false;
1090             }
1091             SocketProcessorBase<S> sc = null;
1092             if (processorCache != null) {
1093                 sc = processorCache.pop();
1094             }
1095             if (sc == null) {
1096                 sc = createSocketProcessor(socketWrapper, event);
1097             } else {
1098                 sc.reset(socketWrapper, event);
1099             }
1100             Executor executor = getExecutor();
1101             if (dispatch && executor != null) {
1102                 executor.execute(sc);
1103             } else {
1104                 sc.run();
1105             }
1106         } catch (RejectedExecutionException ree) {
1107             getLog().warn(sm.getString("endpoint.executor.fail", socketWrapper) , ree);
1108             return false;
1109         } catch (Throwable t) {
1110             ExceptionUtils.handleThrowable(t);
1111             // This means we got an OOM or similar creating a thread, or that
1112             // the pool and its queue are full
1113             getLog().error(sm.getString("endpoint.process.fail"), t);
1114             return false;
1115         }
1116         return true;
1117     }
1118
1119
1120     protected abstract SocketProcessorBase<S> createSocketProcessor(
1121             SocketWrapperBase<S> socketWrapper, SocketEvent event);
1122
1123
1124     // ------------------------------------------------------- Lifecycle methods
1125
1126     /*
1127      * NOTE: There is no maintenance of state or checking for valid transitions
1128      * within this class other than ensuring that bind/unbind are called in the
1129      * right place. It is expected that the calling code will maintain state and
1130      * prevent invalid state transitions.
1131      */

1132
1133     public abstract void bind() throws Exception;
1134     public abstract void unbind() throws Exception;
1135     public abstract void startInternal() throws Exception;
1136     public abstract void stopInternal() throws Exception;
1137
1138
1139     private void bindWithCleanup() throws Exception {
1140         try {
1141             bind();
1142         } catch (Throwable t) {
1143             // Ensure open sockets etc. are cleaned up if something goes
1144             // wrong during bind
1145             ExceptionUtils.handleThrowable(t);
1146             unbind();
1147             throw t;
1148         }
1149     }
1150
1151
1152     public final void init() throws Exception {
1153         if (bindOnInit) {
1154             bindWithCleanup();
1155             bindState = BindState.BOUND_ON_INIT;
1156         }
1157         if (this.domain != null) {
1158             // Register endpoint (as ThreadPool - historical name)
1159             oname = new ObjectName(domain + ":type=ThreadPool,name=\"" + getName() + "\"");
1160             Registry.getRegistry(nullnull).registerComponent(this, oname, null);
1161
1162             ObjectName socketPropertiesOname = new ObjectName(domain +
1163                     ":type=ThreadPool,name=\"" + getName() + "\",subType=SocketProperties");
1164             socketProperties.setObjectName(socketPropertiesOname);
1165             Registry.getRegistry(nullnull).registerComponent(socketProperties, socketPropertiesOname, null);
1166
1167             for (SSLHostConfig sslHostConfig : findSslHostConfigs()) {
1168                 registerJmx(sslHostConfig);
1169             }
1170         }
1171     }
1172
1173
1174     private void registerJmx(SSLHostConfig sslHostConfig) {
1175         if (domain == null) {
1176             // Before init the domain is null
1177             return;
1178         }
1179         ObjectName sslOname = null;
1180         try {
1181             sslOname = new ObjectName(domain + ":type=SSLHostConfig,ThreadPool=\"" +
1182                     getName() + "\",name=" + ObjectName.quote(sslHostConfig.getHostName()));
1183             sslHostConfig.setObjectName(sslOname);
1184             try {
1185                 Registry.getRegistry(nullnull).registerComponent(sslHostConfig, sslOname, null);
1186             } catch (Exception e) {
1187                 getLog().warn(sm.getString("endpoint.jmxRegistrationFailed", sslOname), e);
1188             }
1189         } catch (MalformedObjectNameException e) {
1190             getLog().warn(sm.getString("endpoint.invalidJmxNameSslHost",
1191                     sslHostConfig.getHostName()), e);
1192         }
1193
1194         for (SSLHostConfigCertificate sslHostConfigCert : sslHostConfig.getCertificates()) {
1195             ObjectName sslCertOname = null;
1196             try {
1197                 sslCertOname = new ObjectName(domain +
1198                         ":type=SSLHostConfigCertificate,ThreadPool=\"" + getName() +
1199                         "\",Host=" + ObjectName.quote(sslHostConfig.getHostName()) +
1200                         ",name=" + sslHostConfigCert.getType());
1201                 sslHostConfigCert.setObjectName(sslCertOname);
1202                 try {
1203                     Registry.getRegistry(nullnull).registerComponent(
1204                             sslHostConfigCert, sslCertOname, null);
1205                 } catch (Exception e) {
1206                     getLog().warn(sm.getString("endpoint.jmxRegistrationFailed", sslCertOname), e);
1207                 }
1208             } catch (MalformedObjectNameException e) {
1209                 getLog().warn(sm.getString("endpoint.invalidJmxNameSslHostCert",
1210                         sslHostConfig.getHostName(), sslHostConfigCert.getType()), e);
1211             }
1212         }
1213     }
1214
1215
1216     private void unregisterJmx(SSLHostConfig sslHostConfig) {
1217         Registry registry = Registry.getRegistry(nullnull);
1218         registry.unregisterComponent(sslHostConfig.getObjectName());
1219         for (SSLHostConfigCertificate sslHostConfigCert : sslHostConfig.getCertificates()) {
1220             registry.unregisterComponent(sslHostConfigCert.getObjectName());
1221         }
1222     }
1223
1224
1225     public final void start() throws Exception {
1226         if (bindState == BindState.UNBOUND) {
1227             bindWithCleanup();
1228             bindState = BindState.BOUND_ON_START;
1229         }
1230         startInternal();
1231     }
1232
1233
1234     protected void startAcceptorThread() {
1235         acceptor = new Acceptor<>(this);
1236         String threadName = getName() + "-Acceptor";
1237         acceptor.setThreadName(threadName);
1238         Thread t = new Thread(acceptor, threadName);
1239         t.setPriority(getAcceptorThreadPriority());
1240         t.setDaemon(getDaemon());
1241         t.start();
1242     }
1243
1244
1245     /**
1246      * Pause the endpoint, which will stop it accepting new connections and
1247      * unlock the acceptor.
1248      */

1249     public void pause() {
1250         if (running && !paused) {
1251             paused = true;
1252             releaseConnectionLatch();
1253             unlockAccept();
1254             getHandler().pause();
1255         }
1256     }
1257
1258     /**
1259      * Resume the endpoint, which will make it start accepting new connections
1260      * again.
1261      */

1262     public void resume() {
1263         if (running) {
1264             paused = false;
1265         }
1266     }
1267
1268     public final void stop() throws Exception {
1269         stopInternal();
1270         if (bindState == BindState.BOUND_ON_START || bindState == BindState.SOCKET_CLOSED_ON_STOP) {
1271             unbind();
1272             bindState = BindState.UNBOUND;
1273         }
1274     }
1275
1276     public final void destroy() throws Exception {
1277         if (bindState == BindState.BOUND_ON_INIT) {
1278             unbind();
1279             bindState = BindState.UNBOUND;
1280         }
1281         Registry registry = Registry.getRegistry(nullnull);
1282         registry.unregisterComponent(oname);
1283         registry.unregisterComponent(socketProperties.getObjectName());
1284         for (SSLHostConfig sslHostConfig : findSslHostConfigs()) {
1285             unregisterJmx(sslHostConfig);
1286         }
1287     }
1288
1289
1290     protected abstract Log getLog();
1291
1292     protected LimitLatch initializeConnectionLatch() {
1293         if (maxConnections==-1) return null;
1294         if (connectionLimitLatch==null) {
1295             connectionLimitLatch = new LimitLatch(getMaxConnections());
1296         }
1297         return connectionLimitLatch;
1298     }
1299
1300     private void releaseConnectionLatch() {
1301         LimitLatch latch = connectionLimitLatch;
1302         if (latch!=null) latch.releaseAll();
1303         connectionLimitLatch = null;
1304     }
1305
1306     protected void countUpOrAwaitConnection() throws InterruptedException {
1307         if (maxConnections==-1) return;
1308         LimitLatch latch = connectionLimitLatch;
1309         if (latch!=null) latch.countUpOrAwait();
1310     }
1311
1312     protected long countDownConnection() {
1313         if (maxConnections==-1) return -1;
1314         LimitLatch latch = connectionLimitLatch;
1315         if (latch!=null) {
1316             long result = latch.countDown();
1317             if (result<0) {
1318                 getLog().warn(sm.getString("endpoint.warn.incorrectConnectionCount"));
1319             }
1320             return result;
1321         } else return -1;
1322     }
1323
1324
1325     /**
1326      * Close the server socket (to prevent further connections) if the server
1327      * socket was originally bound on {@link #start()} (rather than on
1328      * {@link #init()}).
1329      *
1330      * @see #getBindOnInit()
1331      */

1332     public final void closeServerSocketGraceful() {
1333         if (bindState == BindState.BOUND_ON_START) {
1334             bindState = BindState.SOCKET_CLOSED_ON_STOP;
1335             try {
1336                 doCloseServerSocket();
1337             } catch (IOException ioe) {
1338                 getLog().warn(sm.getString("endpoint.serverSocket.closeFailed", getName()), ioe);
1339             }
1340         }
1341     }
1342
1343
1344     /**
1345      * Actually close the server socket but don't perform any other clean-up.
1346      *
1347      * @throws IOException If an error occurs closing the socket
1348      */

1349     protected abstract void doCloseServerSocket() throws IOException;
1350
1351     protected abstract U serverSocketAccept() throws Exception;
1352
1353     protected abstract boolean setSocketOptions(U socket);
1354
1355     /**
1356      * Close the socket when the connection has to be immediately closed when
1357      * an error occurs while configuring the accepted socket or trying to
1358      * dispatch it for processing. The wrapper associated with the socket will
1359      * be used for the close.
1360      * @param socket The newly accepted socket
1361      */

1362     protected void closeSocket(U socket) {
1363         SocketWrapperBase<S> socketWrapper = connections.get(socket);
1364         if (socketWrapper != null) {
1365             socketWrapper.close();
1366         }
1367     }
1368
1369     /**
1370      * Close the socket. This is used when the connector is not in a state
1371      * which allows processing the socket, or if there was an error which
1372      * prevented the allocation of the socket wrapper.
1373      * @param socket The newly accepted socket
1374      */

1375     protected abstract void destroySocket(U socket);
1376 }
1377
1378