1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.jscsi.initiator.connection.state;
20
21
22 import java.nio.ByteBuffer;
23
24 import org.jscsi.exception.InternetSCSIException;
25 import org.jscsi.exception.OperationalTextKeyException;
26 import org.jscsi.initiator.connection.Connection;
27 import org.jscsi.parser.AbstractMessageParser;
28 import org.jscsi.parser.ProtocolDataUnit;
29 import org.jscsi.parser.data.DataInParser;
30 import org.jscsi.parser.datasegment.OperationalTextKey;
31 import org.jscsi.parser.scsi.SCSIResponseParser;
32 import org.jscsi.parser.scsi.SCSIStatus;
33
34
35
36
37
38
39
40
41
42 public final class ReadResponseState extends AbstractState {
43
44
45
46
47
48
49
50
51 private static final int WRAP_AROUND_DIVISOR = (int) Math.pow(2, 32);
52
53
54
55
56
57 private final ByteBuffer buffer;
58
59
60 private int bufferOffset;
61
62
63 private int expectedDataSequenceNumber;
64
65
66
67
68
69
70
71
72
73
74
75
76 public ReadResponseState (final Connection initConnection, final ByteBuffer initBuffer, final int initBufferOffset, final int initExpectedDataSequenceNumber) {
77
78 super(initConnection);
79 buffer = initBuffer;
80 bufferOffset = initBufferOffset;
81 expectedDataSequenceNumber = initExpectedDataSequenceNumber;
82 }
83
84
85
86
87
88 public final void execute () throws InternetSCSIException {
89
90 ProtocolDataUnit protocolDataUnit;
91
92 do {
93 protocolDataUnit = connection.receive();
94 boolean dataWasRead = false;
95 if (protocolDataUnit.getBasicHeaderSegment().getParser() instanceof DataInParser) {
96 final DataInParser parser = (DataInParser) protocolDataUnit.getBasicHeaderSegment().getParser();
97
98 if (LOGGER.isDebugEnabled()) {
99 LOGGER.debug("Remaining, DataSegmentLength: " + buffer.remaining() + ", " + protocolDataUnit.getBasicHeaderSegment().getDataSegmentLength());
100 }
101
102 final ByteBuffer dataSegment = protocolDataUnit.getDataSegment();
103 while (buffer.hasRemaining() && dataSegment.hasRemaining()) {
104 buffer.put(dataSegment.get());
105 }
106 dataWasRead = true;
107
108 if (parser.isStatusFlag() && parser.getStatus() == SCSIStatus.GOOD) {
109
110 return;
111 } else if (connection.getSettingAsInt(OperationalTextKey.ERROR_RECOVERY_LEVEL) > 0 && parser.isAcknowledgeFlag()) {
112
113
114 connection.nextState(new SNACKRequestState(connection, this, parser.getTargetTaskTag()));
115
116 return;
117 } else if (protocolDataUnit.getBasicHeaderSegment().getParser() instanceof SCSIResponseParser && !dataWasRead) {
118 readHandleImmediateData(protocolDataUnit);
119 }
120 }
121 } while (!protocolDataUnit.getBasicHeaderSegment().isFinalFlag());
122
123 if (connection.getSettingAsBoolean(OperationalTextKey.IMMEDIATE_DATA)) {
124 return;
125 } else {
126 protocolDataUnit = connection.receive();
127 if (protocolDataUnit.getBasicHeaderSegment().getParser() instanceof SCSIResponseParser) {
128 readHandleImmediateData(protocolDataUnit);
129 }
130 }
131
132 }
133
134 private void readHandleImmediateData (final ProtocolDataUnit protocolDataUnit) throws InternetSCSIException {
135 final SCSIResponseParser parser = (SCSIResponseParser) protocolDataUnit.getBasicHeaderSegment().getParser();
136
137 final ByteBuffer dataSegment = protocolDataUnit.getDataSegment();
138 while (buffer.hasRemaining() && dataSegment.hasRemaining()) {
139 buffer.put(dataSegment.get());
140 }
141
142 if (parser.getStatus() == SCSIStatus.GOOD) {
143
144 super.stateFollowing = false;
145 return;
146 } else {
147 throw new InternetSCSIException();
148 }
149 }
150
151
152
153
154
155 @Override
156 public Exception isCorrect (final ProtocolDataUnit protocolDataUnit) {
157
158 final AbstractMessageParser parser = protocolDataUnit.getBasicHeaderSegment().getParser();
159
160 if (parser instanceof DataInParser) {
161
162 final DataInParser dataParser = (DataInParser) parser;
163 try {
164 if (connection.getSettingAsBoolean(OperationalTextKey.DATA_PDU_IN_ORDER) && connection.getSettingAsBoolean(OperationalTextKey.DATA_SEQUENCE_IN_ORDER)) {
165 if (dataParser.getBufferOffset() < bufferOffset) { return new IllegalStateException(new StringBuilder("This buffer offsets must be in increasing order and overlays are forbidden.").append(" The parserOffset here is ").append(dataParser.getBufferOffset()).append(" and the bufferOffset is ").append(bufferOffset).toString()); }
166 bufferOffset = dataParser.getBufferOffset();
167 }
168 } catch (OperationalTextKeyException e) {
169 return e;
170 }
171
172 if (dataParser.getDataSequenceNumber() != expectedDataSequenceNumber) { return new IllegalStateException(new StringBuilder("Data Sequence Number Mismatch (received, expected): " + dataParser.getDataSequenceNumber() + ", " + expectedDataSequenceNumber).toString());
173
174 }
175
176 incrementExpectedDataSequenceNumber();
177
178 if (dataParser.isStatusFlag()) {
179 incrementExpectedDataSequenceNumber();
180 return super.isCorrect(protocolDataUnit);
181 } else if (dataParser.getStatusSequenceNumber() != 0) { return new IllegalStateException(new StringBuilder("Status Sequence Number must be zero.").toString()); }
182 return null;
183 } else if (parser instanceof SCSIResponseParser) {
184 try {
185 if (connection.getSettingAsBoolean(OperationalTextKey.IMMEDIATE_DATA)) { return new IllegalStateException(new StringBuilder("Parser ").append("should not be instance of SCSIResponseParser because of ImmendiateData-Flag \"no\" in config!").toString()); }
186 } catch (OperationalTextKeyException e) {
187 return e;
188 }
189
190 return null;
191 } else {
192 return new IllegalStateException(new StringBuilder("Parser ").append(protocolDataUnit.getBasicHeaderSegment().getParser().toString()).append(" is instance of ").append(protocolDataUnit.getBasicHeaderSegment().getParser().getClass().toString()).append(" and not instance of either DataInParser or SCSIResponseParser!").toString());
193 }
194
195 }
196
197
198
199
200
201
202
203 private void incrementExpectedDataSequenceNumber () {
204
205 expectedDataSequenceNumber = (expectedDataSequenceNumber + 1) % WRAP_AROUND_DIVISOR;
206 }
207
208
209
210
211
212
213 }