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.command.parameter;
21  
22  import org.waarp.common.command.ReplyCode;
23  import org.waarp.common.command.exception.Reply425Exception;
24  import org.waarp.common.command.exception.Reply501Exception;
25  import org.waarp.common.logging.WaarpLogger;
26  import org.waarp.common.logging.WaarpLoggerFactory;
27  import org.waarp.ftp.core.command.AbstractCommand;
28  import org.waarp.ftp.core.config.FtpConfiguration;
29  import org.waarp.ftp.core.config.FtpInternalConfiguration;
30  import org.waarp.ftp.core.data.FtpDataAsyncConn;
31  import org.waarp.ftp.core.utils.FtpChannelUtils;
32  
33  import java.net.InetAddress;
34  import java.net.InetSocketAddress;
35  
36  /**
37   * PASV command
38   */
39  public class PASV extends AbstractCommand {
40    /**
41     * Internal Logger
42     */
43    private static final WaarpLogger logger =
44        WaarpLoggerFactory.getLogger(PASV.class);
45  
46    @Override
47    public final void exec() throws Reply425Exception, Reply501Exception {
48      // Check if Passive mode is OK
49      if (((FtpConfiguration) (FtpConfiguration.ftpConfiguration)).getActivePassiveMode() >
50          0) {
51        // Active only
52        throw new Reply501Exception("Passive mode not allowed");
53      }
54      // First Check if any argument
55      if (hasArg()) {
56        throw new Reply501Exception("No argument allowed");
57      }
58      // Take a new port: 3 attempts
59      boolean isInit = false;
60      if (getSession().getDataConn().isPassiveMode()) {
61        // Previous mode was Passive so remove the current configuration
62        final InetSocketAddress local =
63            getSession().getDataConn().getLocalAddress();
64        final InetAddress remote =
65            getSession().getDataConn().getRemoteAddress().getAddress();
66        getConfiguration().delFtpSession(remote, local);
67      }
68      for (int i = 1; i <= FtpInternalConfiguration.RETRYNB; i++) {
69        final int newport =
70            FtpDataAsyncConn.getNewPassivePort(getConfiguration());
71        if (newport == -1) {
72          throw new Reply425Exception("No port available");
73        }
74        logger.info("PASV: set Passive Port {}", newport);
75        getSession().getDataConn().setLocalPort(newport);
76        getSession().getDataConn().setPassive();
77        // Init the connection
78        try {
79          if (getSession().getDataConn().initPassiveConnection()) {
80            isInit = true;
81            break;
82          }
83        } catch (final Reply425Exception e) {
84          logger.warn(
85              "Pasv refused at try: " + i + " with port:  since {}" + newport,
86              e.getMessage());
87        }
88      }
89      if (!isInit) {
90        throw new Reply425Exception("Passive mode not started");
91      }
92      // Return the address in Ftp format
93      final InetSocketAddress local =
94          getSession().getDataConn().getLocalAddress();
95      final int servPort = local.getPort();
96      String address = getSession().getConfiguration().getServerAddress();
97      if (address == null) {
98        address = local.getAddress().getHostAddress();
99      }
100     final String slocal = "Entering Passive Mode (" +
101                           FtpChannelUtils.getAddress(address, servPort) + ')';
102     final InetAddress remote =
103         getSession().getDataConn().getRemoteAddress().getAddress();
104     // Add the current FtpSession into the reference of session since the
105     // client will open the connection
106     getConfiguration().setNewFtpSession(remote, local, getSession());
107     // prepare the validation of the next connection
108     getSession().getDataConn().getFtpTransferControl()
109                 .resetWaitForOpenedDataChannel();
110     getSession().setReplyCode(ReplyCode.REPLY_227_ENTERING_PASSIVE_MODE,
111                               slocal);
112     logger.info("PASV: answer ready on {}", slocal);
113   }
114 
115 }