View Javadoc

1   // ========================================================================
2   // Copyright (c) 2003-2009 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at 
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses. 
12  // ========================================================================
13   
14  package org.eclipse.jetty.server.bio;
15  
16  import java.io.IOException;
17  import java.net.InetAddress;
18  import java.net.ServerSocket;
19  import java.net.Socket;
20  import java.util.HashSet;
21  import java.util.Iterator;
22  import java.util.Set;
23  
24  import org.eclipse.jetty.http.HttpException;
25  import org.eclipse.jetty.io.Buffer;
26  import org.eclipse.jetty.io.ByteArrayBuffer;
27  import org.eclipse.jetty.io.EndPoint;
28  import org.eclipse.jetty.io.EofException;
29  import org.eclipse.jetty.io.bio.SocketEndPoint;
30  import org.eclipse.jetty.server.AbstractConnector;
31  import org.eclipse.jetty.server.HttpConnection;
32  import org.eclipse.jetty.server.Request;
33  import org.eclipse.jetty.util.log.Log;
34  
35  
36  /* ------------------------------------------------------------------------------- */
37  /**  Socket Connector.
38   * This connector implements a traditional blocking IO and threading model.
39   * Normal JRE sockets are used and a thread is allocated per connection.
40   * Buffers are managed so that large buffers are only allocated to active connections.
41   * 
42   * This Connector should only be used if NIO is not available.
43   * 
44   * @org.apache.xbean.XBean element="bioConnector" description="Creates a BIO based socket connector"
45   * 
46   * 
47   */
48  public class SocketConnector extends AbstractConnector
49  {
50      protected ServerSocket _serverSocket;
51      protected final Set _connections;
52      
53      /* ------------------------------------------------------------ */
54      /** Constructor.
55       * 
56       */
57      public SocketConnector()
58      {
59          _connections=new HashSet();
60      }
61  
62      /* ------------------------------------------------------------ */
63      public Object getConnection()
64      {
65          return _serverSocket;
66      }
67      
68      /* ------------------------------------------------------------ */
69      public void open() throws IOException
70      {
71          // Create a new server socket and set to non blocking mode
72          if (_serverSocket==null || _serverSocket.isClosed())
73          _serverSocket= newServerSocket(getHost(),getPort(),getAcceptQueueSize());
74          _serverSocket.setReuseAddress(getReuseAddress());
75      }
76  
77      /* ------------------------------------------------------------ */
78      protected ServerSocket newServerSocket(String host, int port,int backlog) throws IOException
79      {
80          ServerSocket ss= host==null?
81              new ServerSocket(port,backlog):
82              new ServerSocket(port,backlog,InetAddress.getByName(host));
83         
84          return ss;
85      }
86      
87      /* ------------------------------------------------------------ */
88      public void close() throws IOException
89      {
90          if (_serverSocket!=null)
91              _serverSocket.close();
92          _serverSocket=null;
93      }
94  
95      /* ------------------------------------------------------------ */
96      public void accept(int acceptorID)
97      	throws IOException, InterruptedException
98      {   
99          Socket socket = _serverSocket.accept();
100         configure(socket);
101         
102         Connection connection=new Connection(socket);
103         connection.dispatch();
104     }
105 
106     /* ------------------------------------------------------------------------------- */
107     /**
108      * Allows subclass to override Conection if required.
109      */
110     protected HttpConnection newHttpConnection(EndPoint endpoint) 
111     {
112         return new HttpConnection(this, endpoint, getServer());
113     }
114 
115     /* ------------------------------------------------------------------------------- */
116     public void customize(EndPoint endpoint, Request request)
117         throws IOException
118     {
119         Connection connection = (Connection)endpoint;
120         int lrmit = isLowResources()?_lowResourceMaxIdleTime:_maxIdleTime;
121         if (connection._sotimeout!=lrmit)
122         {
123             connection._sotimeout=lrmit;
124             ((Socket)endpoint.getTransport()).setSoTimeout(lrmit);
125         }
126               
127         super.customize(endpoint, request);
128     }
129 
130     /* ------------------------------------------------------------------------------- */
131     public int getLocalPort()
132     {
133         if (_serverSocket==null || _serverSocket.isClosed())
134             return -1;
135         return _serverSocket.getLocalPort();
136     }
137 
138     /* ------------------------------------------------------------------------------- */
139     protected void doStart() throws Exception
140     {
141         _connections.clear();
142         super.doStart();
143     }
144 
145     /* ------------------------------------------------------------------------------- */
146     protected void doStop() throws Exception
147     {
148         super.doStop();
149         Set set=null;
150 
151         synchronized(_connections)
152         {
153             set= new HashSet(_connections);
154         }
155         
156         Iterator iter=set.iterator();
157         while(iter.hasNext())
158         {
159             Connection connection = (Connection)iter.next();
160             connection.close();
161         }
162     }
163 
164     /* ------------------------------------------------------------------------------- */
165     /* ------------------------------------------------------------------------------- */
166     /* ------------------------------------------------------------------------------- */
167     protected class Connection extends SocketEndPoint implements Runnable
168     {
169         boolean _dispatched=false;
170         HttpConnection _connection;
171         int _sotimeout;
172         protected Socket _socket;
173         
174         public Connection(Socket socket) throws IOException
175         {
176             super(socket);
177             _connection = newHttpConnection(this);
178             _sotimeout=socket.getSoTimeout();
179             _socket=socket;
180         }
181         
182         public void dispatch() throws IOException
183         {
184             if (getThreadPool()==null || !getThreadPool().dispatch(this))
185             {
186                 Log.warn("dispatch failed for {}",_connection);
187                 close();
188             }
189         }
190         
191         public int fill(Buffer buffer) throws IOException
192         {
193             int l = super.fill(buffer);
194             if (l<0)
195                 close();
196             return l;
197         } 
198         
199         public void close() throws IOException
200         {
201             _connection.getRequest().getAsyncContinuation().cancel();
202             super.close();
203         }
204 
205         public void run()
206         {
207             try
208             {
209                 connectionOpened(_connection);
210                 synchronized(_connections)
211                 {
212                     _connections.add(this);
213                 }
214                 
215                 while (isStarted() && !isClosed())
216                 {
217                     if (_connection.isIdle())
218                     {
219                         if (isLowResources())
220                         {
221                             int lrmit = getLowResourceMaxIdleTime();
222                             if (lrmit>=0 && _sotimeout!= lrmit)
223                             {
224                                 _sotimeout=lrmit;
225                                 _socket.setSoTimeout(_sotimeout);
226                             }
227                         }
228                     }                    
229                     _connection.handle();
230                 }
231             }
232             catch (EofException e)
233             {
234                 Log.debug("EOF", e);
235                 try{close();}
236                 catch(IOException e2){Log.ignore(e2);}
237             }
238             catch (HttpException e)
239             {
240                 Log.debug("BAD", e);
241                 try{close();}
242                 catch(IOException e2){Log.ignore(e2);}
243             }
244             catch(Exception e)
245             {
246                 Log.warn("handle failed?",e);
247                 try{close();}
248                 catch(IOException e2){Log.ignore(e2);}
249             }
250             finally
251             { 
252                 connectionClosed(_connection);
253                 synchronized(_connections)
254                 {
255                     _connections.remove(this);
256                 }
257             }
258         }
259     }
260 }