File indexing completed on 2024-05-12 04:58:50

0001 /**
0002  * SPDX-FileCopyrightText: 2016 Saikrishna Arcot <saiarcot895@gmail.com>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005  */
0006 
0007 #include "bluetoothlinkprovider.h"
0008 #include "bluetoothdevicelink.h"
0009 #include "connectionmultiplexer.h"
0010 #include "core_debug.h"
0011 #include "kdeconnectconfig.h"
0012 #include "multiplexchannel.h"
0013 
0014 #include <QBluetoothServiceInfo>
0015 
0016 BluetoothLinkProvider::BluetoothLinkProvider()
0017     : mServiceUuid(QBluetoothUuid(QStringLiteral("185f3df4-3268-4e3f-9fca-d4d5059915bd")))
0018     , mServiceDiscoveryAgent(new QBluetoothServiceDiscoveryAgent(this))
0019     , connectTimer(new QTimer(this))
0020 {
0021     connectTimer->setInterval(30000);
0022     connectTimer->setSingleShot(false);
0023 
0024     mServiceDiscoveryAgent->setUuidFilter(mServiceUuid);
0025     connect(connectTimer, &QTimer::timeout, this, [this]() {
0026         mServiceDiscoveryAgent->start();
0027     });
0028 
0029     connect(mServiceDiscoveryAgent, &QBluetoothServiceDiscoveryAgent::serviceDiscovered, this, &BluetoothLinkProvider::serviceDiscovered);
0030 }
0031 
0032 void BluetoothLinkProvider::onStart()
0033 {
0034     QBluetoothLocalDevice localDevice;
0035     if (!localDevice.isValid()) {
0036         qCWarning(KDECONNECT_CORE) << "No local bluetooth adapter found";
0037         return;
0038     }
0039 
0040     qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::onStart executed";
0041 
0042     mBluetoothServer = new QBluetoothServer(QBluetoothServiceInfo::RfcommProtocol, this);
0043     mBluetoothServer->setSecurityFlags(QBluetooth::Security::Encryption | QBluetooth::Security::Secure);
0044     connect(mBluetoothServer, &QBluetoothServer::newConnection, this, &BluetoothLinkProvider::serverNewConnection);
0045 
0046     qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::About to start server listen";
0047     mKdeconnectService = mBluetoothServer->listen(mServiceUuid, QStringLiteral("KDE Connect"));
0048 
0049     // Disabled for the moment as once the server is listening, the client will not be able to connect anyway
0050     // mServiceDiscoveryAgent->start();
0051     // connectTimer->start();
0052 }
0053 
0054 void BluetoothLinkProvider::onStop()
0055 {
0056     qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::onStop executed";
0057     if (!mBluetoothServer) {
0058         return;
0059     }
0060 
0061     connectTimer->stop();
0062 
0063     mKdeconnectService.unregisterService();
0064     mBluetoothServer->close();
0065     mBluetoothServer->deleteLater();
0066 }
0067 
0068 // I'm in a new network, let's be polite and introduce myself
0069 void BluetoothLinkProvider::onNetworkChange()
0070 {
0071 }
0072 
0073 void BluetoothLinkProvider::connectError()
0074 {
0075     qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::connectError executed";
0076     QBluetoothSocket *socket = qobject_cast<QBluetoothSocket *>(sender());
0077     if (!socket)
0078         return;
0079 
0080     qCWarning(KDECONNECT_CORE) << "Couldn't connect to bluetooth socket:" << socket->errorString();
0081 
0082     disconnect(socket, &QBluetoothSocket::connected, this, nullptr);
0083     disconnect(socket, &QBluetoothSocket::readyRead, this, nullptr);
0084 
0085 #if QT_VERSION_MAJOR == 5
0086     disconnect(socket, QOverload<QBluetoothSocket::SocketError>::of(&QBluetoothSocket::error), this, nullptr);
0087 #else
0088     disconnect(socket, QOverload<QBluetoothSocket::SocketError>::of(&QBluetoothSocket::errorOccurred), this, nullptr);
0089 #endif
0090 
0091     mSockets.remove(socket->peerAddress());
0092     socket->deleteLater();
0093 }
0094 
0095 void BluetoothLinkProvider::addLink(BluetoothDeviceLink *deviceLink, const QString &deviceId)
0096 {
0097     qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::addLink executed";
0098     if (mLinks.contains(deviceId)) {
0099         delete mLinks.take(deviceId); // not calling deleteLater because this triggers onLinkDestroyed
0100     }
0101     mLinks[deviceId] = deviceLink;
0102 }
0103 
0104 void BluetoothLinkProvider::serviceDiscovered(const QBluetoothServiceInfo &old_info)
0105 {
0106     qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::serviceDiscovered executed ";
0107 
0108     qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::serviceDiscovered info: " << old_info.device().address() << old_info.serviceName()
0109                              << old_info.serviceDescription() << old_info.socketProtocol() << old_info.isValid() << old_info.isComplete()
0110                              << old_info.isRegistered() << old_info.serviceClassUuids();
0111 
0112     auto info = *(new QBluetoothServiceInfo(old_info));
0113     info.setServiceUuid(mServiceUuid);
0114     if (mSockets.contains(info.device().address())) {
0115         qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::serviceDiscovered sockets contains address, returning";
0116         return;
0117     }
0118 
0119     qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::serviceDiscovered before creating socket";
0120     QBluetoothSocket *socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol);
0121 
0122     // Delay before sending data
0123     QPointer<QBluetoothSocket> deleteableSocket = socket;
0124     connect(socket, &QBluetoothSocket::connected, this, [this, deleteableSocket]() {
0125         QTimer::singleShot(500, this, [this, deleteableSocket]() {
0126             qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::serviceDiscovered after delay, executing clientConnected";
0127             clientConnected(deleteableSocket);
0128         });
0129     });
0130 
0131     qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::serviceDiscovered about to call connect";
0132 #if QT_VERSION_MAJOR == 5
0133     connect(socket, QOverload<QBluetoothSocket::SocketError>::of(&QBluetoothSocket::error), this, &BluetoothLinkProvider::connectError);
0134 #else
0135     connect(socket, QOverload<QBluetoothSocket::SocketError>::of(&QBluetoothSocket::errorOccurred), this, &BluetoothLinkProvider::connectError);
0136 #endif
0137 
0138     qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::serviceDiscovered about to call connectToService";
0139 
0140     socket->connectToService(info);
0141 
0142     qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider Connecting to" << info.device().address();
0143 
0144     if (socket->error() != QBluetoothSocket::SocketError::NoSocketError) {
0145         qCWarning(KDECONNECT_CORE) << "BluetoothLinkProvider Socket connection error:" << socket->errorString();
0146     }
0147 }
0148 
0149 // I'm the new device and I'm connected to the existing device. Time to get data.
0150 void BluetoothLinkProvider::clientConnected(QPointer<QBluetoothSocket> socket)
0151 {
0152     qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::clientConnected executed";
0153     if (!socket)
0154         return;
0155 
0156     auto peer = socket->peerAddress();
0157 
0158     qCDebug(KDECONNECT_CORE) << "Connected to" << peer;
0159 
0160     if (mSockets.contains(socket->peerAddress())) {
0161         qCWarning(KDECONNECT_CORE) << "Duplicate connection to" << peer;
0162         socket->close();
0163         socket->deleteLater();
0164         return;
0165     }
0166 
0167     ConnectionMultiplexer *multiplexer = new ConnectionMultiplexer(socket, this);
0168 
0169     mSockets.insert(peer, multiplexer);
0170     disconnect(socket, nullptr, this, nullptr);
0171 
0172     auto channel = QSharedPointer<MultiplexChannel>{multiplexer->getDefaultChannel().release()};
0173     connect(channel.data(), &MultiplexChannel::readyRead, this, [this, peer, channel]() {
0174         clientIdentityReceived(peer, channel);
0175     });
0176     connect(channel.data(), &MultiplexChannel::aboutToClose, this, [this, peer, channel]() {
0177         socketDisconnected(peer, channel.data());
0178     });
0179 
0180     if (channel->bytesAvailable())
0181         clientIdentityReceived(peer, channel);
0182     if (!channel->isOpen())
0183         socketDisconnected(peer, channel.data());
0184 }
0185 
0186 // I'm the new device and the existing device sent me data.
0187 void BluetoothLinkProvider::clientIdentityReceived(const QBluetoothAddress &peer, QSharedPointer<MultiplexChannel> socket)
0188 {
0189     qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::clientIdentityReceived executed";
0190     socket->startTransaction();
0191 
0192     QByteArray identityArray = socket->readLine();
0193     if (identityArray.isEmpty()) {
0194         socket->rollbackTransaction();
0195         return;
0196     }
0197     socket->commitTransaction();
0198 
0199     disconnect(socket.data(), &MultiplexChannel::readyRead, this, nullptr);
0200 
0201     NetworkPacket receivedPacket;
0202     bool success = NetworkPacket::unserialize(identityArray, &receivedPacket);
0203 
0204     if (!success || receivedPacket.type() != PACKET_TYPE_IDENTITY) {
0205         qCWarning(KDECONNECT_CORE) << "BluetoothLinkProvider Received not an identity packet";
0206         mSockets.remove(peer);
0207         socket->close();
0208         socket->deleteLater();
0209         return;
0210     }
0211 
0212     qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider Received identity packet from" << peer;
0213 
0214     // TODO?
0215     // disconnect(socket, &QAbstractSocket::error, this, &BluetoothLinkProvider::connectError);
0216 
0217     QSslCertificate receivedCertificate(receivedPacket.get<QString>(QStringLiteral("certificate")).toLatin1());
0218     DeviceInfo deviceInfo = deviceInfo.FromIdentityPacketAndCert(receivedPacket, receivedCertificate);
0219     BluetoothDeviceLink *deviceLink = new BluetoothDeviceLink(deviceInfo, this, mSockets[peer], socket);
0220 
0221     DeviceInfo myDeviceInfo = KdeConnectConfig::instance().deviceInfo();
0222     NetworkPacket myIdentity = myDeviceInfo.toIdentityPacket();
0223     myIdentity.set(QStringLiteral("certificate"), QString::fromLatin1(myDeviceInfo.certificate.toPem()));
0224     success = deviceLink->sendPacket(myIdentity);
0225 
0226     if (success) {
0227         qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider Handshaking done (I'm the new device)";
0228 
0229         Q_EMIT onConnectionReceived(deviceLink);
0230 
0231         // We kill any possible link from this same device
0232         addLink(deviceLink, deviceInfo.id);
0233 
0234     } else {
0235         // Connection might be lost. Delete it.
0236         delete deviceLink;
0237     }
0238 
0239     // We don't delete the socket because now it's owned by the BluetoothDeviceLink
0240 }
0241 
0242 // I'm the existing device, a new device is kindly introducing itself.
0243 void BluetoothLinkProvider::serverNewConnection()
0244 {
0245     qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::serverNewConnection executed";
0246     QBluetoothSocket *socket = mBluetoothServer->nextPendingConnection();
0247 
0248     qCDebug(KDECONNECT_CORE) << socket->peerAddress() << "Received connection";
0249 
0250     QBluetoothAddress peer = socket->peerAddress();
0251 
0252     if (mSockets.contains(peer)) {
0253         qCDebug(KDECONNECT_CORE) << "Duplicate connection from" << peer;
0254         socket->close();
0255         socket->deleteLater();
0256         return;
0257     }
0258 
0259     ConnectionMultiplexer *multiplexer = new ConnectionMultiplexer(socket, this);
0260 
0261     qCDebug(KDECONNECT_CORE) << socket->peerAddress() << "Multiplexer Instantiated";
0262 
0263     mSockets.insert(peer, multiplexer);
0264     disconnect(socket, nullptr, this, nullptr);
0265 
0266     auto channel = QSharedPointer<MultiplexChannel>{multiplexer->getDefaultChannel().release()};
0267     connect(channel.data(), &MultiplexChannel::readyRead, this, [this, peer, channel]() {
0268         serverDataReceived(peer, channel);
0269     });
0270     connect(channel.data(), &MultiplexChannel::aboutToClose, this, [this, peer, channel]() {
0271         socketDisconnected(peer, channel.data());
0272     });
0273 
0274     if (!channel->isOpen()) {
0275         socketDisconnected(peer, channel.data());
0276         return;
0277     }
0278 
0279     qCDebug(KDECONNECT_CORE) << socket->peerAddress() << "Building and sending identity Packet ";
0280 
0281     DeviceInfo myDeviceInfo = KdeConnectConfig::instance().deviceInfo();
0282     NetworkPacket myIdentity = myDeviceInfo.toIdentityPacket();
0283     myIdentity.set(QStringLiteral("certificate"), QString::fromLatin1(myDeviceInfo.certificate.toPem()));
0284     auto identityPacket = myIdentity.serialize();
0285 
0286     channel->write(identityPacket);
0287 
0288     qCDebug(KDECONNECT_CORE) << "Sent identity packet on default channel to" << socket->peerAddress();
0289 }
0290 
0291 // I'm the existing device and this is the answer to my identity packet (data received)
0292 void BluetoothLinkProvider::serverDataReceived(const QBluetoothAddress &peer, QSharedPointer<MultiplexChannel> socket)
0293 {
0294     qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::serverDataReceived executed";
0295     QByteArray identityArray;
0296     socket->startTransaction();
0297     identityArray = socket->readLine();
0298 
0299     if (identityArray.isEmpty()) {
0300         socket->rollbackTransaction();
0301         return;
0302     }
0303     socket->commitTransaction();
0304 
0305     disconnect(socket.data(), &MultiplexChannel::readyRead, this, nullptr);
0306 
0307     NetworkPacket receivedPacket;
0308     bool success = NetworkPacket::unserialize(identityArray, &receivedPacket);
0309 
0310     if (!success || receivedPacket.type() != PACKET_TYPE_IDENTITY) {
0311         qCWarning(KDECONNECT_CORE) << "Not an identity packet.";
0312         mSockets.remove(peer);
0313         socket->close();
0314         socket->deleteLater();
0315         return;
0316     }
0317 
0318     qCDebug(KDECONNECT_CORE) << "Received identity packet from" << peer;
0319 
0320     QSslCertificate receivedCertificate(receivedPacket.get<QString>(QStringLiteral("certificate")).toLatin1());
0321     DeviceInfo deviceInfo = deviceInfo.FromIdentityPacketAndCert(receivedPacket, receivedCertificate);
0322     BluetoothDeviceLink *deviceLink = new BluetoothDeviceLink(deviceInfo, this, mSockets[peer], socket);
0323 
0324     Q_EMIT onConnectionReceived(deviceLink);
0325 
0326     addLink(deviceLink, deviceInfo.id);
0327 }
0328 
0329 void BluetoothLinkProvider::onLinkDestroyed(const QString &deviceId, DeviceLink *oldPtr)
0330 {
0331     qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider deviceLinkDestroyed" << deviceId;
0332     DeviceLink *link = mLinks.take(deviceId);
0333     Q_ASSERT(link == oldPtr);
0334 }
0335 
0336 void BluetoothLinkProvider::socketDisconnected(const QBluetoothAddress &peer, MultiplexChannel *socket)
0337 {
0338     qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider socketDisconnected";
0339     disconnect(socket, nullptr, this, nullptr);
0340     qCDebug(KDECONNECT_CORE) << "socketDisconnected :: After calling disconnect";
0341 
0342     mSockets.remove(peer);
0343     qCDebug(KDECONNECT_CORE) << "socketDisconnected :: After calling remove";
0344 }
0345 
0346 BluetoothLinkProvider::~BluetoothLinkProvider()
0347 {
0348 }
0349 
0350 #include "moc_bluetoothlinkprovider.cpp"