File indexing completed on 2024-04-28 15:22:05
0001 /* 0002 This file is part of the KDE project 0003 0004 SPDX-FileCopyrightText: 2004, 2005 Jakub Stachowski <qbast@go2.pl> 0005 SPDX-FileCopyrightText: 2018 Harald Sitter <sitter@kde.org> 0006 0007 SPDX-License-Identifier: LGPL-2.0-or-later 0008 */ 0009 0010 #include "avahi-remoteservice_p.h" 0011 #include "avahi_server_interface.h" 0012 #include "avahi_serviceresolver_interface.h" 0013 #include "remoteservice.h" 0014 #include <QCoreApplication> 0015 #include <QDebug> 0016 #include <QEventLoop> 0017 #include <netinet/in.h> 0018 namespace KDNSSD 0019 { 0020 RemoteService::RemoteService(const QString &name, const QString &type, const QString &domain) 0021 : ServiceBase(new RemoteServicePrivate(this, name, type, domain)) 0022 { 0023 } 0024 0025 RemoteService::~RemoteService() 0026 { 0027 } 0028 0029 bool RemoteService::resolve() 0030 { 0031 KDNSSD_D; 0032 resolveAsync(); 0033 while (d->m_running && !d->m_resolved) { 0034 QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); 0035 } 0036 return d->m_resolved; 0037 } 0038 0039 void RemoteService::resolveAsync() 0040 { 0041 KDNSSD_D; 0042 if (d->m_running) { 0043 return; 0044 } 0045 d->m_resolved = false; 0046 registerTypes(); 0047 0048 // Do not race! 0049 // https://github.com/lathiat/avahi/issues/9 0050 // Avahi's DBus API is incredibly racey with signals getting fired 0051 // immediately after a request was made even though we may not yet be 0052 // listening. In lieu of a proper upstream fix for this we'll unfortunately 0053 // have to resort to this hack: 0054 // We register to all signals regardless of path and then filter them once 0055 // we know what "our" path is. This is much more fragile than a proper 0056 // QDBusInterface assisted signal connection but unfortunately the only way 0057 // we can reliably prevent signals getting lost in the race. 0058 // This uses a fancy trick whereby using QDBusMessage as last argument will 0059 // give us the correct signal argument types as well as the underlying 0060 // message so that we may check the message path. 0061 QDBusConnection::systemBus().connect( 0062 "org.freedesktop.Avahi", 0063 "", 0064 "org.freedesktop.Avahi.ServiceResolver", 0065 "Found", 0066 d, 0067 SLOT(gotGlobalFound(int, int, QString, QString, QString, QString, int, QString, ushort, QList<QByteArray>, uint, QDBusMessage))); 0068 QDBusConnection::systemBus() 0069 .connect("org.freedesktop.Avahi", "", "org.freedesktop.Avahi.ServiceResolver", "Failure", d, SLOT(gotGlobalError(QDBusMessage))); 0070 d->m_dbusObjectPath.clear(); 0071 0072 // qDebug() << this << ":Starting resolve of : " << d->m_serviceName << " " << d->m_type << " " << d->m_domain << "\n"; 0073 org::freedesktop::Avahi::Server s(QStringLiteral("org.freedesktop.Avahi"), QStringLiteral("/"), QDBusConnection::systemBus()); 0074 // FIXME: don't use LOOKUP_NO_ADDRESS if NSS unavailable 0075 QDBusReply<QDBusObjectPath> rep = s.ServiceResolverNew(-1, -1, d->m_serviceName, d->m_type, domainToDNS(d->m_domain), -1, 8 /*AVAHI_LOOKUP_NO_ADDRESS*/); 0076 if (!rep.isValid()) { 0077 Q_EMIT resolved(false); 0078 return; 0079 } 0080 0081 d->m_dbusObjectPath = rep.value().path(); 0082 0083 // This is held because we need to explicitly Free it! 0084 d->m_resolver = new org::freedesktop::Avahi::ServiceResolver(s.service(), d->m_dbusObjectPath, s.connection()); 0085 d->m_running = true; 0086 } 0087 0088 bool RemoteService::isResolved() const 0089 { 0090 KDNSSD_D; 0091 return d->m_resolved; 0092 } 0093 0094 void RemoteServicePrivate::gotError() 0095 { 0096 m_resolved = false; 0097 stop(); 0098 0099 Q_EMIT m_parent->resolved(false); 0100 } 0101 0102 void RemoteServicePrivate::gotGlobalFound(int interface, 0103 int protocol, 0104 const QString &name, 0105 const QString &type, 0106 const QString &domain, 0107 const QString &host, 0108 int aprotocol, 0109 const QString &address, 0110 ushort port, 0111 const QList<QByteArray> &txt, 0112 uint flags, 0113 QDBusMessage msg) 0114 { 0115 if (!isOurMsg(msg)) { 0116 return; 0117 } 0118 gotFound(interface, protocol, name, type, domain, host, aprotocol, address, port, txt, flags); 0119 } 0120 0121 void RemoteServicePrivate::gotGlobalError(QDBusMessage msg) 0122 { 0123 if (!isOurMsg(msg)) { 0124 return; 0125 } 0126 gotError(); 0127 } 0128 0129 void RemoteServicePrivate::gotFound(int, 0130 int, 0131 const QString &name, 0132 const QString &, 0133 const QString &domain, 0134 const QString &host, 0135 int, 0136 const QString &, 0137 ushort port, 0138 const QList<QByteArray> &txt, 0139 uint) 0140 { 0141 m_serviceName = name; 0142 m_hostName = host; 0143 m_port = port; 0144 m_domain = DNSToDomain(domain); 0145 for (const QByteArray &x : txt) { 0146 int pos = x.indexOf("="); 0147 if (pos == -1) { 0148 m_textData[x] = QByteArray(); 0149 } else { 0150 m_textData[x.mid(0, pos)] = x.mid(pos + 1, x.size() - pos); 0151 } 0152 } 0153 m_resolved = true; 0154 Q_EMIT m_parent->resolved(true); 0155 } 0156 0157 void RemoteServicePrivate::stop() 0158 { 0159 if (m_resolver) { 0160 m_resolver->Free(); 0161 } 0162 delete m_resolver; 0163 m_resolver = nullptr; 0164 m_running = false; 0165 } 0166 0167 void RemoteService::virtual_hook(int, void *) 0168 { 0169 // BASE::virtual_hook(int, void*); 0170 } 0171 0172 } 0173 0174 #include "moc_avahi-remoteservice_p.cpp" 0175 #include "moc_remoteservice.cpp"