Mercurial Hosting > luan
diff src/org/eclipse/jetty/server/AbstractConnector.java @ 802:3428c60d7cfc
replace jetty jars with source
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Wed, 07 Sep 2016 21:15:48 -0600 |
parents | |
children | ad292e148964 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/eclipse/jetty/server/AbstractConnector.java Wed Sep 07 21:15:48 2016 -0600 @@ -0,0 +1,1222 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.server; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; +import java.util.concurrent.atomic.AtomicLong; + +import javax.servlet.ServletRequest; + +import org.eclipse.jetty.http.HttpBuffers; +import org.eclipse.jetty.http.HttpBuffersImpl; +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpHeaders; +import org.eclipse.jetty.http.HttpSchemes; +import org.eclipse.jetty.io.Buffers; +import org.eclipse.jetty.io.Buffers.Type; +import org.eclipse.jetty.io.Connection; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.io.EofException; +import org.eclipse.jetty.util.component.AggregateLifeCycle; +import org.eclipse.jetty.util.component.Dumpable; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.statistic.CounterStatistic; +import org.eclipse.jetty.util.statistic.SampleStatistic; +import org.eclipse.jetty.util.thread.ThreadPool; + +/** + * Abstract Connector implementation. This abstract implementation of the Connector interface provides: + * <ul> + * <li>AbstractLifeCycle implementation</li> + * <li>Implementations for connector getters and setters</li> + * <li>Buffer management</li> + * <li>Socket configuration</li> + * <li>Base acceptor thread</li> + * <li>Optional reverse proxy headers checking</li> + * </ul> + */ +public abstract class AbstractConnector extends AggregateLifeCycle implements HttpBuffers, Connector, Dumpable +{ + private static final Logger LOG = Log.getLogger(AbstractConnector.class); + + private String _name; + + private Server _server; + private ThreadPool _threadPool; + private String _host; + private int _port = 0; + private String _integralScheme = HttpSchemes.HTTPS; + private int _integralPort = 0; + private String _confidentialScheme = HttpSchemes.HTTPS; + private int _confidentialPort = 0; + private int _acceptQueueSize = 0; + private int _acceptors = 1; + private int _acceptorPriorityOffset = 0; + private boolean _useDNS; + private boolean _forwarded; + private String _hostHeader; + + private String _forwardedHostHeader = HttpHeaders.X_FORWARDED_HOST; + private String _forwardedServerHeader = HttpHeaders.X_FORWARDED_SERVER; + private String _forwardedForHeader = HttpHeaders.X_FORWARDED_FOR; + private String _forwardedProtoHeader = HttpHeaders.X_FORWARDED_PROTO; + private String _forwardedCipherSuiteHeader; + private String _forwardedSslSessionIdHeader; + private boolean _reuseAddress = true; + + protected int _maxIdleTime = 200000; + protected int _lowResourceMaxIdleTime = -1; + protected int _soLingerTime = -1; + + private transient Thread[] _acceptorThreads; + + private final AtomicLong _statsStartedAt = new AtomicLong(-1L); + + /** connections to server */ + private final CounterStatistic _connectionStats = new CounterStatistic(); + /** requests per connection */ + private final SampleStatistic _requestStats = new SampleStatistic(); + /** duration of a connection */ + private final SampleStatistic _connectionDurationStats = new SampleStatistic(); + + protected final HttpBuffersImpl _buffers = new HttpBuffersImpl(); + + /* ------------------------------------------------------------ */ + /** + */ + public AbstractConnector() + { + addBean(_buffers); + } + + /* ------------------------------------------------------------ */ + /* + */ + public Server getServer() + { + return _server; + } + + /* ------------------------------------------------------------ */ + public void setServer(Server server) + { + _server = server; + } + + /* ------------------------------------------------------------ */ + public ThreadPool getThreadPool() + { + return _threadPool; + } + + /* ------------------------------------------------------------ */ + /** Set the ThreadPool. + * The threadpool passed is added via {@link #addBean(Object)} so that + * it's lifecycle may be managed as a {@link AggregateLifeCycle}. + * @param pool the threadPool to set + */ + public void setThreadPool(ThreadPool pool) + { + removeBean(_threadPool); + _threadPool = pool; + addBean(_threadPool); + } + + /* ------------------------------------------------------------ */ + /** + */ + public void setHost(String host) + { + _host = host; + } + + /* ------------------------------------------------------------ */ + /* + */ + public String getHost() + { + return _host; + } + + /* ------------------------------------------------------------ */ + public void setPort(int port) + { + _port = port; + } + + /* ------------------------------------------------------------ */ + public int getPort() + { + return _port; + } + + /* ------------------------------------------------------------ */ + /** + * @return Returns the maxIdleTime. + */ + public int getMaxIdleTime() + { + return _maxIdleTime; + } + + /* ------------------------------------------------------------ */ + /** + * Set the maximum Idle time for a connection, which roughly translates to the {@link Socket#setSoTimeout(int)} call, although with NIO implementations + * other mechanisms may be used to implement the timeout. The max idle time is applied: + * <ul> + * <li>When waiting for a new request to be received on a connection</li> + * <li>When reading the headers and content of a request</li> + * <li>When writing the headers and content of a response</li> + * </ul> + * Jetty interprets this value as the maximum time between some progress being made on the connection. So if a single byte is read or written, then the + * timeout (if implemented by jetty) is reset. However, in many instances, the reading/writing is delegated to the JVM, and the semantic is more strictly + * enforced as the maximum time a single read/write operation can take. Note, that as Jetty supports writes of memory mapped file buffers, then a write may + * take many 10s of seconds for large content written to a slow device. + * <p> + * Previously, Jetty supported separate idle timeouts and IO operation timeouts, however the expense of changing the value of soTimeout was significant, so + * these timeouts were merged. With the advent of NIO, it may be possible to again differentiate these values (if there is demand). + * + * @param maxIdleTime + * The maxIdleTime to set. + */ + public void setMaxIdleTime(int maxIdleTime) + { + _maxIdleTime = maxIdleTime; + } + + /* ------------------------------------------------------------ */ + /** + * @return Returns the maxIdleTime when resources are low. + */ + public int getLowResourcesMaxIdleTime() + { + return _lowResourceMaxIdleTime; + } + + /* ------------------------------------------------------------ */ + /** + * @param maxIdleTime + * The maxIdleTime to set when resources are low. + */ + public void setLowResourcesMaxIdleTime(int maxIdleTime) + { + _lowResourceMaxIdleTime = maxIdleTime; + } + + /* ------------------------------------------------------------ */ + /** + * @return Returns the maxIdleTime when resources are low. + * @deprecated + */ + @Deprecated + public final int getLowResourceMaxIdleTime() + { + return getLowResourcesMaxIdleTime(); + } + + /* ------------------------------------------------------------ */ + /** + * @param maxIdleTime + * The maxIdleTime to set when resources are low. + * @deprecated + */ + @Deprecated + public final void setLowResourceMaxIdleTime(int maxIdleTime) + { + setLowResourcesMaxIdleTime(maxIdleTime); + } + + /* ------------------------------------------------------------ */ + /** + * @return Returns the soLingerTime. + */ + public int getSoLingerTime() + { + return _soLingerTime; + } + + /* ------------------------------------------------------------ */ + /** + * @return Returns the acceptQueueSize. + */ + public int getAcceptQueueSize() + { + return _acceptQueueSize; + } + + /* ------------------------------------------------------------ */ + /** + * @param acceptQueueSize + * The acceptQueueSize to set. + */ + public void setAcceptQueueSize(int acceptQueueSize) + { + _acceptQueueSize = acceptQueueSize; + } + + /* ------------------------------------------------------------ */ + /** + * @return Returns the number of acceptor threads. + */ + public int getAcceptors() + { + return _acceptors; + } + + /* ------------------------------------------------------------ */ + /** + * @param acceptors + * The number of acceptor threads to set. + */ + public void setAcceptors(int acceptors) + { + if (acceptors > 2 * Runtime.getRuntime().availableProcessors()) + LOG.warn("Acceptors should be <=2*availableProcessors: " + this); + _acceptors = acceptors; + } + + /* ------------------------------------------------------------ */ + /** + * @param soLingerTime + * The soLingerTime to set or -1 to disable. + */ + public void setSoLingerTime(int soLingerTime) + { + _soLingerTime = soLingerTime; + } + + /* ------------------------------------------------------------ */ + @Override + protected void doStart() throws Exception + { + if (_server == null) + throw new IllegalStateException("No server"); + + // open listener port + open(); + + if (_threadPool == null) + { + _threadPool = _server.getThreadPool(); + addBean(_threadPool,false); + } + + super.doStart(); + + // Start selector thread + synchronized (this) + { + _acceptorThreads = new Thread[getAcceptors()]; + + for (int i = 0; i < _acceptorThreads.length; i++) + if (!_threadPool.dispatch(new Acceptor(i))) + throw new IllegalStateException("!accepting"); + if (_threadPool.isLowOnThreads()) + LOG.warn("insufficient threads configured for {}",this); + } + + LOG.info("Started {}",this); + } + + /* ------------------------------------------------------------ */ + @Override + protected void doStop() throws Exception + { + try + { + close(); + } + catch (IOException e) + { + LOG.warn(e); + } + + super.doStop(); + + Thread[] acceptors; + synchronized (this) + { + acceptors = _acceptorThreads; + _acceptorThreads = null; + } + if (acceptors != null) + { + for (Thread thread : acceptors) + { + if (thread != null) + thread.interrupt(); + } + } + } + + /* ------------------------------------------------------------ */ + public void join() throws InterruptedException + { + Thread[] threads; + synchronized(this) + { + threads=_acceptorThreads; + } + if (threads != null) + for (Thread thread : threads) + if (thread != null) + thread.join(); + } + + /* ------------------------------------------------------------ */ + protected void configure(Socket socket) throws IOException + { + try + { + socket.setTcpNoDelay(true); + if (_soLingerTime >= 0) + socket.setSoLinger(true,_soLingerTime / 1000); + else + socket.setSoLinger(false,0); + } + catch (Exception e) + { + LOG.ignore(e); + } + } + + /* ------------------------------------------------------------ */ + public void customize(EndPoint endpoint, Request request) throws IOException + { + if (isForwarded()) + checkForwardedHeaders(endpoint,request); + } + + /* ------------------------------------------------------------ */ + protected void checkForwardedHeaders(EndPoint endpoint, Request request) throws IOException + { + HttpFields httpFields = request.getConnection().getRequestFields(); + + // Do SSL first + if (getForwardedCipherSuiteHeader()!=null) + { + String cipher_suite=httpFields.getStringField(getForwardedCipherSuiteHeader()); + if (cipher_suite!=null) + request.setAttribute("javax.servlet.request.cipher_suite",cipher_suite); + } + if (getForwardedSslSessionIdHeader()!=null) + { + String ssl_session_id=httpFields.getStringField(getForwardedSslSessionIdHeader()); + if(ssl_session_id!=null) + { + request.setAttribute("javax.servlet.request.ssl_session_id", ssl_session_id); + request.setScheme(HttpSchemes.HTTPS); + } + } + + // Retrieving headers from the request + String forwardedHost = getLeftMostFieldValue(httpFields,getForwardedHostHeader()); + String forwardedServer = getLeftMostFieldValue(httpFields,getForwardedServerHeader()); + String forwardedFor = getLeftMostFieldValue(httpFields,getForwardedForHeader()); + String forwardedProto = getLeftMostFieldValue(httpFields,getForwardedProtoHeader()); + + if (_hostHeader != null) + { + // Update host header + httpFields.put(HttpHeaders.HOST_BUFFER,_hostHeader); + request.setServerName(null); + request.setServerPort(-1); + request.getServerName(); + } + else if (forwardedHost != null) + { + // Update host header + httpFields.put(HttpHeaders.HOST_BUFFER,forwardedHost); + request.setServerName(null); + request.setServerPort(-1); + request.getServerName(); + } + else if (forwardedServer != null) + { + // Use provided server name + request.setServerName(forwardedServer); + } + + if (forwardedFor != null) + { + request.setRemoteAddr(forwardedFor); + InetAddress inetAddress = null; + + if (_useDNS) + { + try + { + inetAddress = InetAddress.getByName(forwardedFor); + } + catch (UnknownHostException e) + { + LOG.ignore(e); + } + } + + request.setRemoteHost(inetAddress == null?forwardedFor:inetAddress.getHostName()); + } + + if (forwardedProto != null) + { + request.setScheme(forwardedProto); + } + } + + /* ------------------------------------------------------------ */ + protected String getLeftMostFieldValue(HttpFields fields, String header) + { + if (header == null) + return null; + + String headerValue = fields.getStringField(header); + + if (headerValue == null) + return null; + + int commaIndex = headerValue.indexOf(','); + + if (commaIndex == -1) + { + // Single value + return headerValue; + } + + // The left-most value is the farthest downstream client + return headerValue.substring(0,commaIndex); + } + + /* ------------------------------------------------------------ */ + public void persist(EndPoint endpoint) throws IOException + { + } + + /* ------------------------------------------------------------ */ + /* + * @see org.eclipse.jetty.server.Connector#getConfidentialPort() + */ + public int getConfidentialPort() + { + return _confidentialPort; + } + + /* ------------------------------------------------------------ */ + /* ------------------------------------------------------------ */ + /* + * @see org.eclipse.jetty.server.Connector#getConfidentialScheme() + */ + public String getConfidentialScheme() + { + return _confidentialScheme; + } + + /* ------------------------------------------------------------ */ + /* + * @see org.eclipse.jetty.server.Connector#isConfidential(org.eclipse.jetty.server .Request) + */ + public boolean isIntegral(Request request) + { + return false; + } + + /* ------------------------------------------------------------ */ + /* + * @see org.eclipse.jetty.server.Connector#getConfidentialPort() + */ + public int getIntegralPort() + { + return _integralPort; + } + + /* ------------------------------------------------------------ */ + /* + * @see org.eclipse.jetty.server.Connector#getIntegralScheme() + */ + public String getIntegralScheme() + { + return _integralScheme; + } + + /* ------------------------------------------------------------ */ + /* + * @see org.eclipse.jetty.server.Connector#isConfidential(org.eclipse.jetty.server.Request) + */ + public boolean isConfidential(Request request) + { + return _forwarded && request.getScheme().equalsIgnoreCase(HttpSchemes.HTTPS); + } + + /* ------------------------------------------------------------ */ + /** + * @param confidentialPort + * The confidentialPort to set. + */ + public void setConfidentialPort(int confidentialPort) + { + _confidentialPort = confidentialPort; + } + + /* ------------------------------------------------------------ */ + /** + * @param confidentialScheme + * The confidentialScheme to set. + */ + public void setConfidentialScheme(String confidentialScheme) + { + _confidentialScheme = confidentialScheme; + } + + /* ------------------------------------------------------------ */ + /** + * @param integralPort + * The integralPort to set. + */ + public void setIntegralPort(int integralPort) + { + _integralPort = integralPort; + } + + /* ------------------------------------------------------------ */ + /** + * @param integralScheme + * The integralScheme to set. + */ + public void setIntegralScheme(String integralScheme) + { + _integralScheme = integralScheme; + } + + /* ------------------------------------------------------------ */ + protected abstract void accept(int acceptorID) throws IOException, InterruptedException; + + /* ------------------------------------------------------------ */ + public void stopAccept(int acceptorID) throws Exception + { + } + + /* ------------------------------------------------------------ */ + public boolean getResolveNames() + { + return _useDNS; + } + + /* ------------------------------------------------------------ */ + public void setResolveNames(boolean resolve) + { + _useDNS = resolve; + } + + /* ------------------------------------------------------------ */ + /** + * Is reverse proxy handling on? + * + * @return true if this connector is checking the x-forwarded-for/host/server headers + */ + public boolean isForwarded() + { + return _forwarded; + } + + /* ------------------------------------------------------------ */ + /** + * Set reverse proxy handling. If set to true, then the X-Forwarded headers (or the headers set in their place) are looked for to set the request protocol, + * host, server and client ip. + * + * @param check + * true if this connector is checking the x-forwarded-for/host/server headers + * @see #setForwardedForHeader(String) + * @see #setForwardedHostHeader(String) + * @see #setForwardedProtoHeader(String) + * @see #setForwardedServerHeader(String) + */ + public void setForwarded(boolean check) + { + if (check) + LOG.debug("{} is forwarded",this); + _forwarded = check; + } + + /* ------------------------------------------------------------ */ + public String getHostHeader() + { + return _hostHeader; + } + + /* ------------------------------------------------------------ */ + /** + * Set a forced valued for the host header to control what is returned by {@link ServletRequest#getServerName()} and {@link ServletRequest#getServerPort()}. + * This value is only used if {@link #isForwarded()} is true. + * + * @param hostHeader + * The value of the host header to force. + */ + public void setHostHeader(String hostHeader) + { + _hostHeader = hostHeader; + } + + /* ------------------------------------------------------------ */ + /* + * + * @see #setForwarded(boolean) + */ + public String getForwardedHostHeader() + { + return _forwardedHostHeader; + } + + /* ------------------------------------------------------------ */ + /** + * @param forwardedHostHeader + * The header name for forwarded hosts (default x-forwarded-host) + * @see #setForwarded(boolean) + */ + public void setForwardedHostHeader(String forwardedHostHeader) + { + _forwardedHostHeader = forwardedHostHeader; + } + + /* ------------------------------------------------------------ */ + /** + * @return the header name for forwarded server. + * @see #setForwarded(boolean) + */ + public String getForwardedServerHeader() + { + return _forwardedServerHeader; + } + + /* ------------------------------------------------------------ */ + /** + * @param forwardedServerHeader + * The header name for forwarded server (default x-forwarded-server) + * @see #setForwarded(boolean) + */ + public void setForwardedServerHeader(String forwardedServerHeader) + { + _forwardedServerHeader = forwardedServerHeader; + } + + /* ------------------------------------------------------------ */ + /** + * @see #setForwarded(boolean) + */ + public String getForwardedForHeader() + { + return _forwardedForHeader; + } + + /* ------------------------------------------------------------ */ + /** + * @param forwardedRemoteAddressHeader + * The header name for forwarded for (default x-forwarded-for) + * @see #setForwarded(boolean) + */ + public void setForwardedForHeader(String forwardedRemoteAddressHeader) + { + _forwardedForHeader = forwardedRemoteAddressHeader; + } + + /* ------------------------------------------------------------ */ + /** + * Get the forwardedProtoHeader. + * + * @return the forwardedProtoHeader (default X-Forwarded-For) + * @see #setForwarded(boolean) + */ + public String getForwardedProtoHeader() + { + return _forwardedProtoHeader; + } + + /* ------------------------------------------------------------ */ + /** + * Set the forwardedProtoHeader. + * + * @param forwardedProtoHeader + * the forwardedProtoHeader to set (default X-Forwarded-For) + * @see #setForwarded(boolean) + */ + public void setForwardedProtoHeader(String forwardedProtoHeader) + { + _forwardedProtoHeader = forwardedProtoHeader; + } + + /* ------------------------------------------------------------ */ + /** + * @return The header name holding a forwarded cipher suite (default null) + */ + public String getForwardedCipherSuiteHeader() + { + return _forwardedCipherSuiteHeader; + } + + /* ------------------------------------------------------------ */ + /** + * @param forwardedCipherSuite + * The header name holding a forwarded cipher suite (default null) + */ + public void setForwardedCipherSuiteHeader(String forwardedCipherSuite) + { + _forwardedCipherSuiteHeader = forwardedCipherSuite; + } + + /* ------------------------------------------------------------ */ + /** + * @return The header name holding a forwarded SSL Session ID (default null) + */ + public String getForwardedSslSessionIdHeader() + { + return _forwardedSslSessionIdHeader; + } + + /* ------------------------------------------------------------ */ + /** + * @param forwardedSslSessionId + * The header name holding a forwarded SSL Session ID (default null) + */ + public void setForwardedSslSessionIdHeader(String forwardedSslSessionId) + { + _forwardedSslSessionIdHeader = forwardedSslSessionId; + } + + public int getRequestBufferSize() + { + return _buffers.getRequestBufferSize(); + } + + public void setRequestBufferSize(int requestBufferSize) + { + _buffers.setRequestBufferSize(requestBufferSize); + } + + public int getRequestHeaderSize() + { + return _buffers.getRequestHeaderSize(); + } + + public void setRequestHeaderSize(int requestHeaderSize) + { + _buffers.setRequestHeaderSize(requestHeaderSize); + } + + public int getResponseBufferSize() + { + return _buffers.getResponseBufferSize(); + } + + public void setResponseBufferSize(int responseBufferSize) + { + _buffers.setResponseBufferSize(responseBufferSize); + } + + public int getResponseHeaderSize() + { + return _buffers.getResponseHeaderSize(); + } + + public void setResponseHeaderSize(int responseHeaderSize) + { + _buffers.setResponseHeaderSize(responseHeaderSize); + } + + public Type getRequestBufferType() + { + return _buffers.getRequestBufferType(); + } + + public Type getRequestHeaderType() + { + return _buffers.getRequestHeaderType(); + } + + public Type getResponseBufferType() + { + return _buffers.getResponseBufferType(); + } + + public Type getResponseHeaderType() + { + return _buffers.getResponseHeaderType(); + } + + public void setRequestBuffers(Buffers requestBuffers) + { + _buffers.setRequestBuffers(requestBuffers); + } + + public void setResponseBuffers(Buffers responseBuffers) + { + _buffers.setResponseBuffers(responseBuffers); + } + + public Buffers getRequestBuffers() + { + return _buffers.getRequestBuffers(); + } + + public Buffers getResponseBuffers() + { + return _buffers.getResponseBuffers(); + } + + public void setMaxBuffers(int maxBuffers) + { + _buffers.setMaxBuffers(maxBuffers); + } + + public int getMaxBuffers() + { + return _buffers.getMaxBuffers(); + } + + /* ------------------------------------------------------------ */ + @Override + public String toString() + { + return String.format("%s@%s:%d", + getClass().getSimpleName(), + getHost()==null?"0.0.0.0":getHost(), + getLocalPort()<=0?getPort():getLocalPort()); + } + + /* ------------------------------------------------------------ */ + /* ------------------------------------------------------------ */ + /* ------------------------------------------------------------ */ + private class Acceptor implements Runnable + { + int _acceptor = 0; + + Acceptor(int id) + { + _acceptor = id; + } + + /* ------------------------------------------------------------ */ + public void run() + { + Thread current = Thread.currentThread(); + String name; + synchronized (AbstractConnector.this) + { + if (_acceptorThreads == null) + return; + + _acceptorThreads[_acceptor] = current; + name = _acceptorThreads[_acceptor].getName(); + current.setName(name + " Acceptor" + _acceptor + " " + AbstractConnector.this); + } + int old_priority = current.getPriority(); + + try + { + current.setPriority(old_priority - _acceptorPriorityOffset); + while (isRunning() && getConnection() != null) + { + try + { + accept(_acceptor); + } + catch (EofException e) + { + LOG.ignore(e); + } + catch (IOException e) + { + LOG.ignore(e); + } + catch (InterruptedException x) + { + // Connector has been stopped + LOG.ignore(x); + } + catch (Throwable e) + { + LOG.warn(e); + } + } + } + finally + { + current.setPriority(old_priority); + current.setName(name); + + synchronized (AbstractConnector.this) + { + if (_acceptorThreads != null) + _acceptorThreads[_acceptor] = null; + } + } + } + } + + /* ------------------------------------------------------------ */ + public String getName() + { + if (_name == null) + _name = (getHost() == null?"0.0.0.0":getHost()) + ":" + (getLocalPort() <= 0?getPort():getLocalPort()); + return _name; + } + + /* ------------------------------------------------------------ */ + public void setName(String name) + { + _name = name; + } + + /* ------------------------------------------------------------ */ + /** + * @return Get the number of requests handled by this connector since last call of statsReset(). If setStatsOn(false) then this is undefined. + */ + public int getRequests() + { + return (int)_requestStats.getTotal(); + } + + /* ------------------------------------------------------------ */ + /** + * @return Returns the connectionsDurationTotal. + */ + public long getConnectionsDurationTotal() + { + return _connectionDurationStats.getTotal(); + } + + /* ------------------------------------------------------------ */ + /** + * @return Number of connections accepted by the server since statsReset() called. Undefined if setStatsOn(false). + */ + public int getConnections() + { + return (int)_connectionStats.getTotal(); + } + + /* ------------------------------------------------------------ */ + /** + * @return Number of connections currently open that were opened since statsReset() called. Undefined if setStatsOn(false). + */ + public int getConnectionsOpen() + { + return (int)_connectionStats.getCurrent(); + } + + /* ------------------------------------------------------------ */ + /** + * @return Maximum number of connections opened simultaneously since statsReset() called. Undefined if setStatsOn(false). + */ + public int getConnectionsOpenMax() + { + return (int)_connectionStats.getMax(); + } + + /* ------------------------------------------------------------ */ + /** + * @return Mean duration in milliseconds of open connections since statsReset() called. Undefined if setStatsOn(false). + */ + public double getConnectionsDurationMean() + { + return _connectionDurationStats.getMean(); + } + + /* ------------------------------------------------------------ */ + /** + * @return Maximum duration in milliseconds of an open connection since statsReset() called. Undefined if setStatsOn(false). + */ + public long getConnectionsDurationMax() + { + return _connectionDurationStats.getMax(); + } + + /* ------------------------------------------------------------ */ + /** + * @return Standard deviation of duration in milliseconds of open connections since statsReset() called. Undefined if setStatsOn(false). + */ + public double getConnectionsDurationStdDev() + { + return _connectionDurationStats.getStdDev(); + } + + /* ------------------------------------------------------------ */ + /** + * @return Mean number of requests per connection since statsReset() called. Undefined if setStatsOn(false). + */ + public double getConnectionsRequestsMean() + { + return _requestStats.getMean(); + } + + /* ------------------------------------------------------------ */ + /** + * @return Maximum number of requests per connection since statsReset() called. Undefined if setStatsOn(false). + */ + public int getConnectionsRequestsMax() + { + return (int)_requestStats.getMax(); + } + + /* ------------------------------------------------------------ */ + /** + * @return Standard deviation of number of requests per connection since statsReset() called. Undefined if setStatsOn(false). + */ + public double getConnectionsRequestsStdDev() + { + return _requestStats.getStdDev(); + } + + /* ------------------------------------------------------------ */ + /** + * Reset statistics. + */ + public void statsReset() + { + updateNotEqual(_statsStartedAt,-1,System.currentTimeMillis()); + + _requestStats.reset(); + _connectionStats.reset(); + _connectionDurationStats.reset(); + } + + /* ------------------------------------------------------------ */ + public void setStatsOn(boolean on) + { + if (on && _statsStartedAt.get() != -1) + return; + + if (LOG.isDebugEnabled()) + LOG.debug("Statistics on = " + on + " for " + this); + + statsReset(); + _statsStartedAt.set(on?System.currentTimeMillis():-1); + } + + /* ------------------------------------------------------------ */ + /** + * @return True if statistics collection is turned on. + */ + public boolean getStatsOn() + { + return _statsStartedAt.get() != -1; + } + + /* ------------------------------------------------------------ */ + /** + * @return Timestamp stats were started at. + */ + public long getStatsOnMs() + { + long start = _statsStartedAt.get(); + + return (start != -1)?(System.currentTimeMillis() - start):0; + } + + /* ------------------------------------------------------------ */ + protected void connectionOpened(Connection connection) + { + if (_statsStartedAt.get() == -1) + return; + + _connectionStats.increment(); + } + + /* ------------------------------------------------------------ */ + protected void connectionUpgraded(Connection oldConnection, Connection newConnection) + { + _requestStats.set((oldConnection instanceof AbstractHttpConnection)?((AbstractHttpConnection)oldConnection).getRequests():0); + } + + /* ------------------------------------------------------------ */ + protected void connectionClosed(Connection connection) + { + connection.onClose(); + + if (_statsStartedAt.get() == -1) + return; + + long duration = System.currentTimeMillis() - connection.getTimeStamp(); + int requests = (connection instanceof AbstractHttpConnection)?((AbstractHttpConnection)connection).getRequests():0; + _requestStats.set(requests); + _connectionStats.decrement(); + _connectionDurationStats.set(duration); + } + + /* ------------------------------------------------------------ */ + /** + * @return the acceptorPriority + */ + public int getAcceptorPriorityOffset() + { + return _acceptorPriorityOffset; + } + + /* ------------------------------------------------------------ */ + /** + * Set the priority offset of the acceptor threads. The priority is adjusted by this amount (default 0) to either favour the acceptance of new threads and + * newly active connections or to favour the handling of already dispatched connections. + * + * @param offset + * the amount to alter the priority of the acceptor threads. + */ + public void setAcceptorPriorityOffset(int offset) + { + _acceptorPriorityOffset = offset; + } + + /* ------------------------------------------------------------ */ + /** + * @return True if the the server socket will be opened in SO_REUSEADDR mode. + */ + public boolean getReuseAddress() + { + return _reuseAddress; + } + + /* ------------------------------------------------------------ */ + /** + * @param reuseAddress + * True if the the server socket will be opened in SO_REUSEADDR mode. + */ + public void setReuseAddress(boolean reuseAddress) + { + _reuseAddress = reuseAddress; + } + + /* ------------------------------------------------------------ */ + public boolean isLowResources() + { + if (_threadPool != null) + return _threadPool.isLowOnThreads(); + return _server.getThreadPool().isLowOnThreads(); + } + + /* ------------------------------------------------------------ */ + private void updateNotEqual(AtomicLong valueHolder, long compare, long value) + { + long oldValue = valueHolder.get(); + while (compare != oldValue) + { + if (valueHolder.compareAndSet(oldValue,value)) + break; + oldValue = valueHolder.get(); + } + } +}