0

I have a Delphi XE5 Android app that connects to an Indy FTP server running on a PC (Server is the Indy 10 IdFTPServer demo). I FTP.Get the same file from the server (every 2 seconds) and display the contents (24 chars) in a label on my Android device. It always works for 16 times and then the android app exits. From the servers point of view, it reports "10054, Connection reset by peer"

Here is the code:

procedure TForm3.FetchTimerTimer(Sender: TObject);  
var  
    str : string;  
begin
    inc(FetchCnt);    
    aStream.Position := 0;  
    FTP.Get('Time1.txt', aStream);  
    aStream.Position := 0;  
    str := aStream.ReadString(255);  
    CmdLabel.text := inttostr(FetchCnt) + ') ' + str;  
end;  

Is 16 a magic number somewhere ? Works as expected until after the 16th FTP.Get Ideas ?

RRUZ
  • 134,889
  • 20
  • 356
  • 483
  • After further investigation, looks like the Android app is getting a segmentation fault after on the 17th FTP.Get. I can strip out everything besides the FTP.Get and it still fails. If I comment out the FTP.Get, and assign str to 'dummy', it runs (forever). In need of ideas anyone ???? – Paul Peterson Oct 22 '13 at 20:09
  • A Segmentation Fault is like an Access Violation on Windows. But without knowing which code is raising the SF, it is hard to diagnose. Since TIdFTP is able to work 16 times without problem, and it is the same file every time, it makes me think that maybe some memory is getting corrupted or something leading up to the crash. Can you get a stack trace when the error occurs? If you download other files, does it still crash? – Remy Lebeau Oct 23 '13 at 15:04
  • @RemyLebeau Empty project (completely no code at all), with only IdFTP component dropped onto the form and run on 4.3 (HTC One), on application exit the app exits, and right after raises android error "Unfortunatelly, Project1 has closed." Is this a known IdFTP bug, even in XE5 Update 2...? The debugger raises Segmentation fault, at IdStack.DecUsage in IdStack.pas, which is, if I understand correctly, Indy close procedure...? – That Marc Jan 25 '14 at 01:35
  • 1
    @JustMarc: No, it is not a known bug. `TIdStack.IncUsage()` is called when any Indy component is instantiated, and then `TIdStack.DecUsage()` is called when the component is freed. Those methods maintain an active reference to Indy's `GIdStack` global singleton, which is what provides all of the low-level socket API access. If `DecUsage()` is crashing, that might suggest the singleton's reference count is not being managed correctly, so maybe `DecUsage()` is being called on a dead object. – Remy Lebeau Jan 25 '14 at 01:42
  • @RemyLebeau So, if I understand you correctly... `DecUsage()` is being called on a dead object, even though it is there...? Is there any chance that you could try and take a quick look on this, since you're far more acknowledged about it's background...? If it's not too much to ask.. :/ If it is a bug, then I'm sure one of you guru's are the right persons to call it that way, in order to be sure... – That Marc Jan 25 '14 at 02:06
  • @JustMarc: I am saying that it is a *possibility*, I did not say that is what is actually happing. I do not have an Android device to test with, so I cannot validate it myself. You will have to debug your app and check if the `IncUsage()` and `DecUsage()` calls are balanced. One thing I do recall is that Delphi uses ARC for objects on Android, so another possibility might be a unbalanced reference count causing the `GIdStack` object to die prematurely even though Indy thinks it is still alive. I can certainly make since tweaks to Indy's SVN code to account for that, at least. – Remy Lebeau Jan 25 '14 at 03:09
  • @RemyLebeau Ok, so I'm trying to debug through `IdStack` and the funny thing happens: If I debug it for platform 32bit windows - debugs as usual, goes through source breakpoints, and done. If I set Android platform for active, and run with debugger the same code with same breakpoints, it's funny scenario: In debug log, it shows as if it's a break in `IdStack`, while it redirects me to the exact same line number in `System.Classes` file! :O Wtf...? It goes on for all source breakpoints from `IdStack`, and shows them in `System.Classes`... I think it'd be good to open a new question on this one? – That Marc Jan 25 '14 at 05:45
  • The whole IdFTP thing I mean... What you think? – That Marc Jan 25 '14 at 05:46
  • Seems like I found sort of solution, or at least possible cause of error: I created object manually on `FormCreate` rather than just drag&drop on form, but still assigned Form as owner, via `FTP:=TIdFTP.Create(Form1)`, did `FTP.Free` on `FormClose`, and same error appears. However, if I remove owner, and use just `FTP:=TIdFTP.Create`, and then `FTP.Free` at `FormClose`, it does not cause this error. Is this helpful in determining what's about the error? – That Marc Jan 25 '14 at 07:28
  • 1
    @JustMarc: that makes me think the `TComponent.FreeNotification()` system is broken under ARC. `TComponent` maintains active references to its owned components. Calling `FTP.Free()` merely decrements the object's refcount, it does not actually free the object since the Owner still has a reference to it. So the actual free is still delayed until the Owner (the Form) is freed at app exit. If you want to free the object immediately, use `FTP.DisposeOf()` instead. I'm not ruling out the possibility that an ARC/timing issue still exists with the `GIdStack` object, though. – Remy Lebeau Jan 25 '14 at 16:23
  • @JustMarc: do you happen to have a call stack when the crash happens? – Remy Lebeau Jan 25 '14 at 16:28
  • @RemyLebeau I haven't just tried to Free or nil it, and therefore caused decrement of number; It throws error with component dropped on a form, with no code at all (Nothing on form close or anything at all), so it must be some internal error. However, for that same dropped component, `IdFTP1.DisposeOf` solves the issue!!! As well as for manually created object with an owner (as I tried yesterday). So, it is some error, not sure what you were talking about with FreeNotification, but something is off, – That Marc Jan 26 '14 at 03:31
  • and DisposeOf solves it. So it should be always added when IdFTP used (not sure for others, will check them too). Thanks for the tip. I hope this will be further investigated and documented somewhere for anyone having same troubles! :) Ps: I didn't quite understand the last comment - what call stack..? :/ – That Marc Jan 26 '14 at 03:32
  • Under ARC (which Delphi uses for mobile), `FreeAndNil(FTP)`, `FTP.Free()`, and `FTP := nil` basically have no effect when `FTP` has an Owner assigned. `FTP` still has an active reference count of at least 1 (actually, more like 2-3) inside of the Owner, so `FTP` is not actually freed until its Owner is freed. And something is going wrong during that delayed free, I just do not know what yet. `FTP.DisposeOf()` forces `FTP` to be freed immediately (which then causes it to notify its Owner to remove references so the Owner does not try to free it again). – Remy Lebeau Jan 26 '14 at 04:20

