Search code examples
delphi-7indy

Delphi 7 Indy IdFTP did'nt send/receive data


2 years ago, I wrote a simple client/server program for someone using Delphi 7 and Indy to send and receive some data through the Internet. I used TIdFTP to connect to their server and get and put data on it.

It worked well for 2 years. Today, they have opened another office in another city, and they want to copy the program to their new office computer, but the program doesn't work there.

The program connects successfully, but can't read the directory list, or put or get data. If it tries to send a file to the server, they just end up with an empty file!

First, I thought the problem is with the firewall, or something like that, but the program doesn't work on Win XP, 7, or 8 with and without a firewall (I disabled firewalls on all the antivirus, and even the Windows firewall). I know there is no problem with a firewall.

There are only two things different between their computer (that doesn't work) and the other computer (that does work):

  1. ISP
  2. router

They have 4 computers and a cable router.

Now I want to ask you:

  1. can the ISP block traffic like this? Connect successful, but not anything else (put, get, list)?

  2. is there anything about the router and TIdFTP?

What can I do?

my code is very simple like this:

idftp1.Port:=21;
idftp1.Host:='ftp.***.ir';
idftp1.Username:='ftp@***.ir';
idftp1.Password:='***';
idftp1.Connect;
fp:='c:\download';
idftp1.ChangeDir('***');
idftp1.Put(fp+'\message.rhp','message.rhp',false);

Solution

  • This sounds like a network routing issue.

    FTP uses multiple TCP connections. The main command connection, and secondary data transfer connections. The first is always outbound, so NOT likely to be blocked on the client side. The other connections are inbound by default, and so VERY likely to be blocked on the client side. This can be either an ISP blockage or a router blockage, both are a possibility.

    An ISP may block inbound connections. ISPs don't generally like users running their own servers without paying extra for it. FTP transfers act in a server-like mode by default. Check with the ISP if inbound connections are blocked or not.

    FTP is a not a router-friendly protocol. Transfers operate in one of two modes - Active or Passive.

    • In Active mode (the default), when the FTP client wants to transfer data, it opens a listening port and reports the IP and port to the FTP server via a PORT or EPRT command, and then the FTP server connects to this port.

      This is an inbound connection to the FTP client, so it requires port forwarding be configured on the client's router. Some routers are FTP-aware and can recognize these FTP commands so port forwarding can be setup automatically.

      However, most routers are not this smart, requiring an administrator to setup port forwarding manually.

      Unless the router supports uPNP, in which case the FTP client can setup port forwarding programmably. TIdFTP does not implement uPNP, but there are 3rd party uPNP libraries available, as well as a uPNP API implemented in Windows itself.

      If this port forwarding is not setup correctly, the FTP client cannot exchange data with the FTP server. In the case of Put(), this could easily result in an empty file on the server, if the server does not delete the file when the transfer fails (to facilitate later resuming).

    • In Passive mode, when the FTP client wants to transfer data, it sends a PASV or EPSV command to the FTP server, which then opens a listening port and reports the IP and port to the FTP client, and then the FTP client connects to this port.

      This is an outbound connection from the FTP client, so it is not likely to be blocked by an ISP, and does not require any port forwarding on the client's router.

    When a data transfer connection cannot be established, in either mode, the FTP server should be reporting an error message to the FTP client over the command connection, causing the TIdFTP.List(), TIdFTP.Get() and TIdFTP.Put() methods to raise an exception in your code. If that is not happening, something is going wrong.

    So, what can you do? The simplest thing to try is set the TIdFTP.Passive property to True so all data transfer connections are outbound. This is usually enough to avoid any routing issues.