Network problems while using Indy - delphi

function UploadToFTP(file: string ; PathSrv : string): Boolean;
var
server, port, user , password: string;
SR : TSearchRec;
begin
Result := True;
FEventLogger := TEventLogger.Create('Upload FTP');
if file <> '' then
begin
try
server := FServer;
port := FPort;
user := FUserName;
password:= FPassword;
FindFirst(file, faArchive, SR);
try // try except
idftp1.Host:= server;
idftp1.Port := StrToInt(port);
idftp1.Username:= user;
idftp1.Password:= password;
idftp1.Connect();
idftp1.Put(file,PathSrv+SR.Name);
except on E: Exception do begin
Result:= False;
FEventLogger.LogMessage('Exception : ' + E.Message , EVENTLOG_ERROR_TYPE , 0, 2);
WriteToLog('Exception: '+ file+' error message: '+ E.Message);
end;
end;
finally
end;
end;
end;
So I have this function that does an ftp upload to some large files on sometimes slow networks. I've tested it localy and it works ok, but on slow networks i get this eror in 99% of the time.
The specified network name is no longer available.
This is a very strange behavior, becouse the FTP is located on a server that has no disconnecting issues. I also try to watch, and it start the file upload and it does almost all the upload before throwing this error. So for example if I have a 100MB file it does 99MB of the upload then throws the error.
Any ideas what is causing this error or what can I do?
Also from time to time I have an other error
Socket Error # 10054
Connection reset by peer.
To mention,i've tried to upload this files using filezilla and it works, so the problem is somewhere in that code, I might miss something.

Are you using Symantec Endpoint Protection or KIS (Kaspersky Internet Security) ? Take a look here, here and here.
The "The specified network name is no longer available." is caused by Symantec Endpoint Protection 11.0, Symantec has identified this as a known issue.
Btw, in your code don't forget to call .Disconnect() after you're finished uploading the file.

Related

Delphi and Indy10 problem with reading binary data

I have a problem with reading binary data from a network device. I am sending a 4 byte binary command to the device (a Lantronix XPort) and expect a 124 byte response from that device. When monitoring the communications with WireShark, I see the command being sent and the response from the device being returned. Yet, I keep getting an EidReadTimeout exception with message "Read Timed out"
This is the code:
function TXPort.ReadSetup(IP: string; var Setup: TXportSetup0): boolean;
var
Cmd, Resp: TidBytes;
begin
Result := False;
TCP.Host := IP;
SetLength(Cmd,4);
Cmd[3] := XPortGetConfig;
try
TCP.Connect;
TCP.IOHandler.WriteDirect(Cmd);
TCP.IOHandler.ReadBytes(Resp,SizeOf(TXportSetup0),False);
Move(Resp,Setup,SizeOf(TXportSetup0));
except
Exit
end;
TCP.Disconnect;
if Setup.Cmd[3] = (XPortGetConfig + 1) then { if proper response received... }
Result := True; { tell us }
end;
I know that the TCP.Disconnect should be in a 'finally' section but this makes no difference at all.
I've searched numerous sites and fora and one even literally had the same code as I have, but working!
I cannot figure out what is wrong here.
Best,
Meindert

Indy IdFTP fails on Active connection

