Android counterpart: https://invent.kde.org/network/kdeconnect-android/-/merge_requests/399 Bluetooth support is now enabled by default.
This commit is contained in:
parent
eaf45d214b
commit
4dba3394a7
4 changed files with 69 additions and 25 deletions
|
@ -12,7 +12,7 @@ option(MDNS_ENABLED "Use MDNS for device discovery" ON)
|
||||||
add_subdirectory(backends/lan)
|
add_subdirectory(backends/lan)
|
||||||
add_subdirectory(backends/loopback)
|
add_subdirectory(backends/loopback)
|
||||||
|
|
||||||
option(BLUETOOTH_ENABLED "Bluetooth support for kdeconnect" OFF)
|
option(BLUETOOTH_ENABLED "Bluetooth support for kdeconnect" ON)
|
||||||
if(BLUETOOTH_ENABLED)
|
if(BLUETOOTH_ENABLED)
|
||||||
find_package(Qt${QT_MAJOR_VERSION} ${QT_MIN_VERSION} REQUIRED COMPONENTS Bluetooth)
|
find_package(Qt${QT_MAJOR_VERSION} ${QT_MIN_VERSION} REQUIRED COMPONENTS Bluetooth)
|
||||||
add_subdirectory(backends/bluetooth)
|
add_subdirectory(backends/bluetooth)
|
||||||
|
|
|
@ -37,18 +37,23 @@ void BluetoothLinkProvider::onStart()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::onStart executed";
|
||||||
|
|
||||||
mBluetoothServer = new QBluetoothServer(QBluetoothServiceInfo::RfcommProtocol, this);
|
mBluetoothServer = new QBluetoothServer(QBluetoothServiceInfo::RfcommProtocol, this);
|
||||||
mBluetoothServer->setSecurityFlags(QBluetooth::Security::Encryption | QBluetooth::Security::Secure);
|
mBluetoothServer->setSecurityFlags(QBluetooth::Security::Encryption | QBluetooth::Security::Secure);
|
||||||
connect(mBluetoothServer, &QBluetoothServer::newConnection, this, &BluetoothLinkProvider::serverNewConnection);
|
connect(mBluetoothServer, &QBluetoothServer::newConnection, this, &BluetoothLinkProvider::serverNewConnection);
|
||||||
|
|
||||||
mServiceDiscoveryAgent->start();
|
qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::About to start server listen";
|
||||||
|
|
||||||
connectTimer->start();
|
|
||||||
mKdeconnectService = mBluetoothServer->listen(mServiceUuid, QStringLiteral("KDE Connect"));
|
mKdeconnectService = mBluetoothServer->listen(mServiceUuid, QStringLiteral("KDE Connect"));
|
||||||
|
|
||||||
|
// Disabled for the moment as once the server is listening, the client will not be able to connect anyway
|
||||||
|
//mServiceDiscoveryAgent->start();
|
||||||
|
//connectTimer->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BluetoothLinkProvider::onStop()
|
void BluetoothLinkProvider::onStop()
|
||||||
{
|
{
|
||||||
|
qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::onStop executed";
|
||||||
if (!mBluetoothServer) {
|
if (!mBluetoothServer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -67,15 +72,21 @@ void BluetoothLinkProvider::onNetworkChange()
|
||||||
|
|
||||||
void BluetoothLinkProvider::connectError()
|
void BluetoothLinkProvider::connectError()
|
||||||
{
|
{
|
||||||
|
qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::connectError executed";
|
||||||
QBluetoothSocket *socket = qobject_cast<QBluetoothSocket *>(sender());
|
QBluetoothSocket *socket = qobject_cast<QBluetoothSocket *>(sender());
|
||||||
if (!socket)
|
if (!socket)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
qCWarning(KDECONNECT_CORE) << "Couldn't connect to socket:" << socket->errorString();
|
qCWarning(KDECONNECT_CORE) << "Couldn't connect to bluetooth socket:" << socket->errorString();
|
||||||
|
|
||||||
disconnect(socket, &QBluetoothSocket::connected, this, nullptr);
|
disconnect(socket, &QBluetoothSocket::connected, this, nullptr);
|
||||||
disconnect(socket, &QBluetoothSocket::readyRead, this, nullptr);
|
disconnect(socket, &QBluetoothSocket::readyRead, this, nullptr);
|
||||||
|
|
||||||
|
#if QT_VERSION_MAJOR == 5
|
||||||
disconnect(socket, QOverload<QBluetoothSocket::SocketError>::of(&QBluetoothSocket::error), this, nullptr);
|
disconnect(socket, QOverload<QBluetoothSocket::SocketError>::of(&QBluetoothSocket::error), this, nullptr);
|
||||||
|
#else
|
||||||
|
disconnect(socket, QOverload<QBluetoothSocket::SocketError>::of(&QBluetoothSocket::errorOccurred), this, nullptr);
|
||||||
|
#endif
|
||||||
|
|
||||||
mSockets.remove(socket->peerAddress());
|
mSockets.remove(socket->peerAddress());
|
||||||
socket->deleteLater();
|
socket->deleteLater();
|
||||||
|
@ -83,42 +94,60 @@ void BluetoothLinkProvider::connectError()
|
||||||
|
|
||||||
void BluetoothLinkProvider::addLink(BluetoothDeviceLink *deviceLink, const QString &deviceId)
|
void BluetoothLinkProvider::addLink(BluetoothDeviceLink *deviceLink, const QString &deviceId)
|
||||||
{
|
{
|
||||||
QMap<QString, DeviceLink *>::iterator oldLinkIterator = mLinks.find(deviceId);
|
qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::addLink executed";
|
||||||
delete oldLinkIterator.value(); // not calling deleteLater because this triggers onLinkDestroyed
|
if (mLinks.contains(deviceId)) {
|
||||||
|
delete mLinks.take(deviceId); // not calling deleteLater because this triggers onLinkDestroyed
|
||||||
|
}
|
||||||
mLinks[deviceId] = deviceLink;
|
mLinks[deviceId] = deviceLink;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BluetoothLinkProvider::serviceDiscovered(const QBluetoothServiceInfo &old_info)
|
void BluetoothLinkProvider::serviceDiscovered(const QBluetoothServiceInfo &old_info)
|
||||||
{
|
{
|
||||||
auto info = old_info;
|
qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::serviceDiscovered executed ";
|
||||||
|
|
||||||
|
qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::serviceDiscovered info: " << old_info.device().address() << old_info.serviceName() << old_info.serviceDescription() << old_info.socketProtocol() << old_info.isValid() << old_info.isComplete() << old_info.isRegistered() << old_info.serviceClassUuids();
|
||||||
|
|
||||||
|
auto info = *(new QBluetoothServiceInfo(old_info));
|
||||||
info.setServiceUuid(mServiceUuid);
|
info.setServiceUuid(mServiceUuid);
|
||||||
if (mSockets.contains(info.device().address())) {
|
if (mSockets.contains(info.device().address())) {
|
||||||
|
qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::serviceDiscovered sockets contains address, returning";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::serviceDiscovered before creating socket";
|
||||||
QBluetoothSocket *socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol);
|
QBluetoothSocket *socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol);
|
||||||
|
|
||||||
// Delay before sending data
|
// Delay before sending data
|
||||||
QPointer<QBluetoothSocket> deleteableSocket = socket;
|
QPointer<QBluetoothSocket> deleteableSocket = socket;
|
||||||
connect(socket, &QBluetoothSocket::connected, this, [this, deleteableSocket]() {
|
connect(socket, &QBluetoothSocket::connected, this, [this, deleteableSocket]() {
|
||||||
QTimer::singleShot(500, this, [this, deleteableSocket]() {
|
QTimer::singleShot(500, this, [this, deleteableSocket]() {
|
||||||
|
qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::serviceDiscovered after delay, executing clientConnected";
|
||||||
clientConnected(deleteableSocket);
|
clientConnected(deleteableSocket);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
connect(socket, QOverload<QBluetoothSocket::SocketError>::of(&QBluetoothSocket::error), this, &BluetoothLinkProvider::connectError);
|
|
||||||
|
|
||||||
|
qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::serviceDiscovered about to call connect";
|
||||||
|
#if QT_VERSION_MAJOR == 5
|
||||||
|
connect(socket, QOverload<QBluetoothSocket::SocketError>::of(&QBluetoothSocket::error), this, &BluetoothLinkProvider::connectError);
|
||||||
|
#else
|
||||||
|
connect(socket, QOverload<QBluetoothSocket::SocketError>::of(&QBluetoothSocket::errorOccurred), this, &BluetoothLinkProvider::connectError);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::serviceDiscovered about to call connectToService";
|
||||||
|
|
||||||
socket->connectToService(info);
|
socket->connectToService(info);
|
||||||
|
|
||||||
qCDebug(KDECONNECT_CORE) << "Connecting to" << info.device().address();
|
qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider Connecting to" << info.device().address();
|
||||||
|
|
||||||
if (socket->error() != QBluetoothSocket::SocketError::NoSocketError) {
|
if (socket->error() != QBluetoothSocket::SocketError::NoSocketError) {
|
||||||
qCWarning(KDECONNECT_CORE) << "Socket connection error:" << socket->errorString();
|
qCWarning(KDECONNECT_CORE) << "BluetoothLinkProvider Socket connection error:" << socket->errorString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// I'm the new device and I'm connected to the existing device. Time to get data.
|
// I'm the new device and I'm connected to the existing device. Time to get data.
|
||||||
void BluetoothLinkProvider::clientConnected(QPointer<QBluetoothSocket> socket)
|
void BluetoothLinkProvider::clientConnected(QPointer<QBluetoothSocket> socket)
|
||||||
{
|
{
|
||||||
|
qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::clientConnected executed";
|
||||||
if (!socket)
|
if (!socket)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -155,6 +184,7 @@ void BluetoothLinkProvider::clientConnected(QPointer<QBluetoothSocket> socket)
|
||||||
// I'm the new device and the existing device sent me data.
|
// I'm the new device and the existing device sent me data.
|
||||||
void BluetoothLinkProvider::clientIdentityReceived(const QBluetoothAddress &peer, QSharedPointer<MultiplexChannel> socket)
|
void BluetoothLinkProvider::clientIdentityReceived(const QBluetoothAddress &peer, QSharedPointer<MultiplexChannel> socket)
|
||||||
{
|
{
|
||||||
|
qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::clientIdentityReceived executed";
|
||||||
socket->startTransaction();
|
socket->startTransaction();
|
||||||
|
|
||||||
QByteArray identityArray = socket->readLine();
|
QByteArray identityArray = socket->readLine();
|
||||||
|
@ -170,14 +200,14 @@ void BluetoothLinkProvider::clientIdentityReceived(const QBluetoothAddress &peer
|
||||||
bool success = NetworkPacket::unserialize(identityArray, &receivedPacket);
|
bool success = NetworkPacket::unserialize(identityArray, &receivedPacket);
|
||||||
|
|
||||||
if (!success || receivedPacket.type() != PACKET_TYPE_IDENTITY) {
|
if (!success || receivedPacket.type() != PACKET_TYPE_IDENTITY) {
|
||||||
qCWarning(KDECONNECT_CORE) << "Not an identity packet";
|
qCWarning(KDECONNECT_CORE) << "BluetoothLinkProvider Received not an identity packet";
|
||||||
mSockets.remove(peer);
|
mSockets.remove(peer);
|
||||||
socket->close();
|
socket->close();
|
||||||
socket->deleteLater();
|
socket->deleteLater();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qCDebug(KDECONNECT_CORE) << "Received identity packet from" << peer;
|
qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider Received identity packet from" << peer;
|
||||||
|
|
||||||
// TODO?
|
// TODO?
|
||||||
// disconnect(socket, &QAbstractSocket::error, this, &BluetoothLinkProvider::connectError);
|
// disconnect(socket, &QAbstractSocket::error, this, &BluetoothLinkProvider::connectError);
|
||||||
|
@ -192,7 +222,7 @@ void BluetoothLinkProvider::clientIdentityReceived(const QBluetoothAddress &peer
|
||||||
success = deviceLink->sendPacket(myIdentity);
|
success = deviceLink->sendPacket(myIdentity);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
qCDebug(KDECONNECT_CORE) << "Handshaking done (I'm the new device)";
|
qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider Handshaking done (I'm the new device)";
|
||||||
|
|
||||||
Q_EMIT onConnectionReceived(deviceLink);
|
Q_EMIT onConnectionReceived(deviceLink);
|
||||||
|
|
||||||
|
@ -210,9 +240,10 @@ void BluetoothLinkProvider::clientIdentityReceived(const QBluetoothAddress &peer
|
||||||
// I'm the existing device, a new device is kindly introducing itself.
|
// I'm the existing device, a new device is kindly introducing itself.
|
||||||
void BluetoothLinkProvider::serverNewConnection()
|
void BluetoothLinkProvider::serverNewConnection()
|
||||||
{
|
{
|
||||||
|
qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::serverNewConnection executed";
|
||||||
QBluetoothSocket *socket = mBluetoothServer->nextPendingConnection();
|
QBluetoothSocket *socket = mBluetoothServer->nextPendingConnection();
|
||||||
|
|
||||||
qCDebug(KDECONNECT_CORE) << "Received connection from" << socket->peerAddress();
|
qCDebug(KDECONNECT_CORE) << socket->peerAddress() << "Received connection";
|
||||||
|
|
||||||
QBluetoothAddress peer = socket->peerAddress();
|
QBluetoothAddress peer = socket->peerAddress();
|
||||||
|
|
||||||
|
@ -225,6 +256,8 @@ void BluetoothLinkProvider::serverNewConnection()
|
||||||
|
|
||||||
ConnectionMultiplexer *multiplexer = new ConnectionMultiplexer(socket, this);
|
ConnectionMultiplexer *multiplexer = new ConnectionMultiplexer(socket, this);
|
||||||
|
|
||||||
|
qCDebug(KDECONNECT_CORE) << socket->peerAddress() << "Multiplexer Instantiated";
|
||||||
|
|
||||||
mSockets.insert(peer, multiplexer);
|
mSockets.insert(peer, multiplexer);
|
||||||
disconnect(socket, nullptr, this, nullptr);
|
disconnect(socket, nullptr, this, nullptr);
|
||||||
|
|
||||||
|
@ -241,17 +274,22 @@ void BluetoothLinkProvider::serverNewConnection()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qCDebug(KDECONNECT_CORE) << socket->peerAddress() << "Building and sending identity Packet ";
|
||||||
|
|
||||||
DeviceInfo myDeviceInfo = KdeConnectConfig::instance().deviceInfo();
|
DeviceInfo myDeviceInfo = KdeConnectConfig::instance().deviceInfo();
|
||||||
NetworkPacket myIdentity = myDeviceInfo.toIdentityPacket();
|
NetworkPacket myIdentity = myDeviceInfo.toIdentityPacket();
|
||||||
myIdentity.set(QStringLiteral("certificate"), QString::fromLatin1(myDeviceInfo.certificate.toPem()));
|
myIdentity.set(QStringLiteral("certificate"), QString::fromLatin1(myDeviceInfo.certificate.toPem()));
|
||||||
socket->write(myIdentity.serialize());
|
auto identityPacket = myIdentity.serialize();
|
||||||
|
|
||||||
qCDebug(KDECONNECT_CORE) << "Sent identity packet to" << socket->peerAddress();
|
channel->write(identityPacket);
|
||||||
|
|
||||||
|
qCDebug(KDECONNECT_CORE) << "Sent identity packet on default channel to" << socket->peerAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
// I'm the existing device and this is the answer to my identity packet (data received)
|
// I'm the existing device and this is the answer to my identity packet (data received)
|
||||||
void BluetoothLinkProvider::serverDataReceived(const QBluetoothAddress &peer, QSharedPointer<MultiplexChannel> socket)
|
void BluetoothLinkProvider::serverDataReceived(const QBluetoothAddress &peer, QSharedPointer<MultiplexChannel> socket)
|
||||||
{
|
{
|
||||||
|
qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::serverDataReceived executed";
|
||||||
QByteArray identityArray;
|
QByteArray identityArray;
|
||||||
socket->startTransaction();
|
socket->startTransaction();
|
||||||
identityArray = socket->readLine();
|
identityArray = socket->readLine();
|
||||||
|
@ -295,10 +333,12 @@ void BluetoothLinkProvider::onLinkDestroyed(const QString &deviceId, DeviceLink
|
||||||
|
|
||||||
void BluetoothLinkProvider::socketDisconnected(const QBluetoothAddress &peer, MultiplexChannel *socket)
|
void BluetoothLinkProvider::socketDisconnected(const QBluetoothAddress &peer, MultiplexChannel *socket)
|
||||||
{
|
{
|
||||||
qCDebug(KDECONNECT_CORE) << "Disconnected";
|
qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider socketDisconnected";
|
||||||
disconnect(socket, nullptr, this, nullptr);
|
disconnect(socket, nullptr, this, nullptr);
|
||||||
|
qCDebug(KDECONNECT_CORE) << "socketDisconnected :: After calling disconnect";
|
||||||
|
|
||||||
mSockets.remove(peer);
|
mSockets.remove(peer);
|
||||||
|
qCDebug(KDECONNECT_CORE) << "socketDisconnected :: After calling remove";
|
||||||
}
|
}
|
||||||
|
|
||||||
BluetoothLinkProvider::~BluetoothLinkProvider()
|
BluetoothLinkProvider::~BluetoothLinkProvider()
|
||||||
|
|
|
@ -44,7 +44,8 @@ ConnectionMultiplexer::ConnectionMultiplexer(QBluetoothSocket *socket, QObject *
|
||||||
// Only support version 1 (lowest supported = highest supported = 1)
|
// Only support version 1 (lowest supported = highest supported = 1)
|
||||||
qToBigEndian<uint16_t>(1, &message.data()[19]);
|
qToBigEndian<uint16_t>(1, &message.data()[19]);
|
||||||
qToBigEndian<uint16_t>(1, &message.data()[21]);
|
qToBigEndian<uint16_t>(1, &message.data()[21]);
|
||||||
to_write_bytes.append(message);
|
|
||||||
|
socket->write(message);
|
||||||
|
|
||||||
// Send the protocol version message (queued)
|
// Send the protocol version message (queued)
|
||||||
QMetaObject::invokeMethod(this, &ConnectionMultiplexer::bytesWritten, Qt::QueuedConnection);
|
QMetaObject::invokeMethod(this, &ConnectionMultiplexer::bytesWritten, Qt::QueuedConnection);
|
||||||
|
@ -125,16 +126,16 @@ bool ConnectionMultiplexer::tryParseMessage()
|
||||||
*/
|
*/
|
||||||
char message_type = header[0];
|
char message_type = header[0];
|
||||||
uint16_t message_length = qFromBigEndian<uint16_t>(&header.data()[1]);
|
uint16_t message_length = qFromBigEndian<uint16_t>(&header.data()[1]);
|
||||||
#if QT_VERSION_MAJOR == 5
|
|
||||||
quint128 message_uuid_raw;
|
quint128 message_uuid_raw;
|
||||||
|
#ifndef QT_SUPPORTS_INT128
|
||||||
for (int i = 0; i < 16; ++i) {
|
for (int i = 0; i < 16; ++i) {
|
||||||
message_uuid_raw.data[i] = header[3 + i];
|
message_uuid_raw.data[i] = header[3 + i];
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
message_uuid_raw = qFromBigEndian<quint128>(&header.data()[3]);
|
||||||
|
#endif
|
||||||
QBluetoothUuid message_uuid = QBluetoothUuid(message_uuid_raw);
|
QBluetoothUuid message_uuid = QBluetoothUuid(message_uuid_raw);
|
||||||
#else
|
|
||||||
const QByteArray uuisByteArray = header.sliced(3, 16); // Faster than mid, see https://doc.qt.io/qt-6/qbytearray.html#mid
|
|
||||||
QBluetoothUuid message_uuid = QBluetoothUuid::fromBytes(uuisByteArray.constData());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Check if we have the full message including its data
|
// Check if we have the full message including its data
|
||||||
QByteArray data = mSocket->read(message_length);
|
QByteArray data = mSocket->read(message_length);
|
||||||
|
@ -283,6 +284,7 @@ void ConnectionMultiplexer::addChannel(QBluetoothUuid new_id)
|
||||||
closeChannel(new_id);
|
closeChannel(new_id);
|
||||||
},
|
},
|
||||||
Qt::QueuedConnection);
|
Qt::QueuedConnection);
|
||||||
|
|
||||||
auto channelStatePtr = QSharedPointer<MultiplexChannelState>{channelState};
|
auto channelStatePtr = QSharedPointer<MultiplexChannelState>{channelState};
|
||||||
channels[new_id] = channelStatePtr;
|
channels[new_id] = channelStatePtr;
|
||||||
unrequested_channels[new_id] = new MultiplexChannel{channelStatePtr};
|
unrequested_channels[new_id] = new MultiplexChannel{channelStatePtr};
|
||||||
|
|
|
@ -202,6 +202,8 @@ int main(int argc, char *argv[])
|
||||||
QObject::connect(&app, &QGuiApplication::commitDataRequest, disableSessionManagement);
|
QObject::connect(&app, &QGuiApplication::commitDataRequest, disableSessionManagement);
|
||||||
QObject::connect(&app, &QGuiApplication::saveStateRequest, disableSessionManagement);
|
QObject::connect(&app, &QGuiApplication::saveStateRequest, disableSessionManagement);
|
||||||
|
|
||||||
|
qSetMessagePattern(QStringLiteral("%{time} %{category}: %{message}"));
|
||||||
|
|
||||||
return app.exec();
|
return app.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue