View Javadoc

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