]> WPIA git - gigi.git/blob - lib/jetty/org/eclipse/jetty/server/AbstractConnector.java
updating jetty to jetty-9.2.16.v2016040
[gigi.git] / lib / jetty / org / eclipse / jetty / server / AbstractConnector.java
1 //
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.
8 //
9 //      The Eclipse Public License is available at
10 //      http://www.eclipse.org/legal/epl-v10.html
11 //
12 //      The Apache License v2.0 is available at
13 //      http://www.opensource.org/licenses/apache2.0.php
14 //
15 //  You may elect to redistribute this code under either of these licenses.
16 //  ========================================================================
17 //
18
19 package org.eclipse.jetty.server;
20
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;
28 import java.util.Map;
29 import java.util.Set;
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;
35
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;
48
49 /**
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>
52  *
53  * <h2>Connector Services</h2>
54  * The abstract connector manages the dependent services needed by all specific connector instances:
55  * <ul>
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.
58  * </li>
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.
62  * </li>
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.
65  * </li>
66  * </ul>
67  * These services are managed as aggregate beans by the {@link ContainerLifeCycle} super class and
68  * may either be managed or unmanaged beans.
69  *
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
75  * next protocol.
76  *
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.
83  * <p>
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.
86  * <p>
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.
91  *
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.
96  * <p>
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.
104  * <p>
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.
116  * <p>
117  * <h2>Acceptors</h2>
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:
121  * <nl>
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.
127  * </nl>
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.)
131  */
132 @ManagedObject("Abstract implementation of the Connector Interface")
133 public abstract class AbstractConnector extends ContainerLifeCycle implements Connector, Dumpable
134 {
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;
151
152
153     /**
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.
160      */
161     public AbstractConnector(
162             Server server,
163             Executor executor,
164             Scheduler scheduler,
165             ByteBufferPool pool,
166             int acceptors,
167             ConnectionFactory... factories)
168     {
169         _server=server;
170         _executor=executor!=null?executor:_server.getThreadPool();
171         if (scheduler==null)
172             scheduler=_server.getBean(Scheduler.class);
173         _scheduler=scheduler!=null?scheduler:new ScheduledExecutorScheduler();
174         if (pool==null)
175             pool=_server.getBean(ByteBufferPool.class);
176         _byteBufferPool = pool!=null?pool:new ArrayByteBufferPool();
177
178         addBean(_server,false);
179         addBean(_executor);
180         if (executor==null)
181             unmanage(_executor); // inherited from server
182         addBean(_scheduler);
183         addBean(_byteBufferPool);
184
185         for (ConnectionFactory factory:factories)
186             addConnectionFactory(factory);
187
188         int cores = Runtime.getRuntime().availableProcessors();
189         if (acceptors < 0)
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];
194     }
195
196
197     @Override
198     public Server getServer()
199     {
200         return _server;
201     }
202
203     @Override
204     public Executor getExecutor()
205     {
206         return _executor;
207     }
208
209     @Override
210     public ByteBufferPool getByteBufferPool()
211     {
212         return _byteBufferPool;
213     }
214
215     @Override
216     @ManagedAttribute("Idle timeout")
217     public long getIdleTimeout()
218     {
219         return _idleTimeout;
220     }
221
222     /**
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>
226      * <ul>
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>
229      * </ul>
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>
232      *
233      * @param idleTimeout the idle timeout
234      */
235     public void setIdleTimeout(long idleTimeout)
236     {
237         _idleTimeout = idleTimeout;
238     }
239
240     /**
241      * @return Returns the number of acceptor threads.
242      */
243     @ManagedAttribute("number of acceptor threads")
244     public int getAcceptors()
245     {
246         return _acceptors.length;
247     }
248
249     @Override
250     protected void doStart() throws Exception
251     {
252         _defaultConnectionFactory = getConnectionFactory(_defaultProtocol);
253         if(_defaultConnectionFactory==null)
254             throw new IllegalStateException("No protocol factory for default protocol: "+_defaultProtocol);
255
256         super.doStart();
257
258         _stopping=new CountDownLatch(_acceptors.length);
259         for (int i = 0; i < _acceptors.length; i++)
260         {
261             Acceptor a = new Acceptor(i);
262             addBean(a);
263             getExecutor().execute(a);
264         }
265
266         LOG.info("Started {}", this);
267     }
268
269
270     protected void interruptAcceptors()
271     {
272         synchronized (this)
273         {
274             for (Thread thread : _acceptors)
275             {
276                 if (thread != null)
277                     thread.interrupt();
278             }
279         }
280     }
281
282     @Override
283     public Future<Void> shutdown()
284     {
285         return new FutureCallback(true);
286     }
287
288     @Override
289     protected void doStop() throws Exception
290     {
291         // Tell the acceptors we are stopping
292         interruptAcceptors();
293
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);
299         _stopping=null;
300
301         super.doStop();
302         
303         for (Acceptor a : getBeans(Acceptor.class))
304             removeBean(a);
305
306         LOG.info("Stopped {}", this);
307     }
308
309     public void join() throws InterruptedException
310     {
311         join(0);
312     }
313
314     public void join(long timeout) throws InterruptedException
315     {
316         synchronized (this)
317         {
318             for (Thread thread : _acceptors)
319                 if (thread != null)
320                     thread.join(timeout);
321         }
322     }
323
324     protected abstract void accept(int acceptorID) throws IOException, InterruptedException;
325
326
327     /* ------------------------------------------------------------ */
328     /**
329      * @return Is the connector accepting new connections
330      */
331     protected boolean isAccepting()
332     {
333         return isRunning();
334     }
335
336     @Override
337     public ConnectionFactory getConnectionFactory(String protocol)
338     {
339         synchronized (_factories)
340         {
341             return _factories.get(protocol.toLowerCase(Locale.ENGLISH));
342         }
343     }
344
345     @Override
346     public <T> T getConnectionFactory(Class<T> factoryType)
347     {
348         synchronized (_factories)
349         {
350             for (ConnectionFactory f : _factories.values())
351                 if (factoryType.isAssignableFrom(f.getClass()))
352                     return (T)f;
353             return null;
354         }
355     }
356
357     public void addConnectionFactory(ConnectionFactory factory)
358     {
359         synchronized (_factories)
360         {
361             ConnectionFactory old=_factories.remove(factory.getProtocol());
362             if (old!=null)
363                 removeBean(old);
364             _factories.put(factory.getProtocol().toLowerCase(Locale.ENGLISH), factory);
365             addBean(factory);
366             if (_defaultProtocol==null)
367                 _defaultProtocol=factory.getProtocol();
368         }
369     }
370
371     public ConnectionFactory removeConnectionFactory(String protocol)
372     {
373         synchronized (_factories)
374         {
375             ConnectionFactory factory= _factories.remove(protocol.toLowerCase(Locale.ENGLISH));
376             removeBean(factory);
377             return factory;
378         }
379     }
380
381     @Override
382     public Collection<ConnectionFactory> getConnectionFactories()
383     {
384         synchronized (_factories)
385         {
386             return _factories.values();
387         }
388     }
389
390     public void setConnectionFactories(Collection<ConnectionFactory> factories)
391     {
392         synchronized (_factories)
393         {
394             List<ConnectionFactory> existing = new ArrayList<>(_factories.values());
395             for (ConnectionFactory factory: existing)
396                 removeConnectionFactory(factory.getProtocol());
397             for (ConnectionFactory factory: factories)
398                 if (factory!=null)
399                     addConnectionFactory(factory);
400         }
401     }
402
403     @ManagedAttribute("The priority delta to apply to acceptor threads")
404     public int getAcceptorPriorityDelta()
405     {
406         return _acceptorPriorityDelta;
407     }
408
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
416      */
417     public void setAcceptorPriorityDelta(int acceptorPriorityDelta)
418     {
419         int old=_acceptorPriorityDelta;
420         _acceptorPriorityDelta = acceptorPriorityDelta;
421         if (old!=acceptorPriorityDelta && isStarted())
422         {
423             for (Thread thread : _acceptors)
424                 thread.setPriority(Math.max(Thread.MIN_PRIORITY,Math.min(Thread.MAX_PRIORITY,thread.getPriority()-old+acceptorPriorityDelta)));
425         }
426     }
427
428     @Override
429     @ManagedAttribute("Protocols supported by this connector")
430     public List<String> getProtocols()
431     {
432         synchronized (_factories)
433         {
434             return new ArrayList<>(_factories.keySet());
435         }
436     }
437
438     public void clearConnectionFactories()
439     {
440         synchronized (_factories)
441         {
442             _factories.clear();
443         }
444     }
445
446     @ManagedAttribute("This connector's default protocol")
447     public String getDefaultProtocol()
448     {
449         return _defaultProtocol;
450     }
451
452     public void setDefaultProtocol(String defaultProtocol)
453     {
454         _defaultProtocol = defaultProtocol.toLowerCase(Locale.ENGLISH);
455         if (isRunning())
456             _defaultConnectionFactory=getConnectionFactory(_defaultProtocol);
457     }
458
459     @Override
460     public ConnectionFactory getDefaultConnectionFactory()
461     {
462         if (isStarted())
463             return _defaultConnectionFactory;
464         return getConnectionFactory(_defaultProtocol);
465     }
466
467     private class Acceptor implements Runnable
468     {
469         private final int _acceptor;
470         private String _name;
471
472         private Acceptor(int id)
473         {
474             _acceptor = id;
475         }
476
477         @Override
478         public void run()
479         {
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);
484             
485             int priority=thread.getPriority();
486             if (_acceptorPriorityDelta!=0)
487                 thread.setPriority(Math.max(Thread.MIN_PRIORITY,Math.min(Thread.MAX_PRIORITY,priority+_acceptorPriorityDelta)));
488
489             synchronized (AbstractConnector.this)
490             {
491                 _acceptors[_acceptor] = thread;
492             }
493
494             try
495             {
496                 while (isAccepting())
497                 {
498                     try
499                     {
500                         accept(_acceptor);
501                     }
502                     catch (Throwable e)
503                     {
504                         if (isAccepting())
505                             LOG.warn(e);
506                         else
507                             LOG.ignore(e);
508                     }
509                 }
510             }
511             finally
512             {
513                 thread.setName(name);
514                 if (_acceptorPriorityDelta!=0)
515                     thread.setPriority(priority);
516
517                 synchronized (AbstractConnector.this)
518                 {
519                     _acceptors[_acceptor] = null;
520                 }
521                 CountDownLatch stopping=_stopping;
522                 if (stopping!=null)
523                     stopping.countDown();
524             }
525         }
526         
527         @Override
528         public String toString()
529         {
530             String name=_name;
531             if (name==null)
532                 return String.format("acceptor-%d@%x", _acceptor, hashCode());
533             return name;
534         }
535         
536     }
537
538
539
540
541 //    protected void connectionOpened(Connection connection)
542 //    {
543 //        _stats.connectionOpened();
544 //        connection.onOpen();
545 //    }
546 //
547 //    protected void connectionClosed(Connection connection)
548 //    {
549 //        connection.onClose();
550 //        long duration = System.currentTimeMillis() - connection.getEndPoint().getCreatedTimeStamp();
551 //        _stats.connectionClosed(duration, connection.getMessagesIn(), connection.getMessagesOut());
552 //    }
553 //
554 //    public void connectionUpgraded(Connection oldConnection, Connection newConnection)
555 //    {
556 //        oldConnection.onClose();
557 //        _stats.connectionUpgraded(oldConnection.getMessagesIn(), oldConnection.getMessagesOut());
558 //        newConnection.onOpen();
559 //    }
560
561     @Override
562     public Collection<EndPoint> getConnectedEndPoints()
563     {
564         return _immutableEndPoints;
565     }
566
567     protected void onEndPointOpened(EndPoint endp)
568     {
569         _endpoints.add(endp);
570     }
571
572     protected void onEndPointClosed(EndPoint endp)
573     {
574         _endpoints.remove(endp);
575     }
576
577     @Override
578     public Scheduler getScheduler()
579     {
580         return _scheduler;
581     }
582
583     @Override
584     public String getName()
585     {
586         return _name;
587     }
588     
589     /* ------------------------------------------------------------ */
590     /**
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.
595      */
596     public void setName(String name)
597     {
598         _name=name;
599     }
600     
601     @Override
602     public String toString()
603     {
604         return String.format("%s@%x{%s}",
605                 _name==null?getClass().getSimpleName():_name,
606                 hashCode(),
607                 getDefaultProtocol());
608     }
609 }