Coverage Report - org.jscsi.target.connection.stage.login.TargetLoginStage
 
Classes in this File Line Coverage Branch Coverage Complexity
TargetLoginStage
0%
0/48
0%
0/24
3.429
 
 1  
 package org.jscsi.target.connection.stage.login;
 2  
 
 3  
 
 4  
 import java.io.IOException;
 5  
 import java.nio.ByteBuffer;
 6  
 import java.security.DigestException;
 7  
 
 8  
 import org.jscsi.exception.InternetSCSIException;
 9  
 import org.jscsi.parser.BasicHeaderSegment;
 10  
 import org.jscsi.parser.OperationCode;
 11  
 import org.jscsi.parser.ProtocolDataUnit;
 12  
 import org.jscsi.parser.login.LoginRequestParser;
 13  
 import org.jscsi.parser.login.LoginStage;
 14  
 import org.jscsi.parser.login.LoginStatus;
 15  
 import org.jscsi.target.connection.TargetPduFactory;
 16  
 import org.jscsi.target.connection.phase.TargetLoginPhase;
 17  
 import org.jscsi.target.connection.stage.TargetStage;
 18  
 import org.jscsi.target.settings.ConnectionSettingsNegotiator;
 19  
 import org.jscsi.target.settings.SettingsException;
 20  
 import org.jscsi.target.util.ReadWrite;
 21  
 
 22  
 
 23  
 /**
 24  
  * This class is an abstract super-class for stages of the {@link TargetLoginPhase} (see <code>Connection</code> for a
 25  
  * description of the relationship between sessions, connections, phases and sessions), namely the
 26  
  * {@link LoginOperationalParameterNegotiationStage} and the {@link SecurityNegotiationStage}.
 27  
  * <p>
 28  
  * The stage is started by calling the {@link #execute(ProtocolDataUnit)} method with the first {@link ProtocolDataUnit}
 29  
  * to be processed as part of the stage.
 30  
  * <p>
 31  
  * Of equal importance is the {@link #getNextStageNumber()} method, which must be used to find out which stage or phase
 32  
  * will follow this one.
 33  
  * 
 34  
  * @author Andreas Ergenzinger
 35  
  */
 36  
 public abstract class TargetLoginStage extends TargetStage {
 37  
 
 38  
     /**
 39  
      * Manages the text parameter negotiation.
 40  
      */
 41  
     protected final ConnectionSettingsNegotiator negotiator;
 42  
 
 43  
     /**
 44  
      * The stage number used for describing this stage in Login Request PDUs.
 45  
      * 
 46  
      * @see LoginRequestParser#getCurrentStageNumber()
 47  
      * @see LoginRequestParser#getNextStageNumber()
 48  
      */
 49  
     protected final LoginStage stageNumber;
 50  
 
 51  
     /**
 52  
      * An identifier used by the initiator to identify the login task. Sent with the first Login Request PDU.
 53  
      */
 54  
     protected int initiatorTaskTag;
 55  
 
 56  
     /**
 57  
      * A stage number describing which stage the initiator wants to transition to. This value will be updated with every
 58  
      * received PDU.
 59  
      * 
 60  
      * @see #stageNumber
 61  
      */
 62  
     protected LoginStage requestedNextStageNumber;
 63  
 
 64  
     /**
 65  
      * A stage number describing which stage must follow this stage.
 66  
      * <p>
 67  
      * This value is initialized with <code>null</code>, and will be changed in {@link #execute(ProtocolDataUnit)}, if
 68  
      * the stage was finished successfully.
 69  
      * 
 70  
      * @see #stageNumber
 71  
      */
 72  
     protected LoginStage nextStageNumber;
 73  
 
 74  
     /**
 75  
      * The abstract constructor.
 76  
      * 
 77  
      * @param targetLoginPhase the phase this stage is a part of
 78  
      * @param stageNumber the stage number used for describing this stage in Login Request PDUs
 79  
      */
 80  
     public TargetLoginStage (final TargetLoginPhase targetLoginPhase, final LoginStage stageNumber) {
 81  0
         super(targetLoginPhase);
 82  0
         this.stageNumber = stageNumber;
 83  0
         negotiator = connection.getConnectionSettingsNegotiator();
 84  0
     }
 85  
 
 86  
     /**
 87  
      * Returns <code>true</code>, if and only if the specified PDU is a Login Request PDU and the CSN and
 88  
      * InitiatorTaskTag fields check out.
 89  
      * 
 90  
      * @param pdu the PDU to check
 91  
      * @return <code>true</code> if the PDU checks out
 92  
      */
 93  
     protected boolean checkPdu (ProtocolDataUnit pdu) {
 94  0
         final BasicHeaderSegment bhs = pdu.getBasicHeaderSegment();
 95  0
         final LoginRequestParser parser = (LoginRequestParser) bhs.getParser();
 96  0
         if (bhs.getOpCode() == OperationCode.LOGIN_REQUEST && parser.getCurrentStageNumber() == stageNumber && bhs.getInitiatorTaskTag() == initiatorTaskTag) return true;
 97  0
         return false;
 98  
     }
 99  
 
 100  
     /**
 101  
      * Receives a sequence of Login Request PDUs (as indicated by the {@link LoginRequestParser#isContinueFlag()} and
 102  
      * returns the concatenated content of the text data segments.
 103  
      * 
 104  
      * @return the concatenated content of the text data segments
 105  
      * @throws DigestException
 106  
      * @throws InternetSCSIException
 107  
      * @throws IOException
 108  
      * @throws SettingsException
 109  
      * @throws InterruptedException
 110  
      */
 111  
     protected final String receivePduSequence () throws DigestException , InternetSCSIException , IOException , SettingsException , InterruptedException {
 112  0
         final ProtocolDataUnit pdu = connection.receivePdu();
 113  0
         return receivePduSequence(pdu);
 114  
     }
 115  
 
 116  
     /**
 117  
      * Receives a sequence of Login Request PDUs (as indicated by the {@link LoginRequestParser#isContinueFlag()} and
 118  
      * returns the concatenated content of the text data segments.
 119  
      * 
 120  
      * @param pdu the first PDU of the sequence
 121  
      * @return the concatenated content of the text data segments
 122  
      * @throws InternetSCSIException
 123  
      * @throws InterruptedException
 124  
      * @throws IOException
 125  
      * @throws DigestException
 126  
      * @throws SettingsException
 127  
      */
 128  
     protected final String receivePduSequence (ProtocolDataUnit pdu) throws InternetSCSIException , InterruptedException , IOException , DigestException , SettingsException {
 129  
 
 130  
         // StringBuilder for the key-value pairs received during this sequence
 131  0
         final StringBuilder stringBuilder = new StringBuilder();
 132  
 
 133  
         // for accessing the fields of the last received PDU
 134  
         BasicHeaderSegment bhs;
 135  
         LoginRequestParser parser;
 136  
 
 137  
         // begin sequence
 138  0
         int sequenceLength = 1;
 139  0
         while (sequenceLength <= session.getTargetServer().getConfig().getInMaxRecvTextPduSequenceLength()) {
 140  0
             bhs = pdu.getBasicHeaderSegment();
 141  0
             parser = (LoginRequestParser) bhs.getParser();
 142  
 
 143  
             // check PDU
 144  0
             if (!checkPdu(pdu)) {
 145  
                 // send login reject and leave stage
 146  0
                 sendRejectPdu(LoginStatus.INVALID_DURING_LOGIN);
 147  0
                 throw new InternetSCSIException("Wrong PDU in TargetLoginStage");
 148  
             }
 149  
 
 150  
             // PDU is okay, so append text data segment to stringBuilder
 151  0
             ReadWrite.appendTextDataSegmentToStringBuffer(pdu.getDataSegment(), stringBuilder);
 152  
 
 153  
             // remember what stage the initiator wants to transition to
 154  0
             requestedNextStageNumber = parser.getNextStageNumber();
 155  
 
 156  
             // continue?
 157  0
             if (parser.isContinueFlag()) {
 158  
                 // send reception confirmation
 159  0
                 pdu = TargetPduFactory.createLoginResponsePdu(false,// transitFlag
 160  
                         false,// continueFlag
 161  
                         stageNumber,// currentStage
 162  
                         stageNumber,// nextStage
 163  
                         session.getInitiatorSessionID(),// initiatorSessionID
 164  
                         session.getTargetSessionIdentifyingHandle(),// targetSessionIdentifyingHandle
 165  
                         initiatorTaskTag, LoginStatus.SUCCESS,// status
 166  
                         ByteBuffer.allocate(0));// dataSegment
 167  0
                 connection.sendPdu(pdu);
 168  
 
 169  
                 // receive the next pdu
 170  0
                 pdu = connection.receivePdu();
 171  
             } else
 172  
                 // sequence is over
 173  0
                 return stringBuilder.toString();
 174  
         }
 175  
 
 176  
         // initiator's text PDU sequence was too long
 177  
         // send login reject and leave stage
 178  0
         sendRejectPdu(LoginStatus.OUT_OF_RESOURCES);
 179  0
         throw new InternetSCSIException("Wrong PDU in TargetLoginStage");
 180  
     }
 181  
 
 182  
     /**
 183  
      * Sends a Login Response PDU sequence containing the specified <i>key-value</i> pairs.
 184  
      * 
 185  
      * @param keyValuePairs contains <i>key-value</i> pairs to send
 186  
      * @param nextStage indicates if the target is willing to transition to a different stage
 187  
      * @throws SettingsException
 188  
      * @throws InterruptedException
 189  
      * @throws IOException
 190  
      * @throws InternetSCSIException
 191  
      * @throws DigestException
 192  
      */
 193  
     protected final void sendPduSequence (final String keyValuePairs, final LoginStage nextStage) throws SettingsException , InterruptedException , IOException , InternetSCSIException , DigestException {
 194  
 
 195  
         // some variables
 196  
         ProtocolDataUnit pdu;
 197  
         BasicHeaderSegment bhs;
 198  
         LoginRequestParser parser;
 199  0
         boolean continueFlag = true;
 200  0
         boolean transitFlag = false;
 201  
 
 202  
         // split input string into text data segments
 203  0
         final ByteBuffer[] dataSegments = ReadWrite.stringToTextDataSegments(keyValuePairs,// string
 204  
                 settings.getMaxRecvDataSegmentLength());// bufferSize
 205  
 
 206  
         // send all data segments (and receive confirmations)
 207  0
         for (int i = 0; i < dataSegments.length; ++i) {
 208  
 
 209  
             // adjust flags
 210  0
             if (i == dataSegments.length - 1) {
 211  0
                 continueFlag = false;
 212  0
                 if (stageNumber != nextStage) transitFlag = true;
 213  
             }
 214  
 
 215  
             // create and send PDU
 216  0
             pdu = TargetPduFactory.createLoginResponsePdu(transitFlag,// transitFlag
 217  
                     continueFlag,// continueFlag
 218  
                     stageNumber,// currentStage
 219  
                     nextStage,// nextStage
 220  
                     session.getInitiatorSessionID(),// initiatorSessionID
 221  
                     session.getTargetSessionIdentifyingHandle(),// targetSessionIdentifyingHandle
 222  
                     initiatorTaskTag, LoginStatus.SUCCESS,// status
 223  
                     dataSegments[i]);// dataSegment
 224  0
             connection.sendPdu(pdu);
 225  
 
 226  
             // receive confirmation
 227  0
             if (continueFlag) {
 228  
                 // receive and check
 229  0
                 pdu = connection.receivePdu();
 230  0
                 bhs = pdu.getBasicHeaderSegment();
 231  0
                 parser = (LoginRequestParser) bhs.getParser();
 232  0
                 if (!checkPdu(pdu) || parser.isContinueFlag()) {
 233  
                     // send login reject and leave stage
 234  0
                     sendRejectPdu(LoginStatus.INITIATOR_ERROR);
 235  0
                     throw new InternetSCSIException();
 236  
                 }
 237  
             }
 238  
         }
 239  0
     }
 240  
 
 241  
     /**
 242  
      * Sends a Login Response PDU informing the initiator that an error has occurred and that the connection must be
 243  
      * closed.
 244  
      * 
 245  
      * @param errorStatus hints to the cause of the error
 246  
      * @throws InterruptedException
 247  
      * @throws IOException
 248  
      * @throws InternetSCSIException
 249  
      */
 250  
     protected final void sendRejectPdu (final LoginStatus errorStatus) throws InterruptedException , IOException , InternetSCSIException {
 251  0
         final ProtocolDataUnit rejectPDU = TargetPduFactory.createLoginResponsePdu(false,// transit flag
 252  
                 false,// continueFlag
 253  
                 stageNumber,// currentStage
 254  
                 stageNumber,// nextStage
 255  
                 session.getInitiatorSessionID(),// initiatorSessionID
 256  
                 session.getTargetSessionIdentifyingHandle(),// targetSessionIdentifyingHandle
 257  
                 initiatorTaskTag,// initiatorTaskTag
 258  
                 errorStatus,// status
 259  
                 ByteBuffer.allocate(0));// dataSegment
 260  0
         connection.sendPdu(rejectPDU);
 261  0
     }
 262  
 
 263  
     /**
 264  
      * Returns a stage number describing which stage of phase must follow this stage, or <code>null</code> if the
 265  
      * initiator is not allowed to transition any further.
 266  
      * 
 267  
      * @return an identifier of the next stage/phase or <code>null</code>
 268  
      */
 269  
     public final LoginStage getNextStageNumber () {
 270  0
         return nextStageNumber;
 271  
     }
 272  
 }