Bluetooth multiplexer integration and assorted fixes
This commit is contained in:
parent
cda1280456
commit
0b6224fc0e
10 changed files with 145 additions and 173 deletions
|
@ -25,22 +25,24 @@
|
||||||
#include "bluetoothuploadjob.h"
|
#include "bluetoothuploadjob.h"
|
||||||
#include "bluetoothdownloadjob.h"
|
#include "bluetoothdownloadjob.h"
|
||||||
#include "core_debug.h"
|
#include "core_debug.h"
|
||||||
|
#include "connectionmultiplexer.h"
|
||||||
|
#include "multiplexchannel.h"
|
||||||
|
|
||||||
BluetoothDeviceLink::BluetoothDeviceLink(const QString& deviceId, LinkProvider* parent, QBluetoothSocket* socket)
|
BluetoothDeviceLink::BluetoothDeviceLink(const QString& deviceId, LinkProvider* parent, ConnectionMultiplexer* connection, QSharedPointer<MultiplexChannel> socket)
|
||||||
: DeviceLink(deviceId, parent)
|
: DeviceLink(deviceId, parent)
|
||||||
, mSocketReader(new DeviceLineReader(socket, this))
|
, mSocketReader(new DeviceLineReader(socket.data(), this))
|
||||||
, mBluetoothSocket(socket)
|
, mConnection(connection)
|
||||||
|
, mChannel(socket)
|
||||||
, mPairingHandler(new BluetoothPairingHandler(this))
|
, mPairingHandler(new BluetoothPairingHandler(this))
|
||||||
{
|
{
|
||||||
connect(mSocketReader, SIGNAL(readyRead()),
|
connect(mSocketReader, &DeviceLineReader::readyRead, this, &BluetoothDeviceLink::dataReceived);
|
||||||
this, SLOT(dataReceived()));
|
|
||||||
|
|
||||||
//We take ownership of the socket.
|
//We take ownership of the connection.
|
||||||
//When the link provider destroys us,
|
//When the link provider destroys us,
|
||||||
//the socket (and the reader) will be
|
//the socket (and the reader) will be
|
||||||
//destroyed as well
|
//destroyed as well
|
||||||
mBluetoothSocket->setParent(this);
|
mConnection->setParent(this);
|
||||||
connect(mBluetoothSocket, SIGNAL(disconnected()), this, SLOT(deleteLater()));
|
connect(socket.data(), &MultiplexChannel::aboutToClose, this, &QObject::deleteLater);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString BluetoothDeviceLink::name()
|
QString BluetoothDeviceLink::name()
|
||||||
|
@ -51,10 +53,11 @@ QString BluetoothDeviceLink::name()
|
||||||
bool BluetoothDeviceLink::sendPacket(NetworkPacket& np)
|
bool BluetoothDeviceLink::sendPacket(NetworkPacket& np)
|
||||||
{
|
{
|
||||||
if (np.hasPayload()) {
|
if (np.hasPayload()) {
|
||||||
BluetoothUploadJob* uploadJob = new BluetoothUploadJob(np.payload(), mBluetoothSocket->peerAddress(), this);
|
BluetoothUploadJob* uploadJob = new BluetoothUploadJob(np.payload(), mConnection, this);
|
||||||
np.setPayloadTransferInfo(uploadJob->transferInfo());
|
np.setPayloadTransferInfo(uploadJob->transferInfo());
|
||||||
uploadJob->start();
|
uploadJob->start();
|
||||||
}
|
}
|
||||||
|
//TODO: handle too-big packets
|
||||||
int written = mSocketReader->write(np.serialize());
|
int written = mSocketReader->write(np.serialize());
|
||||||
return (written != -1);
|
return (written != -1);
|
||||||
}
|
}
|
||||||
|
@ -89,8 +92,7 @@ void BluetoothDeviceLink::dataReceived()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packet.hasPayloadTransferInfo()) {
|
if (packet.hasPayloadTransferInfo()) {
|
||||||
BluetoothDownloadJob* downloadJob = new BluetoothDownloadJob(mBluetoothSocket->peerAddress(),
|
BluetoothDownloadJob* downloadJob = new BluetoothDownloadJob(mConnection, packet.payloadTransferInfo(), this);
|
||||||
packet.payloadTransferInfo(), this);
|
|
||||||
downloadJob->start();
|
downloadJob->start();
|
||||||
packet.setPayload(downloadJob->payload(), packet.payloadSize());
|
packet.setPayload(downloadJob->payload(), packet.payloadSize());
|
||||||
}
|
}
|
||||||
|
@ -98,6 +100,6 @@ void BluetoothDeviceLink::dataReceived()
|
||||||
Q_EMIT receivedPacket(packet);
|
Q_EMIT receivedPacket(packet);
|
||||||
|
|
||||||
if (mSocketReader->bytesAvailable() > 0) {
|
if (mSocketReader->bytesAvailable() > 0) {
|
||||||
QMetaObject::invokeMethod(this, "dataReceived", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(this, &BluetoothDeviceLink::dataReceived, Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,13 +29,16 @@
|
||||||
#include "../devicelinereader.h"
|
#include "../devicelinereader.h"
|
||||||
#include "bluetoothpairinghandler.h"
|
#include "bluetoothpairinghandler.h"
|
||||||
|
|
||||||
|
class ConnectionMultiplexer;
|
||||||
|
class MultiplexChannel;
|
||||||
|
|
||||||
class KDECONNECTCORE_EXPORT BluetoothDeviceLink
|
class KDECONNECTCORE_EXPORT BluetoothDeviceLink
|
||||||
: public DeviceLink
|
: public DeviceLink
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BluetoothDeviceLink(const QString& deviceId, LinkProvider* parent, QBluetoothSocket* socket);
|
BluetoothDeviceLink(const QString& deviceId, LinkProvider* parent, ConnectionMultiplexer* connection, QSharedPointer<MultiplexChannel> socket);
|
||||||
|
|
||||||
virtual QString name() override;
|
virtual QString name() override;
|
||||||
bool sendPacket(NetworkPacket& np) override;
|
bool sendPacket(NetworkPacket& np) override;
|
||||||
|
@ -50,7 +53,8 @@ private Q_SLOTS:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DeviceLineReader* mSocketReader;
|
DeviceLineReader* mSocketReader;
|
||||||
QBluetoothSocket* mBluetoothSocket;
|
ConnectionMultiplexer* mConnection;
|
||||||
|
QSharedPointer<MultiplexChannel> mChannel;
|
||||||
BluetoothPairingHandler* mPairingHandler;
|
BluetoothPairingHandler* mPairingHandler;
|
||||||
|
|
||||||
void sendMessage(const QString mMessage);
|
void sendMessage(const QString mMessage);
|
||||||
|
|
|
@ -19,13 +19,14 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "bluetoothdownloadjob.h"
|
#include "bluetoothdownloadjob.h"
|
||||||
|
#include "connectionmultiplexer.h"
|
||||||
|
#include "multiplexchannel.h"
|
||||||
|
|
||||||
BluetoothDownloadJob::BluetoothDownloadJob(const QBluetoothAddress& remoteAddress, const QVariantMap& transferInfo, QObject* parent)
|
BluetoothDownloadJob::BluetoothDownloadJob(ConnectionMultiplexer *connection, const QVariantMap& transferInfo, QObject* parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, mRemoteAddress(remoteAddress)
|
|
||||||
, mTransferUuid(QBluetoothUuid(transferInfo.value(QStringLiteral("uuid")).toString()))
|
|
||||||
, mSocket(new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol))
|
|
||||||
{
|
{
|
||||||
|
QBluetoothUuid id{transferInfo.value(QStringLiteral("uuid")).toString()};
|
||||||
|
mSocket = QSharedPointer<MultiplexChannel>{connection->getChannel(id).release()};
|
||||||
}
|
}
|
||||||
|
|
||||||
QSharedPointer<QIODevice> BluetoothDownloadJob::payload() const
|
QSharedPointer<QIODevice> BluetoothDownloadJob::payload() const
|
||||||
|
@ -35,7 +36,4 @@ QSharedPointer<QIODevice> BluetoothDownloadJob::payload() const
|
||||||
|
|
||||||
void BluetoothDownloadJob::start()
|
void BluetoothDownloadJob::start()
|
||||||
{
|
{
|
||||||
connect(mSocket.data(), &QBluetoothSocket::disconnected, mSocket.data(), &QBluetoothSocket::readyRead);
|
|
||||||
connect(mSocket.data(), &QBluetoothSocket::disconnected, mSocket.data(), &QBluetoothSocket::readChannelFinished);
|
|
||||||
mSocket->connectToService(mRemoteAddress, mTransferUuid, QIODevice::ReadOnly);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,19 +29,20 @@
|
||||||
#include <QBluetoothUuid>
|
#include <QBluetoothUuid>
|
||||||
#include <QBluetoothSocket>
|
#include <QBluetoothSocket>
|
||||||
|
|
||||||
|
class ConnectionMultiplexer;
|
||||||
|
class MultiplexChannel;
|
||||||
|
|
||||||
class BluetoothDownloadJob
|
class BluetoothDownloadJob
|
||||||
: public QObject
|
: public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit BluetoothDownloadJob(const QBluetoothAddress& remoteAddress, const QVariantMap& transferInfo, QObject* parent = 0);
|
explicit BluetoothDownloadJob(ConnectionMultiplexer *connection, const QVariantMap& transferInfo, QObject* parent = 0);
|
||||||
|
|
||||||
QSharedPointer<QIODevice> payload() const;
|
QSharedPointer<QIODevice> payload() const;
|
||||||
void start();
|
void start();
|
||||||
private:
|
private:
|
||||||
QBluetoothAddress mRemoteAddress;
|
QSharedPointer<MultiplexChannel> mSocket;
|
||||||
QBluetoothUuid mTransferUuid;
|
|
||||||
QSharedPointer<QBluetoothSocket> mSocket;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BLUETOOTHDOWNLOADJOB_H
|
#endif // BLUETOOTHDOWNLOADJOB_H
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
|
|
||||||
#include "bluetoothlinkprovider.h"
|
#include "bluetoothlinkprovider.h"
|
||||||
#include "core_debug.h"
|
#include "core_debug.h"
|
||||||
|
#include "connectionmultiplexer.h"
|
||||||
|
#include "multiplexchannel.h"
|
||||||
|
|
||||||
#include <KSharedConfig>
|
#include <KSharedConfig>
|
||||||
#include <KConfigGroup>
|
#include <KConfigGroup>
|
||||||
|
@ -42,8 +44,11 @@ BluetoothLinkProvider::BluetoothLinkProvider()
|
||||||
|
|
||||||
mServiceDiscoveryAgent = new QBluetoothServiceDiscoveryAgent(this);
|
mServiceDiscoveryAgent = new QBluetoothServiceDiscoveryAgent(this);
|
||||||
mServiceDiscoveryAgent->setUuidFilter(mServiceUuid);
|
mServiceDiscoveryAgent->setUuidFilter(mServiceUuid);
|
||||||
connect(mServiceDiscoveryAgent, SIGNAL(finished()), this, SLOT(serviceDiscoveryFinished()));
|
connect(connectTimer, &QTimer::timeout, this, [this]() {
|
||||||
connect(connectTimer, SIGNAL(timeout()), mServiceDiscoveryAgent, SLOT(start()));
|
mServiceDiscoveryAgent->start();
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(mServiceDiscoveryAgent, &QBluetoothServiceDiscoveryAgent::serviceDiscovered, this, &BluetoothLinkProvider::serviceDiscovered);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BluetoothLinkProvider::onStart()
|
void BluetoothLinkProvider::onStart()
|
||||||
|
@ -111,95 +116,94 @@ void BluetoothLinkProvider::addLink(BluetoothDeviceLink* deviceLink, const QStri
|
||||||
mLinks[deviceId] = deviceLink;
|
mLinks[deviceId] = deviceLink;
|
||||||
}
|
}
|
||||||
|
|
||||||
//I'm the new device and I found an existing device
|
void BluetoothLinkProvider::serviceDiscovered(const QBluetoothServiceInfo& old_info) {
|
||||||
void BluetoothLinkProvider::serviceDiscoveryFinished()
|
auto info = old_info;
|
||||||
{
|
info.setServiceUuid(mServiceUuid);
|
||||||
const QList<QBluetoothServiceInfo> services = mServiceDiscoveryAgent->discoveredServices();
|
if (mSockets.contains(info.device().address())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (QBluetoothServiceInfo info : services) {
|
QBluetoothSocket* socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol);
|
||||||
if (mSockets.contains(info.device().address())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
QBluetoothSocket* socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol);
|
//Delay before sending data
|
||||||
|
QPointer<QBluetoothSocket> deleteableSocket = socket;
|
||||||
|
connect(socket, &QBluetoothSocket::connected, this, [this,deleteableSocket]() {
|
||||||
|
QTimer::singleShot(500, this, [this,deleteableSocket]() {
|
||||||
|
clientConnected(deleteableSocket);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
connect(socket, SIGNAL(error(QBluetoothSocket::SocketError)), this, SLOT(connectError()));
|
||||||
|
|
||||||
connect(socket, SIGNAL(connected()), this, SLOT(clientConnected()));
|
socket->connectToService(info);
|
||||||
connect(socket, SIGNAL(error(QBluetoothSocket::SocketError)), this, SLOT(connectError()));
|
|
||||||
|
|
||||||
socket->connectToService(info);
|
qCDebug(KDECONNECT_CORE()) << "Connecting to" << info.device().address();
|
||||||
|
|
||||||
qCDebug(KDECONNECT_CORE()) << "Connecting to" << info.device().address();
|
if (socket->error() != QBluetoothSocket::NoSocketError) {
|
||||||
|
qCWarning(KDECONNECT_CORE) << "Socket connection error:" << socket->errorString();
|
||||||
if (socket->error() != QBluetoothSocket::NoSocketError) {
|
|
||||||
qCWarning(KDECONNECT_CORE) << "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()
|
void BluetoothLinkProvider::clientConnected(QPointer<QBluetoothSocket> socket)
|
||||||
{
|
{
|
||||||
QBluetoothSocket* socket = qobject_cast<QBluetoothSocket*>(sender());
|
|
||||||
if (!socket) return;
|
if (!socket) return;
|
||||||
|
|
||||||
qCDebug(KDECONNECT_CORE()) << "Connected to" << socket->peerAddress();
|
auto peer = socket->peerAddress();
|
||||||
|
|
||||||
|
qCDebug(KDECONNECT_CORE()) << "Connected to" << peer;
|
||||||
|
|
||||||
if (mSockets.contains(socket->peerAddress())) {
|
if (mSockets.contains(socket->peerAddress())) {
|
||||||
qCWarning(KDECONNECT_CORE()) << "Duplicate connection to" << socket->peerAddress();
|
qCWarning(KDECONNECT_CORE()) << "Duplicate connection to" << peer;
|
||||||
socket->close();
|
socket->close();
|
||||||
socket->deleteLater();
|
socket->deleteLater();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mSockets.insert(socket->peerAddress(), socket);
|
ConnectionMultiplexer *multiplexer = new ConnectionMultiplexer(socket, this);
|
||||||
|
|
||||||
disconnect(socket, SIGNAL(connected()), this, SLOT(clientConnected()));
|
mSockets.insert(peer, multiplexer);
|
||||||
|
disconnect(socket, nullptr, this, nullptr);
|
||||||
|
|
||||||
connect(socket, SIGNAL(readyRead()), this, SLOT(clientIdentityReceived()));
|
auto channel = QSharedPointer<MultiplexChannel>{multiplexer->getDefaultChannel().release()};
|
||||||
connect(socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
|
connect(channel.data(), &MultiplexChannel::readyRead, this, [this,peer,channel] () { clientIdentityReceived(peer, channel); });
|
||||||
|
connect(channel.data(), &MultiplexChannel::aboutToClose, this, [this,peer,channel] () { socketDisconnected(peer, channel.data()); });
|
||||||
|
|
||||||
|
if (channel->bytesAvailable()) clientIdentityReceived(peer, channel);
|
||||||
|
if (!channel->isOpen()) socketDisconnected(peer, channel.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
//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()
|
void BluetoothLinkProvider::clientIdentityReceived(const QBluetoothAddress &peer, QSharedPointer<MultiplexChannel> socket)
|
||||||
{
|
{
|
||||||
QBluetoothSocket* socket = qobject_cast<QBluetoothSocket*>(sender());
|
socket->startTransaction();
|
||||||
if (!socket) return;
|
|
||||||
|
|
||||||
QByteArray identityArray;
|
QByteArray identityArray = socket->readLine();
|
||||||
|
if (identityArray.isEmpty()) {
|
||||||
if (socket->property("identityArray").isValid()) {
|
socket->rollbackTransaction();
|
||||||
identityArray = socket->property("identityArray").toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!identityArray.contains('\n') && socket->bytesAvailable() > 0) {
|
|
||||||
identityArray += socket->readAll();
|
|
||||||
}
|
|
||||||
if (!identityArray.contains('\n')) {
|
|
||||||
// This method will get retriggered when more data is available.
|
|
||||||
socket->setProperty("identityArray", identityArray);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
socket->setProperty("identityArray", QVariant());
|
socket->commitTransaction();
|
||||||
|
|
||||||
disconnect(socket, SIGNAL(readyRead()), this, SLOT(clientIdentityReceived()));
|
disconnect(socket.data(), &MultiplexChannel::readyRead, this, nullptr);
|
||||||
|
|
||||||
NetworkPacket receivedPacket;
|
NetworkPacket receivedPacket;
|
||||||
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) << "Not an identity packet";
|
||||||
mSockets.remove(socket->peerAddress());
|
mSockets.remove(peer);
|
||||||
socket->close();
|
socket->close();
|
||||||
socket->deleteLater();
|
socket->deleteLater();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qCDebug(KDECONNECT_CORE()) << "Received identity packet from" << socket->peerAddress();
|
qCDebug(KDECONNECT_CORE()) << "Received identity packet from" << peer;
|
||||||
|
|
||||||
disconnect(socket, SIGNAL(error(QBluetoothSocket::SocketError)), this, SLOT(connectError()));
|
//TODO?
|
||||||
|
//disconnect(socket, SIGNAL(error(QBluetoothSocket::SocketError)), this, SLOT(connectError()));
|
||||||
|
|
||||||
const QString& deviceId = receivedPacket.get<QString>(QStringLiteral("deviceId"));
|
const QString& deviceId = receivedPacket.get<QString>(QStringLiteral("deviceId"));
|
||||||
BluetoothDeviceLink* deviceLink = new BluetoothDeviceLink(deviceId, this, socket);
|
BluetoothDeviceLink* deviceLink = new BluetoothDeviceLink(deviceId, this, mSockets[peer], socket);
|
||||||
|
|
||||||
NetworkPacket np2;
|
NetworkPacket np2;
|
||||||
NetworkPacket::createIdentityPacket(&np2);
|
NetworkPacket::createIdentityPacket(&np2);
|
||||||
|
@ -232,65 +236,66 @@ void BluetoothLinkProvider::serverNewConnection()
|
||||||
|
|
||||||
qCDebug(KDECONNECT_CORE()) << "Received connection from" << socket->peerAddress();
|
qCDebug(KDECONNECT_CORE()) << "Received connection from" << socket->peerAddress();
|
||||||
|
|
||||||
if (mSockets.contains(socket->peerAddress())) {
|
QBluetoothAddress peer = socket->peerAddress();
|
||||||
qCDebug(KDECONNECT_CORE()) << "Duplicate connection from" << socket->peerAddress();
|
|
||||||
|
if (mSockets.contains(peer)) {
|
||||||
|
qCDebug(KDECONNECT_CORE()) << "Duplicate connection from" << peer;
|
||||||
socket->close();
|
socket->close();
|
||||||
socket->deleteLater();
|
socket->deleteLater();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(socket, SIGNAL(readyRead()), this, SLOT(serverDataReceived()));
|
ConnectionMultiplexer *multiplexer = new ConnectionMultiplexer(socket, this);
|
||||||
connect(socket, SIGNAL(error(QBluetoothSocket::SocketError)), this, SLOT(connectError()));
|
|
||||||
connect(socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
|
mSockets.insert(peer, multiplexer);
|
||||||
|
disconnect(socket, nullptr, this, nullptr);
|
||||||
|
|
||||||
|
auto channel = QSharedPointer<MultiplexChannel>{multiplexer->getDefaultChannel().release()};
|
||||||
|
connect(channel.data(), &MultiplexChannel::readyRead, this, [this,peer,channel] () { serverDataReceived(peer, channel); });
|
||||||
|
connect(channel.data(), &MultiplexChannel::aboutToClose, this, [this,peer,channel] () { socketDisconnected(peer, channel.data()); });
|
||||||
|
|
||||||
|
if (!channel->isOpen()) {
|
||||||
|
socketDisconnected(peer, channel.data());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
NetworkPacket np2;
|
NetworkPacket np2;
|
||||||
NetworkPacket::createIdentityPacket(&np2);
|
NetworkPacket::createIdentityPacket(&np2);
|
||||||
socket->write(np2.serialize());
|
socket->write(np2.serialize());
|
||||||
|
|
||||||
qCDebug(KDECONNECT_CORE()) << "Sent identity packet to" << socket->peerAddress();
|
qCDebug(KDECONNECT_CORE()) << "Sent identity packet to" << socket->peerAddress();
|
||||||
|
|
||||||
mSockets.insert(socket->peerAddress(), socket);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//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()
|
void BluetoothLinkProvider::serverDataReceived(const QBluetoothAddress &peer, QSharedPointer<MultiplexChannel> socket)
|
||||||
{
|
{
|
||||||
QBluetoothSocket* socket = qobject_cast<QBluetoothSocket*>(sender());
|
|
||||||
if (!socket) return;
|
|
||||||
|
|
||||||
QByteArray identityArray;
|
QByteArray identityArray;
|
||||||
if (socket->property("identityArray").isValid()) {
|
socket->startTransaction();
|
||||||
identityArray = socket->property("identityArray").toByteArray();
|
identityArray = socket->readLine();
|
||||||
}
|
|
||||||
|
|
||||||
while (!identityArray.contains('\n') && socket->bytesAvailable() > 0) {
|
if (identityArray.isEmpty()) {
|
||||||
identityArray += socket->readAll();
|
socket->rollbackTransaction();
|
||||||
}
|
|
||||||
if (!identityArray.contains('\n')) {
|
|
||||||
// This method will get retriggered when more data is available.
|
|
||||||
socket->setProperty("identityArray", identityArray);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
socket->setProperty("identityArray", QVariant());
|
socket->commitTransaction();
|
||||||
|
|
||||||
disconnect(socket, SIGNAL(readyRead()), this, SLOT(serverDataReceived()));
|
disconnect(socket.data(), &MultiplexChannel::readyRead, this, nullptr);
|
||||||
disconnect(socket, SIGNAL(error(QBluetoothSocket::SocketError)), this, SLOT(connectError()));
|
|
||||||
|
|
||||||
NetworkPacket receivedPacket;
|
NetworkPacket receivedPacket;
|
||||||
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) << "Not an identity packet.";
|
||||||
mSockets.remove(socket->peerAddress());
|
mSockets.remove(peer);
|
||||||
socket->close();
|
socket->close();
|
||||||
socket->deleteLater();
|
socket->deleteLater();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qCDebug(KDECONNECT_CORE()) << "Received identity packet from" << socket->peerAddress();
|
qCDebug(KDECONNECT_CORE()) << "Received identity packet from" << peer;
|
||||||
|
|
||||||
const QString& deviceId = receivedPacket.get<QString>(QStringLiteral("deviceId"));
|
const QString& deviceId = receivedPacket.get<QString>(QStringLiteral("deviceId"));
|
||||||
BluetoothDeviceLink* deviceLink = new BluetoothDeviceLink(deviceId, this, socket);
|
BluetoothDeviceLink* deviceLink = new BluetoothDeviceLink(deviceId, this, mSockets[peer], socket);
|
||||||
|
|
||||||
connect(deviceLink, SIGNAL(destroyed(QObject*)),
|
connect(deviceLink, SIGNAL(destroyed(QObject*)),
|
||||||
this, SLOT(deviceLinkDestroyed(QObject*)));
|
this, SLOT(deviceLinkDestroyed(QObject*)));
|
||||||
|
@ -310,14 +315,12 @@ void BluetoothLinkProvider::deviceLinkDestroyed(QObject* destroyedDeviceLink)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BluetoothLinkProvider::socketDisconnected()
|
void BluetoothLinkProvider::socketDisconnected(const QBluetoothAddress &peer, MultiplexChannel *socket)
|
||||||
{
|
{
|
||||||
QBluetoothSocket* socket = qobject_cast<QBluetoothSocket*>(sender());
|
qCDebug(KDECONNECT_CORE()) << "Disconnected";
|
||||||
if (!socket) return;
|
disconnect(socket, nullptr, this, nullptr);
|
||||||
|
|
||||||
disconnect(socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
|
mSockets.remove(peer);
|
||||||
|
|
||||||
mSockets.remove(mSockets.key(socket));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BluetoothLinkProvider::~BluetoothLinkProvider()
|
BluetoothLinkProvider::~BluetoothLinkProvider()
|
||||||
|
|
|
@ -35,6 +35,8 @@
|
||||||
#include "../linkprovider.h"
|
#include "../linkprovider.h"
|
||||||
|
|
||||||
class BluetoothDeviceLink;
|
class BluetoothDeviceLink;
|
||||||
|
class ConnectionMultiplexer;
|
||||||
|
class MultiplexChannel;
|
||||||
|
|
||||||
class KDECONNECTCORE_EXPORT BluetoothLinkProvider
|
class KDECONNECTCORE_EXPORT BluetoothLinkProvider
|
||||||
: public LinkProvider
|
: public LinkProvider
|
||||||
|
@ -53,16 +55,17 @@ public Q_SLOTS:
|
||||||
virtual void onStart() override;
|
virtual void onStart() override;
|
||||||
virtual void onStop() override;
|
virtual void onStop() override;
|
||||||
void connectError();
|
void connectError();
|
||||||
void serviceDiscoveryFinished();
|
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void deviceLinkDestroyed(QObject* destroyedDeviceLink);
|
void deviceLinkDestroyed(QObject* destroyedDeviceLink);
|
||||||
void socketDisconnected();
|
void socketDisconnected(const QBluetoothAddress &peerAddress, MultiplexChannel *socket);
|
||||||
|
|
||||||
void serverNewConnection();
|
void serverNewConnection();
|
||||||
void serverDataReceived();
|
void serverDataReceived(const QBluetoothAddress &peerAddress, QSharedPointer<MultiplexChannel> socket);
|
||||||
void clientConnected();
|
void clientConnected(QPointer<QBluetoothSocket> socket);
|
||||||
void clientIdentityReceived();
|
void clientIdentityReceived(const QBluetoothAddress &peerAddress, QSharedPointer<MultiplexChannel> socket);
|
||||||
|
|
||||||
|
void serviceDiscovered(const QBluetoothServiceInfo &info);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void addLink(BluetoothDeviceLink* deviceLink, const QString& deviceId);
|
void addLink(BluetoothDeviceLink* deviceLink, const QString& deviceId);
|
||||||
|
@ -76,7 +79,7 @@ private:
|
||||||
|
|
||||||
QMap<QString, DeviceLink*> mLinks;
|
QMap<QString, DeviceLink*> mLinks;
|
||||||
|
|
||||||
QMap<QBluetoothAddress, QBluetoothSocket*> mSockets;
|
QMap<QBluetoothAddress, ConnectionMultiplexer*> mSockets;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -20,19 +20,19 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "bluetoothuploadjob.h"
|
#include "bluetoothuploadjob.h"
|
||||||
|
#include "connectionmultiplexer.h"
|
||||||
|
#include "multiplexchannel.h"
|
||||||
|
|
||||||
#include <QBluetoothSocket>
|
#include <QBluetoothSocket>
|
||||||
#include "core_debug.h"
|
#include "core_debug.h"
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
|
|
||||||
BluetoothUploadJob::BluetoothUploadJob(const QSharedPointer<QIODevice>& data, const QBluetoothAddress& remoteAddress, QObject* parent)
|
BluetoothUploadJob::BluetoothUploadJob(const QSharedPointer<QIODevice>& data, ConnectionMultiplexer *connection, QObject* parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, mData(data)
|
, mData(data)
|
||||||
, mRemoteAddress(remoteAddress)
|
, mTransferUuid(connection->newChannel())
|
||||||
, mTransferUuid(QBluetoothUuid::createUuid())
|
|
||||||
, mServer(new QBluetoothServer(QBluetoothServiceInfo::RfcommProtocol, this))
|
|
||||||
{
|
{
|
||||||
mServer->setSecurityFlags(QBluetooth::Encryption | QBluetooth::Secure);
|
mSocket = QSharedPointer<MultiplexChannel>{connection->getChannel(mTransferUuid).release()};
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariantMap BluetoothUploadJob::transferInfo() const
|
QVariantMap BluetoothUploadJob::transferInfo() const
|
||||||
|
@ -44,45 +44,20 @@ QVariantMap BluetoothUploadJob::transferInfo() const
|
||||||
|
|
||||||
void BluetoothUploadJob::start()
|
void BluetoothUploadJob::start()
|
||||||
{
|
{
|
||||||
connect(mServer, &QBluetoothServer::newConnection, this, &BluetoothUploadJob::newConnection);
|
if (!mData->open(QIODevice::ReadOnly)) {
|
||||||
mServiceInfo = mServer->listen(mTransferUuid, QStringLiteral("KDE Connect Transfer Job"));
|
qCWarning(KDECONNECT_CORE) << "error when opening the input to upload";
|
||||||
Q_ASSERT(mServiceInfo.isValid());
|
return; //TODO: Handle error, clean up...
|
||||||
}
|
|
||||||
|
|
||||||
void BluetoothUploadJob::newConnection()
|
|
||||||
{
|
|
||||||
m_socket = mServer->nextPendingConnection();
|
|
||||||
Q_ASSERT(m_socket);
|
|
||||||
m_socket->setParent(this);
|
|
||||||
connect(m_socket, &QBluetoothSocket::disconnected, this, &BluetoothUploadJob::deleteLater);
|
|
||||||
|
|
||||||
if (m_socket->peerAddress() != mRemoteAddress) {
|
|
||||||
m_socket->close();
|
|
||||||
} else {
|
|
||||||
mServer->close();
|
|
||||||
disconnect(mServer, &QBluetoothServer::newConnection, this, &BluetoothUploadJob::newConnection);
|
|
||||||
mServiceInfo.unregisterService();
|
|
||||||
|
|
||||||
if (!mData->open(QIODevice::ReadOnly)) {
|
|
||||||
qCWarning(KDECONNECT_CORE) << "error when opening the input to upload";
|
|
||||||
m_socket->close();
|
|
||||||
deleteLater();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
connect(mSocket.data(), &MultiplexChannel::bytesWritten, this, &BluetoothUploadJob::writeSome);
|
||||||
connect(m_socket, &QBluetoothSocket::bytesWritten, this, &BluetoothUploadJob::writeSome);
|
connect(mSocket.data(), &MultiplexChannel::aboutToClose, this, &BluetoothUploadJob::closeConnection);
|
||||||
connect(m_socket, &QBluetoothSocket::disconnected, this, &BluetoothUploadJob::closeConnection);
|
|
||||||
writeSome();
|
writeSome();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BluetoothUploadJob::writeSome() {
|
void BluetoothUploadJob::writeSome() {
|
||||||
Q_ASSERT(m_socket);
|
|
||||||
|
|
||||||
bool errorOccurred = false;
|
bool errorOccurred = false;
|
||||||
while (m_socket->bytesToWrite() == 0 && mData->bytesAvailable() && m_socket->isWritable()) {
|
while (mSocket->bytesToWrite() == 0 && mData->bytesAvailable() && mSocket->isWritable()) {
|
||||||
qint64 bytes = qMin<qint64>(mData->bytesAvailable(), 4096);
|
qint64 bytes = qMin<qint64>(mData->bytesAvailable(), 4096);
|
||||||
int bytesWritten = m_socket->write(mData->read(bytes));
|
int bytesWritten = mSocket->write(mData->read(bytes));
|
||||||
|
|
||||||
if (bytesWritten < 0) {
|
if (bytesWritten < 0) {
|
||||||
qCWarning(KDECONNECT_CORE()) << "error when writing data to bluetooth upload" << bytes << mData->bytesAvailable();
|
qCWarning(KDECONNECT_CORE()) << "error when writing data to bluetooth upload" << bytes << mData->bytesAvailable();
|
||||||
|
@ -92,18 +67,8 @@ void BluetoothUploadJob::writeSome() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mData->atEnd() || errorOccurred) {
|
if (mData->atEnd() || errorOccurred) {
|
||||||
disconnect(m_socket, &QBluetoothSocket::bytesWritten, this, &BluetoothUploadJob::writeSome);
|
|
||||||
mData->close();
|
mData->close();
|
||||||
|
mSocket->close();
|
||||||
connect(m_socket, &QBluetoothSocket::bytesWritten, this, &BluetoothUploadJob::finishWrites);
|
|
||||||
finishWrites();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BluetoothUploadJob::finishWrites() {
|
|
||||||
Q_ASSERT(m_socket);
|
|
||||||
if (m_socket->bytesToWrite() == 0) {
|
|
||||||
closeConnection();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,30 +30,28 @@
|
||||||
#include <QBluetoothUuid>
|
#include <QBluetoothUuid>
|
||||||
#include <QBluetoothServer>
|
#include <QBluetoothServer>
|
||||||
|
|
||||||
|
class ConnectionMultiplexer;
|
||||||
|
class MultiplexChannel;
|
||||||
|
|
||||||
class BluetoothUploadJob
|
class BluetoothUploadJob
|
||||||
: public QObject
|
: public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit BluetoothUploadJob(const QSharedPointer<QIODevice>& data, const QBluetoothAddress& remoteAddress, QObject* parent = 0);
|
explicit BluetoothUploadJob(const QSharedPointer<QIODevice>& data, ConnectionMultiplexer *connection, QObject* parent = 0);
|
||||||
|
|
||||||
QVariantMap transferInfo() const;
|
QVariantMap transferInfo() const;
|
||||||
void start();
|
void start();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QSharedPointer<QIODevice> mData;
|
QSharedPointer<QIODevice> mData;
|
||||||
QBluetoothAddress mRemoteAddress;
|
|
||||||
QBluetoothUuid mTransferUuid;
|
QBluetoothUuid mTransferUuid;
|
||||||
QBluetoothServer* mServer;
|
QSharedPointer<MultiplexChannel> mSocket;
|
||||||
QBluetoothServiceInfo mServiceInfo;
|
|
||||||
QBluetoothSocket* m_socket;
|
|
||||||
|
|
||||||
void closeConnection();
|
void closeConnection();
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void newConnection();
|
|
||||||
void writeSome();
|
void writeSome();
|
||||||
void finishWrites();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BLUETOOTHUPLOADJOB_H
|
#endif // BLUETOOTHUPLOADJOB_H
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
/**
|
/**
|
||||||
* The default channel uuid. This channel is opened implicitely (without communication).
|
* The default channel uuid. This channel is opened implicitely (without communication).
|
||||||
*/
|
*/
|
||||||
constexpr const char DEFAULT_CHANNEL_UUID[] = "a0d0aaf4-1072-4d81-aa35-902a954b1266";
|
#define DEFAULT_CHANNEL_UUID "a0d0aaf4-1072-4d81-aa35-902a954b1266"
|
||||||
|
|
||||||
//Message type constants
|
//Message type constants
|
||||||
constexpr char MESSAGE_PROTOCOL_VERSION = 0;
|
constexpr char MESSAGE_PROTOCOL_VERSION = 0;
|
||||||
|
@ -60,7 +60,7 @@ ConnectionMultiplexer::ConnectionMultiplexer(QBluetoothSocket *socket, QObject *
|
||||||
QMetaObject::invokeMethod(this, &ConnectionMultiplexer::bytesWritten, Qt::QueuedConnection);
|
QMetaObject::invokeMethod(this, &ConnectionMultiplexer::bytesWritten, Qt::QueuedConnection);
|
||||||
|
|
||||||
//Always open the default channel
|
//Always open the default channel
|
||||||
addChannel(QBluetoothUuid{QString{DEFAULT_CHANNEL_UUID}});
|
addChannel(QBluetoothUuid{QStringLiteral(DEFAULT_CHANNEL_UUID)});
|
||||||
|
|
||||||
//Immediately check if we can read stuff ("readyRead" may not be called in that case)
|
//Immediately check if we can read stuff ("readyRead" may not be called in that case)
|
||||||
if (mSocket->bytesAvailable()) {
|
if (mSocket->bytesAvailable()) {
|
||||||
|
@ -283,7 +283,7 @@ std::unique_ptr<MultiplexChannel> ConnectionMultiplexer::getChannel(QBluetoothUu
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<MultiplexChannel> ConnectionMultiplexer::getDefaultChannel() {
|
std::unique_ptr<MultiplexChannel> ConnectionMultiplexer::getDefaultChannel() {
|
||||||
return getChannel(QBluetoothUuid{QString{DEFAULT_CHANNEL_UUID}});
|
return getChannel(QBluetoothUuid{QStringLiteral(DEFAULT_CHANNEL_UUID)});
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionMultiplexer::bytesWritten() {
|
void ConnectionMultiplexer::bytesWritten() {
|
||||||
|
|
|
@ -25,10 +25,8 @@ DeviceLineReader::DeviceLineReader(QIODevice* device, QObject* parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, m_device(device)
|
, m_device(device)
|
||||||
{
|
{
|
||||||
connect(m_device, SIGNAL(readyRead()),
|
connect(m_device, &QIODevice::readyRead, this, &DeviceLineReader::dataReceived);
|
||||||
this, SLOT(dataReceived()));
|
connect(m_device, &QIODevice::aboutToClose, this, &DeviceLineReader::disconnected);
|
||||||
connect(m_device, SIGNAL(disconnected()),
|
|
||||||
this, SIGNAL(disconnected()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceLineReader::dataReceived()
|
void DeviceLineReader::dataReceived()
|
||||||
|
|
Loading…
Reference in a new issue