summaryrefslogtreecommitdiffstats
path: root/src/bluetooth/qlowenergycontroller_bluez.cpp
diff options
context:
space:
mode:
authorAlex Blasche <alexander.blasche@qt.io>2017-05-18 09:08:29 +0200
committerAlex Blasche <alexander.blasche@qt.io>2017-05-29 10:24:32 +0000
commit8692ff9d1c32bcc56e4c8c0c9f07ee2eb1a2681d (patch)
tree37d3cbf7c137522865c6d76d29250e81d44de181 /src/bluetooth/qlowenergycontroller_bluez.cpp
parentca248e3667f52f951bdd60d923b25a6b8fb4296d (diff)
Avoid bluetoothd and QtBluetooth collision when connecting to BTLE dev
BlueZ's improving support for BTLE creates a new collision when attenpting to connect to remote BTLE devices. There can only ever be one connection. This patch ensures that when QtBluetooth attempts to connect we do not have a pending BTLE connection. This could have been caused via other QtBLuetooth based processes or applications such as bluetoothctl or bluetoothd in general. If a connection is pending we close the connection external to the current QtBLuetooth instance. This is not an ideal situation as several processes can potentially fight over btle access. The long term solution is a port of QtBluetooth to BlueZ's new DBus API. Task-number: QTBUG-55150 Change-Id: I96b30ae180d1348027e8f9f09c997f44409dfc48 Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
Diffstat (limited to 'src/bluetooth/qlowenergycontroller_bluez.cpp')
-rw-r--r--src/bluetooth/qlowenergycontroller_bluez.cpp55
1 files changed, 54 insertions, 1 deletions
diff --git a/src/bluetooth/qlowenergycontroller_bluez.cpp b/src/bluetooth/qlowenergycontroller_bluez.cpp
index 40744670..1649fe8c 100644
--- a/src/bluetooth/qlowenergycontroller_bluez.cpp
+++ b/src/bluetooth/qlowenergycontroller_bluez.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Copyright (C) 2016 Javier S. Pedro <maemo@javispedro.com>
** Contact: https://www.qt.io/licensing/
**
@@ -44,6 +44,8 @@
#include "qleadvertiser_p.h"
#include "bluez/bluez_data_p.h"
#include "bluez/hcimanager_p.h"
+#include "bluez/remotedevicemanager_p.h"
+#include "bluez/bluez5_helper_p.h"
#include <QtCore/QFileInfo>
#include <QtCore/QLoggingCategory>
@@ -530,13 +532,64 @@ void QLowEnergyControllerPrivate::connectToDevice()
// check for active running connections
// BlueZ 5.37+ (maybe even earlier versions) can have pending BTLE connections
// Only one active L2CP socket to CID 0x4 possible at a time
+ // this check is not performed for BlueZ 4 based platforms as bluetoothd
+ // does not support BTLE management
+
+ if (!isBluez5()) {
+ establishL2cpClientSocket();
+ return;
+ }
+
QVector<quint16> activeHandles = hciManager->activeLowEnergyConnections();
if (!activeHandles.isEmpty()) {
qCWarning(QT_BT_BLUEZ) << "Cannot connect due to pending active LE connections";
+
+ if (!device1Manager) {
+ device1Manager = new RemoteDeviceManager(localAdapter, this);
+ connect(device1Manager, &RemoteDeviceManager::finished,
+ this, &QLowEnergyControllerPrivate::activeConnectionTerminationDone);
+ }
+
+ QVector<QBluetoothAddress> connectedAddresses;
+ for (const auto handle: activeHandles) {
+ const QBluetoothAddress addr = hciManager->addressForConnectionHandle(handle);
+ if (!addr.isNull())
+ connectedAddresses.push_back(addr);
+ }
+ device1Manager->scheduleJob(RemoteDeviceManager::JobType::JobDisconnectDevice, connectedAddresses);
+ } else {
+ establishL2cpClientSocket();
+ }
+}
+
+/*!
+ * Handles outcome of attempts to close external connections.
+ */
+void QLowEnergyControllerPrivate::activeConnectionTerminationDone()
+{
+ if (!device1Manager)
+ return;
+
+ qCDebug(QT_BT_BLUEZ) << "RemoteDeviceManager finished attempting"
+ << "to close external connections";
+
+ QVector<quint16> activeHandles = hciManager->activeLowEnergyConnections();
+ if (!activeHandles.isEmpty()) {
+ qCWarning(QT_BT_BLUEZ) << "Cannot close pending external BTLE connections. Aborting connect attempt";
setError(QLowEnergyController::ConnectionError);
setState(QLowEnergyController::UnconnectedState);
return;
+ } else {
+ establishL2cpClientSocket();
}
+}
+
+/*!
+ * Establishes the L2CP client socket.
+ */
+void QLowEnergyControllerPrivate::establishL2cpClientSocket()
+{
+ //we are already in Connecting state
l2cpSocket = new QBluetoothSocket(QBluetoothServiceInfo::L2capProtocol, this);
connect(l2cpSocket, SIGNAL(connected()), this, SLOT(l2cpConnected()));