View Javadoc

1   /**
2    * This file is part of Waarp Project.
3    * 
4    * Copyright 2009, Frederic Bregier, and individual contributors by the @author tags. See the
5    * COPYRIGHT.txt in the distribution for a full listing of individual contributors.
6    * 
7    * All Waarp Project is free software: you can redistribute it and/or modify it under the terms of
8    * the GNU General Public License as published by the Free Software Foundation, either version 3 of
9    * the License, or (at your option) any later version.
10   * 
11   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
12   * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13   * Public License for more details.
14   * 
15   * You should have received a copy of the GNU General Public License along with Waarp . If not, see
16   * <http://www.gnu.org/licenses/>.
17   */
18  package org.waarp.ftp.core.utils;
19  
20  import java.net.Inet4Address;
21  import java.net.Inet6Address;
22  import java.net.InetAddress;
23  import java.net.InetSocketAddress;
24  import java.net.UnknownHostException;
25  import java.util.Iterator;
26  import java.util.Timer;
27  
28  import io.netty.channel.Channel;
29  
30  import org.slf4j.LoggerFactory;
31  import org.waarp.common.crypto.ssl.WaarpSslUtility;
32  import org.waarp.common.logging.WaarpLogger;
33  import org.waarp.common.logging.WaarpLoggerFactory;
34  import org.waarp.common.logging.WaarpSlf4JLoggerFactory;
35  import org.waarp.ftp.core.config.FtpConfiguration;
36  
37  import ch.qos.logback.classic.LoggerContext;
38  
39  /**
40   * Some useful functions related to Channel of Netty
41   * 
42   * @author Frederic Bregier
43   * 
44   */
45  public class FtpChannelUtils implements Runnable {
46      /**
47       * Internal Logger
48       */
49      private static final WaarpLogger logger = WaarpLoggerFactory
50              .getLogger(FtpChannelUtils.class);
51  
52      /**
53       * Get the Remote InetAddress
54       * 
55       * @param channel
56       * @return the remote InetAddress
57       */
58      public static InetAddress getRemoteInetAddress(Channel channel) {
59          InetSocketAddress socketAddress = (InetSocketAddress) channel.remoteAddress();
60          if (socketAddress == null) {
61              socketAddress = new InetSocketAddress(20);
62          }
63          return socketAddress.getAddress();
64      }
65  
66      /**
67       * Get the Local InetAddress
68       * 
69       * @param channel
70       * @return the local InetAddress
71       */
72      public static InetAddress getLocalInetAddress(Channel channel) {
73          InetSocketAddress socketAddress = (InetSocketAddress) channel.localAddress();
74          return socketAddress.getAddress();
75      }
76  
77      /**
78       * Get the Remote InetSocketAddress
79       * 
80       * @param channel
81       * @return the remote InetSocketAddress
82       */
83      public static InetSocketAddress getRemoteInetSocketAddress(Channel channel) {
84          return (InetSocketAddress) channel.remoteAddress();
85      }
86  
87      /**
88       * Get the Local InetSocketAddress
89       * 
90       * @param channel
91       * @return the local InetSocketAddress
92       */
93      public static InetSocketAddress getLocalInetSocketAddress(Channel channel) {
94          return (InetSocketAddress) channel.localAddress();
95      }
96  
97      /**
98       * Get the InetSocketAddress corresponding to the FTP format of address
99       * 
100      * @param arg
101      * @return the InetSocketAddress or null if an error occurs
102      */
103     public static InetSocketAddress getInetSocketAddress(String arg) {
104         String[] elements = arg.split(",");
105         if (elements.length != 6) {
106             return null;
107         }
108         byte[] address = new byte[4];
109         int[] iElements = new int[6];
110         for (int i = 0; i < 6; i++) {
111             try {
112                 iElements[i] = Integer.parseInt(elements[i]);
113             } catch (NumberFormatException e) {
114                 return null;
115             }
116             if (iElements[i] < 0 || iElements[i] > 255) {
117                 return null;
118             }
119         }
120         for (int i = 0; i < 4; i++) {
121             address[i] = (byte) iElements[i];
122         }
123         int port = iElements[4] << 8 | iElements[5];
124         InetAddress inetAddress;
125         try {
126             inetAddress = InetAddress.getByAddress(address);
127         } catch (UnknownHostException e) {
128             return null;
129         }
130         return new InetSocketAddress(inetAddress, port);
131     }
132 
133     /**
134      * Return the Address in the format compatible with FTP argument
135      * 
136      * @param address
137      * @param port
138      * @return the String representation of the address
139      */
140     public static String getAddress(String address, int port) {
141         return address.replace('.', ',') + ',' +
142                 (port >> 8) + ',' + (port & 0xFF);
143     }
144 
145     /**
146      * Return the Address in the format compatible with FTP argument
147      * 
148      * @param address
149      * @return the String representation of the address
150      */
151     public static String getAddress(InetSocketAddress address) {
152         InetAddress servAddr = address.getAddress();
153         int servPort = address.getPort();
154         return servAddr.getHostAddress().replace('.', ',') + ',' +
155                 (servPort >> 8) + ',' + (servPort & 0xFF);
156     }
157 
158     /**
159      * Get the (RFC2428) InetSocketAddress corresponding to the FTP format of address (RFC2428)
160      * 
161      * @param arg
162      * @return the InetSocketAddress or null if an error occurs
163      */
164     public static InetSocketAddress get2428InetSocketAddress(String arg) {
165         // Format: #a#net-addr#tcp-port# where a = 1 IPV4 or 2 IPV6, other will
166         // not be supported
167         if (arg == null || arg.length() == 0) {
168             // bad args
169             return null;
170         }
171         String delim = arg.substring(0, 1);
172         String[] infos = arg.split("\\" + delim);
173         if (infos.length != 3 && infos.length != 4) {
174             // bad format
175             logger.error("Bad address format: " + infos.length);
176             return null;
177         }
178         int start = 0;
179         if (infos.length == 4) {
180             start = 1;
181         }
182         boolean isIPV4 = true;
183         if (infos[start].equals("1")) {
184             isIPV4 = true;
185         } else if (infos[start].equals("2")) {
186             isIPV4 = false;
187         } else {
188             // not supported
189             logger.error("Bad 1 or 2 format in address: " + infos[start]);
190             return null;
191         }
192         start++;
193         InetAddress inetAddress;
194         if (isIPV4) {
195             // IPV4
196             try {
197                 inetAddress = (Inet4Address) InetAddress.getByName(infos[start]);
198             } catch (UnknownHostException e) {
199                 logger.error("Bad IPV4 format", e);
200                 return null;
201             }
202         } else {
203             // IPV6
204             try {
205                 inetAddress = (Inet6Address) InetAddress.getByName(infos[start]);
206             } catch (UnknownHostException e) {
207                 logger.error("Bad IPV6 format", e);
208                 return null;
209             }
210         }
211         start++;
212         int port = 0;
213         try {
214             port = Integer.parseInt(infos[start]);
215         } catch (NumberFormatException e) {
216             logger.error("Bad port number format: " + infos[start]);
217             return null;
218         }
219         return new InetSocketAddress(inetAddress, port);
220     }
221 
222     /**
223      * Return the (RFC2428) Address in the format compatible with FTP (RFC2428)
224      * 
225      * @param address
226      * @return the String representation of the address
227      */
228     public static String get2428Address(InetSocketAddress address) {
229         InetAddress servAddr = address.getAddress();
230         int servPort = address.getPort();
231         StringBuilder builder = new StringBuilder();
232         String hostaddress = servAddr.getHostAddress();
233         builder.append('|');
234         if (hostaddress.contains(":")) {
235             builder.append('2'); // IPV6
236         } else {
237             builder.append('1'); // IPV4
238         }
239         builder.append('|').append(hostaddress).append('|').append(servPort).append('|');
240         return builder.toString();
241     }
242 
243     /**
244      * Terminate all registered command channels
245      * 
246      * @param configuration
247      * @return the number of previously registered command channels
248      */
249     static int terminateCommandChannels(final FtpConfiguration configuration) {
250         int result = configuration.getFtpInternalConfiguration()
251                 .getCommandChannelGroup().size();
252         configuration.getFtpInternalConfiguration().getCommandChannelGroup()
253                 .close();
254         return result;
255     }
256 
257     /**
258      * Terminate all registered data channels
259      * 
260      * @param configuration
261      * @return the number of previously registered data channels
262      */
263     private static int terminateDataChannels(final FtpConfiguration configuration) {
264         int result = configuration.getFtpInternalConfiguration()
265                 .getDataChannelGroup().size();
266         configuration.getFtpInternalConfiguration().getDataChannelGroup()
267                 .close();
268         return result;
269     }
270 
271     /**
272      * Return the current number of command connections
273      * 
274      * @param configuration
275      * @return the current number of command connections
276      */
277     public static int nbCommandChannels(FtpConfiguration configuration) {
278         return configuration.getFtpInternalConfiguration()
279                 .getCommandChannelGroup().size();
280     }
281 
282     /**
283      * Return the current number of data connections
284      * 
285      * @param configuration
286      * @return the current number of data connections
287      */
288     public static int nbDataChannels(FtpConfiguration configuration) {
289         return configuration.getFtpInternalConfiguration()
290                 .getDataChannelGroup().size();
291     }
292 
293     /**
294      * Return the number of still positive command connections
295      * 
296      * @param configuration
297      * @return the number of positive command connections
298      */
299     public static int validCommandChannels(FtpConfiguration configuration) {
300         int result = 0;
301         Channel channel = null;
302         Iterator<Channel> iterator = configuration
303                 .getFtpInternalConfiguration().getCommandChannelGroup()
304                 .iterator();
305         while (iterator.hasNext()) {
306             channel = iterator.next();
307             if (channel.parent() != null) {
308                 // Child Channel
309                 if (channel.isActive()) {
310                     // Normal channel
311                     result++;
312                 } else {
313                     WaarpSslUtility.closingSslChannel(channel);
314                 }
315             } else {
316                 // Parent channel
317                 result++;
318             }
319         }
320         return result;
321     }
322 
323     /**
324      * Exit global ChannelFactory
325      * 
326      * @param configuration
327      */
328     protected static void exit(FtpConfiguration configuration) {
329         configuration.setShutdown(true);
330         long delay = configuration.getTIMEOUTCON() / 2;
331         logger.warn("Exit: Give a delay of " + delay + " ms");
332         configuration.inShutdownProcess();
333         try {
334             Thread.sleep(delay);
335         } catch (InterruptedException e) {
336         }
337         Timer timer = new Timer(true);
338         FtpTimerTask timerTask = new FtpTimerTask(FtpTimerTask.TIMER_CONTROL);
339         timerTask.setConfiguration(configuration);
340         timer.schedule(timerTask, configuration.getTIMEOUTCON() / 4);
341         configuration.getFtpInternalConfiguration()
342                 .getGlobalTrafficShapingHandler().release();
343         configuration.releaseResources();
344         logger.info("Exit Shutdown Data");
345         terminateDataChannels(configuration);
346         logger.warn("Exit end of Data Shutdown");
347     }
348 
349     /**
350      * This function is the top function to be called when the server is to be shutdown.
351      * 
352      * @param configuration
353      */
354     public static void teminateServer(FtpConfiguration configuration) {
355         FtpShutdownHook.configuration = configuration;
356         FtpShutdownHook.terminate(false);
357     }
358 
359     /**
360      * Add a command channel into the list
361      * 
362      * @param channel
363      * @param configuration
364      */
365     public static void addCommandChannel(Channel channel,
366             FtpConfiguration configuration) {
367         // logger.debug("Add Command Channel {}", channel);
368         configuration.getFtpInternalConfiguration().getCommandChannelGroup()
369                 .add(channel);
370     }
371 
372     /**
373      * Add a data channel into the list
374      * 
375      * @param channel
376      * @param configuration
377      */
378     public static void addDataChannel(Channel channel,
379             FtpConfiguration configuration) {
380         // logger.debug("Add Data Channel {}", channel);
381         configuration.getFtpInternalConfiguration().getDataChannelGroup().add(
382                 channel);
383     }
384 
385     /**
386      * Used to run Exit command
387      */
388     private FtpConfiguration configuration;
389 
390     public FtpChannelUtils(FtpConfiguration configuration) {
391         this.configuration = configuration;
392     }
393 
394     @Override
395     public void run() {
396         exit(configuration);
397     }
398 
399     public static void stopLogger() {
400         if (WaarpLoggerFactory.getDefaultFactory() instanceof WaarpSlf4JLoggerFactory) {
401             LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
402             lc.stop();
403         }
404     }
405 
406 }