aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2019-05-26 22:29:58 +0200
committerQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2019-05-26 22:29:58 +0200
commit5998dc29d0c55e0b5bfcc9debd2681f655326e86 (patch)
treed12baa64eaa3780663586cb2753c7cbe346cb8f6
parent02d7238391ae0addc6517759b10d01948b108cb3 (diff)
parent0c00be007c3a72928f6f8e167e8e6f2469f1a88d (diff)
Merge remote-tracking branch 'origin/5.13' into dev
-rw-r--r--src/coap/qcoapclient.cpp46
-rw-r--r--src/coap/qcoapclient.h2
-rw-r--r--src/coap/qcoapclient_p.h2
-rw-r--r--src/coap/qcoapprotocol.cpp24
-rw-r--r--src/coap/qcoapprotocol_p.h3
-rw-r--r--tests/auto/qcoapclient/tst_qcoapclient.cpp61
6 files changed, 118 insertions, 20 deletions
diff --git a/src/coap/qcoapclient.cpp b/src/coap/qcoapclient.cpp
index 5469ef2..dc02464 100644
--- a/src/coap/qcoapclient.cpp
+++ b/src/coap/qcoapclient.cpp
@@ -162,16 +162,8 @@ QCoapClientPrivate::~QCoapClientPrivate()
constructors.
*/
QCoapClient::QCoapClient(QtCoap::SecurityMode securityMode, QObject *parent) :
- QCoapClient(new QCoapQUdpConnection(securityMode), parent)
-{
-}
-
-/*!
- Constructs a QCoapClient object with the given \a connection and
- sets \a parent as the parent object.
-*/
-QCoapClient::QCoapClient(QCoapConnection *connection, QObject *parent) :
- QObject(*new QCoapClientPrivate(new QCoapProtocol, connection), parent)
+ QObject(*new QCoapClientPrivate(new QCoapProtocol, new QCoapQUdpConnection(securityMode)),
+ parent)
{
Q_D(QCoapClient);
@@ -210,6 +202,28 @@ QCoapClient::QCoapClient(QCoapConnection *connection, QObject *parent) :
}
/*!
+ \internal
+
+ Sets the client's connection to \a customConnection.
+*/
+void QCoapClientPrivate::setConnection(QCoapConnection *customConnection)
+{
+ Q_Q(QCoapClient);
+
+ delete connection;
+ connection = customConnection;
+
+ q->connect(connection, &QCoapConnection::readyRead, protocol,
+ [this](const QByteArray &data, const QHostAddress &sender) {
+ protocol->d_func()->onFrameReceived(data, sender);
+ });
+ q->connect(connection, &QCoapConnection::error, protocol,
+ [this](QAbstractSocket::SocketError socketError) {
+ protocol->d_func()->onConnectionError(socketError);
+ });
+}
+
+/*!
Destroys the QCoapClient object and frees up any
resources. Note that QCoapReply objects that are returned from
this class have the QCoapClient set as their parents, which means that
@@ -676,4 +690,16 @@ void QCoapClient::setMaximumRetransmitCount(uint maximumRetransmitCount)
Q_ARG(uint, maximumRetransmitCount));
}
+/*!
+ Sets the minimum token size to \a tokenSize in bytes. For security reasons it is
+ recommended to use tokens with a length of at least 4 bytes. The default value for
+ this parameter is 4 bytes.
+*/
+void QCoapClient::setMinimumTokenSize(int tokenSize)
+{
+ Q_D(QCoapClient);
+ QMetaObject::invokeMethod(d->protocol, "setMinimumTokenSize", Qt::QueuedConnection,
+ Q_ARG(int, tokenSize));
+}
+
QT_END_NAMESPACE
diff --git a/src/coap/qcoapclient.h b/src/coap/qcoapclient.h
index 7171b59..a7478cf 100644
--- a/src/coap/qcoapclient.h
+++ b/src/coap/qcoapclient.h
@@ -55,7 +55,6 @@ class Q_COAP_EXPORT QCoapClient : public QObject
public:
explicit QCoapClient(QtCoap::SecurityMode securityMode = QtCoap::SecurityMode::NoSecurity,
QObject *parent = nullptr);
- explicit QCoapClient(QCoapConnection *connection, QObject *parent = nullptr);
~QCoapClient();
QCoapReply *get(const QCoapRequest &request);
@@ -89,6 +88,7 @@ public:
void setAckTimeout(uint ackTimeout);
void setAckRandomFactor(double ackRandomFactor);
void setMaximumRetransmitCount(uint maximumRetransmitCount);
+ void setMinimumTokenSize(int tokenSize);
Q_SIGNALS:
void finished(QCoapReply *reply);
diff --git a/src/coap/qcoapclient_p.h b/src/coap/qcoapclient_p.h
index 84d3a83..18c916e 100644
--- a/src/coap/qcoapclient_p.h
+++ b/src/coap/qcoapclient_p.h
@@ -63,6 +63,8 @@ public:
QCoapResourceDiscoveryReply *sendDiscovery(const QCoapRequest &request);
bool send(QCoapReply *reply);
+ void setConnection(QCoapConnection *customConnection);
+
Q_DECLARE_PUBLIC(QCoapClient)
};
diff --git a/src/coap/qcoapprotocol.cpp b/src/coap/qcoapprotocol.cpp
index 46f420c..3a6f3ca 100644
--- a/src/coap/qcoapprotocol.cpp
+++ b/src/coap/qcoapprotocol.cpp
@@ -690,9 +690,7 @@ QCoapToken QCoapProtocolPrivate::generateUniqueToken() const
// TODO: Store used token for the period specified by CoAP spec
QCoapToken token;
while (isTokenRegistered(token)) {
- // TODO: Allow setting minimum token size as a security setting
- quint8 length = static_cast<quint8>(QtCoap::randomGenerator().bounded(1, 8));
-
+ quint8 length = static_cast<quint8>(QtCoap::randomGenerator().bounded(minimumTokenSize, 9));
token.resize(length);
quint8 *tokenData = reinterpret_cast<quint8 *>(token.data());
for (int i = 0; i < token.size(); ++i)
@@ -1151,4 +1149,24 @@ void QCoapProtocol::setMaximumServerResponseDelay(uint responseDelay)
d->maximumServerResponseDelay = responseDelay;
}
+/*!
+ \internal
+
+ Sets the minimum token size to \a tokenSize in bytes. For security reasons it is
+ recommended to use tokens with a length of at least 4 bytes. The default value for
+ this parameter is 4 bytes.
+*/
+void QCoapProtocol::setMinimumTokenSize(int tokenSize)
+{
+ Q_D(QCoapProtocol);
+
+ if (tokenSize > 0 && tokenSize <= 8) {
+ d->minimumTokenSize = tokenSize;
+ } else {
+ qCWarning(lcCoapProtocol,
+ "Failed to set the minimum token size,"
+ "it should not be more than 8 bytes and cannot be 0.");
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/coap/qcoapprotocol_p.h b/src/coap/qcoapprotocol_p.h
index 4bd61c8..0e3d3ed 100644
--- a/src/coap/qcoapprotocol_p.h
+++ b/src/coap/qcoapprotocol_p.h
@@ -90,6 +90,7 @@ public:
Q_INVOKABLE void setMaximumRetransmitCount(uint maximumRetransmitCount);
Q_INVOKABLE void setBlockSize(quint16 blockSize);
Q_INVOKABLE void setMaximumServerResponseDelay(uint responseDelay);
+ Q_INVOKABLE void setMinimumTokenSize(int tokenSize);
private:
Q_INVOKABLE void sendRequest(QPointer<QCoapReply> reply, QCoapConnection *connection);
@@ -100,6 +101,7 @@ private:
Q_DECLARE_PRIVATE(QCoapProtocol)
friend class QCoapClient;
+ friend class QCoapClientPrivate;
};
struct CoapExchangeData {
@@ -160,6 +162,7 @@ public:
uint maximumRetransmitCount = 4;
uint ackTimeout = 2000;
uint maximumServerResponseDelay = 250 * 1000;
+ int minimumTokenSize = 4;
double ackRandomFactor = 1.5;
Q_DECLARE_PUBLIC(QCoapProtocol)
diff --git a/tests/auto/qcoapclient/tst_qcoapclient.cpp b/tests/auto/qcoapclient/tst_qcoapclient.cpp
index 6f66346..20f1cab 100644
--- a/tests/auto/qcoapclient/tst_qcoapclient.cpp
+++ b/tests/auto/qcoapclient/tst_qcoapclient.cpp
@@ -77,6 +77,8 @@ private Q_SLOTS:
void confirmableMulticast();
void multicast();
void multicast_blockwise();
+ void setMinimumTokenSize_data();
+ void setMinimumTokenSize();
};
#ifdef QT_BUILD_INTERNAL
@@ -108,9 +110,11 @@ private:
class QCoapClientForSocketErrorTests : public QCoapClient
{
public:
- QCoapClientForSocketErrorTests() :
- QCoapClient(new QCoapQUdpConnectionSocketTests)
- {}
+ QCoapClientForSocketErrorTests()
+ {
+ QCoapClientPrivate *privateClient = static_cast<QCoapClientPrivate *>(d_func());
+ privateClient->setConnection(new QCoapQUdpConnectionSocketTests());
+ }
QCoapQUdpConnection *connection()
{
@@ -162,9 +166,11 @@ public:
class QCoapClientForMulticastTests : public QCoapClient
{
public:
- QCoapClientForMulticastTests() :
- QCoapClient(new QCoapConnectionMulticastTests)
- {}
+ QCoapClientForMulticastTests()
+ {
+ QCoapClientPrivate *privateClient = static_cast<QCoapClientPrivate *>(d_func());
+ privateClient->setConnection(new QCoapConnectionMulticastTests());
+ }
QCoapConnection *connection()
{
@@ -867,6 +873,49 @@ void tst_QCoapClient::multicast_blockwise()
#endif
}
+void tst_QCoapClient::setMinimumTokenSize_data()
+{
+ QTest::addColumn<int>("minTokenSize");
+ QTest::addColumn<int>("expectedMinSize");
+
+ QTest::newRow("in_range") << 6 << 6;
+ QTest::newRow("out_of_range_small") << 0 << 4;
+ QTest::newRow("out_of_range_big") << 9 << 4;
+}
+
+void noMessageOutput(QtMsgType, const QMessageLogContext &, const QString &) {}
+
+void tst_QCoapClient::setMinimumTokenSize()
+{
+#ifdef QT_BUILD_INTERNAL
+ // Don't show warning messages for the out of range values
+ qInstallMessageHandler(noMessageOutput);
+
+ QFETCH(int, minTokenSize);
+ QFETCH(int, expectedMinSize);
+
+ const int maxSize = 8;
+
+ for (int i = 0; i < 20; ++i) {
+ QCoapClientForSocketErrorTests client;
+ client.setMinimumTokenSize(minTokenSize);
+
+ // With QCoapClientForSocketErrorTests the request will fail, but it doesn't matter,
+ // we are interested only in the generated token.
+ QSignalSpy spyClientError(&client, &QCoapClient::error);
+
+ QScopedPointer<QCoapReply> reply;
+ reply.reset(client.get(QCoapRequest("127.0.0.1")));
+
+ QTRY_COMPARE_WITH_TIMEOUT(spyClientError.count(), 1, 10);
+ QVERIFY(reply->request().tokenLength() >= expectedMinSize);
+ QVERIFY(reply->request().tokenLength() <= maxSize);
+ }
+#else
+ QSKIP("Not an internal build, skipping this test");
+#endif
+}
+
QTEST_MAIN(tst_QCoapClient)
#include "tst_qcoapclient.moc"