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.data;
21
22 import io.netty.channel.Channel;
23 import io.netty.channel.ChannelFuture;
24 import org.waarp.common.command.exception.Reply425Exception;
25 import org.waarp.common.crypto.ssl.WaarpSslUtility;
26 import org.waarp.common.logging.SysErrLogger;
27 import org.waarp.common.logging.WaarpLogger;
28 import org.waarp.common.logging.WaarpLoggerFactory;
29 import org.waarp.common.utility.WaarpNettyUtil;
30 import org.waarp.ftp.core.command.FtpArgumentCode;
31 import org.waarp.ftp.core.command.FtpArgumentCode.TransferMode;
32 import org.waarp.ftp.core.command.FtpArgumentCode.TransferStructure;
33 import org.waarp.ftp.core.command.FtpArgumentCode.TransferType;
34 import org.waarp.ftp.core.config.FtpConfiguration;
35 import org.waarp.ftp.core.config.FtpInternalConfiguration;
36 import org.waarp.ftp.core.data.handler.DataNetworkHandler;
37 import org.waarp.ftp.core.exception.FtpNoConnectionException;
38 import org.waarp.ftp.core.session.FtpSession;
39 import org.waarp.ftp.core.utils.FtpChannelUtils;
40
41 import java.net.InetAddress;
42 import java.net.InetSocketAddress;
43 import java.util.concurrent.atomic.AtomicBoolean;
44
45
46
47
48
49 public class FtpDataAsyncConn {
50
51
52
53 private static final WaarpLogger logger =
54 WaarpLoggerFactory.getLogger(FtpDataAsyncConn.class);
55
56
57
58 private final FtpSession session;
59
60
61
62
63 private DataNetworkHandler dataNetworkHandler;
64
65
66
67
68 private Channel dataChannel;
69
70
71
72
73 private InetSocketAddress remoteAddress;
74
75
76
77
78 private InetSocketAddress localAddress;
79
80
81
82
83
84 private int remotePort = -1;
85
86
87
88
89
90
91 private int localPort = -1;
92
93
94
95
96 private final AtomicBoolean passiveMode = new AtomicBoolean(false);
97
98
99
100
101 private final AtomicBoolean isBind = new AtomicBoolean(false);
102
103
104
105
106 private final FtpTransferControl transferControl;
107
108
109
110
111 private FtpArgumentCode.TransferType transferType =
112 FtpArgumentCode.TransferType.ASCII;
113
114
115
116
117 private FtpArgumentCode.TransferSubType transferSubType =
118 FtpArgumentCode.TransferSubType.NONPRINT;
119
120
121
122
123 private FtpArgumentCode.TransferStructure transferStructure =
124 FtpArgumentCode.TransferStructure.FILE;
125
126
127
128
129 private FtpArgumentCode.TransferMode transferMode =
130 FtpArgumentCode.TransferMode.STREAM;
131
132
133
134
135
136
137 public FtpDataAsyncConn(final FtpSession session) {
138 this.session = session;
139 dataChannel = null;
140 remoteAddress = FtpChannelUtils.getRemoteInetSocketAddress(
141 this.session.getControlChannel());
142 remotePort = remoteAddress.getPort();
143 setDefaultLocalPort();
144 resetLocalAddress();
145 passiveMode.set(false);
146 isBind.set(false);
147 transferControl = new FtpTransferControl(session);
148 }
149
150
151
152
153
154
155
156 public final boolean checkCorrectChannel(final Channel channel) {
157 if (dataChannel == null || channel == null) {
158 return false;
159 }
160 return dataChannel.compareTo(channel) == 0;
161 }
162
163
164
165
166 public final synchronized void clear() {
167 unbindData();
168 transferControl.clear();
169 passiveMode.set(false);
170 remotePort = -1;
171 localPort = -1;
172 }
173
174
175
176
177 private void setDefaultLocalPort() {
178 setLocalPort(0);
179 }
180
181
182
183
184
185
186 public final synchronized void setLocalPort(final int localPort) {
187 this.localPort = localPort;
188 }
189
190
191
192
193 public final InetSocketAddress getLocalAddress() {
194 return localAddress;
195 }
196
197
198
199
200 public final InetSocketAddress getRemoteAddress() {
201 return remoteAddress;
202 }
203
204
205
206
207 public final int getRemotePort() {
208 return remotePort;
209 }
210
211
212
213
214 public final synchronized int getLocalPort() {
215 return localPort;
216 }
217
218 private synchronized void resetLocalAddress() {
219 localAddress = new InetSocketAddress(
220 FtpChannelUtils.getLocalInetAddress(session.getControlChannel()),
221 localPort);
222 }
223
224
225
226
227
228
229 public final synchronized void setActive(final InetSocketAddress address) {
230 unbindData();
231 setDefaultLocalPort();
232 resetLocalAddress();
233 remoteAddress = address;
234 passiveMode.set(false);
235 isBind.set(false);
236 remotePort = remoteAddress.getPort();
237 logger.debug("SetActive: {}", this);
238 }
239
240
241
242
243
244
245 public final void setPassive() {
246 unbindData();
247 resetLocalAddress();
248 passiveMode.set(true);
249 isBind.set(false);
250 logger.debug("SetPassive: {}", this);
251 }
252
253
254
255
256 public final boolean isPassiveMode() {
257 return passiveMode.get();
258 }
259
260
261
262
263
264 public final boolean isBind() {
265 return isBind.get();
266 }
267
268
269
270
271
272
273 public final synchronized boolean isActive() {
274 return dataChannel != null && dataChannel.isActive();
275 }
276
277
278
279
280 public final synchronized FtpArgumentCode.TransferMode getMode() {
281 return transferMode;
282 }
283
284
285
286
287 public final synchronized void setMode(
288 final FtpArgumentCode.TransferMode transferMode) {
289 this.transferMode = transferMode;
290 setCorrectCodec();
291 }
292
293
294
295
296 public final synchronized FtpArgumentCode.TransferStructure getStructure() {
297 return transferStructure;
298 }
299
300
301
302
303 public final synchronized void setStructure(
304 final FtpArgumentCode.TransferStructure transferStructure) {
305 this.transferStructure = transferStructure;
306 setCorrectCodec();
307 }
308
309
310
311
312 public final synchronized FtpArgumentCode.TransferSubType getSubType() {
313 return transferSubType;
314 }
315
316
317
318
319 public final synchronized void setSubType(
320 final FtpArgumentCode.TransferSubType transferSubType) {
321 this.transferSubType = transferSubType;
322 setCorrectCodec();
323 }
324
325
326
327
328 public final synchronized FtpArgumentCode.TransferType getType() {
329 return transferType;
330 }
331
332
333
334
335 public final synchronized void setType(
336 final FtpArgumentCode.TransferType transferType) {
337 this.transferType = transferType;
338 setCorrectCodec();
339 }
340
341
342
343
344
345
346 public final boolean isFileStreamBlockAsciiImage() {
347 return transferStructure == TransferStructure.FILE &&
348 (transferMode == TransferMode.STREAM ||
349 transferMode == TransferMode.ZLIB ||
350 transferMode == TransferMode.BLOCK) &&
351 (transferType == TransferType.ASCII ||
352 transferType == TransferType.IMAGE);
353 }
354
355
356
357
358 public final boolean isStreamFile() {
359 return (transferMode == TransferMode.STREAM ||
360 transferMode == TransferMode.ZLIB) &&
361 transferStructure == TransferStructure.FILE;
362 }
363
364
365
366
367
368 private void setCorrectCodec() {
369 try {
370 getDataNetworkHandler().setCorrectCodec();
371 } catch (final FtpNoConnectionException ignored) {
372
373 }
374 }
375
376
377
378
379 public final synchronized void unbindData() {
380 if (isBind.get()) {
381 if (passiveMode.get()) {
382 isBind.set(false);
383 final InetSocketAddress local = getLocalAddress();
384 ChannelFuture future = null;
385 if (dataChannel != null && dataChannel.isActive()) {
386 future = WaarpSslUtility.closingSslChannel(dataChannel);
387 }
388 session.getConfiguration().getFtpInternalConfiguration()
389 .unbindPassive(local);
390
391
392 final InetAddress remote = remoteAddress.getAddress();
393 session.getConfiguration().delFtpSession(remote, local);
394
395 getFtpTransferControl().resetWaitForOpenedDataChannel();
396 if (future != null) {
397 future.awaitUninterruptibly(FtpConfiguration.getDataTimeoutCon());
398 }
399 } else {
400 isBind.set(false);
401 ChannelFuture future = null;
402 if (dataChannel != null && dataChannel.isActive()) {
403 future = WaarpSslUtility.closingSslChannel(dataChannel);
404 }
405 getFtpTransferControl().resetWaitForOpenedDataChannel();
406 if (future != null) {
407 future.awaitUninterruptibly(FtpConfiguration.getDataTimeoutCon());
408 }
409 }
410 }
411 dataChannel = null;
412 dataNetworkHandler = null;
413 }
414
415
416
417
418
419
420
421
422 public final boolean initPassiveConnection() throws Reply425Exception {
423 unbindData();
424 if (passiveMode.get()) {
425
426 session.getConfiguration().getFtpInternalConfiguration()
427 .bindPassive(getLocalAddress(), session.isDataSsl());
428 isBind.set(true);
429 return true;
430 }
431
432 return true;
433 }
434
435
436
437
438
439
440
441
442 public final Channel getCurrentDataChannel() throws FtpNoConnectionException {
443 if (dataChannel == null) {
444 throw new FtpNoConnectionException("No Data Connection active");
445 }
446 return dataChannel;
447 }
448
449
450
451
452
453
454 public final synchronized DataNetworkHandler getDataNetworkHandler()
455 throws FtpNoConnectionException {
456 if (dataNetworkHandler == null) {
457 throw new FtpNoConnectionException("No Data Connection active");
458 }
459 return dataNetworkHandler;
460 }
461
462
463
464
465 public final synchronized void setDataNetworkHandler(
466 final DataNetworkHandler dataNetworkHandler) {
467 this.dataNetworkHandler = dataNetworkHandler;
468 }
469
470
471
472
473
474
475 public static int getNewPassivePort(final FtpConfiguration configuration) {
476 synchronized (FtpConfiguration.ftpConfiguration) {
477 int port = -1;
478 for (int i = 0; i < 1000; i++) {
479 port = configuration.getNextRangePort();
480 if (port > 0 && WaarpNettyUtil.availablePort(port)) {
481 return port;
482 }
483 try {
484 Thread.sleep(FtpInternalConfiguration.RETRYINMS);
485 } catch (final InterruptedException e) {
486 SysErrLogger.FAKE_LOGGER.ignoreLog(e);
487 }
488 }
489 return -1;
490 }
491 }
492
493
494
495
496 public final String getStatus() {
497 final StringBuilder builder = new StringBuilder("Data connection: ").append(
498 isActive()? "connected " : "not connected ").append(
499 isBind()? "bind " : "not bind ").append(
500 isPassiveMode()? "passive mode" : "active mode").append('\n').append(
501 "Mode: ").append(transferMode.name()).append(" localPort: ").append(
502 getLocalPort()).append(" remotePort: ").append(getRemotePort()).append(
503 '\n').append("Structure: ").append(transferStructure.name()).append(
504 '\n').append("Type: ").append(transferType.name()).append(' ').append(
505 transferSubType.name());
506 return builder.toString();
507 }
508
509
510
511
512 @Override
513 public String toString() {
514 return getStatus().replace('\n', ' ');
515 }
516
517
518
519
520 public final FtpTransferControl getFtpTransferControl() {
521 return transferControl;
522 }
523
524
525
526
527
528
529
530
531 public final synchronized void setNewOpenedDataChannel(
532 final Channel dataChannel) throws Reply425Exception {
533 this.dataChannel = dataChannel;
534 if (dataChannel == null) {
535 final String curmode;
536 if (isPassiveMode()) {
537 curmode = "passive";
538 } else {
539 curmode = "active";
540 }
541
542 throw new Reply425Exception(
543 "Cannot open " + curmode + " data connection");
544 }
545 isBind.set(true);
546 }
547 }