From 6f6d94acaefc202e2a922ff2ea672afa64490c4e Mon Sep 17 00:00:00 2001 From: Sami Merila Date: Fri, 14 Oct 2011 12:56:53 +0300 Subject: Maximized dialogs are incorrectly positioned after layout switch The native side seems to return StaCon pane height as zero in Belle. If no StaCon pane height is available, try to fetch Status Pane height and use that one. Task-number: QTBUG-22022 Reviewed-by: Miikka Heikkinen --- src/gui/dialogs/qdialog.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/gui/dialogs/qdialog.cpp b/src/gui/dialogs/qdialog.cpp index 2fb6c67..d2211af 100644 --- a/src/gui/dialogs/qdialog.cpp +++ b/src/gui/dialogs/qdialog.cpp @@ -909,6 +909,10 @@ bool QDialog::symbianAdjustedPosition() AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EStatusPane, statusPaneRect); } else { AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EStaconTop, statusPaneRect); + // In some native layouts, StaCon is not used. Try to fetch the status pane + // height from StatusPane component. + if (statusPaneRect.IsEmpty()) + AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EStatusPane, statusPaneRect); } p.setX(0); -- cgit v0.12 From 18afea90f84fdf44a2b3890716bf6d6a74b7446d Mon Sep 17 00:00:00 2001 From: mread Date: Fri, 14 Oct 2011 11:12:45 +0100 Subject: Early construction of status pane and softkeys for Symbian boosted apps QtAppBooster can partially start apps and hide them in the background before they are requested by the user. This gives an apparently faster start for these apps. Qt is now detecting these app starts and bringing the construction of the status pane and softkeys forward so that they happen in the background. This cuts their construction time off the time between the user clicking on the app and it being ready to use. On a Nokia E7, this gain was measured at an average of 127ms. Task-number: QT-4933 Reviewed-by: Sami Merila --- src/gui/kernel/qapplication.cpp | 4 ++ src/gui/kernel/qapplication_p.h | 1 + src/gui/kernel/qapplication_s60.cpp | 44 +++++++++++++++++++ src/gui/kernel/qt_s60_p.h | 3 ++ src/gui/kernel/qwidget_s60.cpp | 84 ++++++++++++++----------------------- 5 files changed, 83 insertions(+), 53 deletions(-) diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 15d37c3..35a9559 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -874,6 +874,10 @@ void QApplicationPrivate::construct( if (qt_is_gui_used) qt_guiPlatformPlugin(); #endif + +#ifdef Q_OS_SYMBIAN + symbianHandleLiteModeStartup(); +#endif } #if defined(Q_WS_X11) diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index e1252a9..0756d6c 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -561,6 +561,7 @@ public: int symbianProcessWsEvent(const QSymbianEvent *symbianEvent); int symbianHandleCommand(const QSymbianEvent *symbianEvent); int symbianResourceChange(const QSymbianEvent *symbianEvent); + void symbianHandleLiteModeStartup(); void _q_aboutToQuit(); #endif diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index 03da630..7d198ce 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -201,6 +201,32 @@ bool QS60Data::setRecursiveDecorationsVisibility(QWidget *window, Qt::WindowStat } #endif +void QS60Data::createStatusPaneAndCBA() +{ + CEikAppUi *ui = static_cast(S60->appUi()); + MEikAppUiFactory *factory = CEikonEnv::Static()->AppUiFactory(); + QT_TRAP_THROWING( + factory->CreateResourceIndependentFurnitureL(ui); + CEikButtonGroupContainer *cba = CEikButtonGroupContainer::NewL(CEikButtonGroupContainer::ECba, + CEikButtonGroupContainer::EHorizontal, ui, R_AVKON_SOFTKEYS_EMPTY_WITH_IDS); + CEikButtonGroupContainer *oldCba = factory->SwapButtonGroup(cba); + Q_ASSERT(!oldCba); + S60->setButtonGroupContainer(cba); + CEikMenuBar *menuBar = new(ELeave) CEikMenuBar; + menuBar->ConstructL(ui, 0, R_AVKON_MENUPANE_EMPTY); + menuBar->SetMenuType(CEikMenuBar::EMenuOptions); + S60->appUi()->AddToStackL(menuBar, ECoeStackPriorityMenu, ECoeStackFlagRefusesFocus); + CEikMenuBar *oldMenu = factory->SwapMenuBar(menuBar); + Q_ASSERT(!oldMenu); + ) + if (S60->statusPane()) { + // Use QDesktopWidget as the status pane observer to proxy for the AppUi. + // Can't use AppUi directly because it privately inherits from MEikStatusPaneObserver. + QSymbianControl *desktopControl = static_cast(QApplication::desktop()->winId()); + S60->statusPane()->SetObserver(desktopControl); + } +} + void QS60Data::controlVisibilityChanged(CCoeControl *control, bool visible) { if (QWidgetPrivate::mapper && QWidgetPrivate::mapper->contains(control)) { @@ -2580,6 +2606,24 @@ int QApplicationPrivate::symbianResourceChange(const QSymbianEvent *symbianEvent return ret; } +void QApplicationPrivate::symbianHandleLiteModeStartup() +{ + if (QCoreApplication::arguments().contains(QLatin1String("--startup-lite"))) { + if (!QApplication::testAttribute(Qt::AA_S60DontConstructApplicationPanes) + && !S60->buttonGroupContainer() && !S60->statusPane()) { + // hide and force this app to the background before creating screen furniture to avoid flickers + CAknAppUi *appui = static_cast(CCoeEnv::Static()->AppUi()); + if (appui) + appui->HideApplicationFromFSW(ETrue); + CCoeEnv::Static()->RootWin().SetOrdinalPosition(-1); + S60->createStatusPaneAndCBA(); + if (S60->statusPane()) { + S60->setStatusPaneAndButtonGroupVisibility(false, false); + } + } + } +} + #ifndef QT_NO_WHEELEVENT int QApplication::wheelScrollLines() { diff --git a/src/gui/kernel/qt_s60_p.h b/src/gui/kernel/qt_s60_p.h index 96b8141..5ad5b00 100644 --- a/src/gui/kernel/qt_s60_p.h +++ b/src/gui/kernel/qt_s60_p.h @@ -163,6 +163,7 @@ public: int partial_keyboardAutoTranslation : 1; int partialKeyboardOpen : 1; int handleStatusPaneResizeNotifications : 1; + int screenFurnitureFullyCreated : 1; QApplication::QS60MainApplicationFactory s60ApplicationFactory; // typedef'ed pointer type QPointer splitViewLastWidget; @@ -198,6 +199,7 @@ public: static inline void setButtonGroupContainer(CEikButtonGroupContainer* newCba); static void setStatusPaneAndButtonGroupVisibility(bool statusPaneVisible, bool buttonGroupVisible); static bool setRecursiveDecorationsVisibility(QWidget *window, Qt::WindowStates newState); + static void createStatusPaneAndCBA(); #endif static void controlVisibilityChanged(CCoeControl *control, bool visible); static TRect clientRect(); @@ -365,6 +367,7 @@ inline QS60Data::QS60Data() partial_keyboardAutoTranslation(1), partialKeyboardOpen(0), handleStatusPaneResizeNotifications(1), + screenFurnitureFullyCreated(0), s60ApplicationFactory(0) #ifdef Q_OS_SYMBIAN ,s60InstalledTrapHandler(0) diff --git a/src/gui/kernel/qwidget_s60.cpp b/src/gui/kernel/qwidget_s60.cpp index 00661ae..396c306 100644 --- a/src/gui/kernel/qwidget_s60.cpp +++ b/src/gui/kernel/qwidget_s60.cpp @@ -505,63 +505,41 @@ void QWidgetPrivate::show_sys() #ifdef Q_WS_S60 // Lazily initialize the S60 screen furniture when the first window is shown. if (q->isWindow() && !QApplication::testAttribute(Qt::AA_S60DontConstructApplicationPanes) - && !S60->buttonGroupContainer() && !S60->statusPane()) { - - if (!q->testAttribute(Qt::WA_DontShowOnScreen)) { - - // Create the status pane and CBA here - CEikAppUi *ui = static_cast(S60->appUi()); - MEikAppUiFactory *factory = CEikonEnv::Static()->AppUiFactory(); - - QT_TRAP_THROWING( - factory->CreateResourceIndependentFurnitureL(ui); - - CEikButtonGroupContainer *cba = CEikButtonGroupContainer::NewL(CEikButtonGroupContainer::ECba, - CEikButtonGroupContainer::EHorizontal,ui,R_AVKON_SOFTKEYS_EMPTY_WITH_IDS); - if (isFullscreen && !cbaRequested) - cba->MakeVisible(false); - - CEikButtonGroupContainer *oldCba = factory->SwapButtonGroup(cba); - Q_ASSERT(!oldCba); - S60->setButtonGroupContainer(cba); - - // If the creation of the first widget is delayed, for example by doing it - // inside the event loop, S60 somehow "forgets" to set the visibility of the - // toolbar (the three middle softkeys) when you flip the phone over, so we - // need to do it ourselves to avoid a "hole" in the application, even though - // Qt itself does not use the toolbar directly.. - CAknAppUi *appui = dynamic_cast(CEikonEnv::Static()->AppUi()); - if (appui) { - CAknToolbar *toolbar = appui->PopupToolbar(); - if (toolbar && !toolbar->IsVisible()) - toolbar->SetToolbarVisibility(ETrue); - } + && !q->testAttribute(Qt::WA_DontShowOnScreen) && !S60->screenFurnitureFullyCreated) { + // Create the status pane and CBA here if not yet done. These could be created earlier + // if application was launched in "App-Lite" version + if (!S60->buttonGroupContainer() && !S60->statusPane()) + S60->createStatusPaneAndCBA(); + + if (S60->buttonGroupContainer()) { + if (isFullscreen && !cbaRequested) + S60->buttonGroupContainer()->MakeVisible(false); + } + + // If the creation of the first widget is delayed, for example by doing it + // inside the event loop, S60 somehow "forgets" to set the visibility of the + // toolbar (the three middle softkeys) when you flip the phone over, so we + // need to do it ourselves to avoid a "hole" in the application, even though + // Qt itself does not use the toolbar directly.. + CAknAppUi *appui = dynamic_cast(CEikonEnv::Static()->AppUi()); + if (appui) { + CAknToolbar *toolbar = appui->PopupToolbar(); + if (toolbar && !toolbar->IsVisible()) + toolbar->SetToolbarVisibility(ETrue); + } - CEikMenuBar *menuBar = new(ELeave) CEikMenuBar; - menuBar->ConstructL(ui, 0, R_AVKON_MENUPANE_EMPTY); - menuBar->SetMenuType(CEikMenuBar::EMenuOptions); - S60->appUi()->AddToStackL(menuBar,ECoeStackPriorityMenu,ECoeStackFlagRefusesFocus); - - CEikMenuBar *oldMenu = factory->SwapMenuBar(menuBar); - Q_ASSERT(!oldMenu); - ) - - if (S60->statusPane()) { - // Use QDesktopWidget as the status pane observer to proxy for the AppUi. - // Can't use AppUi directly because it privately inherits from MEikStatusPaneObserver. - QSymbianControl *desktopControl = static_cast(QApplication::desktop()->winId()); - S60->statusPane()->SetObserver(desktopControl); - if (isFullscreen) { - const bool cbaVisible = S60->buttonGroupContainer() && S60->buttonGroupContainer()->IsVisible(); - S60->setStatusPaneAndButtonGroupVisibility(false, cbaVisible); - if (cbaVisible) { - // Fix window dimensions as without screen furniture they will have - // defaulted to full screen dimensions initially. - id->handleClientAreaChange(); - } + if (S60->statusPane()) { + if (isFullscreen) { + const bool cbaVisible = S60->buttonGroupContainer() && S60->buttonGroupContainer()->IsVisible(); + S60->setStatusPaneAndButtonGroupVisibility(false, cbaVisible); + if (cbaVisible) { + // Fix window dimensions as without screen furniture they will have + // defaulted to full screen dimensions initially. + id->handleClientAreaChange(); } } } + S60->screenFurnitureFullyCreated = true; } #endif -- cgit v0.12 From d704e61a8ac1fa9ff4aff05cc5d9bd94a777d04e Mon Sep 17 00:00:00 2001 From: Sami Merila Date: Fri, 14 Oct 2011 13:58:16 +0300 Subject: Show SaxBookmarks as maximized in Symbian Previously, SaxBookmarks was always shown as fullscreen app to allow filedialog to show up properly(QFileDialog requires a lot screen space). However, lately Qt for symbian was changed to use native file dialogs as a default. Therefore, the example app can nowadays shown as maximized. Task-number: QTBUG-21776 Reviewed-by: TrustMe --- examples/xml/saxbookmarks/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/xml/saxbookmarks/main.cpp b/examples/xml/saxbookmarks/main.cpp index 5d70ec8..ba0e1db 100644 --- a/examples/xml/saxbookmarks/main.cpp +++ b/examples/xml/saxbookmarks/main.cpp @@ -47,7 +47,7 @@ int main(int argc, char *argv[]) QApplication app(argc, argv); MainWindow mainWin; #if defined(Q_OS_SYMBIAN) - mainWin.showFullScreen(); + mainWin.showMaximized(); #else mainWin.show(); #endif -- cgit v0.12 From 5ad1d248aa02eb30dd4699b071f56fcef1412c94 Mon Sep 17 00:00:00 2001 From: mread Date: Fri, 14 Oct 2011 13:33:17 +0100 Subject: QtGui def file update For the addition of QApplicationPrivate::symbianHandleLiteModeStartup. Two other unfrozen functions also added. Task-number: QT-4933 Reviewed-by: TrustMe --- src/s60installs/bwins/QtGuiu.def | 3 +++ src/s60installs/eabi/QtGuiu.def | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/s60installs/bwins/QtGuiu.def b/src/s60installs/bwins/QtGuiu.def index 16de776..335b94f 100644 --- a/src/s60installs/bwins/QtGuiu.def +++ b/src/s60installs/bwins/QtGuiu.def @@ -13983,4 +13983,7 @@ EXPORTS ?qt_static_metacall@QShortcut@@CAXPAVQObject@@W4Call@QMetaObject@@HPAPAX@Z @ 13982 NONAME ; void QShortcut::qt_static_metacall(class QObject *, enum QMetaObject::Call, int, void * *) ?endOfLine@QTextEngine@@AAEHH@Z @ 13983 NONAME ; int QTextEngine::endOfLine(int) ?queryKeyboardModifiers@QApplication@@SA?AV?$QFlags@W4KeyboardModifier@Qt@@@@XZ @ 13984 NONAME ; class QFlags QApplication::queryKeyboardModifiers(void) + ?resetFontEngineCache@QTextEngine@@QAEXXZ @ 13985 NONAME ; void QTextEngine::resetFontEngineCache(void) + ?symbianHandleLiteModeStartup@QApplicationPrivate@@QAEXXZ @ 13986 NONAME ; void QApplicationPrivate::symbianHandleLiteModeStartup(void) + ?_q_cleanupWinIds@QWidgetPrivate@@QAEXXZ @ 13987 NONAME ; void QWidgetPrivate::_q_cleanupWinIds(void) diff --git a/src/s60installs/eabi/QtGuiu.def b/src/s60installs/eabi/QtGuiu.def index 4133773..3606f9c 100644 --- a/src/s60installs/eabi/QtGuiu.def +++ b/src/s60installs/eabi/QtGuiu.def @@ -12796,4 +12796,7 @@ EXPORTS _ZTV20QBlittablePixmapData @ 12795 NONAME _Zls6QDebugPK13QSymbianEvent @ 12796 NONAME _ZN12QApplication22queryKeyboardModifiersEv @ 12797 NONAME + _ZN11QTextEngine20resetFontEngineCacheEv @ 12798 NONAME + _ZN14QWidgetPrivate16_q_cleanupWinIdsEv @ 12799 NONAME + _ZN19QApplicationPrivate28symbianHandleLiteModeStartupEv @ 12800 NONAME -- cgit v0.12 From 001c01e91d9c6cc724a374fcb8371a0551b21958 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 17 Oct 2011 15:47:42 +0100 Subject: Symbian - Change working directory of applications in ROM Working directory (as opposed to applicationDirPath) was on the Z drive before, change it to be the same. Task-Number: QTBUG-22024 Reviewed-By: mread --- src/corelib/kernel/qcore_symbian_p.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/corelib/kernel/qcore_symbian_p.cpp b/src/corelib/kernel/qcore_symbian_p.cpp index 57ae2af..4f953a7 100644 --- a/src/corelib/kernel/qcore_symbian_p.cpp +++ b/src/corelib/kernel/qcore_symbian_p.cpp @@ -121,18 +121,17 @@ public: TInt err = iFs.CreatePrivatePath(sysdrive); if (err != KErrNone && err != KErrAlreadyExists) qWarning("Failed to create private path on system drive."); - //BC with 4.7: set working directory to same drive as application TFileName pfn = RProcess().FileName(); TInt drive; if (pfn.Length() > 0 && iFs.CharToDrive(pfn[0], drive) == KErrNone) { - // for system drive or rom based apps, leave the path on system drive + //BC with 4.7: create private path on application drive (except rom or system drive which is done above) if (drive != sysdrive && drive != EDriveZ) { err = iFs.CreatePrivatePath(drive); - if (err == KErrNone || err == KErrAlreadyExists) - iFs.SetSessionToPrivate(drive); - else + if (err != KErrNone && err != KErrAlreadyExists) qWarning("Failed to create private path on application drive."); } + //BC with 4.7: set working directory to same drive as application + iFs.SetSessionToPrivate(drive); } } -- cgit v0.12 From e5098123c12880d922923d1117f7b82995c6b5a0 Mon Sep 17 00:00:00 2001 From: aavit Date: Wed, 19 Oct 2011 14:02:24 +0200 Subject: Fixes: the png_handle_cHRM crash bug in bundled libpng 1.5.4 The PNG Development Group explains that libpng 1.5.4 (only) introduced a divide-by-zero bug in png_handle_cHRM(), which could lead to crashes (denial of service) for certain malformed PNGs. Ref. http://www.libpng.org/pub/png/libpng.html This commit contains the patch recommended by the PNG Development Group, ref. http://www.kb.cert.org/vuls/id/477046 Task-number: QTBUG-22168 (cherry picked from commit 55c2ea18c522bd8700f43884124e02b460cdb5e2) --- src/3rdparty/libpng/pngrutil.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/3rdparty/libpng/pngrutil.c b/src/3rdparty/libpng/pngrutil.c index 07e46e2..daf3c5e 100644 --- a/src/3rdparty/libpng/pngrutil.c +++ b/src/3rdparty/libpng/pngrutil.c @@ -1037,12 +1037,14 @@ png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) */ png_uint_32 w = y_red + y_green + y_blue; - png_ptr->rgb_to_gray_red_coeff = (png_uint_16)(((png_uint_32)y_red * - 32768)/w); - png_ptr->rgb_to_gray_green_coeff = (png_uint_16)(((png_uint_32)y_green - * 32768)/w); - png_ptr->rgb_to_gray_blue_coeff = (png_uint_16)(((png_uint_32)y_blue * - 32768)/w); + if (w != 0) { + png_ptr->rgb_to_gray_red_coeff = (png_uint_16)(((png_uint_32)y_red * + 32768)/w); + png_ptr->rgb_to_gray_green_coeff = (png_uint_16)(((png_uint_32)y_green + * 32768)/w); + png_ptr->rgb_to_gray_blue_coeff = (png_uint_16)(((png_uint_32)y_blue * + 32768)/w); + } } } #endif -- cgit v0.12 From 0375fff2b077ddd20a97c1b1c8d34f22553abe0c Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Fri, 21 Oct 2011 09:59:54 +0200 Subject: Fix performance regression on Mac OS X when creating/destroying QMutex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit cf17b743d2fe84ab259b7232ab07b58a1872e18e, which changed QMutex to use a Mach semaphore_t on Mac OS X. We now use pthread_mutex_t on Mac OS X as well. Contention performance is mostly unchanged, but the new constructionQMutex() benchmark added in this commit shows that creating/destroying a semaphore_t is about 20 times slower than pthread_mutex_t. Reviewed-by: Olivier Goffart Reviewed-by: João Abecasis --- src/corelib/thread/qmutex_p.h | 8 +--- src/corelib/thread/qmutex_unix.cpp | 50 +++------------------- .../corelib/thread/qmutex/tst_qmutex.cpp | 19 ++++++++ 3 files changed, 26 insertions(+), 51 deletions(-) diff --git a/src/corelib/thread/qmutex_p.h b/src/corelib/thread/qmutex_p.h index a9923c4..d2ffd28 100644 --- a/src/corelib/thread/qmutex_p.h +++ b/src/corelib/thread/qmutex_p.h @@ -58,10 +58,6 @@ #include #include -#if defined(Q_OS_MAC) -# include -#endif - #if defined(Q_OS_SYMBIAN) # include #endif @@ -83,9 +79,7 @@ public: Qt::HANDLE owner; uint count; -#if defined(Q_OS_MAC) - semaphore_t mach_semaphore; -#elif defined(Q_OS_UNIX) && !defined(Q_OS_LINUX) && !defined(Q_OS_SYMBIAN) +#if defined(Q_OS_UNIX) && !defined(Q_OS_LINUX) && !defined(Q_OS_SYMBIAN) volatile bool wakeup; pthread_mutex_t mutex; pthread_cond_t cond; diff --git a/src/corelib/thread/qmutex_unix.cpp b/src/corelib/thread/qmutex_unix.cpp index 2a9d23c..790fad3 100644 --- a/src/corelib/thread/qmutex_unix.cpp +++ b/src/corelib/thread/qmutex_unix.cpp @@ -65,7 +65,7 @@ QT_BEGIN_NAMESPACE -#if !defined(Q_OS_MAC) && !defined(Q_OS_LINUX) +#if !defined(Q_OS_LINUX) static void report_error(int code, const char *where, const char *what) { if (code != 0) @@ -77,11 +77,7 @@ static void report_error(int code, const char *where, const char *what) QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode) : QMutexData(mode), maximumSpinTime(MaximumSpinTimeThreshold), averageWaitTime(0), owner(0), count(0) { -#if defined(Q_OS_MAC) - kern_return_t r = semaphore_create(mach_task_self(), &mach_semaphore, SYNC_POLICY_FIFO, 0); - if (r != KERN_SUCCESS) - qWarning("QMutex: failed to create semaphore, error %d", r); -#elif !defined(Q_OS_LINUX) +#if !defined(Q_OS_LINUX) wakeup = false; report_error(pthread_mutex_init(&mutex, NULL), "QMutex", "mutex init"); report_error(pthread_cond_init(&cond, NULL), "QMutex", "cv init"); @@ -90,47 +86,13 @@ QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode) QMutexPrivate::~QMutexPrivate() { -#if defined(Q_OS_MAC) - kern_return_t r = semaphore_destroy(mach_task_self(), mach_semaphore); - if (r != KERN_SUCCESS) - qWarning("QMutex: failed to destroy semaphore, error %d", r); -#elif !defined(Q_OS_LINUX) +#if !defined(Q_OS_LINUX) report_error(pthread_cond_destroy(&cond), "QMutex", "cv destroy"); report_error(pthread_mutex_destroy(&mutex), "QMutex", "mutex destroy"); #endif } -#if defined(Q_OS_MAC) - -bool QMutexPrivate::wait(int timeout) -{ - if (contenders.fetchAndAddAcquire(1) == 0) { - // lock acquired without waiting - return true; - } - kern_return_t r; - if (timeout < 0) { - do { - r = semaphore_wait(mach_semaphore); - } while (r == KERN_ABORTED); - if (r != KERN_SUCCESS) - qWarning("QMutex: infinite wait failed, error %d", r); - } else { - mach_timespec_t ts; - ts.tv_nsec = ((timeout % 1000) * 1000) * 1000; - ts.tv_sec = (timeout / 1000); - r = semaphore_timedwait(mach_semaphore, ts); - } - contenders.deref(); - return r == KERN_SUCCESS; -} - -void QMutexPrivate::wakeUp() -{ - semaphore_signal(mach_semaphore); -} - -#elif defined(Q_OS_LINUX) +#if defined(Q_OS_LINUX) static inline int _q_futex(volatile int *addr, int op, int val, const struct timespec *timeout, int *addr2, int val2) { @@ -174,7 +136,7 @@ void QMutexPrivate::wakeUp() (void) _q_futex(&contenders._q_value, FUTEX_WAKE, 1, 0, 0, 0); } -#else // !Q_OS_MAC && !Q_OS_LINUX +#else // !Q_OS_LINUX bool QMutexPrivate::wait(int timeout) { @@ -221,7 +183,7 @@ void QMutexPrivate::wakeUp() report_error(pthread_mutex_unlock(&mutex), "QMutex::unlock", "mutex unlock"); } -#endif // !Q_OS_MAC && !Q_OS_LINUX +#endif // !Q_OS_LINUX QT_END_NAMESPACE diff --git a/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp b/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp index 05a1575..eca38b6 100644 --- a/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp +++ b/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp @@ -128,7 +128,9 @@ private slots: void noThread_data(); void noThread(); + void constructionNative(); void uncontendedNative(); + void constructionQMutex(); void uncontendedQMutex(); void uncontendedQMutexLocker(); @@ -205,6 +207,15 @@ void tst_QMutex::noThread() QCOMPARE(int(count), N); } +void tst_QMutex::constructionNative() +{ + QBENCHMARK { + NativeMutexType mutex; + NativeMutexInitialize(&mutex); + NativeMutexDestroy(&mutex); + } +} + void tst_QMutex::uncontendedNative() { NativeMutexType mutex; @@ -216,6 +227,14 @@ void tst_QMutex::uncontendedNative() NativeMutexDestroy(&mutex); } +void tst_QMutex::constructionQMutex() +{ + QBENCHMARK { + QMutex mutex; + Q_UNUSED(mutex); + } +} + void tst_QMutex::uncontendedQMutex() { QMutex mutex; -- cgit v0.12 From 19bd31fc84cc4916aef4835429fc4a55e85d0c28 Mon Sep 17 00:00:00 2001 From: Richard Moore Date: Wed, 19 Oct 2011 11:40:57 +0200 Subject: Add the ability to enable various SSL bug workarounds. There are lots of buggy SSL servers around and to connect to them you need to disable various features. This commit adds the ability to disable the SSL ticket extension, the ability to disable the insertion of empty fragments, and the ability to disable compression. Task-number: QTBUG-21906 Change-Id: I3e1d0347a46e9030b889bbf15b2aad19b8513b73 Merge-request: 68 Reviewed-by: Peter Hartmann (cherry picked from commit 78d02e93aca5325fc5be9bfd275862795207abaa) (commit was cherry-picked from Qt 5 to 4.8 after agreeing with the author because the merge request was filed against Qt 5.) --- src/network/ssl/qssl.cpp | 30 +++++++++++ src/network/ssl/qssl.h | 11 ++++ src/network/ssl/qsslconfiguration.cpp | 29 +++++++++- src/network/ssl/qsslconfiguration.h | 4 ++ src/network/ssl/qsslconfiguration_p.h | 2 + src/network/ssl/qsslsocket.cpp | 2 + src/network/ssl/qsslsocket_openssl.cpp | 33 +++++++++--- tests/manual/qssloptions/main.cpp | 92 ++++++++++++++++++++++++++++++++ tests/manual/qssloptions/qssloptions.pro | 12 +++++ 9 files changed, 206 insertions(+), 9 deletions(-) create mode 100644 tests/manual/qssloptions/main.cpp create mode 100644 tests/manual/qssloptions/qssloptions.pro diff --git a/src/network/ssl/qssl.cpp b/src/network/ssl/qssl.cpp index 586c894..08a05ff 100644 --- a/src/network/ssl/qssl.cpp +++ b/src/network/ssl/qssl.cpp @@ -120,4 +120,34 @@ QT_BEGIN_NAMESPACE the correct setting for your protocol. */ +/*! + \enum QSsl::SslOption + + Describes the options that can be used to control the details of + SSL behaviour. These options are generally used to turn features off + to work around buggy servers. + + \value SslOptionDisableEmptyFragments Disables the insertion of empty + fragments into the data when using block ciphers. When enabled, this + prevents some attacks (such as the BEAST attack), however it is + incompatible with some servers. + \value SslOptionDisableTickets Disables the SSL session ticket + extension. This can cause slower connection setup, however some servers + are not compatible with the extension. + \value SslOptionDisableCompression Disables the SSL compression + extension. When enabled, this allows the data being passed over SSL to + be compressed, however some servers are not compatible with this + extension. + \value SslOptionDisableServerNameIndication Disables the SSL server + name indication extension. When enabled, this tells the server the virtual + host being accessed allowing it to respond with the correct certificate. + + By default, SslOptionDisableEmptyFragments is turned on since this causes + problems with a large number of servers, but the other options are disabled. + + Note: Availability of above options depends on the version of the SSL + backend in use. +*/ + + QT_END_NAMESPACE diff --git a/src/network/ssl/qssl.h b/src/network/ssl/qssl.h index 2ecd1c3..453d4da 100644 --- a/src/network/ssl/qssl.h +++ b/src/network/ssl/qssl.h @@ -44,6 +44,7 @@ #define QSSL_H #include +#include QT_BEGIN_HEADER @@ -81,8 +82,18 @@ namespace QSsl { SecureProtocols, UnknownProtocol = -1 }; + + enum SslOption { + SslOptionDisableEmptyFragments = 0x01, + SslOptionDisableSessionTickets = 0x02, + SslOptionDisableCompression = 0x04, + SslOptionDisableServerNameIndication = 0x08 + }; + Q_DECLARE_FLAGS(SslOptions, SslOption) } +Q_DECLARE_OPERATORS_FOR_FLAGS(QSsl::SslOptions) + QT_END_NAMESPACE QT_END_HEADER diff --git a/src/network/ssl/qsslconfiguration.cpp b/src/network/ssl/qsslconfiguration.cpp index 69d3b66..e24076e 100644 --- a/src/network/ssl/qsslconfiguration.cpp +++ b/src/network/ssl/qsslconfiguration.cpp @@ -167,7 +167,8 @@ bool QSslConfiguration::operator==(const QSslConfiguration &other) const d->caCertificates == other.d->caCertificates && d->protocol == other.d->protocol && d->peerVerifyMode == other.d->peerVerifyMode && - d->peerVerifyDepth == other.d->peerVerifyDepth; + d->peerVerifyDepth == other.d->peerVerifyDepth && + d->sslOptions == other.d->sslOptions; } /*! @@ -199,7 +200,8 @@ bool QSslConfiguration::isNull() const d->localCertificate.isNull() && d->privateKey.isNull() && d->peerCertificate.isNull() && - d->peerCertificateChain.count() == 0); + d->peerCertificateChain.count() == 0 && + d->sslOptions == 0); } /*! @@ -507,6 +509,29 @@ void QSslConfiguration::setCaCertificates(const QList &certific } /*! + Enables or disables an SSL compatibility option. + + \sa testSSlOption() +*/ +void QSslConfiguration::setSslOption(QSsl::SslOption option, bool on) +{ + if (on) + d->sslOptions |= option; + else + d->sslOptions &= ~option; +} + +/*! + Returns true if the specified SSL compatibility option is enabled. + + \sa testSSlOption() +*/ +bool QSslConfiguration::testSslOption(QSsl::SslOption option) const +{ + return d->sslOptions & option; +} + +/*! Returns the default SSL configuration to be used in new SSL connections. diff --git a/src/network/ssl/qsslconfiguration.h b/src/network/ssl/qsslconfiguration.h index 258b454..ff8c8fc 100644 --- a/src/network/ssl/qsslconfiguration.h +++ b/src/network/ssl/qsslconfiguration.h @@ -59,6 +59,7 @@ #include #include +#include QT_BEGIN_HEADER @@ -118,6 +119,9 @@ public: QList caCertificates() const; void setCaCertificates(const QList &certificates); + void setSslOption(QSsl::SslOption option, bool on); + bool testSslOption(QSsl::SslOption option) const; + static QSslConfiguration defaultConfiguration(); static void setDefaultConfiguration(const QSslConfiguration &configuration); diff --git a/src/network/ssl/qsslconfiguration_p.h b/src/network/ssl/qsslconfiguration_p.h index af80e4c..b83edb9 100644 --- a/src/network/ssl/qsslconfiguration_p.h +++ b/src/network/ssl/qsslconfiguration_p.h @@ -98,6 +98,8 @@ public: QSslSocket::PeerVerifyMode peerVerifyMode; int peerVerifyDepth; + QSsl::SslOptions sslOptions; + // in qsslsocket.cpp: static QSslConfiguration defaultConfiguration(); static void setDefaultConfiguration(const QSslConfiguration &configuration); diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index df61fb6..3ac8f18 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -896,6 +896,7 @@ void QSslSocket::setSslConfiguration(const QSslConfiguration &configuration) d->configuration.peerVerifyDepth = configuration.peerVerifyDepth(); d->configuration.peerVerifyMode = configuration.peerVerifyMode(); d->configuration.protocol = configuration.protocol(); + d->configuration.sslOptions = configuration.d->sslOptions; d->allowRootCertOnDemandLoading = false; } @@ -2027,6 +2028,7 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri ptr->protocol = global->protocol; ptr->peerVerifyMode = global->peerVerifyMode; ptr->peerVerifyDepth = global->peerVerifyDepth; + ptr->sslOptions = global->sslOptions; } /*! diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index 8e53974..3942209 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -285,12 +285,29 @@ init_context: return false; } - // Enable all bug workarounds. - if (configuration.protocol == QSsl::TlsV1SslV3 || configuration.protocol == QSsl::SecureProtocols) { - q_SSL_CTX_set_options(ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2); - } else { - q_SSL_CTX_set_options(ctx, SSL_OP_ALL); - } + // Enable bug workarounds. + long options; + if (configuration.protocol == QSsl::TlsV1SslV3 || configuration.protocol == QSsl::SecureProtocols) + options = SSL_OP_ALL|SSL_OP_NO_SSLv2; + else + options = SSL_OP_ALL; + + // This option is disabled by default, so we need to be able to clear it + if (configuration.sslOptions & QSsl::SslOptionDisableEmptyFragments) + options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; + else + options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; + +#ifdef SSL_OP_NO_TICKET + if (configuration.sslOptions & QSsl::SslOptionDisableSessionTickets) + options |= SSL_OP_NO_TICKET; +#endif +#ifdef SSL_OP_NO_COMPRESSION + if (configuration.sslOptions & QSsl::SslOptionDisableCompression) + options |= SSL_OP_NO_COMPRESSION; +#endif + + q_SSL_CTX_set_options(ctx, options); // Initialize ciphers QByteArray cipherString; @@ -419,7 +436,9 @@ init_context: tlsHostName = hostName; QByteArray ace = QUrl::toAce(tlsHostName); // only send the SNI header if the URL is valid and not an IP - if (!ace.isEmpty() && !QHostAddress().setAddress(tlsHostName)) { + if (!ace.isEmpty() + && !QHostAddress().setAddress(tlsHostName) + && !(configuration.sslOptions & QSsl::SslOptionDisableServerNameIndication)) { #if OPENSSL_VERSION_NUMBER >= 0x10000000L if (!q_SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, ace.data())) #else diff --git a/tests/manual/qssloptions/main.cpp b/tests/manual/qssloptions/main.cpp new file mode 100644 index 0000000..6f2f361 --- /dev/null +++ b/tests/manual/qssloptions/main.cpp @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + + if (argc < 3) { + QTextStream out(stdout); + out << "Usage: " << argv[0] << " host port [options]" << endl; + out << "The options can be one or more of the following:" << endl; + out << "enable_empty_fragments" << endl; + out << "disable_session_tickets" << endl; + out << "disable_compression" << endl; + out << "disable_sni" << endl; + return 1; + } + + QString host = QString::fromLocal8Bit(argv[1]); + int port = QString::fromLocal8Bit(argv[2]).toInt(); + + QSslConfiguration config = QSslConfiguration::defaultConfiguration(); + + for (int i=3; i < argc; i++) { + QString option = QString::fromLocal8Bit(argv[i]); + + if (option == QLatin1String("enable_empty_fragments")) + config.setSslOption(QSsl::SslOptionDisableEmptyFragments, false); + else if (option == QLatin1String("disable_session_tickets")) + config.setSslOption(QSsl::SslOptionDisableSessionTickets, true); + else if (option == QLatin1String("disable_compression")) + config.setSslOption(QSsl::SslOptionDisableCompression, true); + else if (option == QLatin1String("disable_sni")) + config.setSslOption(QSsl::SslOptionDisableServerNameIndication, true); + } + + QSslConfiguration::setDefaultConfiguration(config); + + QSslSocket socket; + //socket.setSslConfiguration(config); + socket.connectToHostEncrypted(host, port); + + if ( !socket.waitForEncrypted() ) { + qDebug() << socket.errorString(); + return 1; + } + + return 0; +} diff --git a/tests/manual/qssloptions/qssloptions.pro b/tests/manual/qssloptions/qssloptions.pro new file mode 100644 index 0000000..c1c8446 --- /dev/null +++ b/tests/manual/qssloptions/qssloptions.pro @@ -0,0 +1,12 @@ +load(qttest_p4) +TEMPLATE = app +TARGET = tst_qssloptions +DEPENDPATH += . +INCLUDEPATH += . + +QT -= gui +QT += network + +#CONFIG += release + +SOURCES += main.cpp -- cgit v0.12