Problems with Events after Disconnect()

Hello,

we use SmartFTP FTP Library with an application developed in Delphi 6. Our customers have different network environments e.g. with or without proxy, some must use passive FTP, some not, etc. We handle events by using an EventSink generated with Delphi Event Sink Generator (by Binh Ly). Here is some log to see what FTP server is used:

[20060425 12:49:59] Resolving host name "x.x.x.x"
[20060425 12:49:59] Connecting to x.x.x.x Port: 21
[20060425 12:49:59] Connected to x.x.x.x.
[20060425 12:49:59] 220 (vsFTPd 2.0.2)
[20060425 12:49:59] USER sbh-ftp
[20060425 12:49:59] 331 Please specify the password.
[20060425 12:49:59] PASS (hidden)
[20060425 12:49:59] 230 Login successful.
[20060425 12:49:59] SYST
[20060425 12:49:59] 215 UNIX Type: L8
[20060425 12:49:59] FEAT
[20060425 12:49:59] 211-Features:
[20060425 12:49:59] EPRT
[20060425 12:49:59] EPSV
[20060425 12:49:59] MDTM
[20060425 12:49:59] PASV
[20060425 12:49:59] REST STREAM
[20060425 12:49:59] SIZE
[20060425 12:49:59] TVFS
[20060425 12:49:59] 211 End

The Problem that I want to describe comes up with customers who use a FTP proxy (ftpFTPProxyTypeOpen) and must use passive FTP. Our application is automatically (without user interaction) doing the following:
  • Create IFTPConnection (FTPConnectionSTA)
  • Create EventSink
  • Connect EventSink with IFTPConnection
  • Set properties of IFTPConnection
  • Set EventProcs to EventSink
  • Connect with FTP server
  • List, DownloadFile, DeleteFile
  • Disconnect from FTP server
  • Disconnect EventSink
  • Destroy EventSink
  • Destroy IFTPConnection
The Problem is that our application is freezing when we disconnect the EventSink.

We have analysed the problem with a little test application which is more interactive e.g. you can connect to and disconnect from the FTP server by button click. We have logged the OnStatus, OnDisconnect and OnSocketDisconnect events and there is a difference between the two cases with proxy/passive FTP and without proxy/no need to use passive FTP:

1. No proxy and not passive FTP

Disconnect Start

OnStatus: QUIT
OnStatus: 221 Goodbye.
OnStatus: Client closed the connection.
OnSocketDisconnected: *** Socket Disconnected ***
OnDisconnected: *** Disconnected ***

Disconnect End (ReturnCode: Error 0 (Success))


2. With FTP proxy and passive FTP

Disconnect Start

OnStatus: QUIT
OnStatus: 221 Goodbye.
OnDisconnected: *** Disconnected ***

Disconnect End (ReturnCode: Error 23 (ConnectionClosed))

OnStatus: Server closed connection
OnSocketDisconnected: *** Socket Disconnected ***


In the first case also our non interactive application is working fine. In the second case it is freezing in the Disconnect of the EventSink and we think it has to do with the Events after the Disconnect from the FTP server. Our application also logs the OnStatus event and until it freezes we can only see the two lines

QUIT
221 Goodbye.

The OnStatus event with "Server closed connection" is not handled until the Disconnect of the EventSink.

We found a dirty workaround to avoid the freezing of our application by placing a waitloop with ProcessMessages between the Disconnect from the FTP server and the Disconnect of the EventSink. But we are not happy about this.

Maybe you have a better idea to handle this situation.

Best regards
Robert Meier
SBH

Hello ..

Two suggestions:

1. If you dont have the latest version of the sfFTPLib please download it from:
https://www.smartftp.com/ftplib/download

2. Use FTPConnectionMTA instead of FTPConnectionSTA

Regards,
-Mat

Hello Mat,

1. We already use the latest version of sfFTPLib.

2. First we have used FTPConnectionMTA but then we have had other problems. If we use FTPConnectionMTA and an exception raises in an event handling routine, sfFTPLib terminates the application without any chance to handle the exception within the application. And because we are using sfFTPLib only in the main thread we thought its better to use FTPConnectionSTA.

Maybe our way to handle the events is not the best. Do you know other possibilities to handle the events in Delphi?

Regards,
Robert

