예제 #1
0
  /** {@inheritDoc} */
  @Nullable
  @Override
  public GridClientMessage decode(GridNioSession ses, ByteBuffer buf)
      throws IOException, GridException {
    ParserState state = ses.removeMeta(PARSER_STATE_META_NAME);

    if (state == null) state = new ParserState();

    PacketType type = state.packetType();

    if (type == null) {
      byte hdr = buf.get(buf.position());

      switch (hdr) {
        case MEMCACHE_REQ_FLAG:
          state.packet(new GridTcpRestPacket());
          state.packetType(PacketType.MEMCACHE);

          break;
        case GRIDGAIN_REQ_FLAG:
          // Skip header.
          buf.get();

          state.packetType(PacketType.GRIDGAIN);

          break;

        default:
          throw new IOException(
              "Failed to parse incoming packet (invalid packet start) [ses="
                  + ses
                  + ", b="
                  + Integer.toHexString(hdr & 0xFF)
                  + ']');
      }
    }

    GridClientMessage result = null;

    switch (state.packetType()) {
      case MEMCACHE:
        result = parseMemcachePacket(ses, buf, state);

        break;
      case GRIDGAIN:
        result = parseCustomPacket(ses, buf, state);

        break;
    }

    if (result == null)
      // Packet was not fully parsed yet.
      ses.addMeta(PARSER_STATE_META_NAME, state);

    return result;
  }
예제 #2
0
  /**
   * Parses custom packet serialized by hessian marshaller.
   *
   * @param ses Session.
   * @param buf Buffer containing not parsed bytes.
   * @param state Parser state.
   * @return Parsed message.
   * @throws IOException If packet parsing or deserialization failed.
   */
  @Nullable
  private GridClientMessage parseCustomPacket(GridNioSession ses, ByteBuffer buf, ParserState state)
      throws IOException {
    assert state.packetType() == PacketType.GRIDGAIN;
    assert state.packet() == null;

    ByteArrayOutputStream tmp = state.buffer();

    int len = state.index();

    while (buf.remaining() > 0) {
      byte b = buf.get();

      if (len == 0) {
        tmp.write(b);

        if (tmp.size() == 4) {
          len = U.bytesToInt(tmp.toByteArray(), 0);

          tmp.reset();

          if (len == 0) return PING_MESSAGE;
          else if (len < 0)
            throw new IOException(
                "Failed to parse incoming packet (invalid packet length) [ses="
                    + ses
                    + ", len="
                    + len
                    + ']');

          state.index(len);
        }
      } else {
        tmp.write(b);

        if (tmp.size() == len) return marshaller.unmarshal(tmp.toByteArray());
      }
    }

    return null;
  }
예제 #3
0
  /** {@inheritDoc} */
  @Override
  public ByteBuffer encode(GridNioSession ses, GridClientMessage msg)
      throws IOException, GridException {
    assert msg != null;

    if (msg instanceof GridTcpRestPacket) return encodeMemcache((GridTcpRestPacket) msg);
    else if (msg == PING_MESSAGE) return ByteBuffer.wrap(PING_PACKET);
    else {
      byte[] data = marshaller.marshal(msg);

      assert data.length > 0;

      ByteBuffer res = ByteBuffer.allocate(data.length + 5);

      res.put(GRIDGAIN_REQ_FLAG);
      res.put(U.intToBytes(data.length));
      res.put(data);

      res.flip();

      return res;
    }
  }
