From 21e7cb1bafdfc06c263e10067d02f9b103ff660f Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Tue, 2 Aug 2016 10:36:56 +0200 Subject: QBluetoothSocket::connectToService - check a socket type first Attempt to connect to a service using a socket with UnknownProtocol socket type will fail, but can result in an incorrect UnknownSocketError reported and also can start a device discovery (then finally failing to connect after all). Check this condition early before trying to actually connect/do device discovery and report error properly as UnsupportedProtocolError. Task-number: QTBUG-55073 Change-Id: Ib39e1ca7ad401e07d6387201a4664a1185d38d39 Reviewed-by: Alex Blasche --- src/bluetooth/qbluetoothsocket.cpp | 27 +++++++++++++ src/bluetooth/qbluetoothsocket_osx.mm | 28 +++++++++++-- .../auto/qbluetoothsocket/tst_qbluetoothsocket.cpp | 47 ++++++++++++++++++++++ 3 files changed, 98 insertions(+), 4 deletions(-) diff --git a/src/bluetooth/qbluetoothsocket.cpp b/src/bluetooth/qbluetoothsocket.cpp index 2b2264e8..065cf74d 100644 --- a/src/bluetooth/qbluetoothsocket.cpp +++ b/src/bluetooth/qbluetoothsocket.cpp @@ -332,6 +332,15 @@ void QBluetoothSocket::connectToService(const QBluetoothServiceInfo &service, Op } d->connectToService(service.device().address(), service.serviceUuid(), openMode); #else + // Report this problem early: + if (socketType() == QBluetoothServiceInfo::UnknownProtocol) { + qCWarning(QT_BT) << "QBluetoothSocket::connectToService cannot " + "connect with 'UnknownProtocol' type"; + d->errorString = tr("Socket type not supported"); + setSocketError(QBluetoothSocket::UnsupportedProtocolError); + return; + } + if (service.protocolServiceMultiplexer() > 0) { if (!d->ensureNativeSocket(QBluetoothServiceInfo::L2capProtocol)) { d->errorString = tr("Unknown socket error"); @@ -401,6 +410,15 @@ void QBluetoothSocket::connectToService(const QBluetoothAddress &address, const } d->connectToService(address, uuid, openMode); #else + // Report this problem early, prevent device discovery: + if (socketType() == QBluetoothServiceInfo::UnknownProtocol) { + qCWarning(QT_BT) << "QBluetoothSocket::connectToService cannot " + "connect with 'UnknownProtocol' type"; + d->errorString = tr("Socket type not supported"); + setSocketError(QBluetoothSocket::UnsupportedProtocolError); + return; + } + QBluetoothServiceInfo service; QBluetoothDeviceInfo device(address, QString(), QBluetoothDeviceInfo::MiscellaneousDevice); service.setDevice(device); @@ -438,6 +456,15 @@ void QBluetoothSocket::connectToService(const QBluetoothAddress &address, quint1 setSocketError(QBluetoothSocket::ServiceNotFoundError); qCWarning(QT_BT) << "Connecting to port is not supported"; #else + // Report this problem early: + if (socketType() == QBluetoothServiceInfo::UnknownProtocol) { + qCWarning(QT_BT) << "QBluetoothSocket::connectToService cannot " + "connect with 'UnknownProtocol' type"; + d->errorString = tr("Socket type not supported"); + setSocketError(QBluetoothSocket::UnsupportedProtocolError); + return; + } + if (state() != QBluetoothSocket::UnconnectedState) { qCWarning(QT_BT) << "QBluetoothSocket::connectToService called on busy socket"; d->errorString = QBluetoothSocket::tr("Trying to connect while connection is in progress"); diff --git a/src/bluetooth/qbluetoothsocket_osx.mm b/src/bluetooth/qbluetoothsocket_osx.mm index 91393138..aa994550 100644 --- a/src/bluetooth/qbluetoothsocket_osx.mm +++ b/src/bluetooth/qbluetoothsocket_osx.mm @@ -73,9 +73,6 @@ QBluetoothSocketPrivate::~QBluetoothSocketPrivate() void QBluetoothSocketPrivate::connectToService(const QBluetoothAddress &address, quint16 port, QIODevice::OpenMode mode) { - // We have readwrite channels with IOBluetooth's channels. - Q_UNUSED(openMode) - Q_ASSERT_X(state == QBluetoothSocket::ServiceLookupState || state == QBluetoothSocket::UnconnectedState, Q_FUNC_INFO, "invalid state"); @@ -86,7 +83,7 @@ void QBluetoothSocketPrivate::connectToService(const QBluetoothAddress &address, txBuffer.clear(); IOReturn status = kIOReturnError; - // Set socket state on q_ptr will emit a signal, + // Setting socket state on q_ptr will emit a signal, // we'd like to avoid any signal until this function completes. const QBluetoothSocket::SocketState oldState = state; // To prevent other connectToService calls (from QBluetoothSocket): @@ -440,6 +437,14 @@ qint64 QBluetoothSocket::bytesToWrite() const void QBluetoothSocket::connectToService(const QBluetoothServiceInfo &service, OpenMode openMode) { + // Report this problem early, potentially avoid device discovery: + if (socketType() == QBluetoothServiceInfo::UnknownProtocol) { + qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "cannot connect with 'UnknownProtocol' type"; + d_ptr->errorString = QCoreApplication::translate(SOCKET, SOC_NETWORK_ERROR); + setSocketError(QBluetoothSocket::UnsupportedProtocolError); + return; + } + if (state() != UnconnectedState && state() != ServiceLookupState) { qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "called on a busy socket"; d_ptr->errorString = QCoreApplication::translate(SOCKET, SOC_CONNECT_IN_PROGRESS); @@ -469,6 +474,14 @@ void QBluetoothSocket::connectToService(const QBluetoothServiceInfo &service, Op void QBluetoothSocket::connectToService(const QBluetoothAddress &address, const QBluetoothUuid &uuid, OpenMode openMode) { + // Report this problem early, avoid device discovery: + if (socketType() == QBluetoothServiceInfo::UnknownProtocol) { + qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "cannot connect with 'UnknownProtocol' type"; + d_ptr->errorString = QCoreApplication::translate(SOCKET, SOC_NETWORK_ERROR); + setSocketError(QBluetoothSocket::UnsupportedProtocolError); + return; + } + if (state() != QBluetoothSocket::UnconnectedState) { qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "called on a busy socket"; d_ptr->errorString = QCoreApplication::translate(SOCKET, SOC_CONNECT_IN_PROGRESS); @@ -486,6 +499,13 @@ void QBluetoothSocket::connectToService(const QBluetoothAddress &address, const void QBluetoothSocket::connectToService(const QBluetoothAddress &address, quint16 port, OpenMode openMode) { + if (socketType() == QBluetoothServiceInfo::UnknownProtocol) { + qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "cannot connect with 'UnknownProtocol' type"; + d_ptr->errorString = QCoreApplication::translate(SOCKET, SOC_NETWORK_ERROR); + setSocketError(QBluetoothSocket::UnsupportedProtocolError); + return; + } + if (state() != QBluetoothSocket::UnconnectedState) { qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "called on a busy socket"; d_ptr->errorString = QCoreApplication::translate(SOCKET, SOC_CONNECT_IN_PROGRESS); diff --git a/tests/auto/qbluetoothsocket/tst_qbluetoothsocket.cpp b/tests/auto/qbluetoothsocket/tst_qbluetoothsocket.cpp index 7af7cf5e..37dce573 100644 --- a/tests/auto/qbluetoothsocket/tst_qbluetoothsocket.cpp +++ b/tests/auto/qbluetoothsocket/tst_qbluetoothsocket.cpp @@ -83,6 +83,8 @@ private slots: void tst_preferredSecurityFlags(); + void tst_unsupportedProtocolError(); + public slots: void serviceDiscovered(const QBluetoothServiceInfo &info); void finished(); @@ -524,6 +526,51 @@ void tst_QBluetoothSocket::tst_preferredSecurityFlags() #endif } +void tst_QBluetoothSocket::tst_unsupportedProtocolError() +{ +#if defined(QT_ANDROID_BLUETOOTH) + QSKIP("Android platform (re)sets RFCOMM socket type, nothing to test"); +#endif + // This socket has 'UnknownProtocol' socketType. + // Any attempt to connectToService should end in + // UnsupportedProtocolError. + QBluetoothSocket socket; + QCOMPARE(socket.socketType(), QBluetoothServiceInfo::UnknownProtocol); + QVERIFY(socket.error() == QBluetoothSocket::NoSocketError); + QVERIFY(socket.errorString() == QString()); + + QSignalSpy errorSpy(&socket, SIGNAL(error(QBluetoothSocket::SocketError))); + + // 1. Stop early with 'UnsupportedProtocolError'. + QBluetoothServiceInfo dummyServiceInfo; + socket.connectToService(dummyServiceInfo, QIODevice::ReadWrite); + QTRY_COMPARE_WITH_TIMEOUT(errorSpy.size(), 1, 1000); + QCOMPARE(errorSpy.size(), 1); + QCOMPARE(errorSpy.takeFirst().at(0).toInt(), int(QBluetoothSocket::UnsupportedProtocolError)); + QVERIFY(socket.errorString().size() != 0); + QCOMPARE(socket.state(), QBluetoothSocket::UnconnectedState); + + errorSpy.clear(); + + // 2. Stop early with UnsupportedProtocolError (before testing an invalid address/port). + socket.connectToService(QBluetoothAddress(), 1, QIODevice::ReadWrite); + QTRY_COMPARE_WITH_TIMEOUT(errorSpy.size(), 1, 1000); + QCOMPARE(errorSpy.size(), 1); + QCOMPARE(errorSpy.takeFirst().at(0).toInt(), int(QBluetoothSocket::UnsupportedProtocolError)); + QVERIFY(socket.errorString().size() != 0); + QCOMPARE(socket.state(), QBluetoothSocket::UnconnectedState); + + errorSpy.clear(); + + // 3. Stop early (ignoring an invalid address/uuid). + socket.connectToService(QBluetoothAddress(), QBluetoothUuid(), QIODevice::ReadWrite); + QTRY_COMPARE_WITH_TIMEOUT(errorSpy.size(), 1, 1000); + QCOMPARE(errorSpy.size(), 1); + QCOMPARE(errorSpy.takeFirst().at(0).toInt(), int(QBluetoothSocket::UnsupportedProtocolError)); + QVERIFY(socket.errorString().size() != 0); + QCOMPARE(socket.state(), QBluetoothSocket::UnconnectedState); +} + QTEST_MAIN(tst_QBluetoothSocket) #include "tst_qbluetoothsocket.moc" -- cgit v1.2.3