0001: /*
0002: * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http/HttpConnector.java,v 1.34 2002/03/18 07:15:39 remm Exp $
0003: * $Revision: 1.34 $
0004: * $Date: 2002/03/18 07:15:39 $
0005: *
0006: * ====================================================================
0007: *
0008: * The Apache Software License, Version 1.1
0009: *
0010: * Copyright (c) 1999 The Apache Software Foundation. All rights
0011: * reserved.
0012: *
0013: * Redistribution and use in source and binary forms, with or without
0014: * modification, are permitted provided that the following conditions
0015: * are met:
0016: *
0017: * 1. Redistributions of source code must retain the above copyright
0018: * notice, this list of conditions and the following disclaimer.
0019: *
0020: * 2. Redistributions in binary form must reproduce the above copyright
0021: * notice, this list of conditions and the following disclaimer in
0022: * the documentation and/or other materials provided with the
0023: * distribution.
0024: *
0025: * 3. The end-user documentation included with the redistribution, if
0026: * any, must include the following acknowlegement:
0027: * "This product includes software developed by the
0028: * Apache Software Foundation (http://www.apache.org/)."
0029: * Alternately, this acknowlegement may appear in the software itself,
0030: * if and wherever such third-party acknowlegements normally appear.
0031: *
0032: * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
0033: * Foundation" must not be used to endorse or promote products derived
0034: * from this software without prior written permission. For written
0035: * permission, please contact apache@apache.org.
0036: *
0037: * 5. Products derived from this software may not be called "Apache"
0038: * nor may "Apache" appear in their names without prior written
0039: * permission of the Apache Group.
0040: *
0041: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0042: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0043: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0044: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
0045: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0046: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0047: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0048: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0049: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0050: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0051: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0052: * SUCH DAMAGE.
0053: * ====================================================================
0054: *
0055: * This software consists of voluntary contributions made by many
0056: * individuals on behalf of the Apache Software Foundation. For more
0057: * information on the Apache Software Foundation, please see
0058: * <http://www.apache.org/>.
0059: *
0060: * [Additional notices, if required by prior licensing conditions]
0061: *
0062: */
0063:
0064: package org.apache.catalina.connector.http;
0065:
0066: import java.io.IOException;
0067: import java.net.BindException;
0068: import java.net.InetAddress;
0069: import java.net.ServerSocket;
0070: import java.net.Socket;
0071: import java.net.UnknownHostException;
0072: import java.security.AccessControlException;
0073: import java.util.Stack;
0074: import java.util.Vector;
0075: import java.util.Enumeration;
0076: import java.security.KeyStoreException;
0077: import java.security.NoSuchAlgorithmException;
0078: import java.security.cert.CertificateException;
0079: import java.security.UnrecoverableKeyException;
0080: import java.security.KeyManagementException;
0081: import org.apache.catalina.Connector;
0082: import org.apache.catalina.Container;
0083: import org.apache.catalina.HttpRequest;
0084: import org.apache.catalina.HttpResponse;
0085: import org.apache.catalina.Lifecycle;
0086: import org.apache.catalina.LifecycleEvent;
0087: import org.apache.catalina.LifecycleException;
0088: import org.apache.catalina.LifecycleListener;
0089: import org.apache.catalina.Logger;
0090: import org.apache.catalina.Request;
0091: import org.apache.catalina.Response;
0092: import org.apache.catalina.Service;
0093: import org.apache.catalina.net.DefaultServerSocketFactory;
0094: import org.apache.catalina.net.ServerSocketFactory;
0095: import org.apache.catalina.util.LifecycleSupport;
0096: import org.apache.catalina.util.StringManager;
0097:
0098: /**
0099: * Implementation of an HTTP/1.1 connector.
0100: *
0101: * @author Craig R. McClanahan
0102: * @author Remy Maucherat
0103: * @version $Revision: 1.34 $ $Date: 2002/03/18 07:15:39 $
0104: * @deprecated
0105: */
0106:
0107: public final class HttpConnector implements Connector, Lifecycle,
0108: Runnable {
0109:
0110: // ----------------------------------------------------- Instance Variables
0111:
0112: /**
0113: * The <code>Service</code> we are associated with (if any).
0114: */
0115: private Service service = null;
0116:
0117: /**
0118: * The accept count for this Connector.
0119: */
0120: private int acceptCount = 10;
0121:
0122: /**
0123: * The IP address on which to bind, if any. If <code>null</code>, all
0124: * addresses on the server will be bound.
0125: */
0126: private String address = null;
0127:
0128: /**
0129: * The input buffer size we should create on input streams.
0130: */
0131: private int bufferSize = 2048;
0132:
0133: /**
0134: * The Container used for processing requests received by this Connector.
0135: */
0136: protected Container container = null;
0137:
0138: /**
0139: * The set of processors that have ever been created.
0140: */
0141: private Vector created = new Vector();
0142:
0143: /**
0144: * The current number of processors that have been created.
0145: */
0146: private int curProcessors = 0;
0147:
0148: /**
0149: * The debugging detail level for this component.
0150: */
0151: private int debug = 0;
0152:
0153: /**
0154: * The "enable DNS lookups" flag for this Connector.
0155: */
0156: private boolean enableLookups = false;
0157:
0158: /**
0159: * The server socket factory for this component.
0160: */
0161: private ServerSocketFactory factory = null;
0162:
0163: /**
0164: * Descriptive information about this Connector implementation.
0165: */
0166: private static final String info = "org.apache.catalina.connector.http.HttpConnector/1.0";
0167:
0168: /**
0169: * The lifecycle event support for this component.
0170: */
0171: protected LifecycleSupport lifecycle = new LifecycleSupport(this );
0172:
0173: /**
0174: * The minimum number of processors to start at initialization time.
0175: */
0176: protected int minProcessors = 5;
0177:
0178: /**
0179: * The maximum number of processors allowed, or <0 for unlimited.
0180: */
0181: private int maxProcessors = 20;
0182:
0183: /**
0184: * Timeout value on the incoming connection.
0185: * Note : a value of 0 means no timeout.
0186: */
0187: private int connectionTimeout = Constants.DEFAULT_CONNECTION_TIMEOUT;
0188:
0189: /**
0190: * The port number on which we listen for HTTP requests.
0191: */
0192: private int port = 8080;
0193:
0194: /**
0195: * The set of processors that have been created but are not currently
0196: * being used to process a request.
0197: */
0198: private Stack processors = new Stack();
0199:
0200: /**
0201: * The server name to which we should pretend requests to this Connector
0202: * were directed. This is useful when operating Tomcat behind a proxy
0203: * server, so that redirects get constructed accurately. If not specified,
0204: * the server name included in the <code>Host</code> header is used.
0205: */
0206: private String proxyName = null;
0207:
0208: /**
0209: * The server port to which we should pretent requests to this Connector
0210: * were directed. This is useful when operating Tomcat behind a proxy
0211: * server, so that redirects get constructed accurately. If not specified,
0212: * the port number specified by the <code>port</code> property is used.
0213: */
0214: private int proxyPort = 0;
0215:
0216: /**
0217: * The redirect port for non-SSL to SSL redirects.
0218: */
0219: private int redirectPort = 443;
0220:
0221: /**
0222: * The request scheme that will be set on all requests received
0223: * through this connector.
0224: */
0225: private String scheme = "http";
0226:
0227: /**
0228: * The secure connection flag that will be set on all requests received
0229: * through this connector.
0230: */
0231: private boolean secure = false;
0232:
0233: /**
0234: * The server socket through which we listen for incoming TCP connections.
0235: */
0236: private ServerSocket serverSocket = null;
0237:
0238: /**
0239: * The string manager for this package.
0240: */
0241: private StringManager sm = StringManager
0242: .getManager(Constants.Package);
0243:
0244: /**
0245: * Has this component been initialized yet?
0246: */
0247: private boolean initialized = false;
0248:
0249: /**
0250: * Has this component been started yet?
0251: */
0252: private boolean started = false;
0253:
0254: /**
0255: * The shutdown signal to our background thread
0256: */
0257: private boolean stopped = false;
0258:
0259: /**
0260: * The background thread.
0261: */
0262: private Thread thread = null;
0263:
0264: /**
0265: * The name to register for the background thread.
0266: */
0267: private String threadName = null;
0268:
0269: /**
0270: * The thread synchronization object.
0271: */
0272: private Object threadSync = new Object();
0273:
0274: /**
0275: * Is chunking allowed ?
0276: */
0277: private boolean allowChunking = true;
0278:
0279: /**
0280: * Use TCP no delay ?
0281: */
0282: private boolean tcpNoDelay = true;
0283:
0284: // ------------------------------------------------------------- Properties
0285:
0286: /**
0287: * Return the <code>Service</code> with which we are associated (if any).
0288: */
0289: public Service getService() {
0290:
0291: return (this .service);
0292:
0293: }
0294:
0295: /**
0296: * Set the <code>Service</code> with which we are associated (if any).
0297: *
0298: * @param service The service that owns this Engine
0299: */
0300: public void setService(Service service) {
0301:
0302: this .service = service;
0303:
0304: }
0305:
0306: /**
0307: * Return the connection timeout for this Connector.
0308: */
0309: public int getConnectionTimeout() {
0310:
0311: return (connectionTimeout);
0312:
0313: }
0314:
0315: /**
0316: * Set the connection timeout for this Connector.
0317: *
0318: * @param count The new connection timeout
0319: */
0320: public void setConnectionTimeout(int connectionTimeout) {
0321:
0322: this .connectionTimeout = connectionTimeout;
0323:
0324: }
0325:
0326: /**
0327: * Return the accept count for this Connector.
0328: */
0329: public int getAcceptCount() {
0330:
0331: return (acceptCount);
0332:
0333: }
0334:
0335: /**
0336: * Set the accept count for this Connector.
0337: *
0338: * @param count The new accept count
0339: */
0340: public void setAcceptCount(int count) {
0341:
0342: this .acceptCount = count;
0343:
0344: }
0345:
0346: /**
0347: * Get the allow chunking flag.
0348: */
0349: public boolean isChunkingAllowed() {
0350:
0351: return (allowChunking);
0352:
0353: }
0354:
0355: /**
0356: * Get the allow chunking flag.
0357: */
0358: public boolean getAllowChunking() {
0359:
0360: return isChunkingAllowed();
0361:
0362: }
0363:
0364: /**
0365: * Set the allow chunking flag.
0366: *
0367: * @param allowChunking Allow chunking flag
0368: */
0369: public void setAllowChunking(boolean allowChunking) {
0370:
0371: this .allowChunking = allowChunking;
0372:
0373: }
0374:
0375: /**
0376: * Return the bind IP address for this Connector.
0377: */
0378: public String getAddress() {
0379:
0380: return (this .address);
0381:
0382: }
0383:
0384: /**
0385: * Set the bind IP address for this Connector.
0386: *
0387: * @param address The bind IP address
0388: */
0389: public void setAddress(String address) {
0390:
0391: this .address = address;
0392:
0393: }
0394:
0395: /**
0396: * Is this connector available for processing requests?
0397: */
0398: public boolean isAvailable() {
0399:
0400: return (started);
0401:
0402: }
0403:
0404: /**
0405: * Return the input buffer size for this Connector.
0406: */
0407: public int getBufferSize() {
0408:
0409: return (this .bufferSize);
0410:
0411: }
0412:
0413: /**
0414: * Set the input buffer size for this Connector.
0415: *
0416: * @param bufferSize The new input buffer size.
0417: */
0418: public void setBufferSize(int bufferSize) {
0419:
0420: this .bufferSize = bufferSize;
0421:
0422: }
0423:
0424: /**
0425: * Return the Container used for processing requests received by this
0426: * Connector.
0427: */
0428: public Container getContainer() {
0429:
0430: return (container);
0431:
0432: }
0433:
0434: /**
0435: * Set the Container used for processing requests received by this
0436: * Connector.
0437: *
0438: * @param container The new Container to use
0439: */
0440: public void setContainer(Container container) {
0441:
0442: this .container = container;
0443:
0444: }
0445:
0446: /**
0447: * Return the current number of processors that have been created.
0448: */
0449: public int getCurProcessors() {
0450:
0451: return (curProcessors);
0452:
0453: }
0454:
0455: /**
0456: * Return the debugging detail level for this component.
0457: */
0458: public int getDebug() {
0459:
0460: return (debug);
0461:
0462: }
0463:
0464: /**
0465: * Set the debugging detail level for this component.
0466: *
0467: * @param debug The new debugging detail level
0468: */
0469: public void setDebug(int debug) {
0470:
0471: this .debug = debug;
0472:
0473: }
0474:
0475: /**
0476: * Return the "enable DNS lookups" flag.
0477: */
0478: public boolean getEnableLookups() {
0479:
0480: return (this .enableLookups);
0481:
0482: }
0483:
0484: /**
0485: * Set the "enable DNS lookups" flag.
0486: *
0487: * @param enableLookups The new "enable DNS lookups" flag value
0488: */
0489: public void setEnableLookups(boolean enableLookups) {
0490:
0491: this .enableLookups = enableLookups;
0492:
0493: }
0494:
0495: /**
0496: * Return the server socket factory used by this Container.
0497: */
0498: public ServerSocketFactory getFactory() {
0499:
0500: if (this .factory == null) {
0501: synchronized (this ) {
0502: this .factory = new DefaultServerSocketFactory();
0503: }
0504: }
0505: return (this .factory);
0506:
0507: }
0508:
0509: /**
0510: * Set the server socket factory used by this Container.
0511: *
0512: * @param factory The new server socket factory
0513: */
0514: public void setFactory(ServerSocketFactory factory) {
0515:
0516: this .factory = factory;
0517:
0518: }
0519:
0520: /**
0521: * Return descriptive information about this Connector implementation.
0522: */
0523: public String getInfo() {
0524:
0525: return (info);
0526:
0527: }
0528:
0529: /**
0530: * Return the minimum number of processors to start at initialization.
0531: */
0532: public int getMinProcessors() {
0533:
0534: return (minProcessors);
0535:
0536: }
0537:
0538: /**
0539: * Set the minimum number of processors to start at initialization.
0540: *
0541: * @param minProcessors The new minimum processors
0542: */
0543: public void setMinProcessors(int minProcessors) {
0544:
0545: this .minProcessors = minProcessors;
0546:
0547: }
0548:
0549: /**
0550: * Return the maximum number of processors allowed, or <0 for unlimited.
0551: */
0552: public int getMaxProcessors() {
0553:
0554: return (maxProcessors);
0555:
0556: }
0557:
0558: /**
0559: * Set the maximum number of processors allowed, or <0 for unlimited.
0560: *
0561: * @param maxProcessors The new maximum processors
0562: */
0563: public void setMaxProcessors(int maxProcessors) {
0564:
0565: this .maxProcessors = maxProcessors;
0566:
0567: }
0568:
0569: /**
0570: * Return the port number on which we listen for HTTP requests.
0571: */
0572: public int getPort() {
0573:
0574: return (this .port);
0575:
0576: }
0577:
0578: /**
0579: * Set the port number on which we listen for HTTP requests.
0580: *
0581: * @param port The new port number
0582: */
0583: public void setPort(int port) {
0584:
0585: this .port = port;
0586:
0587: }
0588:
0589: /**
0590: * Return the proxy server name for this Connector.
0591: */
0592: public String getProxyName() {
0593:
0594: return (this .proxyName);
0595:
0596: }
0597:
0598: /**
0599: * Set the proxy server name for this Connector.
0600: *
0601: * @param proxyName The new proxy server name
0602: */
0603: public void setProxyName(String proxyName) {
0604:
0605: this .proxyName = proxyName;
0606:
0607: }
0608:
0609: /**
0610: * Return the proxy server port for this Connector.
0611: */
0612: public int getProxyPort() {
0613:
0614: return (this .proxyPort);
0615:
0616: }
0617:
0618: /**
0619: * Set the proxy server port for this Connector.
0620: *
0621: * @param proxyPort The new proxy server port
0622: */
0623: public void setProxyPort(int proxyPort) {
0624:
0625: this .proxyPort = proxyPort;
0626:
0627: }
0628:
0629: /**
0630: * Return the port number to which a request should be redirected if
0631: * it comes in on a non-SSL port and is subject to a security constraint
0632: * with a transport guarantee that requires SSL.
0633: */
0634: public int getRedirectPort() {
0635:
0636: return (this .redirectPort);
0637:
0638: }
0639:
0640: /**
0641: * Set the redirect port number.
0642: *
0643: * @param redirectPort The redirect port number (non-SSL to SSL)
0644: */
0645: public void setRedirectPort(int redirectPort) {
0646:
0647: this .redirectPort = redirectPort;
0648:
0649: }
0650:
0651: /**
0652: * Return the scheme that will be assigned to requests received
0653: * through this connector. Default value is "http".
0654: */
0655: public String getScheme() {
0656:
0657: return (this .scheme);
0658:
0659: }
0660:
0661: /**
0662: * Set the scheme that will be assigned to requests received through
0663: * this connector.
0664: *
0665: * @param scheme The new scheme
0666: */
0667: public void setScheme(String scheme) {
0668:
0669: this .scheme = scheme;
0670:
0671: }
0672:
0673: /**
0674: * Return the secure connection flag that will be assigned to requests
0675: * received through this connector. Default value is "false".
0676: */
0677: public boolean getSecure() {
0678:
0679: return (this .secure);
0680:
0681: }
0682:
0683: /**
0684: * Set the secure connection flag that will be assigned to requests
0685: * received through this connector.
0686: *
0687: * @param secure The new secure connection flag
0688: */
0689: public void setSecure(boolean secure) {
0690:
0691: this .secure = secure;
0692:
0693: }
0694:
0695: /**
0696: * Return the TCP no delay flag value.
0697: */
0698: public boolean getTcpNoDelay() {
0699:
0700: return (this .tcpNoDelay);
0701:
0702: }
0703:
0704: /**
0705: * Set the TCP no delay flag which will be set on the socket after
0706: * accepting a connection.
0707: *
0708: * @param tcpNoDelay The new TCP no delay flag
0709: */
0710: public void setTcpNoDelay(boolean tcpNoDelay) {
0711:
0712: this .tcpNoDelay = tcpNoDelay;
0713:
0714: }
0715:
0716: // --------------------------------------------------------- Public Methods
0717:
0718: /**
0719: * Create (or allocate) and return a Request object suitable for
0720: * specifying the contents of a Request to the responsible Container.
0721: */
0722: public Request createRequest() {
0723:
0724: // if (debug >= 2)
0725: // log("createRequest: Creating new request");
0726: HttpRequestImpl request = new HttpRequestImpl();
0727: request.setConnector(this );
0728: return (request);
0729:
0730: }
0731:
0732: /**
0733: * Create (or allocate) and return a Response object suitable for
0734: * receiving the contents of a Response from the responsible Container.
0735: */
0736: public Response createResponse() {
0737:
0738: // if (debug >= 2)
0739: // log("createResponse: Creating new response");
0740: HttpResponseImpl response = new HttpResponseImpl();
0741: response.setConnector(this );
0742: return (response);
0743:
0744: }
0745:
0746: // -------------------------------------------------------- Package Methods
0747:
0748: /**
0749: * Recycle the specified Processor so that it can be used again.
0750: *
0751: * @param processor The processor to be recycled
0752: */
0753: void recycle(HttpProcessor processor) {
0754:
0755: // if (debug >= 2)
0756: // log("recycle: Recycling processor " + processor);
0757: processors.push(processor);
0758:
0759: }
0760:
0761: // -------------------------------------------------------- Private Methods
0762:
0763: /**
0764: * Create (or allocate) and return an available processor for use in
0765: * processing a specific HTTP request, if possible. If the maximum
0766: * allowed processors have already been created and are in use, return
0767: * <code>null</code> instead.
0768: */
0769: private HttpProcessor createProcessor() {
0770:
0771: synchronized (processors) {
0772: if (processors.size() > 0) {
0773: // if (debug >= 2)
0774: // log("createProcessor: Reusing existing processor");
0775: return ((HttpProcessor) processors.pop());
0776: }
0777: if ((maxProcessors > 0) && (curProcessors < maxProcessors)) {
0778: // if (debug >= 2)
0779: // log("createProcessor: Creating new processor");
0780: return (newProcessor());
0781: } else {
0782: if (maxProcessors < 0) {
0783: // if (debug >= 2)
0784: // log("createProcessor: Creating new processor");
0785: return (newProcessor());
0786: } else {
0787: // if (debug >= 2)
0788: // log("createProcessor: Cannot create new processor");
0789: return (null);
0790: }
0791: }
0792: }
0793:
0794: }
0795:
0796: /**
0797: * Log a message on the Logger associated with our Container (if any).
0798: *
0799: * @param message Message to be logged
0800: */
0801: private void log(String message) {
0802:
0803: Logger logger = container.getLogger();
0804: String localName = threadName;
0805: if (localName == null)
0806: localName = "HttpConnector";
0807: if (logger != null)
0808: logger.log(localName + " " + message);
0809: else
0810: System.out.println(localName + " " + message);
0811:
0812: }
0813:
0814: /**
0815: * Log a message on the Logger associated with our Container (if any).
0816: *
0817: * @param message Message to be logged
0818: * @param throwable Associated exception
0819: */
0820: private void log(String message, Throwable throwable) {
0821:
0822: Logger logger = container.getLogger();
0823: String localName = threadName;
0824: if (localName == null)
0825: localName = "HttpConnector";
0826: if (logger != null)
0827: logger.log(localName + " " + message, throwable);
0828: else {
0829: System.out.println(localName + " " + message);
0830: throwable.printStackTrace(System.out);
0831: }
0832:
0833: }
0834:
0835: /**
0836: * Create and return a new processor suitable for processing HTTP
0837: * requests and returning the corresponding responses.
0838: */
0839: private HttpProcessor newProcessor() {
0840:
0841: // if (debug >= 2)
0842: // log("newProcessor: Creating new processor");
0843: HttpProcessor processor = new HttpProcessor(this ,
0844: curProcessors++);
0845: if (processor instanceof Lifecycle) {
0846: try {
0847: ((Lifecycle) processor).start();
0848: } catch (LifecycleException e) {
0849: log("newProcessor", e);
0850: return (null);
0851: }
0852: }
0853: created.addElement(processor);
0854: return (processor);
0855:
0856: }
0857:
0858: /**
0859: * Open and return the server socket for this Connector. If an IP
0860: * address has been specified, the socket will be opened only on that
0861: * address; otherwise it will be opened on all addresses.
0862: *
0863: * @exception IOException input/output or network error
0864: * @exception KeyStoreException error instantiating the
0865: * KeyStore from file (SSL only)
0866: * @exception NoSuchAlgorithmException KeyStore algorithm unsupported
0867: * by current provider (SSL only)
0868: * @exception CertificateException general certificate error (SSL only)
0869: * @exception UnrecoverableKeyException internal KeyStore problem with
0870: * the certificate (SSL only)
0871: * @exception KeyManagementException problem in the key management
0872: * layer (SSL only)
0873: */
0874: private ServerSocket open() throws IOException, KeyStoreException,
0875: NoSuchAlgorithmException, CertificateException,
0876: UnrecoverableKeyException, KeyManagementException {
0877:
0878: // Acquire the server socket factory for this Connector
0879: ServerSocketFactory factory = getFactory();
0880:
0881: // If no address is specified, open a connection on all addresses
0882: if (address == null) {
0883: log(sm.getString("httpConnector.allAddresses"));
0884: try {
0885: return (factory.createSocket(port, acceptCount));
0886: } catch (BindException be) {
0887: throw new BindException(be.getMessage() + ":" + port);
0888: }
0889: }
0890:
0891: // Open a server socket on the specified address
0892: try {
0893: InetAddress is = InetAddress.getByName(address);
0894: log(sm.getString("httpConnector.anAddress", address));
0895: try {
0896: return (factory.createSocket(port, acceptCount, is));
0897: } catch (BindException be) {
0898: throw new BindException(be.getMessage() + ":" + address
0899: + ":" + port);
0900: }
0901: } catch (Exception e) {
0902: log(sm.getString("httpConnector.noAddress", address));
0903: try {
0904: return (factory.createSocket(port, acceptCount));
0905: } catch (BindException be) {
0906: throw new BindException(be.getMessage() + ":" + port);
0907: }
0908: }
0909:
0910: }
0911:
0912: // ---------------------------------------------- Background Thread Methods
0913:
0914: /**
0915: * The background thread that listens for incoming TCP/IP connections and
0916: * hands them off to an appropriate processor.
0917: */
0918: public void run() {
0919:
0920: // Loop until we receive a shutdown command
0921: while (!stopped) {
0922:
0923: // Accept the next incoming connection from the server socket
0924: Socket socket = null;
0925: try {
0926: // if (debug >= 3)
0927: // log("run: Waiting on serverSocket.accept()");
0928: socket = serverSocket.accept();
0929: // if (debug >= 3)
0930: // log("run: Returned from serverSocket.accept()");
0931: if (connectionTimeout > 0)
0932: socket.setSoTimeout(connectionTimeout);
0933: socket.setTcpNoDelay(tcpNoDelay);
0934: } catch (AccessControlException ace) {
0935: log("socket accept security exception", ace);
0936: continue;
0937: } catch (IOException e) {
0938: // if (debug >= 3)
0939: // log("run: Accept returned IOException", e);
0940: try {
0941: // If reopening fails, exit
0942: synchronized (threadSync) {
0943: if (started && !stopped)
0944: log("accept error: ", e);
0945: if (!stopped) {
0946: // if (debug >= 3)
0947: // log("run: Closing server socket");
0948: serverSocket.close();
0949: // if (debug >= 3)
0950: // log("run: Reopening server socket");
0951: serverSocket = open();
0952: }
0953: }
0954: // if (debug >= 3)
0955: // log("run: IOException processing completed");
0956: } catch (IOException ioe) {
0957: log("socket reopen, io problem: ", ioe);
0958: break;
0959: } catch (KeyStoreException kse) {
0960: log("socket reopen, keystore problem: ", kse);
0961: break;
0962: } catch (NoSuchAlgorithmException nsae) {
0963: log("socket reopen, keystore algorithm problem: ",
0964: nsae);
0965: break;
0966: } catch (CertificateException ce) {
0967: log("socket reopen, certificate problem: ", ce);
0968: break;
0969: } catch (UnrecoverableKeyException uke) {
0970: log("socket reopen, unrecoverable key: ", uke);
0971: break;
0972: } catch (KeyManagementException kme) {
0973: log("socket reopen, key management problem: ", kme);
0974: break;
0975: }
0976:
0977: continue;
0978: }
0979:
0980: // Hand this socket off to an appropriate processor
0981: HttpProcessor processor = createProcessor();
0982: if (processor == null) {
0983: try {
0984: log(sm.getString("httpConnector.noProcessor"));
0985: socket.close();
0986: } catch (IOException e) {
0987: ;
0988: }
0989: continue;
0990: }
0991: // if (debug >= 3)
0992: // log("run: Assigning socket to processor " + processor);
0993: processor.assign(socket);
0994:
0995: // The processor will recycle itself when it finishes
0996:
0997: }
0998:
0999: // Notify the threadStop() method that we have shut ourselves down
1000: // if (debug >= 3)
1001: // log("run: Notifying threadStop() that we have shut down");
1002: synchronized (threadSync) {
1003: threadSync.notifyAll();
1004: }
1005:
1006: }
1007:
1008: /**
1009: * Start the background processing thread.
1010: */
1011: private void threadStart() {
1012:
1013: log(sm.getString("httpConnector.starting"));
1014:
1015: thread = new Thread(this , threadName);
1016: thread.setDaemon(true);
1017: thread.start();
1018:
1019: }
1020:
1021: /**
1022: * Stop the background processing thread.
1023: */
1024: private void threadStop() {
1025:
1026: log(sm.getString("httpConnector.stopping"));
1027:
1028: stopped = true;
1029: try {
1030: threadSync.wait(5000);
1031: } catch (InterruptedException e) {
1032: ;
1033: }
1034: thread = null;
1035:
1036: }
1037:
1038: // ------------------------------------------------------ Lifecycle Methods
1039:
1040: /**
1041: * Add a lifecycle event listener to this component.
1042: *
1043: * @param listener The listener to add
1044: */
1045: public void addLifecycleListener(LifecycleListener listener) {
1046:
1047: lifecycle.addLifecycleListener(listener);
1048:
1049: }
1050:
1051: /**
1052: * Get the lifecycle listeners associated with this lifecycle. If this
1053: * Lifecycle has no listeners registered, a zero-length array is returned.
1054: */
1055: public LifecycleListener[] findLifecycleListeners() {
1056:
1057: return lifecycle.findLifecycleListeners();
1058:
1059: }
1060:
1061: /**
1062: * Remove a lifecycle event listener from this component.
1063: *
1064: * @param listener The listener to add
1065: */
1066: public void removeLifecycleListener(LifecycleListener listener) {
1067:
1068: lifecycle.removeLifecycleListener(listener);
1069:
1070: }
1071:
1072: /**
1073: * Initialize this connector (create ServerSocket here!)
1074: */
1075: public void initialize() throws LifecycleException {
1076: if (initialized)
1077: throw new LifecycleException(sm
1078: .getString("httpConnector.alreadyInitialized"));
1079:
1080: this .initialized = true;
1081: Exception eRethrow = null;
1082:
1083: // Establish a server socket on the specified port
1084: try {
1085: serverSocket = open();
1086: } catch (IOException ioe) {
1087: log("httpConnector, io problem: ", ioe);
1088: eRethrow = ioe;
1089: } catch (KeyStoreException kse) {
1090: log("httpConnector, keystore problem: ", kse);
1091: eRethrow = kse;
1092: } catch (NoSuchAlgorithmException nsae) {
1093: log("httpConnector, keystore algorithm problem: ", nsae);
1094: eRethrow = nsae;
1095: } catch (CertificateException ce) {
1096: log("httpConnector, certificate problem: ", ce);
1097: eRethrow = ce;
1098: } catch (UnrecoverableKeyException uke) {
1099: log("httpConnector, unrecoverable key: ", uke);
1100: eRethrow = uke;
1101: } catch (KeyManagementException kme) {
1102: log("httpConnector, key management problem: ", kme);
1103: eRethrow = kme;
1104: }
1105:
1106: if (eRethrow != null)
1107: throw new LifecycleException(threadName + ".open", eRethrow);
1108:
1109: }
1110:
1111: /**
1112: * Begin processing requests via this Connector.
1113: *
1114: * @exception LifecycleException if a fatal startup error occurs
1115: */
1116: public void start() throws LifecycleException {
1117:
1118: // Validate and update our current state
1119: if (started)
1120: throw new LifecycleException(sm
1121: .getString("httpConnector.alreadyStarted"));
1122: threadName = "HttpConnector[" + port + "]";
1123: lifecycle.fireLifecycleEvent(START_EVENT, null);
1124: started = true;
1125:
1126: // Start our background thread
1127: threadStart();
1128:
1129: // Create the specified minimum number of processors
1130: while (curProcessors < minProcessors) {
1131: if ((maxProcessors > 0) && (curProcessors >= maxProcessors))
1132: break;
1133: HttpProcessor processor = newProcessor();
1134: recycle(processor);
1135: }
1136:
1137: }
1138:
1139: /**
1140: * Terminate processing requests via this Connector.
1141: *
1142: * @exception LifecycleException if a fatal shutdown error occurs
1143: */
1144: public void stop() throws LifecycleException {
1145:
1146: // Validate and update our current state
1147: if (!started)
1148: throw new LifecycleException(sm
1149: .getString("httpConnector.notStarted"));
1150: lifecycle.fireLifecycleEvent(STOP_EVENT, null);
1151: started = false;
1152:
1153: // Gracefully shut down all processors we have created
1154: for (int i = created.size() - 1; i >= 0; i--) {
1155: HttpProcessor processor = (HttpProcessor) created
1156: .elementAt(i);
1157: if (processor instanceof Lifecycle) {
1158: try {
1159: ((Lifecycle) processor).stop();
1160: } catch (LifecycleException e) {
1161: log("HttpConnector.stop", e);
1162: }
1163: }
1164: }
1165:
1166: synchronized (threadSync) {
1167: // Close the server socket we were using
1168: if (serverSocket != null) {
1169: try {
1170: serverSocket.close();
1171: } catch (IOException e) {
1172: ;
1173: }
1174: }
1175: // Stop our background thread
1176: threadStop();
1177: }
1178: serverSocket = null;
1179:
1180: }
1181:
1182: }
|