Seite 1 von 1

Problem mit QSslSocket und delete / deleteLater()

Verfasst: 4. Mai 2013 10:14
von hssjc
Hallo Leute,
ich habe ein großes Problem mit SSLSockets, ich mache schon seit Tagen rum,
aber irgendwie finde ich die Lösung einfach nicht.
Ich habe einen Anwendung geschrieben welche Client Anfragen in Threads bearbeitet.
Im Main Thread läuft eine Klasse welche von QTcpServer abgeleitet ist, und deren incomingConnection wie folgt aussieht

Code: Alles auswählen

void Server::incomingConnection(int socketDescriptor){
    QThread* thread = new QThread;
   Worker* worker = new Worker(socketDescriptor);
    worker->moveToThread(thread);
    connect(worker, SIGNAL(errorThread(QString)), this, SLOT(errorThread(QString)));
    connect(thread, SIGNAL(started()), worker, SLOT(process()));
    connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
    connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
    thread->start();
}
Im Konstrukter der Worker Klasse wird der SocketDescriptor übergeben.

Code: Alles auswählen

Worker::Worker(int id)
{
    this->socketDescriptor = id;
}
Die Prozess Methode initialisiert alle Variablen, und erstellt den QSslSocket auf dem Heap.

Code: Alles auswählen

void Worker::process(){
    _st = Settings::getInstance();

    //initialize variables
    sslSocket = 0;
    requestData = "";
    finishedEmitted= false;
    closeConnectionCalled = false;

        sslSocket = new QSslSocket(0);
        if(sslSocket->setSocketDescriptor(socketDescriptor)){

            QString serverKeyPath = _st->serverPrivateKey;
            QString intermediateCertPath = _st->serverIntermediateCert;

            sslSocket->ignoreSslErrors();
            sslSocket->setCiphers(QSslSocket::supportedCiphers());
            sslSocket->setProtocol(QSsl::AnyProtocol);
            sslSocket->setPeerVerifyMode(QSslSocket::VerifyNone);
            sslSocket->setPrivateKey(serverKeyPath);

            sslSocket->setLocalCertificate(QSslCertificate::fromPath(_st->serverCertificate)[0]);

            if(intermediateCertPath.count()>0){
                sslSocket->addExtraCertificate(QSslCertificate::fromPath(_st->serverIntermediateCert)[0]);
            }else{
                sslSocket->addExtraCertificate(QSslCertificate::fromPath(_st->serverCertificate)[0]);
            }

            connect(sslSocket,SIGNAL(sslErrors(QList<QSslError>)),this,SLOT(sslError(QList<QSslError>)),Qt::DirectConnection);
            connect(sslSocket,SIGNAL(readyRead()),this,SLOT(readyRead()),Qt::DirectConnection);
            connect(sslSocket,SIGNAL(disconnected()),this,SLOT(disconnected()),Qt::DirectConnection);
            connect(sslSocket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(socketError(QAbstractSocket::SocketError)),Qt::DirectConnection);
            sslSocket->startServerEncryption();


            bool success = sslSocket->waitForReadyRead(10000);
            if(!success){
                sslSocket->abort();
                finish();
            }


}
Soweit so gut, Ready Read wird ausgelöst, Daten werden mittels sslSocket->readAll eingelesen
und am Ende der ReadyRead Methode wird die finish Methode aufgerufen.
Das Einlesen der Daten funktioniert wunderbar, ebenso das bearbeiten, abspeichern
in der Datenbank und die Ausgabe des Ergebnisses.

Hier möchte ich nun das QSslSocket Objekt vom Heap löschen.
Der Code der finish Methode lautet wie folgt.

Code: Alles auswählen

void Worker::finish(){
    if(!finishedEmitted){
        finishedEmitted = true;
        closeConnection();
        mutex.lock();
        mutex.unlock();
        if(sslSocket){
            sslSocket->blockSignals(true);
            sslSocket->disconnect();
            //sslSocket->deleteLater();
            delete sslSocket;
            sslSocket = 0;
        }
        emit finished();
    }
}

Code: Alles auswählen

void Worker::closeConnection(){
    if(closeConnectionCalled)
        return;

        if(sslSocket){
            mutex.lock();
            if(sslSocket->isValid() && sslSocket->isOpen() && !closeConnectionCalled){
                closeConnectionCalled = true;
                sslSocket->close();
            }
            mutex.unlock();
        }

}
Sobald das Socket Objekt gelöscht wird, dabei spielt es keine Rolle ob in der finish Methode oder
im Destruktor, egal ob mit delete oder sslSocket->deleteLater, es gibt immer hässliche Segmentation Faults.
Wenn man mit dem Debugger reingeht sieht man dass diese entstehen wenn die geladenen Zertifkate
gelöscht werden sollen.
Wenn ich die Zertifikate anders wieim obigen Code so wie hier reinlade, gibt es ein Segmentation Fault beim
Versuch die QHostAddress zu deleten. wobei _st->certServerCertificate ein QSslCertificate ist.

Code: Alles auswählen

QSslCertificate localCert = QSslCertificate(_st->certServerCertificate);
sslSocket->setLocalCertificate (localCert);
Also irgendwie beschleicht mich das Gefühl das der Socket irgendwie zweimal ? deleted wird.
Hat jemand von Euch eine Idee, ich bin echt am verzweifeln ...
Ich hab schon sehr viel gegoogelt, aber keine ähnlichen Probleme gefunden.
Daraus schliese ich dass ich wohl etwas grundlegendes falsch mache ...
Gruß Till

Re: Problem mit QSslSocket und delete / deleteLater()

Verfasst: 4. Mai 2013 17:41
von Christian81
Kannst Du mal eine komplett abgestrippte Version deines Programms posten und nicht nur Codefragmente (als Anhang und wirklich nur minimal). Was sollen die Mutex-Aufrufe?