Example #1
0
  protected Object decode(Channel channel, ChannelBuffer buffer, int readable, byte[] header)
      throws IOException {
    // check magic number.
    if (readable > 0 && header[0] != MAGIC_HIGH || readable > 1 && header[1] != MAGIC_LOW) {
      int length = header.length;
      if (header.length < readable) {
        header = Bytes.copyOf(header, readable);
        buffer.readBytes(header, length, readable - length);
      }
      for (int i = 1; i < header.length - 1; i++) {
        if (header[i] == MAGIC_HIGH && header[i + 1] == MAGIC_LOW) {
          buffer.readerIndex(buffer.readerIndex() - header.length + i);
          header = Bytes.copyOf(header, i);
          break;
        }
      }
      return super.decode(channel, buffer, readable, header);
    }
    // check length.
    if (readable < HEADER_LENGTH) {
      return DecodeResult.NEED_MORE_INPUT;
    }

    // get data length.
    int len = Bytes.bytes2int(header, 12);
    checkPayload(channel, len);

    int tt = len + HEADER_LENGTH;
    if (readable < tt) {
      return DecodeResult.NEED_MORE_INPUT;
    }

    // limit input stream.
    ChannelBufferInputStream is = new ChannelBufferInputStream(buffer, len);

    try {
      return decodeBody(channel, is, header);
    } finally {
      if (is.available() > 0) {
        try {
          if (logger.isWarnEnabled()) {
            logger.warn("Skip input stream " + is.available());
          }
          StreamUtils.skipUnusedStream(is);
        } catch (IOException e) {
          logger.warn(e.getMessage(), e);
        }
      }
    }
  }
Example #2
0
 protected Object decodeBody(Channel channel, InputStream is, byte[] header) throws IOException {
   byte flag = header[2], proto = (byte) (flag & SERIALIZATION_MASK);
   Serialization s = CodecSupport.getSerialization(channel.getUrl(), proto);
   ObjectInput in = s.deserialize(channel.getUrl(), is);
   // get request id.
   long id = Bytes.bytes2long(header, 4);
   if ((flag & FLAG_REQUEST) == 0) {
     // decode response.
     Response res = new Response(id);
     if ((flag & FLAG_EVENT) != 0) {
       res.setEvent(Response.HEARTBEAT_EVENT);
     }
     // get status.
     byte status = header[3];
     res.setStatus(status);
     if (status == Response.OK) {
       try {
         Object data;
         if (res.isHeartbeat()) {
           data = decodeHeartbeatData(channel, in);
         } else if (res.isEvent()) {
           data = decodeEventData(channel, in);
         } else {
           data = decodeResponseData(channel, in, getRequestData(id));
         }
         res.setResult(data);
       } catch (Throwable t) {
         res.setStatus(Response.CLIENT_ERROR);
         res.setErrorMessage(StringUtils.toString(t));
       }
     } else {
       res.setErrorMessage(in.readUTF());
     }
     return res;
   } else {
     // decode request.
     Request req = new Request(id);
     req.setVersion("2.0.0");
     req.setTwoWay((flag & FLAG_TWOWAY) != 0);
     if ((flag & FLAG_EVENT) != 0) {
       req.setEvent(Request.HEARTBEAT_EVENT);
     }
     try {
       Object data;
       if (req.isHeartbeat()) {
         data = decodeHeartbeatData(channel, in);
       } else if (req.isEvent()) {
         data = decodeEventData(channel, in);
       } else {
         data = decodeRequestData(channel, in);
       }
       req.setData(data);
     } catch (Throwable t) {
       // bad request
       req.setBroken(true);
       req.setData(t);
     }
     return req;
   }
 }
