You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@camel.apache.org by "Laurent Chiarello (JIRA)" <ji...@apache.org> on 2018/09/24 15:20:00 UTC

[jira] [Created] (CAMEL-12830) FTP producer stuck if timeout occurs just after connect

Laurent Chiarello created CAMEL-12830:
-----------------------------------------

             Summary: FTP producer stuck if timeout occurs just after connect
                 Key: CAMEL-12830
                 URL: https://issues.apache.org/jira/browse/CAMEL-12830
             Project: Camel
          Issue Type: Bug
          Components: camel-ftp
    Affects Versions: 2.22.1
            Reporter: Laurent Chiarello
         Attachments: FtpSoTimeoutTest.java

In our production systems, we had several threads stuck indefinitely while trying to send a file to an FtpEndpoint. We had both _connectTimeout_ and _soTimeout_ properties set so it surprised us a little bit.

After digging a bit, we found that the scenario is quite simple to reproduce: this happens every time the {{FTPClient}} establishes the TCP connection with a server that does not respond anything.

Here is a simplified view of what happens when establishing a connection using a {{FTPClient}}:
{code:java}
// within Socket Client
public void connect(InetAddress host, int port) throws SocketException,IOException {
    _socket_.connect(new InetSocketAddress(host, port), connectTimeout);
    _connectAction_();
}
protected void _connectAction_() throws IOException { 
    _socket_.setSoTimeout(_timeout_); // _timeout_ is the default timeout of the socket
}

// overridden within FTP
protected void _connectAction_() {
    super._connectAction_();
    if (connectTimeout > 0) {
        int original = _socket_.getSoTimeout();
       _socket_.setSoTimeout(connectTimeout);
    try {
        __getReply();
    } finally {
        _socket_.setSoTimeout(original);
    }
 }{code}
 A {{SocketTimeoutException}} can be thrown either during the initial socket _connect_ action, either during the __getReply() where the FTPClient waits for the hello message from the server.  Both are using _connectTimeout_, after which the original (default) timeout is restored. The _soTimeout_ we specified in the URI is configured by FTPOperations only when the connection is successful. In this case, the Socket is connected, but an exception is thrown afterwards and the _soTimeout_ is left at 0. 

Within Camel, when the RemoteFileProducer encounters an exception while processing an Exchange, it tries to disconnect the endpoint properly with a _logout_ followed by a _disconnect_. 
{code:java}
// RemoteFileProducer
public void handleFailedWrite(Exchange exchange, Exception exception) throws Exception {
    try {
        if (getOperations().isConnected()) { // <== in our case, this returns true because the socket is actually connected
            getOperations().disconnect();
        }
    } catch (...) {
        ...
    }
}
// FTPOperations
protected void doDisconnect() throws GenericFileOperationFailedException {
    try {
        client.logout();
    } catch (IOException e) {
         throw new GenericFileOperationFailedException
    } finally {
        try {
            client.disconnect();
        } catch (IOException e) {
            throw new GenericFileOperationFailedException
        }
    }
}{code}
Unfortunately, at this point, the {{client.logout()}} sends the FTP {{QUIT}} command, then waits for the response still using the default timeout of the Socket. Since the misbehaving server/firewall never sent any form of response, the thread is left waiting forever.

I attached a simple test case to illustrate the scenario, simply using a ServerSocket that never accepts any connection. Also included is an easy workaround that uses a custom FTPClient on which the _default timeout_ is set. 

A possible fix would be to always set the _default timeout_ on the socket, before connecting it.



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)