View Javadoc

1   package org.jscsi.target.connection.phase;
2   
3   
4   import java.io.IOException;
5   import java.security.DigestException;
6   
7   import javax.naming.OperationNotSupportedException;
8   
9   import org.jscsi.exception.InternetSCSIException;
10  import org.jscsi.parser.BasicHeaderSegment;
11  import org.jscsi.parser.ProtocolDataUnit;
12  import org.jscsi.parser.login.LoginRequestParser;
13  import org.jscsi.parser.login.LoginStage;
14  import org.jscsi.target.connection.Connection;
15  import org.jscsi.target.connection.stage.login.LoginOperationalParameterNegotiationStage;
16  import org.jscsi.target.connection.stage.login.SecurityNegotiationStage;
17  import org.jscsi.target.connection.stage.login.TargetLoginStage;
18  import org.jscsi.target.settings.ConnectionSettingsNegotiator;
19  import org.jscsi.target.settings.SettingsException;
20  
21  
22  /**
23   * Objects of this class represent the Target Login Phase of a connection.
24   * 
25   * @see TargetPhase
26   * @author Andreas Ergenzinger
27   */
28  public final class TargetLoginPhase extends TargetPhase {
29  
30      /**
31       * The current stage of this phase
32       */
33      private TargetLoginStage stage;
34  
35      /**
36       * This variable indicates if the initiator is to be considered as authenticated, i.e. if it has given sufficient
37       * proof of its identity to proceed to the next (Target Full Feature) phase.
38       * <p>
39       * Currently the jSCSI Target does not support any authentication methods and this value is initialized to
40       * <code>true</code> for all initiators.
41       */
42      private boolean authenticated = true;// TODO false if authentication
43                                           // required
44  
45      /**
46       * This variable will be <code>true</code> until the first call of {@link #getFirstPduAndSetToFalse()} has happened.
47       * <p>
48       * This value will be <code>true</code> if the currently processed PDU is the first PDU sent by the initiator over
49       * this phase's connection. This means that it must contain all text parameters necessary for either starting a
50       * discovery session or a normal session.
51       */
52      private boolean firstPdu = true;
53  
54      /**
55       * The constructor.
56       * 
57       * @param connection {@inheritDoc}
58       */
59      public TargetLoginPhase (Connection connection) {
60          super(connection);
61      }
62  
63      /**
64       * Starts the login phase.
65       * 
66       * @param pdu {@inheritDoc}
67       * @return {@inheritDoc}
68       * @throws OperationNotSupportedException {@inheritDoc}
69       * @throws IOException {@inheritDoc}
70       * @throws InterruptedException {@inheritDoc}
71       * @throws InternetSCSIException {@inheritDoc}
72       * @throws DigestException {@inheritDoc}
73       * @throws SettingsException {@inheritDoc}
74       */
75      @Override
76      public boolean execute (ProtocolDataUnit pdu) throws IOException , InterruptedException , InternetSCSIException , DigestException , SettingsException {
77  
78          // begin login negotiation
79          final ConnectionSettingsNegotiator negotiator = connection.getConnectionSettingsNegotiator();
80          while (!negotiator.beginNegotiation()) {
81              // do nothing, just wait for permission to begin, method is blocking
82          }
83  
84          boolean loginSuccessful = true;// will determine if settings are
85                                         // committed
86  
87          try {
88              // if possible, enter LOPN Stage
89              BasicHeaderSegment bhs = pdu.getBasicHeaderSegment();
90              LoginRequestParser parser = (LoginRequestParser) bhs.getParser();
91  
92              LoginStage nextStageNumber;// will store return value from the last
93                                         // login stage
94  
95              // Security Negotiation Stage (optional)
96              if (parser.getCurrentStageNumber() == LoginStage.SECURITY_NEGOTIATION) {
97                  // complete SNS
98                  stage = new SecurityNegotiationStage(this);
99                  stage.execute(pdu);
100                 nextStageNumber = stage.getNextStageNumber();
101 
102                 if (nextStageNumber != null)
103                     authenticated = true;
104                 else {
105                     loginSuccessful = false;
106                     return false;
107                 }
108 
109                 if (nextStageNumber == LoginStage.LOGIN_OPERATIONAL_NEGOTIATION) {
110                     // receive first PDU from LOPNS
111                     pdu = connection.receivePdu();
112                     bhs = pdu.getBasicHeaderSegment();
113                     parser = (LoginRequestParser) bhs.getParser();
114                 } else if (nextStageNumber == LoginStage.FULL_FEATURE_PHASE) {
115                     // we are done here
116                     return true;
117                 } else {
118                     // should be unreachable, since SNS may not return NSG==SNS
119                     loginSuccessful = false;
120                     return false;
121                 }
122             }
123 
124             // Login Operational Parameter Negotiation Stage (also optional, but
125             // either SNS or LOPNS must be passed before proceeding to FFP)
126             if (parser != null && authenticated && parser.getCurrentStageNumber() == LoginStage.LOGIN_OPERATIONAL_NEGOTIATION) {
127                 stage = new LoginOperationalParameterNegotiationStage(this);
128                 stage.execute(pdu);
129                 nextStageNumber = stage.getNextStageNumber();
130                 if (nextStageNumber == LoginStage.FULL_FEATURE_PHASE) return true;
131             }
132             // else
133             loginSuccessful = false;
134             return false;
135         } catch (DigestException e) {
136             loginSuccessful = false;
137             throw e;
138         } catch (IOException e) {
139             loginSuccessful = false;
140             throw e;
141         } catch (InterruptedException e) {
142             loginSuccessful = false;
143             throw e;
144         } catch (InternetSCSIException e) {
145             loginSuccessful = false;
146             throw e;
147         } catch (SettingsException e) {
148             loginSuccessful = false;
149             throw e;
150         } finally {
151             // commit or roll back changes and release exclusive negotiator lock
152             negotiator.finishNegotiation(loginSuccessful);
153         }
154     }
155 
156     /**
157      * This method will return <code>true</code> if currently processed PDU is the first PDU sent by the initiator over
158      * this phase's connection. Subsequent calls will always return <code>false</code>.
159      * 
160      * @return <code>true</code> if and only if this method is called for the first time
161      */
162     public boolean getFirstPduAndSetToFalse () {
163         if (!firstPdu) return false;
164         firstPdu = false;
165         return true;
166     }
167 
168     public final boolean getAuthenticated () {
169         return authenticated;
170     }
171 }