1 Answers1

0

There is nothing in TIdFTP to restrict the number of transfers you can perform over the same connection. The error you are seeing means the connection is being lost on the server side. Maybe the demo only allows 16 transfers, I do not know (I am not familiar with the demo you mention). Or maybe there are only a limited number of ports available. Are you performing transfers in Active or Passive mode? I would suggest you put a packet sniffer between your client and server and see what is actually happening over the network.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • I was using Active, tried Passive, but the connection didn't succeed. I'll try the packet sniffer .... – Paul Peterson Oct 22 '13 at 20:49
  • Is there a proxy/router sitting between the client and the server? If a router, Passive mode will not work unless you configure the router with port-forwarding rules to pass FTP connections to the server PC. – Remy Lebeau Oct 22 '13 at 22:47
  • I believe a router, but I assume I want to use Active mode anyways. Everything works fine until the 17th file transfer when the Android client aborts with a segmentation fault and disconnects. I created a new FTP Server from scratch (using Indy) instead of using the demo, and it does the same thing. Problem really seems to be in the client on the Android side, The server will continue running and functioning correctly, even though the client crashes on the 17th, and can be rerun and do another 17. – Paul Peterson Oct 22 '13 at 23:16
  • I would imagine Passive mode to work better on a mobile device, since it is an outbound connection from the device to the server, whereas Active mode is inbound from the server to the device. But if it is working for you, then so be it. As for the segfault, more debugging is needed to know what code is actually raising it, whether it is in Indy or in Android itself. – Remy Lebeau Oct 23 '13 at 15:08
  • Thanks for the help Remy, guess I'll leave the debugging to someone else; since it is early in the Delphi Android life. I switched to using IdTCP Server and client, and the plumbing is up and running. Now I can proceed with the application. Thanks again. Later, Paul – Paul Peterson Oct 24 '13 at 15:50
  • Side Note : I have an similar issue with iOS. around the 15th time – ThisGuy Jan 21 '14 at 17:46
  • Side note 2: Empty project (completely no code at all), with only IdFTP component dropped onto the form and run on 4.3 (HTC One), on application exit the app exits, and right after raises android error "Unfortunatelly, Project1 has closed." Is this a known IdFTP bug, even in XE5 Update 2...? – That Marc Jan 25 '14 at 01:34
  • What makes you think `TIdFTP` is at fault? Do you have the same error with any other components? If you don't connect to an FTP server, there will be very little for `TIdFTP` to clean up, so I can't imagine very much going wrong with it. Have you tried freeing the `TIdFTP` object yourself in the Form's destructor, and then wrap that in a `try/except` block? – Remy Lebeau Jan 25 '14 at 01:39
  • No, I don't have any other component causing errors. That's exactly what is strange. I spent about 5 hours deleting code, part by part in a copy of my project, until I was left with no code at all (no procedures, no vars, only objects), and still got error. There I started to delete components one by one, and after deleting IdFTP, error was gone. So, new project, dropped IdFTP on it, ran - voila, error was here again. So yes, I believe that's the case. +, I don't have any troubles connecting to ftp in my project. I even successfully put and get files to and from it! Only after close it crashes – That Marc Jan 25 '14 at 06:03