Example #3
0
  protected void encodeRequest(Channel channel, ChannelBuffer buffer, Request req)
      throws IOException {
    Serialization serialization = getSerialization(channel);
    // header.
    byte[] header = new byte[HEADER_LENGTH];
    // set magic number.
    Bytes.short2bytes(MAGIC, header);

    // set request and serialization flag.
    header[2] = (byte) (FLAG_REQUEST | serialization.getContentTypeId());

    if (req.isTwoWay()) header[2] |= FLAG_TWOWAY;
    if (req.isEvent()) header[2] |= FLAG_EVENT;

    // set request id.
    Bytes.long2bytes(req.getId(), header, 4);

    // encode request data.
    int savedWriteIndex = buffer.writerIndex();
    buffer.writerIndex(savedWriteIndex + HEADER_LENGTH);
    ChannelBufferOutputStream bos = new ChannelBufferOutputStream(buffer);
    ObjectOutput out = serialization.serialize(channel.getUrl(), bos);
    try {
      if (req.isEvent()) {
        encodeEventData(channel, out, req.getData());
      } else {
        encodeRequestData(channel, out, req.getData());
      }
      out.flushBuffer();
    } finally {
      // modified by lishen
      if (out instanceof Cleanable) {
        ((Cleanable) out).cleanup();
      }
    }

    bos.flush();
    bos.close();
    int len = bos.writtenBytes();
    checkPayload(channel, len);
    Bytes.int2bytes(len, header, 12);

    // write
    buffer.writerIndex(savedWriteIndex);
    buffer.writeBytes(header); // write header.
    buffer.writerIndex(savedWriteIndex + HEADER_LENGTH + len);
  }
Example #4
0
 /*
  * 接收
  *
  * @param context 上下文
  * @param channel 通道
  * @param buffer 缓存
  * @param readable 缓存可读
  * @param bytes 输入缓存
  * @param offset 指向已读数据的偏移量,off之前的数据都是已用过的
  * @param limit 有效长度,limit之后的长度是空白或无效数据,off到limit之间的数据是准备使用的数据
  * @return 后续动作
  * @throws IOException
  */
 private NextAction receive(
     FilterChainContext context,
     Channel channel,
     Buffer buffer,
     int readable,
     byte[] bytes,
     int offset,
     int limit)
     throws IOException {
   for (; ; ) {
     int read = Math.min(readable, bytes.length - limit); // 取bytes缓存空闲区,和可读取新数据,的最小值,即:此次最多读写数据的大小
     buffer.get(bytes, limit, read); // 从可读取新数据中,读取数据,尽量填满bytes缓存空闲区
     limit += read; // 有效数据变长
     readable -= read; // 可读数据变少
     UnsafeByteArrayInputStream input =
         new UnsafeByteArrayInputStream(
             bytes, offset, limit - offset); // 将bytes缓存转成InputStream,不需要关闭
     Object msg = upstreamCodec.decode(channel, input); // 调用Codec接口,解码数据
     if (msg == Codec.NEED_MORE_INPUT) { // 如果Codec觉得数据不够,不足以解码成一个对象
       if (readable == 0) { // 如果没有更多可读数据
         channel.setAttribute(
             BUFFER_KEY, new Object[] {bytes, offset, limit}); // 放入通道属性中,等待下一个Buffer的到来
         return context.getStopAction();
       } else { // 扩充或挪出空闲区,并循环,直到可读数据都加载到bytes缓存
         if (offset == 0) { // 如果bytes缓存全部没有被使用,如果这时数据还不够
           bytes = Bytes.copyOf(bytes, bytes.length << 1); // 将bytes缓存扩大一倍
         } else { // 如果bytes缓存有一段数据已被使用
           int len = limit - offset; // 计算有效数据长度
           System.arraycopy(
               bytes, offset, bytes, 0, len); // 将数据向前移到,压缩到已使用的部分,这样limit后面就会多出一些空闲,可以放数据
           offset = 0; // 移到后,bytes缓存没有数据被使用
           limit = len; // 移到后,有效数据都在bytes缓存最前面
         }
       }
     } else { // 如果解析出一个结果
       int position = input.position(); // 记录InputStream用了多少
       if (position == offset) { // 如果InputStream没有被读过,就返回了数据,直接报错,否则InputStream永远读不完,会死递归
         throw new IOException("Decode without read data.");
       }
       offset = position; // 记录已读数据
       context.setMessage(msg); // 将消息改为解码后的对象,以便被后面的Filter使用。
       if (limit - offset > 0 || readable > 0) { // 如果有效数据没有被读完,或者Buffer区还有未读数据
         return context.getInvokeAction(
             new Object[] {
               buffer, readable, bytes, offset, limit
             }); // 正常执行完Filter,并重新发起一轮Filter,继续读
       } else { // 否则所有数据读完
         return context.getInvokeAction(); // 正常执行完Filter
       }
     }
   }
 }
