Add user configurable mask generation
authorKurt Pattyn <pattyn.kurt@gmail.com>
Wed, 12 Feb 2014 14:17:58 +0000 (15:17 +0100)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Sat, 15 Feb 2014 13:40:02 +0000 (14:40 +0100)
Created a QMaskGenerator abstract base class to serve as a basis for
user specific mask generators. Added the possibility to override the
default mask generation in QWebSocket.

Change-Id: Iaa02b44193f854d103b5f352617789175fe61f89
Reviewed-by: Kurt Pattyn <pattyn.kurt@gmail.com>
12 files changed:
src/websockets/qdefaultmaskgenerator_p.cpp [new file with mode: 0644]
src/websockets/qdefaultmaskgenerator_p.h [new file with mode: 0644]
src/websockets/qmaskgenerator.cpp [new file with mode: 0644]
src/websockets/qmaskgenerator.h [new file with mode: 0644]
src/websockets/qwebsocket.cpp
src/websockets/qwebsocket.h
src/websockets/qwebsocket_p.cpp
src/websockets/qwebsocket_p.h
src/websockets/websockets.pro
tests/auto/auto.pro
tests/auto/qdefaultmaskgenerator/qdefaultmaskgenerator.pro [new file with mode: 0644]
tests/auto/qdefaultmaskgenerator/tst_defaultmaskgenerator.cpp [new file with mode: 0644]

