View Javadoc

1   // ========================================================================
2   // Copyright 2003-2005 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // Licensed under the Apache License, Version 2.0 (the "License");
5   // you may not use this file except in compliance with the License.
6   // You may obtain a copy of the License at 
7   // http://www.apache.org/licenses/LICENSE-2.0
8   // Unless required by applicable law or agreed to in writing, software
9   // distributed under the License is distributed on an "AS IS" BASIS,
10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  // See the License for the specific language governing permissions and
12  // limitations under the License.
13  // ========================================================================
14   
15  package org.mortbay.jetty.bio;
16  
17  import java.io.IOException;
18  import java.net.InetAddress;
19  import java.net.ServerSocket;
20  import java.net.Socket;
21  import java.util.HashSet;
22  import java.util.Iterator;
23  import java.util.Set;
24  
25  import org.mortbay.io.Buffer;
26  import org.mortbay.io.ByteArrayBuffer;
27  import org.mortbay.io.EndPoint;
28  import org.mortbay.io.bio.SocketEndPoint;
29  import org.mortbay.jetty.AbstractConnector;
30  import org.mortbay.jetty.EofException;
31  import org.mortbay.jetty.HttpConnection;
32  import org.mortbay.jetty.HttpException;
33  import org.mortbay.jetty.Request;
34  import org.mortbay.log.Log;
35  
36  
37  /* ------------------------------------------------------------------------------- */
38  /**  Socket Connector.
39   * This connector implements a traditional blocking IO and threading model.
40   * Normal JRE sockets are used and a thread is allocated per connection.
41   * Buffers are managed so that large buffers are only allocated to active connections.
42   * 
43   * This Connector should only be used if NIO is not available.
44   * 
45   * @org.apache.xbean.XBean element="bioConnector" description="Creates a BIO based socket connector"
46   * 
47   * @author gregw
48   */
49  public class SocketConnector extends AbstractConnector
50  {
51      protected ServerSocket _serverSocket;
52      protected Set _connections;
53      
54      /* ------------------------------------------------------------ */
55      /** Constructor.
56       * 
57       */
58      public SocketConnector()
59      {
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     protected Buffer newBuffer(int size)
117     {
118         return new ByteArrayBuffer(size);
119     }
120 
121     /* ------------------------------------------------------------------------------- */
122     public void customize(EndPoint endpoint, Request request)
123         throws IOException
124     {
125         Connection connection = (Connection)endpoint;
126         if (connection._sotimeout!=_maxIdleTime)
127         {
128             connection._sotimeout=_maxIdleTime;
129             ((Socket)endpoint.getTransport()).setSoTimeout(_maxIdleTime);
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 run()
205         {
206             try
207             {
208                 connectionOpened(_connection);
209                 synchronized(_connections)
210                 {
211                     _connections.add(this);
212                 }
213                 
214                 while (isStarted() && !isClosed())
215                 {
216                     if (_connection.isIdle())
217                     {
218                         if (getServer().getThreadPool().isLowOnThreads())
219                         {
220                             int lrmit = getLowResourceMaxIdleTime();
221                             if (lrmit>=0 && _sotimeout!= lrmit)
222                             {
223                                 _sotimeout=lrmit;
224                                 _socket.setSoTimeout(_sotimeout);
225                             }
226                         }
227                     }                    
228                     _connection.handle();
229                 }
230             }
231             catch (EofException e)
232             {
233                 Log.debug("EOF", e);
234                 try{close();}
235                 catch(IOException e2){Log.ignore(e2);}
236             }
237             catch (HttpException e)
238             {
239                 Log.debug("BAD", e);
240                 try{close();}
241                 catch(IOException e2){Log.ignore(e2);}
242             }
243             catch(Throwable e)
244             {
245                 Log.warn("handle failed",e);
246                 try{close();}
247                 catch(IOException e2){Log.ignore(e2);}
248             }
249             finally
250             { 
251                 connectionClosed(_connection);
252                 synchronized(_connections)
253                 {
254                     _connections.remove(this);
255                 }
256             }
257         }
258     }
259 }