@Test
  public void testWriteWhileWriteInProgress() throws Exception {
    AbstractStreamWriteFilter<M> filter = createFilter();
    M message = createMessage(new byte[5]);

    Queue<WriteRequest> queue = new LinkedList<WriteRequest>();

    /*
     * Make up the situation.
     */
    session.setAttribute(filter.CURRENT_STREAM, message);
    session.setAttribute(filter.WRITE_REQUEST_QUEUE, queue);

    NextFilter nextFilter = EasyMock.createMock(NextFilter.class);
    /*
     * Replay.  (We recorded *nothing* because nothing should occur.)
     */
    EasyMock.replay(nextFilter);

    WriteRequest wr = new DefaultWriteRequest(new Object(), new DummyWriteFuture());
    filter.filterWrite(nextFilter, session, wr);
    assertEquals(1, queue.size());
    assertSame(wr, queue.poll());

    /*
     * Verify.
     */
    EasyMock.verify(nextFilter);

    session.removeAttribute(filter.CURRENT_STREAM);
    session.removeAttribute(filter.WRITE_REQUEST_QUEUE);
  }
 @Override
 public void sessionClosed(IoSession session) throws Exception {
   if (session.getAttribute(OTHER_IO_SESSION) != null) {
     IoSession sess = (IoSession) session.getAttribute(OTHER_IO_SESSION);
     sess.setAttribute(OTHER_IO_SESSION, null);
     sess.close(false);
     session.setAttribute(OTHER_IO_SESSION, null);
   }
 }
Ejemplo n.º 3
0
  /** Initialize the encoder and the decoder, storing them in the session attributes. */
  private void initCodec(IoSession session) throws Exception {
    // Creates the decoder and stores it into the newly created session
    ProtocolDecoder decoder = factory.getDecoder(session);
    session.setAttribute(DECODER, decoder);

    // Creates the encoder and stores it into the newly created session
    ProtocolEncoder encoder = factory.getEncoder(session);
    session.setAttribute(ENCODER, encoder);
  }
Ejemplo n.º 4
0
 /** Invoked when a connection has been opened. */
 public void sessionOpened(IoSession session) throws Exception {
   log.debug("sessionOpened()...");
   log.debug("remoteAddress=" + session.getRemoteAddress());
   // Create a new XML parser
   XMLLightweightParser parser = new XMLLightweightParser("UTF-8");
   session.setAttribute(XML_PARSER, parser);
   // Create a new connection
   Connection connection = new Connection(session);
   session.setAttribute(CONNECTION, connection);
   session.setAttribute(STANZA_HANDLER, new StanzaHandler(serverName, connection));
 }
Ejemplo n.º 5
0
  @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);
  }
 protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out)
     throws Exception {
   DecoderState decoderState = (DecoderState) session.getAttribute(DECODER_STATE_KEY);
   if (decoderState == null) {
     decoderState = new DecoderState();
     session.setAttribute(DECODER_STATE_KEY, decoderState);
   }
   if (decoderState.image1 == null) {
     // try to read first image
     if (in.prefixedDataAvailable(4, MAX_IMAGE_SIZE)) {
       decoderState.image1 = readImage(in);
     } else {
       // not enough data available to read first image
       return false;
     }
   }
   if (decoderState.image1 != null) {
     // try to read second image
     if (in.prefixedDataAvailable(4, MAX_IMAGE_SIZE)) {
       BufferedImage image2 = readImage(in);
       ImageResponse imageResponse = new ImageResponse(decoderState.image1, image2);
       out.write(imageResponse);
       decoderState.image1 = null;
       return true;
     } else {
       // not enough data available to read second image
       return false;
     }
   }
   return false;
 }
Ejemplo n.º 7
0
  /**
   * Connect by tcp.
   *
   * @param host the host
   * @param port the port
   * @return the t conn
   */
  public static synchronized TConn connectByTcp(String host, int port, long timeout) {

    TimeStamp t = TimeStamp.create();

    try {
      if (tcpconnector == null) {
        tcpconnector = new TDCConnector();
      }

      tcpconnector.connector.setConnectTimeoutMillis(timeout);

      ConnectFuture connFuture = tcpconnector.connector.connect(new InetSocketAddress(host, port));

      connFuture.awaitUninterruptibly(timeout);
      IoSession session = connFuture.getSession();

      TConn c = new TConn(session);

      session.setAttribute("conn", c);
      return c;
    } catch (Exception e) {
      log.error(
          "error, [" + host + ":" + port + "], cost: " + t.past() + "ms, timeout=" + timeout, e);
    }

    return null;
  }
