KDNSSD

avahi-domainbrowser.cpp
1 /*
2  This file is part of the KDE project
3 
4  SPDX-FileCopyrightText: 2004 Jakub Stachowski <[email protected]>
5  SPDX-FileCopyrightText: 2018 Harald Sitter <[email protected]>
6 
7  SPDX-License-Identifier: LGPL-2.0-or-later
8 */
9 
10 #include "avahi-domainbrowser_p.h"
11 #include <QSet>
12 #include <QFile>
13 #include <QIODevice>
14 #include <QStandardPaths>
15 #include <avahi-common/defs.h>
16 #include "avahi_server_interface.h"
17 #include "domainbrowser.h"
18 #include "avahi_domainbrowser_interface.h"
19 
20 namespace KDNSSD
21 {
22 
23 DomainBrowser::DomainBrowser(DomainType type, QObject *parent) : QObject(parent), d(new DomainBrowserPrivate(type, this))
24 {}
25 
26 DomainBrowser::~DomainBrowser()
27 {
28  delete d;
29 }
30 
32 {
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.
52  .connect("org.freedesktop.Avahi",
53  "",
54  "org.freedesktop.Avahi.DomainBrowser",
55  "ItemNew",
56  d,
57  SLOT(gotGlobalItemNew(int,int,QString,uint,QDBusMessage)));
59  .connect("org.freedesktop.Avahi",
60  "",
61  "org.freedesktop.Avahi.DomainBrowser",
62  "ItemRemove",
63  d,
64  SLOT(gotGlobalItemRemove(int,int,QString,uint,QDBusMessage)));
66  .connect("org.freedesktop.Avahi",
67  "",
68  "org.freedesktop.Avahi.DomainBrowser",
69  "AllForNow",
70  d,
71  SLOT(gotGlobalAllForNow(QDBusMessage)));
72  d->m_dbusObjectPath.clear();
73 
74  org::freedesktop::Avahi::Server s(QStringLiteral("org.freedesktop.Avahi"), QStringLiteral("/"), QDBusConnection::systemBus());
75  QDBusReply<QDBusObjectPath> rep = s.DomainBrowserNew(-1, -1, QString(), (d->m_type == Browsing) ?
76  AVAHI_DOMAIN_BROWSER_BROWSE : AVAHI_DOMAIN_BROWSER_REGISTER, 0);
77  if (!rep.isValid()) {
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_browser = new org::freedesktop::Avahi::DomainBrowser(
85  s.service(),
86  d->m_dbusObjectPath,
87  s.connection());
88 
89  if (d->m_type == Browsing) {
90  QString domains_evar = QString::fromLocal8Bit(qgetenv("AVAHI_BROWSE_DOMAINS"));
91  if (!domains_evar.isEmpty()) {
92  const QStringList edomains = domains_evar.split(QLatin1Char(':'));
93  for (const QString &s : edomains) {
94  d->gotNewDomain(-1, -1, s, 0);
95  }
96  }
97  //FIXME: watch this file and restart browser if it changes
99  QFile domains_cfg(confDir + QStringLiteral("/avahi/browse-domains"));
100  if (domains_cfg.open(QIODevice::ReadOnly | QIODevice::Text))
101  while (!domains_cfg.atEnd()) {
102  d->gotNewDomain(-1, -1, QString::fromUtf8(domains_cfg.readLine().data()).trimmed(), 0);
103  }
104  }
105 }
106 
107 void DomainBrowserPrivate::gotGlobalItemNew(int interface,
108  int protocol,
109  const QString &domain,
110  uint flags,
111  QDBusMessage msg)
112 {
113  if (!isOurMsg(msg)) {
114  return;
115  }
116  gotNewDomain(interface, protocol, domain, flags);
117 }
118 
119 void DomainBrowserPrivate::gotGlobalItemRemove(int interface,
120  int protocol,
121  const QString &domain,
122  uint flags,
123  QDBusMessage msg)
124 {
125  if (!isOurMsg(msg)) {
126  return;
127  }
128  gotRemoveDomain(interface, protocol, domain, flags);
129 }
130 
131 void DomainBrowserPrivate::gotGlobalAllForNow(QDBusMessage msg)
132 {
133  if (!isOurMsg(msg)) {
134  return;
135  }
136 }
137 
138 void DomainBrowserPrivate::gotNewDomain(int, int, const QString &domain, uint)
139 {
140  QString decoded = DNSToDomain(domain);
141  if (m_domains.contains(decoded)) {
142  return;
143  }
144  m_domains += decoded;
145  emit m_parent->domainAdded(decoded);
146 }
147 
148 void DomainBrowserPrivate::gotRemoveDomain(int, int, const QString &domain, uint)
149 {
150  QString decoded = DNSToDomain(domain);
151  if (!m_domains.contains(decoded)) {
152  return;
153  }
154  emit m_parent->domainRemoved(decoded);
155  m_domains.remove(decoded);
156 }
157 
159 {
160  return d->m_domains.values();
161 }
162 
164 {
165  return d->m_started;
166 }
167 
168 }
169 #include "moc_domainbrowser.cpp"
170 #include "moc_avahi-domainbrowser_p.cpp"
bool isRunning() const
Whether the browsing has been started.
DomainType
A type of domain recommendation.
Definition: domainbrowser.h:49
QString writableLocation(QStandardPaths::StandardLocation type)
Domains recommended for browsing for services on (using ServiceBrowser)
Definition: domainbrowser.h:51
QDBusConnection systemBus()
bool isValid() const const
void startBrowse()
Starts browsing.
QString fromLocal8Bit(const char *str, int size)
QString fromUtf8(const char *str, int size)
QDBusReply::Type value() const const
bool isEmpty() const const
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
virtual bool open(QIODevice::OpenMode mode) override
virtual bool atEnd() const const override
DomainBrowser(DomainType type, QObject *parent=nullptr)
Standard constructor.
bool connect(const QString &service, const QString &path, const QString &interface, const QString &name, QObject *receiver, const char *slot)
QStringList domains() const
The current known list of domains of the requested DomainType.
qint64 readLine(char *data, qint64 maxSize)
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Thu Dec 3 2020 22:41:01 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.