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().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 }