View Javadoc
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.net.InetSocketAddress;
23  import java.net.ServerSocket;
24  import java.net.Socket;
25  import java.net.SocketException;
26  import java.nio.channels.Channel;
27  import java.nio.channels.SelectableChannel;
28  import java.nio.channels.SelectionKey;
29  import java.nio.channels.Selector;
30  import java.nio.channels.ServerSocketChannel;
31  import java.nio.channels.SocketChannel;
32  import java.util.concurrent.Executor;
33  import java.util.concurrent.Future;
34  
35  import org.eclipse.jetty.io.ByteBufferPool;
36  import org.eclipse.jetty.io.ChannelEndPoint;
37  import org.eclipse.jetty.io.Connection;
38  import org.eclipse.jetty.io.EndPoint;
39  import org.eclipse.jetty.io.ManagedSelector;
40  import org.eclipse.jetty.io.SelectorManager;
41  import org.eclipse.jetty.io.SocketChannelEndPoint;
42  import org.eclipse.jetty.util.Callback;
43  import org.eclipse.jetty.util.annotation.ManagedAttribute;
44  import org.eclipse.jetty.util.annotation.ManagedObject;
45  import org.eclipse.jetty.util.annotation.Name;
46  import org.eclipse.jetty.util.ssl.SslContextFactory;
47  import org.eclipse.jetty.util.thread.Scheduler;
48  
49  /**
50   * This {@link Connector} implementation is the primary connector for the
51   * Jetty server over TCP/IP.  By the use of various {@link ConnectionFactory} instances it is able
52   * to accept connections for HTTP, HTTP/2 and WebSocket, either directly or over SSL.
53   * <p>
54   * The connector is a fully asynchronous NIO based implementation that by default will
55   * use all the commons services (eg {@link Executor}, {@link Scheduler})  of the
56   * passed {@link Server} instance, but all services may also be constructor injected
57   * into the connector so that it may operate with dedicated or otherwise shared services.
58   * <h2>Connection Factories</h2>
59   * Various convenience constructors are provided to assist with common configurations of
60   * ConnectionFactories, whose generic use is described in {@link AbstractConnector}.
61   * If no connection factories are passed, then the connector will
62   * default to use a {@link HttpConnectionFactory}.  If an non null {@link SslContextFactory}
63   * instance is passed, then this used to instantiate a {@link SslConnectionFactory} which is
64   * prepended to the other passed or default factories.
65   * <h2>Selectors</h2>
66   * The connector will use the {@link Executor} service to execute a number of Selector Tasks,
67   * which are implemented to each use a NIO {@link Selector} instance to asynchronously
68   * schedule a set of accepted connections.  It is the selector thread that will call the
69   * {@link Callback} instances passed in the {@link EndPoint#fillInterested(Callback)} or
70   * {@link EndPoint#write(Callback, java.nio.ByteBuffer...)} methods.  It is expected
71   * that these callbacks may do some non-blocking IO work, but will always dispatch to the
72   * {@link Executor} service any blocking, long running or application tasks.
73   * <p>
74   * The default number of selectors is equal to the number of processors available to the JVM,
75   * which should allow optimal performance even if all the connections used are performing
76   * significant non-blocking work in the callback tasks.
77   */
78  @ManagedObject("HTTP connector using NIO ByteChannels and Selectors")
79  public class ServerConnector extends AbstractNetworkConnector
80  {
81      private final SelectorManager _manager;
82      private volatile ServerSocketChannel _acceptChannel;
83      private volatile boolean _inheritChannel = false;
84      private volatile int _localPort = -1;
85      private volatile int _acceptQueueSize = 0;
86      private volatile boolean _reuseAddress = true;
87      private volatile int _lingerTime = -1;
88  
89      /**
90       * <p>Construct a ServerConnector with a private instance of {@link HttpConnectionFactory} as the only factory.</p>
91       * @param server The {@link Server} this connector will accept connection for.
92       */
93      public ServerConnector(
94          @Name("server") Server server)
95      {
96          this(server,null,null,null,-1,-1,new HttpConnectionFactory());
97      }
98  
99      /**
100      * <p>Construct a ServerConnector with a private instance of {@link HttpConnectionFactory} as the only factory.</p>
101      * @param server The {@link Server} this connector will accept connection for.
102      * @param acceptors
103      *          the number of acceptor threads to use, or -1 for a default value. Acceptors accept new TCP/IP connections.  If 0, then
104      *          the selector threads are used to accept connections.
105      * @param selectors
106      *          the number of selector threads, or &lt;=0 for a default value. Selectors notice and schedule established connection that can make IO progress.
107      */
108     public ServerConnector(
109         @Name("server") Server server,
110         @Name("acceptors") int acceptors,
111         @Name("selectors") int selectors)
112     {
113         this(server,null,null,null,acceptors,selectors,new HttpConnectionFactory());
114     }
115 
116     /**
117      * <p>Construct a ServerConnector with a private instance of {@link HttpConnectionFactory} as the only factory.</p>
118      * @param server The {@link Server} this connector will accept connection for.
119      * @param acceptors
120      *          the number of acceptor threads to use, or -1 for a default value. Acceptors accept new TCP/IP connections.  If 0, then
121      *          the selector threads are used to accept connections.
122      * @param selectors
123      *          the number of selector threads, or &lt;=0 for a default value. Selectors notice and schedule established connection that can make IO progress.
124      * @param factories Zero or more {@link ConnectionFactory} instances used to create and configure connections.
125      */
126     public ServerConnector(
127         @Name("server") Server server,
128         @Name("acceptors") int acceptors,
129         @Name("selectors") int selectors,
130         @Name("factories") ConnectionFactory... factories)
131     {
132         this(server,null,null,null,acceptors,selectors,factories);
133     }
134 
135     /**
136      * <p>Construct a Server Connector with the passed Connection factories.</p>
137      * @param server The {@link Server} this connector will accept connection for.
138      * @param factories Zero or more {@link ConnectionFactory} instances used to create and configure connections.
139      */
140     public ServerConnector(
141         @Name("server") Server server,
142         @Name("factories") ConnectionFactory... factories)
143     {
144         this(server,null,null,null,-1,-1,factories);
145     }
146 
147     /**
148      * <p>Construct a ServerConnector with a private instance of {@link HttpConnectionFactory} as the primary protocol</p>.
149      * @param server The {@link Server} this connector will accept connection for.
150      * @param sslContextFactory If non null, then a {@link SslConnectionFactory} is instantiated and prepended to the
151      * list of HTTP Connection Factory.
152      */
153     public ServerConnector(
154         @Name("server") Server server,
155         @Name("sslContextFactory") SslContextFactory sslContextFactory)
156     {
157         this(server,null,null,null,-1,-1,AbstractConnectionFactory.getFactories(sslContextFactory,new HttpConnectionFactory()));
158     }
159 
160     /**
161      * <p>Construct a ServerConnector with a private instance of {@link HttpConnectionFactory} as the primary protocol</p>.
162      * @param server The {@link Server} this connector will accept connection for.
163      * @param sslContextFactory If non null, then a {@link SslConnectionFactory} is instantiated and prepended to the
164      * list of HTTP Connection Factory.
165      * @param acceptors
166      *          the number of acceptor threads to use, or -1 for a default value. Acceptors accept new TCP/IP connections.  If 0, then
167      *          the selector threads are used to accept connections.
168      * @param selectors
169      *          the number of selector threads, or &lt;=0 for a default value. Selectors notice and schedule established connection that can make IO progress.
170      */
171     public ServerConnector(
172         @Name("server") Server server,
173         @Name("acceptors") int acceptors,
174         @Name("selectors") int selectors,
175         @Name("sslContextFactory") SslContextFactory sslContextFactory)
176     {
177         this(server,null,null,null,acceptors,selectors,AbstractConnectionFactory.getFactories(sslContextFactory,new HttpConnectionFactory()));
178     }
179 
180     /**
181      * @param server The {@link Server} this connector will accept connection for.
182      * @param sslContextFactory If non null, then a {@link SslConnectionFactory} is instantiated and prepended to the
183      * list of ConnectionFactories, with the first factory being the default protocol for the SslConnectionFactory.
184      * @param factories Zero or more {@link ConnectionFactory} instances used to create and configure connections.
185      */
186     public ServerConnector(
187         @Name("server") Server server,
188         @Name("sslContextFactory") SslContextFactory sslContextFactory,
189         @Name("factories") ConnectionFactory... factories)
190     {
191         this(server, null, null, null, -1, -1, AbstractConnectionFactory.getFactories(sslContextFactory, factories));
192     }
193 
194     /**
195      * @param server
196      *          The server this connector will be accept connection for.
197      * @param executor
198      *          An executor used to run tasks for handling requests, acceptors and selectors.
199      *          If null then use the servers executor
200      * @param scheduler
201      *          A scheduler used to schedule timeouts. If null then use the servers scheduler
202      * @param bufferPool
203      *          A ByteBuffer pool used to allocate buffers.  If null then create a private pool with default configuration.
204      * @param acceptors
205      *          the number of acceptor threads to use, or -1 for a default value. Acceptors accept new TCP/IP connections.  If 0, then
206      *          the selector threads are used to accept connections.
207      * @param selectors
208      *          the number of selector threads, or &lt;=0 for a default value. Selectors notice and schedule established connection that can make IO progress.
209      * @param factories
210      *          Zero or more {@link ConnectionFactory} instances used to create and configure connections.
211      */
212     public ServerConnector(
213         @Name("server") Server server,
214         @Name("executor") Executor executor,
215         @Name("scheduler") Scheduler scheduler,
216         @Name("bufferPool") ByteBufferPool bufferPool,
217         @Name("acceptors") int acceptors,
218         @Name("selectors") int selectors,
219         @Name("factories") ConnectionFactory... factories)
220     {
221         super(server,executor,scheduler,bufferPool,acceptors,factories);
222         _manager = newSelectorManager(getExecutor(), getScheduler(),
223             selectors>0?selectors:Math.max(1,Math.min(4,Runtime.getRuntime().availableProcessors()/2)));
224         addBean(_manager, true);
225         setAcceptorPriorityDelta(-2);
226     }
227 
228     protected SelectorManager newSelectorManager(Executor executor, Scheduler scheduler, int selectors)
229     {
230         return new ServerConnectorManager(executor, scheduler, selectors);
231     }
232 
233     @Override
234     protected void doStart() throws Exception
235     {
236         super.doStart();
237 
238         if (getAcceptors()==0)
239         {
240             _acceptChannel.configureBlocking(false);
241             _manager.acceptor(_acceptChannel);
242         }
243     }
244 
245     @Override
246     public boolean isOpen()
247     {
248         ServerSocketChannel channel = _acceptChannel;
249         return channel!=null && channel.isOpen();
250     }
251 
252     /**
253      * @return whether this connector uses a channel inherited from the JVM.
254      * @see System#inheritedChannel()
255      */
256     public boolean isInheritChannel()
257     {
258         return _inheritChannel;
259     }
260 
261     /**
262      * <p>Sets whether this connector uses a channel inherited from the JVM.</p>
263      * <p>If true, the connector first tries to inherit from a channel provided by the system.
264      * If there is no inherited channel available, or if the inherited channel is not usable,
265      * then it will fall back using {@link ServerSocketChannel}.</p>
266      * <p>Use it with xinetd/inetd, to launch an instance of Jetty on demand. The port
267      * used to access pages on the Jetty instance is the same as the port used to
268      * launch Jetty.</p>
269      *
270      * @param inheritChannel whether this connector uses a channel inherited from the JVM.
271      */
272     public void setInheritChannel(boolean inheritChannel)
273     {
274         _inheritChannel = inheritChannel;
275     }
276 
277     @Override
278     public void open() throws IOException
279     {
280         if (_acceptChannel == null)
281         {
282             ServerSocketChannel serverChannel = null;
283             if (isInheritChannel())
284             {
285                 Channel channel = System.inheritedChannel();
286                 if (channel instanceof ServerSocketChannel)
287                     serverChannel = (ServerSocketChannel)channel;
288                 else
289                     LOG.warn("Unable to use System.inheritedChannel() [{}]. Trying a new ServerSocketChannel at {}:{}", channel, getHost(), getPort());
290             }
291 
292             if (serverChannel == null)
293             {
294                 serverChannel = ServerSocketChannel.open();
295 
296                 InetSocketAddress bindAddress = getHost() == null ? new InetSocketAddress(getPort()) : new InetSocketAddress(getHost(), getPort());
297                 serverChannel.socket().setReuseAddress(getReuseAddress());
298                 serverChannel.socket().bind(bindAddress, getAcceptQueueSize());
299 
300                 _localPort = serverChannel.socket().getLocalPort();
301                 if (_localPort <= 0)
302                     throw new IOException("Server channel not bound");
303 
304                 addBean(serverChannel);
305             }
306 
307             serverChannel.configureBlocking(true);
308             addBean(serverChannel);
309 
310             _acceptChannel = serverChannel;
311         }
312     }
313 
314     @Override
315     public Future<Void> shutdown()
316     {
317         // shutdown all the connections
318         return super.shutdown();
319     }
320 
321     @Override
322     public void close()
323     {
324         ServerSocketChannel serverChannel = _acceptChannel;
325         _acceptChannel = null;
326 
327         if (serverChannel != null)
328         {
329             removeBean(serverChannel);
330 
331             // If the interrupt did not close it, we should close it
332             if (serverChannel.isOpen())
333             {
334                 try
335                 {
336                     serverChannel.close();
337                 }
338                 catch (IOException e)
339                 {
340                     LOG.warn(e);
341                 }
342             }
343         }
344         // super.close();
345         _localPort = -2;
346     }
347 
348     @Override
349     public void accept(int acceptorID) throws IOException
350     {
351         ServerSocketChannel serverChannel = _acceptChannel;
352         if (serverChannel != null && serverChannel.isOpen())
353         {
354             SocketChannel channel = serverChannel.accept();
355             accepted(channel);
356         }
357     }
358 
359     private void accepted(SocketChannel channel) throws IOException
360     {
361         channel.configureBlocking(false);
362         Socket socket = channel.socket();
363         configure(socket);
364         _manager.accept(channel);
365     }
366 
367     protected void configure(Socket socket)
368     {
369         try
370         {
371             socket.setTcpNoDelay(true);
372             if (_lingerTime >= 0)
373                 socket.setSoLinger(true, _lingerTime / 1000);
374             else
375                 socket.setSoLinger(false, 0);
376         }
377         catch (SocketException e)
378         {
379             LOG.ignore(e);
380         }
381     }
382 
383     public SelectorManager getSelectorManager()
384     {
385         return _manager;
386     }
387 
388     @Override
389     public Object getTransport()
390     {
391         return _acceptChannel;
392     }
393 
394     @Override
395     @ManagedAttribute("local port")
396     public int getLocalPort()
397     {
398         return _localPort;
399     }
400 
401     protected ChannelEndPoint newEndPoint(SocketChannel channel, ManagedSelector selectSet, SelectionKey key) throws IOException
402     {
403         SocketChannelEndPoint endpoint = new SocketChannelEndPoint(channel, selectSet, key, getScheduler());
404         endpoint.setIdleTimeout(getIdleTimeout());
405         return endpoint;
406     }
407 
408     /**
409      * @return the linger time
410      * @see Socket#getSoLinger()
411      */
412     @ManagedAttribute("TCP/IP solinger time or -1 to disable")
413     public int getSoLingerTime()
414     {
415         return _lingerTime;
416     }
417 
418     /**
419      * @param lingerTime the linger time. Use -1 to disable.
420      * @see Socket#setSoLinger(boolean, int)
421      */
422     public void setSoLingerTime(int lingerTime)
423     {
424         _lingerTime = lingerTime;
425     }
426 
427     /**
428      * @return the accept queue size
429      */
430     @ManagedAttribute("Accept Queue size")
431     public int getAcceptQueueSize()
432     {
433         return _acceptQueueSize;
434     }
435 
436     /**
437      * @param acceptQueueSize the accept queue size (also known as accept backlog)
438      */
439     public void setAcceptQueueSize(int acceptQueueSize)
440     {
441         _acceptQueueSize = acceptQueueSize;
442     }
443 
444     /**
445      * @return whether the server socket reuses addresses
446      * @see ServerSocket#getReuseAddress()
447      */
448     public boolean getReuseAddress()
449     {
450         return _reuseAddress;
451     }
452 
453     /**
454      * @param reuseAddress whether the server socket reuses addresses
455      * @see ServerSocket#setReuseAddress(boolean)
456      */
457     public void setReuseAddress(boolean reuseAddress)
458     {
459         _reuseAddress = reuseAddress;
460     }
461 
462     protected class ServerConnectorManager extends SelectorManager
463     {
464         public ServerConnectorManager(Executor executor, Scheduler scheduler, int selectors)
465         {
466             super(executor, scheduler, selectors);
467         }
468 
469         @Override
470         protected void accepted(SelectableChannel channel) throws IOException
471         {
472             ServerConnector.this.accepted((SocketChannel)channel);
473         }
474 
475         @Override
476         protected ChannelEndPoint newEndPoint(SelectableChannel channel, ManagedSelector selectSet, SelectionKey selectionKey) throws IOException
477         {
478             return ServerConnector.this.newEndPoint((SocketChannel)channel, selectSet, selectionKey);
479         }
480 
481         @Override
482         public Connection newConnection(SelectableChannel channel, EndPoint endpoint, Object attachment) throws IOException
483         {
484             return getDefaultConnectionFactory().newConnection(ServerConnector.this, endpoint);
485         }
486 
487         @Override
488         protected void endPointOpened(EndPoint endpoint)
489         {
490             super.endPointOpened(endpoint);
491             onEndPointOpened(endpoint);
492         }
493 
494         @Override
495         protected void endPointClosed(EndPoint endpoint)
496         {
497             onEndPointClosed(endpoint);
498             super.endPointClosed(endpoint);
499         }
500     }
501 }