1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.waarp.ftp.core.session;
21
22 import io.netty.channel.Channel;
23 import org.waarp.common.command.CommandInterface;
24 import org.waarp.common.command.ReplyCode;
25 import org.waarp.common.command.exception.CommandAbstractException;
26 import org.waarp.common.command.exception.Reply425Exception;
27 import org.waarp.common.file.FileParameterInterface;
28 import org.waarp.common.file.Restart;
29 import org.waarp.common.file.SessionInterface;
30 import org.waarp.common.future.WaarpFuture;
31 import org.waarp.common.logging.WaarpLogger;
32 import org.waarp.common.logging.WaarpLoggerFactory;
33 import org.waarp.ftp.core.command.AbstractCommand;
34 import org.waarp.ftp.core.command.FtpArgumentCode;
35 import org.waarp.ftp.core.command.FtpArgumentCode.TransferSubType;
36 import org.waarp.ftp.core.command.internal.ConnectionCommand;
37 import org.waarp.ftp.core.config.FtpConfiguration;
38 import org.waarp.ftp.core.control.BusinessHandler;
39 import org.waarp.ftp.core.control.NetworkHandler;
40 import org.waarp.ftp.core.data.FtpDataAsyncConn;
41 import org.waarp.ftp.core.exception.FtpNoConnectionException;
42 import org.waarp.ftp.core.file.FtpAuth;
43 import org.waarp.ftp.core.file.FtpDir;
44
45 import java.io.File;
46 import java.net.InetAddress;
47 import java.net.InetSocketAddress;
48 import java.util.concurrent.atomic.AtomicBoolean;
49
50
51
52
53
54
55 public class FtpSession implements SessionInterface {
56
57
58
59 private static final WaarpLogger logger =
60 WaarpLoggerFactory.getLogger(FtpSession.class);
61
62
63
64 private final BusinessHandler businessHandler;
65
66
67
68
69 private final FtpConfiguration configuration;
70
71
72
73
74 private FtpDataAsyncConn dataConn;
75
76
77
78
79 private FtpAuth ftpAuth;
80
81
82
83
84 private FtpDir ftpDir;
85
86
87
88
89 private AbstractCommand previousCommand;
90
91
92
93
94 private AbstractCommand currentCommand;
95
96
97
98 private final AtomicBoolean isCurrentCommandFinished =
99 new AtomicBoolean(true);
100
101
102
103
104 private ReplyCode replyCode;
105
106
107
108
109 private String answer;
110
111
112
113
114 private Restart restart;
115
116
117
118
119 private final WaarpFuture isReady = new WaarpFuture(true);
120
121
122
123
124 private final AtomicBoolean isSsl = new AtomicBoolean(false);
125
126
127
128 private WaarpFuture waitForSsl;
129
130
131
132 private final AtomicBoolean isDataSsl = new AtomicBoolean(false);
133
134
135
136
137
138
139
140 public FtpSession(final FtpConfiguration configuration,
141 final BusinessHandler handler) {
142 this.configuration = configuration;
143 businessHandler = handler;
144 }
145
146
147
148
149 public final BusinessHandler getBusinessHandler() {
150 return businessHandler;
151 }
152
153
154
155
156
157
158 public final FtpConfiguration getConfiguration() {
159 return configuration;
160 }
161
162 @Override
163 public final FtpDir getDir() {
164 return ftpDir;
165 }
166
167
168
169
170 public final FtpDataAsyncConn getDataConn() {
171 return dataConn;
172 }
173
174 @Override
175 public final FtpAuth getAuth() {
176 return ftpAuth;
177 }
178
179 @Override
180 public final Restart getRestart() {
181 return restart;
182 }
183
184
185
186
187
188 public final synchronized void setControlConnected() {
189 dataConn = new FtpDataAsyncConn(this);
190
191 ftpAuth = businessHandler.getBusinessNewAuth();
192 ftpDir = businessHandler.getBusinessNewDir();
193 restart = businessHandler.getBusinessNewRestart();
194 }
195
196
197
198
199
200
201
202
203 public final void setSpecialInit(final FtpAuth auth, final FtpDir dir,
204 final Restart restart) {
205 ftpAuth = auth;
206 ftpDir = dir;
207 this.restart = restart;
208 }
209
210
211
212
213 public final Channel getControlChannel() {
214 final NetworkHandler networkHandler = getNetworkHandler();
215 if (networkHandler != null) {
216 return networkHandler.getControlChannel();
217 }
218 return null;
219 }
220
221
222
223
224 public final NetworkHandler getNetworkHandler() {
225 if (businessHandler != null) {
226 return businessHandler.getNetworkHandler();
227 }
228 return null;
229 }
230
231
232
233
234
235
236 public final void setNextCommand(final CommandInterface command) {
237 previousCommand = currentCommand;
238 currentCommand = (AbstractCommand) command;
239 isCurrentCommandFinished.set(false);
240 }
241
242
243
244
245 public final AbstractCommand getCurrentCommand() {
246 return currentCommand;
247 }
248
249
250
251
252 public final AbstractCommand getPreviousCommand() {
253 return previousCommand;
254 }
255
256
257
258
259
260
261
262 public final void setPreviousAsCurrentCommand() {
263 currentCommand = previousCommand;
264 isCurrentCommandFinished.set(true);
265 }
266
267
268
269
270
271
272 public final boolean isCurrentCommandFinished() {
273 return isCurrentCommandFinished.get();
274 }
275
276
277
278
279 public final void setCurrentCommandFinished() {
280 isCurrentCommandFinished.set(true);
281 }
282
283
284
285
286 public final String getAnswer() {
287 if (answer == null) {
288 if (replyCode == null) {
289 answer = ReplyCode.REPLY_000_SPECIAL_NOSTATUS.getMesg();
290 } else {
291 answer = replyCode.getMesg();
292 }
293 }
294 return answer;
295 }
296
297
298
299
300
301 public final void setReplyCode(final ReplyCode replyCode,
302 final String answer) {
303 this.replyCode = replyCode;
304 if (answer != null) {
305 this.answer = ReplyCode.getFinalMsg(replyCode.getCode(), answer);
306 } else {
307 this.answer = replyCode.getMesg();
308 }
309 }
310
311
312
313
314 public final void setReplyCode(final CommandAbstractException exception) {
315 setReplyCode(exception.code, exception.message);
316 }
317
318
319
320
321
322
323 public final void setExitErrorCode(final String answer) {
324 setReplyCode(
325 ReplyCode.REPLY_421_SERVICE_NOT_AVAILABLE_CLOSING_CONTROL_CONNECTION,
326 answer);
327 }
328
329
330
331
332
333
334 public final void setExitNormalCode(final String answer) {
335 setReplyCode(ReplyCode.REPLY_221_CLOSING_CONTROL_CONNECTION, answer);
336 }
337
338
339
340
341 public final ReplyCode getReplyCode() {
342 return replyCode;
343 }
344
345 @Override
346 public final void clear() {
347 if (dataConn != null) {
348 dataConn.clear();
349 }
350 if (ftpDir != null) {
351 ftpDir.clear();
352 }
353 if (ftpAuth != null) {
354 ftpAuth.clear();
355 }
356 previousCommand = null;
357 replyCode = null;
358 answer = null;
359 isReady.cancel();
360 }
361
362
363
364
365 public final boolean isReady() {
366 isReady.awaitOrInterruptible();
367 return isReady.isSuccess();
368 }
369
370
371
372
373 public final void setReady(final boolean isReady) {
374 if (isReady) {
375 this.isReady.setSuccess();
376 } else {
377 this.isReady.cancel();
378 }
379 }
380
381 @Override
382 public String toString() {
383 final StringBuilder builder = new StringBuilder("FtpSession: ");
384 if (ftpAuth != null) {
385 builder.append("User: ").append(ftpAuth.getUser()).append('/')
386 .append(ftpAuth.getAccount()).append(' ');
387 }
388 if (previousCommand != null) {
389 builder.append("PRVCMD: ").append(previousCommand.getCommand())
390 .append(' ').append(previousCommand.getArg()).append(' ');
391 }
392 if (currentCommand != null) {
393 builder.append("CMD: ").append(currentCommand.getCommand()).append(' ')
394 .append(currentCommand.getArg()).append(' ');
395 }
396 if (replyCode != null) {
397 builder.append("Reply: ")
398 .append(answer != null? answer : replyCode.getMesg()).append(' ');
399 }
400 if (dataConn != null) {
401 builder.append(dataConn);
402 }
403 if (ftpDir != null) {
404 try {
405 builder.append(" PWD: ").append(ftpDir.getPwd());
406 } catch (final CommandAbstractException ignored) {
407
408 }
409 }
410 if (getControlChannel() != null) {
411 builder.append(" Control: ").append(getControlChannel());
412 }
413 try {
414 if (getDataConn().getCurrentDataChannel() != null) {
415 builder.append(" Data: ").append(getDataConn().getCurrentDataChannel());
416 }
417 } catch (final FtpNoConnectionException ignored) {
418
419 }
420 return builder.append('\n').toString();
421 }
422
423 @Override
424 public final int getBlockSize() {
425 return restart.getMaxSize(configuration.getBlocksize());
426 }
427
428 @Override
429 public final FileParameterInterface getFileParameter() {
430 return configuration.getFileParameter();
431 }
432
433
434
435
436
437
438 public static String getBasename(final String path) {
439 final File file = new File(path);
440 return file.getName();
441 }
442
443
444
445
446 public final void reinitFtpAuth() {
447 final AbstractCommand connectioncommand = new ConnectionCommand(this);
448 setNextCommand(connectioncommand);
449 getAuth().clear();
450 getDataConn().clear();
451 getDataConn().getFtpTransferControl().resetWaitForOpenedDataChannel();
452 }
453
454
455
456
457 public final void rein() {
458
459
460 final InetSocketAddress local = getDataConn().getLocalAddress();
461 final InetAddress remote = getDataConn().getRemoteAddress().getAddress();
462 getConfiguration().delFtpSession(remote, local);
463 getDataConn().unbindData();
464 getDataConn().setMode(FtpArgumentCode.TransferMode.STREAM);
465 getDataConn().setStructure(FtpArgumentCode.TransferStructure.FILE);
466 getDataConn().setType(FtpArgumentCode.TransferType.ASCII);
467 getDataConn().setSubType(TransferSubType.NONPRINT);
468 reinitFtpAuth();
469 }
470
471
472
473
474
475
476
477 public final void openDataConnection() throws Reply425Exception {
478 getDataConn().getFtpTransferControl().openDataConnection();
479 final NetworkHandler networkHandler = getNetworkHandler();
480 if (networkHandler != null) {
481 networkHandler.writeIntermediateAnswer();
482 }
483 }
484
485 @Override
486 public final String getUniqueExtension() {
487 return configuration.getUniqueExtension();
488 }
489
490 public final boolean isSsl() {
491 return isSsl.get();
492 }
493
494 public final void setSsl(final boolean isSsl) {
495 this.isSsl.set(isSsl);
496 if (waitForSsl != null) {
497 if (isSsl) {
498 waitForSsl.setSuccess();
499 } else {
500 waitForSsl.cancel();
501 }
502 }
503 }
504
505 public synchronized void prepareSsl() {
506 waitForSsl = new WaarpFuture(true);
507 }
508
509 public final boolean isSslReady() {
510 if (waitForSsl != null) {
511 for (int i = 0; i < 20; i++) {
512 if (waitForSsl.awaitOrInterruptible(100)) {
513 break;
514 }
515 Thread.yield();
516 }
517 logger.debug("DEBUG : {}:{}:{}", waitForSsl.isDone(), isSsl.get(),
518 getControlChannel());
519 }
520 return isSsl.get();
521 }
522
523 public final boolean isDataSsl() {
524 return isDataSsl.get();
525 }
526
527 public final void setDataSsl(final boolean isDataSsl) {
528 this.isDataSsl.set(isDataSsl);
529 }
530
531 }