001: // ========================================================================
002: // Copyright 2003-2005 Mort Bay Consulting Pty. Ltd.
003: // ------------------------------------------------------------------------
004: // Licensed under the Apache License, Version 2.0 (the "License");
005: // you may not use this file except in compliance with the License.
006: // You may obtain a copy of the License at
007: // http://www.apache.org/licenses/LICENSE-2.0
008: // Unless required by applicable law or agreed to in writing, software
009: // distributed under the License is distributed on an "AS IS" BASIS,
010: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
011: // See the License for the specific language governing permissions and
012: // limitations under the License.
013: // ========================================================================
014:
015: package org.mortbay.jetty.bio;
016:
017: import java.io.IOException;
018: import java.net.InetAddress;
019: import java.net.ServerSocket;
020: import java.net.Socket;
021: import java.util.HashSet;
022: import java.util.Iterator;
023: import java.util.Set;
024:
025: import org.mortbay.io.Buffer;
026: import org.mortbay.io.ByteArrayBuffer;
027: import org.mortbay.io.EndPoint;
028: import org.mortbay.io.bio.SocketEndPoint;
029: import org.mortbay.jetty.AbstractConnector;
030: import org.mortbay.jetty.EofException;
031: import org.mortbay.jetty.HttpConnection;
032: import org.mortbay.jetty.HttpException;
033: import org.mortbay.jetty.Request;
034: import org.mortbay.log.Log;
035:
036: /* ------------------------------------------------------------------------------- */
037: /** Socket Connector.
038: * This connector implements a traditional blocking IO and threading model.
039: * Normal JRE sockets are used and a thread is allocated per connection.
040: * Buffers are managed so that large buffers are only allocated to active connections.
041: *
042: * This Connector should only be used if NIO is not available.
043: *
044: * @org.apache.xbean.XBean element="bioConnector" description="Creates a BIO based socket connector"
045: *
046: * @author gregw
047: */
048: public class SocketConnector extends AbstractConnector {
049: protected ServerSocket _serverSocket;
050: protected Set _connections;
051:
052: /* ------------------------------------------------------------ */
053: /** Constructor.
054: *
055: */
056: public SocketConnector() {
057: }
058:
059: /* ------------------------------------------------------------ */
060: public Object getConnection() {
061: return _serverSocket;
062: }
063:
064: /* ------------------------------------------------------------ */
065: public void open() throws IOException {
066: // Create a new server socket and set to non blocking mode
067: _serverSocket = newServerSocket(getHost(), getPort(),
068: getAcceptQueueSize());
069: }
070:
071: /* ------------------------------------------------------------ */
072: protected ServerSocket newServerSocket(String host, int port,
073: int backlog) throws IOException {
074: ServerSocket ss = host == null ? new ServerSocket(port, backlog)
075: : new ServerSocket(port, backlog, InetAddress
076: .getByName(host));
077:
078: return ss;
079: }
080:
081: /* ------------------------------------------------------------ */
082: public void close() throws IOException {
083: if (_serverSocket != null)
084: _serverSocket.close();
085: _serverSocket = null;
086: }
087:
088: /* ------------------------------------------------------------ */
089: public void accept(int acceptorID) throws IOException,
090: InterruptedException {
091: Socket socket = _serverSocket.accept();
092: configure(socket);
093:
094: Connection connection = new Connection(socket);
095: connection.dispatch();
096: }
097:
098: /* ------------------------------------------------------------------------------- */
099: /**
100: * Allows subclass to override Conection if required.
101: */
102: protected HttpConnection newHttpConnection(EndPoint endpoint) {
103: return new HttpConnection(this , endpoint, getServer());
104: }
105:
106: /* ------------------------------------------------------------------------------- */
107: protected Buffer newBuffer(int size) {
108: return new ByteArrayBuffer(size);
109: }
110:
111: /* ------------------------------------------------------------------------------- */
112: public void customize(EndPoint endpoint, Request request)
113: throws IOException {
114: Connection connection = (Connection) endpoint;
115: if (connection._sotimeout != _maxIdleTime) {
116: connection._sotimeout = _maxIdleTime;
117: ((Socket) endpoint.getTransport())
118: .setSoTimeout(_maxIdleTime);
119: }
120:
121: super .customize(endpoint, request);
122: }
123:
124: /* ------------------------------------------------------------------------------- */
125: public int getLocalPort() {
126: if (_serverSocket == null || _serverSocket.isClosed())
127: return -1;
128: return _serverSocket.getLocalPort();
129: }
130:
131: /* ------------------------------------------------------------------------------- */
132: protected void doStart() throws Exception {
133: _connections = new HashSet();
134: super .doStart();
135: }
136:
137: /* ------------------------------------------------------------------------------- */
138: protected void doStop() throws Exception {
139: super .doStop();
140: Set set = new HashSet(_connections);
141: Iterator iter = set.iterator();
142: while (iter.hasNext()) {
143: Connection connection = (Connection) iter.next();
144: connection.close();
145: }
146: }
147:
148: /* ------------------------------------------------------------------------------- */
149: /* ------------------------------------------------------------------------------- */
150: /* ------------------------------------------------------------------------------- */
151: protected class Connection extends SocketEndPoint implements
152: Runnable {
153: boolean _dispatched = false;
154: HttpConnection _connection;
155: int _sotimeout;
156: Socket _socket;
157:
158: public Connection(Socket socket) throws IOException {
159: super (socket);
160: _connection = newHttpConnection(this );
161: _sotimeout = socket.getSoTimeout();
162: _socket = socket;
163: }
164:
165: public void dispatch() throws InterruptedException, IOException {
166: if (!getThreadPool().dispatch(this )) {
167: Log.warn("dispatch failed for {}", _connection);
168: close();
169: }
170: }
171:
172: public int fill(Buffer buffer) throws IOException {
173: int l = super .fill(buffer);
174: if (l < 0)
175: close();
176: return l;
177: }
178:
179: public void run() {
180: try {
181: connectionOpened(_connection);
182: _connections.add(this );
183:
184: while (isStarted() && !isClosed()) {
185: if (_connection.isIdle()) {
186: if (getServer().getThreadPool()
187: .isLowOnThreads()) {
188: int lrmit = getLowResourceMaxIdleTime();
189: if (lrmit >= 0 && _sotimeout != lrmit) {
190: _sotimeout = lrmit;
191: _socket.setSoTimeout(_sotimeout);
192: }
193: }
194: }
195: _connection.handle();
196: }
197: } catch (EofException e) {
198: Log.debug("EOF", e);
199: try {
200: close();
201: } catch (IOException e2) {
202: Log.ignore(e2);
203: }
204: } catch (HttpException e) {
205: Log.debug("BAD", e);
206: try {
207: close();
208: } catch (IOException e2) {
209: Log.ignore(e2);
210: }
211: } catch (Throwable e) {
212: Log.warn("handle failed", e);
213: try {
214: close();
215: } catch (IOException e2) {
216: Log.ignore(e2);
217: }
218: } finally {
219: connectionClosed(_connection);
220: _connections.remove(this);
221: }
222: }
223: }
224: }
|