Add MDNS e2e test
This commit is contained in:
parent
4c13af95c3
commit
fd25318a20
5 changed files with 87 additions and 22 deletions
|
@ -98,12 +98,12 @@ static int query_callback(int sock, const struct sockaddr* from, size_t addrlen,
|
|||
|
||||
switch (record_type) {
|
||||
case MDNS_RECORDTYPE_PTR: {
|
||||
// We don't use mdns_record_parse_ptr() because we want to extract just the service name instead of the full "<service-name>.<_service-type>._tcp.local." string
|
||||
mdns_string_pair_t serviceNamePos = mdns_get_next_substring(data, size, record_offset);
|
||||
discoveredService->name = QString::fromLatin1((char *)data + serviceNamePos.offset, serviceNamePos.length);
|
||||
//static char serviceNameBuffer[256];
|
||||
//mdns_string_t serviceName = mdns_record_parse_ptr(data, size, record_offset, record_length, serviceNameBuffer, sizeof(serviceNameBuffer));
|
||||
//discoveredService->name = QString::fromLatin1(serviceName.str, serviceName.length);
|
||||
// We don't use mdns_record_parse_ptr() because we want to extract just the service name instead of the full "<instance-name>._<service-type>._tcp.local." string
|
||||
mdns_string_pair_t instanceNamePos = mdns_get_next_substring(data, size, record_offset);
|
||||
discoveredService->name = QString::fromLatin1((char *)data + instanceNamePos.offset, instanceNamePos.length);
|
||||
//static char instanceNameBuffer[256];
|
||||
//mdns_string_t instanceName = mdns_record_parse_ptr(data, size, record_offset, record_length, instanceNameBuffer, sizeof(instanceNameBuffer));
|
||||
//discoveredService->name = QString::fromLatin1(instanceName.str, instanceName.length);
|
||||
if (discoveredService->address == QHostAddress::Null) {
|
||||
discoveredService->address = QHostAddress(from); // In case we don't receive a A record, use from as address
|
||||
}
|
||||
|
@ -309,11 +309,11 @@ static mdns_record_t createMdnsRecord(const Announcer::AnnouncedInfo &self,
|
|||
answer.rclass = 0;
|
||||
answer.ttl = 0;
|
||||
switch (record_type) {
|
||||
case MDNS_RECORDTYPE_PTR: // maps "<_service-type>._tcp.local." to "<service-name>.<_service-type>._tcp.local."
|
||||
case MDNS_RECORDTYPE_PTR: // maps "_<service-type>._tcp.local." to "<instance-name>._<service-type>._tcp.local."
|
||||
answer.name = createMdnsString(self.serviceType);
|
||||
answer.data.ptr.name = createMdnsString(self.serviceInstance);
|
||||
break;
|
||||
case MDNS_RECORDTYPE_SRV: // maps "<service-name>.<_service-type>._tcp.local." to "<hostname>.local." and port
|
||||
case MDNS_RECORDTYPE_SRV: // maps "<instance-name>._<service-type>._tcp.local." to "<hostname>.local." and port
|
||||
answer.name = createMdnsString(self.serviceInstance);
|
||||
answer.data.srv.name = createMdnsString(self.hostname);
|
||||
answer.data.srv.port = self.port;
|
||||
|
@ -544,14 +544,14 @@ int Announcer::listenForQueries()
|
|||
return numSockets;
|
||||
}
|
||||
|
||||
Announcer::Announcer(const QString &serviceName, const QString &serviceType, uint16_t port)
|
||||
Announcer::Announcer(const QString &instanceName, const QString &serviceType, uint16_t port)
|
||||
{
|
||||
self.serviceType = serviceType.toLatin1();
|
||||
if (!self.serviceType.endsWith('.')) {
|
||||
// mdns.h needs all the qualified names to end with dot for some reason
|
||||
self.serviceType.append('.');
|
||||
}
|
||||
self.serviceInstance = serviceName.toLatin1() + '.' + self.serviceType;
|
||||
self.serviceInstance = instanceName.toLatin1() + '.' + self.serviceType;
|
||||
self.hostname = QHostInfo::localHostName().toLatin1() + ".local.";
|
||||
self.port = port;
|
||||
detectHostAddresses();
|
||||
|
|
|
@ -13,30 +13,32 @@
|
|||
#include <QString>
|
||||
#include <QVector>
|
||||
|
||||
/*
|
||||
#include "kdeconnectcore_export.h"
|
||||
|
||||
/**
|
||||
* A Qt wrapper for the mdns.h header-only library
|
||||
* from https://github.com/mjansson/mdns
|
||||
*/
|
||||
namespace MdnsWrapper
|
||||
{
|
||||
|
||||
class Discoverer : public QObject
|
||||
class KDECONNECTCORE_EXPORT Discoverer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
struct MdnsService {
|
||||
QString name;
|
||||
QString name; // The instance-name part in "<instance-name>._<service-type>._tcp.local."
|
||||
uint16_t port;
|
||||
QHostAddress address;
|
||||
QHostAddress address; // An IPv4 address (IPv6 addresses are ignored)
|
||||
QMap<QString, QString> txtRecords;
|
||||
};
|
||||
|
||||
// serviceType must be of the form "_<name>._<tcp/udp>.local"
|
||||
// serviceType must be of the form "_<service-type>._<tcp/udp>.local"
|
||||
void startDiscovering(const QString &serviceType);
|
||||
void stopDiscovering();
|
||||
|
||||
void sendQuery(const QString &serviceName);
|
||||
void sendQuery(const QString &serviceType);
|
||||
|
||||
Q_SIGNALS:
|
||||
void serviceFound(const MdnsWrapper::Discoverer::MdnsService &service);
|
||||
|
@ -48,14 +50,14 @@ private:
|
|||
QVector<QSocketNotifier *> responseSocketNotifiers;
|
||||
};
|
||||
|
||||
class Announcer : public QObject
|
||||
class KDECONNECTCORE_EXPORT Announcer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
struct AnnouncedInfo {
|
||||
QByteArray serviceType; // ie: "<_service-type>._tcp.local."
|
||||
QByteArray serviceInstance; // ie: "<service-name>.<_service-type>._tcp.local."
|
||||
QByteArray serviceType; // ie: "_<service-type>._tcp.local."
|
||||
QByteArray serviceInstance; // ie: "<instance-name>._<service-type>._tcp.local."
|
||||
QByteArray hostname; // ie: "<hostname>.local."
|
||||
QVector<QHostAddress> addressesV4;
|
||||
QVector<QHostAddress> addressesV6;
|
||||
|
@ -63,8 +65,8 @@ public:
|
|||
QHash<QByteArray, QByteArray> txtRecords;
|
||||
};
|
||||
|
||||
// serviceType must be of the form "_<name>._<tcp/udp>.local"
|
||||
Announcer(const QString &serviceName, const QString &serviceType, uint16_t port);
|
||||
// serviceType must be of the form "_<service-type>._<tcp/udp>.local"
|
||||
Announcer(const QString &instanceName, const QString &serviceType, uint16_t port);
|
||||
|
||||
void putTxtRecord(const QString &key, const QString &value)
|
||||
{
|
||||
|
|
|
@ -23,7 +23,7 @@ MdnsDiscovery::MdnsDiscovery(LanLinkProvider *lanLinkProvider)
|
|||
mdnsAnnouncer.putTxtRecord(QStringLiteral("type"), config.deviceType().toString());
|
||||
mdnsAnnouncer.putTxtRecord(QStringLiteral("protocol"), QString::number(NetworkPacket::s_protocolVersion));
|
||||
|
||||
connect(&mdnsDiscoverer, &MdnsWrapper::Discoverer::serviceFound, [lanLinkProvider](const MdnsWrapper::Discoverer::MdnsService &service) {
|
||||
connect(&mdnsDiscoverer, &MdnsWrapper::Discoverer::serviceFound, this, [lanLinkProvider](const MdnsWrapper::Discoverer::MdnsService &service) {
|
||||
if (KdeConnectConfig::instance().deviceId() == service.name) {
|
||||
qCDebug(KDECONNECT_CORE) << "Discovered myself, ignoring";
|
||||
return;
|
||||
|
|
|
@ -12,3 +12,4 @@ set(kdeconnect_libraries
|
|||
|
||||
ecm_add_test(pluginloadtest.cpp LINK_LIBRARIES ${kdeconnect_libraries})
|
||||
ecm_add_test(sendfiletest.cpp LINK_LIBRARIES ${kdeconnect_libraries})
|
||||
ecm_add_test(mdnstest.cpp LINK_LIBRARIES ${kdeconnect_libraries})
|
||||
|
|
62
tests/mdnstest.cpp
Normal file
62
tests/mdnstest.cpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2023 Albert Vaca Cintora <albertvaka@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
*/
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QObject>
|
||||
#include <QSignalSpy>
|
||||
#include <QSocketNotifier>
|
||||
#include <QStandardPaths>
|
||||
#include <QTest>
|
||||
|
||||
#include "core/backends/lan/mdns_wrapper.h"
|
||||
#include "kdeconnect-version.h"
|
||||
|
||||
class TestMdns : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
TestMdns()
|
||||
{
|
||||
}
|
||||
|
||||
private Q_SLOTS:
|
||||
void testAnounceAndDiscover()
|
||||
{
|
||||
QString instanceName = QStringLiteral("myinstance");
|
||||
uint16_t instancePort = 1716;
|
||||
QString serviceType = QStringLiteral("_test._udp.local");
|
||||
QString txtKey = QStringLiteral("keyerino");
|
||||
QString txtValue = QStringLiteral("valuerino");
|
||||
|
||||
MdnsWrapper::Announcer announcer(instanceName, serviceType, instancePort);
|
||||
announcer.putTxtRecord(txtKey, txtValue);
|
||||
|
||||
MdnsWrapper::Discoverer discoverer;
|
||||
|
||||
QSignalSpy spy(&discoverer, &MdnsWrapper::Discoverer::serviceFound);
|
||||
|
||||
connect(&discoverer, &MdnsWrapper::Discoverer::serviceFound, this, [instanceName, instancePort, txtKey, txtValue](const MdnsWrapper::Discoverer::MdnsService &service) {
|
||||
QCOMPARE(instanceName, service.name);
|
||||
QCOMPARE(instancePort, service.port);
|
||||
QVERIFY(service.txtRecords.size() == 1);
|
||||
QVERIFY(service.txtRecords.contains(txtKey));
|
||||
QCOMPARE(txtValue, service.txtRecords.value(txtKey));
|
||||
});
|
||||
|
||||
announcer.startAnnouncing();
|
||||
discoverer.startDiscovering(serviceType);
|
||||
|
||||
QVERIFY(spy.wait(2000));
|
||||
QVERIFY(spy.count() > 0);
|
||||
|
||||
discoverer.stopDiscovering();
|
||||
announcer.stopAnnouncing();
|
||||
}
|
||||
};
|
||||
|
||||
QTEST_MAIN(TestMdns);
|
||||
|
||||
#include "mdnstest.moc"
|
Loading…
Reference in a new issue