private boolean handleCompressedFrame(ChannelHandlerContext ctx, ByteBuf in, List<Object> out)
      throws Exception {
    if (!in.isReadable(FRAME_COMPRESS_HEADER_LENGTH)) {
      return false;
    }

    int compressedPayloadLength = in.readInt();
    if (!in.isReadable(compressedPayloadLength)) {
      return false;
    }

    // decompress payload
    Inflater inflater = new Inflater();
    if (in.hasArray()) {
      inflater.setInput(in.array(), in.arrayOffset() + in.readerIndex(), compressedPayloadLength);
      in.skipBytes(compressedPayloadLength);
    } else {
      byte[] array = new byte[compressedPayloadLength];
      in.readBytes(array);
      inflater.setInput(array);
    }

    while (!inflater.finished()) {
      ByteBuf decompressed = ctx.alloc().heapBuffer(1024, 1024);
      byte[] outArray = decompressed.array();
      int count =
          inflater.inflate(outArray, decompressed.arrayOffset(), decompressed.writableBytes());
      decompressed.writerIndex(count);
      // put data in the pipeline
      out.add(decompressed);
    }

    return true;
  }
  /**
   * Read a string that is prefixed by its length encoded by a 4 bytes integer.
   *
   * @param in the buffer to consume
   * @return the read string or {@code null} if not enough data available to read the whole string
   */
  private String readLengthPrefixedString(ByteBuf in) {
    if (!in.isReadable(INT_LENGTH)) {
      return null;
    }
    int length = in.readInt();
    if (!in.isReadable(length)) {
      return null;
    }

    String str = in.toString(in.readerIndex(), length, StandardCharsets.UTF_8);
    in.skipBytes(length);
    return str;
  }
  /**
   * This test makes sure that even when the decoder is confronted with various chunk sizes in the
   * middle of decoding, it can recover and decode all the time eventually.
   */
  @Test
  public void shouldHandleNonUniformNetworkBatches() {
    ByteBuf incoming = Unpooled.copiedBuffer(SET_REQUEST_WITH_CONTENT);
    while (incoming.isReadable()) {
      channel.writeInbound(incoming.readBytes(5));
    }

    BinaryMemcacheRequest request = (BinaryMemcacheRequest) channel.readInbound();

    assertThat(request, notNullValue());
    assertThat(request.getHeader(), notNullValue());
    assertThat(request.getKey(), notNullValue());
    assertThat(request.getExtras(), nullValue());

    request.release();

    MemcacheContent content1 = (MemcacheContent) channel.readInbound();
    MemcacheContent content2 = (MemcacheContent) channel.readInbound();

    assertThat(content1, instanceOf(MemcacheContent.class));
    assertThat(content2, instanceOf(LastMemcacheContent.class));

    assertThat(content1.content().readableBytes(), is(3));
    assertThat(content2.content().readableBytes(), is(5));

    content1.release();
    content2.release();
  }
Beispiel #4
0
 /**
  * Converts the specified Netty {@link ByteBuf} into an {@link HttpData}. Unlike {@link
  * #of(byte[])}, this method makes a copy of the {@link ByteBuf}.
  *
  * @return a new {@link HttpData}. {@link #EMPTY_DATA} if the readable bytes of {@code buf} is 0.
  */
 static HttpData of(ByteBuf buf) {
   requireNonNull(buf, "buf");
   if (!buf.isReadable()) {
     return EMPTY_DATA;
   }
   return of(ByteBufUtil.getBytes(buf));
 }
 @Override
 public void flush() throws IOException {
   if (buf.isReadable()) {
     writeToChannel();
   }
   chc.flush();
 }
  @Override
  public Subobject parseSubobject(final ByteBuf buffer, final boolean loose)
      throws PCEPDeserializerException {
    Preconditions.checkArgument(
        buffer != null && buffer.isReadable(),
        "Array of bytes is mandatory. Can't be null or empty.");
    if (buffer.readableBytes() < HEADER_LENGTH) {
      throw new PCEPDeserializerException(
          "Wrong length of array of bytes. Passed: "
              + buffer.readableBytes()
              + "; Expected: >"
              + HEADER_LENGTH
              + ".");
    }
    final BitArray reserved = BitArray.valueOf(buffer, FLAGS_SIZE);
    final short cType = buffer.readUnsignedByte();

    final LabelType labelType = this.registry.parseLabel(cType, buffer.slice());
    if (labelType == null) {
      throw new PCEPDeserializerException(
          "Unknown C-TYPE for ero label subobject. Passed: " + cType);
    }
    final LabelBuilder builder = new LabelBuilder();
    builder.setUniDirectional(reserved.get(U_FLAG_OFFSET));
    builder.setLabelType(labelType);
    return new SubobjectBuilder()
        .setLoose(loose)
        .setSubobjectType(new LabelCaseBuilder().setLabel(builder.build()).build())
        .build();
  }
 @Override
 protected int doWrite(MessageList<Object> msgs, int index) throws Exception {
   int size = msgs.size();
   int writeIndex = index;
   for (; ; ) {
     if (writeIndex >= size) {
       break;
     }
     Object msg = msgs.get(writeIndex);
     if (msg instanceof ByteBuf) {
       ByteBuf buf = (ByteBuf) msg;
       while (buf.isReadable()) {
         doWriteBytes(buf);
       }
       buf.release();
       writeIndex++;
     } else if (msg instanceof FileRegion) {
       FileRegion region = (FileRegion) msg;
       doWriteFileRegion(region);
       region.release();
       writeIndex++;
     } else {
       throw new UnsupportedOperationException(
           "unsupported message type: " + StringUtil.simpleClassName(msg));
     }
   }
   return writeIndex - index;
 }
Beispiel #8
0
  private Object[] encodeContent(HttpMessage header, HttpContent c) {
    ByteBuf newContent = Unpooled.buffer();
    ByteBuf content = c.data();
    encode(content, newContent);

    if (c instanceof LastHttpContent) {
      ByteBuf lastProduct = Unpooled.buffer();
      finishEncode(lastProduct);

      // Generate an additional chunk if the decoder produced
      // the last product on closure,
      if (lastProduct.isReadable()) {
        if (header == null) {
          return new Object[] {
            new DefaultHttpContent(newContent), new DefaultLastHttpContent(lastProduct)
          };
        } else {
          return new Object[] {
            header, new DefaultHttpContent(newContent), new DefaultLastHttpContent(lastProduct)
          };
        }
      }
    }
    if (header == null) {
      return new Object[] {new DefaultHttpContent(newContent)};
    } else {
      return new Object[] {header, new DefaultHttpContent(newContent)};
    }
  }
 @Override
 public void split(ChannelHandlerContext ctx, ByteBuf input, List<Object> list) throws Exception {
   input.markReaderIndex();
   final byte[] array = new byte[3];
   for (int i = 0; i < array.length; ++i) {
     if (!input.isReadable()) {
       input.resetReaderIndex();
       return;
     }
     array[i] = input.readByte();
     if (array[i] >= 0) {
       final PacketDataSerializer packetDataSerializer =
           new PacketDataSerializer(
               Unpooled.wrappedBuffer(array), ProtocolVersion.MINECRAFT_1_7_10);
       try {
         final int length = packetDataSerializer.readVarInt();
         if (input.readableBytes() < length) {
           input.resetReaderIndex();
           return;
         }
         list.add(input.readBytes(length));
         return;
       } finally {
         packetDataSerializer.release();
       }
     }
   }
   throw new CorruptedFrameException("length wider than 21-bit");
 }