Example #5
0
/**
 * ExchangeCodec.
 *
 * @author qianlei
 * @author william.liangf
 */
public class ExchangeCodec extends TelnetCodec {

  private static final Logger logger = LoggerFactory.getLogger(ExchangeCodec.class);

  // header length.
  protected static final int HEADER_LENGTH = 16;

  // magic header.
  protected static final short MAGIC = (short) 0xdabb;

  protected static final byte MAGIC_HIGH = Bytes.short2bytes(MAGIC)[0];

  protected static final byte MAGIC_LOW = Bytes.short2bytes(MAGIC)[1];

  // message flag.
  protected static final byte FLAG_REQUEST = (byte) 0x80;

  protected static final byte FLAG_TWOWAY = (byte) 0x40;

  protected static final byte FLAG_EVENT = (byte) 0x20;

  protected static final int SERIALIZATION_MASK = 0x1f;

  public Short getMagicCode() {
    return MAGIC;
  }

  public void encode(Channel channel, ChannelBuffer buffer, Object msg) throws IOException {
    if (msg instanceof Request) {
      encodeRequest(channel, buffer, (Request) msg);
    } else if (msg instanceof Response) {
      encodeResponse(channel, buffer, (Response) msg);
    } else {
      super.encode(channel, buffer, msg);
    }

    // TODO modified by lishen
    //        System.out.println(">>>>>>>>>>>>>>>>>>>>>> the resulting byte size of encoding is " +
    // buffer.readableBytes());
    if (logger.isTraceEnabled()) {
      logger.trace("the resulting byte size of encoding is " + buffer.readableBytes());
    }
  }

  public Object decode(Channel channel, ChannelBuffer buffer) throws IOException {
    int readable = buffer.readableBytes();
    byte[] header = new byte[Math.min(readable, HEADER_LENGTH)];
    buffer.readBytes(header);
    return decode(channel, buffer, readable, header);
  }

  protected Object decode(Channel channel, ChannelBuffer buffer, int readable, byte[] header)
      throws IOException {
    // check magic number.
    if (readable > 0 && header[0] != MAGIC_HIGH || readable > 1 && header[1] != MAGIC_LOW) {
      int length = header.length;
      if (header.length < readable) {
        header = Bytes.copyOf(header, readable);
        buffer.readBytes(header, length, readable - length);
      }
      for (int i = 1; i < header.length - 1; i++) {
        if (header[i] == MAGIC_HIGH && header[i + 1] == MAGIC_LOW) {
          buffer.readerIndex(buffer.readerIndex() - header.length + i);
          header = Bytes.copyOf(header, i);
          break;
        }
      }
      return super.decode(channel, buffer, readable, header);
    }
    // check length.
    if (readable < HEADER_LENGTH) {
      return DecodeResult.NEED_MORE_INPUT;
    }

    // get data length.
    int len = Bytes.bytes2int(header, 12);
    checkPayload(channel, len);

    int tt = len + HEADER_LENGTH;
    if (readable < tt) {
      return DecodeResult.NEED_MORE_INPUT;
    }

    // limit input stream.
    ChannelBufferInputStream is = new ChannelBufferInputStream(buffer, len);

    try {
      return decodeBody(channel, is, header);
    } finally {
      if (is.available() > 0) {
        try {
          if (logger.isWarnEnabled()) {
            logger.warn("Skip input stream " + is.available());
          }
          StreamUtils.skipUnusedStream(is);
        } catch (IOException e) {
          logger.warn(e.getMessage(), e);
        }
      }
    }
  }

