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;
20  
21  
22  import java.io.IOException;
23  import java.net.InetSocketAddress;
24  import java.security.DigestException;
25  import java.util.Queue;
26  
27  import org.jscsi.exception.InternetSCSIException;
28  import org.jscsi.exception.NoSuchSessionException;
29  import org.jscsi.exception.OperationalTextKeyException;
30  import org.jscsi.initiator.Configuration;
31  import org.jscsi.initiator.connection.state.IState;
32  import org.jscsi.parser.ProtocolDataUnit;
33  import org.jscsi.parser.datasegment.OperationalTextKey;
34  import org.jscsi.parser.datasegment.SettingsMap;
35  import org.jscsi.utils.SerialArithmeticNumber;
36  import org.slf4j.Logger;
37  import org.slf4j.LoggerFactory;
38  
39  
40  /**
41   * <h1>AbsConnection</h1>
42   * <p/>
43   * This abstract class represents a connection, which is used in the iSCSI Standard (RFC3720). Such a connection is
44   * directed from the initiator to the target. It is used in Sessions.
45   * 
46   * @author Volker Wildi, University of Konstanz
47   * @author Patrice Matthias Brend'amour, University of Konstanz
48   * @author Sebastian Graf, University of Konstanz
49   */
50  public final class Connection {
51  
52      // --------------------------------------------------------------------------
53      // --------------------------------------------------------------------------
54  
55      /** The logger interface. */
56      private static final Logger LOGGER = LoggerFactory.getLogger(Connection.class);
57  
58      // --------------------------------------------------------------------------
59      // --------------------------------------------------------------------------
60  
61      /**
62       * The <code>Session</code> instance, which contains this <code>Connection</code> instance.
63       */
64      private final Session referenceSession;
65  
66      /** The <code>Configuration</code> instance for this connection. */
67      private final Configuration configuration;
68  
69      /** The current state of this connection. */
70      private IState state;
71  
72      /**
73       * The ID of this connection. This must be unique within a <code>Session</code>.
74       */
75      private final short connectionID;
76  
77      /**
78       * The Expected Status Sequence Number, which is expected to received from the target within this connection.
79       */
80      private final SerialArithmeticNumber expectedStatusSequenceNumber;
81  
82      // --------------------------------------------------------------------------
83      // --------------------------------------------------------------------------
84  
85      /**
86       * The worker caller, which handles the transmission of the packages over the network.
87       */
88      private final SenderWorker senderReceiver;
89  
90      /**
91       * Method to create and return a new, empty <code>Connection</code> object with the configured layer of threading.
92       * 
93       * @param session Reference to the <code>AbsSession</code> object, which contains this connection.
94       * @param initConfiguration The configuration to use within this connection.
95       * @param inetAddress The <code>InetSocketAddress</code> to which this connection should established.
96       * @param initConnectionID The ID of this connection.
97       * @throws Exception If any error occurs.
98       */
99  
100     public Connection (final Session session, final Configuration initConfiguration, final InetSocketAddress inetAddress, final short initConnectionID) throws Exception {
101 
102         senderReceiver = new SenderWorker(this, inetAddress);
103 
104         configuration = initConfiguration;
105         connectionID = initConnectionID;
106 
107         referenceSession = session;
108         expectedStatusSequenceNumber = new SerialArithmeticNumber();
109 
110     }
111 
112     /**
113      * Updates all entries of the given response key-values with the stored settings of this instance.
114      * 
115      * @param response The settings of the response.
116      * @throws NoSuchSessionException if a session with this target name is not open.
117      */
118     public final void update (final SettingsMap response) throws NoSuchSessionException {
119 
120         configuration.update(referenceSession.getTargetName(), connectionID, response);
121     }
122 
123     /**
124      * Returns the value of the given parameter, which is parsed to an <code>boolean</code>.
125      * 
126      * @param textKey The name of the parameter.
127      * @return The <code>boolean</code> value of this parameter. So if the value is equal to <code>Yes</code>, then
128      *         <code>true</code> will be returned. Else <code>false</code> is returned.
129      * @throws OperationalTextKeyException If the given parameter cannot be found.
130      */
131     public final boolean getSettingAsBoolean (final OperationalTextKey textKey) throws OperationalTextKeyException {
132         return getSetting(textKey).compareTo("Yes") == 0;
133     }
134 
135     /**
136      * Returns the value of the given parameter, which is parsed to an <code>integer</code>.
137      * 
138      * @param textKey The name of the parameter.
139      * @return The <code>integer</code> value of this parameter.
140      * @throws OperationalTextKeyException If the given parameter cannot be found.
141      */
142     public final int getSettingAsInt (final OperationalTextKey textKey) throws OperationalTextKeyException {
143 
144         return Integer.parseInt(getSetting(textKey));
145     }
146 
147     /**
148      * Returns the value of the given parameter as <code>String</code>.
149      * 
150      * @param textKey The name of the parameter.
151      * @return The value of this parameter.
152      * @throws OperationalTextKeyException If the given parameter cannot be found.
153      */
154     public final String getSetting (final OperationalTextKey textKey) throws OperationalTextKeyException {
155 
156         return configuration.getSetting(referenceSession.getTargetName(), connectionID, textKey);
157     }
158 
159     /**
160      * Returns the settings of the given session and connection.
161      * 
162      * @return The settings of this specific connection.
163      */
164     public final SettingsMap getSettings () {
165 
166         return configuration.getSettings(referenceSession.getTargetName(), connectionID);
167     }
168 
169     // --------------------------------------------------------------------------
170     // --------------------------------------------------------------------------
171 
172     /**
173      * Increments the Expected Status Sequence Number as defined in RFC1982 where <code>SERIAL_BITS = 32</code>.
174      */
175     public final void incrementExpectedStatusSequenceNumber () {
176 
177         expectedStatusSequenceNumber.increment();
178     }
179 
180     /**
181      * Returns the Expected Status Sequence Number of this <code>Connection</code> object.
182      * 
183      * @return The current Expected Status Sequence Number.
184      */
185     public final SerialArithmeticNumber getExpectedStatusSequenceNumber () {
186 
187         return expectedStatusSequenceNumber;
188     }
189 
190     /**
191      * Sets the expected Status Sequence Number to the given one from the leading Login Response.
192      * 
193      * @param newExpectedStatusSequenceNumber The new value.
194      */
195     public final void setExpectedStatusSequenceNumber (final int newExpectedStatusSequenceNumber) {
196 
197         expectedStatusSequenceNumber.setValue(newExpectedStatusSequenceNumber);
198 
199         LOGGER.trace("Set ExpStatSN to " + expectedStatusSequenceNumber);
200     }
201 
202     // --------------------------------------------------------------------------
203     // --------------------------------------------------------------------------
204 
205     /**
206      * Switch to the new state. Start point of the state pattern. All states are computed one after another.
207      * 
208      * @param newState The new state.
209      * @throws InternetSCSIException of any kind
210      */
211     public final void nextState (final IState newState) throws InternetSCSIException {
212 
213         this.state = newState;
214         if (this.state != null) {
215             do {
216                 this.state.execute();
217                 LOGGER.info("State is following: " + this.state.nextStateFollowing());
218             } while (this.state.nextStateFollowing());
219         }
220 
221     }
222 
223     /**
224      * Returns the current state of this connection.
225      * 
226      * @return The current <code>IState</code> instance of this <code>Connection</code> instance.
227      */
228     public final IState getState () {
229 
230         return state;
231     }
232 
233     /**
234      * Returns the session, which contains this connection instance.
235      * 
236      * @return The parent session instance.
237      */
238     public final Session getSession () {
239 
240         return referenceSession;
241     }
242 
243     /**
244      * Returns the ID of this <code>Connection</code> object.
245      * 
246      * @return The connection ID.
247      */
248     public final short getConnectionID () {
249 
250         return connectionID;
251     }
252 
253     // --------------------------------------------------------------------------
254     // --------------------------------------------------------------------------
255 
256     /**
257      * This method does all the necessary steps, which are needed when a connection should be closed.
258      * 
259      * @throws IOException if an I/O error occurs.
260      */
261     public final void close () throws IOException {
262 
263         senderReceiver.close();
264         LOGGER.debug("Connection with ID " + connectionID + " closed.");
265     }
266 
267     /**
268      * Enqueue this protocol data unit to the end of the sending queue.
269      * 
270      * @param protocolDataUnit The protocol data unit to add.
271      * @throws InternetSCSIException for nearly everything
272      */
273     public final void send (final ProtocolDataUnit protocolDataUnit) throws InternetSCSIException {
274 
275         try {
276             senderReceiver.sendOverWire(protocolDataUnit);
277         } catch (IOException e) {
278             throw new InternetSCSIException(e);
279         } catch (InterruptedException e) {
280             throw new InternetSCSIException(e);
281         }
282     }
283 
284     /**
285      * Enqueue all protocol data units to the end of the sending queue.
286      * 
287      * @param protocolDataUnits The list with all protocol data units to add.
288      * @throws InternetSCSIException for nearly everything
289      */
290     public final void send (final Queue<ProtocolDataUnit> protocolDataUnits) throws InternetSCSIException {
291 
292         for (final ProtocolDataUnit unit : protocolDataUnits) {
293             send(unit);
294         }
295     }
296 
297     /**
298      * Reads one <code>ProtocolDataUnit</code> instance from the <code>receivingQueue</code>.
299      * 
300      * @return An instance of a <code>ProtocolDataUnit</code>.
301      * @throws InternetSCSIException for nearly everything
302      */
303     public final ProtocolDataUnit receive () throws InternetSCSIException {
304 
305         try {
306             return senderReceiver.receiveFromWire();
307         } catch (DigestException e) {
308             throw new InternetSCSIException(e);
309         } catch (IOException e) {
310             throw new InternetSCSIException(e);
311         }
312     }
313 
314     // --------------------------------------------------------------------------
315     // --------------------------------------------------------------------------
316     // --------------------------------------------------------------------------
317     // --------------------------------------------------------------------------
318 }