|Subject:||Socket Error #0 in TIdIOHandler.ReadFromSource|
|Posted by:||Alex Ivlev (firstname.lastname@example.org)|
|Date:||Wed, 22 Aug 2007|
Bug: Indy improperly raises an exception EIdSocketError(0).
How to reproduce: If you have a GMail account, test its SMTP connection
without sending anything (note: this is not an SMTP bug, just using SMTP to
demonstrate). A simplified version of the code:
with TIdSMTP.Create(nil) do
with TIdSSLIOHandlerSocketOpenSSL(IOHandler).SSLOptions do
if Connected then Disconnect;
The connection works fine. Then this happens when Disconnect is called:
TIdSMTP.DisconnectNotifyPeer sends QUIT:
TIdTCPConnection.SendCmd sends it and wants a response, calling
TIdTCPConnection.GetResponse, which in turn calls
TIdTCPConnection.GetInternalResponse --> TIdIOHandler.ReadLnWait -->
TIdIOHandler.ReadLn --> TIdIOHandler.ReadFromSource.
GMail doesn't respond after QUIT by whatever reason (but doesn't disconnect
yet either). So the response is empty, and we arrive at the following code
if LByteCount < 0 then
LLastError := GStack.CheckForSocketError(Result, [Id_WSAESHUTDOWN,
FClosedGracefully := True;
// Do not raise unless all data has been read by the user
if InputBufferIsEmpty then begin
LByteCount := 0;
CheckForSocketError is called with Result as its argument for some reason.
Result is the number of bytes read from source (which is 0).
CheckForSocketError simply returns it back and LLastError is 0. But the
input buffer is empty, so a Socker Error exception gets raised with code 0.
I see at least two things wrong here:
1) using Result in CheckForSocketError call;
2) raising an exception when LLastError = 0.