@Override protected void doSessionOpened(HttpSession readSession) throws Exception { IoFilterChain filterChain = readSession.getFilterChain(); filterChain.addLast(CODEC_FILTER, new WsebFrameCodecFilter(0)); ResourceAddress readAddress = readSession.getRemoteAddress(); final WsebSession wsebSession = sessionMap.get(readAddress); assert (wsebSession != null); wsebSession.attachReader(readSession); if (wsebSession.getInactivityTimeout() > 0) { // Activate inactivity timeout only once read session is established currentSessionInactivityTracker.get().addSession(wsebSession); } readSession .getCloseFuture() .addListener( new IoFutureListener<CloseFuture>() { @Override public void operationComplete(CloseFuture future) { wsebSession.close(true); } }); }
@Override protected void doMessageReceived(HttpAcceptSession session, Object message) throws Exception { // this can happen if there is an error if (!(message instanceof WsMessage)) { return; } WsebSession wsebSession = getSession(session); WsMessage wsebMessage = (WsMessage) message; IoFilterChain filterChain = wsebSession.getTransportSession().getFilterChain(); switch (wsebMessage.getKind()) { case COMMAND: for (Command command : ((WsCommandMessage) wsebMessage).getCommands()) { if (command == Command.close()) { session.setWriteHeader(HEADER_CONTENT_LENGTH, "0"); session.close(false); filterChain.fireMessageReceived(new WsCloseMessage()); break; } else if (command == Command.reconnect()) { session.setWriteHeader(HEADER_CONTENT_LENGTH, "0"); session.close(false); break; } // no-op (0x00) - continue reading commands } break; default: filterChain.fireMessageReceived(wsebMessage); break; } }
public void addBridgeFilters(IoFilterChain bridgeFilterChain, WsebSession wsebSession) { bridgeFilterChain.addLast(CODEC_FILTER, codec); if (encoding != null) { bridgeFilterChain.addBefore(CODEC_FILTER, ENCODING_FILTER, encoding); } }
@Override public void onPreAdd(IoFilterChain parent, String name, NextFilter nextFilter) throws Exception { if (parent.contains(this)) { throw new IllegalArgumentException( "You can't add the same filter instance more than once. Create another instance and add it."); } parent.getSession().setAttribute(STATE, new State()); adjustReadBufferSize(parent.getSession()); }
@Override public void onPreAdd(IoFilterChain parent, String name, NextFilter nextFilter) throws Exception { if (parent.contains(this)) { throw new IllegalArgumentException( "You can't add the same filter instance more than once. Create another instance and add it."); } // Initialize the encoder and decoder initCodec(parent.getSession()); }
@Override public void addBridgeFilters(IoFilterChain filterChain) { // setup logging filters for bridge session if (logger.isTraceEnabled()) { filterChain.addFirst( TRACE_LOGGING_FILTER, new ObjectLoggingFilter(logger, WsebProtocol.NAME + "#%s")); } else { filterChain.addFirst( FAULT_LOGGING_FILTER, new ExceptionLoggingFilter(logger, WsebProtocol.NAME + "#%s")); } }
public void addCompression() { IoFilterChain chain = ioSession.getFilterChain(); String baseFilter = EXECUTOR_FILTER_NAME; if (chain.contains(TLS_FILTER_NAME)) { baseFilter = TLS_FILTER_NAME; } chain.addAfter( baseFilter, COMPRESSION_FILTER_NAME, new CompressionFilter(true, false, CompressionFilter.COMPRESSION_MAX)); }
/** Write all the pending messages */ private void flush(long currentTime) { if (flushingSessions.isEmpty()) { return; } do { S session = flushingSessions.poll(); // the same one with firstSession if (session == null) { // Just in case ... It should not happen. break; } // Reset the Schedule for flush flag for this session, // as we are flushing it now session.unscheduledForFlush(); SessionState state = getState(session); switch (state) { case OPENED: try { boolean flushedAll = flushNow(session, currentTime); if (flushedAll && !session.getWriteRequestQueue().isEmpty(session) && !session.isScheduledForFlush()) { scheduleFlush(session); } } catch (Exception e) { scheduleRemove(session); IoFilterChain filterChain = session.getFilterChain(); filterChain.fireExceptionCaught(e); } break; case CLOSING: // Skip if the channel is already closed. break; case OPENING: // Retry later if session is not yet fully initialized. // (In case that Session.write() is called before addSession() // is processed) scheduleFlush(session); return; default: throw new IllegalStateException(String.valueOf(state)); } } while (!flushingSessions.isEmpty()); }
@Override public void onPreAdd(IoFilterChain parent, String name, NextFilter nextFilter) throws SSLException { if (parent.contains(SslFilter.class)) { throw new IllegalStateException("Only one " + SslFilter.class.getName() + " is permitted."); } IoSession session = parent.getSession(); session.setAttribute(NEXT_FILTER, nextFilter); // Create an SSL handler and start handshake. SslHandler handler = new SslHandler(this, sslContext, (IoSessionEx) session, logger); session.setAttribute(SSL_HANDLER, handler); }
private boolean removeNow(S session) { clearWriteRequestQueue(session); try { destroy(session); return true; } catch (Exception e) { IoFilterChain filterChain = session.getFilterChain(); filterChain.fireExceptionCaught(e); } finally { clearWriteRequestQueue(session); ((AbstractIoService) session.getService()).getListeners().fireSessionDestroyed(session); } return false; }
@Override protected void doSessionOpened(final HttpAcceptSession session) throws Exception { WsebSession wsebSession = getSession(session); if (wsebSession == null || wsebSession.isClosing()) { session.close(false); return; } IoFilterChain filterChain = session.getFilterChain(); filterChain.addLast(CODEC_FILTER, codec); // only supported for non-binary upstream if (utf8 != null) { // Note: encoding filter needs to be closer to the network than the codec filter String contentType = session.getReadHeader(HEADER_CONTENT_TYPE); if (CONTENT_TYPE_TEXT_PLAIN_CHARSET_UTF_8.equalsIgnoreCase(contentType)) { filterChain.addBefore(CODEC_FILTER, UTF8_FILTER, utf8); } } final CloseFuture wsebCloseFuture = wsebSession.getCloseFuture(); final IoFutureListener<CloseFuture> listener = new IoFutureListener<CloseFuture>() { @Override public void operationComplete(CloseFuture future) { // Note: this reference to HTTP session is pinned by listener // and must be removed to avoid a memory leak (see below) session.close(false); } }; // detect when emulated session is closed to force upstream to close wsebCloseFuture.addListener(listener); // detect when upstream is closed to remove upstream reference from emulated session session .getCloseFuture() .addListener( new IoFutureListener<CloseFuture>() { @Override public void operationComplete(CloseFuture future) { // Note: a reference to the HTTP upstream session is pinned by listener // and must be removed to avoid a memory leak (see above) wsebCloseFuture.removeListener(listener); } }); wsebSession.attachReader(session); }
@Override public void onPostAdd(IoFilterChain parent, String name, NextFilter nextFilter) throws SSLException { if (autoStart) { initiateHandshake(nextFilter, parent.getSession()); } }
/** {@inheritDoc} */ public void updateTrafficControl(S session) { // try { setInterestedInRead(session, !session.isReadSuspended()); } catch (Exception e) { IoFilterChain filterChain = session.getFilterChain(); filterChain.fireExceptionCaught(e); } try { setInterestedInWrite( session, !session.getWriteRequestQueue().isEmpty(session) && !session.isWriteSuspended()); } catch (Exception e) { IoFilterChain filterChain = session.getFilterChain(); filterChain.fireExceptionCaught(e); } }
@Override public void onPreRemove(IoFilterChain parent, String name, NextFilter nextFilter) throws SSLException { IoSession session = parent.getSession(); stopSsl(session); session.removeAttribute(NEXT_FILTER); session.removeAttribute(SSL_HANDLER); }
private void clearWriteRequestQueue(S session) { WriteRequestQueue writeRequestQueue = session.getWriteRequestQueue(); WriteRequest req; List<WriteRequest> failedRequests = new ArrayList<WriteRequest>(); if ((req = writeRequestQueue.poll(session)) != null) { Object message = req.getMessage(); if (message instanceof IoBuffer) { IoBuffer buf = (IoBuffer) message; // The first unwritten empty buffer must be // forwarded to the filter chain. if (buf.hasRemaining()) { buf.reset(); failedRequests.add(req); } else { IoFilterChain filterChain = session.getFilterChain(); filterChain.fireMessageSent(req); } } else { failedRequests.add(req); } // Discard others. while ((req = writeRequestQueue.poll(session)) != null) { failedRequests.add(req); } } // Create an exception and notify. if (!failedRequests.isEmpty()) { WriteToClosedSessionException cause = new WriteToClosedSessionException(failedRequests); for (WriteRequest r : failedRequests) { session.decreaseScheduledBytesAndMessages(r); r.getFuture().setException(cause); } IoFilterChain filterChain = session.getFilterChain(); filterChain.fireExceptionCaught(cause); } }
@Override protected void doMessageReceived(HttpSession readSession, Object message) throws Exception { ResourceAddress readAddress = BridgeSession.REMOTE_ADDRESS.get(readSession); WsebSession wsebSession = sessionMap.get(readAddress); // handle parallel closure of WSE session during streaming read if (wsebSession == null) { if (logger.isDebugEnabled()) { logger.debug( String.format("Could not find WsebSession for read address:\n" + readAddress)); } return; } WsMessage wsebMessage = (WsMessage) message; IoBufferEx messageBytes = wsebMessage.getBytes(); IoFilterChain filterChain = wsebSession.getTransportSession().getFilterChain(); switch (wsebMessage.getKind()) { case COMMAND: for (Command command : ((WsCommandMessage) wsebMessage).getCommands()) { if (command == Command.reconnect()) { // received a RECONNECT command wsebSession.detachReader(readSession); // re-attach downstream for read final BridgeConnector bridgeConnector = bridgeServiceFactory.newBridgeConnector(readAddress); bridgeConnector.connect(readAddress, selectReadHandler(readAddress), null); break; } else if (command == Command.close()) { // Following should take care of sending CLOSE response and closing reader // (downstream) // Close case was not handled before 3.5.9 filterChain.fireMessageReceived(new WsCloseMessage()); break; } // no-op (0x00) - continue reading commands } break; default: filterChain.fireMessageReceived(wsebMessage); break; } }
@Override public void onPostRemove(IoFilterChain parent, String name, NextFilter nextFilter) throws Exception { parent.getSession().removeAttribute(STATE); }
private void fireMessageSent(S session, WriteRequest req) { session.setCurrentWriteRequest(null); IoFilterChain filterChain = session.getFilterChain(); filterChain.fireMessageSent(req); }
private boolean flushNow(S session, long currentTime) { if (!session.isConnected()) { scheduleRemove(session); return false; } final boolean hasFragmentation = session.getTransportMetadata().hasFragmentation(); final WriteRequestQueue writeRequestQueue = session.getWriteRequestQueue(); // Set limitation for the number of written bytes for read-write // fairness. I used maxReadBufferSize * 3 / 2, which yields best // performance in my experience while not breaking fairness much. final int maxWrittenBytes = session.getConfig().getMaxReadBufferSize() + (session.getConfig().getMaxReadBufferSize() >>> 1); int writtenBytes = 0; WriteRequest req = null; try { // Clear OP_WRITE setInterestedInWrite(session, false); do { // Check for pending writes. req = session.getCurrentWriteRequest(); if (req == null) { req = writeRequestQueue.poll(session); if (req == null) { break; } session.setCurrentWriteRequest(req); } int localWrittenBytes = 0; Object message = req.getMessage(); if (message instanceof IoBuffer) { localWrittenBytes = writeBuffer( session, req, hasFragmentation, maxWrittenBytes - writtenBytes, currentTime); if ((localWrittenBytes > 0) && ((IoBuffer) message).hasRemaining()) { // the buffer isn't empty, we re-interest it in writing writtenBytes += localWrittenBytes; setInterestedInWrite(session, true); return false; } } else if (message instanceof FileRegion) { localWrittenBytes = writeFile( session, req, hasFragmentation, maxWrittenBytes - writtenBytes, currentTime); // Fix for Java bug on Linux // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5103988 // If there's still data to be written in the FileRegion, // return 0 indicating that we need // to pause until writing may resume. if ((localWrittenBytes > 0) && (((FileRegion) message).getRemainingBytes() > 0)) { writtenBytes += localWrittenBytes; setInterestedInWrite(session, true); return false; } } else { throw new IllegalStateException( "Don't know how to handle message of type '" + message.getClass().getName() + "'. Are you missing a protocol encoder?"); } if (localWrittenBytes == 0) { // Kernel buffer is full. setInterestedInWrite(session, true); return false; } writtenBytes += localWrittenBytes; if (writtenBytes >= maxWrittenBytes) { // Wrote too much scheduleFlush(session); return false; } } while (writtenBytes < maxWrittenBytes); } catch (Exception e) { if (req != null) { req.getFuture().setException(e); } IoFilterChain filterChain = session.getFilterChain(); filterChain.fireExceptionCaught(e); return false; } return true; }
protected final void removeFilter(IoFilterChain filterChain, String name) { if (filterChain.contains(name)) { filterChain.remove(name); } }
private void read(S session) { IoSessionConfig config = session.getConfig(); int bufferSize = config.getReadBufferSize(); IoBuffer buf = IoBuffer.allocate(bufferSize); final boolean hasFragmentation = session.getTransportMetadata().hasFragmentation(); try { int readBytes = 0; int ret; try { if (hasFragmentation) { while ((ret = read(session, buf)) > 0) { readBytes += ret; if (!buf.hasRemaining()) { break; } } } else { ret = read(session, buf); if (ret > 0) { readBytes = ret; } } } finally { buf.flip(); } if (readBytes > 0) { IoFilterChain filterChain = session.getFilterChain(); filterChain.fireMessageReceived(buf); buf = null; if (hasFragmentation) { if (readBytes << 1 < config.getReadBufferSize()) { session.decreaseReadBufferSize(); } else if (readBytes == config.getReadBufferSize()) { session.increaseReadBufferSize(); } } } if (ret < 0) { scheduleRemove(session); } } catch (Throwable e) { if (e instanceof IOException) { if (!(e instanceof PortUnreachableException) || !AbstractDatagramSessionConfig.class.isAssignableFrom(config.getClass()) || ((AbstractDatagramSessionConfig) config).isCloseOnPortUnreachable()) { scheduleRemove(session); } } IoFilterChain filterChain = session.getFilterChain(); filterChain.fireExceptionCaught(e); } }
protected final void removeFilter(IoFilterChain filterChain, IoFilter filter) { if (filterChain.contains(filter)) { filterChain.remove(filter); } }
@Override public void onPostRemove(IoFilterChain parent, String name, NextFilter nextFilter) throws Exception { // Clean everything disposeCodec(parent.getSession()); }
@Override protected void fireSessionIdle(IoFilterChain filterChain) { filterChain.fireSessionIdle(IdleStatus.WRITER_IDLE); }