Author: rwinston
Date: Mon Mar  8 09:52:43 2010
New Revision: 920251

URL: http://svn.apache.org/viewvc?rev=920251&view=rev
Log:
NET-288: IPv6 EPRT/EPSV support

Modified:
    
commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTP.java
    
commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPClient.java
    
commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPCommand.java
    
commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPReply.java

Modified: 
commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTP.java
URL: 
http://svn.apache.org/viewvc/commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTP.java?rev=920251&r1=920250&r2=920251&view=diff
==============================================================================
--- 
commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTP.java
 (original)
+++ 
commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTP.java
 Mon Mar  8 09:52:43 2010
@@ -21,6 +21,8 @@
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.net.Socket;
 import java.net.SocketException;
@@ -857,6 +859,58 @@
     }
 
     /***
+     * A convenience method to send the FTP EPRT command to the server,
+     * receive the reply, and return the reply code.
+     * 
+     * @see http://www.faqs.org/rfcs/rfc2428.html
+     * 
+     * Examples:
+     * <code>
+     * <ul>
+     * <li>EPRT |1|132.235.1.2|6275|</li>
+     * <li>EPRT |2|1080::8:800:200C:417A|5282|</li>
+     * </ul>
+     * </code>
+     * <p>
+     * @param host  The host owning the port.
+     * @param port  The new port.
+     * @return The reply code received from the server.
+     * @exception FTPConnectionClosedException
+     *      If the FTP server prematurely closes the connection as a result
+     *      of the client being idle or some other reason causing the server
+     *      to send FTP reply code 421.  This exception may be caught either
+     *      as an IOException or independently as itself.
+     * @exception IOException  If an I/O error occurs while either sending the
+     *      command or receiving the server reply.
+     ***/
+    public int eprt(InetAddress host, int port) throws IOException
+    {
+        int num;
+        StringBuffer info = new StringBuffer();
+        String h;
+
+        // If IPv6, trim the zone index
+        h = host.getHostAddress();
+        num = h.indexOf("%");
+        if (num > 0)
+            h = h.substring(0, num);
+
+        info.append("|");
+        
+        if (host instanceof Inet4Address)
+            info.append("1");
+        else if (host instanceof Inet6Address)
+            info.append("2");
+        info.append("|");
+        info.append(h);
+        info.append("|");
+        info.append(port);
+        info.append("|");
+
+        return sendCommand(FTPCommand.EPRT, info.toString());
+    }
+
+    /***
      * A convenience method to send the FTP PASV command to the server,
      * receive the reply, and return the reply code.  Remember, it's up
      * to you to interpret the reply string containing the host/port
@@ -876,6 +930,26 @@
         return sendCommand(FTPCommand.PASV);
     }
 
+     /***
+     * A convenience method to send the FTP EPSV command to the server,
+     * receive the reply, and return the reply code.  Remember, it's up
+     * to you to interpret the reply string containing the host/port
+     * information.
+     * <p>
+     * @return The reply code received from the server.
+     * @exception FTPConnectionClosedException
+     *      If the FTP server prematurely closes the connection as a result
+     *      of the client being idle or some other reason causing the server
+     *      to send FTP reply code 421.  This exception may be caught either
+     *      as an IOException or independently as itself.
+     * @exception IOException  If an I/O error occurs while either sending the
+     *      command or receiving the server reply.
+     ***/
+    public int epsv() throws IOException
+    {
+        return sendCommand(FTPCommand.EPSV);
+    }
+
     /**
      * A convenience method to send the FTP TYPE command for text files
      * to the server, receive the reply, and return the reply code.

Modified: 
commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPClient.java
URL: 
http://svn.apache.org/viewvc/commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPClient.java?rev=920251&r1=920250&r2=920251&view=diff
==============================================================================
--- 
commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPClient.java
 (original)
+++ 
commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPClient.java
 Mon Mar  8 09:52:43 2010
@@ -23,6 +23,7 @@
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStream;
+import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.net.ServerSocket;
 import java.net.Socket;
@@ -119,11 +120,11 @@
  * transfer modes, and file structures.
  * <p>
  * Because the handling of sockets on different platforms can differ
- * significantly, the FTPClient automatically issues a new PORT command
+ * significantly, the FTPClient automatically issues a new PORT (or EPRT) 
command
  * prior to every transfer requiring that the server connect to the client's
  * data port.  This ensures identical problem-free behavior on Windows, Unix,
  * and Macintosh platforms.  Additionally, it relieves programmers from
- * having to issue the PORT command themselves and dealing with platform
+ * having to issue the PORT (or EPRT) command themselves and dealing with 
platform
  * dependent issues.
  * <p>
  * Additionally, for security purposes, all data connections to the
@@ -365,6 +366,40 @@
 
     }
 
+    private void __parseExtendedPassiveModeReply(String reply)
+    throws MalformedServerReplyException
+    {
+        int port;
+ 
+        reply = reply.substring(reply.indexOf('(') + 1,
+                                reply.indexOf(')')).trim();
+
+        char delim1, delim2, delim3, delim4;
+        delim1 = reply.charAt(0);
+        delim2 = reply.charAt(1);
+        delim3 = reply.charAt(2);
+        delim4 = reply.charAt(reply.length()-1);
+
+        if (!(delim1 == delim2) || !(delim2 == delim3)
+                || !(delim3 == delim4))
+            throw new MalformedServerReplyException(
+                    "Could not parse extended passive host 
information.\nServer Reply: " + reply);
+        try
+        {
+            port = Integer.parseInt(reply.substring(3, reply.length()-1));
+        }
+        catch (NumberFormatException e)
+        {
+            throw new MalformedServerReplyException(
+                "Could not parse extended passive host information.\nServer 
Reply: " + reply);
+        }
+
+
+        // in EPSV mode, the passive host address is implicit
+        __passiveHost = getRemoteAddress().getHostAddress();
+        __passivePort = port;
+    }
+
     private boolean __storeFile(int command, String remote, InputStream local)
     throws IOException
     {
@@ -460,13 +495,26 @@
             ServerSocket server;
             server = _serverSocketFactory_.createServerSocket(0, 1, 
getLocalAddress());
 
-            if (!FTPReply.isPositiveCompletion(port(getLocalAddress(),
+            // try EPRT first. If that fails, and the connection is over IPv4
+            // fallback to PORT
+
+            if (!FTPReply.isPositiveCompletion(eprt(getLocalAddress(),
                                                     server.getLocalPort())))
             {
-                server.close();
-                return null;
-            }
+                if (getRemoteAddress() instanceof Inet6Address)
+                {
+                    server.close();
+                    return null;
+                }
 
+                if (!FTPReply.isPositiveCompletion(port(getLocalAddress(),
+                                                       server.getLocalPort())))
+                {
+                    server.close();
+                    return null;
+                }
+            }
+            
             if ((__restartOffset > 0) && !restart(__restartOffset))
             {
                 server.close();
@@ -494,10 +542,17 @@
         else
         { // We must be in PASSIVE_LOCAL_DATA_CONNECTION_MODE
 
-            if (pasv() != FTPReply.ENTERING_PASSIVE_MODE)
-                return null;
-
-            __parsePassiveModeReply(_replyLines.get(_replyLines.size() - 1));
+               // If we are over an IPv6 connection, try EPSV
+               if (getRemoteAddress() instanceof Inet6Address) {
+                       if (epsv() != FTPReply.ENTERING_EPSV_MODE) 
+                               return null;
+               __parseExtendedPassiveModeReply((String)_replyLines.get(0));
+               }
+               else {
+                       if (pasv() != FTPReply.ENTERING_PASSIVE_MODE)
+                               return null;
+                       __parsePassiveModeReply((String)_replyLines.get(0));
+               }
 
             socket = _socketFactory_.createSocket(__passiveHost, 
__passivePort);
             if ((__restartOffset > 0) && !restart(__restartOffset))

Modified: 
commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPCommand.java
URL: 
http://svn.apache.org/viewvc/commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPCommand.java?rev=920251&r1=920250&r2=920251&view=diff
==============================================================================
--- 
commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPCommand.java
 (original)
+++ 
commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPCommand.java
 Mon Mar  8 09:52:43 2010
@@ -70,6 +70,9 @@
     /** @since 2.1 */
     public static final int FEAT = 34;
     public static final int MFMT = 35;
+    public static final int EPSV = 36;
+    public static final int EPRT = 37;
+
     
     public static final int USERNAME = USER;
     public static final int PASSWORD = PASS;
@@ -118,8 +121,8 @@
                                           "USER", "PASS", "ACCT", "CWD", 
"CDUP", "SMNT", "REIN", "QUIT", "PORT",
                                           "PASV", "TYPE", "STRU", "MODE", 
"RETR", "STOR", "STOU", "APPE", "ALLO",
                                           "REST", "RNFR", "RNTO", "ABOR", 
"DELE", "RMD", "MKD", "PWD", "LIST",
-                                          "NLST", "SITE", "SYST", "STAT", 
"HELP", "NOOP", "MDTM", "FEAT", "MFMT"
-                                      };
+                                          "NLST", "SITE", "SYST", "STAT", 
"HELP", "NOOP", "MDTM", "FEAT", "MFMT",
+                                          "EPSV", "EPRT" };
 
     /**
      * Retrieve the FTP protocol command string corresponding to a specified

Modified: 
commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPReply.java
URL: 
http://svn.apache.org/viewvc/commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPReply.java?rev=920251&r1=920250&r2=920251&view=diff
==============================================================================
--- 
commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPReply.java
 (original)
+++ 
commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPReply.java
 Mon Mar  8 09:52:43 2010
@@ -49,6 +49,7 @@
     public static final int CODE_225 = 225;
     public static final int CODE_226 = 226;
     public static final int CODE_227 = 227;
+    public static final int CODE_229 = 229;
     public static final int CODE_230 = 230;
     public static final int CODE_250 = 250;
     public static final int CODE_257 = 257;
@@ -90,6 +91,7 @@
     public static final int DATA_CONNECTION_OPEN = CODE_225;
     public static final int CLOSING_DATA_CONNECTION = CODE_226;
     public static final int ENTERING_PASSIVE_MODE = CODE_227;
+    public static final int ENTERING_EPSV_MODE = CODE_229;
     public static final int USER_LOGGED_IN = CODE_230;
     public static final int FILE_ACTION_OK = CODE_250;
     public static final int PATHNAME_CREATED = CODE_257;
@@ -157,6 +159,9 @@
     /** @since 2.0 */
     public static final int REQUESTED_PROT_LEVEL_NOT_SUPPORTED = CODE_536;
     
+    // IPv6 error codes
+    // Note this is also used as an FTPS error code reply
+    public static final int EXTENDED_PORT_FAILURE = CODE_522;
 
     // Cannot be instantiated
     private FTPReply()


Reply via email to