Skip to content
Advertisement

Error “227 Entering Passive Mode”/”Connection refused” when downloading from local FTP server in Android emulator

I am trying to download a file from my local FileZilla Server with Java FTPSClient running in Android emulator.

I’ve written this helpercode to download one File:

public boolean downloadSingleFile(FTPSClient ftpClient,
                                  String remoteFilePath, File downloadFile) {
    OutputStream outputStream;
    Log.i("t1", remoteFilePath + " - " + downloadFile.getAbsolutePath());
    try {
        outputStream = new BufferedOutputStream(new FileOutputStream(
                downloadFile));
        ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
        boolean retval = ftpClient.retrieveFile(remoteFilePath, outputStream);
        outputStream.flush();
        return retval;
    } catch (Exception e) {
        Log.e("dwFile", e.toString());
        Log.e("dwFile", ftpClient.getReplyString());
    } return false;
}

I call this function like this:

FTPSClient dwClient = new FTPSClient();
dwClient.addProtocolCommandListener(
    new PrintCommandListener(
    new PrintWriter(new OutputStreamWriter(System.out, "UTF-8")), true));
dwClient.setConnectTimeout(30 * 1000);
dwClient.connect(OmsSettingsFunctions.getFTPServer());
Log.i("dwDB", dwClient.getReplyString());
if (dwClient.login(FPTuser, FTPpass))  {
    Log.i("dwDB", dwClient.getReplyString());
    dwClient.enterLocalPassiveMode();
    File dwFile = new File(externalPath + "/Android/data/com.myapp/files/Documents/db.temp");
    if(!downloadSingleFile(dwClient, "/DBs/db.txt", dwFile)) {
        Log.e("dwDB", "Download could not finish (DB)");
        Log.e("dwDB", dwClient.getReplyString());
    }...

But I keep getting this error:

I/System.out: 220-FileZilla Server version 0.9.41 beta
I/System.out: 220-written by Tim Kosse (Tim.Kosse@gmx.de)
              220 Please visit http://sourceforge.net/projects/filezilla/
I/System.out: AUTH TLS
D/EGL_emulation: eglMakeCurrent: 0xa209dd60: ver 3 0 (tinfo 0x9f652ff0)
D/EGL_emulation: eglMakeCurrent: 0xa209dd60: ver 3 0 (tinfo 0x9f652ff0)
I/System.out: 234 Using authentication type TLS
I/dwDB: 234 Using authentication type TLS
I/Permission: Readingpermission is granted
I/Permission: Writingpermission is granted
I/System.out: USER *******
I/System.out: 331 Password required for omstest
I/System.out: PASS *******
I/System.out: 230 Logged on
I/dwDB: 230 Logged on
I/t1: /DBs/db.txt - /storage/0FF0-280B/Android/data/com.myapp/files/Documents/db.temp
I/System.out: TYPE I
I/System.out: 200 Type set to I
I/System.out: PASV
I/System.out: 227 Entering Passive Mode (127,0,0,1,199,113)
E/dwFile: java.net.ConnectException: Connection refused
          227 Entering Passive Mode (127,0,0,1,199,113)
E/dwDB: Download could not finish (DB)
        227 Entering Passive Mode (127,0,0,1,199,113)

I already tried to use enterLocalActivemode() instead of enterLocalPassivmode() but it didn’t help. The FTP server is TLS enforcing and running on my local machine. I am connecting to it through 10.0.2.2 (Android loopback). How can I fix this?

Advertisement

Answer

While I’m not familiar with Android Emulator, I assume that you need to connect to 10.0.2.2 to connect to the emulator host machine.

In an FTP passive mode, the server sends back an IP address to which the FTP client needs to connect to transfer a file (or a directory listing). As your FTP server listens on 127.0.0.1, it sends back that IP address. But 127.0.0.1 refers to the (emulated) Android host, in the context of your Android code. Hence the “connection refused”.

This is pretty much similar to a common problem with connecting to an FTP server behind a NAT. See FTP server running on Port 2000 over NAT not working on Passive Mode

And the solution is hence the same:

  • In FileZilla Server Interface, go to Edit > Settings > Passive mode settings > IPv4 specific > External Server IP Address for passive mode transfers. And enter 10.0.2.2.
  • Maybe you will also need to uncheck “Don’t use external IP for local connections”.

Obviously this in turn makes the FTP server unusable for normal clients.

As you have correctly commented, this problem only arise when connecting from Android emulator to an FTP server running on emulator host.


Another solution is using FTPClient.setPassiveNatWorkaroundStrategy. It accepts an implementation of HostnameResolver interface. If you implement in a way that it translates 127.0.0.1 to 10.0.2.2, it will allow your Java code to connect even without any change on the server.

public static class ServerResolverImpl implements HostnameResolver {
    private FTPClient client;

    public ServerResolverImpl(FTPClient client) {
        this.client = client;
    }

    @Override
    public String resolve(String hostname) throws UnknownHostException {
        // Ignore "hostname" returned by the server.
        // Instead always use the primary address of the FTP server.
        return this.client.getRemoteAddress().getHostAddress();
    }
}
User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement