View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2012 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.SelectChannelEndPoint;
38  import org.eclipse.jetty.io.SelectorManager;
39  import org.eclipse.jetty.io.SelectorManager.ManagedSelector;
40  import org.eclipse.jetty.util.Callback;
41  import org.eclipse.jetty.util.annotation.ManagedObject;
42  import org.eclipse.jetty.util.annotation.Name;
43  import org.eclipse.jetty.util.ssl.SslContextFactory;
44  import org.eclipse.jetty.util.thread.Scheduler;
45  
46  /**
47   * This {@link Connector} implementation is the primary connector for the
48   * Jetty server over TCP/IP.  By the use of various {@link ConnectionFactory} instances it is able
49   * to accept connections for HTTP, SPDY and WebSocket, either directly or over SSL.
50   * <p>
51   * The connector is a fully asynchronous NIO based implementation that by default will
52   * use all the commons services (eg {@link Executor}, {@link Scheduler})  of the
53   * passed {@link Server} instance, but all services may also be constructor injected
54   * into the connector so that it may operate with dedicated or otherwise shared services.
55   * <p>
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   * <p>
64   * <h2>Selectors</h2>
65   * The connector will use the {@link Executor} service to execute a number of Selector Tasks,
66   * which are implemented to each use a NIO {@link Selector} instance to asynchronously
67   * schedule a set of accepted connections.  It is the selector thread that will call the
68   * {@link Callback} instances passed in the {@link EndPoint#fillInterested(Object, Callback)} or
69   * {@link EndPoint#write(Object, Callback, java.nio.ByteBuffer...)} methods.  It is expected
70   * that these callbacks may do some non-blocking IO work, but will always dispatch to the
71   * {@link Executor} service any blocking, long running or application tasks.
72   * <p>
73   * The default number of selectors is equal to the number of processors available to the JVM,
74   * which should allow optimal performance even if all the connections used are performing
75   * significant non-blocking work in the callback tasks.
76   *
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 = 128;
86      private volatile boolean _reuseAddress = true;
87      private volatile int _lingerTime = -1;
88  
89  
90      public ServerConnector(
91          @Name("server") Server server)
92      {
93          this(server,null,null,null,0,0,new HttpConnectionFactory());
94      }
95  
96      public ServerConnector(
97          @Name("server") Server server,
98          @Name("factories") ConnectionFactory... factories)
99      {
100         this(server,null,null,null,0,0,factories);
101     }
102 
103     public ServerConnector(
104         @Name("server") Server server,
105         @Name("sslContextFactory") SslContextFactory sslContextFactory)
106     {
107         this(server,null,null,null,0,0,AbstractConnectionFactory.getFactories(sslContextFactory,new HttpConnectionFactory()));
108     }
109 
110     public ServerConnector(
111         @Name("server") Server server,
112         @Name("sslContextFactory") SslContextFactory sslContextFactory,
113         @Name("factories") ConnectionFactory... factories)
114     {
115         this(server,null,null,null,0,0,AbstractConnectionFactory.getFactories(sslContextFactory,factories));
116     }
117 
118     /**
119      * @param server    The server this connector will be added to. Must not be null.
120      * @param executor  An executor for this connector or null to use the servers executor
121      * @param scheduler A scheduler for this connector or null to use the servers scheduler
122      * @param pool      A buffer pool for this connector or null to use a default {@link ByteBufferPool}
123      * @param acceptors the number of acceptor threads to use, or 0 for a default value.
124      * @param factories Zero or more {@link ConnectionFactory} instances.
125      */
126     public ServerConnector(
127         @Name("server") Server server,
128         @Name("executor") Executor executor,
129         @Name("scheduler") Scheduler scheduler,
130         @Name("bufferPool") ByteBufferPool pool,
131         @Name("acceptors") int acceptors,
132         @Name("selectors") int selectors,
133         @Name("factories") ConnectionFactory... factories)
134     {
135         super(server,executor,scheduler,pool,acceptors,factories);
136         _manager = new ServerConnectorManager(getExecutor(), getScheduler(), selectors > 0 ? selectors : Runtime.getRuntime().availableProcessors());
137         addBean(_manager, true);
138     }
139 
140     @Override
141     public boolean isOpen()
142     {
143         ServerSocketChannel channel = _acceptChannel;
144         return channel!=null && channel.isOpen();
145     }
146 
147     /**
148      * @return whether this connector uses a channel inherited from the JVM.
149      * @see System#inheritedChannel()
150      */
151     public boolean isInheritChannel()
152     {
153         return _inheritChannel;
154     }
155 
156     /**
157      * <p>Sets whether this connector uses a channel inherited from the JVM.</p>
158      * <p>If true, the connector first tries to inherit from a channel provided by the system.
159      * If there is no inherited channel available, or if the inherited channel is not usable,
160      * then it will fall back using {@link ServerSocketChannel}.</p>
161      * <p>Use it with xinetd/inetd, to launch an instance of Jetty on demand. The port
162      * used to access pages on the Jetty instance is the same as the port used to
163      * launch Jetty.</p>
164      *
165      * @param inheritChannel whether this connector uses a channel inherited from the JVM.
166      */
167     public void setInheritChannel(boolean inheritChannel)
168     {
169         _inheritChannel = inheritChannel;
170     }
171 
172     @Override
173     public void open() throws IOException
174     {
175         if (_acceptChannel == null)
176         {
177             ServerSocketChannel serverChannel = null;
178             if (isInheritChannel())
179             {
180                 Channel channel = System.inheritedChannel();
181                 if (channel instanceof ServerSocketChannel)
182                     serverChannel = (ServerSocketChannel)channel;
183                 else
184                     LOG.warn("Unable to use System.inheritedChannel() [{}]. Trying a new ServerSocketChannel at {}:{}", channel, getHost(), getPort());
185             }
186 
187             if (serverChannel == null)
188             {
189                 serverChannel = ServerSocketChannel.open();
190 
191                 InetSocketAddress bindAddress = getHost() == null ? new InetSocketAddress(getPort()) : new InetSocketAddress(getHost(), getPort());
192                 serverChannel.socket().bind(bindAddress, getAcceptQueueSize());
193                 serverChannel.socket().setReuseAddress(getReuseAddress());
194 
195                 _localPort = serverChannel.socket().getLocalPort();
196                 if (_localPort <= 0)
197                     throw new IOException("Server channel not bound");
198 
199                 addBean(serverChannel);
200             }
201 
202             serverChannel.configureBlocking(true);
203             addBean(serverChannel);
204 
205             _acceptChannel = serverChannel;
206         }
207     }
208 
209     @Override
210     public <C> Future<C> shutdown(C c)
211     {
212         // TODO shutdown all the connections
213         return super.shutdown(c);
214     }
215 
216     @Override
217     public void close()
218     {
219         ServerSocketChannel serverChannel = _acceptChannel;
220         _acceptChannel = null;
221 
222         if (serverChannel != null)
223         {
224             removeBean(serverChannel);
225 
226             // If the interrupt did not close it, we should close it
227             if (serverChannel.isOpen())
228             {
229                 try
230                 {
231                     serverChannel.close();
232                 }
233                 catch (IOException e)
234                 {
235                     LOG.warn(e);
236                 }
237             }
238         }
239         // super.close();
240         _localPort = -2;
241     }
242 
243     @Override
244     public void accept(int acceptorID) throws IOException
245     {
246         ServerSocketChannel serverChannel = _acceptChannel;
247         if (serverChannel != null && serverChannel.isOpen())
248         {
249             SocketChannel channel = serverChannel.accept();
250             channel.configureBlocking(false);
251             Socket socket = channel.socket();
252             configure(socket);
253             _manager.accept(channel);
254         }
255     }
256 
257     protected void configure(Socket socket)
258     {
259         try
260         {
261             socket.setTcpNoDelay(true);
262             if (_lingerTime >= 0)
263                 socket.setSoLinger(true, _lingerTime / 1000);
264             else
265                 socket.setSoLinger(false, 0);
266         }
267         catch (SocketException e)
268         {
269             LOG.ignore(e);
270         }
271     }
272 
273     public SelectorManager getSelectorManager()
274     {
275         return _manager;
276     }
277 
278     @Override
279     public Object getTransport()
280     {
281         return _acceptChannel;
282     }
283 
284     @Override
285     public int getLocalPort()
286     {
287         return _localPort;
288     }
289 
290     protected SelectChannelEndPoint newEndPoint(SocketChannel channel, ManagedSelector selectSet, SelectionKey key) throws IOException
291     {
292         return new SelectChannelEndPoint(channel, selectSet, key, getScheduler(), getIdleTimeout());
293     }
294 
295     /**
296      * @return the linger time
297      * @see Socket#getSoLinger()
298      */
299     public int getLingerTime()
300     {
301         return _lingerTime;
302     }
303 
304     /**
305      * @param lingerTime the linger time. Use -1 to disable.
306      * @see Socket#setSoLinger(boolean, int)
307      */
308     public void setSoLingerTime(int lingerTime)
309     {
310         _lingerTime = lingerTime;
311     }
312 
313     /**
314      * @return the accept queue size
315      */
316     public int getAcceptQueueSize()
317     {
318         return _acceptQueueSize;
319     }
320 
321     /**
322      * @param acceptQueueSize the accept queue size (also known as accept backlog)
323      */
324     public void setAcceptQueueSize(int acceptQueueSize)
325     {
326         _acceptQueueSize = acceptQueueSize;
327     }
328 
329     /**
330      * @return whether the server socket reuses addresses
331      * @see ServerSocket#getReuseAddress()
332      */
333     public boolean getReuseAddress()
334     {
335         return _reuseAddress;
336     }
337 
338     /**
339      * @param reuseAddress whether the server socket reuses addresses
340      * @see ServerSocket#setReuseAddress(boolean)
341      */
342     public void setReuseAddress(boolean reuseAddress)
343     {
344         _reuseAddress = reuseAddress;
345     }
346 
347     private final class ServerConnectorManager extends SelectorManager
348     {
349         private ServerConnectorManager(Executor executor, Scheduler scheduler, int selectors)
350         {
351             super(executor, scheduler, selectors);
352         }
353 
354         @Override
355         protected SelectChannelEndPoint newEndPoint(SocketChannel channel, ManagedSelector selectSet, SelectionKey selectionKey) throws IOException
356         {
357             return ServerConnector.this.newEndPoint(channel, selectSet, selectionKey);
358         }
359 
360         @Override
361         public Connection newConnection(SocketChannel channel, EndPoint endpoint, Object attachment) throws IOException
362         {
363             return getDefaultConnectionFactory().newConnection(ServerConnector.this, endpoint);
364         }
365     }
366 }