PageRenderTime 92ms CodeModel.GetById 3ms app.highlight 75ms RepoModel.GetById 1ms app.codeStats 0ms

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

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

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