Fixing memory leaks in LanDeviceLinkProvider and LanDeviceLink
This commit is contained in:
parent
127a117c62
commit
4b6aa135e3
7 changed files with 55 additions and 60 deletions
|
@ -36,6 +36,7 @@ class DeviceLink
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DeviceLink(const QString& deviceId, LinkProvider* parent);
|
DeviceLink(const QString& deviceId, LinkProvider* parent);
|
||||||
|
virtual ~DeviceLink() { };
|
||||||
|
|
||||||
const QString& deviceId() { return mDeviceId; }
|
const QString& deviceId() { return mDeviceId; }
|
||||||
LinkProvider* provider() { return mLinkProvider; }
|
LinkProvider* provider() { return mLinkProvider; }
|
||||||
|
|
|
@ -30,16 +30,24 @@
|
||||||
#include "downloadjob.h"
|
#include "downloadjob.h"
|
||||||
#include "socketlinereader.h"
|
#include "socketlinereader.h"
|
||||||
|
|
||||||
LanDeviceLink::LanDeviceLink(const QString& d, LinkProvider* a, QTcpSocket* socket)
|
LanDeviceLink::LanDeviceLink(const QString& deviceId, LinkProvider* parent, QTcpSocket* socket)
|
||||||
: DeviceLink(d, a)
|
: DeviceLink(deviceId, parent)
|
||||||
, mSocketLineReader(new SocketLineReader(socket, a))
|
, mSocketLineReader(new SocketLineReader(socket))
|
||||||
{
|
{
|
||||||
connect(mSocketLineReader, SIGNAL(disconnected()),
|
|
||||||
this, SLOT(deleteLater()));
|
|
||||||
connect(mSocketLineReader, SIGNAL(readyRead()),
|
connect(mSocketLineReader, SIGNAL(readyRead()),
|
||||||
this, SLOT(dataReceived()));
|
this, SLOT(dataReceived()));
|
||||||
|
|
||||||
|
//We take ownership of the socket.
|
||||||
|
//When the link provider distroys us,
|
||||||
|
//the socket (and the reader) will be
|
||||||
|
//destroyed as well
|
||||||
|
connect(socket, SIGNAL(disconnected()),
|
||||||
|
this, SLOT(deleteLater()));
|
||||||
|
mSocketLineReader->setParent(this);
|
||||||
|
socket->setParent(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool LanDeviceLink::sendPackageEncrypted(QCA::PublicKey& key, NetworkPackage& np)
|
bool LanDeviceLink::sendPackageEncrypted(QCA::PublicKey& key, NetworkPackage& np)
|
||||||
{
|
{
|
||||||
if (np.hasPayload()) {
|
if (np.hasPayload()) {
|
||||||
|
@ -54,7 +62,7 @@ bool LanDeviceLink::sendPackageEncrypted(QCA::PublicKey& key, NetworkPackage& np
|
||||||
|
|
||||||
//TODO: Actually detect if a package is received or not, now we keep TCP
|
//TODO: Actually detect if a package is received or not, now we keep TCP
|
||||||
//"ESTABLISHED" connections that look legit (return true when we use them),
|
//"ESTABLISHED" connections that look legit (return true when we use them),
|
||||||
//but that are actually broken
|
//but that are actually broken (until keepalive detects that they are down).
|
||||||
return (written != -1);
|
return (written != -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,9 +75,6 @@ bool LanDeviceLink::sendPackage(NetworkPackage& np)
|
||||||
}
|
}
|
||||||
|
|
||||||
int written = mSocketLineReader->write(np.serialize());
|
int written = mSocketLineReader->write(np.serialize());
|
||||||
//TODO: Actually detect if a package is received or not, now we keep TCP
|
|
||||||
//"ESTABLISHED" connections that look legit (return true when we use them),
|
|
||||||
//but that are actually broken
|
|
||||||
return (written != -1);
|
return (written != -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ class LanDeviceLink
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LanDeviceLink(const QString& d, LinkProvider* a, QTcpSocket* socket);
|
LanDeviceLink(const QString& deviceId, LinkProvider* parent, QTcpSocket* socket);
|
||||||
|
|
||||||
bool sendPackage(NetworkPackage& np);
|
bool sendPackage(NetworkPackage& np);
|
||||||
bool sendPackageEncrypted(QCA::PublicKey& key, NetworkPackage& np);
|
bool sendPackageEncrypted(QCA::PublicKey& key, NetworkPackage& np);
|
||||||
|
|
|
@ -104,44 +104,39 @@ void LanLinkProvider::onNetworkChange(QNetworkSession::State state)
|
||||||
NetworkPackage::createIdentityPackage(&np);
|
NetworkPackage::createIdentityPackage(&np);
|
||||||
np.set("tcpPort", mTcpPort);
|
np.set("tcpPort", mTcpPort);
|
||||||
mUdpSocket.writeDatagram(np.serialize(), QHostAddress("255.255.255.255"), port);
|
mUdpSocket.writeDatagram(np.serialize(), QHostAddress("255.255.255.255"), port);
|
||||||
|
|
||||||
//TODO: Ping active connections to see if they are still reachable
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//I'm the existing device, a new device is kindly introducing itself (I will create a TcpSocket)
|
//I'm the existing device, a new device is kindly introducing itself.
|
||||||
|
//I will create a TcpSocket and try to connect. This can result in either connected() or connectError().
|
||||||
void LanLinkProvider::newUdpConnection()
|
void LanLinkProvider::newUdpConnection()
|
||||||
{
|
{
|
||||||
while (mUdpServer->hasPendingDatagrams()) {
|
while (mUdpServer->hasPendingDatagrams()) {
|
||||||
QByteArray datagram;
|
QByteArray datagram;
|
||||||
datagram.resize(mUdpServer->pendingDatagramSize());
|
datagram.resize(mUdpServer->pendingDatagramSize());
|
||||||
QHostAddress sender;
|
QHostAddress sender;
|
||||||
quint16 senderPort;
|
|
||||||
|
|
||||||
mUdpServer->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
|
|
||||||
|
|
||||||
NetworkPackage* np = new NetworkPackage("");
|
|
||||||
bool success = NetworkPackage::unserialize(datagram,np);
|
|
||||||
|
|
||||||
mUdpServer->readDatagram(datagram.data(), datagram.size(), &sender);
|
mUdpServer->readDatagram(datagram.data(), datagram.size(), &sender);
|
||||||
|
|
||||||
NetworkPackage* receivedPackage = new NetworkPackage("");
|
NetworkPackage* receivedPackage = new NetworkPackage("");
|
||||||
success = NetworkPackage::unserialize(datagram, receivedPackage);
|
bool success = NetworkPackage::unserialize(datagram, receivedPackage);
|
||||||
|
|
||||||
if (!success || receivedPackage->type() != PACKAGE_TYPE_IDENTITY) {
|
if (!success || receivedPackage->type() != PACKAGE_TYPE_IDENTITY) {
|
||||||
delete receivedPackage;
|
delete receivedPackage;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
KSharedConfigPtr config = KSharedConfig::openConfig("kdeconnectrc");
|
KSharedConfigPtr config = KSharedConfig::openConfig("kdeconnectrc");
|
||||||
const QString myId = config->group("myself").readEntry<QString>("id","");
|
const QString myId = config->group("myself").readEntry<QString>("id","");
|
||||||
|
|
||||||
//kDebug(debugArea()) << "Ignoring my own broadcast";
|
|
||||||
if (receivedPackage->get<QString>("deviceId") == myId) {
|
if (receivedPackage->get<QString>("deviceId") == myId) {
|
||||||
|
//kDebug(debugArea()) << "Ignoring my own broadcast";
|
||||||
|
delete receivedPackage;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tcpPort = receivedPackage->get<int>("tcpPort", port);
|
int tcpPort = receivedPackage->get<int>("tcpPort", port);
|
||||||
|
|
||||||
//kDebug(debugArea()) << "Received Udp presentation from" << sender << "asking for a tcp connection on port " << tcpPort;
|
//kDebug(debugArea()) << "Received Udp identity package from" << sender << " asking for a tcp connection on port " << tcpPort;
|
||||||
|
|
||||||
QTcpSocket* socket = new QTcpSocket(this);
|
QTcpSocket* socket = new QTcpSocket(this);
|
||||||
receivedIdentityPackages[socket].np = receivedPackage;
|
receivedIdentityPackages[socket].np = receivedPackage;
|
||||||
|
@ -155,9 +150,9 @@ void LanLinkProvider::newUdpConnection()
|
||||||
void LanLinkProvider::connectError()
|
void LanLinkProvider::connectError()
|
||||||
{
|
{
|
||||||
QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender());
|
QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender());
|
||||||
|
if (!socket) return;
|
||||||
disconnect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(connectError()));
|
|
||||||
disconnect(socket, SIGNAL(connected()), this, SLOT(connected()));
|
disconnect(socket, SIGNAL(connected()), this, SLOT(connected()));
|
||||||
|
disconnect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(connectError()));
|
||||||
|
|
||||||
kDebug(debugArea()) << "Fallback (1), try reverse connection";
|
kDebug(debugArea()) << "Fallback (1), try reverse connection";
|
||||||
NetworkPackage np("");
|
NetworkPackage np("");
|
||||||
|
@ -165,17 +160,17 @@ void LanLinkProvider::connectError()
|
||||||
np.set("tcpPort", mTcpPort);
|
np.set("tcpPort", mTcpPort);
|
||||||
mUdpSocket.writeDatagram(np.serialize(), receivedIdentityPackages[socket].sender, port);
|
mUdpSocket.writeDatagram(np.serialize(), receivedIdentityPackages[socket].sender, port);
|
||||||
|
|
||||||
|
//The socket we created didn't work, and we didn't manage
|
||||||
|
//to create a LanDeviceLink from it, deleting everything.
|
||||||
delete receivedIdentityPackages[socket].np;
|
delete receivedIdentityPackages[socket].np;
|
||||||
receivedIdentityPackages.remove(socket);
|
receivedIdentityPackages.remove(socket);
|
||||||
|
delete socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LanLinkProvider::connected()
|
void LanLinkProvider::connected()
|
||||||
{
|
{
|
||||||
|
|
||||||
QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender());
|
QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender());
|
||||||
|
|
||||||
if (!socket) return;
|
if (!socket) return;
|
||||||
|
|
||||||
disconnect(socket, SIGNAL(connected()), this, SLOT(connected()));
|
disconnect(socket, SIGNAL(connected()), this, SLOT(connected()));
|
||||||
disconnect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(connectError()));
|
disconnect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(connectError()));
|
||||||
|
|
||||||
|
@ -189,12 +184,11 @@ void LanLinkProvider::connected()
|
||||||
|
|
||||||
NetworkPackage np2("");
|
NetworkPackage np2("");
|
||||||
NetworkPackage::createIdentityPackage(&np2);
|
NetworkPackage::createIdentityPackage(&np2);
|
||||||
|
|
||||||
bool success = deviceLink->sendPackage(np2);
|
bool success = deviceLink->sendPackage(np2);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
|
|
||||||
//kDebug(debugArea()) << "Handshaking done (i'm the existing device)";
|
kDebug(debugArea()) << "Handshaking done (i'm the existing device)";
|
||||||
|
|
||||||
connect(deviceLink, SIGNAL(destroyed(QObject*)),
|
connect(deviceLink, SIGNAL(destroyed(QObject*)),
|
||||||
this, SLOT(deviceLinkDestroyed(QObject*)));
|
this, SLOT(deviceLinkDestroyed(QObject*)));
|
||||||
|
@ -214,62 +208,64 @@ void LanLinkProvider::connected()
|
||||||
mLinks[deviceId] = deviceLink;
|
mLinks[deviceId] = deviceLink;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
//I think this will never happen
|
//I think this will never happen, but if it happens the deviceLink
|
||||||
|
//(or the socket that is now inside it) might not be valid. Delete them.
|
||||||
|
delete deviceLink;
|
||||||
|
|
||||||
kDebug(debugArea()) << "Fallback (2), try reverse connection";
|
kDebug(debugArea()) << "Fallback (2), try reverse connection";
|
||||||
mUdpSocket.writeDatagram(np2.serialize(), receivedIdentityPackages[socket].sender, port);
|
mUdpSocket.writeDatagram(np2.serialize(), receivedIdentityPackages[socket].sender, port);
|
||||||
delete deviceLink;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
receivedIdentityPackages.remove(socket);
|
|
||||||
|
|
||||||
delete receivedPackage;
|
delete receivedPackage;
|
||||||
|
receivedIdentityPackages.remove(socket);
|
||||||
|
//We don't delete the socket because now it's owned by the LanDeviceLink
|
||||||
}
|
}
|
||||||
|
|
||||||
//I'm the new device and this is the answer to my UDP introduction (no data received yet)
|
//I'm the new device and this is the answer to my UDP identity package (no data received yet)
|
||||||
void LanLinkProvider::newConnection()
|
void LanLinkProvider::newConnection()
|
||||||
{
|
{
|
||||||
//kDebug(debugArea()) << "LanLinkProvider newConnection";
|
//kDebug(debugArea()) << "LanLinkProvider newConnection";
|
||||||
|
|
||||||
while(mTcpServer->hasPendingConnections()) {
|
while(mTcpServer->hasPendingConnections()) {
|
||||||
QTcpSocket* socket = mTcpServer->nextPendingConnection();
|
QTcpSocket* socket = mTcpServer->nextPendingConnection();
|
||||||
socket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
|
configureSocket(socket);
|
||||||
|
//This socket is still managed by us (and child of the QTcpServer), if
|
||||||
|
//it disconnects before we manage to pass it to a LanDeviceLink, it's
|
||||||
|
//our responsability to delete it. We do so with this connection.
|
||||||
|
connect(socket, SIGNAL(disconnected()),
|
||||||
|
socket, SLOT(deleteLater()));
|
||||||
|
connect(socket, SIGNAL(readyRead()),
|
||||||
|
this, SLOT(dataReceived()));
|
||||||
|
|
||||||
connect(socket, SIGNAL(readyRead()), this, SLOT(dataReceived()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
NetworkPackage np(PACKAGE_TYPE_IDENTITY);
|
|
||||||
NetworkPackage::createIdentityPackage(&np);
|
|
||||||
int written = socket->write(np.serialize());
|
|
||||||
|
|
||||||
kDebug(debugArea()) << "LanLinkProvider sent package." << written << " bytes written, waiting for reply";
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//I'm the new device and this is the answer to my UDP introduction (data received)
|
//I'm the new device and this is the answer to my UDP identity package (data received)
|
||||||
void LanLinkProvider::dataReceived()
|
void LanLinkProvider::dataReceived()
|
||||||
{
|
{
|
||||||
QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender());
|
QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender());
|
||||||
configureSocket(socket);
|
|
||||||
|
|
||||||
const QByteArray data = socket->readLine();
|
const QByteArray data = socket->readLine();
|
||||||
|
|
||||||
//kDebug(debugArea()) << "LanLinkProvider received reply:" << data;
|
|
||||||
|
|
||||||
NetworkPackage np("");
|
NetworkPackage np("");
|
||||||
bool success = NetworkPackage::unserialize(data, &np);
|
bool success = NetworkPackage::unserialize(data, &np);
|
||||||
|
//kDebug(debugArea()) << "LanLinkProvider received reply:" << data;
|
||||||
|
|
||||||
if (!success || np.type() != PACKAGE_TYPE_IDENTITY) {
|
if (!success || np.type() != PACKAGE_TYPE_IDENTITY) {
|
||||||
kDebug(debugArea()) << "LanLinkProvider/newConnection: Not an identification package (wuh?)";
|
kDebug(debugArea()) << "LanLinkProvider/newConnection: Not an identification package (wuh?)";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kDebug(debugArea()) << "Handshaking done (i'm the new device)";
|
||||||
|
|
||||||
|
//This socket will now be owned by the LanDeviceLink, forget about it
|
||||||
|
disconnect(socket, SIGNAL(readyRead()),
|
||||||
|
this, SLOT(dataReceived()));
|
||||||
|
disconnect(socket, SIGNAL(disconnected()),
|
||||||
|
socket, SLOT(deleteLater()));
|
||||||
|
|
||||||
const QString& deviceId = np.get<QString>("deviceId");
|
const QString& deviceId = np.get<QString>("deviceId");
|
||||||
LanDeviceLink* deviceLink = new LanDeviceLink(deviceId, this, socket);
|
LanDeviceLink* deviceLink = new LanDeviceLink(deviceId, this, socket);
|
||||||
|
|
||||||
//kDebug(debugArea()) << "Handshaking done (i'm the new device)";
|
|
||||||
|
|
||||||
connect(deviceLink, SIGNAL(destroyed(QObject*)),
|
connect(deviceLink, SIGNAL(destroyed(QObject*)),
|
||||||
this, SLOT(deviceLinkDestroyed(QObject*)));
|
this, SLOT(deviceLinkDestroyed(QObject*)));
|
||||||
|
|
||||||
|
@ -286,7 +282,6 @@ void LanLinkProvider::dataReceived()
|
||||||
|
|
||||||
mLinks[deviceId] = deviceLink;
|
mLinks[deviceId] = deviceLink;
|
||||||
|
|
||||||
disconnect(socket,SIGNAL(readyRead()),this,SLOT(dataReceived()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LanLinkProvider::deviceLinkDestroyed(QObject* destroyedDeviceLink)
|
void LanLinkProvider::deviceLinkDestroyed(QObject* destroyedDeviceLink)
|
||||||
|
|
|
@ -25,13 +25,8 @@ SocketLineReader::SocketLineReader(QTcpSocket* socket, QObject* parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, mSocket(socket)
|
, mSocket(socket)
|
||||||
{
|
{
|
||||||
|
|
||||||
connect(mSocket, SIGNAL(disconnected()),
|
|
||||||
this, SIGNAL(disconnected()));
|
|
||||||
|
|
||||||
connect(mSocket, SIGNAL(readyRead()),
|
connect(mSocket, SIGNAL(readyRead()),
|
||||||
this, SLOT(dataReceived()));
|
this, SLOT(dataReceived()));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketLineReader::dataReceived()
|
void SocketLineReader::dataReceived()
|
||||||
|
|
|
@ -45,7 +45,6 @@ public:
|
||||||
qint64 bytesAvailable() { return mPackages.size(); }
|
qint64 bytesAvailable() { return mPackages.size(); }
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void disconnected();
|
|
||||||
void readyRead();
|
void readyRead();
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
|
|
|
@ -52,7 +52,7 @@ public Q_SLOTS:
|
||||||
virtual void onNetworkChange(QNetworkSession::State state) = 0;
|
virtual void onNetworkChange(QNetworkSession::State state) = 0;
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
//NOTE: The provider will to destroy the DeviceLink when it's no longer accessible,
|
//NOTE: The provider will destroy the DeviceLink when it's no longer accessible,
|
||||||
// and every user should listen to the destroyed signal to remove its references.
|
// and every user should listen to the destroyed signal to remove its references.
|
||||||
// That's the reason because there is no "onConnectionLost".
|
// That's the reason because there is no "onConnectionLost".
|
||||||
void onConnectionReceived(const NetworkPackage& identityPackage, DeviceLink*) const;
|
void onConnectionReceived(const NetworkPackage& identityPackage, DeviceLink*) const;
|
||||||
|
|
Loading…
Reference in a new issue