KDNSSD

avahi-remoteservice.cpp
1/*
2 This file is part of the KDE project
3
4 SPDX-FileCopyrightText: 2004, 2005 Jakub Stachowski <qbast@go2.pl>
5 SPDX-FileCopyrightText: 2018 Harald Sitter <sitter@kde.org>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8*/
9
10#include "avahi-remoteservice_p.h"
11#include "avahi_server_interface.h"
12#include "avahi_serviceresolver_interface.h"
13#include "remoteservice.h"
14#include <QCoreApplication>
15#include <QDebug>
16#include <QEventLoop>
17#include <netinet/in.h>
18namespace KDNSSD
19{
20RemoteService::RemoteService(const QString &name, const QString &type, const QString &domain)
21 : ServiceBase(new RemoteServicePrivate(this, name, type, domain))
22{
23}
24
25RemoteService::~RemoteService()
26{
27}
28
30{
31 KDNSSD_D;
33 while (d->m_running && !d->m_resolved) {
35 }
36 return d->m_resolved;
37}
38
40{
41 KDNSSD_D;
42 if (d->m_running) {
43 return;
44 }
45 d->m_resolved = false;
46 registerTypes();
47
48 // Do not race!
49 // https://github.com/lathiat/avahi/issues/9
50 // Avahi's DBus API is incredibly racey with signals getting fired
51 // immediately after a request was made even though we may not yet be
52 // listening. In lieu of a proper upstream fix for this we'll unfortunately
53 // have to resort to this hack:
54 // We register to all signals regardless of path and then filter them once
55 // we know what "our" path is. This is much more fragile than a proper
56 // QDBusInterface assisted signal connection but unfortunately the only way
57 // we can reliably prevent signals getting lost in the race.
58 // This uses a fancy trick whereby using QDBusMessage as last argument will
59 // give us the correct signal argument types as well as the underlying
60 // message so that we may check the message path.
62 "org.freedesktop.Avahi",
63 "",
64 "org.freedesktop.Avahi.ServiceResolver",
65 "Found",
66 d,
67 SLOT(gotGlobalFound(int, int, QString, QString, QString, QString, int, QString, ushort, QList<QByteArray>, uint, QDBusMessage)));
69 .connect("org.freedesktop.Avahi", "", "org.freedesktop.Avahi.ServiceResolver", "Failure", d, SLOT(gotGlobalError(QDBusMessage)));
70 d->m_dbusObjectPath.clear();
71
72 // qDebug() << this << ":Starting resolve of : " << d->m_serviceName << " " << d->m_type << " " << d->m_domain << "\n";
73 org::freedesktop::Avahi::Server s(QStringLiteral("org.freedesktop.Avahi"), QStringLiteral("/"), QDBusConnection::systemBus());
74 // FIXME: don't use LOOKUP_NO_ADDRESS if NSS unavailable
75 QDBusReply<QDBusObjectPath> rep = s.ServiceResolverNew(-1, -1, d->m_serviceName, d->m_type, domainToDNS(d->m_domain), -1, 8 /*AVAHI_LOOKUP_NO_ADDRESS*/);
76 if (!rep.isValid()) {
77 Q_EMIT resolved(false);
78 return;
79 }
80
81 d->m_dbusObjectPath = rep.value().path();
82
83 // This is held because we need to explicitly Free it!
84 d->m_resolver = new org::freedesktop::Avahi::ServiceResolver(s.service(), d->m_dbusObjectPath, s.connection());
85 d->m_running = true;
86}
87
89{
90 KDNSSD_D;
91 return d->m_resolved;
92}
93
94void RemoteServicePrivate::gotError()
95{
96 m_resolved = false;
97 stop();
98
99 Q_EMIT m_parent->resolved(false);
100}
101
102void RemoteServicePrivate::gotGlobalFound(int interface,
103 int protocol,
104 const QString &name,
105 const QString &type,
106 const QString &domain,
107 const QString &host,
108 int aprotocol,
109 const QString &address,
110 ushort port,
111 const QList<QByteArray> &txt,
112 uint flags,
113 QDBusMessage msg)
114{
115 if (!isOurMsg(msg)) {
116 return;
117 }
118 gotFound(interface, protocol, name, type, domain, host, aprotocol, address, port, txt, flags);
119}
120
121void RemoteServicePrivate::gotGlobalError(QDBusMessage msg)
122{
123 if (!isOurMsg(msg)) {
124 return;
125 }
126 gotError();
127}
128
129void RemoteServicePrivate::gotFound(int,
130 int,
131 const QString &name,
132 const QString &,
133 const QString &domain,
134 const QString &host,
135 int,
136 const QString &,
137 ushort port,
138 const QList<QByteArray> &txt,
139 uint)
140{
141 m_serviceName = name;
142 m_hostName = host;
143 m_port = port;
144 m_domain = DNSToDomain(domain);
145 for (const QByteArray &x : txt) {
146 int pos = x.indexOf("=");
147 if (pos == -1) {
148 m_textData[x] = QByteArray();
149 } else {
150 m_textData[x.mid(0, pos)] = x.mid(pos + 1, x.size() - pos);
151 }
152 }
153 m_resolved = true;
154 Q_EMIT m_parent->resolved(true);
155}
156
157void RemoteServicePrivate::stop()
158{
159 if (m_resolver) {
160 m_resolver->Free();
161 }
162 delete m_resolver;
163 m_resolver = nullptr;
164 m_running = false;
165}
166
167void RemoteService::virtual_hook(int, void *)
168{
169 // BASE::virtual_hook(int, void*);
170}
171
172}
173
174#include "moc_avahi-remoteservice_p.cpp"
175#include "moc_remoteservice.cpp"
RemoteService(const QString &name, const QString &type, const QString &domain)
Creates an unresolved RemoteService representing the service with the given name, type and domain.
void resolveAsync()
Resolves the host name and port of service asynchronously.
bool isResolved() const
Whether the service has been successfully resolved.
void resolved(bool successful)
Emitted when resolving is complete.
bool resolve()
Resolves the host name and port of service synchronously.
Describes a service.
Definition servicebase.h:41
QString name(StandardShortcut id)
void processEvents(QEventLoop::ProcessEventsFlags flags)
QDBusConnection connection() const const
QString service() const const
bool connect(const QString &service, const QString &path, const QString &interface, const QString &name, QObject *receiver, const char *slot)
QDBusConnection systemBus()
bool isValid() const const
Q_EMITQ_EMIT
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:17:48 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.