View Javadoc

1   package org.jscsi.target.connection.stage.fullfeature;
2   
3   
4   import java.io.IOException;
5   import java.nio.ByteBuffer;
6   import java.security.DigestException;
7   import java.util.List;
8   import java.util.Vector;
9   
10  import org.jscsi.exception.InternetSCSIException;
11  import org.jscsi.parser.BasicHeaderSegment;
12  import org.jscsi.parser.ProtocolDataUnit;
13  import org.jscsi.target.connection.TargetPduFactory;
14  import org.jscsi.target.connection.phase.TargetFullFeaturePhase;
15  import org.jscsi.target.settings.SettingsException;
16  import org.jscsi.target.settings.TextKeyword;
17  import org.jscsi.target.settings.TextParameter;
18  import org.jscsi.target.util.ReadWrite;
19  import org.slf4j.Logger;
20  import org.slf4j.LoggerFactory;
21  
22  
23  /**
24   * A stage for processing requests by the initiator for a list of all targets available through the iSCSI portal and for
25   * negotiating connection parameters in the full feature phase.
26   * <p>
27   * That latter functionality is currently not implemented.
28   * 
29   * @author Andreas Ergenzinger
30   */
31  public final class TextNegotiationStage extends TargetFullFeatureStage {
32  
33      private static final Logger LOGGER = LoggerFactory.getLogger(TextNegotiationStage.class);
34  
35      public TextNegotiationStage (TargetFullFeaturePhase targetFullFeaturePhase) {
36          super(targetFullFeaturePhase);
37      }
38  
39      @Override
40      public void execute (ProtocolDataUnit pdu) throws IOException , InterruptedException , InternetSCSIException , DigestException , SettingsException {
41  
42          final BasicHeaderSegment bhs = pdu.getBasicHeaderSegment();
43  
44          final int initiatorTaskTag = bhs.getInitiatorTaskTag();
45  
46          final String textRequest = new String(pdu.getDataSegment().array());
47  
48          LOGGER.debug("text request: " + textRequest);
49  
50          ByteBuffer replyDataSegment = null;// for later
51  
52          // tokenize key-value pairs
53          final List<String> requestKeyValuePairs = TextParameter.tokenizeKeyValuePairs(textRequest);
54  
55          final List<String> responseKeyValuePairs = new Vector<String>();
56  
57          // process SendTargets command
58          if (requestKeyValuePairs != null) {
59              // A SendTargets command consists of a single Text request PDU. This
60              // PDU contains exactly one text key and value.
61              String sendTargetsValue = null;
62  
63              if (requestKeyValuePairs.size() == 1) sendTargetsValue = TextParameter.getSuffix(requestKeyValuePairs.get(0),// string
64                      TextKeyword.SEND_TARGETS + TextKeyword.EQUALS);// prefix
65  
66              if (sendTargetsValue != null) {
67                  // initiator wants target information
68                  /*
69                   * ALL must be supported in discovery session and must not be supported in operational session.
70                   * <name-of-this-target> must be supported in discovery session (and it does no harm to support it in
71                   * the operational session). <nothing> must be supported in the operational session and will only return
72                   * info on the target the initiator is connected to, this means no info is returned in discovery
73                   * session. outcome table | discovery |operational| ---------------+-----------+-----------| ALL | TN +
74                   * TA | fail | ---------------+-----------+-----------| <this target> | TA | TA |
75                   * ---------------+-----------+-----------| <other target> | fail | fail |
76                   * ---------------+-----------+-----------| <nothing> | fail | TA | TN stands for TargetName, TA for
77                   * TargetAddress "fail" means no text response.
78                   */
79                  final boolean normal = session.isNormalSession();
80                  final boolean sendTargetName = // see upper table
81                  !normal && sendTargetsValue.equals(TextKeyword.ALL);
82                  final boolean sendTargetAddress = // see upper table
83                  (!normal && sendTargetsValue.equals(TextKeyword.ALL)) || (session.getTargetServer().isValidTargetName(sendTargetsValue)) || (normal && sendTargetsValue.length() == 0);
84  
85                  /*
86                   * A target record consists of a TargetName key-value pair followed by one or more TargetAddress
87                   * key-value pairs for that TargetName. (table above takes precedence to these definitions)
88                   */
89  
90                  // add TargetName
91                  if (sendTargetName) {
92                      for (String curTargetName : session.getTargetServer().getTargetNames()) {
93                          responseKeyValuePairs.add(TextParameter.toKeyValuePair(TextKeyword.TARGET_NAME, curTargetName));
94                          // add TargetAddress
95                          if (sendTargetAddress) responseKeyValuePairs.add(TextParameter.toKeyValuePair(TextKeyword.TARGET_ADDRESS, session.getTargetServer().getConfig().getTargetAddress() + // domain
96                          TextKeyword.COLON + // :
97                          session.getTargetServer().getConfig().getPort() + // port
98                          TextKeyword.COMMA + // ,
99                          session.getTargetServer().getConfig().getTargetPortalGroupTag())); // groupTag)
100                     }
101                 } else {
102                     // We're here if they sent us a target name and are asking for the address (I think)
103                     if (sendTargetAddress) responseKeyValuePairs.add(TextParameter.toKeyValuePair(TextKeyword.TARGET_ADDRESS, session.getTargetServer().getConfig().getTargetAddress() + // domain
104                     TextKeyword.COLON + // :
105                     session.getTargetServer().getConfig().getPort() + // port
106                     TextKeyword.COMMA + // ,
107                     session.getTargetServer().getConfig().getTargetPortalGroupTag())); // groupTag)
108                 }
109 
110             } else {
111                 // initiator wants to negotiate or declare parameters
112                 // TODO
113             }
114 
115             // concatenate and serialize reply
116             final String replyString = TextParameter.concatenateKeyValuePairs(responseKeyValuePairs);
117 
118             LOGGER.debug("text negotiation stage reply: " + replyString);
119 
120             replyDataSegment = ReadWrite.stringToTextDataSegments(replyString, settings.getMaxRecvDataSegmentLength())[0];// definitely
121                                                                                                                           // fits
122                                                                                                                           // into
123                                                                                                                           // one
124                                                                                                                           // data
125                                                                                                                           // segment
126         }
127 
128         // send reply
129         final ProtocolDataUnit responsePdu = TargetPduFactory.createTextResponsePdu(true,// finalFlag
130                 false,// continueFlag
131                 0,// logicalUnitNumber
132                 initiatorTaskTag, 0xffffffff,// targetTransferTag
133                 replyDataSegment);// dataSegment
134 
135         connection.sendPdu(responsePdu);
136     }
137 
138 }