Beispiel #10
0
    /**
     * Reads the content of the entry into a new buffer. Use {@link #readContent(ByteBufAllocator,
     * InputStream, int)} when the length of the stream is known.
     */
    protected ByteBuf readContent(ByteBufAllocator alloc, InputStream in) throws IOException {
      ByteBuf buf = null;
      boolean success = false;
      try {
        buf = alloc.directBuffer();
        for (; ; ) {
          if (buf.writeBytes(in, 8192) < 0) {
            break;
          }
        }

        success = true;

        if (buf.isReadable()) {
          return buf;
        } else {
          buf.release();
          return Unpooled.EMPTY_BUFFER;
        }
      } finally {
        if (!success && buf != null) {
          buf.release();
        }
      }
    }
  protected void checkCloseFrameBody(ChannelHandlerContext ctx, ByteBuf buffer) {
    if (buffer == null || buffer.capacity() == 0) {
      return;
    }
    if (buffer.capacity() == 1) {
      protocolViolation(ctx, "Invalid close frame body");
    }

    // Save reader index
    int idx = buffer.readerIndex();
    buffer.readerIndex(0);

    // Must have 2 byte integer within the valid range
    int statusCode = buffer.readShort();
    if (statusCode >= 0 && statusCode <= 999
        || statusCode >= 1004 && statusCode <= 1006
        || statusCode >= 1012 && statusCode <= 2999) {
      protocolViolation(ctx, "Invalid close frame getStatus code: " + statusCode);
    }

    // May have UTF-8 message
    if (buffer.isReadable()) {

      try {
        new UTF8Output(buffer);
      } catch (UTF8Exception ex) {
        protocolViolation(ctx, "Invalid close frame reason text. Invalid UTF-8 bytes");
      }
    }

    // Restore reader index
    buffer.readerIndex(idx);
  }
    /**
     * Decodes the client connection preface string from the input buffer.
     *
     * @return {@code true} if processing of the client preface string is complete. Since client
     *     preface strings can only be received by servers, returns true immediately for client
     *     endpoints.
     */
    private boolean readClientPrefaceString(ByteBuf in) throws Http2Exception {
      if (clientPrefaceString == null) {
        return true;
      }

      int prefaceRemaining = clientPrefaceString.readableBytes();
      int bytesRead = min(in.readableBytes(), prefaceRemaining);

      // If the input so far doesn't match the preface, break the connection.
      if (bytesRead == 0
          || !ByteBufUtil.equals(
              in,
              in.readerIndex(),
              clientPrefaceString,
              clientPrefaceString.readerIndex(),
              bytesRead)) {
        String receivedBytes =
            hexDump(
                in, in.readerIndex(), min(in.readableBytes(), clientPrefaceString.readableBytes()));
        throw connectionError(
            PROTOCOL_ERROR,
            "HTTP/2 client preface string missing or corrupt. " + "Hex dump for received bytes: %s",
            receivedBytes);
      }
      in.skipBytes(bytesRead);
      clientPrefaceString.skipBytes(bytesRead);

      if (!clientPrefaceString.isReadable()) {
        // Entire preface has been read.
        clientPrefaceString.release();
        clientPrefaceString = null;
        return true;
      }
      return false;
    }
  private boolean handleDataFrame(ByteBuf in, List<Object> out) {
    if (!in.isReadable(FRAME_DATA_HEADER_LENGTH)) {
      return false;
    }

    int sequenceNumber = in.readInt();
    int entriesCount = in.readInt();

    Map<String, String> dataMessage = new LinkedHashMap<>();

    while (entriesCount-- > 0) {
      String key = readLengthPrefixedString(in);
      if (key == null) {
        return false;
      }

      String value = readLengthPrefixedString(in);
      if (value == null) {
        return false;
      }

      dataMessage.put(key, value);
    }

    out.add(new LumberjackMessage(sequenceNumber, dataMessage));
    return true;
  }
 @Override
 protected void channelRead0(ChannelHandlerContext ctx, FullHttpResponse msg) throws Exception {
   Integer streamId =
       msg.headers().getInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text());
   if (streamId == null) {
     logger.error("HttpResponseHandler unexpected message received: " + msg);
     return;
   }
   onResponseReceived(ctx, streamIdUrlMap.get(streamId));
   Map.Entry<ChannelFuture, ChannelPromise> entry = streamIdPromiseMap.get(streamId);
   if (entry == null) {
     logger.error("Message received for unknown stream id " + streamId);
   } else {
     // Do stuff with the message (for now just print it)
     ByteBuf content = msg.content();
     ContentType contentType = ContentType.parse(msg.headers().get(HttpHeaderNames.CONTENT_TYPE));
     if (content.isReadable()) {
       int contentLength = content.readableBytes();
       byte[] arr = new byte[contentLength];
       content.readBytes(arr);
       handleContent(arr, ctx, contentType);
     }
     entry.getValue().setSuccess();
   }
 }