Ejemplo n.º 8
0
  @Override
  public void messageReceived(IoSession session, Object message) {
    // client only sends AddMessage. otherwise, we will have to identify
    // its type using instanceof operator.
    AddMessage am = (AddMessage) message;

    // add the value to the current sum.
    int sum = ((Integer) session.getAttribute(SUM_KEY)).intValue();
    int value = am.getValue();
    long expectedSum = (long) sum + value;
    if (expectedSum > Integer.MAX_VALUE || expectedSum < Integer.MIN_VALUE) {
      // if the sum overflows or underflows, return error message
      ResultMessage rm = new ResultMessage();
      rm.setSequence(am.getSequence()); // copy sequence
      rm.setOk(false);
      session.write(rm);
    } else {
      // sum up
      sum = (int) expectedSum;
      session.setAttribute(SUM_KEY, new Integer(sum));

      // return the result message
      ResultMessage rm = new ResultMessage();
      rm.setSequence(am.getSequence()); // copy sequence
      rm.setOk(true);
      rm.setValue(sum);
      session.write(rm);
    }
  }
 /////////////////////////////////////
 // 结合CumulativeProtocolDecoder/////////////////////////////////////////////////
 // 获取session的context
 public Context getContext(IoSession session) {
   Context ctx = (Context) session.getAttribute(CONTEXT);
   if (ctx == null) {
     ctx = new Context();
     session.setAttribute(CONTEXT, ctx);
   }
   return ctx;
 }
Ejemplo n.º 10
0
  @Override
  public void sessionOpened(IoSession session) {
    // set idle time to 60 seconds
    session.getConfig().setIdleTime(IdleStatus.BOTH_IDLE, 60);

    // initial sum is zero
    session.setAttribute(SUM_KEY, new Integer(0));
  }
Ejemplo n.º 11
0
  private void storeRemainingInSession(IoBuffer buf, IoSession session) {
    final IoBuffer remainingBuf = IoBuffer.allocate(buf.capacity()).setAutoExpand(true);

    remainingBuf.order(buf.order());
    remainingBuf.put(buf);

    session.setAttribute(BUFFER, remainingBuf);
  }
  @Test
  public void testWritesWriteRequestQueueWhenFinished() throws Exception {
    AbstractStreamWriteFilter<M> filter = createFilter();
    M message = createMessage(new byte[0]);

    WriteRequest wrs[] =
        new WriteRequest[] {
          new DefaultWriteRequest(new Object(), new DummyWriteFuture()),
          new DefaultWriteRequest(new Object(), new DummyWriteFuture()),
          new DefaultWriteRequest(new Object(), new DummyWriteFuture())
        };
    Queue<WriteRequest> queue = new LinkedList<WriteRequest>();
    queue.add(wrs[0]);
    queue.add(wrs[1]);
    queue.add(wrs[2]);

    /*
     * Make up the situation.
     */
    session.setAttribute(filter.CURRENT_STREAM, message);
    session.setAttribute(filter.CURRENT_WRITE_REQUEST, new DefaultWriteRequest(message));
    session.setAttribute(filter.WRITE_REQUEST_QUEUE, queue);

    /*
     * Record expectations
     */
    NextFilter nextFilter = EasyMock.createMock(NextFilter.class);
    nextFilter.filterWrite(session, wrs[0]);
    nextFilter.filterWrite(session, wrs[1]);
    nextFilter.filterWrite(session, wrs[2]);
    nextFilter.messageSent(EasyMock.eq(session), eqWriteRequest(new DefaultWriteRequest(message)));

    /*
     * Replay.
     */
    EasyMock.replay(nextFilter);

    filter.messageSent(nextFilter, session, new DefaultWriteRequest(new Object()));
    assertEquals(0, queue.size());

    /*
     * Verify.
     */
    EasyMock.verify(nextFilter);
  }
