package org.jscsi.target.connection;
import org.jscsi.parser.ProtocolDataUnit;
import org.jscsi.parser.login.ISID;
import org.jscsi.target.Target;
import org.jscsi.target.TargetServer;
import org.jscsi.target.connection.Connection.TargetConnection;
import org.jscsi.target.scsi.inquiry.DeviceIdentificationVpdPage;
import org.jscsi.target.settings.SessionSettingsNegotiator;
import org.jscsi.target.storage.IStorageModule;
import org.jscsi.target.util.SerialArithmeticNumber;
/**
* A class for objects representing an iSCSI session with all necessary
* variables.
* <p>
* Currently, a {@link TargetSession} can only have <b>one</b> {@link Connection}, i.e.
* <code>MaxConnections=1</code>.
*
* @author Andreas Ergenzinger, University of Konstanz
*/
public class TargetSession {
// OODRIVE
// private static final Logger LOGGER = LoggerFactory.getLogger(TargetSession.class); //OODRIVE
/**
* Returns the value of the next {@link TargetSession} object's {@link #targetSessionIdentifyingHandle}
* variable.
*
* @return the value of the next {@link TargetSession} object's {@link #targetSessionIdentifyingHandle}
* variable
*/
private static short getNextTargetSessionIdentifyingHandle() {
short handle = nextTargetSessionIdentifyingHandle++;// no concurrency
// necessary
if (handle == 0) {// is reserved
handle = nextTargetSessionIdentifyingHandle++;
}
return handle;
}
/**
* The {@link TargetServer} that this session is associated with
*/
private TargetServer targetServer;
/**
* The {@link Target} that this session is associated with
*/
private Target target;
/**
* The {@link TargetConnection} used for exchanging messages and data with
* the session's initiator endpoint.
*/
// private final Connection connection; // OODRIVE
/**
* The {@link ISID} used by the initiator for identifying this session.
*/
private ISID initiatorSessionID;
/**
* The TSIH used by the initiator for identifying this session.
*/
private short initiatorSessionHandle ;
/**
* Keeps track of the value to expect in the <code>ExpCmdSN</code> field of
* the next received {@link ProtocolDataUnit}
*/
private SerialArithmeticNumber expectedCommandSequenceNumber;
/**
* Determines the number of iSCSI Command {@link ProtocolDataUnit}s the
* initiator may send without having the wait for confirmation from the
* target that the command has finished.
* <p>
* A value of <code>1</code> means that the initiator must wait for each command to finish before issuing
* the next one.
*
* @see #getExpectedCommandSequenceNumber()
* @see #getMaximumCommandSequenceNumber()
*/
private final int commandWindowSize = 1;
/**
* The {@link SessionSettingsNegotiator} responsible managing connection
* parameters with session scope.
*/
private SessionSettingsNegotiator sessionSettingsNegotiator;
/**
* A value used by the target to identify this session.
*/
private short targetSessionIdentifyingHandle;
/**
* A counter for {@link #targetSessionIdentifyingHandle}s.
*
* @see #getNextTargetSessionIdentifyingHandle()
*/
private static short nextTargetSessionIdentifyingHandle = 1;
/**
* This value determines if this {@link TargetSession} is a discovery
* session or a regular (operational) session.
*/
private SessionType sessionType;
/**
* Constructs a new {@link TargetSession}
*
* @param connection
* the session's (first) {@link Connection}
* @param initiatorSessionID
* the {@link ISID} specified by the initiator
* @param expectedCommandSequenceNumber
* initialization value of {@link #expectedCommandSequenceNumber}
* @param statusSequenceNumber
* the value expected by the initiator in the next {@link ProtocolDataUnit}'s
* <code>StatSN</code> field
*/
public TargetSession(final TargetServer target, final Connection connection,
final ISID initiatorSessionID, final int expectedCommandSequenceNumber, final int statusSequenceNumber, int cid, short tsih) {
this.targetServer = target;
// set connection variables and parameters
connection.setSession(this);
//this.connection = connection;
connection.setStatusSequenceNumber(statusSequenceNumber);
connection.setConnectionID(cid);
setInitiatorSessionHandle(tsih) ;
// initialize ConnectionSettingsNegotiator (makes sure that settings are
// initialized)
sessionSettingsNegotiator = new SessionSettingsNegotiator();
connection.initializeConnectionSettingsNegotiator(sessionSettingsNegotiator);
// set session variables
this.initiatorSessionID = initiatorSessionID;
targetSessionIdentifyingHandle = getNextTargetSessionIdentifyingHandle();
this.expectedCommandSequenceNumber = new SerialArithmeticNumber(expectedCommandSequenceNumber);
}
/**
* Returns the session's {@link TargetServer}.
*
* @return the session's {@link TargetServer}
*/
public TargetServer getTargetServer() {
return targetServer;
}
/**
* Returns the session's {@link Connection}.
*
* @return the session's {@link Connection}
*/
// OODRIVE public Connection getConnection() {
// OODRIVE return connection;
// OODRIVE }
/**
* Returns the session's {@link Target}
*
* @return the session's {@link Target}
*/
// OODRIVE public Target getTarget() {
// OODRIVE return target;
// OODRIVE }
/**
* Returns the session's {@link IStorageModule}.
*
* @return the session's {@link IStorageModule}
*/
public IStorageModule getStorageModule() {
return target.getStorageModule();
}
/**
* Returns the {@link SerialArithmeticNumber} representing the next expected
* command sequence number.
* <p>
* This value will be used both during sending (<code>ExpCmdSN</code> field) and receiving (
* <code>CmdSN</code>) of {@link ProtocolDataUnit}s.
*
* @return the {@link SerialArithmeticNumber} representing the next expected
* command sequence number
* @see #expectedCommandSequenceNumber
*/
SerialArithmeticNumber getExpectedCommandSequenceNumber() {
return expectedCommandSequenceNumber;
}
/**
* Returns the {@link ISID} used by the initiator to identify this session.
*
* @return the {@link ISID} used by the initiator to identify this session
*/
public ISID getInitiatorSessionID() {
return initiatorSessionID;
}
/**
* Returns a {@link SerialArithmeticNumber} representing the maximum command
* sequence number the target will accept.
* <p>
* This value will be used both during sending (<code>MaxCmdSN</code> field) and receiving (checking if
* PDU's <code>CmdSN</code> lies in the command sequence number window resulting from
* {@link #expectedCommandSequenceNumber} and {@link #commandWindowSize}) of {@link ProtocolDataUnit}s.
*
* @return the {@link SerialArithmeticNumber} representing the next expected
* command sequence number
*/
SerialArithmeticNumber getMaximumCommandSequenceNumber() {
return new SerialArithmeticNumber(expectedCommandSequenceNumber.getValue() + commandWindowSize - 1);
}
/**
* Returns the value used by the jSCSI Target to identify this session.
*
* @return the value used by the jSCSI Target to identify this session
*/
public short getTargetSessionIdentifyingHandle() {
return targetSessionIdentifyingHandle;
}
/**
* Returns <code>true</code> if this session is a regular (operational)
* session, and <code>false</code> if it is s discovery session.
*
* @return <code>true</code> if and only if this is not a regular
* (operational) session
*/
public boolean isNormalSession() {
return sessionType == SessionType.NORMAL;
}
/**
* Removes a {@link TargetConnection} from the session's list of open
* connections. If this reduces the number of connections to zero, the
* session will be removed from the {@link TargetServer}'s list of active
* sessions.
*
* @param connection
* the connection to be removed
*/
void removeTargetConnection(Connection connection) {
// do this only if connection count == 0, currently it always is
targetServer.removeTargetConnection((TargetConnection) connection);
}
/**
* Sets the session's type (discovery or operational).
* <p>
* The type may and must be set just once. Repeated calls of this method will fail. <code>true</code> will
* be returned if the session type was set successfully, <code>false</code> if not.
*
* @param sessionType
* the session type
* @return <code>true</code> if the session type was set successfully, <code>false</code> if not
*/
public final boolean setSessionType(SessionType sessionType) {// OODRIVE change to public
// allow just once, accept only non-null parameter
if (sessionType == null || this.sessionType != null)
return false;
this.sessionType = sessionType;
return true;
}
/**
* Sets the target name and retrieves the target (if it exists) from the TargetServer
*
* @param targetName
*/
public void setTargetName(String targetName) {
if (targetName == null)
target = null;
else
target = targetServer.getTarget(targetName);
deviceIdentificationVpdPage = null;
}
public String getTargetName() {
if (target != null)
return target.getTargetName();
return null;
}
private volatile DeviceIdentificationVpdPage deviceIdentificationVpdPage;
public DeviceIdentificationVpdPage getDeviceIdentificationVpdPage() {
// Lazy init of deviceIdentificationVpdPage
DeviceIdentificationVpdPage deviceIdentificationVpdPageTmp = deviceIdentificationVpdPage;
if (deviceIdentificationVpdPageTmp == null && target != null) {
deviceIdentificationVpdPageTmp = new DeviceIdentificationVpdPage(target);
deviceIdentificationVpdPage = deviceIdentificationVpdPageTmp;
}
return deviceIdentificationVpdPageTmp;
}
public short getInitiatorSessionHandle() {
return initiatorSessionHandle;
}
public void setInitiatorSessionHandle(short sessionHandle) {
this.initiatorSessionHandle = sessionHandle;
}
}