Beispiel #15
0
  private void wrap(ChannelHandlerContext ctx, boolean inUnwrap) throws SSLException {
    ByteBuf out = null;
    ChannelPromise promise = null;
    ByteBufAllocator alloc = ctx.alloc();
    try {
      for (; ; ) {
        Object msg = pendingUnencryptedWrites.current();
        if (msg == null) {
          break;
        }

        ByteBuf buf = (ByteBuf) msg;
        if (out == null) {
          out = allocateOutNetBuf(ctx, buf.readableBytes());
        }

        SSLEngineResult result = wrap(alloc, engine, buf, out);
        if (!buf.isReadable()) {
          promise = pendingUnencryptedWrites.remove();
        } else {
          promise = null;
        }

        if (result.getStatus() == Status.CLOSED) {
          // SSLEngine has been closed already.
          // Any further write attempts should be denied.
          pendingUnencryptedWrites.removeAndFailAll(SSLENGINE_CLOSED);
          return;
        } else {
          switch (result.getHandshakeStatus()) {
            case NEED_TASK:
              runDelegatedTasks();
              break;
            case FINISHED:
              setHandshakeSuccess();
              // deliberate fall-through
            case NOT_HANDSHAKING:
              setHandshakeSuccessIfStillHandshaking();
              // deliberate fall-through
            case NEED_WRAP:
              finishWrap(ctx, out, promise, inUnwrap);
              promise = null;
              out = null;
              break;
            case NEED_UNWRAP:
              return;
            default:
              throw new IllegalStateException(
                  "Unknown handshake status: " + result.getHandshakeStatus());
          }
        }
      }
    } catch (SSLException e) {
      setHandshakeFailure(ctx, e);
      throw e;
    } finally {
      finishWrap(ctx, out, promise, inUnwrap);
    }
  }
  private boolean handleWindowFrame(ByteBuf in) {
    if (!in.isReadable(FRAME_WINDOW_HEADER_LENGTH)) {
      return false;
    }

    // update window size
    sessionHandler.windowSizeRead(in.readInt());
    return true;
  }
 public DestroyAllIdentificator(ByteBuf pBuf, int pTargetOrMeta, int pChainOrMeta) {
   this();
   // Target
   if (pBuf.isReadable(4)) {
     for (int li = pBuf.readInt(); li > 0; li--) {
       add(pBuf.readInt(), pBuf.readByte() | pTargetOrMeta);
     }
   }
   // Chain
   if (pBuf.isReadable(4)) {
     int li = pBuf.readInt();
     if (li > 0) {
       chain = new DestroyAllIdentificator();
       for (; li > 0; li--) {
         chain.add(pBuf.readInt(), pBuf.readByte() | pChainOrMeta);
       }
     }
   }
 }
