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