2
votes

Delphi v10.1 Berlin. Indy v10.6.2 OpenSSL v1.0.2h

I have a form I set up in Delphi to test using TIdIMAP4 with an SSL connection (TIdSSLIOHandlerSocketOpenSSL). Because this was for testing, I had a checkbox set up to show me if the IMAP component was currently connected, and I connected the OnStatus and OnStatusInfo events of both the IMAP and SSL IOHandler to code that updated the checkbox. That code was simply:

IsConnectedCB.Checked := imap.Connected;

Eventually (it took me longer than I like to admit) I worked out that that is what was upsetting the SSL connection. Here is an example of what happened (a log of the status messages):

02:35:13 S: Resolving hostname localhost.
02:35:13 S: Connecting to 127.0.0.1.
02:35:13 S: Connected.
02:35:13 S: SSL status: "before/connect initialization"
02:35:13 S: SSL status: "before/connect initialization"
02:35:13 S: SSL status: "SSLv3 write client hello A"
02:35:13 S: SSL status: "SSLv3 read server hello A"
02:35:43 S: SSL status: "SSLv3 read server certificate A"
02:35:46 S: Disconnecting.
02:35:46 S: Disconnected.
02:35:48 E: SSL negotiation failed.

Notice the time difference following "server hello A" (sometimes happened after "client hello A") - this is where the connection attempt times out.

It turns out that a call to imap.Connected ends up making a query inside the IOHandler and that upsets the callback processing.

The solution is simple: Don't read the Connected property during a callback. :-)

But, I would like to be able to update my form status while testing various long running processes, and the OnStatus/OnStatusInfo events are convenient for that (rather than interspersing my own code with lots of calls to update). So...

My question is: Is there a way to tell when it is safe to test the Connected property? (In this case TIdIMAP4.Connected, but I'm sure the problem must apply to most other components using OpenSSL.)

1

1 Answers

2
votes

Is there a way to tell when it is safe to test the Connected property?

As you discovered, Connected performs a read operation. Performing socket I/O is the only way to determine if a blocking socket is still connected and valid. So, you can't use Connected when reading will interfere with the flow of other operations that also need to perform I/O.

In fact, you really shouldn't be using Connected directly at all in most situations. In this case, I would suggest using the TIdIMAP4.On(Dis)Connected and/or TIdIMAP4.OnStatus events to update a Boolean variable, and then have the rest of your code simply check that variable when needed.