Beispiel #18
0
  private void write(ByteBuf buff, boolean end) {
    int readableBytes = buff.readableBytes();
    if (readableBytes == 0 && !end) {
      // nothing to write to the connection just return
      return;
    }

    if (end) {
      completed = true;
    }
    if (!end && !chunked && !contentLengthSet()) {
      throw new IllegalStateException(
          "You must set the Content-Length header to be the total size of the message "
              + "body BEFORE sending any data if you are not using HTTP chunked encoding.");
    }

    written += buff.readableBytes();
    if (conn == null) {
      if (pendingChunks == null) {
        pendingChunks = buff;
      } else {
        CompositeByteBuf pending;
        if (pendingChunks instanceof CompositeByteBuf) {
          pending = (CompositeByteBuf) pendingChunks;
        } else {
          pending = Unpooled.compositeBuffer();
          pending.addComponent(pendingChunks).writerIndex(pendingChunks.writerIndex());
          pendingChunks = pending;
        }
        pending.addComponent(buff).writerIndex(pending.writerIndex() + buff.writerIndex());
      }
      connect();
    } else {
      if (!headWritten) {
        writeHeadWithContent(buff, end);
      } else {
        if (end) {
          if (buff.isReadable()) {
            conn.writeToChannel(new DefaultLastHttpContent(buff, false));
          } else {
            conn.writeToChannel(LastHttpContent.EMPTY_LAST_CONTENT);
          }
        } else {
          conn.writeToChannel(new DefaultHttpContent(buff));
        }
      }
      if (end) {
        conn.reportBytesWritten(written);

        if (respHandler != null) {
          conn.endRequest();
        }
      }
    }
  }
Beispiel #19
0
 /**
  * Calls {@link SSLEngine#unwrap(ByteBuffer, ByteBuffer)} with an empty buffer to handle
  * handshakes, etc.
  */
 private void unwrapNonApp(ChannelHandlerContext ctx) throws SSLException {
   try {
     unwrapSingle(ctx, Unpooled.EMPTY_BUFFER.nioBuffer(), 0);
   } finally {
     ByteBuf decodeOut = this.decodeOut;
     if (decodeOut != null && decodeOut.isReadable()) {
       this.decodeOut = null;
       ctx.fireChannelRead(decodeOut);
     }
   }
 }
 @Override
 public void fromBytes(ByteBuf buf) {
   dimension = ByteBufUtils.readVarInt(buf, 5);
   key = BoundingBoxDeserializer.deserialize(buf);
   boundingBoxes = new HashSet<BoundingBox>();
   while (buf.isReadable()) {
     BoundingBox boundingBox = BoundingBoxDeserializer.deserialize(buf);
     boundingBoxes.add(boundingBox);
   }
   if (boundingBoxes.size() == 0) boundingBoxes.add(key);
 }
  @Test
  public void testDummyIncomingAck() {
    ByteBuf expectResult = Unpooled.wrappedBuffer(new byte[] {(byte) 0x82, 0x00, 0x00});

    ch.writeOutbound(UsnMessageHelper.makeDummyIncomingAck());

    ByteBuf outBuff = (ByteBuf) ch.readOutbound();

    while (expectResult.isReadable()) {
      assertEquals(expectResult.readUnsignedByte(), outBuff.readUnsignedByte());
    }
  }
  private static void parseHeaders(@NotNull HttpResponse response, @NotNull ByteBuf buffer) {
    StringBuilder builder = new StringBuilder();
    while (buffer.isReadable()) {
      builder.setLength(0);

      String key = null;
      boolean valueExpected = true;
      while (true) {
        int b = buffer.readByte();
        if (b < 0 || b == '\n') {
          break;
        }

        if (b != '\r') {
          if (valueExpected && b == ':') {
            valueExpected = false;

            key = builder.toString();
            builder.setLength(0);
            MessageDecoder.skipWhitespace(buffer);
          } else {
            builder.append((char) b);
          }
        }
      }

      if (builder.length() == 0) {
        // end of headers
        return;
      }

      // skip standard headers
      if (StringUtil.isEmpty(key)
          || StringUtilRt.startsWithIgnoreCase(key, "http")
          || StringUtilRt.startsWithIgnoreCase(key, "X-Accel-")) {
        continue;
      }

      String value = builder.toString();
      if (key.equalsIgnoreCase("status")) {
        int index = value.indexOf(' ');
        if (index == -1) {
          LOG.warn("Cannot parse status: " + value);
          response.setStatus(HttpResponseStatus.OK);
        } else {
          response.setStatus(
              HttpResponseStatus.valueOf(Integer.parseInt(value.substring(0, index))));
        }
      } else if (!(key.startsWith("http") || key.startsWith("HTTP"))) {
        response.headers().add(key, value);
      }
    }
  }
 @Override
 public void channelRead(ChannelHandlerContext ctx, Object msg) { // (2)
   ByteBuf in = (ByteBuf) msg;
   try {
     while (in.isReadable()) { // (1)
       System.out.print((char) in.readByte());
       System.out.flush();
     }
   } finally {
     ReferenceCountUtil.release(msg); // (2)
   }
 }
