Hi, attached you'll find a patch that changes the coyote multithreading model to a "hybrid" threading model (NIO+Mulithread). It's fully compatible with the existing Catalina code and is SSL enabled.
The Hybrid model breaks the limitation of one thread per connection, thus you can have a higher number of concurrent users with a lower number of threads. NIO selectors are utilized to detect when a user connection becomes active ( i.e. there is a user http request available to be read), and then, one thread processes the connection as usual, but without blocking on the read() operation because we know that there is one available request. The Hybrid model eliminates the need to close inactive connections (especially important under high load or SSL load) and reduces the number of necessary threads. The patch will be also downloadable in short from http://www.bsc.es/edragon/. Next week I will make available a performance comparison between Tomcat 5.5.9 and the modified Tomcat (Static content, Dynamic content, Secure Dynamic Content and scalability on SMP machines). I'm testing it with RUBiS, Surge and httperf. Now, I am working on the admission control mechanism because it should be improved. (The number of threads doesn't limit the number of concurrent connections so we need to limit it in some way). Best Regards, Vicenç Beltran eDragon Research Group Barcelona Supercomputing Center (BSC) http://www.bsc.es/edragon =================================================================== diff -uprN jakarta-tomcat-5.5.9-src/jakarta-tomcat-catalina/catalina/src/conf/server.xml jakarta-tomcat-5.5.9-src+STWS/jakarta-tomcat-catalina/catalina/src/conf/server.xml --- jakarta-tomcat-5.5.9-src/jakarta-tomcat-catalina/catalina/src/conf/server.xml Sat Mar 26 20:23:58 2005 +++ jakarta-tomcat-5.5.9-src+STWS/jakarta-tomcat-catalina/catalina/src/conf/server.xml Thu May 19 18:58:52 2005 @@ -73,10 +73,10 @@ --> <!-- Define a non-SSL HTTP/1.1 Connector on port 8080 --> - <Connector port="8080" maxHttpHeaderSize="8192" - maxThreads="150" minSpareThreads="25" maxSpareThreads="75" + <Connector port="8080" maxHttpHeaderSize="8192" maxActiveRequest="100" + maxThreads="40" minSpareThreads="10" maxSpareThreads="10" enableLookups="false" redirectPort="8443" acceptCount="100" - connectionTimeout="20000" disableUploadTimeout="true" /> + connectionTimeout="0" disableUploadTimeout="true" /> <!-- Note : To disable connection timeouts, set connectionTimeout value to 0 --> @@ -90,11 +90,11 @@ <!-- Define a SSL HTTP/1.1 Connector on port 8443 --> <!-- - <Connector port="8443" maxHttpHeaderSize="8192" - maxThreads="150" minSpareThreads="25" maxSpareThreads="75" + <Connector port="8443" maxHttpHeaderSize="8192" maxActiveRequest="100" + maxThreads="40" minSpareThreads="10" maxSpareThreads="10" enableLookups="false" disableUploadTimeout="true" acceptCount="100" scheme="https" secure="true" - clientAuth="false" sslProtocol="TLS" /> + connectionTimeout="0" clientAuth="false" sslProtocol="TLS" /> --> <!-- Define an AJP 1.3 Connector on port 8009 --> diff -uprN jakarta-tomcat-5.5.9-src/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/connector/mbeans-descriptors.xml jakarta-tomcat-5.5.9-src+STWS/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/connector/mbeans-descriptors.xml --- jakarta-tomcat-5.5.9-src/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/connector/mbeans-descriptors.xml Sat Mar 26 20:23:59 2005 +++ jakarta-tomcat-5.5.9-src+STWS/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/connector/mbeans-descriptors.xml Thu May 19 12:29:07 2005 @@ -8,6 +8,12 @@ group="Connector" type="org.apache.catalina.connector.Connector"> + <attribute name="maxActiveRequests" + description="Maximum number of active requests" + type="int" + readable="true" + writeable="true"/> + <attribute name="acceptCount" description="The accept count for this Connector" type="int"/> diff -uprN jakarta-tomcat-5.5.9-src/jakarta-tomcat-catalina/webapps/docs/config/http.xml jakarta-tomcat-5.5.9-src+STWS/jakarta-tomcat-catalina/webapps/docs/config/http.xml --- jakarta-tomcat-5.5.9-src/jakarta-tomcat-catalina/webapps/docs/config/http.xml Sat Mar 26 20:24:09 2005 +++ jakarta-tomcat-5.5.9-src+STWS/jakarta-tomcat-catalina/webapps/docs/config/http.xml Thu May 19 12:28:17 2005 @@ -57,6 +57,11 @@ <attributes> + <attribute name="maxActiveRequests" required="false"> + <p>A integer value which can be used to adjust Tomcat response time + under high load.</p> + </attribute> + <attribute name="allowTrace" required="false"> <p>A boolean value which can be used to enable or disable the TRACE HTTP method. If not specified, this attribute is set to false.</p> diff -uprN jakarta-tomcat-5.5.9-src/jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/Http11Processor.java jakarta-tomcat-5.5.9-src+STWS/jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/Http11Processor.java --- jakarta-tomcat-5.5.9-src/jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/Http11Processor.java Sat Mar 26 20:24:10 2005 +++ jakarta-tomcat-5.5.9-src+STWS/jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/Http11Processor.java Thu May 19 19:03:10 2005 @@ -17,6 +17,7 @@ package org.apache.coyote.http11; import java.io.IOException; +import java.net.SocketTimeoutException; import java.io.InputStream; import java.io.InterruptedIOException; import java.io.OutputStream; @@ -774,7 +775,7 @@ public class Http11Processor implements // Error flag error = false; keepAlive = true; - +/* int keepAliveLeft = maxKeepAliveRequests; int soTimeout = socket.getSoTimeout(); int oldSoTimeout = soTimeout; @@ -805,25 +806,33 @@ public class Http11Processor implements error = true; } } +*/ boolean keptAlive = false; - while (started && !error && keepAlive) { + boolean available = true; + + while (started && available && !error && keepAlive) { - // Parsing the request header + // Parsing the request header try { - if( !disableUploadTimeout && keptAlive && soTimeout > 0 ) { +/* if( !disableUploadTimeout && keptAlive && soTimeout > 0 ) { socket.setSoTimeout(soTimeout); } +*/ socket.setSoTimeout(10); inputBuffer.parseRequestLine(); + request.setStartTime(System.currentTimeMillis()); thrA.setParam( threadPool, request.requestURI() ); keptAlive = true; if (!disableUploadTimeout) { socket.setSoTimeout(timeout); - } + } else socket.setSoTimeout(0); + inputBuffer.parseHeaders(); - } catch (IOException e) { + } catch(SocketTimeoutException ste){ + break; + } catch (IOException e) { error = true; break; } catch (Throwable t) { @@ -845,8 +854,8 @@ public class Http11Processor implements error = true; } - if (maxKeepAliveRequests > 0 && --keepAliveLeft == 0) - keepAlive = false; +// if (maxKeepAliveRequests > 0 && --keepAliveLeft == 0) +// keepAlive = false; // Process the request in the adapter if (!error) { @@ -914,9 +923,22 @@ public class Http11Processor implements // Next request inputBuffer.nextRequest(); outputBuffer.nextRequest(); - + + available = inputBuffer.available(); } +// eDragon + + + if(error || !keepAlive){ + try{ + socket.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); // Recycle diff -uprN jakarta-tomcat-5.5.9-src/jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/Http11Protocol.java jakarta-tomcat-5.5.9-src+STWS/jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/Http11Protocol.java --- jakarta-tomcat-5.5.9-src/jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/Http11Protocol.java Sat Mar 26 20:24:10 2005 +++ jakarta-tomcat-5.5.9-src+STWS/jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/Http11Protocol.java Thu May 19 12:23:03 2005 @@ -239,7 +239,7 @@ public class Http11Protocol implements P private String reportedname; private int socketCloseDelay=-1; private boolean disableUploadTimeout = true; - private int socketBuffer = 9000; + private int socketBuffer = 8192; // El famos bug: NIO+SSL+(buff>8192) => BUG!!! private Adapter adapter; private Http11ConnectionHandler cHandler; @@ -283,6 +283,15 @@ public class Http11Protocol implements P setAttribute("minSpareThreads", "" + minSpareThreads); } +/* JMX */ + public void setMaxActiveRequests(int MaxActiveRequests) { + ep.setMaxActiveRequests(MaxActiveRequests); + } + + public int getMaxActiveRequests(){ + return ep.getMaxActiveRequests(); + } + public void setThreadPriority(int threadPriority) { ep.setThreadPriority(threadPriority); setAttribute("threadPriority", "" + threadPriority); @@ -749,13 +758,15 @@ public class Http11Protocol implements P // type of error, provide a configurable delay to give the // unread input time to arrive so it can be successfully read // and discarded by shutdownInput(). +/* eDragon if( proto.socketCloseDelay >= 0 ) { try { Thread.sleep(proto.socketCloseDelay); - } catch (InterruptedException ie) { /* ignore */ } + } catch (InterruptedException ie) { } } TcpConnection.shutdownInput( socket ); +*/ } catch(java.net.SocketException e) { // SocketExceptions are normal Http11Protocol.log.debug @@ -783,9 +794,11 @@ public class Http11Protocol implements P if (processor instanceof ActionHook) { ((ActionHook) processor).action(ActionCode.ACTION_STOP, null); } +/* eDragon // recycle kernel sockets ASAP try { if (socket != null) socket.close (); } - catch (IOException e) { /* ignore */ } + catch (IOException e) { } +*/ } } } diff -uprN jakarta-tomcat-5.5.9-src/jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/InternalInputBuffer.java jakarta-tomcat-5.5.9-src+STWS/jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/InternalInputBuffer.java --- jakarta-tomcat-5.5.9-src/jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/InternalInputBuffer.java Sat Mar 26 20:24:10 2005 +++ jakarta-tomcat-5.5.9-src+STWS/jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/InternalInputBuffer.java Wed May 18 10:47:47 2005 @@ -371,6 +371,9 @@ public class InternalInputBuffer impleme } + public boolean available(){ + return pos < lastValid; + } /** * Read the request line. This function is meant to be used during the diff -uprN jakarta-tomcat-5.5.9-src/jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/net/DefaultServerSocketFactory.java jakarta-tomcat-5.5.9-src+STWS/jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/net/DefaultServerSocketFactory.java --- jakarta-tomcat-5.5.9-src/jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/net/DefaultServerSocketFactory.java Sat Mar 26 20:24:17 2005 +++ jakarta-tomcat-5.5.9-src+STWS/jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/net/DefaultServerSocketFactory.java Thu May 19 12:37:29 2005 @@ -18,6 +18,9 @@ package org.apache.tomcat.util.net; import java.io.*; import java.net.*; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.net.InetSocketAddress; /** * Default server socket factory. Doesn't do much except give us @@ -25,8 +28,10 @@ import java.net.*; * * @author [EMAIL PROTECTED] * @author Harish Prabandham + * @author Vicenç Beltran */ + // Default implementation of server sockets. // @@ -41,23 +46,33 @@ class DefaultServerSocketFactory extends public ServerSocket createSocket (int port) throws IOException { - return new ServerSocket (port); + ServerSocketChannel ssc = ServerSocketChannel.open(); + return ssc.socket(); } public ServerSocket createSocket (int port, int backlog) throws IOException { - return new ServerSocket (port, backlog); + + InetSocketAddress isa = new InetSocketAddress(port); + ServerSocketChannel ssc = ServerSocketChannel.open(); + ssc.socket().bind(isa, backlog); + return ssc.socket(); } public ServerSocket createSocket (int port, int backlog, InetAddress ifAddress) throws IOException { - return new ServerSocket (port, backlog, ifAddress); + InetSocketAddress isa = new InetSocketAddress(ifAddress, port); + ServerSocketChannel ssc = ServerSocketChannel.open(); + ssc.socket().bind(isa, backlog); + return ssc.socket(); } public Socket acceptSocket(ServerSocket socket) throws IOException { - return socket.accept(); + SocketChannel channel = socket.getChannel().accept(); + if (channel != null) return channel.socket(); + else return null; } public void handshake(Socket sock) diff -uprN jakarta-tomcat-5.5.9-src/jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/net/LeaderFollowerWorkerThread.java jakarta-tomcat-5.5.9-src+STWS/jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/net/LeaderFollowerWorkerThread.java --- jakarta-tomcat-5.5.9-src/jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/net/LeaderFollowerWorkerThread.java Sat Mar 26 20:24:17 2005 +++ jakarta-tomcat-5.5.9-src+STWS/jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/net/LeaderFollowerWorkerThread.java Thu May 19 19:06:29 2005 @@ -16,71 +16,182 @@ package org.apache.tomcat.util.net; -import java.net.Socket; import org.apache.tomcat.util.threads.ThreadPoolRunnable; +import java.util.LinkedList; +import java.util.Iterator; +import java.util.Set; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.io.IOException; +import java.net.Socket; -/* - * I switched the threading model here. - * - * We used to have a "listener" thread and a "connection" - * thread, this results in code simplicity but also a needless - * thread switch. - * - * Instead I am now using a pool of threads, all the threads are - * simmetric in their execution and no thread switch is needed. +/** + * @author Vicenç Beltran */ + class LeaderFollowerWorkerThread implements ThreadPoolRunnable { - /* This is not a normal Runnable - it gets attached to an existing - thread, runs and when run() ends - the thread keeps running. - It's better to keep the name ThreadPoolRunnable - avoid confusion. - We also want to use per/thread data and avoid sync wherever possible. - */ - PoolTcpEndpoint endpoint; +/* JMX */ + private static int maxActiveRequests=100; + + static public void setMaxActiveRequests(int MaxActiveRequests){ + maxActiveRequests = MaxActiveRequests; + System.out.println("MaxActiveRequests: "+maxActiveRequests); + } + + static public int getMaxActiveRequests(){ + return maxActiveRequests; + } +/* JMX */ + + private PoolTcpEndpoint endpoint; + + private LinkedList<Socket> registeredSocketList; + private LinkedList<Socket> preAcceptedSockets; + + private Iterator<SelectionKey> iterator; + private SelectionKey slkAccept; + private Selector selector; + + private int filteredActiveRequests; + private int numSelectedKeys; + private int count; - public LeaderFollowerWorkerThread(PoolTcpEndpoint endpoint) { - this.endpoint = endpoint; + public LeaderFollowerWorkerThread (PoolTcpEndpoint Endpoint) { + + endpoint = Endpoint; + preAcceptedSockets = new LinkedList<Socket>(); + registeredSocketList = new LinkedList<Socket>(); + + try{ + selector = Selector.open(); + } catch(IOException e) { e.printStackTrace(); } + + iterator = selector.selectedKeys().iterator(); + + ServerSocketChannel ssc = endpoint.getServerSocket().getChannel(); + slkAccept = null; + try{ + ssc.configureBlocking(false); + slkAccept = ssc.register(selector, SelectionKey.OP_ACCEPT); + }catch (Exception e) { e.printStackTrace(); } + + filteredActiveRequests = 0; + numSelectedKeys = 0; + count = 0; } public Object[] getInitData() { - // no synchronization overhead, but 2 array access Object obj[]=new Object[2]; obj[1]= endpoint.getConnectionHandler().init(); obj[0]=new TcpConnection(); return obj; } - + public void runIt(Object perThrData[]) { - // Create per-thread cache - if (endpoint.isRunning()) { - - // Loop if endpoint is paused - while (endpoint.isPaused()) { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - // Ignore - } - } - - // Accept a new connection - Socket s = null; + // Loop if endpoint is paused + while (endpoint.isPaused()) { try { - s = endpoint.acceptSocket(); - } finally { - // Continue accepting on another thread... - if (endpoint.isRunning()) { - endpoint.tp.runIt(this); - } + Thread.sleep(1000); + } catch (InterruptedException e) { + // Ignore } + } - // Process the connection - if (null != s) { - endpoint.processSocket(s, (TcpConnection) perThrData[0], (Object[]) perThrData[1]); - } + Socket socket = null; + long localTime = System.nanoTime(); + try{ + while(!iterator.hasNext() && preAcceptedSockets.isEmpty()) { + + if(registeredSocketList.isEmpty()) doSelect(); + else doSelectNow(); + + filteredActiveRequests = (filteredActiveRequests+numSelectedKeys)/2; + doAcceptNow(maxActiveRequests-filteredActiveRequests); + } + + + if(preAcceptedSockets.size()*count >= numSelectedKeys){ + count = 0; + socket = preAcceptedSockets.poll(); + } else { + count++; + SelectionKey key = iterator.next(); + socket = (Socket)key.attachment(); + key.cancel(); + socket.getChannel().configureBlocking(true); + numSelectedKeys--; + } + } catch (IOException e){ + e.printStackTrace(); + } finally { + endpoint.tp.runIt(this); } + + try{ + endpoint.processSocket(socket, (TcpConnection) perThrData[0], (Object[]) perThrData[1]); + + synchronized(registeredSocketList){ + registeredSocketList.add(socket); + } + selector.wakeup(); + + } catch(Exception e) { + e.printStackTrace(); + } } - + + + + private void doAcceptNow(int max) { + + Socket s; + for(int i=0; i<max; i++){ + if((s = endpoint.acceptSocket()) == null) return; + preAcceptedSockets.add(s); + } + } + + + private void doSelect() throws IOException { + + selector.select(); + + registerSockets(); + selector.selectedKeys().remove(slkAccept); + numSelectedKeys = selector.selectedKeys().size(); + iterator = selector.selectedKeys().iterator(); + } + + + private void doSelectNow() throws IOException{ + + selector.selectNow(); + registerSockets(); + selector.selectNow(); + selector.selectedKeys().remove(slkAccept); + numSelectedKeys = selector.selectedKeys().size(); + iterator = selector.selectedKeys().iterator(); + } + + + private void registerSockets(){ + Socket socket; + synchronized(registeredSocketList){ + while((socket = registeredSocketList.poll()) !=null){ + try{ + if(!socket.isClosed()){ + socket.getChannel().configureBlocking(false); + socket.getChannel().register(selector, SelectionKey.OP_READ, socket); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + } diff -uprN jakarta-tomcat-5.5.9-src/jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/net/PoolTcpEndpoint.java jakarta-tomcat-5.5.9-src+STWS/jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/net/PoolTcpEndpoint.java --- jakarta-tomcat-5.5.9-src/jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/net/PoolTcpEndpoint.java Sat Mar 26 20:24:17 2005 +++ jakarta-tomcat-5.5.9-src+STWS/jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/net/PoolTcpEndpoint.java Thu May 19 12:20:53 2005 @@ -88,7 +88,7 @@ public class PoolTcpEndpoint implements protected int socketTimeout=-1; private boolean lf = true; - + // ------ Leader follower fields @@ -96,7 +96,7 @@ public class PoolTcpEndpoint implements ThreadPoolRunnable listener; ThreadPool tp; - + // ------ Master slave fields /* The background thread. */ @@ -119,6 +119,15 @@ public class PoolTcpEndpoint implements // -------------------- Configuration -------------------- + public void setMaxActiveRequests(int MaxActiveRequests){ + LeaderFollowerWorkerThread.setMaxActiveRequests(MaxActiveRequests); + } + + public int getMaxActiveRequests(){ + return LeaderFollowerWorkerThread.getMaxActiveRequests(); + } + + public void setMaxThreads(int maxThreads) { if( maxThreads > 0) tp.setMaxThreads(maxThreads); @@ -174,6 +183,10 @@ public class PoolTcpEndpoint implements serverSocket = ss; } + public ServerSocket getServerSocket(){ + return serverSocket; + } + public void setServerSocketFactory( ServerSocketFactory factory ) { this.factory=factory; } @@ -275,11 +288,11 @@ public class PoolTcpEndpoint implements public int getCurrentThreadCount() { return curThreads; } - - public int getCurrentThreadsBusy() { - return curThreads - workerThreads.size(); + + public int getCurrentThreadsBusy(){ + return tp.getCurrentThreadsBusy(); } - + // -------------------- Public methods -------------------- public void initEndpoint() throws IOException, InstantiationException { @@ -304,25 +317,31 @@ public class PoolTcpEndpoint implements } catch( InstantiationException ex1 ) { throw ex1; } + + initialized = true; } public void startEndpoint() throws IOException, InstantiationException { - if (!initialized) { + if (!initialized) { initEndpoint(); } if (lf) { tp.start(); - } + } running = true; paused = false; if (lf) { - listener = new LeaderFollowerWorkerThread(this); - tp.runIt(listener); + for(int i=0; i<4; i++){ + LeaderFollowerWorkerThread listener = new LeaderFollowerWorkerThread(this); + tp.runIt(listener); + } } else { maxThreads = getMaxThreads(); threadStart(); - } + } + + } public void pauseEndpoint() { @@ -407,7 +426,7 @@ public class PoolTcpEndpoint implements accepted = factory.acceptSocket(serverSocket); } if (null == accepted) { - log.warn(sm.getString("endpoint.warn.nullSocket")); + // log.warn(sm.getString("endpoint.warn.nullSocket")); } else { if (!running) { accepted.close(); // rude, but unlikely! @@ -513,13 +532,13 @@ public class PoolTcpEndpoint implements // 1: Set socket options: timeout, linger, etc setSocketOptions(s); - + // 2: SSL handshake step = 2; if (getServerSocketFactory() != null) { getServerSocketFactory().handshake(s); } - + // 3: Process the connection step = 3; con.setEndpoint(this); diff -uprN jakarta-tomcat-5.5.9-src/jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE13SocketFactory.java jakarta-tomcat-5.5.9-src+STWS/jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE13SocketFactory.java --- jakarta-tomcat-5.5.9-src/jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE13SocketFactory.java Sat Mar 26 20:24:17 2005 +++ jakarta-tomcat-5.5.9-src+STWS/jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE13SocketFactory.java Wed May 18 10:47:47 2005 @@ -146,6 +146,14 @@ public class JSSE13SocketFactory extends socket.setNeedClientAuth(clientAuth); } + protected String[] getEnabledProtocols(SSLSocket socket, + String requestedProtocols){ + return null; + } + protected void setEnabledProtocols(SSLSocket socket, + String [] protocols){ + } + protected void configureClientAuth(SSLSocket socket){ // In JSSE 1.0.2 docs it does not explicitly // state whether SSLSockets returned from diff -uprN jakarta-tomcat-5.5.9-src/jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE14SocketFactory.java jakarta-tomcat-5.5.9-src+STWS/jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE14SocketFactory.java --- jakarta-tomcat-5.5.9-src/jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE14SocketFactory.java Sat Mar 26 20:24:17 2005 +++ jakarta-tomcat-5.5.9-src+STWS/jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE14SocketFactory.java Wed May 18 10:47:47 2005 @@ -114,6 +114,8 @@ public class JSSE14SocketFactory extend // create proxy sslProxy = context.getServerSocketFactory(); + sslProxy2 = context.getSocketFactory(); + // Determine which cipher suites to enable String requestedCiphers = (String)attributes.get("ciphers"); enabledCiphers = getEnabledCiphers(requestedCiphers, @@ -180,12 +182,20 @@ public class JSSE14SocketFactory extend return tms; } + + protected void setEnabledProtocols(SSLServerSocket socket, String []protocols){ if (protocols != null) { socket.setEnabledProtocols(protocols); } } + protected void setEnabledProtocols(SSLSocket socket, String []protocols){ + if (protocols != null) { + socket.setEnabledProtocols(protocols); + } + } + protected String[] getEnabledProtocols(SSLServerSocket socket, String requestedProtocols){ String[] supportedProtocols = socket.getSupportedProtocols(); @@ -251,6 +261,74 @@ public class JSSE14SocketFactory extend return enabledProtocols; } + + protected String[] getEnabledProtocols(SSLSocket socket, + String requestedProtocols){ + String[] supportedProtocols = socket.getSupportedProtocols(); + + String[] enabledProtocols = null; + + if (requestedProtocols != null) { + Vector vec = null; + String protocol = requestedProtocols; + int index = requestedProtocols.indexOf(','); + if (index != -1) { + int fromIndex = 0; + while (index != -1) { + protocol = requestedProtocols.substring(fromIndex, index).trim(); + if (protocol.length() > 0) { + /* + * Check to see if the requested protocol is among the + * supported protocols, i.e., may be enabled + */ + for (int i=0; supportedProtocols != null + && i<supportedProtocols.length; i++) { + if (supportedProtocols[i].equals(protocol)) { + if (vec == null) { + vec = new Vector(); + } + vec.addElement(protocol); + break; + } + } + } + fromIndex = index+1; + index = requestedProtocols.indexOf(',', fromIndex); + } // while + protocol = requestedProtocols.substring(fromIndex); + } + + if (protocol != null) { + protocol = protocol.trim(); + if (protocol.length() > 0) { + /* + * Check to see if the requested protocol is among the + * supported protocols, i.e., may be enabled + */ + for (int i=0; supportedProtocols != null + && i<supportedProtocols.length; i++) { + if (supportedProtocols[i].equals(protocol)) { + if (vec == null) { + vec = new Vector(); + } + vec.addElement(protocol); + break; + } + } + } + } + + if (vec != null) { + enabledProtocols = new String[vec.size()]; + vec.copyInto(enabledProtocols); + } + } + + return enabledProtocols; + } + + + protected void configureClientAuth(SSLServerSocket socket){ if (wantClientAuth){ socket.setWantClientAuth(wantClientAuth); @@ -263,5 +341,4 @@ public class JSSE14SocketFactory extend // Per JavaDocs: SSLSockets returned from // SSLServerSocket.accept() inherit this setting. } - } diff -uprN jakarta-tomcat-5.5.9-src/jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java jakarta-tomcat-5.5.9-src+STWS/jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java --- jakarta-tomcat-5.5.9-src/jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java Sat Mar 26 20:24:17 2005 +++ jakarta-tomcat-5.5.9-src+STWS/jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java Wed May 18 10:47:47 2005 @@ -32,6 +32,10 @@ import javax.net.ssl.SSLException; import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLServerSocketFactory; import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.net.InetSocketAddress; /* 1. Make the JSSE's jars available, either as an installed @@ -49,6 +53,7 @@ import javax.net.ssl.SSLSocket; * @author Costin Manolache * @author Stefan Freyr Stefansson * @author EKR -- renamed to JSSESocketFactory + * @author Vicenç Beltran */ public abstract class JSSESocketFactory extends org.apache.tomcat.util.net.ServerSocketFactory @@ -68,7 +73,8 @@ public abstract class JSSESocketFactory protected String clientAuth = "false"; protected SSLServerSocketFactory sslProxy = null; protected String[] enabledCiphers; - + + protected SSLSocketFactory sslProxy2 = null; public JSSESocketFactory () { } @@ -77,18 +83,20 @@ public abstract class JSSESocketFactory throws IOException { if (!initialized) init(); - ServerSocket socket = sslProxy.createServerSocket(port); - initServerSocket(socket); - return socket; + + ServerSocketChannel ssc = ServerSocketChannel.open(); + return ssc.socket(); } public ServerSocket createSocket (int port, int backlog) throws IOException { if (!initialized) init(); - ServerSocket socket = sslProxy.createServerSocket(port, backlog); - initServerSocket(socket); - return socket; + + InetSocketAddress isa = new InetSocketAddress(port); + ServerSocketChannel ssc = ServerSocketChannel.open(); + ssc.socket().bind(isa, backlog); + return ssc.socket(); } public ServerSocket createSocket (int port, int backlog, @@ -96,19 +104,24 @@ public abstract class JSSESocketFactory throws IOException { if (!initialized) init(); - ServerSocket socket = sslProxy.createServerSocket(port, backlog, - ifAddress); - initServerSocket(socket); - return socket; + InetSocketAddress isa = new InetSocketAddress(ifAddress, port); + ServerSocketChannel ssc = ServerSocketChannel.open(); + ssc.socket().bind(isa, backlog); + return ssc.socket(); } - + public Socket acceptSocket(ServerSocket socket) throws IOException { SSLSocket asock = null; try { - asock = (SSLSocket)socket.accept(); - configureClientAuth(asock); + + SocketChannel channel = socket.getChannel().accept(); + if(channel == null) return null; + Socket sk = channel.socket(); + asock = (SSLSocket) sslProxy2.createSocket(sk, sk.getInetAddress().getHostName(), sk.getPort(), true); + initSocket(asock); + asock.setUseClientMode(false); } catch (SSLException e){ throw new SocketException("SSL handshake error" + e.toString()); } @@ -116,7 +129,7 @@ public abstract class JSSESocketFactory } public void handshake(Socket sock) throws IOException { - ((SSLSocket)sock).startHandshake(); + ((SSLSocket)sock).getSession(); } /* @@ -321,6 +334,10 @@ public abstract class JSSESocketFactory abstract protected String[] getEnabledProtocols(SSLServerSocket socket, String requestedProtocols); + + abstract protected String[] getEnabledProtocols(SSLSocket socket, + String requestedProtocols); + /** * Set the SSL protocol variants to be enabled. * @param socket the SSLServerSocket. @@ -329,6 +346,9 @@ public abstract class JSSESocketFactory abstract protected void setEnabledProtocols(SSLServerSocket socket, String [] protocols); + + abstract protected void setEnabledProtocols(SSLSocket socket, + String [] protocols); /** * Configure Client authentication for this version of JSSE. The * JSSE included in Java 1.4 supports the 'want' value. Prior @@ -366,4 +386,21 @@ public abstract class JSSESocketFactory configureClientAuth(socket); } + private void initSocket(SSLSocket socket) { + + + if (enabledCiphers != null) { + socket.setEnabledCipherSuites(enabledCiphers); + } + + String requestedProtocols = (String) attributes.get("protocols"); + setEnabledProtocols(socket, getEnabledProtocols(socket, + requestedProtocols)); + + // we don't know if client auth is needed - + // after parsing the request we may re-handshake + configureClientAuth(socket); + } + + } =================================================================== --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]