How should I be recovering in this situation?
The server crashes, thus the connection has been abnormally closed. Calls to almost everything result in "Connection Reset By Peer" exceptions. I seem to have fixed it by calling Disconnect on the TIdTCPClient object inside the except block, but it results in one final exception with the same message (which I have caught in the second try-except block).
This is with Indy10 and Delphi XE2.
try
if not EcomSocket.Connected then EcomSocket.Connect();
except
on e: Exception do begin
try
EcomSocket.Disconnect();
except
MessageDlg('Connectivity to the server has been lost.', mtError, [mbOK], 0);
end;
end;
end;
Try this:
try
if not EcomSocket.Connected then EcomSocket.Connect();
except
try
EcomSocket.Disconnect(False);
except
end;
if EcomSocket.IOHandler <> nil then EcomSocket.IOHandler.InputBuffer.Clear;
MessageDlg('Connectivity to the server has been lost.', mtError, [mbOK], 0);
end;
Related
Can anyone explain to me how to handle errors with TIdFTP?
For example, I try to connect as follows ...
with IdFTP do
begin
Username := xxxxx;
Password := '1000';
Host := xxx.xxx.xxx.xxx;
Port := 21;
ConnectTimeOut := 5000;
try
Connect;
except
On E: Exception do
ShowMessage(E.Message);
end;
end;
If I use the wrong password (as I have deliberately done in the above example to simulate what might happen if a user provides the wrong password), I get the error "Bad sequence of commands". That tells me nothing about the real problem. Is there any way to get a meaningful description of the actual error, ie: that the password is incorrect?
I use Delphi 10.1 Update 2 and Indy 10.6.2.5341.
We experience access violations in SSL_accept. This happens if a TIdTCPServer is setup using SSL and there is an open connection that has NOT yet negotiated TLS if the TIdTCPServer is stopped.
This looks like a problem in Libssl32 or Indy. This can be simply reproduced with the following code and Putty using a RAW connection. Does anyone knows a solution (or workaround) to prevent these crashes?
procedure TSslCrash.HandlerOnExecute(AContext: TIdContext);
begin
//
end;
procedure TSslCrash.HandlerOnConnect(AContext: TIdContext);
begin
TIdSSLIOHandlerSocketBase(AContext.Connection.IOHandler).PassThrough := False;
end;
procedure TSslCrash.ButtonStartClick(Sender: TObject);
begin
LServer := TIdTCPServer.Create;
LIOHandler := TIdServerIOHandlerSSLOpenSSL.Create;
LIOHandler.SSLOptions.Mode := sslmServer;
LIOHandler.SSLOptions.Method := sslvTLSv1_2;
LIOHandler.SSLOptions.VerifyMode := [];
LIOHandler.SSLOptions.VerifyDepth := 0;
LIOHandler.SSLOptions.CertFile := 'localhost.crt';
LIOHandler.SSLOptions.RootCertFile := 'localhost.crt';
LIOHandler.SSLOptions.KeyFile := 'localhost.key';
LServer.Bindings.Add.Port := 10000;
LServer.IOHandler := LIOHandler;
LServer.OnExecute := HandlerOnExecute;
LServer.OnConnect := HandlerOnConnect;
LServer.Active := True;
//Now open a RAW connection with Putty on port 10000 and keep it open
end;
procedure TSslCrash.ButtonStopClick(Sender: TObject);
begin
if Assigned(LServer) then begin
LServer.Active := False; //This causes an AV in TIdSSLSocket.Accept
FreeAndNil(LIOHandler);
FreeAndNil(LServer);
end;
end;
When Putty is connected in Raw mode, there is no SSL/TLS handshake performed, so SSL_accept() is stuck waiting for a handshake request that never arrives.
When TIdTCPServer is being deactivated, it disconnects active socket connections, failing any blocking socket operations in progress in other threads. In the case of SSL_accept(), that should unblock it so it can exit with an error code that TIdSSLSocket.Accept() can then detect and wrap into a raised exception (EIdOSSLUnderlyingCryptoError, EIdOSSLAcceptError, EIdSocketError, etc depending on the nature of the error code) in the context of the client thread that is waiting for the handshake to complete.
However, when TIdTCPServer is disconnecting a socket connection during deactivation, TIdTCPConnection.Disconnect() is called, which calls TIdIOHandler.Close(), which TIdSSLIOhandlerSocketOpenSSL has overridden to free its internal TIdSSLSocket object - the same object that is calling SSL_accept(). So it is quite likely that the underlying OpenSSL SSL object is being freed in TIdSSLSocket.Destroy() (which calls SSL_shutdown() and SSL_free()) in the context of the deactivating thread while still actively being used in TIdSSLObject.Accept() (which calls SSL_accept()) in the context of the client thread, thus causing an Access Violation.
There is not much that can be done about this without altering Indy's source code. For instance, maybe change TIdCustomTCPServer.DoTerminateContext() to call AContext.Binding.CloseSocket() instead of AContext.Connection.Disconnect(False) so the IOHandler itself is not closed, just the underlying socket (similar to what TIdCustomTCPServer.StopListening() does when terminating its listening accept() threads).
I have opened a ticket in Indy's issue tracker for you:
#218: Access Violation in SSL_accept() when deactivating TIdTCPServer
I am using indy TIDHTTP to code a way to know whether my server on the internet is down or the address of the page on the same server is not available.
I copied the suggestion given in another thread on stackoverflow:
try
IdHTTP1.Get(mypage_address);
except
on E: EIdHTTPProtocolException do begin
if e.errorcode=404 then
showmessage('404 File not found');
// use E.ErrorCode, E.Message, and E.ErrorMessage as needed...
end;
end;
but this way I am only able to detect a server response code and not whether the server did not respond at all. I guess it's trivial but I do not know what is the way to do that?
An EIdHTTPProtocolException exception is raised when TIdHTTP successfully sends a request to the server and it sends an HTTP error reply back to TIdHTTP. If the server cannot be reached at all, a different exception (typically EIdSocketError, EIdConnectException, or EIdConnectTimeout) will be raised instead.
try
IdHTTP1.Head(mypage_address);
except
on E: EIdHTTPProtocolException do begin
ShowMessage(Format('HTTP Error: %d %s', [E.ErrorCode, E.Message]));
end;
on E: EIdConnectTimeout do begin
ShowMessage('Timeout trying to connect');
end;
on E: EIdSocketError do begin
ShowMessage(Format('Socket Error: %d %s', [E.LastError, E.Message]));
end;
on E: Exception do begin
ShowMessage(Format('Error: [%s] %s', [E.ClassName, E.Message]));
end;
end;
I attempted doing the server/site checking scientifically. but eventually simply came down to this:
function TFrameSiteChecker.GetSiteHeader(const AUrl: string): Integer;
begin
try
idhttp1.Head(AUrl);
Result := idhttp1.ResponseCode;
except
on E: exception do
Result := 0;
end;
end;
Logic being, getting the head reduces traffic, log sizes etc.
There is one one right result from the function - the return of status code 200, anything else is a fail.
Also I failed to force windows / the system / indy to not buffer/cache content, so also eventually, just run the checker every 30 minutes on a schedule. Otherwise (unless something else clears the cache) after the first connect it always succeeds, even if you unplug the machine from the network!
Delphi version : XE2,
Indy version: 10.5.8.0.
I have three procedures and all work fine until internet connection gets lost. When it will happen and after that I will try sending message then I can't reconnect when internet will be back. Can't close program (after on close program be not visible, but will use 100 cpu usage). Without "try, exception" there is a Socket Error #1053 on IdIRC1.Say and on Close. Thanks for help.
///Connection:
procedure TForm1.Button5Click(Sender : TObject);
begin
try
IdIRC1.Nickname := 'zzz';
IdIRC1.Password := 'kkk';
if IdIRC1.Connected then
IdIRC1.Disconnect;
IdIRC1.Connect;
IdIRC1.Join('#' + edit3.Text);
except
ShowMessage('ggg');
end;
end;
///Send message:
procedure TForm1.Button3Click(Sender : TObject);
begin
try
IdIRC1.Say('#' + edit3.Text, edit2.Text);
if (edit2.Text <> '') and (IdIRC1.Connected) then
begin
memo6.Lines.Add(edit2.Text);
Edit2.Clear;
end
else
ShowMessage('xxx');
except
ShowMessage('yyy');
end;
end;
///On close:
try
IdIRC1.Disconnect;
except
end;
When you encounter an error accessing the connection, such as because the connection was lost, you need to call Disconnect() and you need to clear the IOHandler.InputBuffer if it still has unread data in it. Disconnect() does not clear the InputBuffer, by design. If the InputBuffer is not empty, Connected() will return True even if the physical socket is disconnected.
I am having problem with IdTCPclient.connected function from Indy in Delphi. I am using Indy10 and Delphi2010 environment. My problem is every time i check the TCP connection with IdTCPclient.connected, it raises exception with these errors EidSocketError, EidReadTimeOut. Is there any way to disconnect and reconnect the connection? (like reset the connection).
Note: I set TCPClient.ReTimeout:= 30000;
The implemented coding for reset the connection is follow.
if IdTCPclient.connected then
begin
IdTCPclient.IOHandler.InputBuffer.Clear;
IdTCPclient.Disconnect;
end;
sleep(1000);
try
IdTCPclient.connect;
except
on E: Exception do
MessageDlg('Connecting Error: '+E.Message, mtError, [mbOk], 0);
end;
But some point, i get exception and it couldn't connect at all. I am not sure what i am doing wrong.
Should i do this?
Disconnect first
Clear input buffer
Destroy TCPclient
Re-create new TCPclient
And then connect it again
If it is the case, can someone provide me a way how to do it properly?
Also, there is another function to re-connecting the TCP in my coding. It also gives me exception as well. I check the connecting before i send a message to TCP. If there is no connection, i reconnect for five times.
result := IdTCPclient.connected
if not result then
begin
for k:=0 to 4 do
beign
sleep(1000);
try
TCPclient.connect;
except
on E: Exception do
MessageDlg('Connecting Error: '+E.Message, mtError, [mbOk], 0);
end
result := TCPclient.connected;
if result then break;
end;
With above two coding, program handles reconnecting and reset the connection pretty well. But some point the program cannot re-connect or reset the connection at all.
What should i do when i get exception? Should i reconnect from exception?
How do we build coding to check the connection regularly?
How do we build coding to to get back the connection when it lost?
Kind regards,
Connected() should not be raising any exceptions at all. If it is, then it is likely a bug. Please provide a stack trace showing that.
The best option is to simply avoid using Connected() whenever possible. When you need to perform an I/O operation, just do so, and let Indy raise an exception if a failure occurs. You can then handle it at that moment, eg:
try
IdTCPClient.DoSomething...
except
on E: EIdException do begin
Reconnect;
end;
end;
procedure Reconnect;
var
k: Integer;
begin
IdTCPClient.Disconnect;
if IdTCPClient.IOHandler <> nil then
IdTCPClient.IOHandler.InputBuffer.Clear;
for k := 0 to 4 do
begin
Sleep(1000);
try
IdTCPClient.Connect;
Exit;
except
on E: Exception do
begin
MessageDlg('Connecting Error: '+E.Message, mtError, [mbOk], 0);
if k = 4 then
raise;
end;
end;
end;
end;
before you connect make sure that the passive Boolean of idftp is false
when you need file transfert change it to true with binary file option