Hello,
My Indy TcpSSLServer crashes several times. I made a test solution with 1 Server and 5 Clients. Every client has 10 Threads. Each Thread connects, transmits, receives and closes the socket every 2 seconds. After 100000 – 200000 connects, the Server crashes with a memory access error. I found the access error in “IdSSLOpenSSL.pas” in “function TidSSLIOHandlerSocketOpenSSL.Readable”. The SocketClass
“fSSLSocket” was nil. Why? I don’t know.
I changed the source and it works.
function TIdSSLIOHandlerSocketOpenSSL.Readable(AMSec: Integer = IdTimeoutDefault): Boolean;
begin
if not fPassThrough then
begin
// Result := (ssl_pending(fSSLSocket.fSSL) > 0); //Original implementation
Result := Assigned(fSSLSocket) and (ssl_pending(fSSLSocket.fSSL) > 0);
if Result then Exit;
end;
Result := inherited Readable(AMSec);
end;
maybe that will help the users too
My system:
Linux: x86_64
Lazarus: 2.0.10
FPC: 3.2.0
Indy: 10.6.2
(04-09-2021, 06:47 PM)fpctuxe Wrote: [ -> ]After 100000 – 200000 connects, the Server crashes with a memory access error. I found the access error in “IdSSLOpenSSL.pas” in “function TidSSLIOHandlerSocketOpenSSL.Readable”. The SocketClass “fSSLSocket” was nil. Why? I don’t know.
Likely related to this issue:
https://github.com/IndySockets/Indy/issues/218
When
TIdSSLIOHandlerSocketOpenSSL is closed, it destroys its
fSSLSocket object, rather than just closing the underlying socket connection but leaving
fSSLSocket alive.
(04-09-2021, 06:47 PM)fpctuxe Wrote: [ -> ]I changed the source and it works.
I don't fully agree with that "fix", as it is just a workaround, which introduces a new race condition, and does not really address the root issue. But without a better fix, I have accepted and checked it in for now, thanks.
Another workaround I have considered before, but haven't implemented yet, is to have
TIdSSLIOHandlerSocketOpenSSL override the virtual
SourceIsAvailable() method to return False when
fSSLSocket is nil.
TIdIOHandler.ReadFromSource() checks
SourceIsAvailable() before and after calling
Readable(). But this is also causes a subtle race condition, too.
Thanks for the answer.
1.
Yes I think you are right if there is no solution, then there is a workaround. I will test your idea with "SourceIsAvailable ()".
2.
Is it possible that all file descriptors are occupied? I believe that sockets are file descriptors under Linux. My system has 1024 descriptors.
So, I have tested the changed with “SourceIsAvailable()”, and it works! I canceled after 1200000 rounds.
Here are the changes:
Back to the original implementation.
function TIdSSLIOHandlerSocketOpenSSL.Readable(AMSec: Integer = IdTimeoutDefault): Boolean;
begin
if not fPassThrough then
begin
Result := (ssl_pending(fSSLSocket.fSSL) > 0);
if Result then Exit;
end;
Result := inherited Readable(AMSec);
end;
New.
definition
protected
function TIdSSLIOHandlerSocketOpenSSL.SourceIsAvailable: Boolean; override;
implementation
function TIdSSLIOHandlerSocketOpenSSL.SourceIsAvailable: Boolean;
begin
Result:=Assigned(fSSLSocket) and inherited SourceIsAvailable;
end;
that's all.
Thanks for support.
(04-11-2021, 01:34 PM)fpctuxe Wrote: [ -> ]function TIdSSLIOHandlerSocketOpenSSL.SourceIsAvailable: Boolean;
begin
Result:=Assigned(fSSLSocket) and inherited SourceIsAvailable;
end;
I was thinking more along the lines of:
Code:
function TIdSSLIOHandlerSocketOpenSSL.SourceIsAvailable: Boolean;
begin
if not fPassThrough then
begin
Result := (fSSLSocket <> nil);
if not Result then Exit;
end;
Result := inherited SourceIsAvailable;
end;
Or:
Code:
function TIdSSLIOHandlerSocketOpenSSL.SourceIsAvailable: Boolean;
begin
if (fPassThrough or (fSSLSocket <> nil)) and inherited SourceIsAvailable;
end;
Hello, I thing you mean this
Code:
function TIdSSLIOHandlerSocketOpenSSL.SourceIsAvailable: Boolean;
begin
Result:= (fPassThrough or (fSSLSocket <> nil)) and inherited SourceIsAvailable;
end;
So, I have long time tested the changed with “SourceIsAvailable()”, and it works!
Than I have tested the Accept method to check is fSSLSocket = NIL. Without the new changes.
But on the moment how the mistake occurs, fSSLSocket was created. In the moment, I wand live with the workaround.
Thanks for your help.