diff --git a/src/websockets/qdefaultmaskgenerator_p.cpp b/src/websockets/qdefaultmaskgenerator_p.cpp
new file mode 100644 (file)
index 0000000..2d8b1a2
--- /dev/null
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtWebSockets module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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, Digia gives you certain additional
+** rights.  These rights are described in the Digia 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.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdefaultmaskgenerator_p.h"
+#include <QDateTime>
+#include <limits>
+
+QT_BEGIN_NAMESPACE
+
+QDefaultMaskGenerator::QDefaultMaskGenerator(QObject *parent) :
+    QMaskGenerator(parent)
+{
+}
+
+QDefaultMaskGenerator::~QDefaultMaskGenerator()
+{
+}
+
+bool QDefaultMaskGenerator::seed()
+{
+    qsrand(static_cast<uint>(QDateTime::currentMSecsSinceEpoch()));
+    return true;
+}
+
+quint32 QDefaultMaskGenerator::nextMask()
+{
+    return quint32((double(qrand()) / RAND_MAX) * std::numeric_limits<quint32>::max());
+}
+
+QT_END_NAMESPACE
diff --git a/src/websockets/qdefaultmaskgenerator_p.h b/src/websockets/qdefaultmaskgenerator_p.h
new file mode 100644 (file)
index 0000000..5050a4a
--- /dev/null
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtWebSockets module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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, Digia gives you certain additional
+** rights.  These rights are described in the Digia 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.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDEFAULTMASKGENERATOR_P_H
+#define QDEFAULTMASKGENERATOR_P_H
+
+//
+//  W A R N I N G
+//  -------------
+//
+// This file is not part of the Qt API.  It exists purely as an
+// implementation detail.  This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtWebSockets/qmaskgenerator.h>
+
+QT_BEGIN_NAMESPACE
+class QObject;
+
+class Q_AUTOTEST_EXPORT QDefaultMaskGenerator : public QMaskGenerator
+{
+    Q_DISABLE_COPY(QDefaultMaskGenerator)
+
+public:
+    explicit QDefaultMaskGenerator(QObject *parent = 0);
+    virtual ~QDefaultMaskGenerator();
+
+    bool seed() Q_DECL_NOEXCEPT Q_DECL_OVERRIDE;
+    quint32 nextMask() Q_DECL_NOEXCEPT Q_DECL_OVERRIDE;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDEFAULTMASKGENERATOR_P_H
diff --git a/src/websockets/qmaskgenerator.cpp b/src/websockets/qmaskgenerator.cpp
new file mode 100644 (file)
index 0000000..9c678b5
--- /dev/null
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtWebSockets module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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, Digia gives you certain additional
+** rights.  These rights are described in the Digia 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.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+    \class QMaskGenerator
+    The QMaskGenerator class provides an abstract base for custom 32-bit mask generators.
+
+    The WebSockets specification as outlined in {http://tools.ietf.org/html/rfc6455}{RFC 6455}
+    requires that all communication from client to server must be masked. This is to prevent
+    malicious scripts to attack bad behaving proxies.
+    For more information about the importance of good masking,
+    see \l {http://w2spconf.com/2011/papers/websocket.pdf}.
+    By default QWebSocket uses the cryptographically insecure qrand() function.
+    The best measure against attacks mentioned in the document above,
+    is to use QWebSocket over a secure connection (\e wss://).
+    In general, always be careful to not have 3rd party script access to
+    a QWebSocket in your application.
+*/
+
+/*!
+    \fn bool QMaskGenerator::seed()
+
+    Initializes the QMaskGenerator by seeding the randomizer.
+    When seed() is not called, it depends on the specific implementation of a subclass if
+    a default seed is used or no seed is used at all.
+*/
+
+/*!
+    \fn quint32 QMaskGenerator::nextMask()
+
+    Returns a new random 32-bit mask. The randomness depends on the RNG used to created the
+    mask.
+*/
+
+#include "qmaskgenerator.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+    Creates a new QMaskGenerator object.
+ */
+QMaskGenerator::QMaskGenerator(QObject *parent) :
+    QObject(parent)
+{
+}
+
+/*!
+    Destroys the QMaskGenerator object.
+ */
+QMaskGenerator::~QMaskGenerator()
+{}
+
+QT_END_NAMESPACE
diff --git a/src/websockets/qmaskgenerator.h b/src/websockets/qmaskgenerator.h
new file mode 100644 (file)
index 0000000..00cadba
--- /dev/null
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtWebSockets module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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, Digia gives you certain additional
+** rights.  These rights are described in the Digia 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.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMASKGENERATOR_H
+#define QMASKGENERATOR_H
+
+#include <QObject>
+#include "QtWebSockets/qwebsockets_global.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q_WEBSOCKETS_EXPORT QMaskGenerator : public QObject
+{
+    Q_DISABLE_COPY(QMaskGenerator)
+
+public:
+    explicit QMaskGenerator(QObject *parent = Q_NULLPTR);
+    virtual ~QMaskGenerator();
+
+    virtual bool seed() = 0;
+    virtual quint32 nextMask() = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // QMASKGENERATOR_H
index 0a0c420..ca8ae08 100644 (file)
     \l {http://tools.ietf.org/html/rfc6455#page-39} {extensions} and
     \l {http://tools.ietf.org/html/rfc6455#page-12} {subprotocols}.
 
-    QWebSocket only supports version 13 of the WebSocket protocol, as outlined in RFC 6455.
+    QWebSocket only supports version 13 of the WebSocket protocol, as outlined in
+    \l {http://tools.ietf.org/html/rfc6455}{RFC 6455}.
+
+    \warning To generate masks, this implementation of WebSockets uses the cryptographically
+    insecure qrand() function.
+    For more information about the importance of good masking,
+    see \l {http://w2spconf.com/2011/papers/websocket.pdf}.
+    The best measure against attacks mentioned in the document above,
+    is to use QWebSocket over a secure connection (\e wss://).
+    In general, always be careful to not have 3rd party script access to
+    a QWebSocket in your application.
 
     \sa QAbstractSocket, QTcpSocket
 
@@ -621,6 +631,26 @@ void QWebSocket::setProxy(const QNetworkProxy &networkProxy)
 #endif
 
 /*!
+    Sets the generator to use for creating masks to \a maskGenerator.
+    The default QWebSocket generator can be reset by supplying a \e Q_NULLPTR.
+    The mask generator can be changed at any time, even while the connection is open.
+ */
+void QWebSocket::setMaskGenerator(const QMaskGenerator *maskGenerator)
+{
+    Q_D(QWebSocket);
+    d->setMaskGenerator(maskGenerator);
+}
+
+/*!
+    Returns the mask generator that is currently used by this QWebSocket.
+ */
+const QMaskGenerator *QWebSocket::maskGenerator() const
+{
+    Q_D(const QWebSocket);
+    return d->maskGenerator();
+}
+
+/*!
     Returns the size in bytes of the readbuffer that is used by the socket.
  */
 qint64 QWebSocket::readBufferSize() const
index 660b3a3..bb9f2db 100644 (file)
@@ -57,6 +57,7 @@ QT_BEGIN_NAMESPACE
 
 class QTcpSocket;
 class QWebSocketPrivate;
+class QMaskGenerator;
 
 class Q_WEBSOCKETS_EXPORT QWebSocket : public QObject
 {
@@ -85,6 +86,8 @@ public:
     QNetworkProxy proxy() const;
     void setProxy(const QNetworkProxy &networkProxy);
 #endif
+    void setMaskGenerator(const QMaskGenerator *maskGenerator);
+    const QMaskGenerator *maskGenerator() const;
     qint64 readBufferSize() const;
     void setReadBufferSize(qint64 size);
 
index 338e581..bff060f 100644 (file)
@@ -44,6 +44,7 @@
 #include "qwebsocketprotocol_p.h"
 #include "qwebsockethandshakerequest_p.h"
 #include "qwebsockethandshakeresponse_p.h"
+#include "qdefaultmaskgenerator_p.h"
 
 #include <QtCore/QUrl>
 #include <QtNetwork/QAuthenticator>
@@ -109,7 +110,9 @@ QWebSocketPrivate::QWebSocketPrivate(const QString &origin, QWebSocketProtocol::
     m_closeReason(),
     m_pingTimer(),
     m_dataProcessor(),
-    m_configuration()
+    m_configuration(),
+    m_pMaskGenerator(&m_defaultMaskGenerator),
+    m_defaultMaskGenerator()
 {
 }
 
@@ -139,7 +142,9 @@ QWebSocketPrivate::QWebSocketPrivate(QTcpSocket *pTcpSocket, QWebSocketProtocol:
     m_closeReason(),
     m_pingTimer(),
     m_dataProcessor(),
-    m_configuration()
+    m_configuration(),
+    m_pMaskGenerator(&m_defaultMaskGenerator),
+    m_defaultMaskGenerator()
 {
 }
 
@@ -149,8 +154,9 @@ QWebSocketPrivate::QWebSocketPrivate(QTcpSocket *pTcpSocket, QWebSocketProtocol:
 void QWebSocketPrivate::init()
 {
     Q_ASSERT(q_ptr);
-    //TODO: need a better randomizer
-    qsrand(static_cast<uint>(QDateTime::currentMSecsSinceEpoch()));
+    Q_ASSERT(m_pMaskGenerator);
+
+    m_pMaskGenerator->seed();
 
     if (m_pSocket) {
         makeConnections(m_pSocket.data());
@@ -762,20 +768,11 @@ qint64 QWebSocketPrivate::doWriteFrames(const QByteArray &data, bool isBinary)
 }
 
 /*!
- * \internal
- */
-quint32 QWebSocketPrivate::generateRandomNumber() const
-{
-    //TODO: need a better randomizer
-    return quint32((double(qrand()) / RAND_MAX) * std::numeric_limits<quint32>::max());
-}
-
-/*!
     \internal
  */
 quint32 QWebSocketPrivate::generateMaskingKey() const
 {
-    return generateRandomNumber();
+    return m_pMaskGenerator->nextMask();
 }
 
 /*!
@@ -786,7 +783,7 @@ QByteArray QWebSocketPrivate::generateKey() const
     QByteArray key;
 
     for (int i = 0; i < 4; ++i) {
-        const quint32 tmp = generateRandomNumber();
+        const quint32 tmp = m_pMaskGenerator->nextMask();
         key.append(static_cast<const char *>(static_cast<const void *>(&tmp)), sizeof(quint32));
     }
 
@@ -1235,6 +1232,26 @@ void QWebSocketPrivate::setProxy(const QNetworkProxy &networkProxy)
 /*!
     \internal
  */
+void QWebSocketPrivate::setMaskGenerator(const QMaskGenerator *maskGenerator)
+{
+    if (!maskGenerator)
+        m_pMaskGenerator = &m_defaultMaskGenerator;
+    else if (maskGenerator != m_pMaskGenerator)
+        m_pMaskGenerator = const_cast<QMaskGenerator *>(maskGenerator);
+}
+
+/*!
+    \internal
+ */
+const QMaskGenerator *QWebSocketPrivate::maskGenerator() const
+{
+    Q_ASSERT(m_pMaskGenerator);
+    return m_pMaskGenerator;
+}
+
+/*!
+    \internal
+ */
 qint64 QWebSocketPrivate::readBufferSize() const
 {
     return m_readBufferSize;
index 3bd9918..c1128c5 100644 (file)
@@ -68,6 +68,7 @@
 
 #include "qwebsocketprotocol.h"
 #include "qwebsocketdataprocessor_p.h"
+#include "qdefaultmaskgenerator_p.h"
 
 QT_BEGIN_NAMESPACE
 
@@ -75,6 +76,7 @@ class QWebSocketHandshakeRequest;
 class QWebSocketHandshakeResponse;
 class QTcpSocket;
 class QWebSocket;
+class QMaskGenerator;
 
 struct QWebSocketConfiguration
 {
@@ -122,6 +124,8 @@ public:
     QNetworkProxy proxy() const;
     void setProxy(const QNetworkProxy &networkProxy);
 #endif
+    void setMaskGenerator(const QMaskGenerator *maskGenerator);
+    const QMaskGenerator *maskGenerator() const;
     qint64 readBufferSize() const;
     void resume();
     void setPauseMode(QAbstractSocket::PauseModes pauseMode);
@@ -195,7 +199,6 @@ private:
 
     quint32 generateMaskingKey() const;
     QByteArray generateKey() const;
-    quint32 generateRandomNumber() const;
     qint64 writeFrames(const QList<QByteArray> &frames) Q_REQUIRED_RESULT;
     qint64 writeFrame(const QByteArray &frame) Q_REQUIRED_RESULT;
 
@@ -226,6 +229,9 @@ private:
     QWebSocketDataProcessor m_dataProcessor;
     QWebSocketConfiguration m_configuration;
 
+    QMaskGenerator *m_pMaskGenerator;
+    QDefaultMaskGenerator m_defaultMaskGenerator;
+
     friend class QWebSocketServerPrivate;
 };
 
index 04bee8e..99e84b6 100644 (file)
@@ -1,7 +1,7 @@
 load(qt_build_config)
 TARGET = QtWebSockets
 
-QT = core network core-private
+QT = core network core-private sql
 
 TEMPLATE = lib
 
@@ -17,7 +17,8 @@ PUBLIC_HEADERS += \
     $$PWD/qwebsocket.h \
     $$PWD/qwebsocketserver.h \
     $$PWD/qwebsocketprotocol.h \
-    $$PWD/qwebsocketcorsauthenticator.h
+    $$PWD/qwebsocketcorsauthenticator.h \
+    $$PWD/qmaskgenerator.h
 
 PRIVATE_HEADERS += \
     $$PWD/qwebsocket_p.h \
@@ -27,7 +28,8 @@ PRIVATE_HEADERS += \
     $$PWD/qwebsockethandshakeresponse_p.h \
     $$PWD/qwebsocketdataprocessor_p.h \
     $$PWD/qwebsocketcorsauthenticator_p.h \
-    $$PWD/qwebsocketframe_p.h
+    $$PWD/qwebsocketframe_p.h \
+    $$PWD/qdefaultmaskgenerator_p.h
 
 SOURCES += \
     $$PWD/qwebsocket.cpp \
@@ -39,7 +41,9 @@ SOURCES += \
     $$PWD/qwebsockethandshakeresponse.cpp \
     $$PWD/qwebsocketdataprocessor.cpp \
     $$PWD/qwebsocketcorsauthenticator.cpp \
-    $$PWD/qwebsocketframe.cpp
+    $$PWD/qwebsocketframe.cpp \
+    $$PWD/qmaskgenerator.cpp \
+    $$PWD/qdefaultmaskgenerator_p.cpp
 
 contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) {
     SOURCES += $$PWD/qsslserver.cpp
index 34b232b..31900a4 100644 (file)
@@ -7,7 +7,8 @@ contains(QT_CONFIG, private_tests): SUBDIRS += \
    websocketprotocol \
    dataprocessor \
    websocketframe \
-   handshakerequest
+   handshakerequest \
+   qdefaultmaskgenerator
 
 SUBDIRS += \
     qwebsocket \
diff --git a/tests/auto/qdefaultmaskgenerator/qdefaultmaskgenerator.pro b/tests/auto/qdefaultmaskgenerator/qdefaultmaskgenerator.pro
new file mode 100644 (file)
index 0000000..1ddccb3
--- /dev/null
@@ -0,0 +1,14 @@
+CONFIG += console
+CONFIG += testcase c++11
+CONFIG -= app_bundle
+
+TEMPLATE = app
+
+TARGET = tst_defaultmaskgenerator
+
+QT = core testlib websockets websockets-private
+
+SOURCES += tst_defaultmaskgenerator.cpp
+
+requires(contains(QT_CONFIG, private_tests))
+DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
diff --git a/tests/auto/qdefaultmaskgenerator/tst_defaultmaskgenerator.cpp b/tests/auto/qdefaultmaskgenerator/tst_defaultmaskgenerator.cpp
new file mode 100644 (file)
index 0000000..46e6d61
--- /dev/null
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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, Digia gives you certain additional
+** rights.  These rights are described in the Digia 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.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtTest/QtTest>
+#include <QtTest/qtestcase.h>
+#include <QtTest/QSignalSpy>
+#include <QtCore/QBuffer>
+#include <QtCore/QByteArray>
+#include <QtCore/QDebug>
+
+#include "private/qdefaultmaskgenerator_p.h"
+
+QT_USE_NAMESPACE
+
+class tst_QDefaultMaskGenerator : public QObject
+{
+    Q_OBJECT
+
+public:
+    tst_QDefaultMaskGenerator();
+
+private Q_SLOTS:
+    void initTestCase();
+    void cleanupTestCase();
+    void init();
+    void cleanup();
+
+    void tst_randomnessWithoutSeed();
+    void tst_randomnessWithSeed();
+
+private:
+};
+
+
+
+tst_QDefaultMaskGenerator::tst_QDefaultMaskGenerator()
+{
+}
+
+void tst_QDefaultMaskGenerator::initTestCase()
+{
+}
+
+void tst_QDefaultMaskGenerator::cleanupTestCase()
+{
+}
+
+void tst_QDefaultMaskGenerator::init()
+{
+}
+
+void tst_QDefaultMaskGenerator::cleanup()
+{
+}
+
+void tst_QDefaultMaskGenerator::tst_randomnessWithoutSeed()
+{
+    //generate two series of data, and see if they differ
+    {
+        QDefaultMaskGenerator generator;
+
+        QVector<quint32> series1, series2;
+        for (int i = 0; i < 1000; ++i)
+            series1 << generator.nextMask();
+        for (int i = 0; i < 1000; ++i)
+            series2 << generator.nextMask();
+
+        QVERIFY(series1 != series2);
+    }
+}
+
+void tst_QDefaultMaskGenerator::tst_randomnessWithSeed()
+{
+    //generate two series of data, and see if they differ
+    //the generator is seeded
+    {
+        QDefaultMaskGenerator generator;
+        generator.seed();
+
+        QVector<quint32> series1, series2;
+        for (int i = 0; i < 1000; ++i)
+            series1 << generator.nextMask();
+        for (int i = 0; i < 1000; ++i)
+            series2 << generator.nextMask();
+
+        QVERIFY(series1 != series2);
+    }
+    //generates two series of data with 2 distinct generators
+    //both generators are seeded
+    {
+        QDefaultMaskGenerator generator1, generator2;
+        generator1.seed();
+        generator2.seed();
+
+        QVector<quint32> series1, series2;
+        for (int i = 0; i < 1000; ++i) {
+            series1 << generator1.nextMask();
+            series2 << generator2.nextMask();
+        }
+
+        QVERIFY(series1 != series2);
+    }
+    //generates two series of data with 2 distinct generators
+    //only one of the two is seeded
+    {
+        QDefaultMaskGenerator generator1, generator2;
+        generator1.seed();
+
+        QVector<quint32> series1, series2;
+        for (int i = 0; i < 1000; ++i) {
+            series1 << generator1.nextMask();
+            series2 << generator2.nextMask();
+        }
+
+        QVERIFY(series1 != series2);
+    }
+}
+
+QTEST_MAIN(tst_QDefaultMaskGenerator)
+
+#include "tst_defaultmaskgenerator.moc"