diff options
author | Sona Kurazyan <sona.kurazyan@qt.io> | 2019-04-01 18:13:57 +0200 |
---|---|---|
committer | Sona Kurazyan <sona.kurazyan@qt.io> | 2019-04-25 06:36:27 +0000 |
commit | e2faedb48d9bbfde275bec22aebb5c1ded430e2c (patch) | |
tree | 9b622bc2950a600cf80c3d65342b06158d7f5c7c | |
parent | cf5699e4050b200b9ee80bf4a1c8fbcecb2877af (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.cpp | 9 | ||||
-rw-r--r-- | src/coap/qcoapclient.h | 1 | ||||
-rw-r--r-- | src/coap/qcoapconnection.cpp | 41 | ||||
-rw-r--r-- | src/coap/qcoapconnection.h | 2 | ||||
-rw-r--r-- | src/coap/qcoapqudpconnection.cpp | 28 | ||||
-rw-r--r-- | src/coap/qcoapqudpconnection.h | 1 | ||||
-rw-r--r-- | tests/auto/qcoapclient/tst_qcoapclient.cpp | 2 | ||||
-rw-r--r-- | tests/auto/qcoapqudpconnection/tst_qcoapqudpconnection.cpp | 24 |
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"); |