aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSona Kurazyan <sona.kurazyan@qt.io>2019-04-01 18:13:57 +0200
committerSona Kurazyan <sona.kurazyan@qt.io>2019-04-25 06:36:27 +0000
commite2faedb48d9bbfde275bec22aebb5c1ded430e2c (patch)
tree9b622bc2950a600cf80c3d65342b06158d7f5c7c
parentcf5699e4050b200b9ee80bf4a1c8fbcecb2877af (diff)
Add an API for closing the connection's transport
Change-Id: I916ddb226b653aaf563ecf0adc3a1110d6da3132 Reviewed-by: Alex Blasche <alexander.blasche@qt.io> Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
-rw-r--r--src/coap/qcoapclient.cpp9
-rw-r--r--src/coap/qcoapclient.h1
-rw-r--r--src/coap/qcoapconnection.cpp41
-rw-r--r--src/coap/qcoapconnection.h2
-rw-r--r--src/coap/qcoapqudpconnection.cpp28
-rw-r--r--src/coap/qcoapqudpconnection.h1
-rw-r--r--tests/auto/qcoapclient/tst_qcoapclient.cpp2
-rw-r--r--tests/auto/qcoapqudpconnection/tst_qcoapqudpconnection.cpp24
8 files changed, 98 insertions, 10 deletions
diff --git a/src/coap/qcoapclient.cpp b/src/coap/qcoapclient.cpp
index b438ba6..d56b072 100644
--- a/src/coap/qcoapclient.cpp
+++ b/src/coap/qcoapclient.cpp
@@ -508,6 +508,15 @@ void QCoapClient::cancelObserve(const QUrl &url)
}
/*!
+ Closes the open sockets and connections to free the transport.
+*/
+void QCoapClient::disconnect()
+{
+ Q_D(QCoapClient);
+ QMetaObject::invokeMethod(d->connection, "disconnect", Qt::QueuedConnection);
+}
+
+/*!
\internal
Sends the CoAP \a request to its own URL and returns a new QCoapReply
diff --git a/src/coap/qcoapclient.h b/src/coap/qcoapclient.h
index 5795191..8701e3c 100644
--- a/src/coap/qcoapclient.h
+++ b/src/coap/qcoapclient.h
@@ -72,6 +72,7 @@ public:
QCoapReply *observe(const QUrl &request);
void cancelObserve(QCoapReply *notifiedReply);
void cancelObserve(const QUrl &url);
+ void disconnect();
QCoapDiscoveryReply *discover(QtCoap::MulticastGroup group = QtCoap::AllCoapNodesIPv4,
int port = QtCoap::DefaultPort,
diff --git a/src/coap/qcoapconnection.cpp b/src/coap/qcoapconnection.cpp
index 0263618..7ee529a 100644
--- a/src/coap/qcoapconnection.cpp
+++ b/src/coap/qcoapconnection.cpp
@@ -98,7 +98,16 @@ Q_LOGGING_CATEGORY(lcCoapConnection, "qt.coap.connection")
This is a pure virtual method.
- \sa bound()
+ \sa bound(), close()
+*/
+
+/*!
+ \fn void QCoapConnection::close()
+
+ Closes the open sockets and connections to free the underlying transport.
+ This is a pure virtual method.
+
+ \sa bind()
*/
/*!
@@ -133,6 +142,12 @@ QCoapConnection::QCoapConnection(QtCoap::SecurityMode securityMode, QObject *par
QCoapConnection::QCoapConnection(QObjectPrivate &dd, QObject *parent)
: QObject(dd, parent)
{
+ connect(this, &QCoapConnection::bound, this,
+ [this]() {
+ Q_D(QCoapConnection);
+ d->state = QCoapConnection::Bound;
+ startToSendRequest();
+ });
}
/*!
@@ -160,16 +175,10 @@ QCoapConnectionPrivate::sendRequest(const QByteArray &request, const QString &ho
CoapFrame frame(request, host, port);
framesToSend.enqueue(frame);
- if (state == QCoapConnection::ConnectionState::Unconnected) {
- q->connect(q, &QCoapConnection::bound, q,
- [this, q]() {
- state = QCoapConnection::ConnectionState::Bound;
- q->startToSendRequest();
- });
+ if (state == QCoapConnection::ConnectionState::Unconnected)
q->bind(host, port);
- } else {
+ else
q->startToSendRequest();
- }
}
/*!
@@ -242,4 +251,18 @@ QCoapSecurityConfiguration QCoapConnection::securityConfiguration() const
return d->securityConfiguration;
}
+/*!
+ Closes the open sockets and connections to free the transport and clears
+ the connection state.
+*/
+void QCoapConnection::disconnect()
+{
+ Q_D(QCoapConnection);
+
+ close();
+
+ d->framesToSend.clear();
+ d->state = QCoapConnection::Unconnected;
+}
+
QT_END_NAMESPACE
diff --git a/src/coap/qcoapconnection.h b/src/coap/qcoapconnection.h
index 017a0bd..017053b 100644
--- a/src/coap/qcoapconnection.h
+++ b/src/coap/qcoapconnection.h
@@ -58,6 +58,7 @@ public:
QCoapSecurityConfiguration securityConfiguration() const;
Q_INVOKABLE void setSecurityConfiguration(const QCoapSecurityConfiguration &configuration);
+ Q_INVOKABLE void disconnect();
Q_SIGNALS:
void error(QAbstractSocket::SocketError error);
@@ -73,6 +74,7 @@ protected:
virtual void bind(const QString &host, quint16 port) = 0;
virtual void writeData(const QByteArray &data, const QString &host, quint16 port) = 0;
+ virtual void close() = 0;
private:
friend class QCoapProtocolPrivate;
diff --git a/src/coap/qcoapqudpconnection.cpp b/src/coap/qcoapqudpconnection.cpp
index 636554c..831b23d 100644
--- a/src/coap/qcoapqudpconnection.cpp
+++ b/src/coap/qcoapqudpconnection.cpp
@@ -242,6 +242,30 @@ void QCoapQUdpConnection::writeData(const QByteArray &data, const QString &host,
}
/*!
+ \internal
+
+ \brief Close the UDP socket
+
+ In the case of a secure connection, this also interrupts any ongoing
+ hand-shake and shuts down the DTLS connection.
+*/
+void QCoapQUdpConnection::close()
+{
+ Q_D(QCoapQUdpConnection);
+
+#if QT_CONFIG(dtls)
+ if (isSecure()) {
+ if (d->dtls->handshakeState() == QDtls::HandshakeInProgress)
+ d->dtls->abortHandshake(d->socket());
+
+ if (d->dtls->isConnectionEncrypted())
+ d->dtls->shutdown(d->socket());
+ }
+#endif
+ d->socket()->close();
+}
+
+/*!
Sets the QUdpSocket socket \a option to \a value.
*/
void QCoapQUdpConnection::setSocketOption(QAbstractSocket::SocketOption option, const QVariant &value)
@@ -393,8 +417,10 @@ void QCoapQUdpConnection::handshakeTimeout()
Q_D(QCoapQUdpConnection);
qCWarning(lcCoapConnection, "Handshake timeout, trying to re-transmit");
- if (!d->dtls->handleTimeout(d->udpSocket))
+ if (d->dtls->handshakeState() == QDtls::HandshakeInProgress &&
+ !d->dtls->handleTimeout(d->udpSocket)) {
qCWarning(lcCoapConnection) << "Failed to re-transmit" << d->dtls->dtlsErrorString();
+ }
}
/*!
diff --git a/src/coap/qcoapqudpconnection.h b/src/coap/qcoapqudpconnection.h
index b070d1d..76c5abf 100644
--- a/src/coap/qcoapqudpconnection.h
+++ b/src/coap/qcoapqudpconnection.h
@@ -69,6 +69,7 @@ protected:
void bind(const QString &host, quint16 port) override;
void writeData(const QByteArray &data, const QString &host, quint16 port) override;
+ void close() override;
void createSocket();
diff --git a/tests/auto/qcoapclient/tst_qcoapclient.cpp b/tests/auto/qcoapclient/tst_qcoapclient.cpp
index ee61f70..04db9f4 100644
--- a/tests/auto/qcoapclient/tst_qcoapclient.cpp
+++ b/tests/auto/qcoapclient/tst_qcoapclient.cpp
@@ -154,6 +154,8 @@ public:
Q_UNUSED(port);
// Do nothing
}
+
+ void close() override {}
};
class QCoapClientForMulticastTests : public QCoapClient
diff --git a/tests/auto/qcoapqudpconnection/tst_qcoapqudpconnection.cpp b/tests/auto/qcoapqudpconnection/tst_qcoapqudpconnection.cpp
index 6b3f0e9..898466d 100644
--- a/tests/auto/qcoapqudpconnection/tst_qcoapqudpconnection.cpp
+++ b/tests/auto/qcoapqudpconnection/tst_qcoapqudpconnection.cpp
@@ -58,6 +58,7 @@ class tst_QCoapQUdpConnection : public QObject
private Q_SLOTS:
void ctor();
void connectToHost();
+ void reconnect();
void sendRequest_data();
void sendRequest();
};
@@ -105,6 +106,29 @@ void tst_QCoapQUdpConnection::connectToHost()
#endif
}
+void tst_QCoapQUdpConnection::reconnect()
+{
+#ifdef QT_BUILD_INTERNAL
+ QCoapQUdpConnectionForTest connection;
+
+ // This will trigger connection.bind()
+ QSignalSpy connectionBoundSpy(&connection, SIGNAL(bound()));
+ connection.sendRequest(QByteArray(), QString(), 0);
+ QTRY_COMPARE(connectionBoundSpy.count(), 1);
+ QCOMPARE(connection.state(), QCoapQUdpConnection::Bound);
+
+ connection.disconnect();
+ QCOMPARE(connection.state(), QCoapQUdpConnection::Unconnected);
+
+ // Make sure that we are able to connect again
+ connection.sendRequest(QByteArray(), QString(), 0);
+ QTRY_COMPARE(connectionBoundSpy.count(), 2);
+ QCOMPARE(connection.state(), QCoapQUdpConnection::Bound);
+#else
+ QSKIP("Not an internal build, skipping this test");
+#endif
+}
+
void tst_QCoapQUdpConnection::sendRequest_data()
{
QTest::addColumn<QString>("protocol");