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.io.Buffer;
25  import org.eclipse.jetty.io.ByteArrayBuffer;
26  import org.eclipse.jetty.io.EndPoint;
27  import org.eclipse.jetty.io.EofException;
28  import org.eclipse.jetty.io.HttpException;
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 Set _connections;
52      
53      /* ------------------------------------------------------------ */
54      /** Constructor.
55       * 
56       */
57      public SocketConnector()
58      {
59      }
60  
61      /* ------------------------------------------------------------ */
62      public Object getConnection()
63      {
64          return _serverSocket;
65      }
66      
67      /* ------------------------------------------------------------ */
68      public void open() throws IOException
69      {
70          // Create a new server socket and set to non blocking mode
71          if (_serverSocket==null || _serverSocket.isClosed())
72          _serverSocket= newServerSocket(getHost(),getPort(),getAcceptQueueSize());
73          _serverSocket.setReuseAddress(getReuseAddress());
74      }
75  
76      /* ------------------------------------------------------------ */
77      protected ServerSocket newServerSocket(String host, int port,int backlog) throws IOException
78      {
79          ServerSocket ss= host==null?
80              new ServerSocket(port,backlog):
81              new ServerSocket(port,backlog,InetAddress.getByName(host));
82         
83          return ss;
84      }
85      
86      /* ------------------------------------------------------------ */
87      public void close() throws IOException
88      {
89          if (_serverSocket!=null)
90              _serverSocket.close();
91          _serverSocket=null;
92      }
93  
94      /* ------------------------------------------------------------ */
95      public void accept(int acceptorID)
96      	throws IOException, InterruptedException
97      {   
98          Socket socket = _serverSocket.accept();
99          configure(socket);
100         
101         Connection connection=new Connection(socket);
102         connection.dispatch();
103     }
104 
105     /* ------------------------------------------------------------------------------- */
106     /**
107      * Allows subclass to override Conection if required.
108      */
109     protected HttpConnection newHttpConnection(EndPoint endpoint) 
110     {
111         return new HttpConnection(this, endpoint, getServer());
112     }
113 
114     /* ------------------------------------------------------------------------------- */
115     public Buffer newBuffer(int size)
116     {
117         return new ByteArrayBuffer(size);
118     }
119 
120     /* ------------------------------------------------------------------------------- */
121     public void customize(EndPoint endpoint, Request request)
122         throws IOException
123     {
124         Connection connection = (Connection)endpoint;
125         int lrmit = isLowResources()?_lowResourceMaxIdleTime:_maxIdleTime;
126         if (connection._sotimeout!=lrmit)
127         {
128             connection._sotimeout=lrmit;
129             ((Socket)endpoint.getTransport()).setSoTimeout(lrmit);
130         }
131               
132         super.customize(endpoint, request);
133     }
134 
135     /* ------------------------------------------------------------------------------- */
136     public int getLocalPort()
137     {
138         if (_serverSocket==null || _serverSocket.isClosed())
139             return -1;
140         return _serverSocket.getLocalPort();
141     }
142 
143     /* ------------------------------------------------------------------------------- */
144     protected void doStart() throws Exception
145     {
146         _connections=new HashSet();
147         super.doStart();
148     }
149 
150     /* ------------------------------------------------------------------------------- */
151     protected void doStop() throws Exception
152     {
153         super.doStop();
154         Set set=null;
155 
156         synchronized(_connections)
157         {
158             set= new HashSet(_connections);
159         }
160         
161         Iterator iter=set.iterator();
162         while(iter.hasNext())
163         {
164             Connection connection = (Connection)iter.next();
165             connection.close();
166         }
167     }
168 
169     /* ------------------------------------------------------------------------------- */
170     /* ------------------------------------------------------------------------------- */
171     /* ------------------------------------------------------------------------------- */
172     protected class Connection extends SocketEndPoint implements Runnable
173     {
174         boolean _dispatched=false;
175         HttpConnection _connection;
176         int _sotimeout;
177         protected Socket _socket;
178         
179         public Connection(Socket socket) throws IOException
180         {
181             super(socket);
182             _connection = newHttpConnection(this);
183             _sotimeout=socket.getSoTimeout();
184             _socket=socket;
185         }
186         
187         public void dispatch() throws InterruptedException, IOException
188         {
189             if (getThreadPool()==null || !getThreadPool().dispatch(this))
190             {
191                 Log.warn("dispatch failed for {}",_connection);
192                 close();
193             }
194         }
195         
196         public int fill(Buffer buffer) throws IOException
197         {
198             int l = super.fill(buffer);
199             if (l<0)
200                 close();
201             return l;
202         } 
203         
204         public void close() throws IOException
205         {
206             _connection.getRequest().getAsyncRequest().cancel();
207             super.close();
208         }
209 
210         public void run()
211         {
212             try
213             {
214                 connectionOpened(_connection);
215                 synchronized(_connections)
216                 {
217                     _connections.add(this);
218                 }
219                 
220                 while (isStarted() && !isClosed())
221                 {
222                     if (_connection.isIdle())
223                     {
224                         if (isLowResources())
225                         {
226                             int lrmit = getLowResourceMaxIdleTime();
227                             if (lrmit>=0 && _sotimeout!= lrmit)
228                             {
229                                 _sotimeout=lrmit;
230                                 _socket.setSoTimeout(_sotimeout);
231                             }
232                         }
233                     }                    
234                     _connection.handle();
235                 }
236             }
237             catch (EofException e)
238             {
239                 Log.debug("EOF", e);
240                 try{close();}
241                 catch(IOException e2){Log.ignore(e2);}
242             }
243             catch (HttpException e)
244             {
245                 Log.debug("BAD", e);
246                 try{close();}
247                 catch(IOException e2){Log.ignore(e2);}
248             }
249             catch(Exception e)
250             {
251                 Log.warn("handle failed?",e);
252                 try{close();}
253                 catch(IOException e2){Log.ignore(e2);}
254             }
255             finally
256             { 
257                 connectionClosed(_connection);
258                 synchronized(_connections)
259                 {
260                     _connections.remove(this);
261                 }
262             }
263         }
264     }
265 }