I would not use the FTPConnectionSTA class unless your environment doesn't support multi threading (VB6, VBScript, Javascript). When using the STA class the events are not fired directly from the worker thread. They are encapsulated and fired from the main thread:
http://support.microsoft.com/kb/q280512/
I think in this case some events (OnSocketDisconnect, etc) are still waiting in the windows message queue of the main thread after the Disconnect() function ends. And thats exactly where you will have a problem if you destroy the Event Sink before these events are processed.

The FTPConnectionMTA fires the events directly from the worker thread. Therefore they are not queued in the windows message loop and you don't have to expect any after the Disconnect() function returned.

Did you try to unadvise/destroy your event sink before you call the Disconnect function?
Destroy Event Sink
Disconnect()

You may want to call the Close() function of the IFTPConnection interface before you destroy the event sink:
Disconnect()
Close()
Destroy Event Sink

Other than that I think your dirty trick to process the message in the Windows Message Queue is not that bad ;-)

Regards,
-Mat

Oops!! Similar problem

Did you try to unadvise/destroy your event sink before you call the Disconnect function?
Destroy Event Sink
Disconnect()
Yes. this trick work
Regards,
Nikolai

We have similar problem as what is described here:
The application will lockup on FTPConnectionMTA object destruction or on the event sink destruction. (Delphi 2006)

What is the proper sequence of destroying the event sink object and the connection object when the connection was not successful?
We have a very unique setup running right now which is very similar to the behavior of the firewall of our customer:
There is a firewall router which allows the control connection to be made no matter that there is no actual FTP server running, but after that closes the control connection.

The software gets a status message saying:

"An established connection was aborted by the software in your host machine."

After this happens if I do not destroy the connection and the event sink objects my application terminates without a reason after few more attempts. I am logging everything but there is no any information about the application trying to exit. It looks like an external process is closing it.

If I de-initialize the connection and the event sink objects depending on the sequence the program locks up either on eventsFTP.Free or objFTP := nil

You can test the behavior of the library connecting to the test router here:

IP address: 72.245.12.133
Port: 21



PS: The smartFtp library is licensed and the LoadLicenseKey has been implemented in the code.


Any help will be appreciated.

Hello ..

I tried to reproduce the problem with the C# sample we provide (Samples folder) but I couldn't. What I noticed when connecting to the IP you provided is that I get a connection timeout. Thus the Connect() call always fails.

[15:52:29] SmartFTP v2.5.1006.12
[15:52:29] Resolving host name "72.245.12.133"
[15:52:29] Connecting to 72.245.12.133 Port: 21
[15:52:50] A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.

C:\Users\mb>ftp 72.245.12.133
> ftp: connect :Connection timed out
ftp>

In C# the event sink object automatically unregisters itself from the ftp object and no manual actions are required. In C++ we unregister the events before the ftp object is destroyed.

It's important that there is no operation in progress at the time you destroy the ftp object. If you are destroying the object from a different thread (not recommended) make sure that you abort any pending operations by calling the Abort() function.

You mentioned that you are calling Disconnect(). This is only necessary if the Connect() call succeeded and ConnectionStatus == sfFTPLib::ftpConnectionStatusConnected right before the Disconnect() call.

Regards,
-Mat

I've got it working. The Disconnect I mentioned is the eventSink.Disconnect. In Delphi that is the Unadvise.
Basically it worked this way:
- if connected - abort current operation
- objFTP.Close
- eventsFTP.Disconnect (unadvise)
- objFTP := nil (destructor)
- Destroy event sink object (eventsFTP.Free; eventsFTP := nil;)

I have also found that any call to update the User Interface in the event handler (like OnProgress or OnStatus) causes the application to lockup as well. I had to implement the "dirty" trick with PostMessage and it works ok.
However I have one other problem left:
Under the same conditions that you have tested (same error messages as you get) after few minutes of init, trying to connect, deinit the application gets closed on itself. Nothing in my log or in the SmartFTP log tha can tell it has been done from the application.
The application is written using Delphi 2006 and I am testing it on a slow single board computer - 800MHz Via Samuel 2.
The application is getting somehow terminated after about 15-16 min of work. Any idea if it may be related to SmartFTP library?
Have in mind that this is based on a code which worked fine with Indy9 and Indy10. The reason we are switching to SmartFTP is that Indy9 does not sopport MODE Z, Indy10 does but it has memory leak in one of the modules.

Found the problem - it was third party component, removed it and it works ok, nothing to do with sfftplib.dll.