1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.waarp.ftp.core.config;
19
20 import java.net.InetAddress;
21 import java.net.InetSocketAddress;
22 import java.util.concurrent.ConcurrentHashMap;
23 import java.util.concurrent.ExecutorService;
24 import java.util.concurrent.Executors;
25 import java.util.concurrent.ScheduledExecutorService;
26
27 import io.netty.bootstrap.Bootstrap;
28 import io.netty.bootstrap.ServerBootstrap;
29 import io.netty.channel.Channel;
30 import io.netty.channel.ChannelException;
31 import io.netty.channel.ChannelFuture;
32 import io.netty.channel.EventLoopGroup;
33 import io.netty.channel.group.ChannelGroup;
34 import io.netty.channel.group.DefaultChannelGroup;
35 import io.netty.channel.nio.NioEventLoopGroup;
36 import io.netty.handler.traffic.ChannelTrafficShapingHandler;
37 import io.netty.handler.traffic.GlobalChannelTrafficShapingHandler;
38 import io.netty.util.concurrent.EventExecutorGroup;
39
40 import org.waarp.common.command.exception.Reply425Exception;
41 import org.waarp.common.crypto.ssl.WaarpSslUtility;
42 import org.waarp.common.logging.WaarpLogger;
43 import org.waarp.common.logging.WaarpLoggerFactory;
44 import org.waarp.common.utility.DetectionUtils;
45 import org.waarp.common.utility.WaarpNettyUtil;
46 import org.waarp.common.utility.WaarpThreadFactory;
47 import org.waarp.ftp.core.control.FtpInitializer;
48 import org.waarp.ftp.core.control.ftps.FtpsInitializer;
49 import org.waarp.ftp.core.data.handler.FtpDataInitializer;
50 import org.waarp.ftp.core.data.handler.ftps.FtpsDataInitializer;
51 import org.waarp.ftp.core.exception.FtpNoConnectionException;
52 import org.waarp.ftp.core.session.FtpSession;
53 import org.waarp.ftp.core.session.FtpSessionReference;
54 import org.waarp.ftp.core.utils.FtpChannelUtils;
55 import org.waarp.ftp.core.utils.FtpShutdownHook;
56
57
58
59
60
61
62
63 public class FtpInternalConfiguration {
64
65
66
67
68 private static final WaarpLogger logger = WaarpLoggerFactory.getLogger(FtpInternalConfiguration.class);
69
70
71
72
73
74 public static final long RETRYINMS = 10;
75
76
77
78
79 public static final int RETRYNB = 3;
80
81
82
83
84 public static final long WAITFORNETOP = 1000;
85
86
87
88 static Boolean ISUNIX = null;
89
90
91
92
93 public static final int BUFFERSIZEDEFAULT = 0x10000;
94
95
96
97
98
99 private ChannelGroup commandChannelGroup = null;
100
101
102
103
104 private final EventLoopGroup execBoss;
105
106
107
108
109 private final EventLoopGroup execWorker;
110
111
112
113
114 private ServerBootstrap serverBootstrap = null;
115
116
117
118
119 private ChannelGroup dataChannelGroup = null;
120
121
122
123
124 private final EventLoopGroup execPassiveDataBoss;
125
126
127
128
129 private final EventLoopGroup execCommandEvent;
130
131
132
133
134 private final EventLoopGroup execDataEvent;
135
136
137
138
139 private final EventLoopGroup execDataWorker;
140
141
142
143
144 private final FtpSessionReference ftpSessionReference = new FtpSessionReference();
145
146
147
148
149 private Bootstrap activeBootstrap = null;
150
151
152
153
154 private ServerBootstrap passiveBootstrap = null;
155
156
157
158
159 private ScheduledExecutorService executorService =
160 Executors.newScheduledThreadPool(2, new WaarpThreadFactory("TimerTrafficFtp"));
161
162
163
164
165 private FtpGlobalTrafficShapingHandler globalTrafficShapingHandler = null;
166
167
168
169
170 private boolean usingNativeSsl = false;
171
172
173
174
175 private boolean acceptAuthProt = false;
176
177
178
179 private Bootstrap activeSslBootstrap = null;
180
181
182
183
184 private ServerBootstrap passiveSslBootstrap = null;
185
186
187
188
189
190
191 public static class BindAddress {
192
193
194
195 public final Channel parent;
196
197
198
199
200 volatile public int nbBind = 0;
201
202
203
204
205
206
207 public BindAddress(Channel channel) {
208 parent = channel;
209 nbBind = 0;
210 }
211 }
212
213
214
215
216 private final ConcurrentHashMap<InetSocketAddress, BindAddress> hashBindPassiveDataConn =
217 new ConcurrentHashMap<InetSocketAddress, BindAddress>();
218
219
220
221
222 private final FtpConfiguration configuration;
223
224
225
226
227
228
229 public FtpInternalConfiguration(FtpConfiguration configuration) {
230 this.configuration = configuration;
231 ISUNIX = !DetectionUtils.isWindows();
232 configuration.getShutdownConfiguration().timeout = configuration.getTIMEOUTCON();
233 new FtpShutdownHook(configuration.getShutdownConfiguration(), configuration);
234 execCommandEvent = new NioEventLoopGroup(configuration.getCLIENT_THREAD(), new WaarpThreadFactory("Command"));
235 execDataEvent = new NioEventLoopGroup(configuration.getCLIENT_THREAD(), new WaarpThreadFactory("Data"));
236 execBoss = new NioEventLoopGroup(configuration.getSERVER_THREAD(), new WaarpThreadFactory("CommandBoss", false));
237 execWorker = new NioEventLoopGroup(configuration.getCLIENT_THREAD(), new WaarpThreadFactory("CommandWorker"));
238 execPassiveDataBoss = new NioEventLoopGroup(configuration.getSERVER_THREAD() * 2, new WaarpThreadFactory(
239 "PassiveDataBoss"));
240 execDataWorker = new NioEventLoopGroup(configuration.getCLIENT_THREAD() * 2, new WaarpThreadFactory("DataWorker"));
241 }
242
243
244
245
246
247
248
249 public void serverStartup() throws FtpNoConnectionException {
250 WaarpLoggerFactory.setDefaultFactory(WaarpLoggerFactory
251 .getDefaultFactory());
252
253 commandChannelGroup = new DefaultChannelGroup(configuration.fromClass.getName(), execWorker.next());
254
255 dataChannelGroup = new DefaultChannelGroup(configuration.fromClass.getName() + ".data", execWorker.next());
256
257
258 passiveBootstrap = new ServerBootstrap();
259 WaarpNettyUtil.setServerBootstrap(passiveBootstrap, execPassiveDataBoss, execDataWorker,
260 (int) configuration.getTIMEOUTCON());
261 if (usingNativeSsl) {
262 passiveBootstrap.childHandler(new FtpsDataInitializer(
263 configuration.dataBusinessHandler, configuration, false));
264 } else {
265 passiveBootstrap.childHandler(new FtpDataInitializer(
266 configuration.dataBusinessHandler, configuration, false));
267 }
268 if (acceptAuthProt) {
269 passiveSslBootstrap = new ServerBootstrap();
270 WaarpNettyUtil.setServerBootstrap(passiveSslBootstrap, execPassiveDataBoss, execDataWorker,
271 (int) configuration.getTIMEOUTCON());
272 passiveSslBootstrap.childHandler(new FtpsDataInitializer(
273 configuration.dataBusinessHandler, configuration, false));
274 } else {
275 passiveSslBootstrap = passiveBootstrap;
276 }
277
278
279 activeBootstrap = new Bootstrap();
280 WaarpNettyUtil.setBootstrap(activeBootstrap, execDataWorker, (int) configuration.getTIMEOUTCON());
281 if (usingNativeSsl) {
282 activeBootstrap.handler(new FtpsDataInitializer(
283 configuration.dataBusinessHandler, configuration, true));
284 } else {
285 activeBootstrap.handler(new FtpDataInitializer(
286 configuration.dataBusinessHandler, configuration, true));
287 }
288 if (acceptAuthProt) {
289 activeSslBootstrap = new Bootstrap();
290 WaarpNettyUtil.setBootstrap(activeSslBootstrap, execDataWorker, (int) configuration.getTIMEOUTCON());
291 activeSslBootstrap.handler(new FtpsDataInitializer(
292 configuration.dataBusinessHandler, configuration, true));
293 } else {
294 activeSslBootstrap = activeBootstrap;
295 }
296
297
298 serverBootstrap = new ServerBootstrap();
299 WaarpNettyUtil.setServerBootstrap(serverBootstrap, execBoss, execWorker, (int) configuration.getTIMEOUTCON());
300 if (usingNativeSsl) {
301 serverBootstrap.childHandler(new FtpsInitializer(
302 configuration.businessHandler, configuration));
303 } else {
304 serverBootstrap.childHandler(new FtpInitializer(
305 configuration.businessHandler, configuration));
306 }
307
308 try {
309 FtpChannelUtils.addCommandChannel(serverBootstrap.bind(
310 new InetSocketAddress(configuration.getServerPort())).sync().channel(),
311 configuration);
312 } catch (InterruptedException e) {
313 throw new FtpNoConnectionException("Can't initiate the FTP server", e);
314 }
315
316
317 configuration.getShutdownConfiguration().timeout = configuration.getTIMEOUTCON();
318 FtpShutdownHook.addShutdownHook();
319
320 globalTrafficShapingHandler = new FtpGlobalTrafficShapingHandler(executorService,
321 configuration.getServerGlobalWriteLimit(),
322 configuration.getServerGlobalReadLimit(),
323 configuration.getServerChannelWriteLimit(),
324 configuration.getServerChannelReadLimit(),
325 configuration.getDelayLimit());
326 }
327
328
329
330
331
332 public ExecutorService getWorker() {
333 return execWorker;
334 }
335
336
337
338
339
340
341
342
343 public void setNewFtpSession(InetAddress ipOnly, InetSocketAddress fullIp,
344 FtpSession session) {
345 ftpSessionReference.setNewFtpSession(ipOnly, fullIp, session);
346 }
347
348
349
350
351
352
353
354
355 public FtpSession getFtpSession(Channel channel, boolean active, boolean remove) {
356 if (active) {
357 return ftpSessionReference.getActiveFtpSession(channel, remove);
358 } else {
359 return ftpSessionReference.getPassiveFtpSession(channel, remove);
360 }
361 }
362
363
364
365
366
367
368
369 public void delFtpSession(InetAddress ipOnly, InetSocketAddress fullIp) {
370 ftpSessionReference.delFtpSession(ipOnly, fullIp);
371 }
372
373
374
375
376
377
378
379
380 public boolean hasFtpSession(InetAddress ipOnly, InetSocketAddress fullIp) {
381 return ftpSessionReference.contains(ipOnly, fullIp);
382 }
383
384
385
386
387
388 public int getNumberSessions() {
389 return ftpSessionReference.sessionsNumber();
390 }
391
392
393
394
395
396
397
398
399
400 public void bindPassive(InetSocketAddress address, boolean ssl) throws Reply425Exception {
401 configuration.bindLock();
402 try {
403 BindAddress bindAddress = hashBindPassiveDataConn.get(address);
404 if (bindAddress == null) {
405 logger.debug("Bind really to {}", address);
406 Channel parentChannel = null;
407 try {
408 ChannelFuture future = null;
409 if (ssl) {
410 future = passiveSslBootstrap.bind(address);
411 } else {
412 future = passiveBootstrap.bind(address);
413 }
414 if (future.await(configuration.getTIMEOUTCON())) {
415 parentChannel = future.sync().channel();
416 } else {
417 logger.warn("Cannot open passive connection due to Timeout");
418 throw new Reply425Exception(
419 "Cannot open a Passive Connection due to Timeout");
420 }
421 } catch (ChannelException e) {
422 logger.warn("Cannot open passive connection {}", e
423 .getMessage());
424 throw new Reply425Exception(
425 "Cannot open a Passive Connection");
426 } catch (InterruptedException e) {
427 logger.warn("Cannot open passive connection {}", e
428 .getMessage());
429 throw new Reply425Exception(
430 "Cannot open a Passive Connection");
431 }
432 bindAddress = new BindAddress(parentChannel);
433 FtpChannelUtils.addDataChannel(parentChannel, configuration);
434 hashBindPassiveDataConn.put(address, bindAddress);
435 }
436 bindAddress.nbBind++;
437 logger.debug("Bind number to {} is {}", address, bindAddress.nbBind);
438 } finally {
439 configuration.bindUnlock();
440 }
441 }
442
443
444
445
446
447
448
449
450 public void unbindPassive(InetSocketAddress address) {
451 configuration.bindLock();
452 try {
453 BindAddress bindAddress = hashBindPassiveDataConn.get(address);
454 if (bindAddress != null) {
455 bindAddress.nbBind--;
456 logger.debug("Bind number to {} left is {}", address, bindAddress.nbBind);
457 if (bindAddress.nbBind == 0) {
458 WaarpSslUtility.closingSslChannel(bindAddress.parent);
459 hashBindPassiveDataConn.remove(address);
460 }
461 } else {
462 logger.warn("No Bind to {}", address);
463 }
464 } finally {
465 configuration.bindUnlock();
466 }
467 }
468
469
470
471
472
473 public int getNbBindedPassive() {
474 return hashBindPassiveDataConn.size();
475 }
476
477
478
479
480
481
482 public EventExecutorGroup getExecutor() {
483 return execCommandEvent;
484 }
485
486
487
488
489
490
491 public EventExecutorGroup getDataExecutor() {
492 return execDataEvent;
493 }
494
495
496
497
498
499 public Bootstrap getActiveBootstrap(boolean ssl) {
500 if (ssl) {
501 return activeSslBootstrap;
502 } else {
503 return activeBootstrap;
504 }
505 }
506
507
508
509
510 public ChannelGroup getCommandChannelGroup() {
511 return commandChannelGroup;
512 }
513
514
515
516
517 public ChannelGroup getDataChannelGroup() {
518 return dataChannelGroup;
519 }
520
521
522
523
524
525 public FtpGlobalTrafficShapingHandler getGlobalTrafficShapingHandler() {
526 return globalTrafficShapingHandler;
527 }
528
529
530
531
532
533 public ChannelTrafficShapingHandler newChannelTrafficShapingHandler() {
534 if (configuration.getServerChannelWriteLimit() == 0 &&
535 configuration.getServerChannelReadLimit() == 0) {
536 return null;
537 }
538 if (globalTrafficShapingHandler instanceof GlobalChannelTrafficShapingHandler) {
539 return null;
540 }
541 return new FtpChannelTrafficShapingHandler(
542 configuration.getServerChannelWriteLimit(),
543 configuration.getServerChannelReadLimit(),
544 configuration.getDelayLimit());
545 }
546
547 public void releaseResources() {
548 WaarpSslUtility.forceCloseAllSslChannels();
549 execBoss.shutdownGracefully();
550 execWorker.shutdownGracefully();
551 execPassiveDataBoss.shutdownGracefully();
552 execDataWorker.shutdownGracefully();
553
554
555 globalTrafficShapingHandler.release();
556 executorService.shutdown();
557 }
558
559 public boolean isAcceptAuthProt() {
560 return acceptAuthProt;
561 }
562
563
564
565
566 public boolean isUsingNativeSsl() {
567 return usingNativeSsl;
568 }
569
570
571
572
573
574 public void setUsingNativeSsl(boolean usingNativeSsl) {
575 this.usingNativeSsl = usingNativeSsl;
576 }
577
578
579
580
581
582 public void setAcceptAuthProt(boolean acceptAuthProt) {
583 this.acceptAuthProt = acceptAuthProt;
584 }
585
586 }