PageRenderTime 73ms CodeModel.GetById 2ms app.highlight 60ms RepoModel.GetById 1ms app.codeStats 0ms

/tc6.0.x/tags/TOMCAT_6_0_10/java/org/apache/tomcat/util/net/NioEndpoint.java

#
Java | 1703 lines | 1003 code | 295 blank | 405 comment | 186 complexity | c28ee0c600a18d2c3e1a51273b125a96 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/*
   2 *  Licensed to the Apache Software Foundation (ASF) under one or more
   3 *  contributor license agreements.  See the NOTICE file distributed with
   4 *  this work for additional information regarding copyright ownership.
   5 *  The ASF licenses this file to You under the Apache License, Version 2.0
   6 *  (the "License"); you may not use this file except in compliance with
   7 *  the License.  You may obtain a copy of the License at
   8 *
   9 *      http://www.apache.org/licenses/LICENSE-2.0
  10 *
  11 *  Unless required by applicable law or agreed to in writing, software
  12 *  distributed under the License is distributed on an "AS IS" BASIS,
  13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 *  See the License for the specific language governing permissions and
  15 *  limitations under the License.
  16 */
  17
  18package org.apache.tomcat.util.net;
  19
  20import java.io.FileInputStream;
  21import java.io.IOException;
  22import java.net.InetAddress;
  23import java.net.InetSocketAddress;
  24import java.net.Socket;
  25import java.nio.ByteBuffer;
  26import java.nio.channels.CancelledKeyException;
  27import java.nio.channels.SelectionKey;
  28import java.nio.channels.Selector;
  29import java.nio.channels.ServerSocketChannel;
  30import java.nio.channels.SocketChannel;
  31import java.security.KeyStore;
  32import java.util.Iterator;
  33import java.util.Set;
  34import java.util.StringTokenizer;
  35import java.util.concurrent.ConcurrentLinkedQueue;
  36import java.util.concurrent.Executor;
  37import java.util.concurrent.atomic.AtomicLong;
  38import javax.net.ssl.KeyManagerFactory;
  39import javax.net.ssl.SSLContext;
  40import javax.net.ssl.SSLEngine;
  41import javax.net.ssl.TrustManagerFactory;
  42
  43import org.apache.juli.logging.Log;
  44import org.apache.juli.logging.LogFactory;
  45import org.apache.tomcat.util.IntrospectionUtils;
  46import org.apache.tomcat.util.net.SecureNioChannel.ApplicationBufferHandler;
  47import org.apache.tomcat.util.res.StringManager;
  48import java.util.concurrent.atomic.AtomicInteger;
  49
  50/**
  51 * NIO tailored thread pool, providing the following services:
  52 * <ul>
  53 * <li>Socket acceptor thread</li>
  54 * <li>Socket poller thread</li>
  55 * <li>Worker threads pool</li>
  56 * </ul>
  57 *
  58 * When switching to Java 5, there's an opportunity to use the virtual
  59 * machine's thread pool.
  60 *
  61 * @author Mladen Turk
  62 * @author Remy Maucherat
  63 * @author Filip Hanik
  64 */
  65public class NioEndpoint {
  66
  67
  68    // -------------------------------------------------------------- Constants
  69
  70
  71    protected static Log log = LogFactory.getLog(NioEndpoint.class);
  72
  73    protected static StringManager sm =
  74        StringManager.getManager("org.apache.tomcat.util.net.res");
  75
  76
  77    /**
  78     * The Request attribute key for the cipher suite.
  79     */
  80    public static final String CIPHER_SUITE_KEY = "javax.servlet.request.cipher_suite";
  81
  82    /**
  83     * The Request attribute key for the key size.
  84     */
  85    public static final String KEY_SIZE_KEY = "javax.servlet.request.key_size";
  86
  87    /**
  88     * The Request attribute key for the client certificate chain.
  89     */
  90    public static final String CERTIFICATE_KEY = "javax.servlet.request.X509Certificate";
  91
  92    /**
  93     * The Request attribute key for the session id.
  94     * This one is a Tomcat extension to the Servlet spec.
  95     */
  96    public static final String SESSION_ID_KEY = "javax.servlet.request.ssl_session";
  97
  98    public static final int OP_REGISTER = -1; //register interest op
  99    // ----------------------------------------------------------------- Fields
 100
 101
 102    /**
 103     * Available workers.
 104     */
 105    protected WorkerStack workers = null;
 106
 107
 108    /**
 109     * Running state of the endpoint.
 110     */
 111    protected volatile boolean running = false;
 112
 113
 114    /**
 115     * Will be set to true whenever the endpoint is paused.
 116     */
 117    protected volatile boolean paused = false;
 118
 119
 120    /**
 121     * Track the initialization state of the endpoint.
 122     */
 123    protected boolean initialized = false;
 124
 125
 126    /**
 127     * Current worker threads busy count.
 128     */
 129    protected int curThreadsBusy = 0;
 130
 131
 132    /**
 133     * Current worker threads count.
 134     */
 135    protected int curThreads = 0;
 136
 137
 138    /**
 139     * Sequence number used to generate thread names.
 140     */
 141    protected int sequence = 0;
 142    
 143    protected NioSelectorPool selectorPool = new NioSelectorPool();
 144    
 145    /**
 146     * Server socket "pointer".
 147     */
 148    protected ServerSocketChannel serverSock = null;
 149
 150    /**
 151     * Cache for key attachment objects
 152     */
 153    protected ConcurrentLinkedQueue<KeyAttachment> keyCache = new ConcurrentLinkedQueue<KeyAttachment>();
 154    
 155    /**
 156     * Cache for poller events
 157     */
 158    protected ConcurrentLinkedQueue<PollerEvent> eventCache = new ConcurrentLinkedQueue<PollerEvent>();
 159
 160    /**
 161     * Bytebuffer cache, each channel holds a set of buffers (two, except for SSL holds four)
 162     */
 163    protected ConcurrentLinkedQueue<NioChannel> nioChannels = new ConcurrentLinkedQueue<NioChannel>() {
 164        protected AtomicInteger size = new AtomicInteger(0);
 165        protected AtomicInteger bytes = new AtomicInteger(0);
 166        public boolean offer(NioChannel socket, KeyAttachment att) {
 167            boolean offer = socketProperties.getBufferPool()==-1?true:size.get()<socketProperties.getBufferPool();
 168            offer = offer && (socketProperties.getBufferPoolSize()==-1?true:(bytes.get()+socket.getBufferSize())<socketProperties.getBufferPoolSize());
 169            //avoid over growing our cache or add after we have stopped
 170            if ( running && (!paused) && (offer) ) {
 171                boolean result = super.offer(socket);
 172                if ( result ) {
 173                    size.incrementAndGet();
 174                    bytes.addAndGet(socket.getBufferSize());
 175                }
 176                return result;
 177            }
 178            else return false;
 179        }
 180        
 181        public NioChannel poll() {
 182            NioChannel result = super.poll();
 183            if ( result != null ) {
 184                size.decrementAndGet();
 185                bytes.addAndGet(-result.getBufferSize());
 186            }
 187            return result;
 188        }
 189        
 190        public void clear() {
 191            super.clear();
 192            size.set(0);
 193        }
 194    };
 195
 196    
 197
 198    // ------------------------------------------------------------- Properties
 199
 200
 201    /**
 202     * External Executor based thread pool.
 203     */
 204    protected Executor executor = null;
 205    public void setExecutor(Executor executor) { this.executor = executor; }
 206    public Executor getExecutor() { return executor; }
 207
 208
 209    /**
 210     * Maximum amount of worker threads.
 211     */
 212    protected int maxThreads = 400;
 213    public void setMaxThreads(int maxThreads) { this.maxThreads = maxThreads; }
 214    public int getMaxThreads() { return maxThreads; }
 215
 216
 217    /**
 218     * Priority of the acceptor and poller threads.
 219     */
 220    protected int threadPriority = Thread.NORM_PRIORITY;
 221    public void setThreadPriority(int threadPriority) { this.threadPriority = threadPriority; }
 222    public int getThreadPriority() { return threadPriority; }
 223
 224
 225    /**
 226     * Server socket port.
 227     */
 228    protected int port;
 229    public int getPort() { return port; }
 230    public void setPort(int port ) { this.port=port; }
 231
 232
 233    /**
 234     * Address for the server socket.
 235     */
 236    protected InetAddress address;
 237    public InetAddress getAddress() { return address; }
 238    public void setAddress(InetAddress address) { this.address = address; }
 239
 240
 241    /**
 242     * Handling of accepted sockets.
 243     */
 244    protected Handler handler = null;
 245    public void setHandler(Handler handler ) { this.handler = handler; }
 246    public Handler getHandler() { return handler; }
 247
 248
 249    /**
 250     * Allows the server developer to specify the backlog that
 251     * should be used for server sockets. By default, this value
 252     * is 100.
 253     */
 254    protected int backlog = 100;
 255    public void setBacklog(int backlog) { if (backlog > 0) this.backlog = backlog; }
 256    public int getBacklog() { return backlog; }
 257
 258    protected SocketProperties socketProperties = new SocketProperties();
 259
 260    /**
 261     * Socket TCP no delay.
 262     */
 263    public boolean getTcpNoDelay() { return socketProperties.getTcpNoDelay();}
 264    public void setTcpNoDelay(boolean tcpNoDelay) { socketProperties.setTcpNoDelay(tcpNoDelay); }
 265
 266
 267    /**
 268     * Socket linger.
 269     */
 270    public int getSoLinger() { return socketProperties.getSoLingerTime(); }
 271    public void setSoLinger(int soLinger) { 
 272        socketProperties.setSoLingerTime(soLinger);
 273        socketProperties.setSoLingerOn(soLinger>=0);
 274    }
 275
 276
 277    /**
 278     * Socket timeout.
 279     */
 280    public int getSoTimeout() { return socketProperties.getSoTimeout(); }
 281    public void setSoTimeout(int soTimeout) { socketProperties.setSoTimeout(soTimeout); }
 282
 283
 284    /**
 285     * Timeout on first request read before going to the poller, in ms.
 286     */
 287    protected int firstReadTimeout = 60000;
 288    public int getFirstReadTimeout() { return firstReadTimeout; }
 289    public void setFirstReadTimeout(int firstReadTimeout) { this.firstReadTimeout = firstReadTimeout; }
 290
 291
 292    /**
 293     * The default is true - the created threads will be
 294     *  in daemon mode. If set to false, the control thread
 295     *  will not be daemon - and will keep the process alive.
 296     */
 297    protected boolean daemon = true;
 298    public void setDaemon(boolean b) { daemon = b; }
 299    public boolean getDaemon() { return daemon; }
 300
 301
 302    /**
 303     * Name of the thread pool, which will be used for naming child threads.
 304     */
 305    protected String name = "TP";
 306    public void setName(String name) { this.name = name; }
 307    public String getName() { return name; }
 308
 309
 310
 311    /**
 312     * Allow comet request handling.
 313     */
 314    protected boolean useComet = true;
 315    public void setUseComet(boolean useComet) { this.useComet = useComet; }
 316    public boolean getUseComet() { return useComet; }
 317
 318
 319    /**
 320     * Acceptor thread count.
 321     */
 322    protected int acceptorThreadCount = 0;
 323    public void setAcceptorThreadCount(int acceptorThreadCount) { this.acceptorThreadCount = acceptorThreadCount; }
 324    public int getAcceptorThreadCount() { return acceptorThreadCount; }
 325
 326
 327
 328    /**
 329     * Poller thread count.
 330     */
 331    protected int pollerThreadCount = 0;
 332    public void setPollerThreadCount(int pollerThreadCount) { this.pollerThreadCount = pollerThreadCount; }
 333    public int getPollerThreadCount() { return pollerThreadCount; }
 334
 335    protected long selectorTimeout = 1000;
 336    public void setSelectorTimeout(long timeout){ this.selectorTimeout = timeout;}
 337    public long getSelectorTimeout(){ return this.selectorTimeout; }
 338    /**
 339     * The socket poller.
 340     */
 341    protected Poller[] pollers = null;
 342    protected int pollerRoundRobin = 0;
 343    public Poller getPoller0() {
 344        pollerRoundRobin = (pollerRoundRobin + 1) % pollers.length;
 345        Poller poller = pollers[pollerRoundRobin];
 346        return poller;
 347    }
 348
 349
 350    /**
 351     * The socket poller used for Comet support.
 352     */
 353    public Poller getCometPoller0() {
 354        Poller poller = getPoller0();
 355        return poller;
 356    }
 357
 358
 359    /**
 360     * Dummy maxSpareThreads property.
 361     */
 362    public int getMaxSpareThreads() { return Math.min(getMaxThreads(),5); }
 363
 364
 365    /**
 366     * Dummy minSpareThreads property.
 367     */
 368    public int getMinSpareThreads() { return Math.min(getMaxThreads(),5); }
 369    
 370    /**
 371     * Generic properties, introspected
 372     */
 373    public void setProperty(String name, String value) {
 374        final String selectorPoolName = "selectorPool.";
 375        final String socketName = "socket.";
 376        try {
 377            if (name.startsWith(selectorPoolName)) {
 378                IntrospectionUtils.setProperty(selectorPool, name.substring(selectorPoolName.length()), value);
 379            } else if (name.startsWith(socketName)) {
 380                IntrospectionUtils.setProperty(socketProperties, name.substring(socketName.length()), value);
 381            }
 382        }catch ( Exception x ) {
 383            log.error("Unable to set attribute \""+name+"\" to \""+value+"\"",x);
 384        }
 385    }
 386
 387
 388    // --------------------  SSL related properties --------------------
 389    protected String keystoreFile = System.getProperty("user.home")+"/.keystore";
 390    public String getKeystoreFile() { return keystoreFile;}
 391    public void setKeystoreFile(String s ) { this.keystoreFile = s; }
 392    public void setKeystore(String s ) { setKeystoreFile(s);}
 393    public String getKeystore() { return getKeystoreFile();}
 394    
 395    protected String algorithm = "SunX509";
 396    public String getAlgorithm() { return algorithm;}
 397    public void setAlgorithm(String s ) { this.algorithm = s;}
 398
 399    protected boolean clientAuth = false;
 400    public boolean getClientAuth() { return clientAuth;}
 401    public void setClientAuth(boolean b ) { this.clientAuth = b;}
 402    
 403    protected String keystorePass = "changeit";
 404    public String getKeystorePass() { return keystorePass;}
 405    public void setKeystorePass(String s ) { this.keystorePass = s;}
 406    
 407    protected String keystoreType = "JKS";
 408    public String getKeystoreType() { return keystoreType;}
 409    public void setKeystoreType(String s ) { this.keystoreType = s;}
 410
 411    protected String sslProtocol = "TLS"; 
 412    
 413    public String getSslProtocol() { return sslProtocol;}
 414    public void setSslProtocol(String s) { sslProtocol = s;}
 415    
 416    protected String sslEnabledProtocols=null; //"TLSv1,SSLv3,SSLv2Hello"
 417    protected String[] sslEnabledProtocolsarr =  new String[0];
 418    public void setSslEnabledProtocols(String s) {
 419        this.sslEnabledProtocols = s;
 420        StringTokenizer t = new StringTokenizer(s,",");
 421        sslEnabledProtocolsarr = new String[t.countTokens()];
 422        for (int i=0; i<sslEnabledProtocolsarr.length; i++ ) sslEnabledProtocolsarr[i] = t.nextToken();
 423    }
 424    
 425    
 426    protected String ciphers = null;
 427    protected String[] ciphersarr = new String[0];
 428    public String getCiphers() { return ciphers;}
 429    public void setCiphers(String s) { 
 430        ciphers = s;
 431        if ( s == null ) ciphersarr = new String[0];
 432        else {
 433            StringTokenizer t = new StringTokenizer(s,",");
 434            ciphersarr = new String[t.countTokens()];
 435            for (int i=0; i<ciphersarr.length; i++ ) ciphersarr[i] = t.nextToken();
 436        }
 437    }
 438    
 439    /**
 440     * SSL engine.
 441     */
 442    protected boolean SSLEnabled = false;
 443    public boolean isSSLEnabled() { return SSLEnabled;}
 444    public void setSSLEnabled(boolean SSLEnabled) {this.SSLEnabled = SSLEnabled;}
 445
 446    protected boolean secure = false;
 447    public boolean getSecure() { return secure;}
 448    public void setSecure(boolean b) { secure = b;}
 449
 450    public void setSelectorPool(NioSelectorPool selectorPool) {
 451        this.selectorPool = selectorPool;
 452    }
 453
 454    public void setSocketProperties(SocketProperties socketProperties) {
 455        this.socketProperties = socketProperties;
 456    }
 457
 458    protected SSLContext sslContext = null;
 459    public SSLContext getSSLContext() { return sslContext;}
 460    public void setSSLContext(SSLContext c) { sslContext = c;}
 461    
 462    // --------------------------------------------------------- Public Methods
 463
 464
 465    /**
 466     * Number of keepalive sockets.
 467     */
 468    public int getKeepAliveCount() {
 469        if (pollers == null) {
 470            return 0;
 471        } else {
 472            int keepAliveCount = 0;
 473            for (int i = 0; i < pollers.length; i++) {
 474                keepAliveCount += pollers[i].getKeepAliveCount();
 475            }
 476            return keepAliveCount;
 477        }
 478    }
 479
 480
 481
 482    /**
 483     * Return the amount of threads that are managed by the pool.
 484     *
 485     * @return the amount of threads that are managed by the pool
 486     */
 487    public int getCurrentThreadCount() {
 488        return curThreads;
 489    }
 490
 491
 492    /**
 493     * Return the amount of threads currently busy.
 494     *
 495     * @return the amount of threads currently busy
 496     */
 497    public int getCurrentThreadsBusy() {
 498        return curThreadsBusy;
 499    }
 500
 501
 502    /**
 503     * Return the state of the endpoint.
 504     *
 505     * @return true if the endpoint is running, false otherwise
 506     */
 507    public boolean isRunning() {
 508        return running;
 509    }
 510
 511
 512    /**
 513     * Return the state of the endpoint.
 514     *
 515     * @return true if the endpoint is paused, false otherwise
 516     */
 517    public boolean isPaused() {
 518        return paused;
 519    }
 520
 521
 522    // ----------------------------------------------- Public Lifecycle Methods
 523
 524
 525    /**
 526     * Initialize the endpoint.
 527     */
 528    public void init()
 529        throws Exception {
 530
 531        if (initialized)
 532            return;
 533
 534        serverSock = ServerSocketChannel.open();
 535        InetSocketAddress addr = (address!=null?new InetSocketAddress(address,port):new InetSocketAddress(port));
 536        serverSock.socket().bind(addr,100); //todo, set backlog value
 537        serverSock.configureBlocking(true); //mimic APR behavior
 538
 539        // Initialize thread count defaults for acceptor, poller and sendfile
 540        if (acceptorThreadCount == 0) {
 541            // FIXME: Doesn't seem to work that well with multiple accept threads
 542            acceptorThreadCount = 1;
 543        }
 544        if (pollerThreadCount <= 0) {
 545            //minimum one poller thread
 546            pollerThreadCount = 1;
 547        }
 548
 549        // Initialize SSL if needed
 550        if (isSSLEnabled()) {
 551            // Initialize SSL
 552            char[] passphrase = getKeystorePass().toCharArray();
 553
 554            KeyStore ks = KeyStore.getInstance(getKeystoreType());
 555            ks.load(new FileInputStream(getKeystoreFile()), passphrase);
 556            KeyStore ts = KeyStore.getInstance(getKeystoreType());
 557            ts.load(new FileInputStream(getKeystoreFile()), passphrase);
 558
 559            KeyManagerFactory kmf = KeyManagerFactory.getInstance(getAlgorithm());
 560            kmf.init(ks, passphrase);
 561
 562            TrustManagerFactory tmf = TrustManagerFactory.getInstance(getAlgorithm());
 563            tmf.init(ts);
 564
 565            sslContext = SSLContext.getInstance(getSslProtocol());
 566            sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
 567
 568        }
 569
 570        initialized = true;
 571
 572    }
 573
 574
 575    /**
 576     * Start the APR endpoint, creating acceptor, poller threads.
 577     */
 578    public void start()
 579        throws Exception {
 580        // Initialize socket if not done before
 581        if (!initialized) {
 582            init();
 583        }
 584        if (!running) {
 585            running = true;
 586            paused = false;
 587            
 588            // Create worker collection
 589            if (executor == null) {
 590                workers = new WorkerStack(maxThreads);
 591                //executor = new ThreadPoolExecutor(getMinSpareThreads(),getMaxThreads(),5000,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
 592            }
 593
 594            // Start acceptor threads
 595            for (int i = 0; i < acceptorThreadCount; i++) {
 596                Thread acceptorThread = new Thread(new Acceptor(), getName() + "-Acceptor-" + i);
 597                acceptorThread.setPriority(threadPriority);
 598                acceptorThread.setDaemon(daemon);
 599                acceptorThread.start();
 600            }
 601
 602            // Start poller threads
 603            pollers = new Poller[pollerThreadCount];
 604            for (int i = 0; i < pollerThreadCount; i++) {
 605                pollers[i] = new Poller();
 606                pollers[i].init();
 607                Thread pollerThread = new Thread(pollers[i], getName() + "-Poller-" + i);
 608                pollerThread.setPriority(threadPriority);
 609                pollerThread.setDaemon(true);
 610                pollerThread.start();
 611            }
 612        }
 613    }
 614
 615
 616    /**
 617     * Pause the endpoint, which will make it stop accepting new sockets.
 618     */
 619    public void pause() {
 620        if (running && !paused) {
 621            paused = true;
 622            unlockAccept();
 623        }
 624    }
 625
 626
 627    /**
 628     * Resume the endpoint, which will make it start accepting new sockets
 629     * again.
 630     */
 631    public void resume() {
 632        if (running) {
 633            paused = false;
 634        }
 635    }
 636
 637
 638    /**
 639     * Stop the endpoint. This will cause all processing threads to stop.
 640     */
 641    public void stop() {
 642        if (running) {
 643            running = false;
 644            unlockAccept();
 645            for (int i = 0; i < pollers.length; i++) {
 646                pollers[i].destroy();
 647            }
 648            pollers = null;
 649        }
 650        eventCache.clear();
 651        keyCache.clear();
 652        nioChannels.clear();
 653    }
 654
 655
 656    /**
 657     * Deallocate APR memory pools, and close server socket.
 658     */
 659    public void destroy() throws Exception {
 660        if (running) {
 661            stop();
 662        }
 663        // Close server socket
 664        serverSock.socket().close();
 665        serverSock.close();
 666        serverSock = null;
 667        sslContext = null;
 668        initialized = false;
 669        nioChannels.clear();
 670    }
 671
 672
 673    // ------------------------------------------------------ Protected Methods
 674
 675
 676    /**
 677     * Get a sequence number used for thread naming.
 678     */
 679    protected int getSequence() {
 680        return sequence++;
 681    }
 682
 683    public int getWriteBufSize() {
 684        return socketProperties.getTxBufSize();
 685    }
 686
 687    public int getReadBufSize() {
 688        return socketProperties.getRxBufSize();
 689    }
 690
 691    public NioSelectorPool getSelectorPool() {
 692        return selectorPool;
 693    }
 694
 695    public SocketProperties getSocketProperties() {
 696        return socketProperties;
 697    }
 698
 699    /**
 700     * Unlock the server socket accept using a bogus connection.
 701     */
 702    protected void unlockAccept() {
 703        java.net.Socket s = null;
 704        try {
 705            // Need to create a connection to unlock the accept();
 706            if (address == null) {
 707                s = new java.net.Socket("127.0.0.1", port);
 708            } else {
 709                s = new java.net.Socket(address, port);
 710                // setting soLinger to a small value will help shutdown the
 711                // connection quicker
 712                s.setSoLinger(true, 0);
 713            }
 714        } catch(Exception e) {
 715            if (log.isDebugEnabled()) {
 716                log.debug(sm.getString("endpoint.debug.unlock", "" + port), e);
 717            }
 718        } finally {
 719            if (s != null) {
 720                try {
 721                    s.close();
 722                } catch (Exception e) {
 723                    // Ignore
 724                }
 725            }
 726        }
 727    }
 728
 729
 730    /**
 731     * Process the specified connection.
 732     */
 733    protected boolean setSocketOptions(SocketChannel socket) {
 734        // Process the connection
 735        int step = 1;
 736        try {
 737            //disable blocking, APR style, we are gonna be polling it
 738            socket.configureBlocking(false);
 739            Socket sock = socket.socket();
 740            socketProperties.setProperties(sock);
 741
 742            NioChannel channel = nioChannels.poll();
 743            if ( channel == null ) {
 744                // 2: SSL setup
 745                step = 2;
 746
 747                if (sslContext != null) {
 748                    SSLEngine engine = createSSLEngine();
 749                    int appbufsize = engine.getSession().getApplicationBufferSize();
 750                    NioBufferHandler bufhandler = new NioBufferHandler(Math.max(appbufsize,getReadBufSize()),
 751                                                                       Math.max(appbufsize,getWriteBufSize()),
 752                                                                       socketProperties.getDirectBuffer());
 753                    channel = new SecureNioChannel(socket, engine, bufhandler, selectorPool);
 754                } else {
 755                    NioBufferHandler bufhandler = new NioBufferHandler(getReadBufSize(),
 756                                                                       getWriteBufSize(),
 757                                                                       socketProperties.getDirectBuffer());
 758
 759                    channel = new NioChannel(socket, bufhandler);
 760                }
 761            } else {
 762                
 763                channel.setIOChannel(socket);
 764                if ( channel instanceof SecureNioChannel ) {
 765                    SSLEngine engine = createSSLEngine();
 766                    ((SecureNioChannel)channel).reset(engine);
 767                } else {
 768                    channel.reset();
 769                }
 770            }
 771            getPoller0().register(channel);
 772
 773        } catch (Throwable t) {
 774            try {
 775                log.error("",t);
 776            }catch ( Throwable tt){}
 777            // Tell to close the socket
 778            return false;
 779        }
 780        return true;
 781    }
 782
 783    protected SSLEngine createSSLEngine() {
 784        SSLEngine engine = sslContext.createSSLEngine();
 785        engine.setNeedClientAuth(getClientAuth());
 786        engine.setUseClientMode(false);
 787        if ( ciphersarr.length > 0 ) engine.setEnabledCipherSuites(ciphersarr);
 788        if ( sslEnabledProtocolsarr.length > 0 ) engine.setEnabledProtocols(sslEnabledProtocolsarr);
 789        
 790        return engine;
 791    }
 792
 793
 794    /**
 795     * Create (or allocate) and return an available processor for use in
 796     * processing a specific HTTP request, if possible.  If the maximum
 797     * allowed processors have already been created and are in use, return
 798     * <code>null</code> instead.
 799     */
 800    protected Worker createWorkerThread() {
 801
 802        synchronized (workers) {
 803            if (workers.size() > 0) {
 804                curThreadsBusy++;
 805                return (workers.pop());
 806            }
 807            if ((maxThreads > 0) && (curThreads < maxThreads)) {
 808                curThreadsBusy++;
 809                return (newWorkerThread());
 810            } else {
 811                if (maxThreads < 0) {
 812                    curThreadsBusy++;
 813                    return (newWorkerThread());
 814                } else {
 815                    return (null);
 816                }
 817            }
 818        }
 819
 820    }
 821
 822
 823    /**
 824     * Create and return a new processor suitable for processing HTTP
 825     * requests and returning the corresponding responses.
 826     */
 827    protected Worker newWorkerThread() {
 828
 829        Worker workerThread = new Worker();
 830        workerThread.start();
 831        return (workerThread);
 832
 833    }
 834
 835
 836    /**
 837     * Return a new worker thread, and block while to worker is available.
 838     */
 839    protected Worker getWorkerThread() {
 840        // Allocate a new worker thread
 841        Worker workerThread = createWorkerThread();
 842        while (workerThread == null) {
 843            try {
 844                synchronized (workers) {
 845                    workerThread = createWorkerThread();
 846                    if ( workerThread == null ) workers.wait();
 847                }
 848            } catch (InterruptedException e) {
 849                // Ignore
 850            }
 851            if ( workerThread == null ) workerThread = createWorkerThread();
 852        }
 853        return workerThread;
 854    }
 855
 856
 857    /**
 858     * Recycle the specified Processor so that it can be used again.
 859     *
 860     * @param workerThread The processor to be recycled
 861     */
 862    protected void recycleWorkerThread(Worker workerThread) {
 863        synchronized (workers) {
 864            workers.push(workerThread);
 865            curThreadsBusy--;
 866            workers.notify();
 867        }
 868    }
 869
 870
 871    protected boolean processSocket(SocketChannel socket) {
 872        try {
 873            if (executor == null) {
 874                getWorkerThread().assign(socket);
 875            }  else {
 876                executor.execute(new SocketOptionsProcessor(socket));
 877            }
 878        } catch (Throwable t) {
 879            // This means we got an OOM or similar creating a thread, or that
 880            // the pool and its queue are full
 881            log.error(sm.getString("endpoint.process.fail"), t);
 882            return false;
 883        }
 884        return true;
 885    }
 886    /**
 887     * Process given socket.
 888     */
 889    protected boolean processSocket(NioChannel socket) {
 890        try {
 891            if (executor == null) {
 892                getWorkerThread().assign(socket);
 893            }  else {
 894                executor.execute(new SocketProcessor(socket));
 895            }
 896        } catch (Throwable t) {
 897            // This means we got an OOM or similar creating a thread, or that
 898            // the pool and its queue are full
 899            log.error(sm.getString("endpoint.process.fail"), t);
 900            return false;
 901        }
 902        return true;
 903    }
 904
 905
 906    /**
 907     * Process given socket for an event.
 908     */
 909    protected boolean processSocket(NioChannel socket, SocketStatus status) {
 910        try {
 911            if (executor == null) {
 912                getWorkerThread().assign(socket, status);
 913            } else {
 914                executor.execute(new SocketEventProcessor(socket, status));
 915            }
 916        } catch (Throwable t) {
 917            // This means we got an OOM or similar creating a thread, or that
 918            // the pool and its queue are full
 919            log.error(sm.getString("endpoint.process.fail"), t);
 920            return false;
 921        }
 922        return true;
 923    }
 924
 925
 926    // --------------------------------------------------- Acceptor Inner Class
 927
 928
 929    /**
 930     * Server socket acceptor thread.
 931     */
 932    protected class Acceptor implements Runnable {
 933
 934
 935        /**
 936         * The background thread that listens for incoming TCP/IP connections and
 937         * hands them off to an appropriate processor.
 938         */
 939        public void run() {
 940
 941            // Loop until we receive a shutdown command
 942            while (running) {
 943
 944                // Loop if endpoint is paused
 945                while (paused) {
 946                    try {
 947                        Thread.sleep(1000);
 948                    } catch (InterruptedException e) {
 949                        // Ignore
 950                    }
 951                }
 952
 953                try {
 954                    // Accept the next incoming connection from the server socket
 955                    SocketChannel socket = serverSock.accept();
 956                    // Hand this socket off to an appropriate processor
 957                    if ( running && (!paused) && socket != null ) processSocket(socket);
 958                } catch (Throwable t) {
 959                    log.error(sm.getString("endpoint.accept.fail"), t);
 960                }
 961
 962                // The processor will recycle itself when it finishes
 963
 964            }
 965
 966        }
 967
 968    }
 969
 970
 971    // ----------------------------------------------------- Poller Inner Classes
 972
 973    /**
 974     * 
 975     * PollerEvent, cacheable object for poller events to avoid GC
 976     */
 977    public class PollerEvent implements Runnable {
 978        
 979        protected NioChannel socket;
 980        protected int interestOps;
 981        protected KeyAttachment key;
 982        public PollerEvent(NioChannel ch, KeyAttachment k, int intOps) {
 983            reset(ch, k, intOps);
 984        }
 985    
 986        public void reset(NioChannel ch, KeyAttachment k, int intOps) {
 987            socket = ch;
 988            interestOps = intOps;
 989            key = k;
 990        }
 991    
 992        public void reset() {
 993            reset(null, null, 0);
 994        }
 995    
 996        public void run() {
 997            if ( interestOps == OP_REGISTER ) {
 998                try {
 999                    socket.getIOChannel().register(socket.getPoller().getSelector(), SelectionKey.OP_READ, key);
1000                } catch (Exception x) {
1001                    log.error("", x);
1002                }
1003            } else {
1004                final SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector());
1005                final KeyAttachment att = (KeyAttachment) key.attachment();
1006                try {
1007                    if (key != null) {
1008                        key.interestOps(interestOps);
1009                        att.interestOps(interestOps);
1010                    }
1011                }
1012                catch (CancelledKeyException ckx) {
1013                    try {
1014                        if (key != null && key.attachment() != null) {
1015                            KeyAttachment ka = (KeyAttachment) key.attachment();
1016                            ka.setError(true); //set to collect this socket immediately
1017                        }
1018                        try {
1019                            socket.close();
1020                        }
1021                        catch (Exception ignore) {}
1022                        if (socket.isOpen())
1023                            socket.close(true);
1024                    }
1025                    catch (Exception ignore) {}
1026                }
1027            }//end if
1028        }//run
1029        
1030        public String toString() {
1031            return super.toString()+"[intOps="+this.interestOps+"]";
1032        }
1033    }
1034    /**
1035     * Poller class.
1036     */
1037    public class Poller implements Runnable {
1038
1039        protected Selector selector;
1040        protected ConcurrentLinkedQueue<Runnable> events = new ConcurrentLinkedQueue<Runnable>();
1041        
1042        protected boolean close = false;
1043        protected long nextExpiration = 0;//optimize expiration handling
1044
1045        protected int keepAliveCount = 0;
1046        public int getKeepAliveCount() { return keepAliveCount; }
1047        
1048        protected AtomicLong wakeupCounter = new AtomicLong(0l);
1049
1050
1051
1052        public Poller() throws IOException {
1053            this.selector = Selector.open();
1054        }
1055        
1056        public Selector getSelector() { return selector;}
1057
1058        /**
1059         * Create the poller. With some versions of APR, the maximum poller size will
1060         * be 62 (reocmpiling APR is necessary to remove this limitation).
1061         */
1062        protected void init() {
1063            keepAliveCount = 0;
1064        }
1065
1066        /**
1067         * Destroy the poller.
1068         */
1069        protected void destroy() {
1070            // Wait for polltime before doing anything, so that the poller threads
1071            // exit, otherwise parallel descturction of sockets which are still
1072            // in the poller can cause problems
1073            close = true;
1074            events.clear();
1075            selector.wakeup();
1076        }
1077        
1078        public void addEvent(Runnable event) {
1079            events.offer(event);
1080            if ( wakeupCounter.incrementAndGet() < 3 ) selector.wakeup();
1081        }
1082
1083        /**
1084         * Add specified socket and associated pool to the poller. The socket will
1085         * be added to a temporary array, and polled first after a maximum amount
1086         * of time equal to pollTime (in most cases, latency will be much lower,
1087         * however).
1088         *
1089         * @param socket to add to the poller
1090         */
1091        public void add(final NioChannel socket) {
1092            add(socket,SelectionKey.OP_READ);
1093        }
1094        
1095        public void add(final NioChannel socket, final int interestOps) {
1096            PollerEvent r = eventCache.poll();
1097            if ( r==null) r = new PollerEvent(socket,null,interestOps);
1098            else r.reset(socket,null,interestOps);
1099            addEvent(r);
1100        }
1101        
1102        public boolean events() {
1103            boolean result = false;
1104            //synchronized (events) {
1105                Runnable r = null;
1106                result = (events.size() > 0);
1107                while ( (r = (Runnable)events.poll()) != null ) {
1108                    try {
1109                        r.run();
1110                        if ( r instanceof PollerEvent ) {
1111                            ((PollerEvent)r).reset();
1112                            eventCache.offer((PollerEvent)r);
1113                        }
1114                    } catch ( Exception x ) {
1115                        log.error("",x);
1116                    }
1117                }
1118                //events.clear();
1119            //}
1120            return result;
1121        }
1122        
1123        public void register(final NioChannel socket)
1124        {
1125            socket.setPoller(this);
1126            KeyAttachment key = keyCache.poll();
1127            final KeyAttachment ka = key!=null?key:new KeyAttachment();
1128            ka.reset(this,socket);
1129            PollerEvent r = eventCache.poll();
1130            ka.interestOps(SelectionKey.OP_READ);//this is what OP_REGISTER turns into.
1131            if ( r==null) r = new PollerEvent(socket,ka,OP_REGISTER);
1132            else r.reset(socket,ka,OP_REGISTER);
1133            addEvent(r);
1134        }
1135        
1136        public void cancelledKey(SelectionKey key, SocketStatus status) {
1137            try {
1138                KeyAttachment ka = (KeyAttachment) key.attachment();
1139                if (ka != null && ka.getComet()) {
1140                    //the comet event takes care of clean up
1141                    processSocket(ka.getChannel(), status);
1142                }else {
1143                    if (key.isValid()) key.cancel();
1144                    if (key.channel().isOpen()) key.channel().close();
1145                    key.attach(null);
1146                }
1147            } catch (Throwable e) {
1148                if ( log.isDebugEnabled() ) log.error("",e);
1149                // Ignore
1150            }
1151        }
1152        /**
1153         * The background thread that listens for incoming TCP/IP connections and
1154         * hands them off to an appropriate processor.
1155         */
1156        public void run() {
1157            // Loop until we receive a shutdown command
1158            while (running) {
1159                // Loop if endpoint is paused
1160                while (paused) {
1161                    try {
1162                        Thread.sleep(1000);
1163                    } catch (InterruptedException e) {
1164                        // Ignore
1165                    }
1166                }
1167                boolean hasEvents = false;
1168
1169                hasEvents = (hasEvents | events());
1170                // Time to terminate?
1171                if (close) return;
1172
1173                int keyCount = 0;
1174                try {
1175                    keyCount = selector.select(selectorTimeout);
1176                    wakeupCounter.set(0);
1177                    if ( close ) { selector.close(); return; }
1178                } catch ( NullPointerException x ) {
1179                    //sun bug 5076772 on windows JDK 1.5
1180                    if ( wakeupCounter == null || selector == null ) throw x;
1181                    continue;
1182                } catch ( CancelledKeyException x ) {
1183                    //sun bug 5076772 on windows JDK 1.5
1184                    if ( wakeupCounter == null || selector == null ) throw x;
1185                    continue;
1186                } catch (Throwable x) {
1187                    log.error("",x);
1188                    continue;
1189                }
1190                //either we timed out or we woke up, process events first
1191                if ( keyCount == 0 ) hasEvents = (hasEvents | events());
1192
1193                Iterator iterator = keyCount > 0 ? selector.selectedKeys().iterator() : null;
1194                // Walk through the collection of ready keys and dispatch
1195                // any active event.
1196                while (iterator != null && iterator.hasNext()) {
1197                    SelectionKey sk = (SelectionKey) iterator.next();
1198                    iterator.remove();
1199                    KeyAttachment attachment = (KeyAttachment)sk.attachment();
1200                    try {
1201                        if ( sk.isValid() && attachment != null ) {
1202                            attachment.access();
1203                            sk.attach(attachment);
1204                            sk.interestOps(0); //this is a must, so that we don't have multiple threads messing with the socket
1205                            attachment.interestOps(0);
1206                            NioChannel channel = attachment.getChannel();
1207                            if (sk.isReadable() || sk.isWritable() ) {
1208                                if ( attachment.getComet() ) {
1209                                    if (!processSocket(channel, SocketStatus.OPEN))
1210                                        processSocket(channel, SocketStatus.DISCONNECT);
1211                                } else {
1212                                    boolean close = (!processSocket(channel));
1213                                    if ( close ) {
1214                                        channel.close();
1215                                        channel.getIOChannel().socket().close();
1216                                    }
1217                                }
1218                            } 
1219                        } else {
1220                            //invalid key
1221                            cancelledKey(sk, SocketStatus.ERROR);
1222                        }
1223                    } catch ( CancelledKeyException ckx ) {
1224                        cancelledKey(sk, SocketStatus.ERROR);
1225                    } catch (Throwable t) {
1226                        log.error("",t);
1227                    }
1228                }//while
1229                //process timeouts
1230                timeout(keyCount,hasEvents);
1231            }//while
1232            synchronized (this) {
1233                this.notifyAll();
1234            }
1235
1236        }
1237        protected void timeout(int keyCount, boolean hasEvents) {
1238            long now = System.currentTimeMillis();
1239            //don't process timeouts too frequently, but if the selector simply timed out
1240            //then we can check timeouts to avoid gaps
1241            if ( (now < nextExpiration) && (keyCount>0 || hasEvents) ) return;
1242            nextExpiration = now + (long)socketProperties.getSoTimeout();
1243            //timeout
1244            Set<SelectionKey> keys = selector.keys();
1245            for (Iterator<SelectionKey> iter = keys.iterator(); iter.hasNext(); ) {
1246                SelectionKey key = iter.next();
1247                try {
1248                    KeyAttachment ka = (KeyAttachment) key.attachment();
1249                    if ( ka == null ) {
1250                        cancelledKey(key, SocketStatus.ERROR); //we don't support any keys without attachments
1251                    } else if ( ka.getError() ) {
1252                        cancelledKey(key, SocketStatus.DISCONNECT);
1253                    }else if ((ka.interestOps()&SelectionKey.OP_READ) == SelectionKey.OP_READ) {
1254                        //only timeout sockets that we are waiting for a read from
1255                        long delta = now - ka.getLastAccess();
1256                        long timeout = (ka.getTimeout()==-1)?((long) socketProperties.getSoTimeout()):(ka.getTimeout());
1257                        boolean isTimedout = delta > timeout;
1258                        if (isTimedout) {
1259                            key.interestOps(0); 
1260                            ka.interestOps(0); //avoid duplicate timeout calls
1261                            cancelledKey(key, SocketStatus.TIMEOUT);
1262                        } else {
1263                            long nextTime = now+(timeout-delta);
1264                            nextExpiration = (nextTime < nextExpiration)?nextTime:nextExpiration;
1265                        }
1266                    }//end if
1267                }catch ( CancelledKeyException ckx ) {
1268                    cancelledKey(key, SocketStatus.ERROR);
1269                }
1270            }//for
1271        }
1272    }
1273    
1274    public static class KeyAttachment {
1275        
1276        public KeyAttachment() {
1277            
1278        }
1279        public void reset(Poller poller, NioChannel channel) {
1280            this.channel = channel;
1281            this.poller = poller;
1282            lastAccess = System.currentTimeMillis();
1283            currentAccess = false;
1284            comet = false;
1285            timeout = -1;
1286            error = false;
1287        }
1288        
1289        public void reset() {
1290            reset(null,null);
1291        }
1292        
1293        public Poller getPoller() { return poller;}
1294        public void setPoller(Poller poller){this.poller = poller;}
1295        public long getLastAccess() { return lastAccess; }
1296        public void access() { access(System.currentTimeMillis()); }
1297        public void access(long access) { lastAccess = access; }
1298        public void setComet(boolean comet) { this.comet = comet; }
1299        public boolean getComet() { return comet; }
1300        public boolean getCurrentAccess() { return currentAccess; }
1301        public void setCurrentAccess(boolean access) { currentAccess = access; }
1302        public Object getMutex() {return mutex;}
1303        public void setTimeout(long timeout) {this.timeout = timeout;}
1304        public long getTimeout() {return this.timeout;}
1305        public boolean getError() { return error; }
1306        public void setError(boolean error) { this.error = error; }
1307        public NioChannel getChannel() { return channel;}
1308        public void setChannel(NioChannel channel) { this.channel = channel;}
1309        protected Poller poller = null;
1310        protected int interestOps = 0;
1311        public int interestOps() { return interestOps;}
1312        public int interestOps(int ops) { this.interestOps  = ops; return ops; }
1313        protected Object mutex = new Object();
1314        protected long lastAccess = -1;
1315        protected boolean currentAccess = false;
1316        protected boolean comet = false;
1317        protected long timeout = -1;
1318        protected boolean error = false;
1319        protected NioChannel channel = null;
1320
1321    }
1322
1323
1324
1325    // ----------------------------------------------------- Worker Inner Class
1326
1327
1328    /**
1329     * Server processor class.
1330     */
1331    protected class Worker implements Runnable {
1332
1333
1334        protected Thread thread = null;
1335        protected boolean available = false;
1336        protected Object socket = null;
1337        protected SocketStatus status = null;
1338
1339
1340        /**
1341         * Process an incoming TCP/IP connection on the specified socket.  Any
1342         * exception that occurs during processing must be logged and swallowed.
1343         * <b>NOTE</b>:  This method is called from our Connector's thread.  We
1344         * must assign it to our own thread so that multiple simultaneous
1345         * requests can be handled.
1346         *
1347         * @param socket TCP socket to process
1348         */
1349        protected synchronized void assign(Object socket) {
1350
1351            // Wait for the Processor to get the previous Socket
1352            while (available) {
1353                try {
1354                    wait();
1355                } catch (InterruptedException e) {
1356                }
1357            }
1358            // Store the newly available Socket and notify our thread
1359            this.socket = socket;
1360            status = null;
1361            available = true;
1362            notifyAll();
1363
1364        }
1365
1366
1367        protected synchronized void assign(Object socket, SocketStatus status) {
1368
1369            // Wait for the Processor to get the previous Socket
1370            while (available) {
1371                try {
1372                    wait();
1373                } catch (InterruptedException e) {
1374                }
1375            }
1376
1377            // Store the newly available Socket and notify our thread
1378            this.socket = socket;
1379            this.status = status;
1380            available = true;
1381            notifyAll();
1382        }
1383
1384
1385        /**
1386         * Await a newly assigned Socket from our Connector, or <code>null</code>
1387         * if we are supposed to shut down.
1388         */
1389        protected synchronized Object await() {
1390
1391            // Wait for the Connector to provide a new Socket
1392            while (!available) {
1393                try {
1394                    wait();
1395                } catch (InterruptedException e) {
1396                }
1397            }
1398
1399            // Notify the Connector that we have received this Socket
1400            Object socket = this.socket;
1401            available = false;
1402            notifyAll();
1403
1404            return (socket);
1405
1406        }
1407
1408
1409        /**
1410         * The background thread that listens for incoming TCP/IP connections and
1411         * hands them off to an appropriate processor.
1412         */
1413        public void run() {
1414
1415            // Process requests until we receive a shutdown signal
1416            while (running) {
1417                try {
1418                    // Wait for the next socket to be assigned
1419                    Object channel = await();
1420                    if (channel == null)
1421                        continue;
1422
1423                    if ( channel instanceof SocketChannel) {
1424                        SocketChannel sc = (SocketChannel)channel;
1425                        if ( !setSocketOptions(sc) ) {
1426                            try {
1427                                sc.socket().close();
1428                                sc.close();
1429                            }catch ( IOException ix ) {
1430                                if ( log.isDebugEnabled() ) log.debug("",ix);
1431                            }
1432                        } else {
1433                            //now we have it registered, remove it from the cache
1434                            
1435                        }
1436                    } else {
1437                        
1438                        NioChannel socket = (NioChannel)channel;
1439
1440                        SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector());
1441                        int handshake = -1;
1442                        try {
1443                            handshake = socket.handshake(key.isReadable(), key.isWritable());
1444                        }catch ( IOException x ) {
1445                            handshake = -1;
1446                            if ( log.isDebugEnabled() ) log.debug("Error during SSL handshake",x);
1447                        }catch ( CancelledKeyException ckx ) {
1448                            handshake = -1;
1449                        }
1450                        if ( handshake == 0 ) {
1451                            // Process the request from this socket
1452                            if ((status != null) && (handler.event(socket, status) == Handler.SocketState.CLOSED)) {
1453                                // Close socket and pool
1454                                try {
1455                                    KeyAttachment att = (KeyAttachment)socket.getAttachment(true);
1456                                    try {socket.close();}catch (Exception ignore){}
1457                                    if ( socket.isOpen() ) socket.close(true);
1458                                    key.cancel();
1459                                    key.attach(null);
1460                                    nioChannels.offer(socket);
1461                                    if ( att!=null ) keyCache.offer(att);
1462                                }catch ( Exception x ) {
1463                                    log.error("",x);
1464                                }
1465         

Large files files are truncated, but you can click here to view the full file