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