1 package org.jscsi.target.connection; 2 3 4 import org.jscsi.parser.ProtocolDataUnit; 5 import org.jscsi.parser.login.ISID; 6 import org.jscsi.target.Target; 7 import org.jscsi.target.TargetServer; 8 import org.jscsi.target.settings.SessionSettingsNegotiator; 9 import org.jscsi.target.storage.IStorageModule; 10 import org.jscsi.target.util.SerialArithmeticNumber; 11 12 13 /** 14 * A class for objects representing an iSCSI session with all necessary variables. 15 * <p> 16 * Currently, a {@link TargetSession} can only have <b>one</b> {@link Connection}, i.e. <code>MaxConnections=1</code>. 17 * 18 * @author Andreas Ergenzinger, University of Konstanz 19 */ 20 public class TargetSession { 21 22 /** 23 * Returns the value of the next {@link TargetSession} object's {@link #targetSessionIdentifyingHandle} variable. 24 * 25 * @return the value of the next {@link TargetSession} object's {@link #targetSessionIdentifyingHandle} variable 26 */ 27 private static short getNextTargetSessionIdentifyingHandle () { 28 short handle = nextTargetSessionIdentifyingHandle++;// no concurrency 29 // necessary 30 if (handle == 0) {// is reserved 31 handle = nextTargetSessionIdentifyingHandle++; 32 } 33 return handle; 34 } 35 36 /** 37 * The {@link TargetServer} that this session is associated with 38 */ 39 private TargetServer targetServer; 40 41 /** 42 * The {@link Target} that this session is associated with 43 */ 44 private Target target; 45 46 /** 47 * The {@link TargetConnection} used for exchanging messages and data with the session's initiator endpoint. 48 */ 49 private Connection connection; 50 51 /** 52 * The {@link ISID} used by the initiator for identifying this session. 53 */ 54 private ISID initiatorSessionID; 55 56 /** 57 * Keeps track of the value to expect in the <code>ExpCmdSN</code> field of the next received 58 * {@link ProtocolDataUnit} 59 */ 60 private SerialArithmeticNumber expectedCommandSequenceNumber; 61 62 /** 63 * Determines the number of iSCSI Command {@link ProtocolDataUnit}s the initiator may send without having the wait 64 * for confirmation from the target that the command has finished. 65 * <p> 66 * A value of <code>1</code> means that the initiator must wait for each command to finish before issuing the next 67 * one. 68 * 69 * @see #getExpectedCommandSequenceNumber() 70 * @see #getMaximumCommandSequenceNumber() 71 */ 72 private final int commandWindowSize = 1; 73 74 /** 75 * The {@link SessionSettingsNegotiator} responsible managing connection parameters with session scope. 76 */ 77 private SessionSettingsNegotiator sessionSettingsNegotiator; 78 79 /** 80 * A value used by the target to identify this session. 81 */ 82 private short targetSessionIdentifyingHandle; 83 84 /** 85 * A counter for {@link #targetSessionIdentifyingHandle}s. 86 * 87 * @see #getNextTargetSessionIdentifyingHandle() 88 */ 89 private static short nextTargetSessionIdentifyingHandle = 1; 90 91 /** 92 * This value determines if this {@link TargetSession} is a discovery session or a regular (operational) session. 93 */ 94 private SessionType sessionType; 95 96 /** 97 * Constructs a new {@link TargetSession} 98 * 99 * @param connection the session's (first) {@link Connection} 100 * @param initiatorSessionID the {@link ISID} specified by the initiator 101 * @param expectedCommandSequenceNumber initialization value of {@link #expectedCommandSequenceNumber} 102 * @param statusSequenceNumber the value expected by the initiator in the next {@link ProtocolDataUnit}'s 103 * <code>StatSN</code> field 104 */ 105 public TargetSession (final TargetServer target, final Connection connection, final ISID initiatorSessionID, final int expectedCommandSequenceNumber, final int statusSequenceNumber) { 106 this.targetServer = target; 107 // set connection variables and parameters 108 connection.setSession(this); 109 this.connection = connection; 110 connection.setStatusSequenceNumber(statusSequenceNumber); 111 112 // initialize ConnectionSettingsNegotiator (makes sure that settings are 113 // initialized) 114 sessionSettingsNegotiator = new SessionSettingsNegotiator(); 115 connection.initializeConnectionSettingsNegotiator(sessionSettingsNegotiator); 116 117 // set session variables 118 this.initiatorSessionID = initiatorSessionID; 119 targetSessionIdentifyingHandle = getNextTargetSessionIdentifyingHandle(); 120 this.expectedCommandSequenceNumber = new SerialArithmeticNumber(expectedCommandSequenceNumber); 121 } 122 123 /** 124 * Returns the session's {@link TargetServer}. 125 * 126 * @return the session's {@link TargetServer} 127 */ 128 public TargetServer getTargetServer () { 129 return targetServer; 130 } 131 132 /** 133 * Returns the session's {@link Connection}. 134 * 135 * @return the session's {@link Connection} 136 */ 137 public Connection getConnection () { 138 return connection; 139 } 140 141 /** 142 * Returns the session's {@link Target} 143 * 144 * @return the session's {@link Target} 145 */ 146 public Target getTarget () { 147 return target; 148 } 149 150 /** 151 * Returns the session's {@link IStorageModule}. 152 * 153 * @return the session's {@link IStorageModule} 154 */ 155 public IStorageModule getStorageModule () { 156 return target.getStorageModule(); 157 } 158 159 /** 160 * Returns the {@link SerialArithmeticNumber} representing the next expected command sequence number. 161 * <p> 162 * This value will be used both during sending (<code>ExpCmdSN</code> field) and receiving ( <code>CmdSN</code>) of 163 * {@link ProtocolDataUnit}s. 164 * 165 * @return the {@link SerialArithmeticNumber} representing the next expected command sequence number 166 * @see #expectedCommandSequenceNumber 167 */ 168 SerialArithmeticNumber getExpectedCommandSequenceNumber () { 169 return expectedCommandSequenceNumber; 170 } 171 172 /** 173 * Returns the {@link ISID} used by the initiator to identify this session. 174 * 175 * @return the {@link ISID} used by the initiator to identify this session 176 */ 177 public ISID getInitiatorSessionID () { 178 return initiatorSessionID; 179 } 180 181 /** 182 * Returns a {@link SerialArithmeticNumber} representing the maximum command sequence number the target will accept. 183 * <p> 184 * This value will be used both during sending (<code>MaxCmdSN</code> field) and receiving (checking if PDU's 185 * <code>CmdSN</code> lies in the command sequence number window resulting from 186 * {@link #expectedCommandSequenceNumber} and {@link #commandWindowSize}) of {@link ProtocolDataUnit}s. 187 * 188 * @return the {@link SerialArithmeticNumber} representing the next expected command sequence number 189 */ 190 SerialArithmeticNumber getMaximumCommandSequenceNumber () { 191 return new SerialArithmeticNumber(expectedCommandSequenceNumber.getValue() + commandWindowSize - 1); 192 } 193 194 /** 195 * Returns the value used by the jSCSI Target to identify this session. 196 * 197 * @return the value used by the jSCSI Target to identify this session 198 */ 199 public short getTargetSessionIdentifyingHandle () { 200 return targetSessionIdentifyingHandle; 201 } 202 203 /** 204 * Returns <code>true</code> if this session is a regular (operational) session, and <code>false</code> if it is s 205 * discovery session. 206 * 207 * @return <code>true</code> if and only if this is not a regular (operational) session 208 */ 209 public boolean isNormalSession () { 210 return sessionType == SessionType.NORMAL; 211 } 212 213 /** 214 * Removes a {@link TargetConnection} from the session's list of open connections. If this reduces the number of 215 * connections to zero, the session will be removed from the {@link TargetServer}'s list of active sessions. 216 * 217 * @param connection the connection to be removed 218 */ 219 void removeTargetConnection (Connection connection) { 220 // do this only if connection count == 0, currently it always is 221 targetServer.removeTargetSession(this); 222 } 223 224 /** 225 * Sets the session's type (discovery or operational). 226 * <p> 227 * The type may and must be set just once. Repeated calls of this method will fail. <code>true</code> will be 228 * returned if the session type was set successfully, <code>false</code> if not. 229 * 230 * @param sessionType the session type 231 * @return <code>true</code> if the session type was set successfully, <code>false</code> if not 232 */ 233 boolean setSessionType (SessionType sessionType) { 234 // allow just once, accept only non-null parameter 235 if (sessionType == null || this.sessionType != null) return false; 236 this.sessionType = sessionType; 237 return true; 238 } 239 240 /** 241 * Sets the target name and retrieves the target (if it exists) from the TargetServer 242 * 243 * @param targetName 244 */ 245 public void setTargetName (String targetName) { 246 if (targetName == null) target = null; 247 target = targetServer.getTarget(targetName); 248 } 249 250 public String getTargetName () { 251 if (target != null) return target.getTargetName(); 252 return null; 253 } 254 }