package io.eguan.nbdsrv.packet; /* * #%L * Project eguan * %% * Copyright (C) 2012 - 2017 Oodrive * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ import java.nio.ByteBuffer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Represents a packet received during the data pushing phase. * * @author oodrive * @author ebredzinski * @author jmcaba * @author llambert */ public final class DataPushingPacket { private static final Logger LOGGER = LoggerFactory.getLogger(DataPushingPacket.class); /** Magic */ public static final long MAGIC = 0x25609513L; /** Static Size */ private static final int HEADER_SIZE = 32 / 8 + 32 / 8 + 64 / 8 + 64 / 8 + 32 / 8; /** Magic Number */ private final long magic; /** Request type */ private final DataPushingCmd type; /** Handle to identify the request */ private final long handle; /** Offset for the read/write request */ private final long from; /** Number of bytes to read/write */ private final long len; /** * Gets the magic number contained in the request. * * @return the magic number */ public final long getMagic() { return magic; } /** * Gets the command type contained int the request. * * @return the {@link DataPushingCmd} */ public final DataPushingCmd getType() { return type; } /** * Gets the handle used in the request to identify itself. * * @return the handle */ public final long getHandle() { return handle; } /** * Gets the offset to read/write data. * * @return the position of the first byte */ public final long getFrom() { return from; } /** * Gets the number of bytes to read/write. * * @return the number of bytes to read/write */ public final long getLen() { return len; } public DataPushingPacket(final long magic, final DataPushingCmd type, final long handle, final long from, final long len) { this.magic = magic; this.type = type; this.handle = handle; this.from = from; this.len = len; } /** * Allocate the header for Data Pushing command. * * @return the {@link ByteBuffer} allocated */ public static final ByteBuffer allocateHeader() { return (ByteBuffer) NbdByteBufferCache.allocate(Utils.MAX_HEADER_SIZE).limit(HEADER_SIZE); } /** * Release the header for Data Pushing command. * * @param the * {@link ByteBuffer} allocated */ public static final void release(final ByteBuffer buffer) { NbdByteBufferCache.release(buffer); } /** * Serialize a Data pushing command. * * @return the {@link ByteBuffer} */ public static final ByteBuffer serialize(final DataPushingPacket packet) { final ByteBuffer buffer = allocateHeader(); Utils.putUnsignedInt(buffer, packet.magic); Utils.putUnsignedInt(buffer, packet.type.value()); Utils.putUnsignedLong(buffer, packet.handle); Utils.putUnsignedLong(buffer, packet.from); Utils.putUnsignedInt(buffer, packet.len); buffer.flip(); return buffer; } /** * Deserialize a Data pushing command. * * @return the {@link DataPushingPacket} */ public static final DataPushingPacket deserialize(final ByteBuffer buffer) { final long magicNumber = Utils.getUnsignedInt(buffer); if (LOGGER.isTraceEnabled()) { LOGGER.trace("magicNumber=0x" + Long.toHexString(magicNumber)); } final DataPushingCmd type = DataPushingCmd.valueOf(Utils.getUnsignedInt(buffer)); if (LOGGER.isTraceEnabled()) { LOGGER.trace("type=0x" + Long.toHexString(type.value())); } // No need to check the sign final long handle = Utils.getUnsignedLong(buffer); if (LOGGER.isTraceEnabled()) { LOGGER.trace("handle=0x" + Long.toHexString(handle)); } final long from; final long len; // The len and from for the command different from READ and WRITE, might be a value which can not be contained // in a signed long, so ignore it if (type == DataPushingCmd.NBD_CMD_READ || type == DataPushingCmd.NBD_CMD_WRITE || type == DataPushingCmd.NBD_CMD_TRIM) { from = Utils.getUnsignedLong(buffer); if (LOGGER.isTraceEnabled()) { LOGGER.trace("from=0x" + Long.toHexString(from)); } len = Utils.getUnsignedInt(buffer); if (LOGGER.isTraceEnabled()) { LOGGER.trace("len=0x" + Long.toHexString(len)); } } else { len = 0; from = 0; } return new DataPushingPacket(magicNumber, type, handle, from, len); } }