  protected Object decodeBody(Channel channel, InputStream is, byte[] header) throws IOException {
    byte flag = header[2], proto = (byte) (flag & SERIALIZATION_MASK);
    Serialization s = CodecSupport.getSerialization(channel.getUrl(), proto);
    ObjectInput in = s.deserialize(channel.getUrl(), is);
    // get request id.
    long id = Bytes.bytes2long(header, 4);
    if ((flag & FLAG_REQUEST) == 0) {
      // decode response.
      Response res = new Response(id);
      if ((flag & FLAG_EVENT) != 0) {
        res.setEvent(Response.HEARTBEAT_EVENT);
      }
      // get status.
      byte status = header[3];
      res.setStatus(status);
      if (status == Response.OK) {
        try {
          Object data;
          if (res.isHeartbeat()) {
            data = decodeHeartbeatData(channel, in);
          } else if (res.isEvent()) {
            data = decodeEventData(channel, in);
          } else {
            data = decodeResponseData(channel, in, getRequestData(id));
          }
          res.setResult(data);
        } catch (Throwable t) {
          res.setStatus(Response.CLIENT_ERROR);
          res.setErrorMessage(StringUtils.toString(t));
        }
      } else {
        res.setErrorMessage(in.readUTF());
      }
      return res;
    } else {
      // decode request.
      Request req = new Request(id);
      req.setVersion("2.0.0");
      req.setTwoWay((flag & FLAG_TWOWAY) != 0);
      if ((flag & FLAG_EVENT) != 0) {
        req.setEvent(Request.HEARTBEAT_EVENT);
      }
      try {
        Object data;
        if (req.isHeartbeat()) {
          data = decodeHeartbeatData(channel, in);
        } else if (req.isEvent()) {
          data = decodeEventData(channel, in);
        } else {
          data = decodeRequestData(channel, in);
        }
        req.setData(data);
      } catch (Throwable t) {
        // bad request
        req.setBroken(true);
        req.setData(t);
      }
      return req;
    }
  }

  protected Object getRequestData(long id) {
    DefaultFuture future = DefaultFuture.getFuture(id);
    if (future == null) return null;
    Request req = future.getRequest();
    if (req == null) return null;
    return req.getData();
  }

  protected void encodeRequest(Channel channel, ChannelBuffer buffer, Request req)
      throws IOException {
    Serialization serialization = getSerialization(channel);
    // header.
    byte[] header = new byte[HEADER_LENGTH];
    // set magic number.
    Bytes.short2bytes(MAGIC, header);

    // set request and serialization flag.
    header[2] = (byte) (FLAG_REQUEST | serialization.getContentTypeId());

    if (req.isTwoWay()) header[2] |= FLAG_TWOWAY;
    if (req.isEvent()) header[2] |= FLAG_EVENT;

    // set request id.
    Bytes.long2bytes(req.getId(), header, 4);

    // encode request data.
    int savedWriteIndex = buffer.writerIndex();
    buffer.writerIndex(savedWriteIndex + HEADER_LENGTH);
    ChannelBufferOutputStream bos = new ChannelBufferOutputStream(buffer);
    ObjectOutput out = serialization.serialize(channel.getUrl(), bos);
    try {
      if (req.isEvent()) {
        encodeEventData(channel, out, req.getData());
      } else {
        encodeRequestData(channel, out, req.getData());
      }
      out.flushBuffer();
    } finally {
      // modified by lishen
      if (out instanceof Cleanable) {
        ((Cleanable) out).cleanup();
      }
    }

    bos.flush();
    bos.close();
    int len = bos.writtenBytes();
    checkPayload(channel, len);
    Bytes.int2bytes(len, header, 12);

    // write
    buffer.writerIndex(savedWriteIndex);
    buffer.writeBytes(header); // write header.
    buffer.writerIndex(savedWriteIndex + HEADER_LENGTH + len);
  }

