From 5342be5ceffc84b56476fff57dd7d5e1bbfeb471 Mon Sep 17 00:00:00 2001 From: Juha Turunen Date: Thu, 9 Sep 2010 09:59:49 +0200 Subject: QSslSocketPrivate::systemCaCertificates() hangs sometimes on Symbian The patch fixes the hanging issues on some Symbian devices that occurs while retrieving certificates from the Symbian certificate store. The hanging was caused by the certificate info array not being closed before exiting the thread. This alone wouldn't make the existing implementation work, so the patch replaces it with a pure Symbian style implementation which doesn't seem to be affected (probably some OpenC threads issue). Merge-request: 808 Reviewed-by: Shane Kearns Reviewed-by: Simon Hausmann Task: QTBUG-13033 --- src/network/ssl/qsslsocket_openssl.cpp | 193 ++++++++++++++++++--------------- src/network/ssl/qsslsocket_openssl_p.h | 77 ++++++------- 2 files changed, 136 insertions(+), 134 deletions(-) diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index 94b1568..5033393 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -71,6 +71,9 @@ QT_BEGIN_NAMESPACE PtrCertFindCertificateInStore QSslSocketPrivate::ptrCertFindCertificateInStore = 0; PtrCertCloseStore QSslSocketPrivate::ptrCertCloseStore = 0; #elif defined(Q_OS_SYMBIAN) +#include +#include +#include #include #endif @@ -570,120 +573,138 @@ void QSslSocketPrivate::resetDefaultCiphers() #if defined(Q_OS_SYMBIAN) -QCertificateRetriever::QCertificateRetriever(QCertificateConsumer* parent) - : CActive(EPriorityStandard) - , certStore(0) - , certFilter(0) - , consumer(parent) - , currentCertificateIndex(0) - , certDescriptor(0, 0) +CSymbianCertificateRetriever::CSymbianCertificateRetriever() : CActive(CActive::EPriorityStandard), + iSequenceError(KErrNone) { - CActiveScheduler::Add(this); - QT_TRAP_THROWING(certStore = CUnifiedCertStore::NewL(qt_s60GetRFs(), EFalse)); - QT_TRAP_THROWING(certFilter = CCertAttributeFilter::NewL()); - certFilter->SetFormat(EX509Certificate); } -QCertificateRetriever::~QCertificateRetriever() +CSymbianCertificateRetriever::~CSymbianCertificateRetriever() { - delete certFilter; - delete certStore; - Cancel(); + iThread.Close(); } -void QCertificateRetriever::fetch() +CSymbianCertificateRetriever* CSymbianCertificateRetriever::NewL() { - certStore->Initialize(iStatus); - state = Initializing; - SetActive(); + CSymbianCertificateRetriever* self = new (ELeave) CSymbianCertificateRetriever(); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + return self; } -void QCertificateRetriever::list() +int CSymbianCertificateRetriever::GetCertificates(QList &certificates) { - certStore->List(certs, *certFilter, iStatus); - state = Listing; - SetActive(); + iCertificates = &certificates; + + TRequestStatus status; + iThread.Logon(status); + iThread.Resume(); + User::WaitForRequest(status); + if (iThread.ExitType() == EExitKill) + return KErrDied; + else + return status.Int(); // Logon() completes with the thread's exit value } -void QCertificateRetriever::retrieveNextCertificate() +void CSymbianCertificateRetriever::doThreadEntryL() { - CCTCertInfo* cert = certs[currentCertificateIndex]; - currentCertificate.resize(cert->Size()); - certDescriptor.Set((TUint8*)currentCertificate.data(), 0, currentCertificate.size()); - certStore->Retrieve(*cert, certDescriptor, iStatus); - state = RetrievingCertificates; + CActiveScheduler* activeScheduler = new (ELeave) CActiveScheduler; + CleanupStack::PushL(activeScheduler); + CActiveScheduler::Install(activeScheduler); + + CActiveScheduler::Add(this); + + // These aren't deleted in the destructor so leaving the to CS is ok + iCertStore = CUnifiedCertStore::NewLC(qt_s60GetRFs(), EFalse); + iCertFilter = CCertAttributeFilter::NewLC(); + + // Kick off the sequence by initializing the cert store + iState = Initializing; + iCertStore->Initialize(iStatus); SetActive(); -} -void QCertificateRetriever::RunL() -{ - QT_TRYCATCH_LEAVING(run()); + CActiveScheduler::Start(); + + // Sequence complete, clean up + + // These MUST be cleaned up before the installed CActiveScheduler is destroyed and can't be left to the + // destructor of CSymbianCertificateRetriever. Otherwise the destructor of CActiveScheduler will get + // stuck. + iCertInfos.Close(); + CleanupStack::PopAndDestroy(3); // activeScheduler, iCertStore, iCertFilter } -void QCertificateRetriever::run() + +TInt CSymbianCertificateRetriever::ThreadEntryPoint(TAny* aParams) { - switch (state) { - case Initializing: - list(); - break; - case Listing: - currentCertificateIndex = 0; - retrieveNextCertificate(); - break; - case RetrievingCertificates: - consumer->addEncodedCertificate(currentCertificate); - currentCertificate = QByteArray(); + CTrapCleanup* cleanupStack = CTrapCleanup::New(); - currentCertificateIndex++; + CSymbianCertificateRetriever* self = (CSymbianCertificateRetriever*) aParams; + TRAPD(err, self->doThreadEntryL()); + delete cleanupStack; - if (currentCertificateIndex < certs.Count()) - retrieveNextCertificate(); - else - consumer->finish(); - break; - } + // doThreadEntryL() can leave only before the retrieval sequence is started + if (err) + return err; + else + return self->iSequenceError; // return any error that occured during the retrieval } -void QCertificateRetriever::DoCancel() +void CSymbianCertificateRetriever::ConstructL() { - switch (state) { - case Initializing: - certStore->CancelInitialize(); - break; - case Listing: - certStore->CancelList(); - break; - case RetrievingCertificates: - certStore->CancelRetrieve(); - break; - } + User::LeaveIfError(iThread.Create(_L("CertWorkerThread"), + CSymbianCertificateRetriever::ThreadEntryPoint, 16384, NULL, this)); } -QCertificateConsumer::QCertificateConsumer(QObject* parent) - : QObject(parent) - , retriever(0) +void CSymbianCertificateRetriever::DoCancel() { + // We never cancel the sequence } -QCertificateConsumer::~QCertificateConsumer() +TInt CSymbianCertificateRetriever::RunError(TInt aError) { - delete retriever; + // If something goes wrong in the sequence, abort the sequence + iSequenceError = aError; // this gets reported to the client in the TRequestStatus + CActiveScheduler::Stop(); + return KErrNone; } -void QCertificateConsumer::finish() +void CSymbianCertificateRetriever::GetCertificateL() { - delete retriever; - retriever = 0; - emit finished(); + CCTCertInfo* certInfo = iCertInfos[iCurrentCertIndex]; + iCertificateData.resize(certInfo->Size()); + TPtr8 des((TUint8*)iCertificateData.data(), 0, iCertificateData.size()); + iCertStore->Retrieve(*certInfo, des, iStatus); + iState = RetrievingCertificates; + SetActive(); } -void QCertificateConsumer::start() +void CSymbianCertificateRetriever::RunL() { - retriever = new QCertificateRetriever(this); - Q_CHECK_PTR(retriever); - retriever->fetch(); -} + switch (iState) { + case Initializing: + iState = Listing; + iCertStore->List(iCertInfos, *iCertFilter, iStatus); + SetActive(); + break; + case Listing: + iCurrentCertIndex = 0; + GetCertificateL(); + break; + + case RetrievingCertificates: + iCertificates->append(iCertificateData); + iCertificateData = QByteArray(); + iCurrentCertIndex++; + if (iCurrentCertIndex < iCertInfos.Count()) + GetCertificateL(); + else + // Stop the scheduler to return to the thread entry function + CActiveScheduler::Stop(); + break; + } +} #endif // defined(Q_OS_SYMBIAN) QList QSslSocketPrivate::systemCaCertificates() @@ -760,23 +781,15 @@ QList QSslSocketPrivate::systemCaCertificates() systemCerts.append(QSslCertificate::fromPath(QLatin1String("/usr/share/ssl/*.pem"), QSsl::Pem, QRegExp::Wildcard)); // Centos, Redhat, SuSE systemCerts.append(QSslCertificate::fromPath(QLatin1String("/usr/local/ssl/*.pem"), QSsl::Pem, QRegExp::Wildcard)); // Normal OpenSSL Tarball #elif defined(Q_OS_SYMBIAN) - QThread* certThread = new QThread; + QList certs; + QScopedPointer retriever(CSymbianCertificateRetriever::NewL()); - QCertificateConsumer *consumer = new QCertificateConsumer(); - consumer->moveToThread(certThread); - QObject::connect(certThread, SIGNAL(started()), consumer, SLOT(start())); - QObject::connect(consumer, SIGNAL(finished()), certThread, SLOT(quit()), Qt::DirectConnection); - - certThread->start(); - certThread->wait(); - foreach (const QByteArray &encodedCert, consumer->encodedCertificates()) { + retriever->GetCertificates(certs); + foreach (const QByteArray &encodedCert, certs) { QSslCertificate cert(encodedCert, QSsl::Der); if (!cert.isNull()) systemCerts.append(cert); } - - delete consumer; - delete certThread; #endif return systemCerts; diff --git a/src/network/ssl/qsslsocket_openssl_p.h b/src/network/ssl/qsslsocket_openssl_p.h index 7a4e6b6..dec98ae 100644 --- a/src/network/ssl/qsslsocket_openssl_p.h +++ b/src/network/ssl/qsslsocket_openssl_p.h @@ -120,67 +120,56 @@ public: }; #if defined(Q_OS_SYMBIAN) + +#include +#include +#include #include // link against certstore.lib #include // link against ctframework.lib -class QCertificateRetriever; +// The purpose of this class is to wrap the asynchronous API of Symbian certificate store to one +// synchronizable call. The user of this class needs to provide a TRequestStatus object which can +// be used with User::WaitForRequest() unlike with the calls of the certificate store API. +// A thread is used instead of a CActiveSchedulerWait scheme, because that would make the call +// asynchronous (other events might be processed during the call even though the call would be seemingly +// synchronous). -class QCertificateConsumer : public QObject +class CSymbianCertificateRetriever : public CActive { - Q_OBJECT public: - QCertificateConsumer(QObject* parent = 0); - ~QCertificateConsumer(); - - void finish(); - - void addEncodedCertificate(const QByteArray& certificate) - { certificates.append(certificate); } - QList encodedCertificates() const { return certificates; } - -public slots: - void start(); + static CSymbianCertificateRetriever* NewL(); + ~CSymbianCertificateRetriever(); -signals: - void finished(); + int GetCertificates(QList &aCertificates); private: - QList certificates; - QCertificateRetriever *retriever; -}; - - -class QCertificateRetriever : public CActive -{ -public: - QCertificateRetriever(QCertificateConsumer* consumer); - ~QCertificateRetriever(); - - void fetch(); + void ConstructL(); + CSymbianCertificateRetriever(); + static TInt ThreadEntryPoint(TAny* aParams); + void doThreadEntryL(); + void GetCertificateL(); + void DoCancel(); + void RunL(); + TInt RunError(TInt aError); private: - virtual void RunL(); - virtual void DoCancel(); - - void run(); - void list(); - void retrieveNextCertificate(); - enum { Initializing, Listing, RetrievingCertificates - } state; - - CUnifiedCertStore* certStore; - RMPointerArray certs; - CCertAttributeFilter* certFilter; - QCertificateConsumer* consumer; - int currentCertificateIndex; - QByteArray currentCertificate; - TPtr8 certDescriptor; + } iState; + + RThread iThread; + CUnifiedCertStore* iCertStore; + RMPointerArray iCertInfos; + CCertAttributeFilter* iCertFilter; + TInt iCurrentCertIndex; + QByteArray iCertificateData; + QList* iCertificates; + TInt iSequenceError; }; + #endif -- cgit v0.12 From 647a3999bb073395ebb3df2137fb60e5b0435d16 Mon Sep 17 00:00:00 2001 From: Sami Merila Date: Thu, 9 Sep 2010 11:59:03 +0300 Subject: Cursor is misplaced in the editors text area When QInputMethodEvent::Cursor with value 0 is sent to QLineEdit, cursor is still visible. QLineControl (text control widget inside QLineEdit) handles the internal state of cursor visibility correctly and then promptly ignores the state when drawing the text. Issue is corrected by checking the cursor visibility state when drawing the cursor into widget. Task-number: QT-3670 Reviewed-by: axis --- src/gui/widgets/qlinecontrol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp index b6dfd13..4d47c82 100644 --- a/src/gui/widgets/qlinecontrol.cpp +++ b/src/gui/widgets/qlinecontrol.cpp @@ -527,7 +527,7 @@ void QLineControl::draw(QPainter *painter, const QPoint &offset, const QRect &cl int cursor = m_cursor; if (m_preeditCursor != -1) cursor += m_preeditCursor; - if(!m_blinkPeriod || m_blinkStatus) + if (!m_hideCursor && (!m_blinkPeriod || m_blinkStatus)) m_textLayout.drawCursor(painter, offset, cursor, m_cursorWidth); } } -- cgit v0.12 From 9d1361ab3affe34f1c3a08d3e4b83bd4e2c89eb8 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 9 Sep 2010 13:38:07 +0300 Subject: Change RLibrary handle in QS60PluginResolver to be process wide This fix enables Symbian version plugins to be accessed from all threads of the process. Task-number: QT-3895 Reviewed-by: Janne Koskinen --- src/corelib/kernel/qcore_symbian_p.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/corelib/kernel/qcore_symbian_p.cpp b/src/corelib/kernel/qcore_symbian_p.cpp index 5afde9a..66296b0 100644 --- a/src/corelib/kernel/qcore_symbian_p.cpp +++ b/src/corelib/kernel/qcore_symbian_p.cpp @@ -131,7 +131,6 @@ public: private: void init() { -#ifdef Q_OS_SYMBIAN _LIT(KLibName_3_1, "qts60plugin_3_1" QT_LIBINFIX_UNICODE L".dll"); _LIT(KLibName_3_2, "qts60plugin_3_2" QT_LIBINFIX_UNICODE L".dll"); _LIT(KLibName_5_0, "qts60plugin_5_0" QT_LIBINFIX_UNICODE L".dll"); @@ -157,7 +156,12 @@ private: TUidType libUid(KDynamicLibraryUid, KSharedLibraryUid, TUid::Uid(uidValue)); lib.Load(libName, libUid); -#endif + + // Duplicate lib handle to enable process wide access to it. Since Duplicate overwrites + // existing handle without closing it, store original for subsequent closing. + RLibrary origHandleCloser = lib; + lib.Duplicate(RThread(), EOwnerProcess); + origHandleCloser.Close(); } RLibrary lib; -- cgit v0.12 From 8ed2b25f87bc632d0e7d375c3506fab1c59ca1a2 Mon Sep 17 00:00:00 2001 From: Sami Merila Date: Thu, 9 Sep 2010 14:36:32 +0300 Subject: Editable QComboBox popup immediately closes itself after a click This is due that timer that blocks for while mouse release events (blockMouseReleaseTimer) is not started. There is an optimization in QComboBox that tries to avoid calling d->viewContainer() since that method creates the viewContainter if it doesn't exist. Unfortunately this optimization does not take into account if the container is already created. In this particular case, viewContainer is already created, but since QComboBox creates a QLineEdit, it skips the timer start, which leads to situation where combobox's popup menu receiving mouse release event and thus closes itself. As a fix, blockMouseReleaseTimer is started if the viewContainer is already created. Task-number: QTBUG-13231 Reviewed-by: axis --- src/gui/widgets/qcombobox.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/widgets/qcombobox.cpp b/src/gui/widgets/qcombobox.cpp index 917a325..96d2acd 100644 --- a/src/gui/widgets/qcombobox.cpp +++ b/src/gui/widgets/qcombobox.cpp @@ -2849,7 +2849,8 @@ void QComboBox::mousePressEvent(QMouseEvent *e) if (sc == QStyle::SC_ComboBoxArrow) d->updateArrow(QStyle::State_Sunken); #ifdef QT_KEYPAD_NAVIGATION - if (!d->lineEdit) { + //if the container already exists, then d->viewContainer() is safe to call + if (d->container) { #endif // We've restricted the next couple of lines, because by not calling // viewContainer(), we avoid creating the QComboBoxPrivateContainer. -- cgit v0.12