package org.jscsi.target.connection.stage.fullfeature;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.security.DigestException;
import org.jscsi.exception.InternetSCSIException;
import org.jscsi.parser.BasicHeaderSegment;
import org.jscsi.parser.ProtocolDataUnit;
import org.jscsi.parser.nop.NOPOutParser;
import org.jscsi.target.connection.TargetPduFactory;
import org.jscsi.target.connection.phase.TargetFullFeaturePhase;
import org.jscsi.target.settings.SettingsException;
import org.jscsi.utils.ByteBufferCache;
/**
* A stage for processing NOP-Out PDUs, which are used by the initiator for
* pinging the target, making sure that the connection is still up.
* <p>
* The {@link #execute(ProtocolDataUnit)} method will process these ping messages and send a NOP-In PDU as
* ping echo, containing a copy of the NOP-Out PDU's data segment.
* <p>
* If either the NOP-OUT PDU's initiator or target transfer tag equals the reserved value of 0xffffffff, then
* no reply will be sent, since the PDU is only supposed to acknowledge a changed ExpCmdSN, or serve as an
* echo to a NOP-IN ping sent by the target.
*
* @author Andreas Ergenzinger
*/
public class PingStage extends TargetFullFeatureStage {
private static final int RESERVED_TAG_VALUE = 0xffffffff;
public PingStage(TargetFullFeaturePhase targetFullFeaturePhase) {
super(targetFullFeaturePhase);
}
@Override
public void execute(final ProtocolDataUnit pdu) throws IOException, InterruptedException,
InternetSCSIException, DigestException, SettingsException {
final BasicHeaderSegment bhs = pdu.getBasicHeaderSegment();
final NOPOutParser parser = (NOPOutParser)bhs.getParser();
if (parser.getTargetTransferTag() != RESERVED_TAG_VALUE) {
/*
* This is an error. The jSCSI Target does not send NOP-In ping
* messages, which would be the only legal reason for the initiator
* sending a NOP-Out with the TargetTransferTag equal to 0xffffffff.
* And even if the jSCSI Target was sending pings, the echo would be
* processed in a dedicated stage.
*
* Therefore, we treat this as an error. Close the connection.
*/
throw new InternetSCSIException("NOP-Out PDU TargetTransferTag = "
+ parser.getTargetTransferTag() + " in PingStage");
}
// decide whether or not response is necessary
if (bhs.getInitiatorTaskTag() == RESERVED_TAG_VALUE)
return;// send no response
// else
// prepare response data segment (copy up to initiator's
// MaxRecvDataSegmentLength)
final ByteBuffer dataSegment = pdu.getDataSegment();
final int dataSegmentLength =
Math.min(dataSegment.capacity(), settings.getMaxRecvDataSegmentLength());
dataSegment.rewind().limit(dataSegmentLength);
final ByteBuffer responseDataSegment = ByteBufferCache.allocate(dataSegmentLength);
if (dataSegmentLength>0)
responseDataSegment.put(dataSegment);
/*
responseDataSegment.put(pdu.getDataSegment().array(),// source array,
0,// offset within the array of the first byte to be read
dataSegmentLength);// length
*/
// send response
final ProtocolDataUnit responsePdu = TargetPduFactory.createNopInPDU(0,// logicalUnitNumber,
// reserved
bhs.getInitiatorTaskTag(),// initiatorTaskTag
RESERVED_TAG_VALUE,// targetTransferTag
responseDataSegment);
connection.sendPdu(responsePdu);
}
}