Beispiel #24
0
 @Override
 public ByteBuf translateFrame(ByteBuf readBuffer)
     throws LimitExedeedException, InvalidDataException {
   while (readBuffer.isReadable()) {
     switch (status) {
       case STATUS_H:
         h = readBuffer.readByte();
         status = STATUS_L;
         break;
       case STATUS_L:
         l = readBuffer.readByte();
         final int blen =
             Protocol.order == ByteOrder.BIG_ENDIAN
                 ? (0x0000ff00 & (h << 8)) | (0x000000ff & l)
                 : (0x0000ff00 & (l << 8)) | (0x000000ff & h);
         if (context != null) {
           if (blen <= 0 || blen > maxFrameSize) {
             throw new LimitExedeedException("帧长度非法:" + h + "/" + l + ":" + blen);
           }
         }
         incompleteframe = PooledByteBufAllocator.DEFAULT.buffer(blen + 16 + 2);
         incompleteframe = incompleteframe.order(Protocol.order);
         incompleteframe.writeShort(blen);
         status = STATUS_C;
         break;
       case STATUS_C:
         int len = incompleteframe.writableBytes() - 16;
         len = len < readBuffer.readableBytes() ? len : readBuffer.readableBytes();
         // incompleteframe.writeBytes(readBuffer, len);
         if (readBuffer.hasMemoryAddress()) {
           PlatformDependent.copyMemory(
               readBuffer.memoryAddress() + readBuffer.readerIndex(),
               incompleteframe.memoryAddress() + incompleteframe.writerIndex(),
               len);
         } else if (readBuffer.hasArray()) {
           PlatformDependent.copyMemory(
               readBuffer.array(),
               readBuffer.arrayOffset() + readBuffer.readerIndex(),
               incompleteframe.memoryAddress() + incompleteframe.writerIndex(),
               len);
         }
         incompleteframe.writerIndex(incompleteframe.writerIndex() + len);
         readBuffer.readerIndex(readBuffer.readerIndex() + len);
         if ((incompleteframe.writableBytes() - 16) <= 0) {
           status = STATUS_H;
           return incompleteframe;
         }
         break;
     }
   }
   return null;
 }
 /**
  * Read the next decoded {@link ByteBuf} from the {@link EmbeddedChannel} or {@code null} if one
  * does not exist.
  *
  * @param decoder The channel to read from
  * @return The next decoded {@link ByteBuf} from the {@link EmbeddedChannel} or {@code null} if
  *     one does not exist
  */
 private static ByteBuf nextReadableBuf(EmbeddedChannel decoder) {
   for (; ; ) {
     final ByteBuf buf = decoder.readInbound();
     if (buf == null) {
       return null;
     }
     if (!buf.isReadable()) {
       buf.release();
       continue;
     }
     return buf;
   }
 }