Ejemplo n.º 13
0
 private CharsetDecoder charsetDecoder(IoSession session) {
   synchronized (session) {
     CharsetDecoder decoder = (CharsetDecoder) session.getAttribute(CHARSET_DECODER);
     if (decoder == null) {
       decoder = config.getCharset().newDecoder();
       session.setAttribute(CHARSET_DECODER, decoder);
     }
     return decoder;
   }
 }
Ejemplo n.º 14
0
  /*
   * (non-Javadoc)
   *
   * @see
   * org.apache.mina.core.service.IoHandlerAdapter#sessionCreated(org.apache
   * .mina.core.session.IoSession)
   */
  public void sessionCreated(IoSession session) throws Exception {
    log.info("stub created:" + session.getRemoteAddress());

    Counter.add("mdc", "connection", 1);

    TConn d = new TConn(session);
    d.set("x-forwarded-for", session.getRemoteAddress().toString());

    session.setAttribute("conn", d);
  }
Ejemplo n.º 15
0
 private DecoderState decoderState(IoSession session) {
   synchronized (session) {
     DecoderState decoderState = (DecoderState) session.getAttribute(DECODER_STATE);
     if (decoderState == null) {
       decoderState = new DecoderState();
       session.setAttribute(DECODER_STATE, decoderState);
     }
     return decoderState;
   }
 }
Ejemplo n.º 16
0
 /** {@inheritDoc} */
 @Override
 public void sessionOpened(IoSession session) throws Exception {
   String sessionId = (String) session.getAttribute(RTMPConnection.RTMP_SESSION_ID);
   log.debug("Session opened: {} id: {}", session.getId(), sessionId);
   RTMPConnManager connManager = (RTMPConnManager) RTMPConnManager.getInstance();
   session.setAttribute(
       RTMPConnection.RTMP_CONN_MANAGER,
       new WeakReference<IConnectionManager<RTMPConnection>>(connManager));
   RTMPMinaConnection conn = (RTMPMinaConnection) connManager.getConnectionBySessionId(sessionId);
   handler.connectionOpened(conn);
 }
Ejemplo n.º 17
0
  /**
   * Return a reference to the decoder callback. If it's not already created and stored into the
   * session, we create a new instance.
   */
  private ProtocolDecoderOutput getDecoderOut(IoSession session, NextFilter nextFilter) {
    ProtocolDecoderOutput out = (ProtocolDecoderOutput) session.getAttribute(DECODER_OUT);

    if (out == null) {
      // Create a new instance, and stores it into the session
      out = new ProtocolDecoderOutputImpl();
      session.setAttribute(DECODER_OUT, out);
    }

    return out;
  }
Ejemplo n.º 18
0
 /**
  * Force the NioSession to be released and cleaned up.
  *
  * @param session
  */
 private void forceClose(final IoSession session) {
   log.warn("Force close - session: {}", session.getId());
   if (session.containsAttribute("FORCED_CLOSE")) {
     log.info("Close already forced on this session: {}", session.getId());
   } else {
     // set flag
     session.setAttribute("FORCED_CLOSE", Boolean.TRUE);
     session.suspendRead();
     cleanSession(session, true);
   }
 }
Ejemplo n.º 19
0
 @Override
 public void sessionCreated(IoSession session) throws Exception {
   MRTMPEdgeConnection conn = new MRTMPEdgeConnection();
   conn.setIoSession(session);
   mrtmpManager.registerConnection(conn);
   session.setAttribute(MRTMPEdgeConnection.EDGE_CONNECTION_KEY, conn);
   session.getFilterChain().addFirst("protocolFilter", new ProtocolCodecFilter(this.codecFactory));
   if (log.isDebugEnabled()) {
     session.getFilterChain().addLast("logger", new LoggingFilter());
   }
   log.debug("Created MRTMP Edge Connection {}", conn);
 }
Ejemplo n.º 20
0
  private ProtocolEncoderOutput getEncoderOut(
      IoSession session, NextFilter nextFilter, WriteRequest writeRequest) {
    ProtocolEncoderOutput out = (ProtocolEncoderOutput) session.getAttribute(ENCODER_OUT);

    if (out == null) {
      // Create a new instance, and stores it into the session
      out = new ProtocolEncoderOutputImpl(session, nextFilter, writeRequest);
      session.setAttribute(ENCODER_OUT, out);
    }

    return out;
  }
