tags:

views:

302

answers:

4

I am using Delphi 2010 and Indy 10 that ships with it. The MemStream is a TMemoryStream and it contains a file downloaded from a website.

IdTrivialFTP1 := TIdTrivialFTP.Create(nil);
try
  IdTrivialFtp1.Name := 'IdTrivialFTP1';
  IdTrivialFTP1.Host := 'my-tftp-server-name.contoso.com';
  IdTrivialFTP1.Port := 69;
  IdTrivialFTP1.ReceiveTimeout := 4000;

  MemStream.Position := 0;
  IdTrivialFTP1.Put(MemStream, sFileName);
finally
  FreeAndNil(IdTrivialFTP1);
end;

Whenever I run this code, I get the error:

Project TestProject.exe raised exception class ERangeError with message 'Range check error'.

I've been doing quite a bit of google-ing to understand this error, but I'm currently at a loss. I've also seen only 1 example of how to perform a TFTP PUT using Indy components.

Any ideas?

UPDATE: If I trace into the error a bit, I find that the error is being thrown from within "IdTrivialFTP.pas" on line 272:

    CurrentDataBlk := WordToStr(GStack.HostToNetwork(Word(TFTP_DATA)))
+ WordToStr(GStack.HostToNetwork(BlockCtr));

For clarity, here is the context of that code:

if BlockCtr > PrevBlockCtr then
  begin
    DataLen := IndyMin(BufferSize - hdrsize, SourceStream.Size - SourceStream.Position);
    SetLength(CurrentDataBlk, DataLen + hdrsize);
    CurrentDataBlk := WordToStr(GStack.HostToNetwork(Word(TFTP_DATA))) + WordToStr(GStack.HostToNetwork(BlockCtr));
    SetLength(CurrentDataBlk, DataLen + hdrsize);
    //SourceStream.ReadBuffer(CurrentDataBlk[hdrsize+1], DataLen);
    DoWork(wmWrite, DataLen);
    TerminateTransfer := DataLen < BufferSize - hdrsize;
    PrevBlockCtr := BlockCtr;
  end;
  Send(FPeerIP, FPeerPort, CurrentDataBlk);
until False;  { repeat }
+1  A: 

You can resolve this pretty easily yourself:

  • Set a breakpoint on the line with IdTrivialFTP1.Name.
  • Hit F9 to run your app. Do whatever triggers the code to FTP the file.
  • When the IDE stops on the breakpoint, hit F8 to step line by line through the code.
  • Note the line where you hit F8 and an exception is triggered. That's the problem line.

Since you only have two lines that should trigger a range check error (the ones assigning Port and ReceiveTimeout), finding out which one is the culprit should be +trivial+ (pun intended). I'd suspect it's the port setting.

Also, don't forget that Indy comes with full source code. You can also trace into that as well, if you set your project's compiler options to use debug DCUs. (Project|Options|Compiler)

Ken White
The problem is in the Indy source code, but honestly, I don't know how to fix it. I'll update my comment with the detail.
Mick
+3  A: 

Good job determining the source of the exception. That should always be the first thing you do when you encounter an exception.

The Indy code you're using is broken. Even if there weren't a range-check error, it still wouldn't send any data from the source stream. You can see for yourself that the line that reads the contents of the stream has been commented out. It's still commented out in today's development snapshot, and it looks like it's been over two years since anyone has worked on that file. In fact, that line has been commented out ever since the file was added to the Subversion repository in revision 7.

Ditch TIdTrivialFTP and try your luck with the full-fledged FTP client instead, TIdFTP.

Rob Kennedy
Some systems, such as VOIP phones, do use TFTP and not FTP.
Remy Lebeau - TeamB
+1  A: 

My answer would have been; Indy sucks, ditch it and use Francois Piette's ICS components.

W

Warren P
I'll check it out.
Mick
+1  A: 

The version of Indy 10 that shipped with D2010 is NOT the latest Indy 10 revision that is available. The Indy code you have quoted as being broken does not exist in the current version anymore. TIdTrivialFTP was re-written awhile back ago to fix a lot of issues (I forgot to check it in at the time, though. I have done so now). Please download the latest Indy 10 snapshot from Indy's SVN server or Fulgan mirror (you will have to wait a day for it to catch up). Download links are available on Indy's website.

Remy Lebeau - TeamB
I have IdTrivialFTP.pas at revision 3979 from svn.atozed.com, and the `SourceStream.ReadBuffer` line is still commented out.
Rob Kennedy
Check the IdTrivialFTP.pas that is located at \Indy10\branches\Tiburon\Lib\Protocols.
Mick
Also, I just realized that I checked out revision 3980, so that may be the reason you didn't see it.
Mick
Ah, yes. I see now that development is occurring on the **Tiburon branch**, not on the trunk. How long till that's fixed, Remy? Tiburon was the codename for Delphi 2009, wasn't it? I'd never think to get the latest revision from a branch named for an outmoded codename.
Rob Kennedy
Yes, Tiburon was the Delphi 2009 codename. That is when we started Indy's Unicode integration. It is still not finished yet. There is no ETA for when the Tiburon branch will be merged into the Trunk. Using the Branch instead of the Trunk to get the latest code is stated in the download instructions on Indy's website.
Remy Lebeau - TeamB