Mega Search
23.2 Million


Sign Up

Make a donation  
EOF was observed that violates the protocol indy [Edit]  
News Group: embarcadero.public.delphi.internet.winsock

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]  
News Group: embarcadero.public.delphi.internet.winsock
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  
News Group: embarcadero.public.delphi.internet.winsock
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  
News Group: embarcadero.public.delphi.internet.winsock
> {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]  
News Group: embarcadero.public.delphi.internet.winsock
> {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]  
News Group: embarcadero.public.delphi.internet.winsock
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)

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 19-Dec-2014, at 3:20 PM EST
From: Remy Lebeau (TeamB)