Ejemplo n.º 21
0
 /** {@inheritDoc} */
 @Override
 public void sessionCreated(IoSession session) throws Exception {
   log.debug("Session created RTMP");
   // add rtmpe filter, rtmp protocol filter is added upon successful handshake
   session.getFilterChain().addFirst("rtmpeFilter", new RTMPEIoFilter());
   // create a connection
   RTMPMinaConnection conn = createRTMPMinaConnection();
   // add session to the connection
   conn.setIoSession(session);
   // add the handler
   conn.setHandler(handler);
   // add the connections session id for look up using the connection manager
   session.setAttribute(RTMPConnection.RTMP_SESSION_ID, conn.getSessionId());
   // create an inbound handshake
   InboundHandshake handshake = new InboundHandshake();
   // set whether or not unverified will be allowed
   handshake.setUnvalidatedConnectionAllowed(
       ((RTMPHandler) handler).isUnvalidatedConnectionAllowed());
   // add the in-bound handshake, defaults to non-encrypted mode
   session.setAttribute(RTMPConnection.RTMP_HANDSHAKE, handshake);
 }
Ejemplo n.º 22
0
  public void startTLS(boolean clientMode, String remoteServer, ClientAuth authentication)
      throws Exception {
    boolean c2s = (remoteServer == null);
    KeyStore ksKeys = SSLConfig.getKeyStore();
    String keypass = SSLConfig.getKeyPassword();

    KeyStore ksTrust = (c2s ? SSLConfig.getc2sTrustStore() : SSLConfig.gets2sTrustStore());
    String trustpass = (c2s ? SSLConfig.getc2sTrustPassword() : SSLConfig.gets2sTrustPassword());
    if (c2s) Log.debug("NIOConnection: startTLS: using c2s");
    else Log.debug("NIOConnection: startTLS: using s2s");
    // KeyManager's decide which key material to use.
    KeyManager[] km = SSLJiveKeyManagerFactory.getKeyManagers(ksKeys, keypass);

    // TrustManager's decide whether to allow connections.
    TrustManager[] tm = SSLJiveTrustManagerFactory.getTrustManagers(ksTrust, trustpass);

    if (clientMode || authentication == ClientAuth.needed || authentication == ClientAuth.wanted) {
      // We might need to verify a certificate from our peer, so get different TrustManager[]'s
      if (c2s) {
        // Check if we can trust certificates presented by the client
        tm = new TrustManager[] {new ClientTrustManager(ksTrust)};
      } else {
        // Check if we can trust certificates presented by the server
        tm = new TrustManager[] {new ServerTrustManager(remoteServer, ksTrust, this)};
      }
    }

    String algorithm = JiveGlobals.getProperty(ConnectionSettings.Client.TLS_ALGORITHM, "TLS");
    SSLContext tlsContext = SSLContext.getInstance(algorithm);

    tlsContext.init(km, tm, null);

    SslFilter filter = new SslFilter(tlsContext);
    filter.setUseClientMode(clientMode);
    // Disable SSLv3 due to POODLE vulnerability.
    filter.setEnabledProtocols(new String[] {"TLSv1", "TLSv1.1", "TLSv1.2"});
    if (authentication == ClientAuth.needed) {
      filter.setNeedClientAuth(true);
    } else if (authentication == ClientAuth.wanted) {
      // Just indicate that we would like to authenticate the client but if client
      // certificates are self-signed or have no certificate chain then we are still
      // good
      filter.setWantClientAuth(true);
    }
    ioSession.getFilterChain().addAfter(EXECUTOR_FILTER_NAME, TLS_FILTER_NAME, filter);
    ioSession.setAttribute(SslFilter.DISABLE_ENCRYPTION_ONCE, Boolean.TRUE);

    if (!clientMode) {
      // Indicate the client that the server is ready to negotiate TLS
      deliverRawText("<proceed xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>");
    }
  }
Ejemplo n.º 23
0
  /*
   * (non-Javadoc)
   *
   * @see
   * org.apache.mina.core.service.IoHandlerAdapter#sessionCreated(org.apache
   * .mina.core.session.IoSession)
   */
  public void sessionCreated(IoSession session) throws Exception {
    String remote = session.getRemoteAddress().toString();
    log.info("stub created:" + remote);

    /** check the allow ip */
    if (TConn.ALLOW_IP == null || "*".equals(TConn.ALLOW_IP) || remote.matches(TConn.ALLOW_IP)) {
      TConn d = new TConn(session);
      session.setAttribute("conn", d);
    } else {
      log.warn("deny the connection:" + remote + ", allow ip:" + TConn.ALLOW_IP);
      session.close(true);
    }
  }
