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"