Reputation: 2111
I am really stumped and hoping somebody out there knows something about my problem.
I have a very simple SSL client and server. The connection is fine. Communication is fine. The problem arises when the client disconnects from the server. This fires a signal on the server which is handled in the SLOT error_handler(QAbstractSocket::SocketError in_error)
. In that function is where the sslSocket
object has to be deleted, I would imagine.
However doing this causes the server to seg fault. I don’t understand what’s going on. I expected this to be really straightforward but apparently I am missing some Qt (or other) concept.
Can anybody help out?
Essential server code:
void SSLServer::incomingConnection(int sd)
{
sslSocket = new SSLSocket(this);
if( sslSocket->setSocketDescriptor(sd))
{
QFile sslkeyfile(privKey_);
sslSocket->setPrivateKey(QSslKey(sslkeyfile.readAll(),QSsl::Rsa));
QFile cliCertFile(serverCert_);
sslSocket->setLocalCertificate(QSslCertificate(cliCertFile.readAll()));
QFile certFile(caCert_);
sslSocket->addCaCertificate(QSslCertificate(certFile.readAll()));
sslSocket->setPeerVerifyMode(QSslSocket::VerifyPeer);
sslSocket->setProtocol(QSsl::SslV3);
connect(sslSocket, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(error_handler(QAbstractSocket::SocketError)));
connect(sslSocket, SIGNAL(sslErrors(QList<QSslError>)),
this, SLOT(ssl_error_handler(QList<QSslError>)));
connect(sslSocket, SIGNAL(encrypted()), this,
SLOT(ready()));
connect(sslSocket, SIGNAL(readyRead()), this,
SLOT(read_data_from_client()));
sslSocket->startServerEncryption();
if(!sslSocket->waitForEncrypted())
{
qDebug() << "failed to perform SSL handshake with client";
return;
}
}
}
void SSLServer::read_data_from_client()
{
QByteArray qstrbytes = sslSocket->readAll();
qDebug() << Q_FUNC_INFO << qstrbytes;
}
void SSLServer::ready()
{
QSslCertificate clientCert = sslSocket->peerCertificate();
qDebug() << clientCert.isValid();
}
void SSLServer::error_handler(QAbstractSocket::SocketError in_error)
{
qDebug() << Q_FUNC_INFO << in_error;
if(in_error == QAbstractSocket::RemoteHostClosedError)
{
delete sslSocket; //// line causes crash !!!!!!
}
}
Upvotes: 3
Views: 1839
Reputation: 27611
If you think how a QObject class such as SSLSocket class may be written, it could be something like this:-
class SSLSocket : public QObject
{
signals:
void sslErrors(QList<QSslError>);
void SomeFunction()
{
// something went wrong, emit error
emit sslErrors(errorList);
Cleanup(); // If a slot connected to sslErrors deleted this, what happens now?!
}
}
When the signal sslErrors is triggered, your slot function is called. As you can see, after emitting the signal, the class may have more work to do. If you immediately delete the object in your slot, this is going to crash, which is why you should always use deleteLater() for deleting QObject instances in slot functions.
The deleteLater function will ensure that the slot function has finished executing and the call stack restored, so it will be deleted at the appropriate time.
Note that the code above is not actually what SSLSocket does, but just an example.
Upvotes: 3
Reputation: 9789
Use QObject::deleteLater()
instead of delete
since QSslSocket
inherits QObject
. You may still receive messages on the socket which is causing the crash when you just delete
the object.
sslSocket->deleteLater();
When you call deleteLater()
, Qt automatically disconnects all slots and signals and calls the object destructor after there are no pending events being delivered to the object. See QObject::~QObject()
for more information.
Upvotes: 6
Reputation: 71899
Here's Qt example code using QSslSocket:
http://qt-project.org/doc/qt-4.8/network-securesocketclient-sslclient-cpp.html
As the other posters mentioned, use deleteLater()
, and the error notification is not the only place to do so.
Upvotes: 1
Reputation: 3989
QSslSocket is a QObject. Never just delete a QObject. For sure don't do this in a slot. Always use deleteLater().
Upvotes: 1