Ejemplo n.º 24
0
 @Override
 public void messageSent(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) {
   if (writeRequest instanceof EncryptedWriteRequest) {
     EncryptedWriteRequest wrappedRequest = (EncryptedWriteRequest) writeRequest;
     nextFilter.messageSent(session, wrappedRequest.getParentRequest());
   } else if (writeRequest == AbstractIoSessionEx.REGISTERED_EVENT) {
     // Session has been realigned, need to reset NEXT_FILTER so it has the new filter chain for
     // the new IO thread
     session.setAttribute(NEXT_FILTER, nextFilter);
   } else {
     // ignore extra buffers used for handshaking
   }
 }
Ejemplo n.º 25
0
 @Override
 public void exceptionCaught(IoSession ioSession, Throwable cause) throws Exception {
   boolean disconnectNeeded = false;
   Session quickFixSession = findQFSession(ioSession);
   Throwable realCause = cause;
   if (cause instanceof ProtocolDecoderException && cause.getCause() != null) {
     realCause = cause.getCause();
   } else {
     Throwable chain = cause;
     while (chain != null && chain.getCause() != null) {
       chain = chain.getCause();
       if (chain instanceof IOException) {
         realCause = chain;
         break;
       }
     }
   }
   String reason;
   if (realCause instanceof IOException) {
     if (quickFixSession != null && quickFixSession.isEnabled()) {
       reason = "Socket exception (" + ioSession.getRemoteAddress() + "): " + cause;
     } else {
       reason = "Socket (" + ioSession.getRemoteAddress() + "): " + cause;
     }
     disconnectNeeded = true;
   } else if (realCause instanceof CriticalProtocolCodecException) {
     reason = "Critical protocol codec error: " + cause;
     disconnectNeeded = true;
   } else if (realCause instanceof ProtocolCodecException) {
     reason = "Protocol handler exception: " + cause;
   } else {
     reason = cause.toString();
   }
   if (disconnectNeeded) {
     try {
       if (quickFixSession != null) {
         quickFixSession.disconnect(reason, true);
       } else {
         log.error(reason, cause);
         ioSession.closeNow();
       }
     } finally {
       ioSession.setAttribute("QFJ_RESET_IO_CONNECTOR", Boolean.TRUE);
     }
   } else {
     log.error(reason, cause);
   }
 }
  /**
   * 根据host和port新建一个IoSession连接
   *
   * @param host 连接主机IP
   * @param port 连接端口
   * @param timeout 未收到数据超时时间/秒
   */
  @Override
  public void connect(String host, int port, int timeout) throws Exception {
    connector.getSessionConfig().setIdleTime(IdleStatus.READER_IDLE, timeout);
    log.debug("超时时间:" + timeout + "秒");
    // 设置连接超时时间
    connector.setConnectTimeoutMillis(ExpressConstant.CONNECT_TIMEOUT);

    // 创建连接
    ConnectFuture future = connector.connect(new InetSocketAddress(host, port));

    // 等待连接创建完成
    future.awaitUninterruptibly();

    // 得到连接Session
    session = future.getSession();
    // 设置Session同步锁对象
    session.setAttribute(ExpressConstant.SESSION_LOCK, new LockExpress());
  }
  public void encode(IoSession session, Object message, ProtocolEncoderOutput out)
      throws Exception {
    CharsetEncoder encoder = (CharsetEncoder) session.getAttribute(ENCODER);
    if (encoder == null) {
      encoder = m_charset.newEncoder();
      session.setAttribute(ENCODER, encoder);
    }

    String value = message.toString();
    IoBuffer buf = IoBuffer.allocate(value.length()).setAutoExpand(true);
    buf.putString(value, encoder);
    if (buf.position() > Integer.MAX_VALUE) {
      throw new IllegalArgumentException("Line length: " + buf.position());
    }
    buf.putString(m_delimiter.getValue(), encoder);
    buf.flip();
    out.write(buf);
  }
