All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jscsi.parser.BasicHeaderSegment Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (c) 2012, University of Konstanz, Distributed Systems Group All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 * following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of
 * conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation and/or other materials provided with the
 * distribution. * Neither the name of the University of Konstanz nor the names of its contributors may be used to
 * endorse or promote products derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package org.jscsi.parser;


import java.nio.ByteBuffer;

import org.jscsi.exception.InternetSCSIException;
import org.jscsi.utils.Utils;


/**
 * 

BasicHeaderSegment

*

* This class encapsulate a Basic Header Segment (BHS), which is defined in the iSCSI Protocol (RFC3720). It provides * methods for serializing or deserializing such an object. The contained data can be accessed seperately by the getter * methods. *

* The BHS has a fixed size, which is stored in the variable BHS_FIXED_SIZE. And these must the first bytes * in a valid iSCSI Protocol Data Unit (PDU). org.jscsi.utils * * @author Volker Wildi */ public final class BasicHeaderSegment { // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** The BHS has a fixed size of 48 bytes. */ static final int BHS_FIXED_SIZE = 48; /** Offset of the byte 8 till 11 in the BHS. */ static final int BYTES_8_11 = 8; /** Offset of the byte 16 till 19 in the BHS. */ static final int BYTES_16_19 = 16; /** Offset of the byte 20 till 23 in the BHS. */ static final int BYTES_20_23 = 20; // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** Bit mask to extract the immediate flag of a 32 bit number. */ private static final int IMMEDIATE_FLAG_MASK = 0x40000000; /** Bit mask to extract the operation code of a 32 bit number. */ private static final int OPERATION_CODE_MASK = 0x3F000000; /** Bit mask to extract the final flag of a 32 bit number. */ private static final int FINAL_FLAG_MASK = 0x00800000; // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** * For request PDUs, the I bit set to 1 is an immediate delivery marker. */ private boolean immediateFlag; /** * The operation code indicates the type of iSCSI PDU the header encapsulates. The operation codes are divided into * two categories: initiator opcodes and target opcodes. Initiator opcodes are in PDUs sent by the * initiator (request PDUs). Target opcodes are in PDUs sent by the target (response PDUs). *

* Initiators MUST NOT use target opcodes and targets MUST NOT use initiator opcodes. */ private OperationCode operationCode; /** * When set to 1 it indicates the final (or only) PDU of a sequence. */ private boolean finalFlag; /** * Total length of all AHS header segments in units of four byte words including padding, if any. *

* The TotalAHSLength is only used in PDUs that have an AHS and MUST be 0 in all other * PDUs. */ private byte totalAHSLength; /** * This is the data segment payload length in bytes (excluding padding). The DataSegmentLength MUST be * 0 whenever the PDU has no data segment. */ private int dataSegmentLength; /** * The initiator assigns a Task Tag to each iSCSI task it issues. While a task exists, this tag MUST uniquely * identify the task session-wide. SCSI may also use the initiator task tag as part of the SCSI task identifier when * the timespan during which an iSCSI initiator task tag must be unique extends over the timespan during which a * SCSI task tag must be unique. However, the iSCSI Initiator Task Tag must exist and be unique even for untagged * SCSI commands. */ private int initiatorTaskTag; /** The used parser for the messages. */ private AbstractMessageParser parser; // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** Default constructor, creates new, empty BasicHeaderSegment object. */ BasicHeaderSegment () { } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** * This method serializes the informations of this BHS object to the byte representation defined by the iSCSI * Standard. * * @param dst The destination array to write in. * @param offset The start offset in dst. * @return The length (in bytes) of the serialized form of this BHS object. * @throws InternetSCSIException If any violation of the iSCSI-Standard emerge. */ final int serialize (final ByteBuffer dst, final int offset) throws InternetSCSIException { // has the destination array enough space to store this basic header // segment dst.position(offset); if (dst.remaining() < BHS_FIXED_SIZE) { throw new IllegalArgumentException("Destination array is too small."); } int line = 0; if (immediateFlag) { line |= IMMEDIATE_FLAG_MASK; } line |= operationCode.value() << Constants.THREE_BYTES_SHIFT; if (finalFlag) { line |= FINAL_FLAG_MASK; } dst.putInt(line); dst.putInt(dataSegmentLength | (totalAHSLength << Constants.THREE_BYTES_SHIFT)); dst.putInt(BYTES_16_19, initiatorTaskTag); parser.serializeBasicHeaderSegment(dst, offset); return BHS_FIXED_SIZE; } /** * Extract from the given Protocol Data Unit the BHS. After an successful extraction this methods and setreturns the * right message parser object for this kind of message. * * @param protocolDataUnit The reference ProtocolDataUnit instance, which contains this * BasicHeaderSegment object. * @param src The bytes representation of a Protocol Data Unit. * @return The length (in bytes), which are read from pdu. * @throws InternetSCSIException If any violation of the iSCSI-Standard emerge. */ final int deserialize (final ProtocolDataUnit protocolDataUnit, final ByteBuffer src) throws InternetSCSIException { if (src.remaining() < BHS_FIXED_SIZE) { throw new InternetSCSIException("This Protocol Data Unit does not contain" + " an valid Basic Header Segment."); } final int firstLine = src.getInt(); immediateFlag = Utils.isBitSet(firstLine & IMMEDIATE_FLAG_MASK); final int code = (firstLine & OPERATION_CODE_MASK) >> Constants.THREE_BYTES_SHIFT; operationCode = OperationCode.valueOf((byte) code); finalFlag = Utils.isBitSet(firstLine & FINAL_FLAG_MASK); totalAHSLength = src.get(); dataSegmentLength = Utils.getUnsignedInt(src.get()) << Constants.TWO_BYTES_SHIFT; dataSegmentLength += Utils.getUnsignedInt(src.get()) << Constants.ONE_BYTE_SHIFT; dataSegmentLength += Utils.getUnsignedInt(src.get()); initiatorTaskTag = src.getInt(BYTES_16_19); parser = MessageParserFactory.getParser(protocolDataUnit, operationCode); src.rewind(); parser.deserializeBasicHeaderSegment(src); return BHS_FIXED_SIZE; } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** * The Length of the Data Segment. * * @return length of the data segment */ public final int getDataSegmentLength () { return dataSegmentLength; } /** * When this flag is set it indicates the final (or only) PDU of a sequence. In some kinds of messages (PDU) this * methods has the meaning of the TransitFlag. * * @return The state of the final flag. */ public final boolean isFinalFlag () { return finalFlag; } /** * For request PDUs, the immediate flag can be set as an immediate delivery marker. * * @return The state of the immediate flag. */ public final boolean isImmediateFlag () { return immediateFlag; } /** * The initiator assigns a Task Tag to each iSCSI task it issues. While a task exists, this tag MUST uniquely * identify the task session-wide. SCSI may also use the initiator task tag as part of the SCSI task identifier when * the timespan during which an iSCSI initiator task tag must be unique extends over the timespan during which a * SCSI task tag must be unique. However, the iSCSI Initiator Task Tag must exist and be unique even for untagged * SCSI commands. * * @return the initiator task tag. */ public final int getInitiatorTaskTag () { return initiatorTaskTag; } /** * The length of the Additional Header Segment. * * @return The length of the contained AHSs */ public final byte getTotalAHSLength () { return totalAHSLength; } /** * Returns the operation code, which is used in this BHS. * * @return The operation code of this BHS. */ public final OperationCode getOpCode () { return operationCode; } /** * Returns a object of the used parser of this BHS. * * @return The parser object to use for this PDU. */ public final AbstractMessageParser getParser () { return parser; } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** * Set a new length for the data segment. * * @param initDataSegmentLength The new length of this BasicHeaderSegment object. */ final void setDataSegmentLength (final int initDataSegmentLength) { dataSegmentLength = initDataSegmentLength; } /** * Changes the state of the final flag. * * @param initFinalFlag The new state of the final flag. */ final void setFinal (final boolean initFinalFlag) { finalFlag = initFinalFlag; } /** * Changes the state of the immediate flag. * * @param initImmediateFlag The new state of the immediate flag. */ final void setImmediate (final boolean initImmediateFlag) { immediateFlag = initImmediateFlag; } /** * Changes the value of the initiator task tag. * * @param initInitiatorTaskTag The new value of the initiator task tag. */ public final void setInitiatorTaskTag (final int initInitiatorTaskTag) { // FIXME: Change to allow fixed values initiatorTaskTag = initInitiatorTaskTag; } /** * This sets the length (in units of four bytes) of the total length of the given AHS. * * @param initTotalAHSLength The new length. */ final void setTotalAHSLength (final byte initTotalAHSLength) { totalAHSLength = initTotalAHSLength; } /** * Set a new operation code for this BHS object. * * @param protocolDataUnit The reference ProtocolDataUnit instance, which contains this * BasicHeaderSegment object. * @param initOperationCode The new operation code. */ final void setOperationCode (final ProtocolDataUnit protocolDataUnit, final OperationCode initOperationCode) { operationCode = initOperationCode; parser = MessageParserFactory.getParser(protocolDataUnit, initOperationCode); } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** * Creates a string object with all values for easy debugging. * * @return The string with all informations of this BHS. */ public final String toString () { if (parser == null) { final StringBuilder sb = new StringBuilder(); Utils.printField(sb, "ParserClass", "null", 1); Utils.printField(sb, "OpCode", this.getOpCode().toString(), 1); Utils.printField(sb, "FinalFlag", finalFlag, 1); Utils.printField(sb, "TotalAHSLength", totalAHSLength, 1); Utils.printField(sb, "DataSegmentLength", dataSegmentLength, 1); Utils.printField(sb, "InitiatorTaskTag", initiatorTaskTag, 1); return sb.toString(); } final StringBuilder sb = new StringBuilder(Constants.LOG_INITIAL_SIZE); Utils.printField(sb, "ParserClass", parser.getClass().getSimpleName(), 1); Utils.printField(sb, "ImmediateFlag", immediateFlag, 1); Utils.printField(sb, "OpCode", operationCode.value(), 1); Utils.printField(sb, "FinalFlag", finalFlag, 1); Utils.printField(sb, "TotalAHSLength", totalAHSLength, 1); Utils.printField(sb, "DataSegmentLength", dataSegmentLength, 1); Utils.printField(sb, "InitiatorTaskTag", initiatorTaskTag, 1); sb.append(parser.toString()); return sb.toString(); } /** {@inheritDoc} */ @Override final public boolean equals (Object o) { if (o instanceof BasicHeaderSegment == false) return false; BasicHeaderSegment oBhs = (BasicHeaderSegment) o; if (oBhs.isFinalFlag() == this.isFinalFlag() && oBhs.isImmediateFlag() == this.isImmediateFlag() && oBhs.getParser().getClass() == this.getParser().getClass() && oBhs.getDataSegmentLength() == this.getDataSegmentLength() && oBhs.getInitiatorTaskTag() == this.getInitiatorTaskTag() && oBhs.getOpCode().compareTo(this.getOpCode()) == 0 && oBhs.getTotalAHSLength() == this.getTotalAHSLength()) return true; return false; } @Override public int hashCode() { int result = super.hashCode(); result = 31 * result + (immediateFlag ? 1 : 0); result = 31 * result + (operationCode != null ? operationCode.hashCode() : 0); result = 31 * result + (finalFlag ? 1 : 0); result = 31 * result + (int) totalAHSLength; result = 31 * result + dataSegmentLength; result = 31 * result + initiatorTaskTag; result = 31 * result + (parser != null ? parser.hashCode() : 0); return result; } /** * Clears all the stored content of this BasicHeaderSegment object. */ final void clear () { immediateFlag = false; operationCode = OperationCode.LOGIN_REQUEST; finalFlag = false; totalAHSLength = 0x00; dataSegmentLength = 0x00000000; initiatorTaskTag = 0x00000000; parser = null; } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy