/** * Validates incoming packet and deserializes all fields that need to be deserialized. * * @param ses Session on which packet is being parsed. * @param req Raw packet. * @return Same packet with fields deserialized. * @throws IOException If parsing failed. * @throws GridException If deserialization failed. */ private GridClientMessage assemble(GridNioSession ses, GridTcpRestPacket req) throws IOException, GridException { byte[] extras = req.extras(); // First, decode key and value, if any if (req.key() != null || req.value() != null) { short keyFlags = 0; short valFlags = 0; if (req.hasFlags()) { if (extras == null || extras.length < FLAGS_LENGTH) throw new IOException( "Failed to parse incoming packet (flags required for command) [ses=" + ses + ", opCode=" + Integer.toHexString(req.operationCode() & 0xFF) + ']'); keyFlags = U.bytesToShort(extras, 0); valFlags = U.bytesToShort(extras, 2); } if (req.key() != null) { assert req.key() instanceof byte[]; byte[] rawKey = (byte[]) req.key(); // Only values can be hessian-encoded. req.key(decodeObj(keyFlags, rawKey)); } if (req.value() != null) { assert req.value() instanceof byte[]; byte[] rawVal = (byte[]) req.value(); req.value(decodeObj(valFlags, rawVal)); } } if (req.hasExpiration()) { if (extras == null || extras.length < 8) throw new IOException( "Failed to parse incoming packet (expiration value required for command) [ses=" + ses + ", opCode=" + Integer.toHexString(req.operationCode() & 0xFF) + ']'); req.expiration(U.bytesToInt(extras, 4) & 0xFFFFFFFFL); } if (req.hasInitial()) { if (extras == null || extras.length < 16) throw new IOException( "Failed to parse incoming packet (initial value required for command) [ses=" + ses + ", opCode=" + Integer.toHexString(req.operationCode() & 0xFF) + ']'); req.initial(U.bytesToLong(extras, 8)); } if (req.hasDelta()) { if (extras == null || extras.length < 8) throw new IOException( "Failed to parse incoming packet (delta value required for command) [ses=" + ses + ", opCode=" + Integer.toHexString(req.operationCode() & 0xFF) + ']'); req.delta(U.bytesToLong(extras, 0)); } if (extras != null) { // Clients that include cache name must always include flags. int length = 4; if (req.hasExpiration()) length += 4; if (req.hasDelta()) length += 8; if (req.hasInitial()) length += 8; if (extras.length - length > 0) { byte[] cacheName = new byte[extras.length - length]; System.arraycopy(extras, length, cacheName, 0, extras.length - length); req.cacheName(new String(cacheName)); } } return req; }
/** * 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; }