  protected void encodeResponse(Channel channel, ChannelBuffer buffer, Response res)
      throws IOException {
    try {
      Serialization serialization = getSerialization(channel);
      // header.
      byte[] header = new byte[HEADER_LENGTH];
      // set magic number.
      Bytes.short2bytes(MAGIC, header);
      // set request and serialization flag.
      header[2] = serialization.getContentTypeId();
      if (res.isHeartbeat()) header[2] |= FLAG_EVENT;
      // set response status.
      byte status = res.getStatus();
      header[3] = status;
      // set request id.
      Bytes.long2bytes(res.getId(), header, 4);

      int savedWriteIndex = buffer.writerIndex();
      buffer.writerIndex(savedWriteIndex + HEADER_LENGTH);
      ChannelBufferOutputStream bos = new ChannelBufferOutputStream(buffer);
      ObjectOutput out = serialization.serialize(channel.getUrl(), bos);
      try {
        // encode response data or error message.
        if (status == Response.OK) {
          if (res.isHeartbeat()) {
            encodeHeartbeatData(channel, out, res.getResult());
          } else {
            encodeResponseData(channel, out, res.getResult());
          }
        } else out.writeUTF(res.getErrorMessage());
        out.flushBuffer();
      } finally {
        // modified by lishen
        if (out instanceof Cleanable) {
          ((Cleanable) out).cleanup();
        }
      }

      bos.flush();
      bos.close();

      int len = bos.writtenBytes();
      checkPayload(channel, len);
      Bytes.int2bytes(len, header, 12);
      // write
      buffer.writerIndex(savedWriteIndex);
      buffer.writeBytes(header); // write header.
      buffer.writerIndex(savedWriteIndex + HEADER_LENGTH + len);
    } catch (Throwable t) {
      // 发送失败信息给Consumer,否则Consumer只能等超时了
      if (!res.isEvent() && res.getStatus() != Response.BAD_RESPONSE) {
        try {
          // FIXME 在Codec中打印出错日志?在IoHanndler的caught中统一处理?
          logger.warn(
              "Fail to encode response: "
                  + res
                  + ", send bad_response info instead, cause: "
                  + t.getMessage(),
              t);

          Response r = new Response(res.getId(), res.getVersion());
          r.setStatus(Response.BAD_RESPONSE);
          r.setErrorMessage(
              "Failed to send response: " + res + ", cause: " + StringUtils.toString(t));
          channel.send(r);

          return;
        } catch (RemotingException e) {
          logger.warn(
              "Failed to send bad_response info back: " + res + ", cause: " + e.getMessage(), e);
        }
      }

      // 重新抛出收到的异常
      if (t instanceof IOException) {
        throw (IOException) t;
      } else if (t instanceof RuntimeException) {
        throw (RuntimeException) t;
      } else if (t instanceof Error) {
        throw (Error) t;
      } else {
        throw new RuntimeException(t.getMessage(), t);
      }
    }
  }

  @Override
  protected Object decodeData(ObjectInput in) throws IOException {
    return decodeRequestData(in);
  }

  @Deprecated
  protected Object decodeHeartbeatData(ObjectInput in) throws IOException {
    try {
      return in.readObject();
    } catch (ClassNotFoundException e) {
      throw new IOException(StringUtils.toString("Read object failed.", e));
    }
  }

  protected Object decodeRequestData(ObjectInput in) throws IOException {
    try {
      return in.readObject();
    } catch (ClassNotFoundException e) {
      throw new IOException(StringUtils.toString("Read object failed.", e));
    }
  }

