PageRenderTime 103ms CodeModel.GetById 3ms app.highlight 88ms RepoModel.GetById 1ms app.codeStats 0ms

/java/org/apache/tomcat/util/net/AprEndpoint.java

https://github.com/kanishin/tomcat
Java | 2293 lines | 1464 code | 286 blank | 543 comment | 374 complexity | 37ef9eb7b4ac3790e1788f20421a3290 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.security.AccessController;
  21import java.security.PrivilegedAction;
  22import java.util.ArrayList;
  23import java.util.HashMap;
  24import java.util.Iterator;
  25import java.util.Map;
  26import java.util.concurrent.ConcurrentHashMap;
  27import java.util.concurrent.ConcurrentLinkedQueue;
  28import java.util.concurrent.Executor;
  29import java.util.concurrent.RejectedExecutionException;
  30
  31import org.apache.juli.logging.Log;
  32import org.apache.juli.logging.LogFactory;
  33import org.apache.tomcat.jni.Address;
  34import org.apache.tomcat.jni.Error;
  35import org.apache.tomcat.jni.File;
  36import org.apache.tomcat.jni.Library;
  37import org.apache.tomcat.jni.OS;
  38import org.apache.tomcat.jni.Poll;
  39import org.apache.tomcat.jni.Pool;
  40import org.apache.tomcat.jni.SSL;
  41import org.apache.tomcat.jni.SSLContext;
  42import org.apache.tomcat.jni.SSLSocket;
  43import org.apache.tomcat.jni.Sockaddr;
  44import org.apache.tomcat.jni.Socket;
  45import org.apache.tomcat.jni.Status;
  46import org.apache.tomcat.util.ExceptionUtils;
  47import org.apache.tomcat.util.net.AbstractEndpoint.Acceptor.AcceptorState;
  48import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
  49
  50
  51/**
  52 * APR tailored thread pool, providing the following services:
  53 * <ul>
  54 * <li>Socket acceptor thread</li>
  55 * <li>Socket poller thread</li>
  56 * <li>Sendfile thread</li>
  57 * <li>Worker threads pool</li>
  58 * </ul>
  59 *
  60 * When switching to Java 5, there's an opportunity to use the virtual
  61 * machine's thread pool.
  62 *
  63 * @author Mladen Turk
  64 * @author Remy Maucherat
  65 */
  66public class AprEndpoint extends AbstractEndpoint {
  67
  68
  69    // -------------------------------------------------------------- Constants
  70
  71
  72    private static final Log log = LogFactory.getLog(AprEndpoint.class);
  73
  74    // ----------------------------------------------------------------- Fields
  75    /**
  76     * Root APR memory pool.
  77     */
  78    protected long rootPool = 0;
  79
  80
  81    /**
  82     * Server socket "pointer".
  83     */
  84    protected long serverSock = 0;
  85
  86
  87    /**
  88     * APR memory pool for the server socket.
  89     */
  90    protected long serverSockPool = 0;
  91
  92
  93    /**
  94     * SSL context.
  95     */
  96    protected long sslContext = 0;
  97
  98
  99    protected ConcurrentLinkedQueue<SocketWrapper<Long>> waitingRequests =
 100            new ConcurrentLinkedQueue<>();
 101
 102    private final Map<Long,AprSocketWrapper> connections = new ConcurrentHashMap<>();
 103
 104    // ------------------------------------------------------------ Constructor
 105
 106    public AprEndpoint() {
 107        // Need to override the default for maxConnections to align it with what
 108        // was pollerSize (before the two were merged)
 109        setMaxConnections(8 * 1024);
 110    }
 111
 112    // ------------------------------------------------------------- Properties
 113
 114
 115    /**
 116     * Defer accept.
 117     */
 118    protected boolean deferAccept = true;
 119    public void setDeferAccept(boolean deferAccept) { this.deferAccept = deferAccept; }
 120    @Override
 121    public boolean getDeferAccept() { return deferAccept; }
 122
 123
 124    /**
 125     * Size of the sendfile (= concurrent files which can be served).
 126     */
 127    protected int sendfileSize = 1 * 1024;
 128    public void setSendfileSize(int sendfileSize) { this.sendfileSize = sendfileSize; }
 129    public int getSendfileSize() { return sendfileSize; }
 130
 131
 132    /**
 133     * Handling of accepted sockets.
 134     */
 135    protected Handler handler = null;
 136    public void setHandler(Handler handler ) { this.handler = handler; }
 137    public Handler getHandler() { return handler; }
 138
 139
 140    /**
 141     * Poll interval, in microseconds. The smaller the value, the more CPU the poller
 142     * will use, but the more responsive to activity it will be.
 143     */
 144    protected int pollTime = 2000;
 145    public int getPollTime() { return pollTime; }
 146    public void setPollTime(int pollTime) { if (pollTime > 0) { this.pollTime = pollTime; } }
 147
 148
 149    /**
 150     * Use sendfile for sending static files.
 151     */
 152    protected boolean useSendfile = Library.APR_HAS_SENDFILE;
 153    public void setUseSendfile(boolean useSendfile) { this.useSendfile = useSendfile; }
 154    @Override
 155    public boolean getUseSendfile() { return useSendfile; }
 156
 157
 158    /**
 159     * Allow comet request handling.
 160     */
 161    protected boolean useComet = true;
 162    public void setUseComet(boolean useComet) { this.useComet = useComet; }
 163    @Override
 164    public boolean getUseComet() { return useComet; }
 165    @Override
 166    public boolean getUseCometTimeout() { return false; } // Not supported
 167    @Override
 168    public boolean getUsePolling() { return true; } // Always supported
 169
 170
 171    /**
 172     * Sendfile thread count.
 173     */
 174    protected int sendfileThreadCount = 0;
 175    public void setSendfileThreadCount(int sendfileThreadCount) { this.sendfileThreadCount = sendfileThreadCount; }
 176    public int getSendfileThreadCount() { return sendfileThreadCount; }
 177
 178
 179    /**
 180     * The socket poller.
 181     */
 182    protected Poller poller = null;
 183    public Poller getPoller() {
 184        return poller;
 185    }
 186
 187
 188    /**
 189     * The socket poller.
 190     */
 191    protected AsyncTimeout asyncTimeout = null;
 192    public AsyncTimeout getAsyncTimeout() {
 193        return asyncTimeout;
 194    }
 195
 196
 197    /**
 198     * The static file sender.
 199     */
 200    protected Sendfile sendfile = null;
 201    public Sendfile getSendfile() {
 202        return sendfile;
 203    }
 204
 205
 206    /**
 207     * SSL protocols.
 208     */
 209    protected String SSLProtocol = "all";
 210    public String getSSLProtocol() { return SSLProtocol; }
 211    public void setSSLProtocol(String SSLProtocol) { this.SSLProtocol = SSLProtocol; }
 212
 213
 214    /**
 215     * SSL password (if a cert is encrypted, and no password has been provided, a callback
 216     * will ask for a password).
 217     */
 218    protected String SSLPassword = null;
 219    public String getSSLPassword() { return SSLPassword; }
 220    public void setSSLPassword(String SSLPassword) { this.SSLPassword = SSLPassword; }
 221
 222
 223    /**
 224     * SSL cipher suite.
 225     */
 226    protected String SSLCipherSuite = "ALL";
 227    public String getSSLCipherSuite() { return SSLCipherSuite; }
 228    public void setSSLCipherSuite(String SSLCipherSuite) { this.SSLCipherSuite = SSLCipherSuite; }
 229
 230
 231    /**
 232     * SSL certificate file.
 233     */
 234    protected String SSLCertificateFile = null;
 235    public String getSSLCertificateFile() { return SSLCertificateFile; }
 236    public void setSSLCertificateFile(String SSLCertificateFile) { this.SSLCertificateFile = SSLCertificateFile; }
 237
 238
 239    /**
 240     * SSL certificate key file.
 241     */
 242    protected String SSLCertificateKeyFile = null;
 243    public String getSSLCertificateKeyFile() { return SSLCertificateKeyFile; }
 244    public void setSSLCertificateKeyFile(String SSLCertificateKeyFile) { this.SSLCertificateKeyFile = SSLCertificateKeyFile; }
 245
 246
 247    /**
 248     * SSL certificate chain file.
 249     */
 250    protected String SSLCertificateChainFile = null;
 251    public String getSSLCertificateChainFile() { return SSLCertificateChainFile; }
 252    public void setSSLCertificateChainFile(String SSLCertificateChainFile) { this.SSLCertificateChainFile = SSLCertificateChainFile; }
 253
 254
 255    /**
 256     * SSL CA certificate path.
 257     */
 258    protected String SSLCACertificatePath = null;
 259    public String getSSLCACertificatePath() { return SSLCACertificatePath; }
 260    public void setSSLCACertificatePath(String SSLCACertificatePath) { this.SSLCACertificatePath = SSLCACertificatePath; }
 261
 262
 263    /**
 264     * SSL CA certificate file.
 265     */
 266    protected String SSLCACertificateFile = null;
 267    public String getSSLCACertificateFile() { return SSLCACertificateFile; }
 268    public void setSSLCACertificateFile(String SSLCACertificateFile) { this.SSLCACertificateFile = SSLCACertificateFile; }
 269
 270
 271    /**
 272     * SSL CA revocation path.
 273     */
 274    protected String SSLCARevocationPath = null;
 275    public String getSSLCARevocationPath() { return SSLCARevocationPath; }
 276    public void setSSLCARevocationPath(String SSLCARevocationPath) { this.SSLCARevocationPath = SSLCARevocationPath; }
 277
 278
 279    /**
 280     * SSL CA revocation file.
 281     */
 282    protected String SSLCARevocationFile = null;
 283    public String getSSLCARevocationFile() { return SSLCARevocationFile; }
 284    public void setSSLCARevocationFile(String SSLCARevocationFile) { this.SSLCARevocationFile = SSLCARevocationFile; }
 285
 286
 287    /**
 288     * SSL verify client.
 289     */
 290    protected String SSLVerifyClient = "none";
 291    public String getSSLVerifyClient() { return SSLVerifyClient; }
 292    public void setSSLVerifyClient(String SSLVerifyClient) { this.SSLVerifyClient = SSLVerifyClient; }
 293
 294
 295    /**
 296     * SSL verify depth.
 297     */
 298    protected int SSLVerifyDepth = 10;
 299    public int getSSLVerifyDepth() { return SSLVerifyDepth; }
 300    public void setSSLVerifyDepth(int SSLVerifyDepth) { this.SSLVerifyDepth = SSLVerifyDepth; }
 301
 302
 303    /**
 304     * SSL allow insecure renegotiation for the the client that does not
 305     * support the secure renegotiation.
 306     */
 307    protected boolean SSLInsecureRenegotiation = false;
 308    public void setSSLInsecureRenegotiation(boolean SSLInsecureRenegotiation) { this.SSLInsecureRenegotiation = SSLInsecureRenegotiation; }
 309    public boolean getSSLInsecureRenegotiation() { return SSLInsecureRenegotiation; }
 310
 311    protected boolean SSLHonorCipherOrder = false;
 312    /**
 313     * Set to <code>true</code> to enforce the <i>server's</i> cipher order
 314     * instead of the default which is to allow the client to choose a
 315     * preferred cipher.
 316     */
 317    public void setSSLHonorCipherOrder(boolean SSLHonorCipherOrder) { this.SSLHonorCipherOrder = SSLHonorCipherOrder; }
 318    public boolean getSSLHonorCipherOrder() { return SSLHonorCipherOrder; }
 319
 320    /**
 321     * Disables compression of the SSL stream. This thwarts CRIME attack
 322     * and possibly improves performance by not compressing uncompressible
 323     * content such as JPEG, etc.
 324     */
 325    protected boolean SSLDisableCompression = false;
 326
 327    /**
 328     * Set to <code>true</code> to disable SSL compression. This thwarts CRIME
 329     * attack.
 330     */
 331    public void setSSLDisableCompression(boolean SSLDisableCompression) { this.SSLDisableCompression = SSLDisableCompression; }
 332    public boolean getSSLDisableCompression() { return SSLDisableCompression; }
 333
 334    /**
 335     * Port in use.
 336     */
 337    @Override
 338    public int getLocalPort() {
 339        long s = serverSock;
 340        if (s == 0) {
 341            return -1;
 342        } else {
 343            long sa;
 344            try {
 345                sa = Address.get(Socket.APR_LOCAL, s);
 346                Sockaddr addr = Address.getInfo(sa);
 347                return addr.port;
 348            } catch (Exception e) {
 349                return -1;
 350            }
 351        }
 352    }
 353
 354
 355    @Override
 356    public String[] getCiphersUsed() {
 357        // TODO : Investigate if it is possible to extract the current list of
 358        //        available ciphers. Native code changes will be required.
 359        return new String[] { getSSLCipherSuite() };
 360    }
 361
 362
 363    // --------------------------------------------------------- Public Methods
 364
 365    /**
 366     * Number of keepalive sockets.
 367     */
 368    public int getKeepAliveCount() {
 369        if (poller == null) {
 370            return 0;
 371        }
 372
 373        return poller.getConnectionCount();
 374    }
 375
 376
 377    /**
 378     * Number of sendfile sockets.
 379     */
 380    public int getSendfileCount() {
 381        if (sendfile == null) {
 382            return 0;
 383        }
 384
 385        return sendfile.getSendfileCount();
 386    }
 387
 388
 389    // ----------------------------------------------- Public Lifecycle Methods
 390
 391
 392    /**
 393     * Initialize the endpoint.
 394     */
 395    @Override
 396    public void bind() throws Exception {
 397
 398        // Create the root APR memory pool
 399        try {
 400            rootPool = Pool.create(0);
 401        } catch (UnsatisfiedLinkError e) {
 402            throw new Exception(sm.getString("endpoint.init.notavail"));
 403        }
 404
 405        // Create the pool for the server socket
 406        serverSockPool = Pool.create(rootPool);
 407        // Create the APR address that will be bound
 408        String addressStr = null;
 409        if (getAddress() != null) {
 410            addressStr = getAddress().getHostAddress();
 411        }
 412        int family = Socket.APR_INET;
 413        if (Library.APR_HAVE_IPV6) {
 414            if (addressStr == null) {
 415                if (!OS.IS_BSD && !OS.IS_WIN32 && !OS.IS_WIN64)
 416                    family = Socket.APR_UNSPEC;
 417            } else if (addressStr.indexOf(':') >= 0) {
 418                family = Socket.APR_UNSPEC;
 419            }
 420         }
 421
 422        long inetAddress = Address.info(addressStr, family,
 423                getPort(), 0, rootPool);
 424        // Create the APR server socket
 425        serverSock = Socket.create(Address.getInfo(inetAddress).family,
 426                Socket.SOCK_STREAM,
 427                Socket.APR_PROTO_TCP, rootPool);
 428        if (OS.IS_UNIX) {
 429            Socket.optSet(serverSock, Socket.APR_SO_REUSEADDR, 1);
 430        }
 431        // Deal with the firewalls that tend to drop the inactive sockets
 432        Socket.optSet(serverSock, Socket.APR_SO_KEEPALIVE, 1);
 433        // Bind the server socket
 434        int ret = Socket.bind(serverSock, inetAddress);
 435        if (ret != 0) {
 436            throw new Exception(sm.getString("endpoint.init.bind", "" + ret, Error.strerror(ret)));
 437        }
 438        // Start listening on the server socket
 439        ret = Socket.listen(serverSock, getBacklog());
 440        if (ret != 0) {
 441            throw new Exception(sm.getString("endpoint.init.listen", "" + ret, Error.strerror(ret)));
 442        }
 443        if (OS.IS_WIN32 || OS.IS_WIN64) {
 444            // On Windows set the reuseaddr flag after the bind/listen
 445            Socket.optSet(serverSock, Socket.APR_SO_REUSEADDR, 1);
 446        }
 447
 448        // Sendfile usage on systems which don't support it cause major problems
 449        if (useSendfile && !Library.APR_HAS_SENDFILE) {
 450            useSendfile = false;
 451        }
 452
 453        // Initialize thread count default for acceptor
 454        if (acceptorThreadCount == 0) {
 455            // FIXME: Doesn't seem to work that well with multiple accept threads
 456            acceptorThreadCount = 1;
 457        }
 458
 459        // Delay accepting of new connections until data is available
 460        // Only Linux kernels 2.4 + have that implemented
 461        // on other platforms this call is noop and will return APR_ENOTIMPL.
 462        if (deferAccept) {
 463            if (Socket.optSet(serverSock, Socket.APR_TCP_DEFER_ACCEPT, 1) == Status.APR_ENOTIMPL) {
 464                deferAccept = false;
 465            }
 466        }
 467
 468        // Initialize SSL if needed
 469        if (isSSLEnabled()) {
 470
 471            if (SSLCertificateFile == null) {
 472                // This is required
 473                throw new Exception(sm.getString("endpoint.apr.noSslCertFile"));
 474            }
 475
 476            // SSL protocol
 477            int value = SSL.SSL_PROTOCOL_NONE;
 478            if (SSLProtocol == null || SSLProtocol.length() == 0) {
 479                value = SSL.SSL_PROTOCOL_ALL;
 480            } else {
 481                for (String protocol : SSLProtocol.split("\\+")) {
 482                    protocol = protocol.trim();
 483                    if ("SSLv2".equalsIgnoreCase(protocol)) {
 484                        value |= SSL.SSL_PROTOCOL_SSLV2;
 485                    } else if ("SSLv3".equalsIgnoreCase(protocol)) {
 486                        value |= SSL.SSL_PROTOCOL_SSLV3;
 487                    } else if ("TLSv1".equalsIgnoreCase(protocol)) {
 488                        value |= SSL.SSL_PROTOCOL_TLSV1;
 489                    } else if ("all".equalsIgnoreCase(protocol)) {
 490                        value |= SSL.SSL_PROTOCOL_ALL;
 491                    } else {
 492                        // Protocol not recognized, fail to start as it is safer than
 493                        // continuing with the default which might enable more than the
 494                        // is required
 495                        throw new Exception(sm.getString(
 496                                "endpoint.apr.invalidSslProtocol", SSLProtocol));
 497                    }
 498                }
 499            }
 500
 501            // Create SSL Context
 502            sslContext = SSLContext.make(rootPool, value, SSL.SSL_MODE_SERVER);
 503            if (SSLInsecureRenegotiation) {
 504                boolean legacyRenegSupported = false;
 505                try {
 506                    legacyRenegSupported = SSL.hasOp(SSL.SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION);
 507                    if (legacyRenegSupported)
 508                        SSLContext.setOptions(sslContext, SSL.SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION);
 509                } catch (UnsatisfiedLinkError e) {
 510                    // Ignore
 511                }
 512                if (!legacyRenegSupported) {
 513                    // OpenSSL does not support unsafe legacy renegotiation.
 514                    log.warn(sm.getString("endpoint.warn.noInsecureReneg",
 515                                          SSL.versionString()));
 516                }
 517            }
 518
 519            // Set cipher order: client (default) or server
 520            if (SSLHonorCipherOrder) {
 521                boolean orderCiphersSupported = false;
 522                try {
 523                    orderCiphersSupported = SSL.hasOp(SSL.SSL_OP_CIPHER_SERVER_PREFERENCE);
 524                    if (orderCiphersSupported)
 525                        SSLContext.setOptions(sslContext, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE);
 526                } catch (UnsatisfiedLinkError e) {
 527                    // Ignore
 528                }
 529                if (!orderCiphersSupported) {
 530                    // OpenSSL does not support ciphers ordering.
 531                    log.warn(sm.getString("endpoint.warn.noHonorCipherOrder",
 532                                          SSL.versionString()));
 533                }
 534            }
 535
 536            // Disable compression if requested
 537            if (SSLDisableCompression) {
 538                boolean disableCompressionSupported = false;
 539                try {
 540                    disableCompressionSupported = SSL.hasOp(SSL.SSL_OP_NO_COMPRESSION);
 541                    if (disableCompressionSupported)
 542                        SSLContext.setOptions(sslContext, SSL.SSL_OP_NO_COMPRESSION);
 543                } catch (UnsatisfiedLinkError e) {
 544                    // Ignore
 545                }
 546                if (!disableCompressionSupported) {
 547                    // OpenSSL does not support ciphers ordering.
 548                    log.warn(sm.getString("endpoint.warn.noDisableCompression",
 549                                          SSL.versionString()));
 550                }
 551            }
 552
 553            // List the ciphers that the client is permitted to negotiate
 554            SSLContext.setCipherSuite(sslContext, SSLCipherSuite);
 555            // Load Server key and certificate
 556            SSLContext.setCertificate(sslContext, SSLCertificateFile, SSLCertificateKeyFile, SSLPassword, SSL.SSL_AIDX_RSA);
 557            // Set certificate chain file
 558            SSLContext.setCertificateChainFile(sslContext, SSLCertificateChainFile, false);
 559            // Support Client Certificates
 560            SSLContext.setCACertificate(sslContext, SSLCACertificateFile, SSLCACertificatePath);
 561            // Set revocation
 562            SSLContext.setCARevocation(sslContext, SSLCARevocationFile, SSLCARevocationPath);
 563            // Client certificate verification
 564            value = SSL.SSL_CVERIFY_NONE;
 565            if ("optional".equalsIgnoreCase(SSLVerifyClient)) {
 566                value = SSL.SSL_CVERIFY_OPTIONAL;
 567            } else if ("require".equalsIgnoreCase(SSLVerifyClient)) {
 568                value = SSL.SSL_CVERIFY_REQUIRE;
 569            } else if ("optionalNoCA".equalsIgnoreCase(SSLVerifyClient)) {
 570                value = SSL.SSL_CVERIFY_OPTIONAL_NO_CA;
 571            }
 572            SSLContext.setVerify(sslContext, value, SSLVerifyDepth);
 573            // For now, sendfile is not supported with SSL
 574            useSendfile = false;
 575        }
 576    }
 577
 578    public long getJniSslContext() {
 579        return sslContext;
 580    }
 581
 582    /**
 583     * Start the APR endpoint, creating acceptor, poller and sendfile threads.
 584     */
 585    @Override
 586    public void startInternal() throws Exception {
 587
 588        if (!running) {
 589            running = true;
 590            paused = false;
 591
 592            // Create worker collection
 593            if (getExecutor() == null) {
 594                createExecutor();
 595            }
 596
 597            initializeConnectionLatch();
 598
 599            // Start poller thread
 600            poller = new Poller();
 601            poller.init();
 602            Thread pollerThread = new Thread(poller, getName() + "-Poller");
 603            pollerThread.setPriority(threadPriority);
 604            pollerThread.setDaemon(true);
 605            pollerThread.start();
 606
 607            // Start sendfile thread
 608            if (useSendfile) {
 609                sendfile = new Sendfile();
 610                sendfile.init();
 611                Thread sendfileThread =
 612                        new Thread(sendfile, getName() + "-Sendfile");
 613                sendfileThread.setPriority(threadPriority);
 614                sendfileThread.setDaemon(true);
 615                sendfileThread.start();
 616            }
 617
 618            startAcceptorThreads();
 619
 620            // Start async timeout thread
 621            asyncTimeout = new AsyncTimeout();
 622            Thread timeoutThread = new Thread(asyncTimeout,
 623                    getName() + "-AsyncTimeout");
 624            timeoutThread.setPriority(threadPriority);
 625            timeoutThread.setDaemon(true);
 626            timeoutThread.start();
 627        }
 628    }
 629
 630
 631    /**
 632     * Stop the endpoint. This will cause all processing threads to stop.
 633     */
 634    @Override
 635    public void stopInternal() {
 636        releaseConnectionLatch();
 637        if (!paused) {
 638            pause();
 639        }
 640        if (running) {
 641            running = false;
 642            poller.stop();
 643            asyncTimeout.stop();
 644            unlockAccept();
 645            for (AbstractEndpoint.Acceptor acceptor : acceptors) {
 646                long waitLeft = 10000;
 647                while (waitLeft > 0 &&
 648                        acceptor.getState() != AcceptorState.ENDED &&
 649                        serverSock != 0) {
 650                    try {
 651                        Thread.sleep(50);
 652                    } catch (InterruptedException e) {
 653                        // Ignore
 654                    }
 655                    waitLeft -= 50;
 656                }
 657                if (waitLeft == 0) {
 658                    log.warn(sm.getString("endpoint.warn.unlockAcceptorFailed",
 659                            acceptor.getThreadName()));
 660                   // If the Acceptor is still running force
 661                   // the hard socket close.
 662                   if (serverSock != 0) {
 663                       Socket.shutdown(serverSock, Socket.APR_SHUTDOWN_READ);
 664                       serverSock = 0;
 665                   }
 666                }
 667            }
 668            try {
 669                poller.destroy();
 670            } catch (Exception e) {
 671                // Ignore
 672            }
 673            poller = null;
 674            connections.clear();
 675            if (useSendfile) {
 676                try {
 677                    sendfile.destroy();
 678                } catch (Exception e) {
 679                    // Ignore
 680                }
 681                sendfile = null;
 682            }
 683        }
 684        shutdownExecutor();
 685    }
 686
 687
 688    /**
 689     * Deallocate APR memory pools, and close server socket.
 690     */
 691    @Override
 692    public void unbind() throws Exception {
 693        if (running) {
 694            stop();
 695        }
 696
 697        // Destroy pool if it was initialised
 698        if (serverSockPool != 0) {
 699            Pool.destroy(serverSockPool);
 700            serverSockPool = 0;
 701        }
 702
 703        // Close server socket if it was initialised
 704        if (serverSock != 0) {
 705            Socket.close(serverSock);
 706            serverSock = 0;
 707        }
 708
 709        sslContext = 0;
 710
 711        // Close all APR memory pools and resources if initialised
 712        if (rootPool != 0) {
 713            Pool.destroy(rootPool);
 714            rootPool = 0;
 715        }
 716
 717        handler.recycle();
 718    }
 719
 720
 721    // ------------------------------------------------------ Protected Methods
 722
 723    @Override
 724    protected AbstractEndpoint.Acceptor createAcceptor() {
 725        return new Acceptor();
 726    }
 727
 728
 729    /**
 730     * Process the specified connection.
 731     */
 732    protected boolean setSocketOptions(long socket) {
 733        // Process the connection
 734        int step = 1;
 735        try {
 736
 737            // 1: Set socket options: timeout, linger, etc
 738            if (socketProperties.getSoLingerOn() && socketProperties.getSoLingerTime() >= 0)
 739                Socket.optSet(socket, Socket.APR_SO_LINGER, socketProperties.getSoLingerTime());
 740            if (socketProperties.getTcpNoDelay())
 741                Socket.optSet(socket, Socket.APR_TCP_NODELAY, (socketProperties.getTcpNoDelay() ? 1 : 0));
 742            Socket.timeoutSet(socket, socketProperties.getSoTimeout() * 1000);
 743
 744            // 2: SSL handshake
 745            step = 2;
 746            if (sslContext != 0) {
 747                SSLSocket.attach(sslContext, socket);
 748                if (SSLSocket.handshake(socket) != 0) {
 749                    if (log.isDebugEnabled()) {
 750                        log.debug(sm.getString("endpoint.err.handshake") + ": " + SSL.getLastError());
 751                    }
 752                    return false;
 753                }
 754            }
 755
 756        } catch (Throwable t) {
 757            ExceptionUtils.handleThrowable(t);
 758            if (log.isDebugEnabled()) {
 759                if (step == 2) {
 760                    log.debug(sm.getString("endpoint.err.handshake"), t);
 761                } else {
 762                    log.debug(sm.getString("endpoint.err.unexpected"), t);
 763                }
 764            }
 765            // Tell to close the socket
 766            return false;
 767        }
 768        return true;
 769    }
 770
 771
 772    /**
 773     * Allocate a new poller of the specified size.
 774     */
 775    protected long allocatePoller(int size, long pool, int timeout) {
 776        try {
 777            return Poll.create(size, pool, 0, timeout * 1000);
 778        } catch (Error e) {
 779            if (Status.APR_STATUS_IS_EINVAL(e.getError())) {
 780                log.info(sm.getString("endpoint.poll.limitedpollsize", "" + size));
 781                return 0;
 782            } else {
 783                log.error(sm.getString("endpoint.poll.initfail"), e);
 784                return -1;
 785            }
 786        }
 787    }
 788
 789    /**
 790     * Process given socket. This is called when the socket has been
 791     * accepted.
 792     */
 793    protected boolean processSocketWithOptions(long socket) {
 794        try {
 795            // During shutdown, executor may be null - avoid NPE
 796            if (running) {
 797                if (log.isDebugEnabled()) {
 798                    log.debug("processSocketWithOptions(long): " + socket);
 799                }
 800                AprSocketWrapper wrapper =
 801                        new AprSocketWrapper(Long.valueOf(socket));
 802                wrapper.setKeepAliveLeft(getMaxKeepAliveRequests());
 803                connections.put(Long.valueOf(socket), wrapper);
 804                getExecutor().execute(new SocketWithOptionsProcessor(wrapper));
 805            }
 806        } catch (RejectedExecutionException x) {
 807            log.warn("Socket processing request was rejected for:"+socket,x);
 808            return false;
 809        } catch (Throwable t) {
 810            ExceptionUtils.handleThrowable(t);
 811            // This means we got an OOM or similar creating a thread, or that
 812            // the pool and its queue are full
 813            log.error(sm.getString("endpoint.process.fail"), t);
 814            return false;
 815        }
 816        return true;
 817    }
 818
 819
 820    /**
 821     * Process given socket. Called in non-comet mode, typically keep alive
 822     * or upgraded protocol.
 823     */
 824    public boolean processSocket(long socket, SocketStatus status) {
 825        try {
 826            Executor executor = getExecutor();
 827            if (executor == null) {
 828                log.warn(sm.getString("endpoint.warn.noExector",
 829                        Long.valueOf(socket), null));
 830            } else {
 831                SocketWrapper<Long> wrapper =
 832                        connections.get(Long.valueOf(socket));
 833                // Make sure connection hasn't been closed
 834                if (wrapper != null) {
 835                    executor.execute(new SocketProcessor(wrapper, status));
 836                }
 837            }
 838        } catch (RejectedExecutionException x) {
 839            log.warn("Socket processing request was rejected for:"+socket,x);
 840            return false;
 841        } catch (Throwable t) {
 842            ExceptionUtils.handleThrowable(t);
 843            // This means we got an OOM or similar creating a thread, or that
 844            // the pool and its queue are full
 845            log.error(sm.getString("endpoint.process.fail"), t);
 846            return false;
 847        }
 848        return true;
 849    }
 850
 851
 852    public boolean processSocketAsync(SocketWrapper<Long> socket,
 853            SocketStatus status) {
 854        try {
 855            synchronized (socket) {
 856                if (waitingRequests.remove(socket)) {
 857                    SocketProcessor proc = new SocketProcessor(socket, status);
 858                    ClassLoader loader = Thread.currentThread().getContextClassLoader();
 859                    try {
 860                        //threads should not be created by the webapp classloader
 861                        if (Constants.IS_SECURITY_ENABLED) {
 862                            PrivilegedAction<Void> pa = new PrivilegedSetTccl(
 863                                    getClass().getClassLoader());
 864                            AccessController.doPrivileged(pa);
 865                        } else {
 866                            Thread.currentThread().setContextClassLoader(
 867                                    getClass().getClassLoader());
 868                        }
 869                        Executor executor = getExecutor();
 870                        if (executor == null) {
 871                            log.warn(sm.getString("endpoint.warn.noExector",
 872                                    socket, status));
 873                            return false;
 874                        } else {
 875                            executor.execute(proc);
 876                        }
 877                    } finally {
 878                        if (Constants.IS_SECURITY_ENABLED) {
 879                            PrivilegedAction<Void> pa = new PrivilegedSetTccl(loader);
 880                            AccessController.doPrivileged(pa);
 881                        } else {
 882                            Thread.currentThread().setContextClassLoader(loader);
 883                        }
 884                    }
 885                }
 886            }
 887        } catch (RejectedExecutionException x) {
 888            log.warn("Socket processing request was rejected for: "+socket, x);
 889            return false;
 890        } catch (Throwable t) {
 891            ExceptionUtils.handleThrowable(t);
 892            // This means we got an OOM or similar creating a thread, or that
 893            // the pool and its queue are full
 894            log.error(sm.getString("endpoint.process.fail"), t);
 895            return false;
 896        }
 897        return true;
 898    }
 899
 900    private void destroySocket(long socket) {
 901        // If not running the socket will be destroyed by
 902        // parent pool or acceptor socket.
 903        // In any case disable double free which would cause JVM core.
 904
 905        // While the connector is running, destroySocket() will call
 906        // countDownConnection(). Once the connector is stopped, the latch is
 907        // removed so it does not matter that destroySocket() does not call
 908        // countDownConnection() in that case
 909        connections.remove(Long.valueOf(socket));
 910        destroySocket(socket, running);
 911    }
 912
 913    private void destroySocket(long socket, boolean doIt) {
 914        if (log.isDebugEnabled()) {
 915            String msg = "destroySocket(long,boolean): " + socket + " " + doIt;
 916            if (log.isTraceEnabled()) {
 917                log.trace(msg, new Exception());
 918            } else {
 919                log.debug(msg);
 920            }
 921        }
 922        // Be VERY careful if you call this method directly. If it is called
 923        // twice for the same socket the JVM will core. Currently this is only
 924        // called from Poller.closePollset() to ensure kept alive connections
 925        // are closed when calling stop() followed by start().
 926        if (doIt && socket != 0) {
 927            Socket.destroy(socket);
 928            countDownConnection();
 929        }
 930    }
 931
 932    @Override
 933    protected Log getLog() {
 934        return log;
 935    }
 936
 937    // --------------------------------------------------- Acceptor Inner Class
 938    /**
 939     * The background thread that listens for incoming TCP/IP connections and
 940     * hands them off to an appropriate processor.
 941     */
 942    protected class Acceptor extends AbstractEndpoint.Acceptor {
 943
 944        private final Log log = LogFactory.getLog(AprEndpoint.Acceptor.class);
 945
 946        @Override
 947        public void run() {
 948
 949            int errorDelay = 0;
 950
 951            // Loop until we receive a shutdown command
 952            while (running) {
 953
 954                // Loop if endpoint is paused
 955                while (paused && running) {
 956                    state = AcceptorState.PAUSED;
 957                    try {
 958                        Thread.sleep(50);
 959                    } catch (InterruptedException e) {
 960                        // Ignore
 961                    }
 962                }
 963
 964                if (!running) {
 965                    break;
 966                }
 967                state = AcceptorState.RUNNING;
 968
 969                try {
 970                    //if we have reached max connections, wait
 971                    countUpOrAwaitConnection();
 972
 973                    long socket = 0;
 974                    try {
 975                        // Accept the next incoming connection from the server
 976                        // socket
 977                        socket = Socket.accept(serverSock);
 978                    } catch (Exception e) {
 979                        //we didn't get a socket
 980                        countDownConnection();
 981                        // Introduce delay if necessary
 982                        errorDelay = handleExceptionWithDelay(errorDelay);
 983                        // re-throw
 984                        throw e;
 985                    }
 986                    // Successful accept, reset the error delay
 987                    errorDelay = 0;
 988
 989                    if (running && !paused) {
 990                        // Hand this socket off to an appropriate processor
 991                        if (!processSocketWithOptions(socket)) {
 992                            // Close socket and pool right away
 993                            destroySocket(socket);
 994                        }
 995                    } else {
 996                        // Close socket and pool right away
 997                        destroySocket(socket);
 998                    }
 999                } catch (Throwable t) {
1000                    ExceptionUtils.handleThrowable(t);
1001                    if (running) {
1002                        String msg = sm.getString("endpoint.accept.fail");
1003                        if (t instanceof Error) {
1004                            Error e = (Error) t;
1005                            if (e.getError() == 233) {
1006                                // Not an error on HP-UX so log as a warning
1007                                // so it can be filtered out on that platform
1008                                // See bug 50273
1009                                log.warn(msg, t);
1010                            } else {
1011                                log.error(msg, t);
1012                            }
1013                        } else {
1014                                log.error(msg, t);
1015                        }
1016                    }
1017                }
1018                // The processor will recycle itself when it finishes
1019            }
1020            state = AcceptorState.ENDED;
1021        }
1022    }
1023
1024
1025    /**
1026     * Async timeout thread
1027     */
1028    protected class AsyncTimeout implements Runnable {
1029
1030        private volatile boolean asyncTimeoutRunning = true;
1031
1032        /**
1033         * The background thread that checks async requests and fires the
1034         * timeout if there has been no activity.
1035         */
1036        @Override
1037        public void run() {
1038
1039            // Loop until we receive a shutdown command
1040            while (asyncTimeoutRunning) {
1041                try {
1042                    Thread.sleep(1000);
1043                } catch (InterruptedException e) {
1044                    // Ignore
1045                }
1046                long now = System.currentTimeMillis();
1047                Iterator<SocketWrapper<Long>> sockets =
1048                    waitingRequests.iterator();
1049                while (sockets.hasNext()) {
1050                    SocketWrapper<Long> socket = sockets.next();
1051                    if (socket.async) {
1052                        long access = socket.getLastAccess();
1053                        if (socket.getTimeout() > 0 &&
1054                                (now-access)>socket.getTimeout()) {
1055                            processSocketAsync(socket,SocketStatus.TIMEOUT);
1056                        }
1057                    }
1058                }
1059
1060                // Loop if endpoint is paused
1061                while (paused && asyncTimeoutRunning) {
1062                    try {
1063                        Thread.sleep(1000);
1064                    } catch (InterruptedException e) {
1065                        // Ignore
1066                    }
1067                }
1068
1069            }
1070        }
1071
1072
1073        protected void stop() {
1074            asyncTimeoutRunning = false;
1075        }
1076    }
1077
1078
1079    // -------------------------------------------------- SocketInfo Inner Class
1080
1081    public static class SocketInfo {
1082        public long socket;
1083        public int timeout;
1084        public int flags;
1085        public boolean read() {
1086            return (flags & Poll.APR_POLLIN) == Poll.APR_POLLIN;
1087        }
1088        public boolean write() {
1089            return (flags & Poll.APR_POLLOUT) == Poll.APR_POLLOUT;
1090        }
1091        public static int merge(int flag1, int flag2) {
1092            return ((flag1 & Poll.APR_POLLIN) | (flag2 & Poll.APR_POLLIN))
1093                | ((flag1 & Poll.APR_POLLOUT) | (flag2 & Poll.APR_POLLOUT));
1094        }
1095        @Override
1096        public String toString() {
1097            StringBuilder sb = new StringBuilder();
1098            sb.append("Socket: [");
1099            sb.append(socket);
1100            sb.append("], timeout: [");
1101            sb.append(timeout);
1102            sb.append("], flags: [");
1103            sb.append(flags);
1104            return sb.toString();
1105        }
1106    }
1107
1108
1109    // ---------------------------------------------- SocketTimeouts Inner Class
1110
1111    public class SocketTimeouts {
1112        protected int size;
1113
1114        protected long[] sockets;
1115        protected long[] timeouts;
1116        protected int pos = 0;
1117
1118        public SocketTimeouts(int size) {
1119            this.size = 0;
1120            sockets = new long[size];
1121            timeouts = new long[size];
1122        }
1123
1124        public void add(long socket, long timeout) {
1125            sockets[size] = socket;
1126            timeouts[size] = timeout;
1127            size++;
1128        }
1129
1130        public boolean remove(long socket) {
1131            for (int i = 0; i < size; i++) {
1132                if (sockets[i] == socket) {
1133                    sockets[i] = sockets[size - 1];
1134                    timeouts[i] = timeouts[size - 1];
1135                    size--;
1136                    return true;
1137                }
1138            }
1139            return false;
1140        }
1141
1142        public long check(long date) {
1143            while (pos < size) {
1144                if (date >= timeouts[pos]) {
1145                    long result = sockets[pos];
1146                    sockets[pos] = sockets[size - 1];
1147                    timeouts[pos] = timeouts[size - 1];
1148                    size--;
1149                    return result;
1150                }
1151                pos++;
1152            }
1153            pos = 0;
1154            return 0;
1155        }
1156
1157    }
1158
1159
1160    // -------------------------------------------------- SocketList Inner Class
1161
1162    public class SocketList {
1163        protected int size;
1164        protected int pos;
1165
1166        protected long[] sockets;
1167        protected int[] timeouts;
1168        protected int[] flags;
1169
1170        protected SocketInfo info = new SocketInfo();
1171
1172        public SocketList(int size) {
1173            this.size = 0;
1174            pos = 0;
1175            sockets = new long[size];
1176            timeouts = new int[size];
1177            flags = new int[size];
1178        }
1179
1180        public int size() {
1181            return this.size;
1182        }
1183
1184        public SocketInfo get() {
1185            if (pos == size) {
1186                return null;
1187            } else {
1188                info.socket = sockets[pos];
1189                info.timeout = timeouts[pos];
1190                info.flags = flags[pos];
1191                pos++;
1192                return info;
1193            }
1194        }
1195
1196        public void clear() {
1197            size = 0;
1198            pos = 0;
1199        }
1200
1201        public boolean add(long socket, int timeout, int flag) {
1202            if (size == sockets.length) {
1203                return false;
1204            } else {
1205                for (int i = 0; i < size; i++) {
1206                    if (sockets[i] == socket) {
1207                        flags[i] = SocketInfo.merge(flags[i], flag);
1208                        return true;
1209                    }
1210                }
1211                sockets[size] = socket;
1212                timeouts[size] = timeout;
1213                flags[size] = flag;
1214                size++;
1215                return true;
1216            }
1217        }
1218
1219        public void duplicate(SocketList copy) {
1220            copy.size = size;
1221            copy.pos = pos;
1222            System.arraycopy(sockets, 0, copy.sockets, 0, size);
1223            System.arraycopy(timeouts, 0, copy.timeouts, 0, size);
1224            System.arraycopy(flags, 0, copy.flags, 0, size);
1225        }
1226
1227    }
1228
1229    // ------------------------------------------------------ Poller Inner Class
1230
1231   public class Poller implements Runnable {
1232
1233        /**
1234         * Pointers to the pollers.
1235         */
1236        protected long[] pollers = null;
1237
1238        /**
1239         * Actual poller size.
1240         */
1241        protected int actualPollerSize = 0;
1242
1243        /**
1244         * Amount of spots left in the poller.
1245         */
1246        protected int[] pollerSpace = null;
1247
1248        /**
1249         * Amount of low level pollers in use by this poller.
1250         */
1251        protected int pollerCount;
1252
1253        /**
1254         * Timeout value for the poll call.
1255         */
1256        protected int pollerTime;
1257
1258        /**
1259         * Root pool.
1260         */
1261        protected long pool = 0;
1262
1263        /**
1264         * Socket descriptors.
1265         */
1266        protected long[] desc;
1267
1268        /**
1269         * List of sockets to be added to the poller.
1270         */
1271        protected SocketList addList = null;
1272
1273        /**
1274         * List of sockets to be added to the poller.
1275         */
1276        protected SocketList localAddList = null;
1277
1278        /**
1279         * Structure used for storing timeouts.
1280         */
1281        protected SocketTimeouts timeouts = null;
1282
1283
1284        /**
1285         * Last run of maintain. Maintain will run usually every 5s.
1286         */
1287        protected long lastMaintain = System.currentTimeMillis();
1288
1289
1290        /**
1291         * Amount of connections inside this poller.
1292         */
1293        protected int connectionCount = 0;
1294        public int getConnectionCount() { return connectionCount; }
1295
1296
1297        private volatile boolean pollerRunning = true;
1298
1299        /**
1300         * Create the poller. With some versions of APR, the maximum poller size
1301         * will be 62 (recompiling APR is necessary to remove this limitation).
1302         */
1303        protected void init() {
1304
1305            pool = Pool.create(serverSockPool);
1306
1307            // Single poller by default
1308            int defaultPollerSize = getMaxConnections();
1309
1310            if ((OS.IS_WIN32 || OS.IS_WIN64) && (defaultPollerSize > 1024)) {
1311                // The maximum per poller to get reasonable performance is 1024
1312                // Adjust poller size so that it won't reach the limit. This is
1313                // a limitation of XP / Server 2003 that has been fixed in
1314                // Vista / Server 2008 onwards.
1315                actualPollerSize = 1024;
1316            } else {
1317                actualPollerSize = defaultPollerSize;
1318            }
1319
1320            timeouts = new SocketTimeouts(defaultPollerSize);
1321
1322            // At the moment, setting the timeout is useless, but it could get
1323            // used again as the normal poller could be faster using maintain.
1324            // It might not be worth bothering though.
1325            long pollset = allocatePoller(actualPollerSize, pool, -1);
1326            if (pollset == 0 && actualPollerSize > 1024) {
1327                actualPollerSize = 1024;
1328                pollset = allocatePoller(actualPollerSize, pool, -1);
1329            }
1330            if (pollset == 0) {
1331                actualPollerSize = 62;
1332                pollset = allocatePoller(actualPollerSize, pool, -1);
1333            }
1334
1335            pollerCount = defaultPollerSize / actualPollerSize;
1336            pollerTime = pollTime / pollerCount;
1337
1338            pollers = new long[pollerCount];
1339            pollers[0] = pollset;
1340            for (int i = 1; i < pollerCount; i++) {
1341                pollers[i] = allocatePoller(actualPollerSize, pool, -1);
1342            }
1343
1344            pollerSpace = new int[pollerCount];
1345            for (int i = 0; i < pollerCount; i++) {
1346                pollerSpace[i] = actualPollerSize;
1347            }
1348
1349            desc = new long[actualPollerSize * 2];
1350            connectionCount = 0;
1351            addList = new SocketList(defaultPollerSize);
1352            localAddList = new SocketList(defaultPollerSize);
1353        }
1354
1355
1356        /*
1357         * This method is synchronized so that it is not possible for a socket
1358         * to be added to the Poller's addList once this method has completed.
1359         */
1360        protected synchronized void stop() {
1361            pollerRunning = false;
1362        }
1363
1364
1365        /**
1366         * Destroy the poller.
1367         */
1368        protected void destroy() {
1369            // Wait for pollerTime before doing anything, so that the poller
1370            // threads exit, otherwise parallel destruction of sockets which are
1371            // still in the poller can cause problems
1372            try {
1373                synchronized (this) {
1374                    this.notify();
1375                    this.wait(pollTime / 1000);
1376                }
1377            } catch (InterruptedException e) {
1378                // Ignore
1379            }
1380            // Close all sockets in the add queue
1381            SocketInfo info = addList.get();
1382            while (info != null) {
1383                boolean comet =
1384                        connections.get(Long.valueOf(info.socket)).isComet();
1385                if (!comet || (comet && !processSocket(
1386                        info.socket, SocketStatus.STOP))) {
1387                    destroySocket(info.socket);
1388                }
1389                info = addList.get();
1390            }
1391            addList.clear();
1392            // Close all sockets still in the poller
1393            for (int i = 0; i < pollerCount; i++) {
1394                int rv = Poll.pollset(pollers[i], desc);
1395                if (rv > 0) {
1396                    for (int n = 0; n < rv; n++) {
1397                        boolean comet = connections.get(
1398                                Long.valueOf(desc[n*2+1])).isComet();
1399                        if (!comet || (comet && !processSocket(
1400                                desc[n*2+1], SocketStatus.STOP))) {
1401                            destroySocket(desc[n*2+1], true);
1402                        }
1403                    }
1404                }
1405            }
1406            Pool.destroy(pool);
1407            connectionCount = 0;
1408        }
1409
1410
1411        /**
1412         * Add specified socket and associated pool to the poller. The socket
1413         * will be added to a temporary array, and polled first after a maximum
1414         * amount of time equal to pollTime (in most cases, latency will be much
1415         * lower, however). Note: If both read and write are false, the socket
1416         * will only be checked for timeout; if the socket was already present
1417         * in the poller, a callback event will be generated and the socket will
1418         * be removed from the poller.
1419         *
1420         * @param socket to add to the poller
1421         * @param timeout to use for this connection
1422         * @param read to do read polling
1423         * @param write to do write polling
1424         */
1425        public void add(long socket, int timeout, boolean read, boolean write) {
1426            add(socket, timeout,
1427                    (read ? Poll.APR_POLLIN : 0) |
1428                    (write ? Poll.APR_POLLOUT : 0));
1429        }
1430
1431        private void add(long socket, int timeout, int flags) {
1432            if (log.isDebugEnabled()) {
1433                String msg = "Poller.add(long,int,int) " + socket + " " +
1434                        timeout + " " + flags;
1435                if (log.isTraceEnabled()) {
1436                    log.trace(msg, new Exception());
1437                } else {
1438                    log.debug(msg);
1439                }
1440            }
1441            if (timeout <= 0) {
1442                // Always put a timeout in
1443                timeout = Integer.MAX_VALUE;
1444            }
1445            boolean ok = false;
1446            synchronized (this) {
1447                // Add socket to the list. Newly added sockets

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