/**
* 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.text;
import org.jscsi.exception.InternetSCSIException;
import org.jscsi.parser.Constants;
import org.jscsi.parser.ProtocolDataUnit;
import org.jscsi.parser.TargetMessageParser;
import org.jscsi.parser.datasegment.DataSegmentFactory.DataSegmentFormat;
import org.jscsi.utils.Utils;
/**
* <h1>TextResponseParser</h1>
* <p>
* This class parses a Text Response message defined in the iSCSI Standard (RFC3720).
*
* @author Volker Wildi
*/
public final class TextResponseParser extends TargetMessageParser {
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
/** Continue Flag. */
private boolean continueFlag;
/** Target Transfer Tag. */
private int targetTransferTag;
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
/**
* Default constructor, creates a new, empty <code>TextResponseParser</code> object.
*
* @param initProtocolDataUnit
* The reference <code>ProtocolDataUnit</code> instance, which
* contains this <code>TextResponseParser</code> subclass object.
*/
public TextResponseParser(final ProtocolDataUnit initProtocolDataUnit) {
super(initProtocolDataUnit);
}
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
/** {@inheritDoc} */
@Override
public final String toString() {
final StringBuilder sb = new StringBuilder(Constants.LOG_INITIAL_SIZE);
Utils.printField(sb, "Continue Flag", continueFlag, 1);
Utils.printField(sb, "LUN", logicalUnitNumber, 1);
Utils.printField(sb, "Target Transfer Tag", targetTransferTag, 1);
sb.append(super.toString());
return sb.toString();
}
/** {@inheritDoc} */
@Override
public final DataSegmentFormat getDataSegmentFormat() {
return DataSegmentFormat.TEXT;
}
/** {@inheritDoc} */
@Override
public final void clear() {
super.clear();
continueFlag = false;
targetTransferTag = 0x00000000;
}
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
/**
* When set to <code>1</code>, indicates that the text (set of key=value
* pairs) in this Text Response is not complete (it will be continued on
* subsequent Text Responses); otherwise, it indicates that this Text
* Response ends a set of key=value pairs. A Text Response with the <code>C</code> bit set to
* <code>1</code> MUST have the <code>F</code> bit
* set to <code>0</code>.
*
* @return <code>True</code>, if the Continue Flag is set. Else <code>false</code>.
*/
public final boolean isContinueFlag() {
return continueFlag;
}
/**
* When a target has more work to do (e.g., cannot transfer all the
* remaining text data in a single Text Response or has to continue the
* negotiation) and has enough resources to proceed, it MUST set the Target
* Transfer Tag to a value other than the reserved value of <code>0xffffffff</code>.
* <p>
* Otherwise, the Target Transfer Tag MUST be set to <code>0xffffffff</code> . When the Target Transfer
* Tag is not <code>0xffffffff</code>, the <code>LUN</code> field may be significant. The initiator MUST
* copy the Target Transfer Tag and <code>LUN</code> in its next request to indicate that it wants the
* rest of the data. When the target receives a Text Request with the Target Transfer Tag set to the
* reserved value of <code>0xffffffff</code>, it resets its internal information (resets state) associated
* with the given Initiator Task Tag (restarts the negotiation). When a target cannot finish the operation
* in a single Text Response, and does not have enough resources to continue, it rejects the Text Request
* with the appropriate Reject code.
*
* @return The Target Transfer Tag of this <code>TextResponseParser</code> object.
*/
public final int getTargetTransferTag() {
return targetTransferTag;
}
public final void setContinueFlag(boolean continueFlag) {
this.continueFlag = continueFlag;
}
public final void setTargetTransferTag(int targetTransferTag) {
this.targetTransferTag = targetTransferTag;
}
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
/** {@inheritDoc} */
@Override
protected final void deserializeBytes1to3(final int line) throws InternetSCSIException {
continueFlag = Utils.isBitSet(line & Constants.CONTINUE_FLAG_MASK);
// all bits are reserved, except the continue flag bit
Utils.isReserved(line & (Constants.LAST_THREE_BYTES_MASK ^ Constants.CONTINUE_FLAG_MASK));
}
/** {@inheritDoc} */
@Override
protected final void deserializeBytes20to23(final int line) throws InternetSCSIException {
targetTransferTag = line;
}
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
/** {@inheritDoc} */
@Override
protected final void checkIntegrity() throws InternetSCSIException {
String exceptionMessage;
do {
if (protocolDataUnit.getBasicHeaderSegment().isFinalFlag() && continueFlag) {
exceptionMessage = "Final and Continue Flag cannot be set at the same time.";
break;
}
// message is checked correctly
return;
} while (false);
throw new InternetSCSIException(exceptionMessage);
}
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
/** {@inheritDoc} */
@Override
protected final int serializeBytes1to3() {
int line = 0;
if (continueFlag) {
line = Constants.CONTINUE_FLAG_MASK;
}
return line;
}
/** {@inheritDoc} */
@Override
protected final int serializeBytes20to23() {
return targetTransferTag;
}
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
}