From 8b7b52d66f2616040ca4aaae3f2732be96e19ab8 Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Fri, 23 Nov 2018 18:04:40 +0100 Subject: Enable the use of the Win32 Bluetooth backend This change enables the optional use of the Win32-based Bluetooth backend on Windows. By default, the WinRT backend is used, if supported by the platform. The use of the Win32 backend must be selected by the -native-win32-bluetooth configuration option. Task-number: QTBUG-40698 Change-Id: I6904bf077467d826e3ff5ad026ebae5f955f2e37 Reviewed-by: Oliver Wolff Reviewed-by: Alex Blasche --- src/bluetooth/bluetooth.pro | 3 - src/bluetooth/configure.json | 16 +- .../qbluetoothdevicediscoveryagent_win.cpp | 43 +++--- src/bluetooth/qbluetoothlocaldevice_win.cpp | 32 ++-- src/bluetooth/qbluetoothserver.cpp | 3 +- src/bluetooth/qbluetoothserver_android.cpp | 5 +- src/bluetooth/qbluetoothserver_bluez.cpp | 5 +- src/bluetooth/qbluetoothserver_p.cpp | 6 +- src/bluetooth/qbluetoothserver_p.h | 10 +- src/bluetooth/qbluetoothserver_win.cpp | 162 ++++++++++++++++++-- src/bluetooth/qbluetoothserver_winrt.cpp | 6 +- src/bluetooth/qbluetoothservicediscoveryagent.h | 4 - src/bluetooth/qbluetoothservicediscoveryagent_p.h | 1 + .../qbluetoothservicediscoveryagent_win.cpp | 157 +++++++++---------- src/bluetooth/qbluetoothserviceinfo_p.h | 13 ++ src/bluetooth/qbluetoothserviceinfo_win.cpp | 59 +++++++- src/bluetooth/qbluetoothsocket_win.cpp | 168 +++++++++++---------- src/bluetooth/qbluetoothsocket_win_p.h | 5 - src/bluetooth/qbluetoothtransfermanager.cpp | 4 +- src/bluetooth/qlowenergycontroller.cpp | 1 + src/bluetooth/qlowenergycontroller_p.h | 1 - src/bluetooth/qlowenergycontroller_win.cpp | 90 ++++++----- 22 files changed, 497 insertions(+), 297 deletions(-) (limited to 'src') diff --git a/src/bluetooth/bluetooth.pro b/src/bluetooth/bluetooth.pro index eedd4864..a2fd617d 100644 --- a/src/bluetooth/bluetooth.pro +++ b/src/bluetooth/bluetooth.pro @@ -252,9 +252,6 @@ qtConfig(bluez) { include(windows/windows.pri) - # remove dummy warning once platform port is complete - include(dummy/dummy.pri) - SOURCES += \ qbluetoothdevicediscoveryagent_win.cpp \ qbluetoothlocaldevice_win.cpp \ diff --git a/src/bluetooth/configure.json b/src/bluetooth/configure.json index 53923e12..3bd95903 100644 --- a/src/bluetooth/configure.json +++ b/src/bluetooth/configure.json @@ -2,6 +2,12 @@ "module": "bluetooth", "testDir": "../../config.tests", + "commandline": { + "options": { + "native-win32-bluetooth": "boolean" + } + }, + "libraries": { "bluez": { "label": "BlueZ", @@ -52,9 +58,16 @@ "condition": "features.bluez_le && tests.linux_crypto_api", "output": [ "privateFeature" ] }, + "native-win32-bluetooth": { + "label": "Native Win32 Bluetooth", + "purpose": "Uses the native Win32 Bluetooth backend.", + "section": "Qt Bluetooth", + "autoDetect": false, + "output": [ "publicFeature", "feature" ] + }, "winrt_bt": { "label": "WinRT Bluetooth API (desktop & UWP)", - "condition": "config.win32 && tests.winrt_bt", + "condition": "config.win32 && !features.native-win32-bluetooth && tests.winrt_bt", "output": [ "privateFeature" ] }, "winrt_btle_no_pairing": { @@ -85,6 +98,7 @@ Only classic Bluetooth will be available." "bluez", "bluez_le", "linux_crypto_api", + "native-win32-bluetooth", "winrt_bt", "winrt_btle_no_pairing" ] diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_win.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_win.cpp index 3645bd21..159428d4 100644 --- a/src/bluetooth/qbluetoothdevicediscoveryagent_win.cpp +++ b/src/bluetooth/qbluetoothdevicediscoveryagent_win.cpp @@ -154,7 +154,7 @@ static QBluetoothDeviceInfo findFirstClassicDevice( *systemErrorCode = NO_ERROR; foundDevice = createClassicDeviceInfo(deviceInfo); } else { - *systemErrorCode = ::GetLastError(); + *systemErrorCode = int(::GetLastError()); } return foundDevice; @@ -168,7 +168,7 @@ static QBluetoothDeviceInfo findNextClassicDevice( QBluetoothDeviceInfo foundDevice; if (!::BluetoothFindNextDevice(hSearch, &deviceInfo)) { - *systemErrorCode = ::GetLastError(); + *systemErrorCode = int(::GetLastError()); } else { *systemErrorCode = NO_ERROR; foundDevice = createClassicDeviceInfo(deviceInfo); @@ -186,6 +186,7 @@ static void closeClassicSearch(HBLUETOOTH_DEVICE_FIND hSearch) static QVector enumerateLeDevices( DWORD *systemErrorCode) { + // GUID_BLUETOOTHLE_DEVICE_INTERFACE const QUuid deviceInterfaceGuid("781aee18-7733-4ce4-add0-91f41c67b592"); const HDEVINFO hDeviceInfo = ::SetupDiGetClassDevs( reinterpret_cast(&deviceInterfaceGuid), @@ -194,7 +195,7 @@ static QVector enumerateLeDevices( DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if (hDeviceInfo == INVALID_HANDLE_VALUE) { - *systemErrorCode = ::GetLastError(); + *systemErrorCode = int(::GetLastError()); return QVector(); } @@ -213,7 +214,7 @@ static QVector enumerateLeDevices( reinterpret_cast(&deviceInterfaceGuid), index++, &deviceInterfaceData)) { - *systemErrorCode = ::GetLastError(); + *systemErrorCode = int(::GetLastError()); break; } @@ -226,7 +227,7 @@ static QVector enumerateLeDevices( &deviceInterfaceDetailDataSize, nullptr)) { if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) { - *systemErrorCode = ::GetLastError(); + *systemErrorCode = int(::GetLastError()); break; } } @@ -251,7 +252,7 @@ static QVector enumerateLeDevices( deviceInterfaceDetailDataBuffer.size(), &deviceInterfaceDetailDataSize, &deviceInfoData)) { - *systemErrorCode = ::GetLastError(); + *systemErrorCode = int(::GetLastError()); break; } @@ -534,28 +535,20 @@ void QBluetoothDeviceDiscoveryAgentPrivate::processDiscoveredDevice( auto end = discoveredDevices.end(); auto deviceIt = std::find_if(discoveredDevices.begin(), end, equalAddress); if (deviceIt == end) { - qCDebug(QT_BT_WINDOWS) << "Emit: " << foundDevice.address(); + qCDebug(QT_BT_WINDOWS) << "Found device: " << foundDevice.name() << foundDevice.address(); discoveredDevices.append(foundDevice); emit q->deviceDiscovered(foundDevice); - } else if (*deviceIt == foundDevice - || deviceIt->coreConfigurations() == foundDevice.coreConfigurations()) { - qCDebug(QT_BT_WINDOWS) << "Duplicate: " << foundDevice.address(); } else { - // We assume that if the existing device it is low energy, it means that - // the found device should be as classic, because it is impossible to get - // same low energy device. - if (deviceIt->coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration) - *deviceIt = foundDevice; - - // We assume that it is impossible to have multiple devices with same core - // configurations, which have one address. This possible only in case a device - // provided both low energy and classic features at the same time. - deviceIt->setCoreConfigurations(QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration); - deviceIt->setCached(foundDevice.isCached()); - - Q_Q(QBluetoothDeviceDiscoveryAgent); - qCDebug(QT_BT_WINDOWS) << "Updated: " << deviceIt->address(); - emit q->deviceDiscovered(*deviceIt); + qCDebug(QT_BT_WINDOWS) << "Updating device:" << deviceIt->name() << deviceIt->address(); + // merge service uuids + QList uuids = deviceIt->serviceUuids(); + uuids.append(foundDevice.serviceUuids()); + const QSet uuidSet = uuids.toSet(); + if (deviceIt->serviceUuids().count() != uuidSet.count()) + deviceIt->setServiceUuids(uuidSet.toList().toVector()); + if (deviceIt->coreConfigurations() != foundDevice.coreConfigurations()) + deviceIt->setCoreConfigurations( + QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration); } } diff --git a/src/bluetooth/qbluetoothlocaldevice_win.cpp b/src/bluetooth/qbluetoothlocaldevice_win.cpp index a3f3c339..cf17cad1 100644 --- a/src/bluetooth/qbluetoothlocaldevice_win.cpp +++ b/src/bluetooth/qbluetoothlocaldevice_win.cpp @@ -100,39 +100,34 @@ void QBluetoothLocalDevice::setHostMode( return; if (requestedMode == QBluetoothLocalDevice::HostPoweredOff) { - if (::BluetoothIsDiscoverable(NULL) - && !::BluetoothEnableDiscovery(NULL, FALSE)) { + if (::BluetoothIsDiscoverable(nullptr) + && !::BluetoothEnableDiscovery(nullptr, FALSE)) { qCWarning(QT_BT_WINDOWS) << "Unable to disable the discoverable mode"; emit error(QBluetoothLocalDevice::UnknownError); return; } - if (::BluetoothIsConnectable(NULL) - && !::BluetoothEnableIncomingConnections(NULL, FALSE)) { + if (::BluetoothIsConnectable(nullptr) + && !::BluetoothEnableIncomingConnections(nullptr, FALSE)) { qCWarning(QT_BT_WINDOWS) << "Unable to disable the connectable mode"; emit error(QBluetoothLocalDevice::UnknownError); return; } } else if (requestedMode == QBluetoothLocalDevice::HostConnectable) { - if (::BluetoothIsDiscoverable(NULL)) { - if (!::BluetoothEnableDiscovery(NULL, FALSE)) { - qCWarning(QT_BT_WINDOWS) << "Unable to disable the discoverable mode"; - emit error(QBluetoothLocalDevice::UnknownError); - return; - } - } else if (!::BluetoothEnableIncomingConnections(NULL, TRUE)) { + if (!::BluetoothIsConnectable(nullptr) + && !::BluetoothEnableIncomingConnections(nullptr, TRUE)) { qCWarning(QT_BT_WINDOWS) << "Unable to enable the connectable mode"; emit error(QBluetoothLocalDevice::UnknownError); return; } } else if (requestedMode == QBluetoothLocalDevice::HostDiscoverable || requestedMode == QBluetoothLocalDevice::HostDiscoverableLimitedInquiry) { - if (!::BluetoothIsConnectable(NULL) - && !::BluetoothEnableIncomingConnections(NULL, TRUE)) { + if (!::BluetoothIsConnectable(nullptr) + && !::BluetoothEnableIncomingConnections(nullptr, TRUE)) { qCWarning(QT_BT_WINDOWS) << "Unable to enable the connectable mode"; emit error(QBluetoothLocalDevice::UnknownError); return; } - if (!::BluetoothEnableDiscovery(NULL, TRUE)) { + if (!::BluetoothEnableDiscovery(nullptr, TRUE)) { qCWarning(QT_BT_WINDOWS) << "Unable to enable the discoverable mode"; emit error(QBluetoothLocalDevice::UnknownError); return; @@ -149,9 +144,9 @@ QBluetoothLocalDevice::HostMode QBluetoothLocalDevice::hostMode() const return HostPoweredOff; } - if (::BluetoothIsDiscoverable(NULL)) + if (::BluetoothIsDiscoverable(nullptr)) return HostDiscoverable; - if (::BluetoothIsConnectable(NULL)) + if (::BluetoothIsConnectable(nullptr)) return HostConnectable; return HostPoweredOff; } @@ -170,18 +165,21 @@ void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pai { Q_UNUSED(address); Q_UNUSED(pairing); + Q_UNIMPLEMENTED(); } QBluetoothLocalDevice::Pairing QBluetoothLocalDevice::pairingStatus( const QBluetoothAddress &address) const { Q_UNUSED(address); + Q_UNIMPLEMENTED(); return Unpaired; } void QBluetoothLocalDevice::pairingConfirmation(bool confirmation) { Q_UNUSED(confirmation); + Q_UNIMPLEMENTED(); } QBluetoothLocalDevicePrivate::QBluetoothLocalDevicePrivate( @@ -230,7 +228,7 @@ QList QBluetoothLocalDevicePrivate::localAdapters() QList foundAdapters; - HANDLE hRadio = 0; + HANDLE hRadio = nullptr; if (const HBLUETOOTH_RADIO_FIND hSearch = ::BluetoothFindFirstRadio(¶ms, &hRadio)) { for (;;) { BLUETOOTH_RADIO_INFO radio; diff --git a/src/bluetooth/qbluetoothserver.cpp b/src/bluetooth/qbluetoothserver.cpp index 6991518f..75ac9979 100644 --- a/src/bluetooth/qbluetoothserver.cpp +++ b/src/bluetooth/qbluetoothserver.cpp @@ -167,9 +167,8 @@ QT_BEGIN_NAMESPACE Constructs a bluetooth server with \a parent and \a serverType. */ QBluetoothServer::QBluetoothServer(QBluetoothServiceInfo::Protocol serverType, QObject *parent) - : QObject(parent), d_ptr(new QBluetoothServerPrivate(serverType)) + : QObject(parent), d_ptr(new QBluetoothServerPrivate(serverType, this)) { - d_ptr->q_ptr = this; } /*! diff --git a/src/bluetooth/qbluetoothserver_android.cpp b/src/bluetooth/qbluetoothserver_android.cpp index 4c469c76..eed3a1ea 100644 --- a/src/bluetooth/qbluetoothserver_android.cpp +++ b/src/bluetooth/qbluetoothserver_android.cpp @@ -53,9 +53,10 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID) QHash __fakeServerPorts; -QBluetoothServerPrivate::QBluetoothServerPrivate(QBluetoothServiceInfo::Protocol sType) +QBluetoothServerPrivate::QBluetoothServerPrivate(QBluetoothServiceInfo::Protocol sType, + QBluetoothServer *parent) : socket(0),maxPendingConnections(1), securityFlags(QBluetooth::NoSecurity), serverType(sType), - m_lastError(QBluetoothServer::NoError) + m_lastError(QBluetoothServer::NoError), q_ptr(parent) { thread = new ServerAcceptanceThread(); thread->setMaxPendingConnections(maxPendingConnections); diff --git a/src/bluetooth/qbluetoothserver_bluez.cpp b/src/bluetooth/qbluetoothserver_bluez.cpp index 54bc85a0..a98f5398 100644 --- a/src/bluetooth/qbluetoothserver_bluez.cpp +++ b/src/bluetooth/qbluetoothserver_bluez.cpp @@ -66,9 +66,10 @@ QBluetoothSocket *QBluetoothServerPrivate::createSocketForServer( return socket; } -QBluetoothServerPrivate::QBluetoothServerPrivate(QBluetoothServiceInfo::Protocol sType) +QBluetoothServerPrivate::QBluetoothServerPrivate(QBluetoothServiceInfo::Protocol sType, + QBluetoothServer *parent) : maxPendingConnections(1), securityFlags(QBluetooth::Authorization), serverType(sType), - m_lastError(QBluetoothServer::NoError) + m_lastError(QBluetoothServer::NoError), q_ptr(parent) { if (sType == QBluetoothServiceInfo::RfcommProtocol) socket = createSocketForServer(QBluetoothServiceInfo::RfcommProtocol); diff --git a/src/bluetooth/qbluetoothserver_p.cpp b/src/bluetooth/qbluetoothserver_p.cpp index 4f28c9b1..6657e151 100644 --- a/src/bluetooth/qbluetoothserver_p.cpp +++ b/src/bluetooth/qbluetoothserver_p.cpp @@ -46,8 +46,10 @@ QT_BEGIN_NAMESPACE -QBluetoothServerPrivate::QBluetoothServerPrivate(QBluetoothServiceInfo::Protocol sType) - : maxPendingConnections(1), serverType(sType), m_lastError(QBluetoothServer::NoError) +QBluetoothServerPrivate::QBluetoothServerPrivate(QBluetoothServiceInfo::Protocol sType, + QBluetoothServer *parent) + : maxPendingConnections(1), serverType(sType), m_lastError(QBluetoothServer::NoError), + q_ptr(parent) { #ifndef QT_IOS_BLUETOOTH printDummyWarning(); diff --git a/src/bluetooth/qbluetoothserver_p.h b/src/bluetooth/qbluetoothserver_p.h index d78eee5f..5ace7f75 100644 --- a/src/bluetooth/qbluetoothserver_p.h +++ b/src/bluetooth/qbluetoothserver_p.h @@ -57,7 +57,7 @@ #include "qbluetoothserver.h" #include "qbluetooth.h" -#if QT_CONFIG(bluez) +#if QT_CONFIG(bluez) || defined(QT_WIN_BLUETOOTH) QT_FORWARD_DECLARE_CLASS(QSocketNotifier) #endif @@ -81,7 +81,6 @@ QT_BEGIN_NAMESPACE class QBluetoothAddress; class QBluetoothSocket; - class QBluetoothServer; #ifndef QT_OSX_BLUETOOTH @@ -91,7 +90,7 @@ class QBluetoothServerPrivate Q_DECLARE_PUBLIC(QBluetoothServer) public: - QBluetoothServerPrivate(QBluetoothServiceInfo::Protocol serverType); + QBluetoothServerPrivate(QBluetoothServiceInfo::Protocol serverType, QBluetoothServer *parent); ~QBluetoothServerPrivate(); #if QT_CONFIG(bluez) @@ -101,6 +100,9 @@ public: static QBluetoothSocket *createSocketForServer( QBluetoothServiceInfo::Protocol socketType = QBluetoothServiceInfo::RfcommProtocol); #endif +#if defined(QT_WIN_BLUETOOTH) + void _q_newConnection(); +#endif public: QBluetoothSocket *socket; @@ -114,7 +116,7 @@ protected: private: QBluetoothServer::Error m_lastError; -#if QT_CONFIG(bluez) +#if QT_CONFIG(bluez) || defined(QT_WIN_BLUETOOTH) QSocketNotifier *socketNotifier = nullptr; #elif defined(QT_ANDROID_BLUETOOTH) ServerAcceptanceThread *thread; diff --git a/src/bluetooth/qbluetoothserver_win.cpp b/src/bluetooth/qbluetoothserver_win.cpp index a9f8659e..a57d39a5 100644 --- a/src/bluetooth/qbluetoothserver_win.cpp +++ b/src/bluetooth/qbluetoothserver_win.cpp @@ -40,35 +40,134 @@ #include "qbluetoothserver.h" #include "qbluetoothserver_p.h" #include "qbluetoothsocket.h" +#include "qbluetoothlocaldevice.h" + +#include +#include + +#include +#include +#include QT_BEGIN_NAMESPACE -QBluetoothServerPrivate::QBluetoothServerPrivate(QBluetoothServiceInfo::Protocol sType) - : maxPendingConnections(1), serverType(sType), m_lastError(QBluetoothServer::NoError) +Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINDOWS) + +QBluetoothServerPrivate::QBluetoothServerPrivate(QBluetoothServiceInfo::Protocol sType, + QBluetoothServer *parent) + : maxPendingConnections(1), serverType(sType), q_ptr(parent), + m_lastError(QBluetoothServer::NoError) { - if (sType == QBluetoothServiceInfo::RfcommProtocol) - socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol); - else - socket = new QBluetoothSocket(QBluetoothServiceInfo::L2capProtocol); + Q_Q(QBluetoothServer); + Q_ASSERT(sType == QBluetoothServiceInfo::RfcommProtocol); + socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol, q); } QBluetoothServerPrivate::~QBluetoothServerPrivate() { - delete socket; +} + +void QBluetoothServerPrivate::_q_newConnection() +{ + // disable socket notifier until application calls nextPendingConnection(). + socketNotifier->setEnabled(false); + + emit q_ptr->newConnection(); } void QBluetoothServer::close() { + Q_D(QBluetoothServer); + + delete d->socketNotifier; + d->socketNotifier = nullptr; + + d->socket->close(); } bool QBluetoothServer::listen(const QBluetoothAddress &address, quint16 port) { - Q_UNUSED(address); - Q_UNUSED(port); Q_D(QBluetoothServer); - d->m_lastError = UnsupportedProtocolError; - emit error(d->m_lastError); - return false; + + if (d->serverType != QBluetoothServiceInfo::RfcommProtocol) { + qCWarning(QT_BT_WINDOWS) << "Protocol is not supported."; + d->m_lastError = QBluetoothServer::UnsupportedProtocolError; + emit error(d->m_lastError); + return false; + } + + if (d->socket->state() == QBluetoothSocket::ListeningState) { + qCWarning(QT_BT_WINDOWS) << "Socket already in listen mode, close server first"; + return false; + } + + const QBluetoothLocalDevice device(address); + if (!device.isValid()) { + qCWarning(QT_BT_WINDOWS) << "Device does not support Bluetooth or" + << address.toString() << "is not a valid local adapter"; + d->m_lastError = QBluetoothServer::UnknownError; + emit error(d->m_lastError); + return false; + } + + const QBluetoothLocalDevice::HostMode hostMode = device.hostMode(); + if (hostMode == QBluetoothLocalDevice::HostPoweredOff) { + d->m_lastError = QBluetoothServer::PoweredOffError; + emit error(d->m_lastError); + qCWarning(QT_BT_WINDOWS) << "Bluetooth device is powered off"; + return false; + } + + int sock = d->socket->socketDescriptor(); + if (sock < 0) { + /* Negative socket descriptor is not always an error case. + * Another cause could be a call to close()/abort(). + * Check whether we can recover by re-creating the socket. + */ + delete d->socket; + d->socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol, this); + sock = d->socket->socketDescriptor(); + if (sock < 0) { + d->m_lastError = InputOutputError; + emit error(d->m_lastError); + return false; + } + } + + if (sock < 0) + return false; + + SOCKADDR_BTH addr = {}; + addr.addressFamily = AF_BTH; + addr.port = (port == 0) ? BT_PORT_ANY : port; + addr.btAddr = address.toUInt64(); + + if (::bind(sock, reinterpret_cast(&addr), sizeof(SOCKADDR_BTH)) < 0) { + if (errno == EADDRINUSE) + d->m_lastError = ServiceAlreadyRegisteredError; + else + d->m_lastError = InputOutputError; + emit error(d->m_lastError); + return false; + } + + if (::listen(sock, d->maxPendingConnections) < 0) { + d->m_lastError = InputOutputError; + emit error(d->m_lastError); + return false; + } + + d->socket->setSocketState(QBluetoothSocket::ListeningState); + + if (!d->socketNotifier) { + d->socketNotifier = new QSocketNotifier(d->socket->socketDescriptor(), + QSocketNotifier::Read, this); + connect(d->socketNotifier, &QSocketNotifier::activated, this, [d](){ + d->_q_newConnection(); + }); + } + + return true; } void QBluetoothServer::setMaxPendingConnections(int numConnections) @@ -78,22 +177,53 @@ void QBluetoothServer::setMaxPendingConnections(int numConnections) bool QBluetoothServer::hasPendingConnections() const { - return false; + Q_D(const QBluetoothServer); + + if (!d || !d->socketNotifier) + return false; + + // if the socket notifier is disabled there is a pending connection waiting for us to accept. + return !d->socketNotifier->isEnabled(); } QBluetoothSocket *QBluetoothServer::nextPendingConnection() { - return 0; + Q_D(QBluetoothServer); + + if (!hasPendingConnections()) + return nullptr; + + if (d->serverType != QBluetoothServiceInfo::RfcommProtocol) + return nullptr; + + SOCKADDR_BTH addr = {}; + int length = sizeof(SOCKADDR_BTH); + int pending = ::accept(d->socket->socketDescriptor(), + reinterpret_cast(&addr), &length); + + QBluetoothSocket *newSocket = nullptr; + + if (pending >= 0) { + newSocket = new QBluetoothSocket(); + newSocket->setSocketDescriptor(pending, QBluetoothServiceInfo::RfcommProtocol); + } + + d->socketNotifier->setEnabled(true); + return newSocket; } QBluetoothAddress QBluetoothServer::serverAddress() const { - return QBluetoothAddress(); + Q_D(const QBluetoothServer); + + return d->socket->localAddress(); } quint16 QBluetoothServer::serverPort() const { - return 0; + Q_D(const QBluetoothServer); + + return d->socket->localPort(); } void QBluetoothServer::setSecurityFlags(QBluetooth::SecurityFlags security) diff --git a/src/bluetooth/qbluetoothserver_winrt.cpp b/src/bluetooth/qbluetoothserver_winrt.cpp index 3bcd6b33..b9d98eb7 100644 --- a/src/bluetooth/qbluetoothserver_winrt.cpp +++ b/src/bluetooth/qbluetoothserver_winrt.cpp @@ -70,8 +70,10 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINRT) QHash __fakeServerPorts; -QBluetoothServerPrivate::QBluetoothServerPrivate(QBluetoothServiceInfo::Protocol sType) - : maxPendingConnections(1), serverType(sType), m_lastError(QBluetoothServer::NoError), socket(0) +QBluetoothServerPrivate::QBluetoothServerPrivate(QBluetoothServiceInfo::Protocol sType, + QBluetoothServer *parent) + : maxPendingConnections(1), serverType(sType), m_lastError(QBluetoothServer::NoError), + socket(0), q_ptr(parent) { #ifdef CLASSIC_APP_BUILD CoInitialize(NULL); diff --git a/src/bluetooth/qbluetoothservicediscoveryagent.h b/src/bluetooth/qbluetoothservicediscoveryagent.h index 8533ab72..f1fa4640 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent.h +++ b/src/bluetooth/qbluetoothservicediscoveryagent.h @@ -111,10 +111,6 @@ Q_SIGNALS: private: QBluetoothServiceDiscoveryAgentPrivate *d_ptr; - -#ifdef QT_WIN_BLUETOOTH - Q_PRIVATE_SLOT(d_func(), void _q_nextSdpScan(QVariant input)) -#endif }; QT_END_NAMESPACE diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_p.h b/src/bluetooth/qbluetoothservicediscoveryagent_p.h index 4a522826..cb588f70 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent_p.h +++ b/src/bluetooth/qbluetoothservicediscoveryagent_p.h @@ -165,6 +165,7 @@ public: #endif #ifdef QT_WIN_BLUETOOTH void _q_nextSdpScan(const QVariant &input); + bool serviceMatches(const QBluetoothServiceInfo &info); #endif private: diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_win.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_win.cpp index 98ec1952..c34443aa 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent_win.cpp +++ b/src/bluetooth/qbluetoothservicediscoveryagent_win.cpp @@ -49,55 +49,30 @@ #include #include #include -#include -#include - -Q_GLOBAL_STATIC(QLibrary, bluetoothapis) - -#define DEFINEFUNC(ret, func, ...) \ - typedef ret (WINAPI *fp_##func)(__VA_ARGS__); \ - static fp_##func p##func; -#define RESOLVEFUNC(func) \ - p##func = (fp_##func)resolveFunction(library, #func); \ - if (!p##func) \ - return false; +#if defined(Q_CC_MINGW) +// Workaround for MinGW headers declaring BluetoothSdpGetElementData incorrectly. +# define BluetoothSdpGetElementData _BluetoothSdpGetElementData_notok +# include +# undef BluetoothSdpGetElementData + extern "C" DWORD WINAPI BluetoothSdpGetElementData(LPBYTE, ULONG, PSDP_ELEMENT_DATA); +#else +# include +#endif -DEFINEFUNC(DWORD, BluetoothSdpGetElementData, LPBYTE, ULONG, PSDP_ELEMENT_DATA) +#include +#include QT_BEGIN_NAMESPACE struct FindServiceResult { QBluetoothServiceInfo info; - Qt::HANDLE hSearch; - int systemError; + Qt::HANDLE hSearch = INVALID_HANDLE_VALUE; + int systemError = NO_ERROR; }; Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINDOWS) -static inline QFunctionPointer resolveFunction(QLibrary *library, const char *func) -{ - const QFunctionPointer symbolFunctionPointer = library->resolve(func); - if (!symbolFunctionPointer) - qWarning("Cannot resolve '%s' in '%s'.", func, qPrintable(library->fileName())); - return symbolFunctionPointer; -} - -static inline bool resolveFunctions(QLibrary *library) -{ - if (!library->isLoaded()) { - library->setFileName(QStringLiteral("bluetoothapis")); - if (!library->load()) { - qWarning("Unable to load '%s' library.", qPrintable(library->fileName())); - return false; - } - } - - RESOLVEFUNC(BluetoothSdpGetElementData) - - return true; -} - static QList spdContainerToVariantList(LPBYTE containerStream, ULONG containerLength); static QVariant spdElementToVariant(const SDP_ELEMENT_DATA &element) @@ -152,19 +127,15 @@ static QVariant spdElementToVariant(const SDP_ELEMENT_DATA &element) } case SDP_TYPE_UUID: { switch (element.specificType) { - case SDP_ST_UUID128: { - //Not sure if this will work, might be evil - Q_ASSERT(sizeof(element.data.uuid128) == sizeof(quint128)); - - quint128 uuid128; - memcpy(&uuid128, &(element.data.uuid128), sizeof(quint128)); - - variant = QVariant::fromValue(QBluetoothUuid(uuid128)); - } + case SDP_ST_UUID128: + variant = QVariant::fromValue(QBluetoothUuid(element.data.uuid128)); + break; case SDP_ST_UUID32: variant = QVariant::fromValue(QBluetoothUuid(quint32(element.data.uuid32))); + break; case SDP_ST_UUID16: variant = QVariant::fromValue(QBluetoothUuid(quint16(element.data.uuid16))); + break; default: break; } @@ -177,7 +148,7 @@ static QVariant spdElementToVariant(const SDP_ELEMENT_DATA &element) } case SDP_TYPE_URL: { const QString urlString = QString::fromLocal8Bit(reinterpret_cast(element.data.url.value), - (int)element.data.url.length); + int(element.data.url.length)); const QUrl url(urlString); if (url.isValid()) variant = QVariant::fromValue(url); @@ -198,7 +169,7 @@ static QVariant spdElementToVariant(const SDP_ELEMENT_DATA &element) break; } case SDP_TYPE_BOOLEAN: - variant = QVariant::fromValue((bool)element.data.booleanVal); + variant = QVariant::fromValue(bool(element.data.booleanVal)); break; case SDP_TYPE_NIL: break; @@ -211,13 +182,13 @@ static QVariant spdElementToVariant(const SDP_ELEMENT_DATA &element) static QList spdContainerToVariantList(LPBYTE containerStream, ULONG containerLength) { - HBLUETOOTH_CONTAINER_ELEMENT iter = NULL; - SDP_ELEMENT_DATA element; + HBLUETOOTH_CONTAINER_ELEMENT iter = nullptr; + SDP_ELEMENT_DATA element = {}; QList sequence; for (;;) { - const DWORD result = BluetoothSdpGetContainerElementData(containerStream, + const DWORD result = ::BluetoothSdpGetContainerElementData(containerStream, containerLength, &iter, &element); @@ -244,9 +215,9 @@ static BOOL SDP_CALLBACK bluetoothSdpCallback(ULONG attributeId, LPBYTE valueStr { QBluetoothServiceInfo *result = static_cast(param); - SDP_ELEMENT_DATA element; + SDP_ELEMENT_DATA element = {}; - if (pBluetoothSdpGetElementData(valueStream, streamSize, &element) == ERROR_SUCCESS) + if (::BluetoothSdpGetElementData(valueStream, streamSize, &element) == ERROR_SUCCESS) { switch (element.type) { case SDP_TYPE_UINT: case SDP_TYPE_INT: @@ -257,6 +228,7 @@ static BOOL SDP_CALLBACK bluetoothSdpCallback(ULONG attributeId, LPBYTE valueStr case SDP_TYPE_SEQUENCE: case SDP_TYPE_ALTERNATIVE: { const QVariant variant = spdElementToVariant(element); + result->setAttribute(attributeId, variant); break; } @@ -265,7 +237,7 @@ static BOOL SDP_CALLBACK bluetoothSdpCallback(ULONG attributeId, LPBYTE valueStr default: break; } - + } return true; } @@ -281,13 +253,12 @@ enum { static FindServiceResult findNextService(HANDLE hSearch) { FindServiceResult result; - result.systemError = NO_ERROR; result.hSearch = hSearch; QByteArray resultBuffer(2048, 0); WSAQUERYSET *resultQuery = reinterpret_cast(resultBuffer.data()); DWORD resultBufferSize = DWORD(resultBuffer.size()); - const int resultCode = WSALookupServiceNext(hSearch, + const int resultCode = ::WSALookupServiceNext(hSearch, WSAControlFlags, &resultBufferSize, resultQuery); @@ -295,12 +266,12 @@ static FindServiceResult findNextService(HANDLE hSearch) if (resultCode == SOCKET_ERROR) { result.systemError = ::WSAGetLastError(); if (result.systemError == WSA_E_NO_MORE) - WSALookupServiceEnd(hSearch); + ::WSALookupServiceEnd(hSearch); return result; } if (resultQuery->lpBlob - && BluetoothSdpEnumAttributes(resultQuery->lpBlob->pBlobData, + && ::BluetoothSdpEnumAttributes(resultQuery->lpBlob->pBlobData, resultQuery->lpBlob->cbSize, bluetoothSdpCallback, &result.info)) { @@ -313,38 +284,35 @@ static FindServiceResult findNextService(HANDLE hSearch) static FindServiceResult findFirstService(const QBluetoothAddress &address) { - //### should we try for 2.2 on all platforms ?? - WSAData wsadata; + WSAData wsadata = {}; FindServiceResult result; - result.hSearch = INVALID_HANDLE_VALUE; // IPv6 requires Winsock v2.0 or better. - if (WSAStartup(MAKEWORD(2, 0), &wsadata) != 0) { + if (::WSAStartup(MAKEWORD(2, 0), &wsadata) != 0) { result.systemError = ::WSAGetLastError(); return result; } const QString addressAsString = QStringLiteral("(%1)").arg(address.toString()); - - QVector addressAsWChar(addressAsString.size()); + QVector addressAsWChar(addressAsString.size() + 1); addressAsString.toWCharArray(addressAsWChar.data()); GUID protocol = L2CAP_PROTOCOL_UUID; //Search for L2CAP and RFCOMM services WSAQUERYSET serviceQuery = {}; - serviceQuery.dwSize = sizeof(WSAQUERYSET); //As specified by the windows documentation - serviceQuery.lpServiceClassId = &protocol; //The protocal of the service what is being queried - serviceQuery.dwNameSpace = NS_BTH; //As specified by the windows documentation - serviceQuery.dwNumberOfCsAddrs = 0; //As specified by the windows documentation - serviceQuery.lpszContext = addressAsWChar.data(); //The remote address that query will run on - - HANDLE hSearch; - const int resultCode = WSALookupServiceBegin(&serviceQuery, + serviceQuery.dwSize = sizeof(WSAQUERYSET); + serviceQuery.lpServiceClassId = &protocol; + serviceQuery.dwNameSpace = NS_BTH; + serviceQuery.dwNumberOfCsAddrs = 0; + serviceQuery.lpszContext = addressAsWChar.data(); + + HANDLE hSearch = nullptr; + const int resultCode = ::WSALookupServiceBegin(&serviceQuery, WSAControlFlags, &hSearch); if (resultCode == SOCKET_ERROR) { result.systemError = ::WSAGetLastError(); - WSALookupServiceEnd(hSearch); + ::WSALookupServiceEnd(hSearch); return result; } return findNextService(hSearch); @@ -363,8 +331,6 @@ QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate( { Q_UNUSED(deviceAdapter); - resolveFunctions(bluetoothapis()); - threadFind = new QThread; threadWorkerFind = new ThreadWorkerFind; threadWorkerFind->moveToThread(threadFind); @@ -376,9 +342,8 @@ QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate( QBluetoothServiceDiscoveryAgentPrivate::~QBluetoothServiceDiscoveryAgentPrivate() { - if (pendingFinish) { + if (pendingFinish) stop(); - } if (threadFind) threadFind->quit(); } @@ -392,7 +357,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &addr const auto threadWorker = threadWorkerFind; QMetaObject::invokeMethod(threadWorkerFind, [threadWorker, address]() { - FindServiceResult result = findFirstService(address); + const FindServiceResult result = findFirstService(address); emit threadWorker->findFinished(QVariant::fromValue(result)); }, Qt::QueuedConnection); } @@ -403,13 +368,29 @@ void QBluetoothServiceDiscoveryAgentPrivate::stop() pendingStop = true; } +bool QBluetoothServiceDiscoveryAgentPrivate::serviceMatches(const QBluetoothServiceInfo &info) +{ + if (uuidFilter.isEmpty()) + return true; + + if (uuidFilter.contains(info.serviceUuid())) + return true; + + const QList serviceClassUuids = info.serviceClassUuids(); + for (const QBluetoothUuid &uuid : serviceClassUuids) + if (uuidFilter.contains(uuid)) + return true; + + return false; +} + void QBluetoothServiceDiscoveryAgentPrivate::_q_nextSdpScan(const QVariant &input) { Q_Q(QBluetoothServiceDiscoveryAgent); auto result = input.value(); if (pendingStop) { - WSALookupServiceEnd(result.hSearch); + ::WSALookupServiceEnd(result.hSearch); pendingStop = false; pendingFinish = false; emit q->canceled(); @@ -418,7 +399,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_nextSdpScan(const QVariant &inpu result.systemError = NO_ERROR; } else if (result.systemError != NO_ERROR) { if (result.hSearch != INVALID_HANDLE_VALUE) - WSALookupServiceEnd(result.hSearch); + ::WSALookupServiceEnd(result.hSearch); error = (result.systemError == ERROR_INVALID_HANDLE) ? QBluetoothServiceDiscoveryAgent::InvalidBluetoothAdapterError : QBluetoothServiceDiscoveryAgent::InputOutputError; @@ -426,13 +407,17 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_nextSdpScan(const QVariant &inpu qCWarning(QT_BT_WINDOWS) << errorString; emit q->error(this->error); } else { - result.info.setDevice(discoveredDevices.at(0)); - if (result.info.isValid()) { - if (!isDuplicatedService(result.info)) { - discoveredServices.append(result.info); - emit q->serviceDiscovered(result.info); + + if (serviceMatches(result.info)) { + result.info.setDevice(discoveredDevices.at(0)); + if (result.info.isValid()) { + if (!isDuplicatedService(result.info)) { + discoveredServices.append(result.info); + emit q->serviceDiscovered(result.info); + } } } + const auto threadWorker = threadWorkerFind; const auto hSearch = result.hSearch; QMetaObject::invokeMethod(threadWorkerFind, [threadWorker, hSearch]() diff --git a/src/bluetooth/qbluetoothserviceinfo_p.h b/src/bluetooth/qbluetoothserviceinfo_p.h index e4e835e4..0638867d 100644 --- a/src/bluetooth/qbluetoothserviceinfo_p.h +++ b/src/bluetooth/qbluetoothserviceinfo_p.h @@ -78,6 +78,11 @@ namespace ABI { } #endif +#ifdef QT_WIN_BLUETOOTH +#include +#include +#endif + QT_BEGIN_NAMESPACE class QBluetoothServiceInfo; @@ -120,6 +125,14 @@ private: bool writeSdpAttributes(); #endif +#ifdef QT_WIN_BLUETOOTH + SOCKADDR_BTH sockaddr = {}; + CSADDR_INFO addrinfo = {}; + WSAQUERYSET regInfo = {}; + QVector serviceName; + QVector serviceDescription; +#endif + mutable bool registered; }; diff --git a/src/bluetooth/qbluetoothserviceinfo_win.cpp b/src/bluetooth/qbluetoothserviceinfo_win.cpp index 6629e610..1f1293ad 100644 --- a/src/bluetooth/qbluetoothserviceinfo_win.cpp +++ b/src/bluetooth/qbluetoothserviceinfo_win.cpp @@ -39,10 +39,15 @@ #include "qbluetoothserviceinfo.h" #include "qbluetoothserviceinfo_p.h" +#include "qbluetoothserver_p.h" +#include "qbluetoothserver.h" + +#include QT_BEGIN_NAMESPACE QBluetoothServiceInfoPrivate::QBluetoothServiceInfoPrivate() + : registered(false) { } @@ -52,18 +57,64 @@ QBluetoothServiceInfoPrivate::~QBluetoothServiceInfoPrivate() bool QBluetoothServiceInfoPrivate::isRegistered() const { - return false; + return registered; } bool QBluetoothServiceInfoPrivate::registerService(const QBluetoothAddress &localAdapter) { - Q_UNUSED(localAdapter); - return false; + if (registered) + return false; + + GUID serviceUuid = attributes.value(QBluetoothServiceInfo::ServiceId).value(); + const QString name = attributes.value(QBluetoothServiceInfo::ServiceName).toString(); + const QString description = attributes.value(QBluetoothServiceInfo::ServiceDescription).toString(); + + ::memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.addressFamily = AF_BTH; + sockaddr.port = serverChannel(); + sockaddr.btAddr = localAdapter.toUInt64(); + + ::memset(&addrinfo, 0, sizeof(addrinfo)); + addrinfo.LocalAddr.iSockaddrLength = sizeof(SOCKADDR_BTH); + addrinfo.LocalAddr.lpSockaddr = (LPSOCKADDR)&sockaddr; + addrinfo.RemoteAddr.iSockaddrLength = sizeof(SOCKADDR_BTH); + addrinfo.RemoteAddr.lpSockaddr = (LPSOCKADDR)&sockaddr; + addrinfo.iSocketType = SOCK_STREAM; + addrinfo.iProtocol = BTHPROTO_RFCOMM; + + serviceName.resize(name.size() + 1); + name.toWCharArray(serviceName.data()); + serviceName[name.size()] = WCHAR(0); + serviceDescription.resize(description.size() + 1); + description.toWCharArray(serviceDescription.data()); + serviceDescription[description.size()] = WCHAR(0); + + ::memset(®Info, 0, sizeof(regInfo)); + regInfo.dwSize = sizeof(WSAQUERYSET); + regInfo.dwNameSpace = NS_BTH; + regInfo.dwNumberOfCsAddrs = 1; + regInfo.lpcsaBuffer = &addrinfo; + regInfo.lpszServiceInstanceName = serviceName.data(); + regInfo.lpszComment = serviceDescription.data(); + regInfo.lpServiceClassId = &serviceUuid; + + if (::WSASetService(®Info, RNRSERVICE_REGISTER, 0) == SOCKET_ERROR) + return false; + + registered = true; + return true; } bool QBluetoothServiceInfoPrivate::unregisterService() { - return false; + if (!registered) + return false; + + if (::WSASetService(®Info, RNRSERVICE_DELETE, 0) == SOCKET_ERROR) + return false; + + registered = false; + return true; } QT_END_NAMESPACE diff --git a/src/bluetooth/qbluetoothsocket_win.cpp b/src/bluetooth/qbluetoothsocket_win.cpp index 781decad..83855323 100644 --- a/src/bluetooth/qbluetoothsocket_win.cpp +++ b/src/bluetooth/qbluetoothsocket_win.cpp @@ -57,6 +57,8 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINDOWS) QBluetoothSocketPrivateWin::QBluetoothSocketPrivateWin() : QBluetoothSocketBasePrivate() { + WSAData wsadata = {}; + ::WSAStartup(MAKEWORD(2, 0), &wsadata); } QBluetoothSocketPrivateWin::~QBluetoothSocketPrivateWin() @@ -73,20 +75,17 @@ bool QBluetoothSocketPrivateWin::ensureNativeSocket(QBluetoothServiceInfo::Proto return true; abort(); } - socketType = type; - switch (type) { - case QBluetoothServiceInfo::RfcommProtocol: - socket = ::socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM); - break; - default: - socket = INVALID_SOCKET; + if (type != QBluetoothServiceInfo::RfcommProtocol) { + socket = int(INVALID_SOCKET); errorString = QBluetoothSocket::tr("Unsupported protocol. Win32 only supports RFCOMM sockets"); q->setSocketError(QBluetoothSocket::UnsupportedProtocolError); return false; } + socket = ::socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM); + if (static_cast(socket) == INVALID_SOCKET) { const int error = ::WSAGetLastError(); qCWarning(QT_BT_WINDOWS) << "Failed to create socket:" << error << qt_error_string(error); @@ -157,27 +156,14 @@ void QBluetoothSocketPrivateWin::connectToService( // we are checking the service protocol and not socketType() // socketType will change in ensureNativeSocket() - if (service.socketProtocol() == QBluetoothServiceInfo::UnknownProtocol) { - qCWarning(QT_BT_WINDOWS) << "QBluetoothSocket::connectToService cannot " - "connect with 'UnknownProtocol' (type provided by given service)"; + if (service.socketProtocol() != QBluetoothServiceInfo::RfcommProtocol) { + qCWarning(QT_BT_WINDOWS) << "QBluetoothSocket::connectToService called with unsupported protocol"; errorString = QBluetoothSocket::tr("Socket type not supported"); q->setSocketError(QBluetoothSocket::UnsupportedProtocolError); return; } - if (service.protocolServiceMultiplexer() > 0) { - Q_ASSERT(service.socketProtocol() == QBluetoothServiceInfo::L2capProtocol); - - if (!ensureNativeSocket(QBluetoothServiceInfo::L2capProtocol)) { - errorString = QBluetoothSocket::tr("Unknown socket error"); - q->setSocketError(QBluetoothSocket::UnknownSocketError); - return; - } - connectToServiceHelper(service.device().address(), service.protocolServiceMultiplexer(), - openMode); - } else if (service.serverChannel() > 0) { - Q_ASSERT(service.socketProtocol() == QBluetoothServiceInfo::RfcommProtocol); - + if (service.serverChannel() > 0) { if (!ensureNativeSocket(QBluetoothServiceInfo::RfcommProtocol)) { errorString = QBluetoothSocket::tr("Unknown socket error"); q->setSocketError(QBluetoothSocket::UnknownSocketError); @@ -195,14 +181,13 @@ void QBluetoothSocketPrivateWin::connectToService( q->doDeviceDiscovery(service, openMode); } } + void QBluetoothSocketPrivateWin::_q_writeNotify() { Q_Q(QBluetoothSocket); if (state == QBluetoothSocket::ConnectingState) { - updateAddressesAndPorts(); q->setSocketState(QBluetoothSocket::ConnectedState); - emit q->connected(); connectWriteNotifier->setEnabled(false); } else { if (txBuffer.isEmpty()) { @@ -220,7 +205,7 @@ void QBluetoothSocketPrivateWin::_q_writeNotify() q->setSocketError(QBluetoothSocket::NetworkError); } else if (writtenBytes <= size) { // add remainder back to buffer - char *remainder = &buf[writtenBytes]; + const char *remainder = &buf[writtenBytes]; txBuffer.ungetBlock(remainder, size - writtenBytes); if (writtenBytes > 0) emit q->bytesWritten(writtenBytes); @@ -264,6 +249,9 @@ void QBluetoothSocketPrivateWin::_q_readNotify() } q->disconnectFromService(); + } else if (bytesRead == 0) { + q->setSocketError(QBluetoothSocket::RemoteHostClosedError); + q->setSocketState(QBluetoothSocket::UnconnectedState); } else { const int unusedBytes = QPRIVATELINEARBUFFER_BUFFERSIZE - bytesRead; buffer.chop(unusedBytes); @@ -280,11 +268,8 @@ void QBluetoothSocketPrivateWin::_q_exceptNotify() errorString = qt_error_string(error); q->setSocketError(QBluetoothSocket::UnknownSocketError); - if (state == QBluetoothSocket::ConnectingState) { + if (state == QBluetoothSocket::ConnectingState) abort(); - q->setSocketState(QBluetoothSocket::UnconnectedState); - emit q->disconnected(); - } } void QBluetoothSocketPrivateWin::connectToService( @@ -348,55 +333,104 @@ void QBluetoothSocketPrivateWin::abort() delete exceptNotifier; exceptNotifier = nullptr; - m_localAddress.clear(); - m_localPort = 0; - m_peerAddress.clear(); - m_peerPort = 0; - // We don't transition through Closing for abort, so // we don't call disconnectFromService or QBluetoothSocket::close ::closesocket(socket); - socket = INVALID_SOCKET; + socket = int(INVALID_SOCKET); + + Q_Q(QBluetoothSocket); + + const bool wasConnected = q->state() == QBluetoothSocket::ConnectedState; + q->setSocketState(QBluetoothSocket::UnconnectedState); + if (wasConnected) { + q->setOpenMode(QIODevice::NotOpen); + emit q->readChannelFinished(); + } } QString QBluetoothSocketPrivateWin::localName() const { - const QBluetoothLocalDevice device(m_localAddress); + const QBluetoothAddress localAddr = localAddress(); + if (localAddr == QBluetoothAddress()) + return {}; + const QBluetoothLocalDevice device(localAddr); return device.name(); } QBluetoothAddress QBluetoothSocketPrivateWin::localAddress() const { - return m_localAddress; + if (static_cast(socket) == INVALID_SOCKET) + return {}; + SOCKADDR_BTH localAddr = {}; + int localAddrLength = sizeof(localAddr); + const int localResult = ::getsockname(socket, reinterpret_cast(&localAddr), &localAddrLength); + if (localResult == SOCKET_ERROR) { + const int error = ::WSAGetLastError(); + qCWarning(QT_BT_WINDOWS) << "Error getting local address" << error << qt_error_string(error); + return {}; + } + return QBluetoothAddress(localAddr.btAddr); } quint16 QBluetoothSocketPrivateWin::localPort() const { - return m_localPort; + if (static_cast(socket) == INVALID_SOCKET) + return {}; + SOCKADDR_BTH localAddr = {}; + int localAddrLength = sizeof(localAddr); + const int localResult = ::getsockname(socket, reinterpret_cast(&localAddr), &localAddrLength); + if (localResult == SOCKET_ERROR) { + const int error = ::WSAGetLastError(); + qCWarning(QT_BT_WINDOWS) << "Error getting local port" << error << qt_error_string(error); + return {}; + } + return localAddr.port; } QString QBluetoothSocketPrivateWin::peerName() const { - if (static_cast(socket) == INVALID_SOCKET) + const QBluetoothAddress peerAddr = peerAddress(); + if (peerAddr == QBluetoothAddress()) return {}; BLUETOOTH_DEVICE_INFO bdi = {}; bdi.dwSize = sizeof(bdi); - bdi.Address.ullLong = m_peerAddress.toUInt64(); + bdi.Address.ullLong = peerAddr.toUInt64(); const DWORD res = ::BluetoothGetDeviceInfo(nullptr, &bdi); - if (res == ERROR_SUCCESS) - return QString::fromWCharArray(&bdi.szName[0]); - qCWarning(QT_BT_WINDOWS) << "Error calling BluetoothGetDeviceInfo" << res << qt_error_string(res); - return {}; + if (res != ERROR_SUCCESS) { + qCWarning(QT_BT_WINDOWS) << "Error calling BluetoothGetDeviceInfo" << res << qt_error_string(res); + return {}; + } + return QString::fromWCharArray(&bdi.szName[0]); } QBluetoothAddress QBluetoothSocketPrivateWin::peerAddress() const { - return m_peerAddress; + if (static_cast(socket) == INVALID_SOCKET) + return {}; + SOCKADDR_BTH peerAddr = {}; + int peerAddrLength = sizeof(peerAddr); + const int peerResult = ::getpeername(socket, reinterpret_cast(&peerAddr), &peerAddrLength); + if (peerResult == SOCKET_ERROR) { + const int error = ::WSAGetLastError(); + qCWarning(QT_BT_WINDOWS) << "Error getting peer address and port" << error << qt_error_string(error); + return {}; + } + return QBluetoothAddress(peerAddr.btAddr); } quint16 QBluetoothSocketPrivateWin::peerPort() const { - return m_peerPort; + if (static_cast(socket) == INVALID_SOCKET) + return {}; + SOCKADDR_BTH peerAddr = {}; + int peerAddrLength = sizeof(peerAddr); + const int peerResult = ::getpeername(socket, reinterpret_cast(&peerAddr), &peerAddrLength); + if (peerResult == SOCKET_ERROR) { + const int error = ::WSAGetLastError(); + qCWarning(QT_BT_WINDOWS) << "Error getting peer address and port" << error << qt_error_string(error); + return {}; + } + return peerAddr.port; } qint64 QBluetoothSocketPrivateWin::writeData(const char *data, qint64 maxSize) @@ -427,8 +461,10 @@ qint64 QBluetoothSocketPrivateWin::writeData(const char *data, qint64 maxSize) if (!connectWriteNotifier) return -1; - if (txBuffer.isEmpty()) + if (txBuffer.isEmpty()) { connectWriteNotifier->setEnabled(true); + QMetaObject::invokeMethod(this, "_q_writeNotify", Qt::QueuedConnection); + } char *txbuf = txBuffer.reserve(maxSize); ::memcpy(txbuf, data, maxSize); @@ -459,19 +495,20 @@ void QBluetoothSocketPrivateWin::close() connectWriteNotifier->setEnabled(true); } -bool QBluetoothSocketPrivateWin::setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType_, - QBluetoothSocket::SocketState socketState, QBluetoothSocket::OpenMode openMode) +bool QBluetoothSocketPrivateWin::setSocketDescriptor(int socketDescriptor, + QBluetoothServiceInfo::Protocol protocol, + QBluetoothSocket::SocketState socketState, + QBluetoothSocket::OpenMode openMode) { Q_Q(QBluetoothSocket); abort(); - socketType = socketType_; + socketType = protocol; socket = socketDescriptor; if (!createNotifiers()) return false; - updateAddressesAndPorts(); q->setSocketState(socketState); q->setOpenMode(openMode); if (socketState == QBluetoothSocket::ConnectedState) { @@ -526,33 +563,6 @@ bool QBluetoothSocketPrivateWin::createNotifiers() return true; } -void QBluetoothSocketPrivateWin::updateAddressesAndPorts() -{ - SOCKADDR_BTH localAddr = {}; - int localAddrLength = sizeof(localAddr); - const int localResult = ::getsockname(socket, reinterpret_cast(&localAddr), &localAddrLength); - if (localResult != SOCKET_ERROR) { - m_localAddress = QBluetoothAddress(localAddr.btAddr); - m_localPort = localAddr.port; - } else { - const int error = ::WSAGetLastError(); - qCWarning(QT_BT_WINDOWS) << "Error getting local address and port" << error << qt_error_string(error); - errorString = QBluetoothSocket::tr("Cannot get socket's local address and port"); - } - - SOCKADDR_BTH peerAddr = {}; - int peerAddrLength = sizeof(peerAddr); - const int peerResult = ::getpeername(socket, reinterpret_cast(&peerAddr), &peerAddrLength); - if (peerResult != SOCKET_ERROR) { - m_peerAddress = QBluetoothAddress(peerAddr.btAddr); - m_peerPort = peerAddr.port; - } else { - const int error = ::WSAGetLastError(); - qCWarning(QT_BT_WINDOWS) << "Error getting peer address and port" << error << qt_error_string(error); - errorString = QBluetoothSocket::tr("Cannot get socket's peer address and port"); - } -} - bool QBluetoothSocketPrivateWin::configureSecurity() { Q_Q(QBluetoothSocket); diff --git a/src/bluetooth/qbluetoothsocket_win_p.h b/src/bluetooth/qbluetoothsocket_win_p.h index fe0fc99f..77f4842e 100644 --- a/src/bluetooth/qbluetoothsocket_win_p.h +++ b/src/bluetooth/qbluetoothsocket_win_p.h @@ -108,14 +108,9 @@ private slots: private: bool createNotifiers(); - void updateAddressesAndPorts(); bool configureSecurity(); QSocketNotifier *exceptNotifier = nullptr; - QBluetoothAddress m_localAddress; - quint16 m_localPort = 0; - QBluetoothAddress m_peerAddress; - quint16 m_peerPort = 0; }; QT_END_NAMESPACE diff --git a/src/bluetooth/qbluetoothtransfermanager.cpp b/src/bluetooth/qbluetoothtransfermanager.cpp index 37a3191a..d84f726c 100644 --- a/src/bluetooth/qbluetoothtransfermanager.cpp +++ b/src/bluetooth/qbluetoothtransfermanager.cpp @@ -121,8 +121,8 @@ QBluetoothTransferReply *QBluetoothTransferManager::put(const QBluetoothTransfer connect(reply, SIGNAL(finished(QBluetoothTransferReply*)), this, SIGNAL(finished(QBluetoothTransferReply*))); return reply; #else - // Android, iOS, and WinRT have no implementation -#if !defined(QT_ANDROID_BLUETOOTH) && !defined(QT_IOS_BLUETOOTH) && !defined(QT_WINRT_BLUETOOTH) + // Android, iOS, and Win/WinRT have no implementation +#if !defined(QT_ANDROID_BLUETOOTH) && !defined(QT_IOS_BLUETOOTH) && !defined(QT_WINRT_BLUETOOTH) && !defined(QT_WIN_BLUETOOTH) printDummyWarning(); #endif Q_UNUSED(request); diff --git a/src/bluetooth/qlowenergycontroller.cpp b/src/bluetooth/qlowenergycontroller.cpp index c3742b76..444bfb38 100644 --- a/src/bluetooth/qlowenergycontroller.cpp +++ b/src/bluetooth/qlowenergycontroller.cpp @@ -324,6 +324,7 @@ static QLowEnergyControllerPrivate *privateController(QLowEnergyController::Role return new QLowEnergyControllerPrivateWinRT(); #endif #elif defined(QT_WIN_BLUETOOTH) + Q_UNUSED(role); return new QLowEnergyControllerPrivateWin32(); #else Q_UNUSED(role); diff --git a/src/bluetooth/qlowenergycontroller_p.h b/src/bluetooth/qlowenergycontroller_p.h index fe1da852..54a49b53 100644 --- a/src/bluetooth/qlowenergycontroller_p.h +++ b/src/bluetooth/qlowenergycontroller_p.h @@ -104,7 +104,6 @@ public: const QByteArray &newValue) override; void addToGenericAttributeList(const QLowEnergyServiceData &service, - QLowEnergyHandle startHandle) override; }; diff --git a/src/bluetooth/qlowenergycontroller_win.cpp b/src/bluetooth/qlowenergycontroller_win.cpp index cc848d1e..ced69685 100644 --- a/src/bluetooth/qlowenergycontroller_win.cpp +++ b/src/bluetooth/qlowenergycontroller_win.cpp @@ -51,7 +51,7 @@ #include // for std::max -#include +#include QT_BEGIN_NAMESPACE @@ -81,7 +81,7 @@ public: return; m_value = QByteArray(reinterpret_cast(&gattValue->Data[0]), - gattValue->DataSize); + int(gattValue->DataSize)); } QByteArray m_value; @@ -109,12 +109,12 @@ static QString getServiceSystemPath(const QBluetoothAddress &deviceAddress, { const HDEVINFO deviceInfoSet = ::SetupDiGetClassDevs( reinterpret_cast(&serviceUuid), - NULL, - 0, + nullptr, + nullptr, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if (deviceInfoSet == INVALID_HANDLE_VALUE) { - *systemErrorCode = ::GetLastError(); + *systemErrorCode = int(::GetLastError()); return QString(); } @@ -128,11 +128,11 @@ static QString getServiceSystemPath(const QBluetoothAddress &deviceAddress, if (!::SetupDiEnumDeviceInterfaces( deviceInfoSet, - NULL, + nullptr, reinterpret_cast(&serviceUuid), index++, &deviceInterfaceData)) { - *systemErrorCode = ::GetLastError(); + *systemErrorCode = int(::GetLastError()); break; } @@ -140,11 +140,11 @@ static QString getServiceSystemPath(const QBluetoothAddress &deviceAddress, if (!::SetupDiGetDeviceInterfaceDetail( deviceInfoSet, &deviceInterfaceData, - NULL, + nullptr, deviceInterfaceDetailDataSize, &deviceInterfaceDetailDataSize, - NULL)) { - const DWORD error = ::GetLastError(); + nullptr)) { + const int error = int(::GetLastError()); if (error != ERROR_INSUFFICIENT_BUFFER) { *systemErrorCode = error; break; @@ -156,7 +156,7 @@ static QString getServiceSystemPath(const QBluetoothAddress &deviceAddress, deviceInfoData.cbSize = sizeof(deviceInfoData); QByteArray deviceInterfaceDetailDataBuffer( - deviceInterfaceDetailDataSize, 0); + int(deviceInterfaceDetailDataSize), 0); PSP_INTERFACE_DEVICE_DETAIL_DATA deviceInterfaceDetailData = reinterpret_cast @@ -169,10 +169,10 @@ static QString getServiceSystemPath(const QBluetoothAddress &deviceAddress, deviceInfoSet, &deviceInterfaceData, deviceInterfaceDetailData, - deviceInterfaceDetailDataBuffer.size(), + DWORD(deviceInterfaceDetailDataBuffer.size()), &deviceInterfaceDetailDataSize, &deviceInfoData)) { - *systemErrorCode = ::GetLastError(); + *systemErrorCode = int(::GetLastError()); break; } @@ -195,29 +195,28 @@ static HANDLE openSystemDevice( const QString &systemPath, QIODevice::OpenMode openMode, int *systemErrorCode) { DWORD desiredAccess = 0; - DWORD shareMode = 0; + DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; if (openMode & QIODevice::ReadOnly) { desiredAccess |= GENERIC_READ; - shareMode |= FILE_SHARE_READ; } if (openMode & QIODevice::WriteOnly) { desiredAccess |= GENERIC_WRITE; - shareMode |= FILE_SHARE_WRITE; + shareMode &= ~DWORD(FILE_SHARE_WRITE); } const HANDLE hDevice = ::CreateFile( reinterpret_cast(systemPath.utf16()), desiredAccess, shareMode, - NULL, + nullptr, OPEN_EXISTING, 0, - NULL); + nullptr); *systemErrorCode = (INVALID_HANDLE_VALUE == hDevice) - ? ::GetLastError() : NO_ERROR; + ? int(::GetLastError()) : NO_ERROR; return hDevice; } @@ -259,7 +258,7 @@ static QVector enumeratePrimaryGattServices( const HRESULT hr = ::BluetoothGATTGetServices( hDevice, servicesCount, - foundServices.isEmpty() ? NULL : &foundServices[0], + foundServices.isEmpty() ? nullptr : &foundServices[0], &servicesCount, BLUETOOTH_GATT_FLAG_NONE); @@ -267,7 +266,7 @@ static QVector enumeratePrimaryGattServices( *systemErrorCode = NO_ERROR; return foundServices; } else { - const DWORD error = WIN32_FROM_HRESULT(hr); + const int error = WIN32_FROM_HRESULT(hr); if (error == ERROR_MORE_DATA) { foundServices.resize(servicesCount); } else { @@ -293,7 +292,7 @@ static QVector enumerateGattCharacteristics( hService, gattService, characteristicsCount, - foundCharacteristics.isEmpty() ? NULL : &foundCharacteristics[0], + foundCharacteristics.isEmpty() ? nullptr : &foundCharacteristics[0], &characteristicsCount, BLUETOOTH_GATT_FLAG_NONE); @@ -301,7 +300,7 @@ static QVector enumerateGattCharacteristics( *systemErrorCode = NO_ERROR; return foundCharacteristics; } else { - const DWORD error = WIN32_FROM_HRESULT(hr); + const int error = WIN32_FROM_HRESULT(hr); if (error == ERROR_MORE_DATA) { foundCharacteristics.resize(characteristicsCount); } else { @@ -324,7 +323,7 @@ static QByteArray getGattCharacteristicValue( USHORT valueBufferSize = 0; for (;;) { const auto valuePtr = valueBuffer.isEmpty() - ? NULL + ? nullptr : reinterpret_cast(valueBuffer.data()); const HRESULT hr = ::BluetoothGATTGetCharacteristicValue( @@ -338,11 +337,12 @@ static QByteArray getGattCharacteristicValue( if (SUCCEEDED(hr)) { *systemErrorCode = NO_ERROR; return QByteArray(reinterpret_cast(&valuePtr->Data[0]), - valuePtr->DataSize); + int(valuePtr->DataSize)); } else { - const DWORD error = WIN32_FROM_HRESULT(hr); + const int error = WIN32_FROM_HRESULT(hr); if (error == ERROR_MORE_DATA) { valueBuffer.resize(valueBufferSize); + valueBuffer.fill(0); } else { *systemErrorCode = error; return QByteArray(); @@ -362,7 +362,7 @@ static void setGattCharacteristicValue( QByteArray valueBuffer; QDataStream out(&valueBuffer, QIODevice::WriteOnly); - ULONG dataSize = value.size(); + ULONG dataSize = ULONG(value.size()); out.writeRawData(reinterpret_cast(&dataSize), sizeof(dataSize)); out.writeRawData(value.constData(), value.size()); @@ -396,7 +396,7 @@ static QVector enumerateGattDescriptors( hService, gattCharacteristic, descriptorsCount, - foundDescriptors.isEmpty() ? NULL : &foundDescriptors[0], + foundDescriptors.isEmpty() ? nullptr : &foundDescriptors[0], &descriptorsCount, BLUETOOTH_GATT_FLAG_NONE); @@ -404,7 +404,7 @@ static QVector enumerateGattDescriptors( *systemErrorCode = NO_ERROR; return foundDescriptors; } else { - const DWORD error = WIN32_FROM_HRESULT(hr); + const int error = WIN32_FROM_HRESULT(hr); if (error == ERROR_MORE_DATA) { foundDescriptors.resize(descriptorsCount); } else { @@ -427,7 +427,7 @@ static QByteArray getGattDescriptorValue( USHORT valueBufferSize = 0; for (;;) { const auto valuePtr = valueBuffer.isEmpty() - ? NULL + ? nullptr : reinterpret_cast(valueBuffer.data()); const HRESULT hr = ::BluetoothGATTGetDescriptorValue( @@ -440,12 +440,18 @@ static QByteArray getGattDescriptorValue( if (SUCCEEDED(hr)) { *systemErrorCode = NO_ERROR; + if (gattDescriptor->DescriptorType == CharacteristicUserDescription) { + QString valueString = QString::fromUtf16(reinterpret_cast(&valuePtr->Data[0]), + valuePtr->DataSize/2); + return valueString.toUtf8(); + } return QByteArray(reinterpret_cast(&valuePtr->Data[0]), - valuePtr->DataSize); + int(valuePtr->DataSize)); } else { - const DWORD error = WIN32_FROM_HRESULT(hr); + const int error = WIN32_FROM_HRESULT(hr); if (error == ERROR_MORE_DATA) { valueBuffer.resize(valueBufferSize); + valueBuffer.fill(0); } else { *systemErrorCode = error; return QByteArray(); @@ -463,7 +469,7 @@ static void setGattDescriptorValue( return; } - const int requiredValueBufferSize = sizeof(BTH_LE_GATT_DESCRIPTOR_VALUE) + const int requiredValueBufferSize = int(sizeof(BTH_LE_GATT_DESCRIPTOR_VALUE)) + value.size(); QByteArray valueBuffer(requiredValueBufferSize, 0); @@ -486,7 +492,7 @@ static void setGattDescriptorValue( } gattValue->DataSize = ULONG(value.size()); - ::memcpy(gattValue->Data, value.constData(), value.size()); + ::memcpy(gattValue->Data, value.constData(), size_t(value.size())); const HRESULT hr = ::BluetoothGATTSetDescriptorValue( hService, @@ -579,7 +585,7 @@ static BTH_LE_UUID nativeLeUuidFromQtBluetoothUuid(const QBluetoothUuid &uuid) ::ZeroMemory(&gattUuid, sizeof(gattUuid)); if (uuid.minimumSize() == 2) { gattUuid.IsShortUuid = TRUE; - gattUuid.Value.ShortUuid = uuid.data1; // other fields should be empty! + gattUuid.Value.ShortUuid = USHORT(uuid.data1); // other fields should be empty! } else { gattUuid.Value.LongUuid = uuid; } @@ -701,7 +707,6 @@ QLowEnergyControllerPrivateWin32::~QLowEnergyControllerPrivateWin32() void QLowEnergyControllerPrivateWin32::init() { - Q_UNIMPLEMENTED(); } void QLowEnergyControllerPrivateWin32::connectToDevice() @@ -762,7 +767,7 @@ void QLowEnergyControllerPrivateWin32::disconnectFromDevice() thread = nullptr; } - for (const QSharedPointer servicePrivate: serviceList) + for (const auto &servicePrivate: serviceList) closeSystemDevice(servicePrivate->hService); Q_Q(QLowEnergyController); @@ -839,6 +844,11 @@ void QLowEnergyControllerPrivateWin32::discoverServiceDetails( servicePrivate->hService = openSystemService(remoteDevice, service, QIODevice::ReadOnly | QIODevice::WriteOnly, &systemErrorCode); + if (systemErrorCode != NO_ERROR) { + servicePrivate->hService = openSystemService(remoteDevice, service, + QIODevice::ReadOnly, + &systemErrorCode); + } } if (systemErrorCode != NO_ERROR) { @@ -853,7 +863,7 @@ void QLowEnergyControllerPrivateWin32::discoverServiceDetails( servicePrivate->endHandle = servicePrivate->startHandle; const QVector foundCharacteristics = - enumerateGattCharacteristics(servicePrivate->hService, NULL, &systemErrorCode); + enumerateGattCharacteristics(servicePrivate->hService, nullptr, &systemErrorCode); if (systemErrorCode != NO_ERROR) { qCWarning(QT_BT_WINDOWS) << "Unable to get characteristics for service" << service.toString() @@ -868,7 +878,7 @@ void QLowEnergyControllerPrivateWin32::discoverServiceDetails( QLowEnergyServicePrivate::CharData detailsData; - detailsData.hValueChangeEvent = NULL; + detailsData.hValueChangeEvent = nullptr; detailsData.uuid = qtBluetoothUuidFromNativeLeUuid( gattCharacteristic.CharacteristicUuid); @@ -1150,7 +1160,7 @@ void QLowEnergyControllerPrivateWin32::jobFinished(const ThreadWorkerJob &job) } else { if (charDetails.hValueChangeEvent) { unregisterEvent(charDetails.hValueChangeEvent, &data.systemErrorCode); - charDetails.hValueChangeEvent = NULL; + charDetails.hValueChangeEvent = nullptr; } } -- cgit v1.2.3