View Javadoc

1   /**
2    * Copyright (c) 2012, University of Konstanz, Distributed Systems Group All rights reserved.
3    * 
4    * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
5    * following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of
6    * conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice,
7    * this list of conditions and the following disclaimer in the documentation and/or other materials provided with the
8    * distribution. * Neither the name of the University of Konstanz nor the names of its contributors may be used to
9    * endorse or promote products derived from this software without specific prior written permission.
10   * 
11   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
12   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
13   * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
14   * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
15   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
16   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
17   * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18   */
19  package org.jscsi.initiator.connection.state;
20  
21  
22  import java.util.LinkedList;
23  import java.util.Queue;
24  
25  import org.jscsi.exception.InternetSCSIException;
26  import org.jscsi.initiator.connection.Connection;
27  import org.jscsi.parser.OperationCode;
28  import org.jscsi.parser.ProtocolDataUnit;
29  import org.jscsi.parser.data.DataOutParser;
30  import org.jscsi.parser.datasegment.IDataSegmentIterator;
31  import org.jscsi.parser.datasegment.IDataSegmentIterator.IDataSegmentChunk;
32  import org.jscsi.parser.datasegment.OperationalTextKey;
33  
34  
35  /**
36   * <h1>WriteSecondBurstState</h1>
37   * <p/>
38   * This state handles the second and all following Write Sending States, which sends at most <code>MaxBurstLength</code>
39   * bytes in each sequence.
40   * 
41   * @author Volker Wildi
42   */
43  public final class WriteSecondBurstState extends AbstractState {
44  
45      // --------------------------------------------------------------------------
46      // --------------------------------------------------------------------------
47  
48      /** The chunk of the data segment to send as next. */
49      private final IDataSegmentIterator iterator;
50  
51      /**
52       * The Target Transfer Tag, which is sent by the iSCSI Target within a Ready2Transfer PDU.
53       */
54      private final int targetTransferTag;
55  
56      /**
57       * The desired data transfer length, which the iSCSI Target specified in the last Ready2Transfer message.
58       */
59      private final int desiredDataTransferLength;
60  
61      /** The sequence number of this data package unit. */
62      private int dataSequenceNumber;
63  
64      /** The start offset of the data to send. */
65      private int bufferOffset;
66  
67      // --------------------------------------------------------------------------
68      // --------------------------------------------------------------------------
69  
70      /**
71       * Constructor to create a <code>WriteSecondBurstState</code> instance, which sends the second and all following
72       * data sequences.
73       * 
74       * @param initConnection This is the connection, which is used for the network transmission.
75       * @param initIterator The next chunk of the data to send.
76       * @param initTargetTransferTag The Target Transfer Tag to use.
77       * @param initDesiredDataTransferLength The desired data transfer length, which the iSCSI Target specified in the
78       *            last Ready2Transfer message.
79       * @param initDataSequenceNumber The Data Sequence Number to use as next.
80       * @param initBufferOffset The start offset of the data to send.
81       */
82      public WriteSecondBurstState (final Connection initConnection, final IDataSegmentIterator initIterator, final int initTargetTransferTag, final int initDesiredDataTransferLength, final int initDataSequenceNumber, final int initBufferOffset) {
83  
84          super(initConnection);
85          iterator = initIterator;
86          targetTransferTag = initTargetTransferTag;
87          if (LOGGER.isDebugEnabled()) {
88              LOGGER.debug("TTT set to " + targetTransferTag);
89          }
90          desiredDataTransferLength = initDesiredDataTransferLength;
91          // dataSequenceNumber = initDataSequenceNumber;//FIXME always starts at
92          // 0
93          dataSequenceNumber = 0;
94          bufferOffset = initBufferOffset;
95      }
96  
97      // --------------------------------------------------------------------------
98      // --------------------------------------------------------------------------
99  
100     /** {@inheritDoc} */
101     public final void execute () throws InternetSCSIException {
102 
103         final Queue<ProtocolDataUnit> protocolDataUnits = new LinkedList<ProtocolDataUnit>();
104 
105         ProtocolDataUnit protocolDataUnit;
106         DataOutParser dataOut;
107         IDataSegmentChunk dataSegmentChunk;
108         boolean finalFlag = false;
109         final int maxRecvDataSegmentLength = connection.getSettingAsInt(OperationalTextKey.MAX_RECV_DATA_SEGMENT_LENGTH);
110         int bytes2Transfer = Math.min(connection.getSettingAsInt(OperationalTextKey.MAX_BURST_LENGTH), desiredDataTransferLength);
111 
112         if (LOGGER.isTraceEnabled()) {
113             LOGGER.trace("bytes2Transfer: " + bytes2Transfer + " iterator.hasNext(): " + iterator.hasNext());
114         }
115 
116         while (bytes2Transfer > 0 && iterator.hasNext()) {
117             if (bytes2Transfer <= maxRecvDataSegmentLength) {
118                 dataSegmentChunk = iterator.next(bytes2Transfer);
119                 finalFlag = true;
120             } else {
121                 dataSegmentChunk = iterator.next(maxRecvDataSegmentLength);
122                 finalFlag = false;
123             }
124 
125             protocolDataUnit = protocolDataUnitFactory.create(false, finalFlag, OperationCode.SCSI_DATA_OUT, connection.getSetting(OperationalTextKey.HEADER_DIGEST), connection.getSetting(OperationalTextKey.DATA_DIGEST));
126             protocolDataUnit.getBasicHeaderSegment().setInitiatorTaskTag(connection.getSession().getInitiatorTaskTag());
127 
128             dataOut = (DataOutParser) protocolDataUnit.getBasicHeaderSegment().getParser();
129 
130             dataOut.setTargetTransferTag(targetTransferTag);
131             dataOut.setDataSequenceNumber(dataSequenceNumber++);
132             dataOut.setBufferOffset(bufferOffset);
133             bufferOffset += maxRecvDataSegmentLength;
134 
135             protocolDataUnit.setDataSegment(dataSegmentChunk);
136 
137             protocolDataUnits.offer(protocolDataUnit);
138             bytes2Transfer -= maxRecvDataSegmentLength;
139         }
140 
141         connection.send(protocolDataUnits);
142         connection.nextState(new WriteSecondResponseState(connection, iterator, dataSequenceNumber, bufferOffset));
143 
144         // return true;
145     }
146 
147     /**
148      * {@inheritDoc}
149      */
150     public boolean nextStateFollowing () {
151         return true;
152     }
153 
154     // --------------------------------------------------------------------------
155     // --------------------------------------------------------------------------
156     // --------------------------------------------------------------------------
157     // --------------------------------------------------------------------------
158 
159 }