Ejemplo n.º 28
0
 @Override
 protected void processCmd(IoSession session, Auth_Rsp t) {
   if (t.getSucess()) {
     session.setAttribute("auth", true);
     changeSessionId(session, t.getSessionId());
     @SuppressWarnings("unchecked")
     PacketCollector<Auth_Rsp> pc = CallbackStore.instance().getPacketCollector(t.getId());
     if (pc != null) {
       pc.onCollect(t);
     }
     doRegister(t);
     log.info("============================================================");
     log.info("认证成功Session:{}  所在IP为:{}", t.getSessionId(), t.getIp());
   } else {
     log.info("============================================================");
     log.info("认证失败,原因是:{} ", t.getReason());
   }
   log.info("============================================================");
 }
Ejemplo n.º 29
0
  /**
   * Connect by udp.
   *
   * @param host the host
   * @param port the port
   * @return the t conn
   */
  public static synchronized TConn connectByUdp(String host, int port) {
    try {
      if (udpconnector == null) {
        udpconnector = new UDCConnector();
      }

      ConnectFuture connFuture = udpconnector.connector.connect(new InetSocketAddress(host, port));
      connFuture.awaitUninterruptibly();
      IoSession session = connFuture.getSession();

      TConn c = new TConn(session);

      session.setAttribute("conn", c);
      return c;
    } catch (Exception e) {
      log.error("[" + host + ":" + port + "]", e);
    }
    return null;
  }
Ejemplo n.º 30
0
  /**
   * <tt>in</tt> の内容を内部のバッファに蓄積し、 デコード要求を {@link #doDecode(IoSession, IoBuffer,
   * ProtocolDecoderOutput)} に送ります。 <tt>doDecode()</tt> は <tt>false</tt> を返すまで繰り返し呼び出され、
   * デコードが終わると累積バッファのサイズが縮められます。
   *
   * @throws IllegalStateException <tt>doDecode()</tt> が累積バッファの内容を 消費せずに <tt>true</tt> を返した場合
   */
  public void decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
    if (!session.getTransportMetadata().hasFragmentation()) {
      while (in.hasRemaining()) {
        if (!doDecode(session, in, out)) {
          break;
        }
      }

      return;
    }

    boolean usingSessionBuffer = true;
    IoBuffer buf = (IoBuffer) session.getAttribute(BUFFER);
    // If we have a session buffer, append data to that; otherwise
    // use the buffer read from the network directly.
    if (buf != null) {
      boolean appended = false;
      // Make sure that the buffer is auto-expanded.
      if (buf.isAutoExpand()) {
        try {
          buf.put(in);
          appended = true;
        } catch (IllegalStateException e) {
          // A user called derivation method (e.g. slice()),
          // which disables auto-expansion of the parent buffer.
        } catch (IndexOutOfBoundsException e) {
          // A user disabled auto-expansion.
        }
      }

      if (appended) {
        buf.flip();
      } else {
        // Reallocate the buffer if append operation failed due to
        // derivation or disabled auto-expansion.
        buf.flip();
        IoBuffer newBuf = IoBuffer.allocate(buf.remaining() + in.remaining()).setAutoExpand(true);
        newBuf.order(buf.order());
        newBuf.put(buf);
        newBuf.put(in);
        newBuf.flip();
        buf = newBuf;

        // Update the session attribute.
        session.setAttribute(BUFFER, buf);
      }
    } else {
      buf = in;
      usingSessionBuffer = false;
    }

    for (; ; ) {
      int oldPos = buf.position();
      boolean decoded = doDecode(session, buf, out);
      if (decoded) {
        if (buf.position() == oldPos) {
          throw new IllegalStateException(
              "doDecode() can't return true when buffer is not consumed.");
        }

        if (!buf.hasRemaining()) {
          break;
        }
      } else {
        break;
      }
    }

    // if there is any data left that cannot be decoded, we store
    // it in a buffer in the session and next time this decoder is
    // invoked the session buffer gets appended to
    if (buf.hasRemaining()) {
      if (usingSessionBuffer && buf.isAutoExpand()) {
        buf.compact();
      } else {
        storeRemainingInSession(buf, session);
      }
    } else {
      if (usingSessionBuffer) {
        removeSessionBuffer(session);
      }
    }
  }