Trolltech Home | Qt4-preview-feedback Home | Recent Threads | All Threads | Author | Date
All threads index page 1

Qt4-preview-feedback Archive, May 2007
QSslSocket delayed handshake problem


Message 1 in thread

I decided to give the new QSslSocket a try having been using the QtSslSocket
solution for some time.  Porting to use the new class didn't take long but I
came across a problem where the connection would hang and eventually timeout
during the handshake.  The handshake is delayed, only occurring after the
client has sent a STARTTLS command over an unencrypted connection (i.e.
QSslSocket starts out in unencrypted mode and then switches to encryption
later).

I've done some investigation and think there might be a problem in the
current snapshot (20070507).  This appears to be caused by Qt's reluctance
to send recursive readyRead() signals.  The sequence of events would seem to
be as follows:

1. My server receives a readyRead() signal indicating that data is present
   (i.e. the STARTTLS command).

2. My slot processes the command, sends back an acknowledgement and then
   calls QSslSocket::startServerEncryption() to begin the handshake.

3. I then call QSslSocket::waitForEncrypted() to wait for the handshake to
   complete.  Note that I haven't returned from my slot yet.

4. QSslSocket::waitForEncrypted() contains the following code:

    while (!d->connectionEncrypted) {
        // Start the handshake, if this hasn't been started yet.
        if (d->mode == UnencryptedMode)
            startClientEncryption();
        // Loop, waiting until the connection has been encrypted or an error
        // occurs.
        if (!d->plainSocket->waitForReadyRead(qBound(0, msecs - stopWatch.elapsed(), msecs)))
            return false;
    }

   I'm essentially seeing the connection never leave this loop as it reads the
   first part of the handshake from the client and then loops again and tries
   to read something else while the client is expecting a response.  This is
   what causes the connection to hang.

5. Looking at QAbstractSocket::waitForReadyRead(), it appears that the readyRead()
   signal is not emitted if we're still in the process of emitting it.  Since
   execution never left my original slot, readyRead() is not emitted.  Thus this
   loop will never do anything with the data available on the socket, because
   readyRead() will never call QSslSocket's private slot _q_readyReadSlot(),
   which is what reads the data from the socket and processes it through OpenSSL,
   completing the handshake.

With this in mind, I added a call to d->_q_readyReadSlot() immediately following
the waitForReadyRead() and this fixes the problem with the handshake.  However,
I'm also seeing further stalls once the connection is encrypted which appear to
have a similar solution, i.e. adding an explicit slot call following instances of
waitForReadyRead().

Is this likely to be fixed in Qt or do I need to restructure my code to
avoid this recursion?

-- 
 [ signature omitted ]