KDNSSD

avahi-domainbrowser.cpp
1/*
2 This file is part of the KDE project
3
4 SPDX-FileCopyrightText: 2004 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-domainbrowser_p.h"
11#include "avahi_domainbrowser_interface.h"
12#include "avahi_server_interface.h"
13#include "domainbrowser.h"
14#include <QFile>
15#include <QIODevice>
16#include <QSet>
17#include <QStandardPaths>
18#include <avahi-common/defs.h>
19
20namespace KDNSSD
21{
23 : QObject(parent)
24 , d(new DomainBrowserPrivate(type, this))
25{
26}
27
28DomainBrowser::~DomainBrowser() = default;
29
31{
33 if (d->m_started) {
34 return;
35 }
36 d->m_started = true;
37
38 // Do not race!
39 // https://github.com/lathiat/avahi/issues/9
40 // Avahi's DBus API is incredibly racey with signals getting fired
41 // immediately after a request was made even though we may not yet be
42 // listening. In lieu of a proper upstream fix for this we'll unfortunately
43 // have to resort to this hack:
44 // We register to all signals regardless of path and then filter them once
45 // we know what "our" path is. This is much more fragile than a proper
46 // QDBusInterface assisted signal connection but unfortunately the only way
47 // we can reliably prevent signals getting lost in the race.
48 // This uses a fancy trick whereby using QDBusMessage as last argument will
49 // give us the correct signal argument types as well as the underlying
50 // message so that we may check the message path.
51 QDBusConnection::systemBus().connect("org.freedesktop.Avahi",
52 "",
53 "org.freedesktop.Avahi.DomainBrowser",
54 "ItemNew",
55 d,
56 SLOT(gotGlobalItemNew(int, int, QString, uint, QDBusMessage)));
57 QDBusConnection::systemBus().connect("org.freedesktop.Avahi",
58 "",
59 "org.freedesktop.Avahi.DomainBrowser",
60 "ItemRemove",
61 d,
62 SLOT(gotGlobalItemRemove(int, int, QString, uint, QDBusMessage)));
64 .connect("org.freedesktop.Avahi", "", "org.freedesktop.Avahi.DomainBrowser", "AllForNow", d, SLOT(gotGlobalAllForNow(QDBusMessage)));
65 d->m_dbusObjectPath.clear();
66
67 org::freedesktop::Avahi::Server s(QStringLiteral("org.freedesktop.Avahi"), QStringLiteral("/"), QDBusConnection::systemBus());
69 s.DomainBrowserNew(-1, -1, QString(), (d->m_type == Browsing) ? AVAHI_DOMAIN_BROWSER_BROWSE : AVAHI_DOMAIN_BROWSER_REGISTER, 0);
70 if (!rep.isValid()) {
71 return;
72 }
73
74 d->m_dbusObjectPath = rep.value().path();
75
76 // This is held because we need to explicitly Free it!
77 d->m_browser = new org::freedesktop::Avahi::DomainBrowser(s.service(), d->m_dbusObjectPath, s.connection());
78
79 if (d->m_type == Browsing) {
80 QString domains_evar = QString::fromLocal8Bit(qgetenv("AVAHI_BROWSE_DOMAINS"));
81 if (!domains_evar.isEmpty()) {
82 const QStringList edomains = domains_evar.split(QLatin1Char(':'));
83 for (const QString &s : edomains) {
84 d->gotNewDomain(-1, -1, s, 0);
85 }
86 }
87 // FIXME: watch this file and restart browser if it changes
89 QFile domains_cfg(confDir + QStringLiteral("/avahi/browse-domains"));
90 if (domains_cfg.open(QIODevice::ReadOnly | QIODevice::Text))
91 while (!domains_cfg.atEnd()) {
92 d->gotNewDomain(-1, -1, QString::fromUtf8(domains_cfg.readLine().data()).trimmed(), 0);
93 }
94 }
95}
96
97void DomainBrowserPrivate::gotGlobalItemNew(int interface, int protocol, const QString &domain, uint flags, QDBusMessage msg)
98{
99 if (!isOurMsg(msg)) {
100 return;
101 }
102 gotNewDomain(interface, protocol, domain, flags);
103}
104
105void DomainBrowserPrivate::gotGlobalItemRemove(int interface, int protocol, const QString &domain, uint flags, QDBusMessage msg)
106{
107 if (!isOurMsg(msg)) {
108 return;
109 }
110 gotRemoveDomain(interface, protocol, domain, flags);
111}
112
113void DomainBrowserPrivate::gotGlobalAllForNow(QDBusMessage msg)
114{
115 if (!isOurMsg(msg)) {
116 return;
117 }
118}
119
120void DomainBrowserPrivate::gotNewDomain(int, int, const QString &domain, uint)
121{
122 QString decoded = DNSToDomain(domain);
123 if (m_domains.contains(decoded)) {
124 return;
125 }
126 m_domains += decoded;
127 Q_EMIT m_parent->domainAdded(decoded);
128}
129
130void DomainBrowserPrivate::gotRemoveDomain(int, int, const QString &domain, uint)
131{
132 QString decoded = DNSToDomain(domain);
133 if (!m_domains.contains(decoded)) {
134 return;
135 }
136 Q_EMIT m_parent->domainRemoved(decoded);
137 m_domains.remove(decoded);
138}
139
141{
142 Q_D(const DomainBrowser);
143 return d->m_domains.values();
144}
145
147{
148 Q_D(const DomainBrowser);
149 return d->m_started;
150}
151
152}
153#include "moc_avahi-domainbrowser_p.cpp"
154#include "moc_domainbrowser.cpp"
Browses recommended domains for browsing or publishing to.
DomainBrowser(DomainType type, QObject *parent=nullptr)
Standard constructor.
void startBrowse()
Starts browsing.
bool isRunning() const
Whether the browsing has been started.
QStringList domains() const
The current known list of domains of the requested DomainType.
DomainType
A type of domain recommendation.
@ Browsing
Domains recommended for browsing for services on (using ServiceBrowser)
char * data()
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
bool open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags)
virtual bool atEnd() const const override
QByteArray readLine(qint64 maxSize)
QString writableLocation(StandardLocation type)
QString fromLocal8Bit(QByteArrayView str)
QString fromUtf8(QByteArrayView str)
bool isEmpty() const const
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QString trimmed() const const
Q_D(Todo)
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.