Bluetooth multiplexer integration and assorted fixes

This commit is contained in:
Matthijs Tijink 2019-03-08 19:18:01 +01:00
parent cda1280456
commit 0b6224fc0e
10 changed files with 145 additions and 173 deletions

View file

@ -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);
} }
} }

View file

@ -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);

View file

@ -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);
} }

View file

@ -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

View file

@ -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()

View file

@ -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;
}; };

View file

@ -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();
} }
} }

View file

@ -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

View file

@ -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() {

View file

@ -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()