2 // ========================================================================
3 // Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4 // ------------------------------------------------------------------------
5 // All rights reserved. This program and the accompanying materials
6 // are made available under the terms of the Eclipse Public License v1.0
7 // and Apache License v2.0 which accompanies this distribution.
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
19 package org.eclipse.jetty.server;
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.LinkedHashMap;
26 import java.util.List;
27 import java.util.Locale;
30 import java.util.concurrent.ConcurrentHashMap;
31 import java.util.concurrent.CountDownLatch;
32 import java.util.concurrent.Executor;
33 import java.util.concurrent.Future;
34 import java.util.concurrent.TimeUnit;
36 import org.eclipse.jetty.io.ArrayByteBufferPool;
37 import org.eclipse.jetty.io.ByteBufferPool;
38 import org.eclipse.jetty.io.EndPoint;
39 import org.eclipse.jetty.util.FutureCallback;
40 import org.eclipse.jetty.util.annotation.ManagedAttribute;
41 import org.eclipse.jetty.util.annotation.ManagedObject;
42 import org.eclipse.jetty.util.component.ContainerLifeCycle;
43 import org.eclipse.jetty.util.component.Dumpable;
44 import org.eclipse.jetty.util.log.Log;
45 import org.eclipse.jetty.util.log.Logger;
46 import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
47 import org.eclipse.jetty.util.thread.Scheduler;
50 * <p>An abstract implementation of {@link Connector} that provides a {@link ConnectionFactory} mechanism
51 * for creating {@link Connection} instances for various protocols (HTTP, SSL, SPDY, etc).</p>
53 * <h2>Connector Services</h2>
54 * The abstract connector manages the dependent services needed by all specific connector instances:
56 * <li>The {@link Executor} service is used to run all active tasks needed by this connector such as accepting connections
57 * or handle HTTP requests. The default is to use the {@link Server#getThreadPool()} as an executor.
59 * <li>The {@link Scheduler} service is used to monitor the idle timeouts of all connections and is also made available
60 * to the connections to time such things as asynchronous request timeouts. The default is to use a new
61 * {@link ScheduledExecutorScheduler} instance.
63 * <li>The {@link ByteBufferPool} service is made available to all connections to be used to acquire and release
64 * {@link ByteBuffer} instances from a pool. The default is to use a new {@link ArrayByteBufferPool} instance.
67 * These services are managed as aggregate beans by the {@link ContainerLifeCycle} super class and
68 * may either be managed or unmanaged beans.
70 * <h2>Connection Factories</h2>
71 * The connector keeps a collection of {@link ConnectionFactory} instances, each of which are known by their
72 * protocol name. The protocol name may be a real protocol (eg http/1.1 or spdy/3) or it may be a private name
73 * that represents a special connection factory. For example, the name "SSL-http/1.1" is used for
74 * an {@link SslConnectionFactory} that has been instantiated with the {@link HttpConnectionFactory} as it's
77 * <h4>Configuring Connection Factories</h4>
78 * The collection of available {@link ConnectionFactory} may be constructor injected or modified with the
79 * methods {@link #addConnectionFactory(ConnectionFactory)}, {@link #removeConnectionFactory(String)} and
80 * {@link #setConnectionFactories(Collection)}. Only a single {@link ConnectionFactory} instance may be configured
81 * per protocol name, so if two factories with the same {@link ConnectionFactory#getProtocol()} are set, then
82 * the second will replace the first.
84 * The protocol factory used for newly accepted connections is specified by
85 * the method {@link #setDefaultProtocol(String)} or defaults to the protocol of the first configured factory.
87 * Each Connection factory type is responsible for the configuration of the protocols that it accepts. Thus to
88 * configure the HTTP protocol, you pass a {@link HttpConfiguration} instance to the {@link HttpConnectionFactory}
89 * (or the SPDY factories that can also provide HTTP Semantics). Similarly the {@link SslConnectionFactory} is
90 * configured by passing it a {@link SslContextFactory} and a next protocol name.
92 * <h4>Connection Factory Operation</h4>
93 * {@link ConnectionFactory}s may simply create a {@link Connection} instance to support a specific
94 * protocol. For example, the {@link HttpConnectionFactory} will create a {@link HttpConnection} instance
95 * that can handle http/1.1, http/1.0 and http/0.9.
97 * {@link ConnectionFactory}s may also create a chain of {@link Connection} instances, using other {@link ConnectionFactory} instances.
98 * For example, the {@link SslConnectionFactory} is configured with a next protocol name, so that once it has accepted
99 * a connection and created an {@link SslConnection}, it then used the next {@link ConnectionFactory} from the
100 * connector using the {@link #getConnectionFactory(String)} method, to create a {@link Connection} instance that
101 * will handle the unecrypted bytes from the {@link SslConnection}. If the next protocol is "http/1.1", then the
102 * {@link SslConnectionFactory} will have a protocol name of "SSL-http/1.1" and lookup "http/1.1" for the protocol
103 * to run over the SSL connection.
105 * {@link ConnectionFactory}s may also create temporary {@link Connection} instances that will exchange bytes
106 * over the connection to determine what is the next protocol to use. For example the NPN protocol is an extension
107 * of SSL to allow a protocol to be specified during the SSL handshake. NPN is used by the SPDY protocol to
108 * negotiate the version of SPDY or HTTP that the client and server will speak. Thus to accept a SPDY connection, the
109 * connector will be configured with {@link ConnectionFactory}s for "SSL-NPN", "NPN", "spdy/3", "spdy/2", "http/1.1"
110 * with the default protocol being "SSL-NPN". Thus a newly accepted connection uses "SSL-NPN", which specifies a
111 * SSLConnectionFactory with "NPN" as the next protocol. Thus an SslConnection instance is created chained to an NPNConnection
112 * instance. The NPN connection then negotiates with the client to determined the next protocol, which could be
113 * "spdy/3", "spdy/2" or the default of "http/1.1". Once the next protocol is determined, the NPN connection
114 * calls {@link #getConnectionFactory(String)} to create a connection instance that will replace the NPN connection as
115 * the connection chained to the SSLConnection.
118 * The connector will execute a number of acceptor tasks to the {@link Exception} service passed to the constructor.
119 * The acceptor tasks run in a loop while the connector is running and repeatedly call the abstract {@link #accept(int)} method.
120 * The implementation of the accept method must:
122 * <li>block waiting for new connections
123 * <li>accept the connection (eg socket accept)
124 * <li>perform any configuration of the connection (eg. socket linger times)
125 * <li>call the {@link #getDefaultConnectionFactory()} {@link ConnectionFactory#newConnection(Connector, org.eclipse.jetty.io.EndPoint)}
126 * method to create a new Connection instance.
128 * The default number of acceptor tasks is the minimum of 1 and half the number of available CPUs. Having more acceptors may reduce
129 * the latency for servers that see a high rate of new connections (eg HTTP/1.0 without keep-alive). Typically the default is
130 * sufficient for modern persistent protocols (HTTP/1.1, SPDY etc.)
132 @ManagedObject("Abstract implementation of the Connector Interface")
133 public abstract class AbstractConnector extends ContainerLifeCycle implements Connector, Dumpable
135 protected final Logger LOG = Log.getLogger(getClass());
136 // Order is important on server side, so we use a LinkedHashMap
137 private final Map<String, ConnectionFactory> _factories = new LinkedHashMap<>();
138 private final Server _server;
139 private final Executor _executor;
140 private final Scheduler _scheduler;
141 private final ByteBufferPool _byteBufferPool;
142 private final Thread[] _acceptors;
143 private final Set<EndPoint> _endpoints = Collections.newSetFromMap(new ConcurrentHashMap<EndPoint, Boolean>());
144 private final Set<EndPoint> _immutableEndPoints = Collections.unmodifiableSet(_endpoints);
145 private volatile CountDownLatch _stopping;
146 private long _idleTimeout = 30000;
147 private String _defaultProtocol;
148 private ConnectionFactory _defaultConnectionFactory;
149 private String _name;
150 private int _acceptorPriorityDelta;
154 * @param server The server this connector will be added to. Must not be null.
155 * @param executor An executor for this connector or null to use the servers executor
156 * @param scheduler A scheduler for this connector or null to either a {@link Scheduler} set as a server bean or if none set, then a new {@link ScheduledExecutorScheduler} instance.
157 * @param pool A buffer pool for this connector or null to either a {@link ByteBufferPool} set as a server bean or none set, the new {@link ArrayByteBufferPool} instance.
158 * @param acceptors the number of acceptor threads to use, or -1 for a default value. If 0, then no acceptor threads will be launched and some other mechanism will need to be used to accept new connections.
159 * @param factories The Connection Factories to use.
161 public AbstractConnector(
167 ConnectionFactory... factories)
170 _executor=executor!=null?executor:_server.getThreadPool();
172 scheduler=_server.getBean(Scheduler.class);
173 _scheduler=scheduler!=null?scheduler:new ScheduledExecutorScheduler();
175 pool=_server.getBean(ByteBufferPool.class);
176 _byteBufferPool = pool!=null?pool:new ArrayByteBufferPool();
178 addBean(_server,false);
181 unmanage(_executor); // inherited from server
183 addBean(_byteBufferPool);
185 for (ConnectionFactory factory:factories)
186 addConnectionFactory(factory);
188 int cores = Runtime.getRuntime().availableProcessors();
190 acceptors=Math.max(1, Math.min(4,cores/8));
191 if (acceptors > cores)
192 LOG.warn("Acceptors should be <= availableProcessors: " + this);
193 _acceptors = new Thread[acceptors];
198 public Server getServer()
204 public Executor getExecutor()
210 public ByteBufferPool getByteBufferPool()
212 return _byteBufferPool;
216 @ManagedAttribute("Idle timeout")
217 public long getIdleTimeout()
223 * <p>Sets the maximum Idle time for a connection, which roughly translates to the {@link Socket#setSoTimeout(int)}
224 * call, although with NIO implementations other mechanisms may be used to implement the timeout.</p>
225 * <p>The max idle time is applied:</p>
227 * <li>When waiting for a new message to be received on a connection</li>
228 * <li>When waiting for a new message to be sent on a connection</li>
230 * <p>This value is interpreted as the maximum time between some progress being made on the connection.
231 * So if a single byte is read or written, then the timeout is reset.</p>
233 * @param idleTimeout the idle timeout
235 public void setIdleTimeout(long idleTimeout)
237 _idleTimeout = idleTimeout;
241 * @return Returns the number of acceptor threads.
243 @ManagedAttribute("number of acceptor threads")
244 public int getAcceptors()
246 return _acceptors.length;
250 protected void doStart() throws Exception
252 _defaultConnectionFactory = getConnectionFactory(_defaultProtocol);
253 if(_defaultConnectionFactory==null)
254 throw new IllegalStateException("No protocol factory for default protocol: "+_defaultProtocol);
258 _stopping=new CountDownLatch(_acceptors.length);
259 for (int i = 0; i < _acceptors.length; i++)
261 Acceptor a = new Acceptor(i);
263 getExecutor().execute(a);
266 LOG.info("Started {}", this);
270 protected void interruptAcceptors()
274 for (Thread thread : _acceptors)
283 public Future<Void> shutdown()
285 return new FutureCallback(true);
289 protected void doStop() throws Exception
291 // Tell the acceptors we are stopping
292 interruptAcceptors();
294 // If we have a stop timeout
295 long stopTimeout = getStopTimeout();
296 CountDownLatch stopping=_stopping;
297 if (stopTimeout > 0 && stopping!=null)
298 stopping.await(stopTimeout,TimeUnit.MILLISECONDS);
303 for (Acceptor a : getBeans(Acceptor.class))
306 LOG.info("Stopped {}", this);
309 public void join() throws InterruptedException
314 public void join(long timeout) throws InterruptedException
318 for (Thread thread : _acceptors)
320 thread.join(timeout);
324 protected abstract void accept(int acceptorID) throws IOException, InterruptedException;
327 /* ------------------------------------------------------------ */
329 * @return Is the connector accepting new connections
331 protected boolean isAccepting()
337 public ConnectionFactory getConnectionFactory(String protocol)
339 synchronized (_factories)
341 return _factories.get(protocol.toLowerCase(Locale.ENGLISH));
346 public <T> T getConnectionFactory(Class<T> factoryType)
348 synchronized (_factories)
350 for (ConnectionFactory f : _factories.values())
351 if (factoryType.isAssignableFrom(f.getClass()))
357 public void addConnectionFactory(ConnectionFactory factory)
359 synchronized (_factories)
361 ConnectionFactory old=_factories.remove(factory.getProtocol());
364 _factories.put(factory.getProtocol().toLowerCase(Locale.ENGLISH), factory);
366 if (_defaultProtocol==null)
367 _defaultProtocol=factory.getProtocol();
371 public ConnectionFactory removeConnectionFactory(String protocol)
373 synchronized (_factories)
375 ConnectionFactory factory= _factories.remove(protocol.toLowerCase(Locale.ENGLISH));
382 public Collection<ConnectionFactory> getConnectionFactories()
384 synchronized (_factories)
386 return _factories.values();
390 public void setConnectionFactories(Collection<ConnectionFactory> factories)
392 synchronized (_factories)
394 List<ConnectionFactory> existing = new ArrayList<>(_factories.values());
395 for (ConnectionFactory factory: existing)
396 removeConnectionFactory(factory.getProtocol());
397 for (ConnectionFactory factory: factories)
399 addConnectionFactory(factory);
403 @ManagedAttribute("The priority delta to apply to acceptor threads")
404 public int getAcceptorPriorityDelta()
406 return _acceptorPriorityDelta;
409 /* ------------------------------------------------------------ */
410 /** Set the acceptor thread priority delta.
411 * <p>This allows the acceptor thread to run at a different priority.
412 * Typically this would be used to lower the priority to give preference
413 * to handling previously accepted connections rather than accepting
414 * new connections</p>
415 * @param acceptorPriorityDelta
417 public void setAcceptorPriorityDelta(int acceptorPriorityDelta)
419 int old=_acceptorPriorityDelta;
420 _acceptorPriorityDelta = acceptorPriorityDelta;
421 if (old!=acceptorPriorityDelta && isStarted())
423 for (Thread thread : _acceptors)
424 thread.setPriority(Math.max(Thread.MIN_PRIORITY,Math.min(Thread.MAX_PRIORITY,thread.getPriority()-old+acceptorPriorityDelta)));
429 @ManagedAttribute("Protocols supported by this connector")
430 public List<String> getProtocols()
432 synchronized (_factories)
434 return new ArrayList<>(_factories.keySet());
438 public void clearConnectionFactories()
440 synchronized (_factories)
446 @ManagedAttribute("This connector's default protocol")
447 public String getDefaultProtocol()
449 return _defaultProtocol;
452 public void setDefaultProtocol(String defaultProtocol)
454 _defaultProtocol = defaultProtocol.toLowerCase(Locale.ENGLISH);
456 _defaultConnectionFactory=getConnectionFactory(_defaultProtocol);
460 public ConnectionFactory getDefaultConnectionFactory()
463 return _defaultConnectionFactory;
464 return getConnectionFactory(_defaultProtocol);
467 private class Acceptor implements Runnable
469 private final int _acceptor;
470 private String _name;
472 private Acceptor(int id)
480 final Thread thread = Thread.currentThread();
481 String name=thread.getName();
482 _name=String.format("%s-acceptor-%d@%x-%s",name,_acceptor,hashCode(),AbstractConnector.this.toString());
483 thread.setName(_name);
485 int priority=thread.getPriority();
486 if (_acceptorPriorityDelta!=0)
487 thread.setPriority(Math.max(Thread.MIN_PRIORITY,Math.min(Thread.MAX_PRIORITY,priority+_acceptorPriorityDelta)));
489 synchronized (AbstractConnector.this)
491 _acceptors[_acceptor] = thread;
496 while (isAccepting())
513 thread.setName(name);
514 if (_acceptorPriorityDelta!=0)
515 thread.setPriority(priority);
517 synchronized (AbstractConnector.this)
519 _acceptors[_acceptor] = null;
521 CountDownLatch stopping=_stopping;
523 stopping.countDown();
528 public String toString()
532 return String.format("acceptor-%d@%x", _acceptor, hashCode());
541 // protected void connectionOpened(Connection connection)
543 // _stats.connectionOpened();
544 // connection.onOpen();
547 // protected void connectionClosed(Connection connection)
549 // connection.onClose();
550 // long duration = System.currentTimeMillis() - connection.getEndPoint().getCreatedTimeStamp();
551 // _stats.connectionClosed(duration, connection.getMessagesIn(), connection.getMessagesOut());
554 // public void connectionUpgraded(Connection oldConnection, Connection newConnection)
556 // oldConnection.onClose();
557 // _stats.connectionUpgraded(oldConnection.getMessagesIn(), oldConnection.getMessagesOut());
558 // newConnection.onOpen();
562 public Collection<EndPoint> getConnectedEndPoints()
564 return _immutableEndPoints;
567 protected void onEndPointOpened(EndPoint endp)
569 _endpoints.add(endp);
572 protected void onEndPointClosed(EndPoint endp)
574 _endpoints.remove(endp);
578 public Scheduler getScheduler()
584 public String getName()
589 /* ------------------------------------------------------------ */
591 * Set a connector name. A context may be configured with
592 * virtual hosts in the form "@contextname" and will only serve
593 * requests from the named connector,
594 * @param name A connector name.
596 public void setName(String name)
602 public String toString()
604 return String.format("%s@%x{%s}",
605 _name==null?getClass().getSimpleName():_name,
607 getDefaultProtocol());