/** * 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 <COPYRIGHT HOLDER> 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.parser.datasegment.DataSegmentFactory.DataSegmentFormat; import org.jscsi.utils.Utils; /** * <h1>AbstractMessageParser</h1> * <p> * Abstract class from which each parser (initiator or target message parser) for a specific Protocol Data * Unit (PDU) is inherited. The version of iSCSI Protocol is the RFC3720. * * @author Volker Wildi */ public abstract class AbstractMessageParser { // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** Bit mask to extract the first operation code specific field. */ private static final int FIRST_SPECIFIC_FIELD_MASK = 0x007FFFFF; // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** * The <b>read-only</b> reference to the <code>ProtocolDataUnit</code> instance, which contains this * <code>AbstractMessageParser</code> type. */ protected final ProtocolDataUnit protocolDataUnit; // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** * Some opcodes operate on a specific Logical Unit. The Logical Unit Number * (LUN) field identifies which Logical Unit. If the opcode does not relate * to a Logical Unit, this field is either ignored or may be used in an * opcode specific way. The LUN field is 64-bits and should be formatted in * accordance with [SAM2]. For example, LUN[0] from [SAM2] is BHS byte <code>8</code> and so on up to * LUN[7] from [SAM2], which is BHS byte <code>15</code>. */ protected long logicalUnitNumber; // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** * Default Contructor to create a new, empty AbstractMessageParser object. * * @param initProtocolDataUnit * The reference <code>ProtocolDataUnit</code> instance, which * contains this <code>AbstractMessageParser</code> object. */ public AbstractMessageParser(final ProtocolDataUnit initProtocolDataUnit) { protocolDataUnit = initProtocolDataUnit; } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** * This method defines the order of the parsing process of the operation * code specific fields and check their integtity. * * @param pdu * Array which contains the total Protocol Data Unit. * @throws InternetSCSIException * If any violation of the iSCSI-Standard emerge. */ final void deserializeBasicHeaderSegment(final ByteBuffer pdu) throws InternetSCSIException { deserializeBytes1to3(pdu.getInt() & FIRST_SPECIFIC_FIELD_MASK); pdu.position(BasicHeaderSegment.BYTES_8_11); deserializeBytes8to11(pdu.getInt()); deserializeBytes12to15(pdu.getInt()); pdu.position(BasicHeaderSegment.BYTES_20_23); deserializeBytes20to23(pdu.getInt()); deserializeBytes24to27(pdu.getInt()); deserializeBytes28to31(pdu.getInt()); deserializeBytes32to35(pdu.getInt()); deserializeBytes36to39(pdu.getInt()); deserializeBytes40to43(pdu.getInt()); deserializeBytes44to47(pdu.getInt()); } /** * This method serializes the whole BHS to its byte representation. * * @param dst * The destination <code>ByteBuffer</code> to write to. * @param offset * The start offset in <code>dst</code>. * @throws InternetSCSIException * If any violation of the iSCSI-Standard emerge. */ final void serializeBasicHeaderSegment(final ByteBuffer dst, final int offset) throws InternetSCSIException { dst.position(offset); dst.putInt(offset, dst.getInt() | serializeBytes1to3()); dst.position(offset + BasicHeaderSegment.BYTES_8_11); dst.putInt(serializeBytes8to11()); dst.putInt(serializeBytes12to15()); dst.position(offset + BasicHeaderSegment.BYTES_20_23); dst.putInt(serializeBytes20to23()); dst.putInt(serializeBytes24to27()); dst.putInt(serializeBytes28to31()); dst.putInt(serializeBytes32to35()); dst.putInt(serializeBytes36to39()); dst.putInt(serializeBytes40to43()); dst.putInt(serializeBytes44to47()); } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** * If this method returns <code>true</code>, hen it indicates that the data * segment data is interpreted as binary data. Else the data segment data * must be interpreted as Text Format. * * @return Returns a format defined by the DataSegmentFormat enumeration. * @see DataSegmentFormat */ public abstract DataSegmentFormat getDataSegmentFormat(); /** * If this method returns <code>true</code>, it indicates that this derived * AbstractMessageParser can contain one or more Additional Header Segments. * * @return Returns <code>true</code>, if this AbstractMessageParser object * can contain one or more AHSs. * @see AdditionalHeaderSegment */ public boolean canContainAdditionalHeaderSegments() { return false; } /** * If this method returns <code>true</code>, then it indicates that this * derived <code>AbstractMessageParser</code> instance can be protected by a * digest. * * @return <code>true</code>, if the ProtocolDataUnit can be protected by a * header and/or a data digest. Else <code>false</code>. */ public boolean canHaveDigests() { return true; } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** * Returns the short version of the used sequence numbers of this parser * instance. * * @return The string with all needed sequence numbers. */ public abstract String getShortInfo(); /** * This method concatenate all the fields of a derived parser to allow an * easy generation of debug informations. * * @return The debug formatted string. */ public String toString() { final StringBuilder sb = new StringBuilder(Constants.LOG_INITIAL_SIZE); sb.append("ParserType: "); sb.append(AbstractMessageParser.class); return sb.toString(); } /** * This method sets all settings to their initial values. */ public void clear() { logicalUnitNumber = 0x0000000000000000L; } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** * This <code>AbstractMessageParser</code> instance affects the * incrementation of a <code>Sequence Number</code> counter. * * @return <code>true</code>, if the counter has to be incremented. */ public abstract boolean incrementSequenceNumber(); /** * Returns the Logical Unit Number (LUN) of this <code>AbstractMessageParser</code> object. * * @return The Logical Unit Number of this object. */ public final long getLogicalUnitNumber() { return logicalUnitNumber; } /** * Set the Logical Unit Number (LUN) of this <code>AbstractMessageParser</code> object. * * @param logicalUnitNumber * The Logical Unit Number of this object. */ public final void setLogicalUnitNumber(final long logicalUnitNumber) { this.logicalUnitNumber = logicalUnitNumber; } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** * Parse the bytes <code>1</code> till <code>3</code> in the Basic Header * Segment. * * @param line * The actual line * @throws InternetSCSIException * If any violation of the iSCSI-Standard emerge. */ protected abstract void deserializeBytes1to3(final int line) throws InternetSCSIException; /** * Parse the bytes <code>8</code> till <code>11</code> in the Basic Header * Segment. * * @param line * The actual line * @throws InternetSCSIException * If any violation of the iSCSI-Standard emerge. */ protected void deserializeBytes8to11(final int line) throws InternetSCSIException { logicalUnitNumber = Utils.getUnsignedLong(line); logicalUnitNumber <<= Constants.FOUR_BYTES_SHIFT; } /** * Parse the bytes <code>12</code> till <code>15</code> in the Basic Header * Segment. * * @param line * The actual line * @throws InternetSCSIException * If any violation of the iSCSI-Standard emerge. */ protected void deserializeBytes12to15(final int line) throws InternetSCSIException { logicalUnitNumber |= Utils.getUnsignedLong(line); } /** * Parse the bytes <code>20</code> till <code>23</code> in the Basic Header * Segment. * * @param line * The actual line * @throws InternetSCSIException * If any violation of the iSCSI-Standard emerge. */ protected abstract void deserializeBytes20to23(final int line) throws InternetSCSIException; /** * Parse the bytes <code>24</code> till <code>27</code> in the Basic Header * Segment. * * @param line * The actual line * @throws InternetSCSIException * If any violation of the iSCSI-Standard emerge. */ protected abstract void deserializeBytes24to27(final int line) throws InternetSCSIException; /** * Parse the bytes <code>28</code> till <code>31</code> in the Basic Header * Segment. * * @param line * The actual line * @throws InternetSCSIException * If any violation of the iSCSI-Standard emerge. */ protected abstract void deserializeBytes28to31(final int line) throws InternetSCSIException; /** * Parse the bytes <code>32</code> till <code>35</code> in the Basic Header * Segment. * * @param line * The actual line * @throws InternetSCSIException * If any violation of the iSCSI-Standard emerge. */ protected abstract void deserializeBytes32to35(final int line) throws InternetSCSIException; /** * Parse the bytes <code>36</code> till <code>39</code> in the Basic Header * Segment. * * @param line * The actual line * @throws InternetSCSIException * If any violation of the iSCSI-Standard emerge. */ protected abstract void deserializeBytes36to39(final int line) throws InternetSCSIException; /** * Parse the bytes <code>40</code> till <code>43</code> in the Basic Header * Segment. * * @param line * The actual line * @throws InternetSCSIException * If any violation of the iSCSI-Standard emerge. */ protected abstract void deserializeBytes40to43(final int line) throws InternetSCSIException; /** * Parse the bytes <code>44</code> till <code>47</code> in the Basic Header * Segment. * * @param line * The actual line * @throws InternetSCSIException * If any violation of the iSCSI-Standard emerge. */ protected abstract void deserializeBytes44to47(final int line) throws InternetSCSIException; // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** * Serializes the bytes <code>1</code> till <code>3</code> in the Basic * Header Segment. * * @return The serialized byte representation. */ protected abstract int serializeBytes1to3(); /** * Serializes the bytes <code>8</code> till <code>11</code> in the Basic * Header Segment. * * @return The serialized byte representation. * @throws InternetSCSIException * if any violation of the iSCSI Standard (RFC3720) occurs. */ protected int serializeBytes8to11() throws InternetSCSIException { return (int)(logicalUnitNumber >>> Constants.FOUR_BYTES_SHIFT); } /** * Serializes the bytes <code>12</code> till <code>15</code> in the Basic * Header Segment. * * @return The serialized byte representation. */ protected int serializeBytes12to15() { return (int)(logicalUnitNumber & Constants.LAST_FOUR_BYTES_MASK); } /** * Serializes the bytes <code>20</code> till <code>23</code> in the Basic * Header Segment. * * @return The serialized byte representation. */ protected abstract int serializeBytes20to23(); /** * Serializes the bytes <code>24</code> till <code>27</code> in the Basic * Header Segment. * * @return The serialized byte representation. */ protected abstract int serializeBytes24to27(); /** * Serializes the bytes <code>28</code> till <code>31</code> in the Basic * Header Segment. * * @return The serialized byte representation. */ protected abstract int serializeBytes28to31(); /** * Serializes the bytes <code>32</code> till <code>35</code> in the Basic * Header Segment. * * @return The serialized byte representation. */ protected abstract int serializeBytes32to35(); /** * Serializes the bytes <code>36</code> till <code>39</code> in the Basic * Header Segment. * * @return The serialized byte representation. */ protected abstract int serializeBytes36to39(); /** * Serializes the bytes <code>40</code> till <code>43</code> in the Basic * Header Segment. * * @return The serialized byte representation. */ protected abstract int serializeBytes40to43(); /** * Serializes the bytes <code>44</code> till <code>47</code> in the Basic * Header Segment. * * @return The serialized byte representation. */ protected abstract int serializeBytes44to47(); // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** * This method checks, if all parsed fields are valid. Because there are * several fields, which are reserved for future versions, and these must be * zero. Is this the case an exception will be thrown. * * @throws InternetSCSIException * If the integrity is violated. */ protected abstract void checkIntegrity() throws InternetSCSIException; // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- }