KISS

Keep It Simple Stupid

Downloading a file via FTP in Android

| comments

One of my recent tasks has been to download a file from an FTP server. The recommended solution is to use the Apache Commons Net library for that, which supports FTP among many others protocols. Adding it to the project was as easy as putting the jar into the libs/ directory.

Following a few examples, here is how to download a file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
private Boolean downloadAndSaveFile(String server, int portNumber,
        String user, String password, String filename, File localFile)
        throws IOException {
    FTPClient ftp = null;

    try {
        ftp = new FTPClient();
        ftp.setConnectTimeout(5 * MILLIS_IN_SEC);
        ftp.connect(server, portNumber);
        Log.d(LOG_TAG, "Connected. Reply: " + ftp.getReplyString());

        ftp.login(user, password);
        Log.d(LOG_TAG, "Logged in");
        ftp.setFileType(FTP.BINARY_FILE_TYPE);
        Log.d(LOG_TAG, "Downloading");
        ftp.enterLocalPassiveMode();

        OutputStream outputStream = null;
        boolean success = false;
        try {
            outputStream = new BufferedOutputStream(new FileOutputStream(
                    localFile));
            success = ftp.retrieveFile(filename, outputStream);
        } finally {
            if (outputStream != null) {
                outputStream.close();
            }
        }

        return success;
    } finally {
        if (ftp != null) {
            ftp.logout();
            ftp.disconnect();
        }
    }
}

When running on device, an exception gets thrown every time from the retrieveFile() function: java.net.SocketTimeoutException: Connection timed out, which seems strange because the connection is already established. Looking at the logs on the server, I saw the following commands coming: USER, PASS, TYPE I, and PASV, but there was no RETR command. Is this a bug in the library or …?

Our testing FTP server is located somewhere in corporate networks, which implies a lot of restrictions and firewalls. After some recollections on how FTP protocol works, I figured the problem was in the passive mode (http://www.ncftp.com/ncftpd/doc/misc/ftp_and_firewalls.html). The reply to the PASV command was like this: 227 Entering Passive Mode (172,168,20,1,204,173), which stated the IP address and port to connect to, but it was local (172.168.20.1), whereas the client had connected to the external IP of the server (like 88.88.88.88).

To conclude and/or remind, you can’t download a file from an FTP server behind NAT when the client is in passive mode. On the other hand, active mode doesn’t seem to work on Android (http://stackoverflow.com/questions/1567601/android-ftp-library#comment3775027_1651337).

Comments