1 package org.jscsi.target;
2
3
4 import java.io.BufferedReader;
5 import java.io.File;
6 import java.io.IOException;
7 import java.io.InputStreamReader;
8 import java.net.InetAddress;
9 import java.net.InetSocketAddress;
10 import java.net.NetworkInterface;
11 import java.nio.channels.ServerSocketChannel;
12 import java.nio.channels.SocketChannel;
13 import java.security.DigestException;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.Enumeration;
17 import java.util.HashMap;
18 import java.util.List;
19 import java.util.Vector;
20 import java.util.concurrent.Callable;
21 import java.util.concurrent.atomic.AtomicInteger;
22
23 import org.jscsi.exception.InternetSCSIException;
24 import org.jscsi.parser.OperationCode;
25 import org.jscsi.parser.ProtocolDataUnit;
26 import org.jscsi.parser.login.ISID;
27 import org.jscsi.parser.login.LoginRequestParser;
28 import org.jscsi.target.connection.Connection;
29 import org.jscsi.target.connection.Connection.TargetConnection;
30 import org.jscsi.target.connection.TargetSession;
31 import org.jscsi.target.scsi.inquiry.DeviceIdentificationVpdPage;
32 import org.jscsi.target.settings.SettingsException;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36
37
38
39
40
41
42
43
44 public final class TargetServer implements Callable<Void> {
45
46 private static final Logger LOGGER = LoggerFactory.getLogger(TargetServer.class);
47
48
49
50
51 private ServerSocketChannel serverSocketChannel;
52
53
54
55
56 private Collection<TargetSession> sessions = new Vector<TargetSession>();
57
58
59
60
61 private Configuration config;
62
63
64
65
66 private DeviceIdentificationVpdPage deviceIdentificationVpdPage;
67
68
69
70
71 private HashMap<String , Target> targets = new HashMap<String , Target>();
72
73
74
75
76
77 private static final AtomicInteger nextTargetTransferTag = new AtomicInteger();
78
79
80
81
82 private Connection connection;
83
84
85
86
87 private boolean running = true;
88
89 public TargetServer (final Configuration conf) {
90 this.config = conf;
91
92 LOGGER.debug("Starting jSCSI-target: ");
93
94
95
96 LOGGER.debug(" port: " + getConfig().getPort());
97 LOGGER.debug(" loading targets.");
98
99 List<Target> targetInfo = getConfig().getTargets();
100 for (Target curTargetInfo : targetInfo) {
101
102 targets.put(curTargetInfo.getTargetName(), curTargetInfo);
103
104 LOGGER.debug(" target name: " + curTargetInfo.getTargetName() + " loaded.");
105 }
106
107 this.deviceIdentificationVpdPage = new DeviceIdentificationVpdPage(this);
108 }
109
110
111
112
113
114
115
116
117
118 public static int getNextTargetTransferTag () {
119
120 int tag;
121 do {
122 tag = nextTargetTransferTag.getAndIncrement();
123 } while (tag == -1);
124 return tag;
125 }
126
127
128
129
130
131
132
133 public static void main (String[] args) throws Exception {
134 TargetServer target;
135
136 System.out.println("This system provides more than one IP Address to advertise.\n");
137
138 Enumeration<NetworkInterface> interfaceEnum = NetworkInterface.getNetworkInterfaces();
139 NetworkInterface i;
140 int addressCounter = 0;
141 List<InetAddress> addresses = new ArrayList<InetAddress>();
142 while (interfaceEnum.hasMoreElements()) {
143 i = interfaceEnum.nextElement();
144 Enumeration<InetAddress> addressEnum = i.getInetAddresses();
145 InetAddress address;
146
147 while (addressEnum.hasMoreElements()) {
148 address = addressEnum.nextElement();
149 System.out.println("[" + addressCounter + "] " + address.getHostAddress());
150 addresses.add(address);
151 addressCounter++;
152 }
153 }
154
155
156
157
158
159 System.out.print("\nWhich one should be used?\nType in the number: ");
160 Integer chosenIndex = null;
161
162 while (chosenIndex == null) {
163 BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
164 String line = br.readLine();
165 try {
166 chosenIndex = Integer.parseInt(line);
167 } catch (NumberFormatException nfe) {
168 chosenIndex = null;
169 }
170 }
171
172 String targetAddress = addresses.get(chosenIndex).getHostAddress();
173 System.out.println("Using ip address " + addresses.get(chosenIndex).getHostAddress());
174
175
176 switch (args.length) {
177 case 0 :
178 target = new TargetServer(Configuration.create(targetAddress));
179 break;
180 case 1 :
181
182
183 target = new TargetServer(Configuration.create(Configuration.CONFIGURATION_SCHEMA_FILE.exists() ? Configuration.CONFIGURATION_SCHEMA_FILE : new File("classpath://jscsi-target.xsd"), new File(args[0]), targetAddress));
184 break;
185 case 2 :
186 target = new TargetServer(Configuration.create(new File(args[0]), new File(args[1]), targetAddress));
187 break;
188 default :
189 throw new IllegalArgumentException("Only zero or one Parameter (Path to Configuration-File) allowed!");
190 }
191
192 target.call();
193 }
194
195 public Void call () throws Exception {
196
197
198 try {
199
200
201 serverSocketChannel = ServerSocketChannel.open();
202 serverSocketChannel.configureBlocking(true);
203
204
205 serverSocketChannel.socket().bind(new InetSocketAddress(getConfig().getTargetAddress(), getConfig().getPort()));
206
207 while (running) {
208
209
210
211 final SocketChannel socketChannel = serverSocketChannel.accept();
212
213
214 socketChannel.socket().setTcpNoDelay(true);
215
216 connection = new TargetConnection(socketChannel, true);
217 try {
218 final ProtocolDataUnit pdu = connection.receivePdu();
219
220 if (pdu.getBasicHeaderSegment().getOpCode() != OperationCode.LOGIN_REQUEST) throw new InternetSCSIException();
221
222
223 LoginRequestParser parser = (LoginRequestParser) pdu.getBasicHeaderSegment().getParser();
224 ISID initiatorSessionID = parser.getInitiatorSessionID();
225
226
227
228
229
230 TargetSession session = new TargetSession(this, connection, initiatorSessionID, parser.getCommandSequenceNumber(),
231
232
233
234
235
236
237
238 parser.getExpectedStatusSequenceNumber());
239
240 sessions.add(session);
241
242 connection.call();
243 } catch (DigestException | InternetSCSIException | SettingsException e) {
244 LOGGER.info("Throws Exception", e);
245 continue;
246 }
247 }
248 } catch (IOException e) {
249
250 LOGGER.error("Throws Exception", e);
251 }
252
253 System.out.println("Closing socket channel.");
254 serverSocketChannel.close();
255 for(TargetSession session: sessions){
256 System.out.println("Commiting uncommited changes.");
257 session.getStorageModule().close();
258 }
259 return null;
260 }
261
262 public Configuration getConfig () {
263 return config;
264 }
265
266 public DeviceIdentificationVpdPage getDeviceIdentificationVpdPage () {
267 return deviceIdentificationVpdPage;
268 }
269
270 public Target getTarget (String targetName) {
271 synchronized (targets) {
272 return targets.get(targetName);
273 }
274 }
275
276
277
278
279
280
281 public synchronized void removeTargetSession (TargetSession session) {
282 sessions.remove(session);
283 }
284
285 public String[] getTargetNames () {
286 String[] returnNames = new String[targets.size()];
287 returnNames = targets.keySet().toArray(returnNames);
288 return returnNames;
289 }
290
291
292
293
294
295
296
297 public boolean isValidTargetName (String checkTargetName) {
298 return targets.containsKey(checkTargetName);
299 }
300
301
302
303
304
305
306 public Connection getConnection () {
307 return this.connection;
308 }
309
310
311
312
313 public void stop(){
314 this.running = false;
315 for(TargetSession session : sessions){
316 if(!session.getConnection().stop()){
317 this.running = true;
318 LOGGER.error("Unable to stop session for " + session.getTargetName());
319 }
320 }
321 }
322
323 }