When reconnect a client after Server disconnet, "EOF was observed that violates the protocol" indy exception is raised.
The only way to reconnect the client is to exit and re-execute client's application.
Server side:
{code}
procedure TTCPServer.DoConnect(AContext: TIdContext);
var
OK : Boolean;
begin
inherited;
try
AContext.Connection.IOHandler.ReadTimeout := -1;
TSSLClientHandler(AContext.Connection.IOHandler).PassThrough := (not FUseSSL);
Ok := True;
except
Ok := False; // EOF was observed that violates the protocol
end;
if (not Ok) then Exit;
... ....
end;
{code}
Client side:
{code}
FSSLHandler.SSLOptions.CipherList := SSLClientCipherList;
FSSLHandler.SSLOptions.Mode := sslmUnassigned;
FSSLHandler.SSLOptions.SSLVersions := [sslvTLSv1..High(TIdSSLVersion)];
FSSLHandler.PassThrough := False;
procedure TTCPClientThread.InternalDisconnect;
var
IsConnected : Boolean;
begin
Sleep(1);
FTCPClient.FCS.Lock;
try
IsConnected := FConnection.Connected;
except
IsConnected := False;
end;
if IsConnected then
begin
try
FConnection.Disconnect(True);
if Assigned(FConnection.IOHandler) then FConnection.IOHandler.InputBuffer.Clear;
except
end;
end;
FTCPClient.FCS.Unlock;
end;
function TTCPClientThread.InternalConnect:Boolean;
var
begin
Result := False;
Sleep(1);
if FTCPClient.FTerminated then Exit;
FTCPClient.FCS.Lock;
InternalDisconnect;
if FTCPClient.UseSSL then FConnection.IOHandler := FSSLHandler;
FConnection.ConnectTimeout := 10000;
FConnection.ReadTimeout := -1;
FConnection.Host := FTCPClient.FParams.Host;
FConnection.Port := FTCPClient.FParams.Port;
if FConnection.Host<>'' then
begin
try
FConnection.Connect;
Result := True;
except
end;
end;
FTCPClient.FCS.Unlock;
end;
procedure TTCPClientThread.TryReconnect(const SocketError:Integer);
begin
if (SocketError=0) or FTCPClient.FTerminated or IsShuttingDown then Exit;
InternalConnect;
end;
procedure TTCPClientThread.Execute;
var
SocketError : Integer;
aStr : UnicodeString;
begin
inherited;
InternalConnect;
while True do
begin
if IsShuttingDown or FTCPClient.FTerminated then Break;
if (FTCPClient.FParams.Host<>'') and (FTCPClient.FParams.Port>0) then
begin
aStr := Read(SocketError);
if aStr<>'' then
begin
... Process Data ...
end;
TryReconnect(SocketError);
end
else Sleep(1);
end;
InternalDisconnect;
end;
{code}
How to force the TIdTCPClient to reconnect to the server without exiting application ?
Thanks
Vote for best question.
Score: 0
# Vote: 0
Date Posted: 19-Dec-2014, at 2:53 PM EST
From: Hafedh TRIMECHE
Re: EOF was observed that violates the protocol indy [Edit]
Hafedh wrote:
> I modified the code as you recommended.
>
> Indy 5224 and OpenSSL 1.0.1j
>
> but the connection never established and an exception is raised at the
> TIdThread.Execute;
On which side, the server or the client? What type of exception is being
raised? On which line in your code?
> Is there a way to set PassThrough before the connection is established?
Not on the server side, no. PassThrough defaults to False for new connections,
and must be set to True in/after the OnConnect event.
On the client side, you can set PassThrough before calling Connect(), you
just have to assign the SSLIOHandler to the client beforehand.
--
Remy Lebeau (TeamB)
Vote for best answer.
Score: 0
# Vote: 0
Date Posted: 20-Dec-2014, at 11:40 AM EST
From: Remy Lebeau (TeamB)
Re: EOF was observed that violates the protocol indy
Hafedh wrote:
> The problem is solved by wrapping TIdSSLIOHandlerSocketOpenSSL.
> SSLSocket must be freed to reconnect to server.
You should not need to do any of that.
--
Remy Lebeau (TeamB)
Vote for best answer.
Score: 0
# Vote: 0
Date Posted: 20-Dec-2014, at 11:39 AM EST
From: Remy Lebeau (TeamB)
Re: EOF was observed that violates the protocol indy
> {quote:title=Hafedh TRIMECHE wrote:}{quote}
> When reconnect a client after Server disconnet, "EOF was observed that violates the protocol" indy exception is raised.
> The only way to reconnect the client is to exit and re-execute client's application.
> Server side:
> {code}
> procedure TTCPServer.DoConnect(AContext: TIdContext);
> var
> OK : Boolean;
> begin
> inherited;
> try
> AContext.Connection.IOHandler.ReadTimeout := -1;
> TSSLClientHandler(AContext.Connection.IOHandler).PassThrough := (not FUseSSL);
> Ok := True;
> except
> Ok := False; // EOF was observed that violates the protocol
> end;
> if (not Ok) then Exit;
>
> ... ....
> end;
> {code}
>
> Client side:
> {code}
>
> FSSLHandler.SSLOptions.CipherList := SSLClientCipherList;
> FSSLHandler.SSLOptions.Mode := sslmUnassigned;
> FSSLHandler.SSLOptions.SSLVersions := [sslvTLSv1..High(TIdSSLVersion)];
> FSSLHandler.PassThrough := False;
>
> procedure TTCPClientThread.InternalDisconnect;
> var
> IsConnected : Boolean;
> begin
> Sleep(1);
> FTCPClient.FCS.Lock;
> try
> IsConnected := FConnection.Connected;
> except
> IsConnected := False;
> end;
> if IsConnected then
> begin
> try
> FConnection.Disconnect(True);
> if Assigned(FConnection.IOHandler) then FConnection.IOHandler.InputBuffer.Clear;
> except
> end;
> end;
> FTCPClient.FCS.Unlock;
> end;
>
> function TTCPClientThread.InternalConnect:Boolean;
> var
> begin
> Result := False;
> Sleep(1);
> if FTCPClient.FTerminated then Exit;
> FTCPClient.FCS.Lock;
> InternalDisconnect;
> if FTCPClient.UseSSL then FConnection.IOHandler := FSSLHandler;
> FConnection.ConnectTimeout := 10000;
> FConnection.ReadTimeout := -1;
> FConnection.Host := FTCPClient.FParams.Host;
> FConnection.Port := FTCPClient.FParams.Port;
> if FConnection.Host<>'' then
> begin
> try
> FConnection.Connect;
> Result := True;
> except
> end;
> end;
> FTCPClient.FCS.Unlock;
> end;
>
> procedure TTCPClientThread.TryReconnect(const SocketError:Integer);
> begin
> if (SocketError=0) or FTCPClient.FTerminated or IsShuttingDown then Exit;
> InternalConnect;
> end;
>
> procedure TTCPClientThread.Execute;
> var
> SocketError : Integer;
> aStr : UnicodeString;
> begin
> inherited;
> InternalConnect;
> while True do
> begin
> if IsShuttingDown or FTCPClient.FTerminated then Break;
> if (FTCPClient.FParams.Host<>'') and (FTCPClient.FParams.Port>0) then
> begin
> aStr := Read(SocketError);
> if aStr<>'' then
> begin
> ... Process Data ...
> end;
> TryReconnect(SocketError);
> end
> else Sleep(1);
> end;
> InternalDisconnect;
> end;
> {code}
>
> How to force the TIdTCPClient to reconnect to the server without exiting application ?
>
> Thanks
The problem is solved by wrapping TIdSSLIOHandlerSocketOpenSSL. SSLSocket must be freed to reconnect to server.
{code}
TSSLClientHandler = class(TIdSSLIOHandlerSocketOpenSSL)
private
type
TSSLSocketWrapper = class(TIdSSLSocket);
TSSLContextWrapper = class(TIdSSLContext);
protected
procedure DoBeforeConnect(ASender:TIdSSLIOHandlerSocketOpenSSL);override;
procedure InitComponent; override;
public
function SSL:Pointer;
function Ctx:Pointer;
end;
{ TSSLClientWrapper }
function TSSLClientHandler.Ctx:Pointer;
begin
if Assigned(fSSLContext) then Result := TSSLContextWrapper(fSSLContext).fContext
else Result := nil;
end;
procedure TSSLClientHandler.DoBeforeConnect(ASender:TIdSSLIOHandlerSocketOpenSSL);
begin
inherited;
if Assigned(fSSLContext) then FreeAndNil(fSSLContext);
if Assigned(fSSLSocket) then FreeAndNil(fSSLSocket);
Init;
end;
procedure TSSLClientHandler.InitComponent;
begin
inherited;
SSLOptions.CipherList := SSLClientCipherList;
SSLOptions.Mode := sslmClient;
SSLOptions.SSLVersions := SSLMethodVersions;
PassThrough := False;
end;
function TSSLClientHandler.SSL: Pointer;
begin
if Assigned(fSSLContext) then Result := TSSLSocketWrapper(SSLSocket).fSSL
else Result := nil;
end;
{code}
Vote for best answer.
Score: 0
# Vote: 0
Date Posted: 20-Dec-2014, at 2:13 AM EST
From: Hafedh TRIMECHE
Re: EOF was observed that violates the protocol indy [Edit]
> {quote:title=Remy Lebeau (TeamB) wrote:}{quote}
> Hafedh wrote:
>
> > When reconnect a client after Server disconnet, "EOF was observed
> > that violates the protocol" indy exception is raised.
>
> That usually means there is a mismatch between the SSL/TLS versions that
> the SSLIOHandler and client are configured to use.
>
> > except
> > Ok := False; // EOF was observed that violates the protocol
> > end;
> > if (not Ok) then Exit;
>
> You are swallowing the exception and allowing the connection to proceed even
> though the handshake failed. Don't swallow the exception, let it pass into
> the server so it knows the connection is not viable and needs to be closed.
>
> > FSSLHandler.SSLOptions.Mode := sslmUnassigned;
>
> You should use sslmClient instead.
>
> > procedure TTCPClientThread.InternalDisconnect;
>
> This code is also misusing exceptions, and you don't need to check Connected()
> before calling Disconnect(). Try this instead:
>
> {code}
> procedure TTCPClientThread.InternalDisconnect;
> begin
> Sleep(1);
> FTCPClient.FCS.Lock;
> try
> FConnection.Disconnect(True);
> if Assigned(FConnection.IOHandler) then
> FConnection.IOHandler.InputBuffer.Clear;
> finally
> FTCPClient.FCS.Unlock;
> end;
> end;
> {code}
>
> > procedure TTCPClientThread.Execute;
>
> Try something more like this instead:
>
> {code}
> procedure TTCPClientThread.Execute;
> var
> aStr: String;
> begin
> while (not Terminated) and (not IsShuttingDown) and (not FTCPClient.FTerminated)
> do
> begin
> if not InternalConnect then
> begin
> if Terminated or IsShuttingDown or FTCPClient.FTerminated then Exit;
> Sleep(5000);
> Continue;
> end;
> try
> aStr := Read();
> if aStr <> '' then
> begin
> //... Process Data ...
> end;
> except
> InternalDisconnect;
> end;
> end;
> end;
>
> procedure TTCPClientThread.DoTerminate;
> begin
> InternalDisconnect;
> inherited;
> end;
> {code}
>
> --
> Remy Lebeau (TeamB)
Hello Remy,
I modified the code as you recommended.
Indy 5224 and OpenSSL 1.0.1j
but the connection never established and an exception is raised at the TIdThread.Execute;
{code}
except
Terminate;
raise;
end;
finally
Cleanup;
end;
{code}
Is there a way to set PassThrough before the connection is established ?
The exception is raised after setting PassThrough to False.
If I shutdown the client application and relaunch it, the connection is established without problem.
Regards.
Vote for best answer.
Score: 0
# Vote: 0
Date Posted: 20-Dec-2014, at 12:47 AM EST
From: Hafedh TRIMECHE
Re: EOF was observed that violates the protocol indy [Edit]
Hafedh wrote:
> When reconnect a client after Server disconnet, "EOF was observed
> that violates the protocol" indy exception is raised.
That usually means there is a mismatch between the SSL/TLS versions that
the SSLIOHandler and client are configured to use.
> except
> Ok := False; // EOF was observed that violates the protocol
> end;
> if (not Ok) then Exit;
You are swallowing the exception and allowing the connection to proceed even
though the handshake failed. Don't swallow the exception, let it pass into
the server so it knows the connection is not viable and needs to be closed.
> FSSLHandler.SSLOptions.Mode := sslmUnassigned;
You should use sslmClient instead.
> procedure TTCPClientThread.InternalDisconnect;
This code is also misusing exceptions, and you don't need to check Connected()
before calling Disconnect(). Try this instead:
{code}
procedure TTCPClientThread.InternalDisconnect;
begin
Sleep(1);
FTCPClient.FCS.Lock;
try
FConnection.Disconnect(True);
if Assigned(FConnection.IOHandler) then
FConnection.IOHandler.InputBuffer.Clear;
finally
FTCPClient.FCS.Unlock;
end;
end;
{code}
> procedure TTCPClientThread.Execute;
Try something more like this instead:
{code}
procedure TTCPClientThread.Execute;
var
aStr: String;
begin
while (not Terminated) and (not IsShuttingDown) and (not FTCPClient.FTerminated)
do
begin
if not InternalConnect then
begin
if Terminated or IsShuttingDown or FTCPClient.FTerminated then Exit;
Sleep(5000);
Continue;
end;
try
aStr := Read();
if aStr <> '' then
begin
//... Process Data ...
end;
except
InternalDisconnect;
end;
end;
end;
procedure TTCPClientThread.DoTerminate;
begin
InternalDisconnect;
inherited;
end;
{code}
--
Remy Lebeau (TeamB)