예제 #4
0
  /**
   * Encodes memcache message to a raw byte array.
   *
   * @param msg Message being serialized.
   * @return Serialized message.
   * @throws GridException If serialization failed.
   */
  private ByteBuffer encodeMemcache(GridTcpRestPacket msg) throws GridException {
    GridByteArrayList res = new GridByteArrayList(HDR_LEN);

    int keyLength = 0;

    int keyFlags = 0;

    if (msg.key() != null) {
      ByteArrayOutputStream rawKey = new ByteArrayOutputStream();

      keyFlags = encodeObj(msg.key(), rawKey);

      msg.key(rawKey.toByteArray());

      keyLength = rawKey.size();
    }

    int dataLength = 0;

    int valFlags = 0;

    if (msg.value() != null) {
      ByteArrayOutputStream rawVal = new ByteArrayOutputStream();

      valFlags = encodeObj(msg.value(), rawVal);

      msg.value(rawVal.toByteArray());

      dataLength = rawVal.size();
    }

    int flagsLength = 0;

    if (msg.addFlags()) // || keyFlags > 0 || valFlags > 0)
    flagsLength = FLAGS_LENGTH;

    res.add(MEMCACHE_RES_FLAG);

    res.add(msg.operationCode());

    // Cast is required due to packet layout.
    res.add((short) keyLength);

    // Cast is required due to packet layout.
    res.add((byte) flagsLength);

    // Data type is always 0x00.
    res.add((byte) 0x00);

    res.add((short) msg.status());

    res.add(keyLength + flagsLength + dataLength);

    res.add(msg.opaque(), 0, msg.opaque().length);

    // CAS, unused.
    res.add(0L);

    assert res.size() == HDR_LEN;

    if (flagsLength > 0) {
      res.add((short) keyFlags);
      res.add((short) valFlags);
    }

    assert msg.key() == null || msg.key() instanceof byte[];
    assert msg.value() == null || msg.value() instanceof byte[];

    if (keyLength > 0) res.add((byte[]) msg.key(), 0, ((byte[]) msg.key()).length);

    if (dataLength > 0) res.add((byte[]) msg.value(), 0, ((byte[]) msg.value()).length);

    return ByteBuffer.wrap(res.entireArray());
  }
예제 #5
0
  /**
   * Parses memcache protocol message.
   *
   * @param ses Session.
   * @param buf Buffer containing not parsed bytes.
   * @param state Current parser state.
   * @return Parsed packet.s
   * @throws IOException If packet cannot be parsed.
   * @throws GridException If deserialization error occurred.
   */
  @Nullable
  private GridClientMessage parseMemcachePacket(
      GridNioSession ses, ByteBuffer buf, ParserState state) throws IOException, GridException {
    assert state.packetType() == PacketType.MEMCACHE;
    assert state.packet() != null;
    assert state.packet() instanceof GridTcpRestPacket;

    GridTcpRestPacket req = (GridTcpRestPacket) state.packet();
    ByteArrayOutputStream tmp = state.buffer();
    int i = state.index();

    while (buf.remaining() > 0) {
      byte b = buf.get();

      if (i == 0) req.requestFlag(b);
      else if (i == 1) req.operationCode(b);
      else if (i == 2 || i == 3) {
        tmp.write(b);

        if (i == 3) {
          req.keyLength(U.bytesToShort(tmp.toByteArray(), 0));

          tmp.reset();
        }
      } else if (i == 4) req.extrasLength(b);
      else if (i >= 8 && i <= 11) {
        tmp.write(b);

        if (i == 11) {
          req.totalLength(U.bytesToInt(tmp.toByteArray(), 0));

          tmp.reset();
        }
      } else if (i >= 12 && i <= 15) {
        tmp.write(b);

        if (i == 15) {
          req.opaque(tmp.toByteArray());

          tmp.reset();
        }
      } else if (i >= HDR_LEN && i < HDR_LEN + req.extrasLength()) {
        tmp.write(b);

        if (i == HDR_LEN + req.extrasLength() - 1) {
          req.extras(tmp.toByteArray());

          tmp.reset();
        }
      } else if (i >= HDR_LEN + req.extrasLength()
          && i < HDR_LEN + req.extrasLength() + req.keyLength()) {
        tmp.write(b);

        if (i == HDR_LEN + req.extrasLength() + req.keyLength() - 1) {
          req.key(tmp.toByteArray());

          tmp.reset();
        }
      } else if (i >= HDR_LEN + req.extrasLength() + req.keyLength()
          && i < HDR_LEN + req.totalLength()) {
        tmp.write(b);

        if (i == HDR_LEN + req.totalLength() - 1) {
          req.value(tmp.toByteArray());

          tmp.reset();
        }
      }

      if (i == HDR_LEN + req.totalLength() - 1)
        // Assembled the packet.
        return assemble(ses, req);

      i++;
    }

    state.index(i);

    return null;
  }