Beispiel #26
0
  // make sure we don't return without first releasing the file reference content
  @Override
  public ReturnOption handle(FileDescriptor file, ByteBuf data) {
    if (file == FileDescriptor.FINAL) return this.downstream.handle(file, data);

    ByteBuf in = data;

    if (in != null) {
      while (in.isReadable()) {
        int amt = Math.min(in.readableBytes(), this.size - this.currchunk);

        ByteBuf out = in.copy(in.readerIndex(), amt);

        in.skipBytes(amt);
        this.currchunk += amt;

        boolean eof = (this.currchunk == this.size) || (!in.isReadable() && file.isEof());

        this.nextMessage(out, file, eof);

        if (eof) {
          this.seqnum++;
          this.currchunk = 0;
        }
      }

      in.release();
    } else if (file.isEof()) {
      this.nextMessage(null, file, false);
    }

    // write all messages in the queue
    while (this.outlist.size() > 0) {
      ReturnOption ret = this.downstream.handle(this.outlist.remove(0), this.outbuf.remove(0));

      if (ret != ReturnOption.CONTINUE) return ret;
    }

    return ReturnOption.CONTINUE;
  }
Beispiel #27
0
 private void getParams() {
   if (request.method() == HttpMethod.GET) {
     params = null;
   } else if (request.method() == HttpMethod.POST) {
     ByteBuf content = request.content();
     if (content.isReadable()) {
       String param = content.toString(WaarpStringUtils.UTF8);
       QueryStringDecoder queryStringDecoder2 = new QueryStringDecoder("/?" + param);
       params = queryStringDecoder2.parameters();
     } else {
       params = null;
     }
   }
 }
 private void processUtf8(ByteBuf in, ByteBuf out, boolean jsonpMode) {
   while (in.isReadable()) {
     short value = (short) (in.readByte() & 0xFF);
     if (value >>> 7 == 0) {
       if (jsonpMode && (value == '\\' || value == '\'')) {
         out.writeByte('\\');
       }
       out.writeByte(value);
     } else {
       out.writeByte(((value >>> 6) | 0xC0));
       out.writeByte(((value & 0x3F) | 0x80));
     }
   }
 }
 @Override
 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
   ByteBuf in = (ByteBuf) msg;
   try {
     // System.out.println(in.toString());
     while (in.isReadable()) {
       System.out.print((char) in.readByte());
       System.out.flush();
     }
   } finally {
     // same as in.release();
     ReferenceCountUtil.release(msg);
   }
 }
  @Override
  protected void channelRead0(io.netty.channel.ChannelHandlerContext ctx, PacketsMessage message)
      throws Exception {
    ByteBuf content = message.getContent();
    MainBaseClient client = message.getClient();

    if (log.isTraceEnabled()) {
      log.trace(
          "In message: {} sessionId: {}",
          content.toString(CharsetUtil.UTF_8),
          client.getSessionId());
    }
    while (content.isReadable()) {
      try {
        Packet packet = decoder.decodePackets(content, client.getSessionId());
        Namespace ns = namespacesHub.get(packet.getEndpoint());
        if (ns == null) {
          log.debug(
              "Can't find namespace for endpoint: {}, sessionId: {} probably it was removed.",
              packet.getEndpoint(),
              client.getSessionId());
          return;
        }

        if (packet.getType() == PacketType.CONNECT) {
          client.addChildClient(ns);
        }

        NamespaceClient nClient = (NamespaceClient) client.getChildClient(ns);
        if (nClient == null) {
          log.debug(
              "Can't find namespace client in namespace: {}, sessionId: {} probably it was disconnected.",
              ns.getName(),
              client.getSessionId());
          return;
        }
        packetListener.onPacket(packet, nClient);
      } catch (Exception ex) {
        String c = content.toString(CharsetUtil.UTF_8);
        log.error(
            "Error during data processing. Client sessionId: "
                + client.getSessionId()
                + ", data: "
                + c,
            ex);
        return;
      }
    }
  }