View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  package org.waarp.ftp.core.config;
21  
22  import io.netty.channel.Channel;
23  import io.netty.handler.traffic.GlobalChannelTrafficShapingHandler;
24  import io.netty.util.AttributeKey;
25  import org.waarp.common.file.FileParameterInterface;
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.WaarpShutdownHook.ShutdownConfiguration;
30  import org.waarp.ftp.core.control.BusinessHandler;
31  import org.waarp.ftp.core.data.handler.DataBusinessHandler;
32  import org.waarp.ftp.core.exception.FtpNoConnectionException;
33  import org.waarp.ftp.core.exception.FtpUnknownFieldException;
34  import org.waarp.ftp.core.session.FtpSession;
35  
36  import java.io.File;
37  import java.net.InetAddress;
38  import java.net.InetSocketAddress;
39  import java.util.HashMap;
40  import java.util.concurrent.locks.ReentrantLock;
41  
42  /**
43   * Abstract class for configuration
44   */
45  public abstract class FtpConfiguration {
46    public static final String FTP_SESSION_ATTRIBUTE_KEY_NAME = "FtpSession";
47    public static final AttributeKey<FtpSession> FTP_SESSION_ATTRIBUTE_KEY =
48        AttributeKey.newInstance(FTP_SESSION_ATTRIBUTE_KEY_NAME);
49    private static final String STOU = ".stou";
50    private static final String PROPERTY_HAS_NO_VALUE = "Property has no value: ";
51    /**
52     * Internal Logger
53     */
54    private static final WaarpLogger logger =
55        WaarpLoggerFactory.getLogger(FtpConfiguration.class);
56    /**
57     * Global Accessor
58     */
59    public static Object ftpConfiguration;
60  
61    // FTP Configuration: Externals
62    /**
63     * Default session limit 64Mbit, so up to 8 full simultaneous clients
64     */
65    static final long DEFAULT_SESSION_LIMIT = 0x800000L;
66  
67    /**
68     * Default global limit 512Mbit
69     */
70    static final long DEFAULT_GLOBAL_LIMIT = 0x4000000L;
71  
72    /**
73     * Nb of milliseconds after pending data transfer is in timeout
74     */
75    private static long dataTimeoutCon = 5000;
76  
77    /**
78     * PASSWORD for SHUTDOWN
79     */
80    private static final String FTP_PASSWORD = "FTP_PASSWORD";//NOSONAR
81  
82    // END OF STATIC VALUES
83    /**
84     * Internal configuration
85     */
86    private final FtpInternalConfiguration internalConfiguration;
87  
88    /**
89     * SERVER PORT
90     */
91    private int serverPort = 21;
92    /**
93     * Default Address if any
94     */
95    private String serverAddress;
96  
97    /**
98     * Base Directory
99     */
100   private String baseDirectory;
101 
102   /**
103    * Associated FileParameterInterface
104    */
105   private final FileParameterInterface fileParameter;
106 
107   /**
108    * True if the service is going to shutdown
109    */
110   private boolean isShutdown;
111 
112   /**
113    * Default number of threads in pool for Server. The default value is for
114    * client for Executor in the Pipeline
115    * for Business logic. Server will change this value on startup if not set.
116    * Default 0 means in proportion of
117    * real core number.
118    */
119   private int serverThread;
120 
121   /**
122    * Default number of threads in pool for Client part.
123    */
124   private int clientThread = 80;
125 
126   /**
127    * Which class owns this configuration
128    */
129   final Class<?> fromClass;
130 
131   /**
132    * Which class will be used for DataBusinessHandler
133    */
134   final Class<? extends DataBusinessHandler> dataBusinessHandler;
135 
136   /**
137    * Which class will be used for BusinessHandler
138    */
139   final Class<? extends BusinessHandler> businessHandler;
140 
141   /**
142    * Internal Lock
143    */
144   private final ReentrantLock lock = new ReentrantLock();
145 
146   /**
147    * Nb of milliseconds after connection is in timeout
148    */
149   private long timeoutCon = 30000;
150 
151   /**
152    * Size by default of block size for receive/sending files. Should be a
153    * multiple of 8192 (maximum = 64K due to
154    * block limitation to 2 bytes)
155    */
156   private int blocksize = 0x10000; // 64K
157 
158   /**
159    * Limit in Write byte/s to apply globally to the FTP Server
160    */
161   protected long serverGlobalWriteLimit = DEFAULT_GLOBAL_LIMIT;
162 
163   /**
164    * Limit in Read byte/s to apply globally to the FTP Server
165    */
166   protected long serverGlobalReadLimit = DEFAULT_GLOBAL_LIMIT;
167 
168   /**
169    * Limit in Write byte/s to apply by session to the FTP Server
170    */
171   protected long serverChannelWriteLimit = DEFAULT_SESSION_LIMIT;
172 
173   /**
174    * Limit in Read byte/s to apply by session to the FTP Server
175    */
176   protected long serverChannelReadLimit = DEFAULT_SESSION_LIMIT;
177 
178   /**
179    * Delay in ms between two checks
180    */
181   protected long delayLimit = 1000;
182 
183   /**
184    * Should the file be deleted when the transfer is aborted on STOR like
185    * commands
186    */
187   private boolean deleteOnAbort;
188 
189   /**
190    * Max global memory limit: default is 1GB
191    */
192   private int maxGlobalMemory = 1073741824;
193 
194   /**
195    * 1 = Active, -1 = Passive, 0 = Both
196    */
197   private int activePassiveMode = 0;
198 
199   /**
200    * General Configuration Object
201    */
202   private final HashMap<String, Object> properties =
203       new HashMap<String, Object>();
204 
205   /**
206    * Use by ShutdownHook
207    */
208   private final ShutdownConfiguration shutdownConfiguration =
209       new ShutdownConfiguration();
210 
211   /**
212    * Simple constructor
213    *
214    * @param classtype Owner
215    * @param businessHandler class that will be used for
216    *     BusinessHandler
217    * @param dataBusinessHandler class that will be used for
218    *     DataBusinessHandler
219    * @param fileParameter the FileParameterInterface to used
220    */
221   protected FtpConfiguration(final Class<?> classtype,
222                              final Class<? extends BusinessHandler> businessHandler,
223                              final Class<? extends DataBusinessHandler> dataBusinessHandler,
224                              final FileParameterInterface fileParameter) {
225     fromClass = classtype;
226     this.dataBusinessHandler = dataBusinessHandler;
227     this.businessHandler = businessHandler;
228     internalConfiguration = new FtpInternalConfiguration(this);
229     this.fileParameter = fileParameter;
230     ftpConfiguration = this;
231   }
232 
233   /**
234    * @param key
235    *
236    * @return The String property associated to the key
237    *
238    * @throws FtpUnknownFieldException
239    */
240   public final String getStringProperty(final String key)
241       throws FtpUnknownFieldException {
242     final String s = (String) properties.get(key);
243     if (s == null) {
244       throw new FtpUnknownFieldException(PROPERTY_HAS_NO_VALUE + key);
245     }
246     return s;
247   }
248 
249   /**
250    * @param key
251    *
252    * @return The Integer property associated to the key
253    *
254    * @throws FtpUnknownFieldException
255    */
256   public final int getIntProperty(final String key)
257       throws FtpUnknownFieldException {
258     final Integer i = (Integer) properties.get(key);
259     if (i == null) {
260       throw new FtpUnknownFieldException(PROPERTY_HAS_NO_VALUE + key);
261     }
262     return i;
263   }
264 
265   /**
266    * @param key
267    *
268    * @return The File associated to the key
269    *
270    * @throws FtpUnknownFieldException
271    */
272   public final File getFileProperty(final String key)
273       throws FtpUnknownFieldException {
274     final File f = (File) properties.get(key);
275     if (f == null) {
276       throw new FtpUnknownFieldException(PROPERTY_HAS_NO_VALUE + key);
277     }
278     return f;
279   }
280 
281   /**
282    * @param key
283    *
284    * @return The Object property associated to the key
285    *
286    * @throws FtpUnknownFieldException
287    */
288   public final Object getProperty(final String key)
289       throws FtpUnknownFieldException {
290     final Object o = properties.get(key);
291     if (o == null) {
292       throw new FtpUnknownFieldException(PROPERTY_HAS_NO_VALUE + key);
293     }
294     return o;
295   }
296 
297   /**
298    * @return the TCP Port to listen in the Ftp Server
299    */
300   public final int getServerPort() {
301     return serverPort;
302   }
303 
304   /**
305    * @return the Address of the Ftp Server if any (may be null)
306    */
307   public final String getServerAddress() {
308     return serverAddress;
309   }
310 
311   /**
312    * @return the limit in Write byte/s to apply globally to the Ftp Server
313    */
314   public final long getServerGlobalWriteLimit() {
315     return serverGlobalWriteLimit;
316   }
317 
318   /**
319    * @return the limit in Write byte/s to apply for each session to the Ftp
320    *     Server
321    */
322   public final long getServerChannelWriteLimit() {
323     return serverChannelWriteLimit;
324   }
325 
326   /**
327    * @return the limit in Read byte/s to apply globally to the Ftp Server
328    */
329   public final long getServerGlobalReadLimit() {
330     return serverGlobalReadLimit;
331   }
332 
333   /**
334    * @return the limit in Read byte/s to apply for each session to the Ftp
335    *     Server
336    */
337   public final long getServerChannelReadLimit() {
338     return serverChannelReadLimit;
339   }
340 
341   /**
342    * @return the delayLimit to apply between two check
343    */
344   public final long getDelayLimit() {
345     return delayLimit;
346   }
347 
348   /**
349    * Check the password for Shutdown
350    *
351    * @param password
352    *
353    * @return True if the password is OK
354    */
355   public boolean checkPassword(final String password) {
356     final String serverpassword;
357     try {
358       serverpassword = getStringProperty(FTP_PASSWORD);
359     } catch (final FtpUnknownFieldException e) {
360       return false;
361     }
362     return serverpassword.equals(password);
363   }
364 
365   /**
366    * Return the next available port for passive connections.
367    *
368    * @return the next available Port for Passive connections
369    */
370   public abstract int getNextRangePort();
371 
372   /**
373    * @return the Base Directory of this Ftp Server
374    */
375   public final String getBaseDirectory() {
376     return baseDirectory;
377   }
378 
379   /**
380    * @param key
381    * @param s
382    */
383   public final void setStringProperty(final String key, final String s) {
384     properties.put(key, s);
385   }
386 
387   /**
388    * @param key
389    * @param i
390    */
391   public final void setIntProperty(final String key, final int i) {
392     properties.put(key, i);
393   }
394 
395   /**
396    * @param key
397    * @param f
398    */
399   public final void setFileProperty(final String key, final File f) {
400     properties.put(key, f);
401   }
402 
403   /**
404    * @param key
405    * @param o
406    */
407   public final void setProperty(final String key, final Object o) {
408     properties.put(key, o);
409   }
410 
411   /**
412    * @param port the new port
413    */
414   public final void setServerPort(final int port) {
415     serverPort = port;
416   }
417 
418   /**
419    * @param address the address to use while answering for address
420    */
421   public final void setServerAddress(final String address) {
422     serverAddress = address;
423   }
424 
425   /**
426    * @param dir the new base directory
427    */
428   public final void setBaseDirectory(final String dir) {
429     baseDirectory = dir;
430   }
431 
432   /**
433    * @param password the new password for shutdown
434    */
435   public final void setPassword(final String password) {
436     setStringProperty(FTP_PASSWORD, password);
437   }
438 
439   /**
440    * @return the dataBusinessHandler
441    */
442   public final Class<? extends DataBusinessHandler> getDataBusinessHandler() {
443     return dataBusinessHandler;
444   }
445 
446   /**
447    * Init internal configuration
448    *
449    * @throws FtpNoConnectionException
450    */
451   public final void serverStartup() throws FtpNoConnectionException {
452     logger.debug("Server Startup");
453     internalConfiguration.serverStartup();
454     logger.debug("Server Startup done");
455   }
456 
457   /**
458    * Reset the global monitor for bandwidth limitation and change future
459    * channel
460    * monitors with values divided by
461    * 10 (channel = global / 10)
462    *
463    * @param writeLimit
464    * @param readLimit
465    */
466   public final void changeNetworkLimit(final long writeLimit,
467                                        final long readLimit) {
468     long newWriteLimit = writeLimit > 1024? writeLimit : serverGlobalWriteLimit;
469     if (writeLimit <= 0) {
470       newWriteLimit = 0;
471     }
472     long newReadLimit = readLimit > 1024? readLimit : serverGlobalReadLimit;
473     if (readLimit <= 0) {
474       newReadLimit = 0;
475     }
476     final FtpGlobalTrafficShapingHandler fgts =
477         internalConfiguration.getGlobalTrafficShapingHandler();
478     fgts.configure(newWriteLimit, newReadLimit);
479     serverChannelReadLimit = newReadLimit / 10;
480     serverChannelWriteLimit = newWriteLimit / 10;
481     if (fgts instanceof GlobalChannelTrafficShapingHandler) {
482       fgts.configureChannel(serverChannelWriteLimit, serverChannelReadLimit);
483     }
484   }
485 
486   /**
487    * Compute number of threads for both client and server from the real number
488    * of available processors (double +
489    * 1) if the value is less than 64 threads.
490    */
491   public final void computeNbThreads() {
492     int nb = Runtime.getRuntime().availableProcessors() * 2 + 1;
493     if (nb > 32) {
494       nb = Runtime.getRuntime().availableProcessors() + 1;
495     }
496     if (getServerThread() < nb) {
497       setServerThread(nb);
498       setClientThread(getServerThread() * 10);
499     } else if (getClientThread() < nb) {
500       setClientThread(nb * 10);
501     }
502   }
503 
504   /**
505    * In bind/unbind operation, lock
506    */
507   public final void bindLock() {
508     lock.lock();
509   }
510 
511   /**
512    * In bind/unbind operation, unlock
513    */
514   public final void bindUnlock() {
515     lock.unlock();
516   }
517 
518   /**
519    * @return the FtpInternalConfiguration
520    */
521   public final FtpInternalConfiguration getFtpInternalConfiguration() {
522     return internalConfiguration;
523   }
524 
525   /**
526    * Add a session from a couple of addresses
527    *
528    * @param ipOnly
529    * @param fullIp
530    * @param session
531    */
532   public final void setNewFtpSession(final InetAddress ipOnly,
533                                      final InetSocketAddress fullIp,
534                                      final FtpSession session) {
535     internalConfiguration.setNewFtpSession(ipOnly, fullIp, session);
536   }
537 
538   /**
539    * Return and remove the FtpSession
540    *
541    * @param channel
542    * @param active
543    *
544    * @return the FtpSession if it exists associated to this channel
545    */
546   public final FtpSession getFtpSession(final Channel channel,
547                                         final boolean active) {
548     FtpSession session = null;
549     for (int i = 0; i < FtpInternalConfiguration.RETRYNB * 2; i++) {
550       if (active) {
551         session = channel.attr(FTP_SESSION_ATTRIBUTE_KEY).get();
552         if (session != null) {
553           return session;
554         }
555         try {
556           Thread.sleep(FtpInternalConfiguration.RETRYINMS * 10);
557         } catch (final InterruptedException e1) {//NOSONAR
558           SysErrLogger.FAKE_LOGGER.ignoreLog(e1);
559         }
560       } else {
561         session = internalConfiguration.getFtpSession(channel);
562         if (session == null) {
563           logger.debug("Session not found at try " + i);
564           try {
565             Thread.sleep(FtpInternalConfiguration.RETRYINMS * 10);
566           } catch (final InterruptedException e1) {//NOSONAR
567             SysErrLogger.FAKE_LOGGER.ignoreLog(e1);
568           }
569         } else {
570           return session;
571         }
572       }
573     }
574     if (session == null) {
575       if (active) {
576         session = channel.attr(FTP_SESSION_ATTRIBUTE_KEY).get();
577         if (session != null) {
578           return session;
579         }
580       } else {
581         // Last try using all current sessions
582         session = internalConfiguration.findPassiveFtpSession(channel);
583         if (session != null) {
584           logger.debug("Found from port Passive? {}", channel.localAddress());
585           return session;
586         }
587       }
588     }
589     if (session == null) {
590       logger.error("Could not find {} session for {}",
591                    active? "Active" : "Passive", channel);
592     }
593     return session;
594   }
595 
596   /**
597    * Remove the FtpSession
598    *
599    * @param ipOnly
600    * @param fullIp
601    */
602   public final void delFtpSession(final InetAddress ipOnly,
603                                   final InetSocketAddress fullIp) {
604     internalConfiguration.delFtpSession(ipOnly, fullIp);
605   }
606 
607   /**
608    * @return the fileParameter
609    */
610   public final FileParameterInterface getFileParameter() {
611     return fileParameter;
612   }
613 
614   public final String getUniqueExtension() {
615     // Can be overridden if necessary
616     return STOU;
617   }
618 
619   /**
620    * To use if any external resources are to be released when shutting down
621    */
622   public void releaseResources() {
623     internalConfiguration.releaseResources();
624   }
625 
626   /**
627    * Shutdown process is on going
628    */
629   public abstract void inShutdownProcess();
630 
631   /**
632    * @return the isShutdown
633    */
634   public final boolean isShutdown() {
635     return isShutdown;
636   }
637 
638   /**
639    * @param isShutdown the isShutdown to set
640    */
641   public final void setShutdown(final boolean isShutdown) {
642     this.isShutdown = isShutdown;
643   }
644 
645   /**
646    * @return the sERVER_THREAD
647    */
648   public final int getServerThread() {
649     return serverThread;
650   }
651 
652   /**
653    * @param serverThread0 the sERVER_THREAD to set
654    */
655   public final void setServerThread(final int serverThread0) {
656     serverThread = serverThread0;
657   }
658 
659   /**
660    * @return the cLIENT_THREAD
661    */
662   public final int getClientThread() {
663     return clientThread;
664   }
665 
666   /**
667    * @param clientThread0 the cLIENT_THREAD to set
668    */
669   public final void setClientThread(final int clientThread0) {
670     clientThread = clientThread0;
671   }
672 
673   /**
674    * @return the tIMEOUTCON
675    */
676   public final long getTimeoutCon() {
677     return timeoutCon;
678   }
679 
680   /**
681    * @param tIMEOUTCON the tIMEOUTCON to set
682    */
683   public final void setTimeoutCon(final long tIMEOUTCON) {
684     timeoutCon = tIMEOUTCON;
685   }
686 
687   /**
688    * @return the bLOCKSIZE
689    */
690   public final int getBlocksize() {
691     return blocksize;
692   }
693 
694   /**
695    * @param bLOCKSIZE the bLOCKSIZE to set
696    */
697   public final void setBlocksize(final int bLOCKSIZE) {
698     blocksize = bLOCKSIZE;
699   }
700 
701   /**
702    * @return the deleteOnAbort
703    */
704   public final boolean isDeleteOnAbort() {
705     return deleteOnAbort;
706   }
707 
708   /**
709    * @param deleteOnAbort the deleteOnAbort to set
710    */
711   public final void setDeleteOnAbort(final boolean deleteOnAbort) {
712     this.deleteOnAbort = deleteOnAbort;
713   }
714 
715   /**
716    * @return the dATATIMEOUTCON
717    */
718   public static long getDataTimeoutCon() {
719     return dataTimeoutCon;
720   }
721 
722   /**
723    * @param dATATIMEOUTCON the dATATIMEOUTCON to set
724    */
725   public static void setDataTimeoutCon(final long dATATIMEOUTCON) {
726     dataTimeoutCon = dATATIMEOUTCON;
727   }
728 
729   /**
730    * @return the active (1) or passive (-1) or both (0) mode
731    */
732   public final int getActivePassiveMode() {
733     return activePassiveMode;
734   }
735 
736   /**
737    * @param activePassiveModeArg the mode to set (1 = Active, -1 = Passive, 0 = Both - default -)
738    */
739   public final void setActivePassiveMode(final int activePassiveModeArg) {
740     activePassiveMode =
741         activePassiveModeArg < 0? -1 : (activePassiveModeArg > 0? 1 : 0);
742   }
743 
744   /**
745    * @return the maxGlobalMemory
746    */
747   public final int getMaxGlobalMemory() {
748     return maxGlobalMemory;
749   }
750 
751   /**
752    * @param maxGlobalMemory the maxGlobalMemory to set
753    */
754   public final void setMaxGlobalMemory(final int maxGlobalMemory) {
755     this.maxGlobalMemory = maxGlobalMemory;
756   }
757 
758   /**
759    * @return the shutdownConfiguration
760    */
761   public final ShutdownConfiguration getShutdownConfiguration() {
762     return shutdownConfiguration;
763   }
764 }