  protected Object decodeResponseData(ObjectInput in) throws IOException {
    try {
      return in.readObject();
    } catch (ClassNotFoundException e) {
      throw new IOException(StringUtils.toString("Read object failed.", e));
    }
  }

  @Override
  protected void encodeData(ObjectOutput out, Object data) throws IOException {
    encodeRequestData(out, data);
  }

  private void encodeEventData(ObjectOutput out, Object data) throws IOException {
    out.writeObject(data);
  }

  @Deprecated
  protected void encodeHeartbeatData(ObjectOutput out, Object data) throws IOException {
    encodeEventData(out, data);
  }

  protected void encodeRequestData(ObjectOutput out, Object data) throws IOException {
    out.writeObject(data);
  }

  protected void encodeResponseData(ObjectOutput out, Object data) throws IOException {
    out.writeObject(data);
  }

  @Override
  protected Object decodeData(Channel channel, ObjectInput in) throws IOException {
    return decodeRequestData(channel, in);
  }

  protected Object decodeEventData(Channel channel, ObjectInput in) throws IOException {
    try {
      return in.readObject();
    } catch (ClassNotFoundException e) {
      throw new IOException(StringUtils.toString("Read object failed.", e));
    }
  }

  @Deprecated
  protected Object decodeHeartbeatData(Channel channel, ObjectInput in) throws IOException {
    try {
      return in.readObject();
    } catch (ClassNotFoundException e) {
      throw new IOException(StringUtils.toString("Read object failed.", e));
    }
  }

  protected Object decodeRequestData(Channel channel, ObjectInput in) throws IOException {
    return decodeRequestData(in);
  }

  protected Object decodeResponseData(Channel channel, ObjectInput in) throws IOException {
    return decodeResponseData(in);
  }

  protected Object decodeResponseData(Channel channel, ObjectInput in, Object requestData)
      throws IOException {
    return decodeResponseData(channel, in);
  }

  @Override
  protected void encodeData(Channel channel, ObjectOutput out, Object data) throws IOException {
    encodeRequestData(channel, out, data);
  }

  private void encodeEventData(Channel channel, ObjectOutput out, Object data) throws IOException {
    encodeEventData(out, data);
  }

  @Deprecated
  protected void encodeHeartbeatData(Channel channel, ObjectOutput out, Object data)
      throws IOException {
    encodeHeartbeatData(out, data);
  }

  protected void encodeRequestData(Channel channel, ObjectOutput out, Object data)
      throws IOException {
    encodeRequestData(out, data);
  }

