diff --git a/core/networkpacket.cpp b/core/networkpacket.cpp index 5da65afa..ced10f81 100644 --- a/core/networkpacket.cpp +++ b/core/networkpacket.cpp @@ -1,170 +1,155 @@ /** * Copyright 2013 Albert Vaca * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "networkpacket.h" #include "core_debug.h" #include #include #include #include #include #include #include #include "dbushelper.h" #include "filetransferjob.h" #include "pluginloader.h" #include "kdeconnectconfig.h" QDebug operator<<(QDebug s, const NetworkPacket& pkg) { s.nospace() << "NetworkPacket(" << pkg.type() << ':' << pkg.body(); if (pkg.hasPayload()) { s.nospace() << ":withpayload"; } s.nospace() << ')'; return s.space(); } const int NetworkPacket::s_protocolVersion = 7; NetworkPacket::NetworkPacket(const QString& type, const QVariantMap& body) : m_id(QString::number(QDateTime::currentMSecsSinceEpoch())) , m_type(type) , m_body(body) , m_payload() , m_payloadSize(0) { } void NetworkPacket::createIdentityPacket(NetworkPacket* np) { np->m_id = QString::number(QDateTime::currentMSecsSinceEpoch()); np->m_type = PACKET_TYPE_IDENTITY; np->m_payload = QSharedPointer(); np->m_payloadSize = 0; np->set(QStringLiteral("deviceId"), KdeConnectConfig::instance().deviceId()); np->set(QStringLiteral("deviceName"), KdeConnectConfig::instance().name()); np->set(QStringLiteral("deviceType"), KdeConnectConfig::instance().deviceType()); np->set(QStringLiteral("protocolVersion"), NetworkPacket::s_protocolVersion); np->set(QStringLiteral("incomingCapabilities"), PluginLoader::instance()->incomingCapabilities()); np->set(QStringLiteral("outgoingCapabilities"), PluginLoader::instance()->outgoingCapabilities()); //qCDebug(KDECONNECT_CORE) << "createIdentityPacket" << np->serialize(); } -template -QVariantMap qobject2qvariant(const T* object) -{ - QVariantMap map; - auto metaObject = T::staticMetaObject; - for(int i = metaObject.propertyOffset(); i < metaObject.propertyCount(); ++i) { - QMetaProperty prop = metaObject.property(i); - map.insert(QString::fromLatin1(prop.name()), prop.readOnGadget(object)); - } - - return map; -} - QByteArray NetworkPacket::serialize() const { //Object -> QVariant - //QVariantMap variant; - //variant["id"] = mId; - //variant["type"] = mType; - //variant["body"] = mBody; - QVariantMap variant = qobject2qvariant(this); + QVariantMap variant; + variant.insert(QStringLiteral("id"), m_id); + variant.insert(QStringLiteral("type"), m_type); + variant.insert(QStringLiteral("body"), m_body); if (hasPayload()) { - //qCDebug(KDECONNECT_CORE) << "Serializing payloadTransferInfo"; - variant[QStringLiteral("payloadSize")] = payloadSize(); - variant[QStringLiteral("payloadTransferInfo")] = m_payloadTransferInfo; + variant.insert(QStringLiteral("payloadSize"), m_payloadSize); + variant.insert(QStringLiteral("payloadTransferInfo"), m_payloadTransferInfo); } //QVariant -> json auto jsonDocument = QJsonDocument::fromVariant(variant); QByteArray json = jsonDocument.toJson(QJsonDocument::Compact); if (json.isEmpty()) { qCDebug(KDECONNECT_CORE) << "Serialization error:"; } else { /*if (!isEncrypted()) { //qCDebug(KDECONNECT_CORE) << "Serialized packet:" << json; }*/ json.append('\n'); } return json; } template void qvariant2qobject(const QVariantMap& variant, T* object) { for ( QVariantMap::const_iterator iter = variant.begin(); iter != variant.end(); ++iter ) { const int propertyIndex = T::staticMetaObject.indexOfProperty(iter.key().toLatin1()); if (propertyIndex < 0) { qCWarning(KDECONNECT_CORE) << "missing property" << object << iter.key(); continue; } QMetaProperty property = T::staticMetaObject.property(propertyIndex); bool ret = property.writeOnGadget(object, *iter); if (!ret) { qCWarning(KDECONNECT_CORE) << "couldn't set" << object << "->" << property.name() << '=' << *iter; } } } bool NetworkPacket::unserialize(const QByteArray& a, NetworkPacket* np) { //Json -> QVariant QJsonParseError parseError; auto parser = QJsonDocument::fromJson(a, &parseError); if (parser.isNull()) { qCDebug(KDECONNECT_CORE) << "Unserialization error:" << parseError.errorString(); return false; } auto variant = parser.toVariant().toMap(); qvariant2qobject(variant, np); if (np->m_payloadSize == -1) { np->m_payloadSize = np->get(QStringLiteral("size"), -1); } np->m_payloadTransferInfo = variant[QStringLiteral("payloadTransferInfo")].toMap(); //Will return an empty qvariantmap if was not present, which is ok //Ids containing characters that are not allowed as dbus paths would make app crash if (np->m_body.contains(QStringLiteral("deviceId"))) { QString deviceId = np->get(QStringLiteral("deviceId")); DBusHelper::filterNonExportableCharacters(deviceId); np->set(QStringLiteral("deviceId"), deviceId); } return true; } FileTransferJob* NetworkPacket::createPayloadTransferJob(const QUrl& destination) const { return new FileTransferJob(this, destination); } diff --git a/tests/networkpackettests.cpp b/tests/networkpackettests.cpp index 09d57d78..e4e8082a 100644 --- a/tests/networkpackettests.cpp +++ b/tests/networkpackettests.cpp @@ -1,95 +1,143 @@ /** * Copyright 2013 Albert Vaca * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "networkpackettests.h" #include "core/networkpacket.h" #include +#include QTEST_GUILESS_MAIN(NetworkPacketTests); void NetworkPacketTests::initTestCase() { // Called before the first testfunction is executed } void NetworkPacketTests::networkPacketTest() { NetworkPacket np(QStringLiteral("com.test")); np.set(QStringLiteral("hello"), QStringLiteral("hola")); QCOMPARE( (np.get(QStringLiteral("hello"), QStringLiteral("bye"))) , QStringLiteral("hola") ); np.set(QStringLiteral("hello"), QString()); QCOMPARE((np.get(QStringLiteral("hello"), QStringLiteral("bye"))) , QString()); np.body().remove(QStringLiteral("hello")); QCOMPARE((np.get(QStringLiteral("hello"), QStringLiteral("bye"))) , QStringLiteral("bye")); np.set(QStringLiteral("foo"), QStringLiteral("bar")); QByteArray ba = np.serialize(); //qDebug() << "Serialized packet:" << ba; NetworkPacket np2(QLatin1String("")); NetworkPacket::unserialize(ba,&np2); QCOMPARE( np.id(), np2.id() ); QCOMPARE( np.type(), np2.type() ); QCOMPARE( np.body(), np2.body() ); QByteArray json("{\"id\":\"123\",\"type\":\"test\",\"body\":{\"testing\":true}}"); //qDebug() << json; NetworkPacket::unserialize(json,&np2); QCOMPARE( np2.id(), QStringLiteral("123") ); QCOMPARE( (np2.get(QStringLiteral("testing"))), true ); QCOMPARE( (np2.get(QStringLiteral("not_testing"))), false ); QCOMPARE( (np2.get(QStringLiteral("not_testing"),true)), true ); //NetworkPacket::unserialize("this is not json",&np2); //QtTest::ignoreMessage(QtSystemMsg, "json_parser - syntax error found, forcing abort, Line 1 Column 0"); //QtTest::ignoreMessage(QtDebugMsg, "Unserialization error: 1 \"syntax error, unexpected string\""); } void NetworkPacketTests::networkPacketIdentityTest() { NetworkPacket np(QLatin1String("")); NetworkPacket::createIdentityPacket(&np); QCOMPARE( np.get(QStringLiteral("protocolVersion"), -1) , NetworkPacket::s_protocolVersion ); QCOMPARE( np.type() , PACKET_TYPE_IDENTITY ); } +void NetworkPacketTests::networkPacketPayloadTest() +{ + QByteArray json; + NetworkPacket np; + + // empty package + np = NetworkPacket(QStringLiteral("com.test")); + json = np.serialize(); + qDebug() << json; + QVERIFY(!json.contains("\"payloadSize\"")); + QVERIFY(!json.contains("\"payloadTransferInfo\"")); + + // package with payload + QByteArray buffer("test data"); + auto payload = QSharedPointer(new QBuffer(&buffer, this)); + np = NetworkPacket(QStringLiteral("com.test")); + np.setPayload(payload, buffer.size()); + + json = np.serialize(); + qDebug() << json; + QVERIFY(json.contains("\"payloadSize\":9")); + QVERIFY(json.contains("\"payloadTransferInfo\"")); + + // package with empty payload + QByteArray emptyBuffer("test data"); + auto emptyPayload = QSharedPointer(new QBuffer(&emptyBuffer, this)); + np = NetworkPacket(QStringLiteral("com.test")); + np.setPayload(emptyPayload, 0); + + json = np.serialize(); + qDebug() << json; + QVERIFY(!json.contains("\"payloadSize\"")); + QVERIFY(!json.contains("\"payloadTransferInfo\"")); + + // incoming package without payload + np = NetworkPacket(); + QVERIFY(NetworkPacket::unserialize( + "{\"body\":{},\"id\":\"1578136807254\",\"type\":\"com.test\"}\n", &np)); + QVERIFY(!np.hasPayload()); + + // incoming package without payload (but with payload keys) + np = NetworkPacket(); + QVERIFY(NetworkPacket::unserialize( + "{\"body\":{},\"id\":\"1578136807254\",\"payloadSize\":0,\"payloadTransferInfo\":{},\"type\":\"com.test\"}\n", &np)); + QVERIFY(!np.hasPayload()); +} + void NetworkPacketTests::cleanupTestCase() { // Called after the last testfunction was executed } void NetworkPacketTests::init() { // Called before each testfunction is executed } void NetworkPacketTests::cleanup() { // Called after every testfunction } diff --git a/tests/networkpackettests.h b/tests/networkpackettests.h index 0d91d6dd..931161ce 100644 --- a/tests/networkpackettests.h +++ b/tests/networkpackettests.h @@ -1,44 +1,45 @@ /** * Copyright 2013 Albert Vaca * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef NETWORKPACKETTESTS_H #define NETWORKPACKETTESTS_H #include class NetworkPacketTests : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void networkPacketTest(); void networkPacketIdentityTest(); + void networkPacketPayloadTest(); //void networkPacketEncryptionTest(); void cleanupTestCase(); void init(); void cleanup(); }; #endif