I'm trying to use Indy's IdFTP to send and receive some files via FTP.
function TDatosFTP.TransfiereFTP(Fm: TForm): boolean;
var
TimeoutFTP: integer;
begin
Result := false;
with TIdFTP.Create(Fm) do
try
try
TimeoutFTP := 2000;
Host := Servidor;
Port := 21;
UserName := Usuario;
PassWord := Contra;
Passive := Pasivo;
Connect(true, TimeoutFTP);
if not Connected then
begin
Error := true;
end
else
begin
TransferType := ftASCII;
if Binario then
TransferType := ftBinary;
OnWorkEnd := FinDeTransmision;
if Descargar then
Get(Remoto , Local, True)
else
Put(InterpretarRutaEspecial(Local), Remoto, True);
if Descargar and Borrar then
Delete(Remoto);
Disconnect;
Result := true;
Fm.Hide;
end;
Except on E: Exception do
Mensaje := E.Message;
end;
finally
Free;
end;
if not Result then
ErrorTransmision;
end;
Whenever I try to do a PUT/GET on Active mode I get the following error: EIdProtocolReplyError: 'Failed to establish connection". It works fine on Passive mode.
The thing is that I want to use Indy (used elsewhere in the project) but the previous version of the code, using OverbyteIcsFtpCli works fine both in Active and Passive mode.
This is the code using OverbyteIcsFtpCli:
function TDatosFTP.TransfiereFTP(Fm: TForm): boolean;
begin
with TFtpClient.Create(Fm) do
try
HostName := Servidor;
Port := '21';
UserName := Usuario;
PassWord := Contra;
HostDirName := '';
HostFileName := Origen;
LocalFileName := InterpretarRutaEspecial(Destino);
Binary := Binario;
Passive := Pasivo;
OnRequestDone := FinDeTransmision;
if Descargar then
Result := Receive
else
Result := Transmit;
OnRequestDone := nil;
if Descargar and Borrar then
Delete;
Result := Result and not Error;
Fm.Hide;
if not Result then
ErrorTransmision;
finally
Free;
end;
end;
So I took a look under the hood using wireshark and I found that Indy's FTP is not answering some messages from the server.
This is the file-transmission handshake with OverBytes' FTP:
I've highlighted in yellow the two packets sent between server and client that start the data transmission.
Now let's see what happens with Indy's FTP:
The server is sending the packet to start the file transmission but IdFTP is not answering.
I've seen this question but this two tests where ran in the same computer, same network connection, same firewall, etc. Also this one, but I want the FTP to work both in active and passive modes.
What's happening?
In an Active mode transfer, an FTP server creates an outgoing TCP connection to the receiver.
Your Wireshark captures clearly show that the FTP server in question is creating that transfer connection BEFORE sending a response to the RETR command to let your client know that the connection is proceeding. TFtpClient is accepting that connection before receiving the RETR response. But TIdFTP waits for the RETR response before it will then accept the transfer connection (this also applies to TIdFTP's handling of STOR/STOU/APPE commands, too).
LPortSv.BeginListen; // <-- opens a listening port for transfer
...
SendPort(LPortSv.Binding); // <-- sends the PORT command
...
SendCmd(ACommand, [125, 150, 154]); // <-- sends the RETR command and waits for a response!
...
LPortSv.Listen(ListenTimeout); // <-- accepts the transfer connection
...
Re-reading RFC 959, it says the following:
The passive data transfer process (this may be a user-DTP or a second server-DTP) shall "listen" on the data port prior to sending a transfer request command. The FTP request command determines the direction of the data transfer. The server, upon receiving the transfer request, will initiate the data connection to the port. When the connection is established, the data transfer begins between DTP's, and the server-PI sends a confirming reply to the user-PI.
ICS is asynchronous, so this situation is not a big deal for it to handle. But Indy uses blocking sockets, so TIdFTP will need to be updated to account for this situation, likely by monitoring both command and transfer ports simultaneously so it can act accordingly regardless of the order in which the transfer connection and the command response arrive in.
I have opened a ticket in Indy's issue tracker for this:
#300: TIdFTP fails on Active mode transfer connection with vsFTPd
UPDATE: the fix has been merged into the main code now.

FireDAC "unable to complete network request to host"

The full error text is Remote error: [FireDAC][Phys][FB]Unable to complete network request to host "dataserver16". Error writing data to the connection. Now it seems that others have had this problem then once they sorted it, it went away, but I have the problem sporadically.
My Datasnap ISAPI.dll which contains the FireDAC Firebird connection, is running on an IIS server on a different machine to the one where the database is hosted (dataserver16) but on the same subnet. I know everything is configured correctly, because the application works to expectations about 70% of the time! The other 30% of the time, my Datasnap client receives this error (as passed back from the dll).
IMHO it looks like there is a Network issue. If the Connection is Etablished and you can read and write Data to this connection it seams to be correct.
Have you tried to do a Ping from your Source System to the Target and log that Ping so you can See if the hole Connection to the Server disapears?
Open Commandwindow as Admin and Type:
Ping {TARGET} -t >> c:\ping.log
Than wait until the Error apears and check the Logfile if your Target was available the hole Time.
For more Help we need more Background Information, like Firebird Version or If you are able to reproduce the Error + Source Code how you set up your Connection.
For completeness, I am posting my solution here. Perhaps others will gain benefit from this answer. The solution is to perform retries of the Firebird connection. The way I did it, is every TSQLQuery's BeforeOpen event handler is wired to the same method. This has improved reliability considerably (even if it slowed it down a little). The code for FireDAC is similar. Both DBX and FireDac work equally well here.
const
retrycount = 3;
procedure TServerMethodsDBX.QueryBeforeOpen(DataSet: TDataSet);
begin
TryConnect(TSQLQuery(DataSet).SQLConnection);
// ...
end;
procedure TServerMethodsDBX.TryConnect(SQLConn: TSQLConnection);
var
i: Integer;
Error: String;
begin
i := 0;
SQLConn.Close;
while (not SQLConn.Connected) and (i < retrycount) do
begin
try
SQLConn.Connected := True
except
on e: exception do
begin
Error := Error + ' ' + e.Message;
Sleep(500);
Inc(i);
end;
end;
end;
if i = retrycount then
LogMessage('Tryconnect error: ' + Error);
end;

IdTCPClient cannot connect through weak internet connections

I have a simple procedure that uses TIdTCPClient to connect to a server. Its purpose is to try to reach the server and block the thread until the connection is established. It works well with stable internet connections. The problem is, when this client is executed on some computers (all of these computers have slow or unstable internet connection like mobile 3G or just in small distant towns), it always fails to connect with "Connect timed out" exception. At the same time abovementioned computers run browsers, IM clients, etc, and these applications work fine. My server application also shows no sign of new client.
Here is the procedure:
procedure ConnectToServer;
begin
EnterCriticalSection(CS_Connect);
try
while not Client.Connected do
begin
Log('Connection attempt...');
Client.Port := <port goes here>;
Client.IPVersion := Id_IPv4;
Client.Host := '<ip address here>';
Client.ConnectTimeout := 11500;
try
Client.Connect;
except
on E: Exception do
Log('Exception: ' + E.ToString);
end;
if Client.Connected then
begin
Log('Connected after ' + inttostr(attempts) + ' failed attempts');
Client.IOHandler.WriteLn(MSG_HELLO);
attempts := 0;
exit;
end;
Inc(attempts);
Log('Connection attempt failed');
Sleep( min(attempts * 1000, 50000) );
end;
finally
LeaveCriticalSection(CS_Connect);
end;
end;
You are not doing anything wrong (though your use of Connected is redundant). Indy uses the same socket API that other apps use. They all use the same underlying connect() function. So the problem is not with Indy, it is with the OS itself. Since you have a weak signal, it is hit/miss when any given connection will succeed or fail.

Pascal Synapse error handling

I have some code written in Lazarus/FreePascal that uses the Synapse IMAPSend library unit. I attempt to login to an IMAP server over SSL (IMAPS) but the call to Login fails.
I've tried checking for exceptions - none are thrown.
Wireshark shows nothing beyond a TCP three-way handshake to the appropriate server and port.
Here's the code
function GetImapResponse(host, port, user, pass:String): String;
var
response: String = '';
imap: TIMAPSend;
no_unseen: integer;
begin
imap := TIMAPSend.create;
try
imap.TargetHost := host; //'10.0.0.16';
imap.TargetPort := port; //'993';
imap.UserName := user; //'red';
imap.Password := pass; //'********';
imap.AutoTLS := false;
imap.FullSSL := true;
response := response + 'IMAP login to '+user+'#'+host+':'+port+' ... ';
if imap.Login then
begin
response := response + 'Logged in OK. ';
// How many unseen?
no_unseen := imap.StatusFolder('INBOX','UNSEEN');
Form1.Label2.Caption := IntToStr(no_unseen);
response := 'INBOX contains ' + IntToStr(no_unseen) + ' unseen messages. ';
end
else
begin
response := response + 'IMAP Login failed. ';
end;
except
on E: Exception do
begin
response := response + 'Exception: ' + E.Message;
showMessage(response);
end;
end;
{
finally
imap.free;
response := response + 'Finally. ';
end;
}
Result := response;
end;
Here's the String result of this function
IMAP login to red#10.0.0.16:993 ... IMAP Login failed.
Question: Is there a way to see some details of what IMAPSend thinks happened?
Update 1
As shown in SimaWB's answer plus comments by Arioch 'The
mySynaDebug := TsynaDebug.Create;
imap.Sock.OnStatus := #MySynaDebug.HookStatus;
imap.Sock.OnMonitor := #MySynaDebug.HookMonitor;
produced a projectname.slog file containing
20130722-103643.605 0011F230HR_SocketClose:
20130722-103643.609 0011F230HR_ResolvingBegin: 10.0.0.16:993
20130722-103643.620 0011F230HR_ResolvingEnd: 10.0.0.16:993
20130722-103643.623 0011F230HR_SocketCreate: IPv4
20130722-103643.628 0011F230HR_Connect: 10.0.0.16:993
20130722-103643.631 0011F230HR_Error: 10091,SSL/TLS support is not compiled!
So I am moving forward :-)
I do have libssl32.dll and libeay32.dll in my project folder but will check I have the right versions and have done the right things with the chicken entrails.
Update 2:
I was using the 64-bit version of Lazarus. The OpenSSL DLLs are 32-bit DLLs which Synapse's ssl_openssl unit loads dynamically. I installed the 32-bit version of Lazarus/FPC and now my IMAP/SSL client program compiles and works as expected.
It seems the current 64-bit Lazarus/FPC binary distribution (v1.0.10/2.6.2) cannot cross-compile to i386 (which I think might have helped).
Did you try synadbg unit of Synapse?
imap := TIMAPSend.create;
imap.Sock.OnStatus := TSynaDebug.HookStatus;
imap.Sock.OnMonitor := TSynaDebug.HookMonitor;
Then the application create a log file with extension '.slog'. May be you can find more details in the log file.
Same error in the .slog file on Ubuntu 64-bit was fixed with "sudo apt-get install libssl-dev" and including "ssl_openssl" in the uses section.
The problem is here: imap.AutoTLS := false;
imap.FullSSL := true; try to set true to false and false to true...
and port should be 587

Resources