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

https://github.com/enson16855/tomcat · Java · 1174 lines · 823 code · 157 blank · 194 comment · 183 complexity · 58ffb6b2294c872a3f8dd2d7753f7aa1 MD5 · raw 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. package org.apache.tomcat.util.net;
  18. import java.io.File;
  19. import java.io.IOException;
  20. import java.net.InetSocketAddress;
  21. import java.net.SocketAddress;
  22. import java.net.StandardSocketOptions;
  23. import java.nio.ByteBuffer;
  24. import java.nio.channels.AsynchronousChannelGroup;
  25. import java.nio.channels.AsynchronousServerSocketChannel;
  26. import java.nio.channels.AsynchronousSocketChannel;
  27. import java.nio.channels.ClosedChannelException;
  28. import java.nio.channels.CompletionHandler;
  29. import java.nio.channels.FileChannel;
  30. import java.nio.file.StandardOpenOption;
  31. import java.util.concurrent.Executor;
  32. import java.util.concurrent.ExecutorService;
  33. import java.util.concurrent.RejectedExecutionException;
  34. import java.util.concurrent.TimeUnit;
  35. import javax.net.ssl.KeyManager;
  36. import javax.net.ssl.SSLContext;
  37. import javax.net.ssl.SSLEngine;
  38. import javax.net.ssl.SSLSessionContext;
  39. import javax.net.ssl.X509KeyManager;
  40. import org.apache.juli.logging.Log;
  41. import org.apache.juli.logging.LogFactory;
  42. import org.apache.tomcat.util.ExceptionUtils;
  43. import org.apache.tomcat.util.collections.SynchronizedStack;
  44. import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
  45. import org.apache.tomcat.util.net.SecureNio2Channel.ApplicationBufferHandler;
  46. import org.apache.tomcat.util.net.jsse.NioX509KeyManager;
  47. /**
  48. * NIO2 endpoint.
  49. */
  50. public class Nio2Endpoint extends AbstractEndpoint<Nio2Channel> {
  51. // -------------------------------------------------------------- Constants
  52. private static final Log log = LogFactory.getLog(Nio2Endpoint.class);
  53. // ----------------------------------------------------------------- Fields
  54. /**
  55. * Server socket "pointer".
  56. */
  57. private AsynchronousServerSocketChannel serverSock = null;
  58. /**
  59. * use send file
  60. */
  61. private boolean useSendfile = true;
  62. /**
  63. * The size of the OOM parachute.
  64. */
  65. private int oomParachute = 1024*1024;
  66. /**
  67. * Allows detecting if a completion handler completes inline.
  68. */
  69. private static ThreadLocal<Boolean> inlineCompletion = new ThreadLocal<>();
  70. /**
  71. * Thread group associated with the server socket.
  72. */
  73. private AsynchronousChannelGroup threadGroup = null;
  74. private volatile boolean allClosed;
  75. /**
  76. * The oom parachute, when an OOM error happens,
  77. * will release the data, giving the JVM instantly
  78. * a chunk of data to be able to recover with.
  79. */
  80. private byte[] oomParachuteData = null;
  81. /**
  82. * Make sure this string has already been allocated
  83. */
  84. private static final String oomParachuteMsg =
  85. "SEVERE:Memory usage is low, parachute is non existent, your system may start failing.";
  86. /**
  87. * Keep track of OOM warning messages.
  88. */
  89. private long lastParachuteCheck = System.currentTimeMillis();
  90. /**
  91. * Cache for SocketProcessor objects
  92. */
  93. private SynchronizedStack<SocketProcessor> processorCache;
  94. /**
  95. * Cache for socket wrapper objects
  96. */
  97. private SynchronizedStack<Nio2SocketWrapper> socketWrapperCache;
  98. /**
  99. * Bytebuffer cache, each channel holds a set of buffers (two, except for SSL holds four)
  100. */
  101. private SynchronizedStack<Nio2Channel> nioChannels;
  102. // ------------------------------------------------------------- Properties
  103. /**
  104. * Use the object caches to reduce GC at the expense of additional memory use.
  105. */
  106. private boolean useCaches = false;
  107. public void setUseCaches(boolean useCaches) { this.useCaches = useCaches; }
  108. public boolean getUseCaches() { return useCaches; }
  109. /**
  110. * Priority of the poller threads.
  111. */
  112. private int pollerThreadPriority = Thread.NORM_PRIORITY;
  113. public void setPollerThreadPriority(int pollerThreadPriority) { this.pollerThreadPriority = pollerThreadPriority; }
  114. public int getPollerThreadPriority() { return pollerThreadPriority; }
  115. /**
  116. * Handling of accepted sockets.
  117. */
  118. private Handler handler = null;
  119. public void setHandler(Handler handler ) { this.handler = handler; }
  120. public Handler getHandler() { return handler; }
  121. /**
  122. * Allow comet request handling.
  123. */
  124. private boolean useComet = true;
  125. public void setUseComet(boolean useComet) { this.useComet = useComet; }
  126. @Override
  127. public boolean getUseComet() { return useComet; }
  128. @Override
  129. public boolean getUseCometTimeout() { return getUseComet(); }
  130. @Override
  131. public boolean getUsePolling() { return true; } // Always supported
  132. public void setSocketProperties(SocketProperties socketProperties) {
  133. this.socketProperties = socketProperties;
  134. }
  135. public void setUseSendfile(boolean useSendfile) {
  136. this.useSendfile = useSendfile;
  137. }
  138. /**
  139. * Is deferAccept supported?
  140. */
  141. @Override
  142. public boolean getDeferAccept() {
  143. // Not supported
  144. return false;
  145. }
  146. public void setOomParachute(int oomParachute) {
  147. this.oomParachute = oomParachute;
  148. }
  149. public void setOomParachuteData(byte[] oomParachuteData) {
  150. this.oomParachuteData = oomParachuteData;
  151. }
  152. private SSLContext sslContext = null;
  153. public SSLContext getSSLContext() { return sslContext;}
  154. public void setSSLContext(SSLContext c) { sslContext = c;}
  155. private String[] enabledCiphers;
  156. private String[] enabledProtocols;
  157. /**
  158. * Port in use.
  159. */
  160. @Override
  161. public int getLocalPort() {
  162. AsynchronousServerSocketChannel ssc = serverSock;
  163. if (ssc == null) {
  164. return -1;
  165. } else {
  166. try {
  167. SocketAddress sa = ssc.getLocalAddress();
  168. if (sa != null && sa instanceof InetSocketAddress) {
  169. return ((InetSocketAddress) sa).getPort();
  170. } else {
  171. return -1;
  172. }
  173. } catch (IOException e) {
  174. return -1;
  175. }
  176. }
  177. }
  178. @Override
  179. public String[] getCiphersUsed() {
  180. return enabledCiphers;
  181. }
  182. // --------------------------------------------------------- OOM Parachute Methods
  183. protected void checkParachute() {
  184. boolean para = reclaimParachute(false);
  185. if (!para && (System.currentTimeMillis()-lastParachuteCheck)>10000) {
  186. try {
  187. log.fatal(oomParachuteMsg);
  188. }catch (Throwable t) {
  189. ExceptionUtils.handleThrowable(t);
  190. System.err.println(oomParachuteMsg);
  191. }
  192. lastParachuteCheck = System.currentTimeMillis();
  193. }
  194. }
  195. protected boolean reclaimParachute(boolean force) {
  196. if ( oomParachuteData != null ) return true;
  197. if ( oomParachute > 0 && ( force || (Runtime.getRuntime().freeMemory() > (oomParachute*2))) )
  198. oomParachuteData = new byte[oomParachute];
  199. return oomParachuteData != null;
  200. }
  201. protected void releaseCaches() {
  202. if (useCaches) {
  203. this.socketWrapperCache.clear();
  204. this.nioChannels.clear();
  205. this.processorCache.clear();
  206. }
  207. if ( handler != null ) handler.recycle();
  208. }
  209. // --------------------------------------------------------- Public Methods
  210. /**
  211. * Number of keepalive sockets.
  212. */
  213. public int getKeepAliveCount() {
  214. // For this connector, only the overall connection count is relevant
  215. return -1;
  216. }
  217. // ----------------------------------------------- Public Lifecycle Methods
  218. /**
  219. * Initialize the endpoint.
  220. */
  221. @Override
  222. public void bind() throws Exception {
  223. // Create worker collection
  224. if ( getExecutor() == null ) {
  225. createExecutor();
  226. }
  227. if (getExecutor() instanceof ExecutorService) {
  228. threadGroup = AsynchronousChannelGroup.withThreadPool((ExecutorService) getExecutor());
  229. }
  230. // AsynchronousChannelGroup currently needs exclusive access to its executor service
  231. if (!internalExecutor) {
  232. log.warn(sm.getString("endpoint.nio2.exclusiveExecutor"));
  233. }
  234. serverSock = AsynchronousServerSocketChannel.open(threadGroup);
  235. socketProperties.setProperties(serverSock);
  236. InetSocketAddress addr = (getAddress()!=null?new InetSocketAddress(getAddress(),getPort()):new InetSocketAddress(getPort()));
  237. serverSock.bind(addr,getBacklog());
  238. // Initialize thread count defaults for acceptor, poller
  239. if (acceptorThreadCount == 0) {
  240. // NIO2 does not allow any form of IO concurrency
  241. acceptorThreadCount = 1;
  242. }
  243. // Initialize SSL if needed
  244. if (isSSLEnabled()) {
  245. SSLUtil sslUtil = handler.getSslImplementation().getSSLUtil(this);
  246. sslContext = sslUtil.createSSLContext();
  247. sslContext.init(wrap(sslUtil.getKeyManagers()),
  248. sslUtil.getTrustManagers(), null);
  249. SSLSessionContext sessionContext =
  250. sslContext.getServerSessionContext();
  251. if (sessionContext != null) {
  252. sslUtil.configureSessionContext(sessionContext);
  253. }
  254. // Determine which cipher suites and protocols to enable
  255. enabledCiphers = sslUtil.getEnableableCiphers(sslContext);
  256. enabledProtocols = sslUtil.getEnableableProtocols(sslContext);
  257. }
  258. if (oomParachute>0) reclaimParachute(true);
  259. }
  260. public KeyManager[] wrap(KeyManager[] managers) {
  261. if (managers==null) return null;
  262. KeyManager[] result = new KeyManager[managers.length];
  263. for (int i=0; i<result.length; i++) {
  264. if (managers[i] instanceof X509KeyManager && getKeyAlias()!=null) {
  265. result[i] = new NioX509KeyManager((X509KeyManager)managers[i],getKeyAlias());
  266. } else {
  267. result[i] = managers[i];
  268. }
  269. }
  270. return result;
  271. }
  272. /**
  273. * Start the NIO endpoint, creating acceptor, poller threads.
  274. */
  275. @Override
  276. public void startInternal() throws Exception {
  277. if (!running) {
  278. allClosed = false;
  279. running = true;
  280. paused = false;
  281. // Create worker collection
  282. if ( getExecutor() == null ) {
  283. createExecutor();
  284. }
  285. if (useCaches) {
  286. processorCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
  287. socketProperties.getProcessorCache());
  288. socketWrapperCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
  289. socketProperties.getSocketWrapperCache());
  290. nioChannels = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
  291. socketProperties.getBufferPool());
  292. }
  293. initializeConnectionLatch();
  294. startAcceptorThreads();
  295. setAsyncTimeout(new AsyncTimeout());
  296. Thread timeoutThread = new Thread(getAsyncTimeout(), getName() + "-AsyncTimeout");
  297. timeoutThread.setPriority(threadPriority);
  298. timeoutThread.setDaemon(true);
  299. timeoutThread.start();
  300. }
  301. }
  302. /**
  303. * Stop the endpoint. This will cause all processing threads to stop.
  304. */
  305. @Override
  306. public void stopInternal() {
  307. releaseConnectionLatch();
  308. if (!paused) {
  309. pause();
  310. }
  311. if (running) {
  312. running = false;
  313. getAsyncTimeout().stop();
  314. unlockAccept();
  315. }
  316. // Use the executor to avoid binding the main thread if something bad
  317. // occurs and unbind will also wait for a bit for it to complete
  318. getExecutor().execute(new Runnable() {
  319. @Override
  320. public void run() {
  321. // Timeout any pending async request
  322. for (SocketWrapper<Nio2Channel> socket : waitingRequests) {
  323. processSocket(socket, SocketStatus.TIMEOUT, false);
  324. }
  325. // Then close all active connections if any remains
  326. try {
  327. handler.closeAll();
  328. } catch (Throwable t) {
  329. ExceptionUtils.handleThrowable(t);
  330. } finally {
  331. allClosed = true;
  332. }
  333. }
  334. });
  335. if (useCaches) {
  336. socketWrapperCache.clear();
  337. nioChannels.clear();
  338. processorCache.clear();
  339. }
  340. }
  341. /**
  342. * Deallocate NIO memory pools, and close server socket.
  343. */
  344. @Override
  345. public void unbind() throws Exception {
  346. if (running) {
  347. stop();
  348. }
  349. // Close server socket
  350. serverSock.close();
  351. serverSock = null;
  352. sslContext = null;
  353. // Unlike other connectors, the thread pool is tied to the server socket
  354. shutdownExecutor();
  355. releaseCaches();
  356. }
  357. @Override
  358. public void shutdownExecutor() {
  359. if (threadGroup != null && internalExecutor) {
  360. try {
  361. long timeout = getExecutorTerminationTimeoutMillis();
  362. while (timeout > 0 && !allClosed) {
  363. timeout -= 100;
  364. Thread.sleep(100);
  365. }
  366. threadGroup.shutdownNow();
  367. if (timeout > 0) {
  368. threadGroup.awaitTermination(timeout, TimeUnit.MILLISECONDS);
  369. }
  370. } catch (IOException e) {
  371. getLog().warn(sm.getString("endpoint.warn.executorShutdown", getName()), e);
  372. } catch (InterruptedException e) {
  373. // Ignore
  374. }
  375. if (!threadGroup.isTerminated()) {
  376. getLog().warn(sm.getString("endpoint.warn.executorShutdown", getName()));
  377. }
  378. threadGroup = null;
  379. }
  380. // Mostly to cleanup references
  381. super.shutdownExecutor();
  382. }
  383. // ------------------------------------------------------ Protected Methods
  384. public int getWriteBufSize() {
  385. return socketProperties.getTxBufSize();
  386. }
  387. public int getReadBufSize() {
  388. return socketProperties.getRxBufSize();
  389. }
  390. @Override
  391. public boolean getUseSendfile() {
  392. return useSendfile;
  393. }
  394. public int getOomParachute() {
  395. return oomParachute;
  396. }
  397. public byte[] getOomParachuteData() {
  398. return oomParachuteData;
  399. }
  400. @Override
  401. protected AbstractEndpoint.Acceptor createAcceptor() {
  402. return new Acceptor();
  403. }
  404. /**
  405. * Process the specified connection.
  406. */
  407. protected boolean setSocketOptions(AsynchronousSocketChannel socket) {
  408. // Process the connection
  409. try {
  410. socketProperties.setProperties(socket);
  411. Nio2Channel channel = (useCaches) ? nioChannels.pop() : null;
  412. if (channel == null) {
  413. // SSL setup
  414. if (sslContext != null) {
  415. SSLEngine engine = createSSLEngine();
  416. int appBufferSize = engine.getSession().getApplicationBufferSize();
  417. NioBufferHandler bufhandler = new NioBufferHandler(
  418. Math.max(appBufferSize, socketProperties.getAppReadBufSize()),
  419. Math.max(appBufferSize, socketProperties.getAppWriteBufSize()),
  420. socketProperties.getDirectBuffer());
  421. channel = new SecureNio2Channel(engine, bufhandler, this);
  422. } else {
  423. NioBufferHandler bufhandler = new NioBufferHandler(
  424. socketProperties.getAppReadBufSize(),
  425. socketProperties.getAppWriteBufSize(),
  426. socketProperties.getDirectBuffer());
  427. channel = new Nio2Channel(bufhandler);
  428. }
  429. } else {
  430. if (sslContext != null) {
  431. SSLEngine engine = createSSLEngine();
  432. ((SecureNio2Channel) channel).setSSLEngine(engine);
  433. }
  434. }
  435. Nio2SocketWrapper socketWrapper = (useCaches) ? socketWrapperCache.pop() : null;
  436. if (socketWrapper == null) {
  437. socketWrapper = new Nio2SocketWrapper(channel);
  438. }
  439. channel.reset(socket, socketWrapper);
  440. socketWrapper.reset(channel, getSocketProperties().getSoTimeout());
  441. socketWrapper.setKeepAliveLeft(Nio2Endpoint.this.getMaxKeepAliveRequests());
  442. socketWrapper.setSecure(isSSLEnabled());
  443. if (sslContext != null) {
  444. // Use the regular processing, as the first handshake needs to be done there
  445. processSocket(socketWrapper, SocketStatus.OPEN_READ, true);
  446. } else {
  447. // Wait until some bytes are available to start the real processing
  448. awaitBytes(socketWrapper);
  449. }
  450. } catch (Throwable t) {
  451. ExceptionUtils.handleThrowable(t);
  452. try {
  453. log.error("",t);
  454. } catch (Throwable tt) {
  455. ExceptionUtils.handleThrowable(t);
  456. }
  457. // Tell to close the socket
  458. return false;
  459. }
  460. return true;
  461. }
  462. protected SSLEngine createSSLEngine() {
  463. SSLEngine engine = sslContext.createSSLEngine();
  464. if ("false".equals(getClientAuth())) {
  465. engine.setNeedClientAuth(false);
  466. engine.setWantClientAuth(false);
  467. } else if ("true".equals(getClientAuth()) || "yes".equals(getClientAuth())){
  468. engine.setNeedClientAuth(true);
  469. } else if ("want".equals(getClientAuth())) {
  470. engine.setWantClientAuth(true);
  471. }
  472. engine.setUseClientMode(false);
  473. engine.setEnabledCipherSuites(enabledCiphers);
  474. engine.setEnabledProtocols(enabledProtocols);
  475. handler.onCreateSSLEngine(engine);
  476. return engine;
  477. }
  478. /**
  479. * Returns true if a worker thread is available for processing.
  480. * @return boolean
  481. */
  482. protected boolean isWorkerAvailable() {
  483. return true;
  484. }
  485. @Override
  486. public void processSocket(SocketWrapper<Nio2Channel> socketWrapper,
  487. SocketStatus socketStatus, boolean dispatch) {
  488. processSocket0(socketWrapper, socketStatus, dispatch);
  489. }
  490. protected boolean processSocket0(SocketWrapper<Nio2Channel> socketWrapper, SocketStatus status, boolean dispatch) {
  491. try {
  492. SocketProcessor sc = (useCaches) ? processorCache.pop() : null;
  493. if (sc == null) {
  494. sc = new SocketProcessor(socketWrapper, status);
  495. } else {
  496. sc.reset(socketWrapper, status);
  497. }
  498. Executor executor = getExecutor();
  499. if (dispatch && executor != null) {
  500. executor.execute(sc);
  501. } else {
  502. sc.run();
  503. }
  504. } catch (RejectedExecutionException ree) {
  505. log.debug(sm.getString("endpoint.executor.fail", socketWrapper), ree);
  506. return false;
  507. } catch (Throwable t) {
  508. ExceptionUtils.handleThrowable(t);
  509. // This means we got an OOM or similar creating a thread, or that
  510. // the pool and its queue are full
  511. log.error(sm.getString("endpoint.process.fail"), t);
  512. return false;
  513. }
  514. return true;
  515. }
  516. public void closeSocket(SocketWrapper<Nio2Channel> socket, SocketStatus status) {
  517. if (socket == null) {
  518. return;
  519. }
  520. try {
  521. if (socket.isComet() && status != null) {
  522. socket.setComet(false);//to avoid a loop
  523. if (status == SocketStatus.TIMEOUT) {
  524. if (processSocket0(socket, status, true)) {
  525. return; // don't close on comet timeout
  526. }
  527. } else {
  528. // Don't dispatch if the lines below are canceling the key
  529. processSocket0(socket, status, false);
  530. }
  531. }
  532. handler.release(socket);
  533. try {
  534. if (socket.getSocket() != null) {
  535. socket.getSocket().close(true);
  536. }
  537. } catch (Exception e){
  538. if (log.isDebugEnabled()) {
  539. log.debug(sm.getString(
  540. "endpoint.debug.socketCloseFail"), e);
  541. }
  542. }
  543. Nio2SocketWrapper nio2Socket = (Nio2SocketWrapper) socket;
  544. try {
  545. if (nio2Socket.getSendfileData() != null
  546. && nio2Socket.getSendfileData().fchannel != null
  547. && nio2Socket.getSendfileData().fchannel.isOpen()) {
  548. nio2Socket.getSendfileData().fchannel.close();
  549. }
  550. } catch (Exception ignore) {
  551. }
  552. nio2Socket.reset(null, -1);
  553. countDownConnection();
  554. } catch (Throwable e) {
  555. ExceptionUtils.handleThrowable(e);
  556. if (log.isDebugEnabled()) log.error("",e);
  557. }
  558. }
  559. @Override
  560. protected Log getLog() {
  561. return log;
  562. }
  563. // --------------------------------------------------- Acceptor Inner Class
  564. /**
  565. * With NIO2, the main acceptor thread only initiates the initial accept
  566. * but periodically checks that the connector is still accepting (if not
  567. * it will attempt to start again). It is also responsible for periodic
  568. * checks of async timeouts, rather than use a dedicated thread for that.
  569. */
  570. protected class Acceptor extends AbstractEndpoint.Acceptor {
  571. @Override
  572. public void run() {
  573. int errorDelay = 0;
  574. // Loop until we receive a shutdown command
  575. while (running) {
  576. // Loop if endpoint is paused
  577. while (paused && running) {
  578. state = AcceptorState.PAUSED;
  579. try {
  580. Thread.sleep(50);
  581. } catch (InterruptedException e) {
  582. // Ignore
  583. }
  584. }
  585. if (!running) {
  586. break;
  587. }
  588. state = AcceptorState.RUNNING;
  589. try {
  590. //if we have reached max connections, wait
  591. countUpOrAwaitConnection();
  592. AsynchronousSocketChannel socket = null;
  593. try {
  594. // Accept the next incoming connection from the server
  595. // socket
  596. socket = serverSock.accept().get();
  597. } catch (Exception e) {
  598. countDownConnection();
  599. if (running) {
  600. // Introduce delay if necessary
  601. errorDelay = handleExceptionWithDelay(errorDelay);
  602. // re-throw
  603. throw e;
  604. } else {
  605. break;
  606. }
  607. }
  608. // Successful accept, reset the error delay
  609. errorDelay = 0;
  610. // Configure the socket
  611. if (running && !paused) {
  612. // Hand this socket off to an appropriate processor
  613. if (!setSocketOptions(socket)) {
  614. countDownConnection();
  615. closeSocket(socket);
  616. }
  617. } else {
  618. countDownConnection();
  619. // Close socket right away
  620. closeSocket(socket);
  621. }
  622. } catch (Throwable t) {
  623. ExceptionUtils.handleThrowable(t);
  624. log.error(sm.getString("endpoint.accept.fail"), t);
  625. }
  626. }
  627. state = AcceptorState.ENDED;
  628. }
  629. }
  630. private void closeSocket(AsynchronousSocketChannel socket) {
  631. try {
  632. socket.close();
  633. } catch (IOException ioe) {
  634. if (log.isDebugEnabled()) {
  635. log.debug("", ioe);
  636. }
  637. }
  638. }
  639. public static class Nio2SocketWrapper extends SocketWrapper<Nio2Channel> {
  640. private SendfileData sendfileData = null;
  641. private boolean upgradeInit = false;
  642. public Nio2SocketWrapper(Nio2Channel channel) {
  643. super(channel);
  644. }
  645. @Override
  646. public void reset(Nio2Channel channel, long soTimeout) {
  647. super.reset(channel, soTimeout);
  648. upgradeInit = false;
  649. sendfileData = null;
  650. }
  651. @Override
  652. public long getTimeout() {
  653. long timeout = super.getTimeout();
  654. return (timeout > 0) ? timeout : Long.MAX_VALUE;
  655. }
  656. @Override
  657. public void setUpgraded(boolean upgraded) {
  658. if (upgraded && !isUpgraded()) {
  659. upgradeInit = true;
  660. }
  661. super.setUpgraded(upgraded);
  662. }
  663. public boolean isUpgradeInit() {
  664. boolean value = upgradeInit;
  665. upgradeInit = false;
  666. return value;
  667. }
  668. public void setSendfileData(SendfileData sf) { this.sendfileData = sf; }
  669. public SendfileData getSendfileData() { return this.sendfileData; }
  670. }
  671. // ------------------------------------------------ Application Buffer Handler
  672. public static class NioBufferHandler implements ApplicationBufferHandler {
  673. private ByteBuffer readbuf = null;
  674. private ByteBuffer writebuf = null;
  675. public NioBufferHandler(int readsize, int writesize, boolean direct) {
  676. if ( direct ) {
  677. readbuf = ByteBuffer.allocateDirect(readsize);
  678. writebuf = ByteBuffer.allocateDirect(writesize);
  679. }else {
  680. readbuf = ByteBuffer.allocate(readsize);
  681. writebuf = ByteBuffer.allocate(writesize);
  682. }
  683. }
  684. @Override
  685. public ByteBuffer getReadBuffer() {return readbuf;}
  686. @Override
  687. public ByteBuffer getWriteBuffer() {return writebuf;}
  688. }
  689. // ------------------------------------------------ Handler Inner Interface
  690. /**
  691. * Bare bones interface used for socket processing. Per thread data is to be
  692. * stored in the ThreadWithAttributes extra folders, or alternately in
  693. * thread local fields.
  694. */
  695. public interface Handler extends AbstractEndpoint.Handler {
  696. public SocketState process(SocketWrapper<Nio2Channel> socket,
  697. SocketStatus status);
  698. public void release(SocketWrapper<Nio2Channel> socket);
  699. public void closeAll();
  700. public SSLImplementation getSslImplementation();
  701. public void onCreateSSLEngine(SSLEngine engine);
  702. }
  703. /**
  704. * The completion handler used for asynchronous read operations
  705. */
  706. private CompletionHandler<Integer, SocketWrapper<Nio2Channel>> awaitBytes
  707. = new CompletionHandler<Integer, SocketWrapper<Nio2Channel>>() {
  708. @Override
  709. public synchronized void completed(Integer nBytes, SocketWrapper<Nio2Channel> attachment) {
  710. if (nBytes.intValue() < 0) {
  711. failed(new ClosedChannelException(), attachment);
  712. return;
  713. }
  714. processSocket0(attachment, SocketStatus.OPEN_READ, true);
  715. }
  716. @Override
  717. public void failed(Throwable exc, SocketWrapper<Nio2Channel> attachment) {
  718. processSocket0(attachment, SocketStatus.DISCONNECT, true);
  719. }
  720. };
  721. public void addTimeout(SocketWrapper<Nio2Channel> socket) {
  722. waitingRequests.add(socket);
  723. }
  724. public boolean removeTimeout(SocketWrapper<Nio2Channel> socket) {
  725. return waitingRequests.remove(socket);
  726. }
  727. public static void startInline() {
  728. inlineCompletion.set(Boolean.TRUE);
  729. }
  730. public static void endInline() {
  731. inlineCompletion.set(Boolean.FALSE);
  732. }
  733. public static boolean isInline() {
  734. Boolean flag = inlineCompletion.get();
  735. if (flag == null) {
  736. return false;
  737. } else {
  738. return flag.booleanValue();
  739. }
  740. }
  741. public void awaitBytes(SocketWrapper<Nio2Channel> socket) {
  742. if (socket == null || socket.getSocket() == null) {
  743. return;
  744. }
  745. ByteBuffer byteBuffer = socket.getSocket().getBufHandler().getReadBuffer();
  746. byteBuffer.clear();
  747. socket.getSocket().read(byteBuffer, socket.getTimeout(),
  748. TimeUnit.MILLISECONDS, socket, awaitBytes);
  749. }
  750. public boolean processSendfile(final Nio2SocketWrapper socket) {
  751. // Configure the send file data
  752. SendfileData data = socket.getSendfileData();
  753. if (data.fchannel == null || !data.fchannel.isOpen()) {
  754. java.nio.file.Path path = new File(data.fileName).toPath();
  755. try {
  756. data.fchannel = java.nio.channels.FileChannel
  757. .open(path, StandardOpenOption.READ).position(data.pos);
  758. } catch (IOException e) {
  759. closeSocket(socket, SocketStatus.ERROR);
  760. return false;
  761. }
  762. }
  763. final ByteBuffer buffer;
  764. if (!socketProperties.getDirectBuffer() && sslContext == null) {
  765. // If not using SSL and direct buffers are not used, the
  766. // idea of sendfile is to avoid memory copies, so allocate a
  767. // direct buffer
  768. int bufferSize;
  769. try {
  770. Integer bufferSizeInteger = socket.getSocket().getIOChannel().getOption(StandardSocketOptions.SO_SNDBUF);
  771. if (bufferSizeInteger != null) {
  772. bufferSize = bufferSizeInteger.intValue();
  773. } else {
  774. bufferSize = 8192;
  775. }
  776. } catch (IOException e) {
  777. bufferSize = 8192;
  778. }
  779. buffer = ByteBuffer.allocateDirect(bufferSize);
  780. } else {
  781. buffer = socket.getSocket().getBufHandler().getWriteBuffer();
  782. }
  783. int nr = -1;
  784. try {
  785. nr = data.fchannel.read(buffer);
  786. } catch (IOException e1) {
  787. closeSocket(socket, SocketStatus.ERROR);
  788. return false;
  789. }
  790. if (nr >= 0) {
  791. buffer.flip();
  792. socket.getSocket().write(buffer, data, new CompletionHandler<Integer, SendfileData>() {
  793. @Override
  794. public void completed(Integer nw, SendfileData attachment) {
  795. if (nw.intValue() < 0) { // Reach the end of stream
  796. closeSocket(socket, SocketStatus.DISCONNECT);
  797. try {
  798. attachment.fchannel.close();
  799. } catch (IOException e) {
  800. // Ignore
  801. }
  802. return;
  803. }
  804. attachment.pos += nw.intValue();
  805. attachment.length -= nw.intValue();
  806. if (attachment.length <= 0) {
  807. socket.setSendfileData(null);
  808. try {
  809. attachment.fchannel.close();
  810. } catch (IOException e) {
  811. // Ignore
  812. }
  813. if (attachment.keepAlive) {
  814. awaitBytes(socket);
  815. } else {
  816. closeSocket(socket, SocketStatus.DISCONNECT);
  817. }
  818. return;
  819. }
  820. boolean ok = true;
  821. if (!buffer.hasRemaining()) {
  822. // This means that all data in the buffer has
  823. // been
  824. // written => Empty the buffer and read again
  825. buffer.clear();
  826. try {
  827. if (attachment.fchannel.read(buffer) >= 0) {
  828. buffer.flip();
  829. if (attachment.length < buffer.remaining()) {
  830. buffer.limit(buffer.limit() - buffer.remaining() + (int) attachment.length);
  831. }
  832. } else {
  833. // Reach the EOF
  834. ok = false;
  835. }
  836. } catch (Throwable th) {
  837. ExceptionUtils.handleThrowable(th);
  838. if (log.isDebugEnabled()) {
  839. log.debug(sm.getString("endpoint.sendfile.error"), th);
  840. }
  841. ok = false;
  842. }
  843. }
  844. if (ok) {
  845. socket.getSocket().write(buffer, attachment, this);
  846. } else {
  847. try {
  848. attachment.fchannel.close();
  849. } catch (IOException e) {
  850. // Ignore
  851. }
  852. closeSocket(socket, SocketStatus.ERROR);
  853. }
  854. }
  855. @Override
  856. public void failed(Throwable exc, SendfileData attachment) {
  857. // Closing channels
  858. closeSocket(socket, SocketStatus.ERROR);
  859. try {
  860. attachment.fchannel.close();
  861. } catch (IOException e) {
  862. // Ignore
  863. }
  864. }
  865. });
  866. return true;
  867. } else {
  868. return false;
  869. }
  870. }
  871. // ---------------------------------------------- SocketProcessor Inner Class
  872. /**
  873. * This class is the equivalent of the Worker, but will simply use in an
  874. * external Executor thread pool.
  875. */
  876. protected class SocketProcessor implements Runnable {
  877. private SocketWrapper<Nio2Channel> socket = null;
  878. private SocketStatus status = null;
  879. public SocketProcessor(SocketWrapper<Nio2Channel> socket, SocketStatus status) {
  880. reset(socket,status);
  881. }
  882. public void reset(SocketWrapper<Nio2Channel> socket, SocketStatus status) {
  883. this.socket = socket;
  884. this.status = status;
  885. }
  886. @Override
  887. public void run() {
  888. // Upgraded connections need to allow multiple threads to access the
  889. // connection at the same time to enable blocking IO to be used when
  890. // NIO has been configured
  891. if (socket.isUpgraded() &&
  892. SocketStatus.OPEN_WRITE == status) {
  893. synchronized (socket.getWriteThreadLock()) {
  894. doRun();
  895. }
  896. } else {
  897. synchronized (socket) {
  898. doRun();
  899. }
  900. }
  901. }
  902. private void doRun() {
  903. boolean launch = false;
  904. try {
  905. int handshake = -1;
  906. try {
  907. if (socket.getSocket() != null) {
  908. // For STOP there is no point trying to handshake as the
  909. // Poller has been stopped.
  910. if (socket.getSocket().isHandshakeComplete() ||
  911. status == SocketStatus.STOP) {
  912. handshake = 0;
  913. } else {
  914. handshake = socket.getSocket().handshake();
  915. // The handshake process reads/writes from/to the
  916. // socket. status may therefore be OPEN_WRITE once
  917. // the handshake completes. However, the handshake
  918. // happens when the socket is opened so the status
  919. // must always be OPEN_READ after it completes. It
  920. // is OK to always set this as it is only used if
  921. // the handshake completes.
  922. status = SocketStatus.OPEN_READ;
  923. }
  924. }
  925. } catch (IOException x) {
  926. handshake = -1;
  927. if (log.isDebugEnabled()) {
  928. log.debug(sm.getString("endpoint.err.handshake"), x);
  929. }
  930. }
  931. if (handshake == 0) {
  932. SocketState state = SocketState.OPEN;
  933. // Process the request from this socket
  934. if (status == null) {
  935. state = handler.process(socket, SocketStatus.OPEN_READ);
  936. } else {
  937. state = handler.process(socket, status);
  938. }
  939. if (state == SocketState.CLOSED) {
  940. // Close socket and pool
  941. socket.setComet(false);
  942. closeSocket(socket, SocketStatus.ERROR);
  943. if (useCaches && running && !paused) {
  944. nioChannels.push(socket.getSocket());
  945. }
  946. if (useCaches && running && !paused && socket != null) {
  947. socketWrapperCache.push((Nio2SocketWrapper) socket);
  948. }
  949. } else if (state == SocketState.UPGRADING) {
  950. socket.setKeptAlive(true);
  951. socket.access();
  952. launch = true;
  953. }
  954. } else if (handshake == -1 ) {
  955. closeSocket(socket, SocketStatus.DISCONNECT);
  956. if (useCaches && running && !paused) {
  957. nioChannels.push(socket.getSocket());
  958. }
  959. if (useCaches && running && !paused && socket != null) {
  960. socketWrapperCache.push(((Nio2SocketWrapper) socket));
  961. }
  962. }
  963. } catch (OutOfMemoryError oom) {
  964. try {
  965. oomParachuteData = null;
  966. log.error("", oom);
  967. closeSocket(socket, SocketStatus.ERROR);
  968. releaseCaches();
  969. } catch (Throwable oomt) {
  970. try {
  971. System.err.println(oomParachuteMsg);
  972. oomt.printStackTrace();
  973. } catch (Throwable letsHopeWeDontGetHere){
  974. ExceptionUtils.handleThrowable(letsHopeWeDontGetHere);
  975. }
  976. }
  977. } catch (VirtualMachineError vme) {
  978. ExceptionUtils.handleThrowable(vme);
  979. } catch (Throwable t) {
  980. log.error(sm.getString("endpoint.processing.fail"), t);
  981. if (socket != null) {
  982. closeSocket(socket, SocketStatus.ERROR);
  983. }
  984. } finally {
  985. if (launch) {
  986. try {
  987. getExecutor().execute(new SocketProcessor(socket, SocketStatus.OPEN_READ));
  988. } catch (NullPointerException npe) {
  989. if (running) {
  990. log.error(sm.getString("endpoint.launch.fail"),
  991. npe);
  992. }
  993. }
  994. }
  995. socket = null;
  996. status = null;
  997. //return to cache
  998. if (useCaches && running && !paused) {
  999. processorCache.push(this);
  1000. }
  1001. }
  1002. }
  1003. }
  1004. // ----------------------------------------------- SendfileData Inner Class
  1005. /**
  1006. * SendfileData class.
  1007. */
  1008. public static class SendfileData {
  1009. // File
  1010. public String fileName;
  1011. public FileChannel fchannel;
  1012. public long pos;
  1013. public long length;
  1014. // KeepAlive flag
  1015. public boolean keepAlive;
  1016. }
  1017. }