  protected void encodeResponseData(Channel channel, ObjectOutput out, Object data)
      throws IOException {
    encodeResponseData(out, data);
  }
}
Example #6
0
  protected void encodeResponse(Channel channel, ChannelBuffer buffer, Response res)
      throws IOException {
    try {
      Serialization serialization = getSerialization(channel);
      // header.
      byte[] header = new byte[HEADER_LENGTH];
      // set magic number.
      Bytes.short2bytes(MAGIC, header);
      // set request and serialization flag.
      header[2] = serialization.getContentTypeId();
      if (res.isHeartbeat()) header[2] |= FLAG_EVENT;
      // set response status.
      byte status = res.getStatus();
      header[3] = status;
      // set request id.
      Bytes.long2bytes(res.getId(), header, 4);

      int savedWriteIndex = buffer.writerIndex();
      buffer.writerIndex(savedWriteIndex + HEADER_LENGTH);
      ChannelBufferOutputStream bos = new ChannelBufferOutputStream(buffer);
      ObjectOutput out = serialization.serialize(channel.getUrl(), bos);
      try {
        // encode response data or error message.
        if (status == Response.OK) {
          if (res.isHeartbeat()) {
            encodeHeartbeatData(channel, out, res.getResult());
          } else {
            encodeResponseData(channel, out, res.getResult());
          }
        } else out.writeUTF(res.getErrorMessage());
        out.flushBuffer();
      } finally {
        // modified by lishen
        if (out instanceof Cleanable) {
          ((Cleanable) out).cleanup();
        }
      }

      bos.flush();
      bos.close();

      int len = bos.writtenBytes();
      checkPayload(channel, len);
      Bytes.int2bytes(len, header, 12);
      // write
      buffer.writerIndex(savedWriteIndex);
      buffer.writeBytes(header); // write header.
      buffer.writerIndex(savedWriteIndex + HEADER_LENGTH + len);
    } catch (Throwable t) {
      // 发送失败信息给Consumer,否则Consumer只能等超时了
      if (!res.isEvent() && res.getStatus() != Response.BAD_RESPONSE) {
        try {
          // FIXME 在Codec中打印出错日志?在IoHanndler的caught中统一处理?
          logger.warn(
              "Fail to encode response: "
                  + res
                  + ", send bad_response info instead, cause: "
                  + t.getMessage(),
              t);

          Response r = new Response(res.getId(), res.getVersion());
          r.setStatus(Response.BAD_RESPONSE);
          r.setErrorMessage(
              "Failed to send response: " + res + ", cause: " + StringUtils.toString(t));
          channel.send(r);

          return;
        } catch (RemotingException e) {
          logger.warn(
              "Failed to send bad_response info back: " + res + ", cause: " + e.getMessage(), e);
        }
      }

      // 重新抛出收到的异常
      if (t instanceof IOException) {
        throw (IOException) t;
      } else if (t instanceof RuntimeException) {
        throw (RuntimeException) t;
      } else if (t instanceof Error) {
        throw (Error) t;
      } else {
        throw new RuntimeException(t.getMessage(), t);
      }
    }
  }
 @Override
 protected void decode(ChannelHandlerContext ctx, ByteBuf input, List<Object> out)
     throws Exception {
   int readable = input.readableBytes();
   if (readable <= 0) {
     return;
   }
   int off, limit;
   byte[] buf = mBuffer;
   if (buf == null) {
     buf = new byte[bufferSize];
     off = limit = 0;
   } else {
     off = mOffset;
     limit = mLimit;
   }
   com.antrou.dubbo.remoting.netty4.NettyChannel channel =
       com.antrou.dubbo.remoting.netty4.NettyChannel.getOrAddChannel(
           ctx.channel(), url, handler);
   boolean remaining = true;
   Object msg;
   UnsafeByteArrayInputStream bis;
   try {
     do {
       // read data into buffer.
       int read = Math.min(readable, buf.length - limit);
       input.readBytes(buf, limit, read);
       limit += read;
       readable -= read;
       bis = new UnsafeByteArrayInputStream(buf, off, limit - off);
       // decode object.
       do {
         try {
           msg = codec.decode(channel, bis);
         } catch (IOException e) {
           remaining = false;
           throw e;
         }
         if (msg == Codec.NEED_MORE_INPUT) {
           if (off == 0) {
             if (readable > 0) {
               buf = Bytes.copyOf(buf, buf.length << 1);
             }
           } else {
             int len = limit - off;
             System.arraycopy(buf, off, buf, 0, len); // adjust buffer.
             off = 0;
             limit = len;
           }
           break;
         } else {
           int pos = bis.position();
           if (off == pos) {
             remaining = false;
             throw new IOException("Decode without read data.");
           }
           if (msg != null) {
             out.add(msg);
           }
           off = pos;
         }
       } while (bis.available() > 0);
     } while (readable > 0);
   } finally {
     if (remaining) {
       int len = limit - off;
       if (len < buf.length / 2) {
         System.arraycopy(buf, off, buf, 0, len);
         off = 0;
         limit = len;
       }
       mBuffer = buf;
       mOffset = off;
       mLimit = limit;
     } else {
       mBuffer = null;
       mOffset = mLimit = 0;
     }
     com.antrou.dubbo.remoting.netty4.NettyChannel.removeChannelIfDisconnected(ctx.channel());
   }
 }