Improved disconnect handling in FtpClient: retrieveFile never returns under 
certain conditions and calling FtpClient.disconnect does not terminate the 
transfer.
----------------------------------------------------------------------------------------------------------------------------------------------------------------

                 Key: NET-406
                 URL: https://issues.apache.org/jira/browse/NET-406
             Project: Commons Net
          Issue Type: Improvement
          Components: FTP
    Affects Versions: 2.0
         Environment: Linux
            Reporter: Nils Martin Sande


During file download it is possible for the transfer to stop without any time 
out being triggered in FtpClient. The result is a "lost" thread (it never 
returns from retrieveFile). Calling interrupt on the missing thread does not do 
anything. 

When we encountered this error we fist tried to monitor the downloaded file and 
then call FtpClient.disconnect if the size on disk remained unchanged for a 
given period of time. This did not solve the problem since FtpClient.disconnect 
does not close the socket used by the transfer. Changing FtpClient so that it 
keeps track of active sockets and then closing all active sockets on 
FtpClient.disconnect solved the problem for us. Although this error is not very 
common, the ability to completely kill the connection including all transfers 
seems like a useful feature. I have included the details of the modifications 
we made, maybe someone will find them useful. If there is a better way to get 
around this please let me know.

{code:title=FtpClient.java_retrieveFile|borderStyle=solid}
//The modified retrieveFile method (__activeSockets is a synchronized 
List<Socket>)
public boolean retrieveFile(String remote, OutputStream local)
            throws IOException {
        InputStream input;
        Socket socket;

        if ((socket = _openDataConnection_(FTPCommand.RETR, remote)) == null) {
            return false;
        }
        __activeSockets.add(socket);
        try {
            input = new BufferedInputStream(socket.getInputStream(),
                    getBufferSize());
            if (__fileType == ASCII_FILE_TYPE) {
                input = new FromNetASCIIInputStream(input);
            }
            // Treat everything else as binary for now
            try {
                Util.copyStream(input, local, getBufferSize(),
                        CopyStreamEvent.UNKNOWN_STREAM_SIZE, null,
                        false);
            } catch (IOException e) {
                try {
                    socket.close();
                } catch (IOException f) {
                }
                throw e;
            }
            socket.close();
            return completePendingCommand();
        } finally {
            __activeSockets.remove(socket);
        }
    }

//The modified disconnect method
public void disconnect() throws IOException {
        super.disconnect();
        __initDefaults();
        IOException exception = null;
        for (Socket socket : __activeSockets) {
            try {
                socket.close();
            } catch (IOException ex) {
                exception = ex;
            }
        }
        __activeSockets.clear();
        if (exception != null) {
            throw exception;
        }
    }
{code}



--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira

Reply via email to