Coverage Report - org.jscsi.target.connection.Connection
 
Classes in this File Line Coverage Branch Coverage Complexity
Connection
N/A
N/A
0
Connection$TargetConnection
0%
0/48
0%
0/8
0
 
 1  
 package org.jscsi.target.connection;
 2  
 
 3  
 
 4  
 import java.io.IOException;
 5  
 import java.nio.channels.SocketChannel;
 6  
 import java.security.DigestException;
 7  
 import java.util.concurrent.Callable;
 8  
 
 9  
 import javax.naming.OperationNotSupportedException;
 10  
 
 11  
 import org.jscsi.exception.InternetSCSIException;
 12  
 import org.jscsi.parser.OperationCode;
 13  
 import org.jscsi.parser.ProtocolDataUnit;
 14  
 import org.jscsi.target.connection.phase.TargetFullFeaturePhase;
 15  
 import org.jscsi.target.connection.phase.TargetLoginPhase;
 16  
 import org.jscsi.target.connection.phase.TargetPhase;
 17  
 import org.jscsi.target.connection.stage.fullfeature.PingStage;
 18  
 import org.jscsi.target.connection.stage.fullfeature.ReadStage;
 19  
 import org.jscsi.target.settings.ConnectionSettingsNegotiator;
 20  
 import org.jscsi.target.settings.SessionSettingsNegotiator;
 21  
 import org.jscsi.target.settings.Settings;
 22  
 import org.jscsi.target.settings.SettingsException;
 23  
 import org.jscsi.target.util.FastByteArrayProvider;
 24  
 import org.jscsi.target.util.SerialArithmeticNumber;
 25  
 import org.slf4j.Logger;
 26  
 import org.slf4j.LoggerFactory;
 27  
 
 28  
 
 29  
 /**
 30  
  * A class for objects representing an iSCSI connection with all necessary variables.
 31  
  * <p>
 32  
  * Each {@link TargetConnection} runs in a separate {@link Thread}. The conceptually most important parts of its
 33  
  * behavior can be likened to a finite state machine (FSM), in which the most basic states (stages) are grouped into
 34  
  * more general states (phases). Commands send by the initiator are carried out in these stages, usually without
 35  
  * transitioning to a different phase. A connection's current phase determines which stages are reachable, limiting the
 36  
  * kind of commands the initiator may issue at any given moment.
 37  
  * 
 38  
  * @author Andreas Ergenzinger
 39  
  */
 40  
 public interface Connection extends Callable<Void> {
 41  
 
 42  
     Settings getSettings ();
 43  
 
 44  
     SerialArithmeticNumber getStatusSequenceNumber ();
 45  
 
 46  
     boolean isLeadingConnection ();
 47  
 
 48  
     ProtocolDataUnit receivePdu () throws DigestException , InternetSCSIException , IOException , SettingsException;
 49  
 
 50  
     void sendPdu (ProtocolDataUnit pDataUnit) throws InterruptedException , IOException , InternetSCSIException;
 51  
 
 52  
     ConnectionSettingsNegotiator getConnectionSettingsNegotiator ();
 53  
 
 54  
     void setSession (TargetSession pSession);
 55  
 
 56  
     TargetSession getTargetSession ();
 57  
 
 58  
     void setStatusSequenceNumber (int pStatusSequenceNumber);
 59  
 
 60  
     void initializeConnectionSettingsNegotiator (SessionSettingsNegotiator pSettingsNegotiator);
 61  
 
 62  
     byte[] getDataInArray (int pLength);
 63  
     
 64  
     public boolean stop();
 65  
 
 66  0
     public static class TargetConnection implements Connection {
 67  
 
 68  0
         private static final Logger LOGGER = LoggerFactory.getLogger(TargetConnection.class);
 69  
 
 70  
         /**
 71  
          * The {@link TargetSession} this connection belongs to.
 72  
          */
 73  
         private TargetSession targetSession;
 74  
 
 75  
         /**
 76  
          * The {@link TargetSenderWorker} used by this connection for sending and receiving {@link ProtocolDataUnit}s.
 77  
          */
 78  
         TargetSenderWorker senderWorker;
 79  
 
 80  
         /**
 81  
          * The {@link ConnectionSettingsNegotiator} of this connection responsible for negotiating and storing
 82  
          * connection parameters which have been negotiated with or declared by the initiator.
 83  
          */
 84  
         private ConnectionSettingsNegotiator connectionSettingsNegotiator;
 85  
 
 86  
         /**
 87  
          * The current {@link TargetPhase} describing a general state of the connection.
 88  
          */
 89  
         private TargetPhase phase;
 90  
 
 91  
         /**
 92  
          * A counter for the <code>StatSN</code> field of sent {@link ProtocolDataUnit} objects with Status.
 93  
          */
 94  
         private SerialArithmeticNumber statusSequenceNumber;
 95  
 
 96  
         /**
 97  
          * Will manage and serve as a source of byte arrays to be used for sending Data In PDUs in the {@link ReadStage}
 98  
          * .
 99  
          */
 100  0
         private FastByteArrayProvider dataInArrayProvider = new FastByteArrayProvider(4);
 101  
 
 102  
         /**
 103  
          * <code>true</code> if and only if this connection is the first connection to be associated with its parent
 104  
          * session.
 105  
          * <p>
 106  
          * This distinction is necessary because some parameters may only be declared over the leading connection.
 107  
          */
 108  
         private final boolean isLeadingConnection;
 109  
 
 110  
         /**
 111  
          * The last {@link ProtocolDataUnit} received on this connection.
 112  
          */
 113  
         private ProtocolDataUnit lastReceivedPDU;
 114  
 
 115  
         /**
 116  
          * The {@link TargetConnection} constructor.
 117  
          * 
 118  
          * @param socketChannel used for sending and receiving PDUs
 119  
          * @param isLeadingConnection <code>true</code> if and only if this connection is the first connection
 120  
          *            associated with its enclosing session
 121  
          */
 122  0
         public TargetConnection (SocketChannel socketChannel, final boolean isLeadingConnection) {
 123  0
             this.isLeadingConnection = isLeadingConnection;
 124  0
             senderWorker = new TargetSenderWorker(this, socketChannel);
 125  0
         }
 126  
 
 127  
         /**
 128  
          * Returns a byte array that can be used for holding data segment data of Data In PDUs sent during the
 129  
          * {@link ReadStage}.
 130  
          * 
 131  
          * @param length the length of the array
 132  
          * @return a byte array of the specified length
 133  
          */
 134  
         public byte[] getDataInArray (final int length) {
 135  0
             return dataInArrayProvider.getArray(length);
 136  
         }
 137  
 
 138  
         /**
 139  
          * Returns the {@link TargetSession} this connection belongs to.
 140  
          * 
 141  
          * @return the {@link TargetSession} this connection belongs to
 142  
          */
 143  
         TargetSession getSession () {
 144  0
             return targetSession;
 145  
         }
 146  
 
 147  
         /**
 148  
          * Sets the {@link TargetSession} this connection belongs to.
 149  
          * 
 150  
          * @param session the {@link TargetSession} this connection belongs to
 151  
          */
 152  
         public void setSession (TargetSession session) {
 153  0
             this.targetSession = session;
 154  0
             senderWorker.setSession(session);
 155  0
         }
 156  
 
 157  
         /**
 158  
          * Returns the next {@link ProtocolDataUnit} to be received on the connection.
 159  
          * <p>
 160  
          * The method will block until a PDU has been completely received.
 161  
          * 
 162  
          * @return the next received PDU
 163  
          * @throws DigestException if a digest error has occured
 164  
          * @throws InternetSCSIException if a general iSCSI protocol error has been detected
 165  
          * @throws IOException if the connection was closed
 166  
          * @throws SettingsException will not happen
 167  
          */
 168  
         public ProtocolDataUnit receivePdu () throws DigestException , InternetSCSIException , IOException , SettingsException {
 169  0
             lastReceivedPDU = senderWorker.receiveFromWire();
 170  
 
 171  0
             if (lastReceivedPDU.getBasicHeaderSegment().getOpCode().equals(OperationCode.NOP_OUT)) {
 172  
                 try {
 173  
                     // System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Handling ping immediately..");
 174  
                     // System.out.println("******************************\nRecieving\nSystem Time: " + new
 175  
                     // java.sql.Timestamp(System.currentTimeMillis()).toString() + "\n" + lastReceivedPDU +
 176  
                     // "\n******************************");
 177  0
                     new PingStage(new TargetFullFeaturePhase(this)).execute(lastReceivedPDU);
 178  0
                 } catch (InterruptedException e) {}
 179  0
                 lastReceivedPDU = senderWorker.receiveFromWire();
 180  
             }
 181  
 
 182  
             // System.out.println("******************************\nRecieving\nSystem Time: " + new
 183  
             // java.sql.Timestamp(System.currentTimeMillis()).toString() + "\n" + lastReceivedPDU +
 184  
             // "\n******************************");
 185  0
             return lastReceivedPDU;
 186  
         }
 187  
 
 188  
         /**
 189  
          * Serializes and sends a {@link ProtocolDataUnit} over the connection.
 190  
          * 
 191  
          * @param pdu the PDU to send
 192  
          * @throws InterruptedException
 193  
          * @throws IOException
 194  
          * @throws InternetSCSIException
 195  
          */
 196  
         public void sendPdu (ProtocolDataUnit pdu) throws InterruptedException , IOException , InternetSCSIException {
 197  
             // System.out.println("******************************\nSending\nSystem Time: " + new
 198  
             // java.sql.Timestamp(System.currentTimeMillis()).toString() + "\n" + pdu +
 199  
             // "\n******************************");
 200  0
             senderWorker.sendOverWire(pdu);
 201  0
         }
 202  
 
 203  
         /**
 204  
          * Starts the processing of PDUs by this connection.
 205  
          * <p>
 206  
          * For this method to work properly, the leading PDU send by the initiator over this connection must have been
 207  
          * received via {@link #receivePdu()}.
 208  
          * 
 209  
          */
 210  
         public Void call () {
 211  
 
 212  
             try {
 213  
                 // *** login phase ***
 214  0
                 phase = new TargetLoginPhase(this);
 215  0
                 if (phase.execute(lastReceivedPDU)) {
 216  0
                     LOGGER.debug("Login Phase successful");
 217  
 
 218  
                     // if this is the leading connection, set the session type
 219  0
                     final Settings settings = getSettings();
 220  0
                     if (isLeadingConnection) targetSession.setSessionType(SessionType.getSessionType(settings.getSessionType()));
 221  0
                     targetSession.setTargetName(settings.getTargetName());
 222  
                     // *** full feature phase ***
 223  0
                     phase = new TargetFullFeaturePhase(this);
 224  
 
 225  0
                     phase.execute();
 226  
                 }
 227  0
                 senderWorker.close();
 228  0
             } catch (OperationNotSupportedException | IOException | InterruptedException | InternetSCSIException | DigestException
 229  
                     | SettingsException e) {
 230  0
                 LOGGER.error("Exception throws", e);
 231  0
             }
 232  
 
 233  0
             targetSession.removeTargetConnection(this);
 234  
 
 235  0
             LOGGER.debug("closed connection");
 236  
 
 237  0
             return null;
 238  
         }
 239  
 
 240  
         public TargetSession getTargetSession () {
 241  0
             return targetSession;
 242  
         }
 243  
 
 244  
         /**
 245  
          * Returns <code>true</code> if this is the leading connection, i.e. the first TargetConnection in the
 246  
          * connection's {@link TargetSession}. Otherwise <code>false</code> is returned.
 247  
          * 
 248  
          * @return <code>true</code> if this is the leading connection
 249  
          */
 250  
         public boolean isLeadingConnection () {
 251  0
             return isLeadingConnection;
 252  
         }
 253  
 
 254  
         /**
 255  
          * Initializes {@link #connectionSettingsNegotiator}.
 256  
          * <p>
 257  
          * This method must be be called after the this connection has been added to its session.
 258  
          */
 259  
         public void initializeConnectionSettingsNegotiator (final SessionSettingsNegotiator sessionSettingsNegotiator) {
 260  0
             connectionSettingsNegotiator = new ConnectionSettingsNegotiator(sessionSettingsNegotiator);
 261  0
         }
 262  
 
 263  
         /**
 264  
          * Returns a {@link Settings} object with a snapshot of the current connection and session parameters.
 265  
          * 
 266  
          * @return the current {@link Settings}
 267  
          */
 268  
         public Settings getSettings () {
 269  0
             return connectionSettingsNegotiator.getSettings();
 270  
         }
 271  
 
 272  
         public ConnectionSettingsNegotiator getConnectionSettingsNegotiator () {
 273  0
             return connectionSettingsNegotiator;
 274  
         }
 275  
 
 276  
         public SerialArithmeticNumber getStatusSequenceNumber () {
 277  0
             return statusSequenceNumber;
 278  
         }
 279  
 
 280  
         public void setStatusSequenceNumber (final int statusSequenceNumber) {
 281  0
             this.statusSequenceNumber = new SerialArithmeticNumber(statusSequenceNumber);
 282  0
         }
 283  
         
 284  
         public boolean stop(){
 285  0
             if(phase instanceof TargetFullFeaturePhase){
 286  0
                 ((TargetFullFeaturePhase)phase).stop();
 287  0
                 return true;
 288  
             }
 289  
             
 290  0
             return false;
 291  
         }
 292  
     }
 293  
 }