Changeset View
Changeset View
Standalone View
Standalone View
src/avahi-domainbrowser.cpp
1 | /* This file is part of the KDE project | 1 | /* This file is part of the KDE project | ||
---|---|---|---|---|---|
2 | * | 2 | * | ||
3 | * Copyright (C) 2004 Jakub Stachowski <qbast@go2.pl> | 3 | * Copyright (C) 2004 Jakub Stachowski <qbast@go2.pl> | ||
4 | * Copyright (C) 2018 Harald Sitter <sitter@kde.org> | ||||
4 | * | 5 | * | ||
5 | * This library is free software; you can redistribute it and/or | 6 | * This library is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Library General Public | 7 | * modify it under the terms of the GNU Library General Public | ||
7 | * License as published by the Free Software Foundation; either | 8 | * License as published by the Free Software Foundation; either | ||
8 | * version 2 of the License, or (at your option) any later version. | 9 | * version 2 of the License, or (at your option) any later version. | ||
9 | * | 10 | * | ||
10 | * This library is distributed in the hope that it will be useful, | 11 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
Show All 28 Lines | |||||
40 | } | 41 | } | ||
41 | 42 | | |||
42 | void DomainBrowser::startBrowse() | 43 | void DomainBrowser::startBrowse() | ||
43 | { | 44 | { | ||
44 | if (d->m_started) { | 45 | if (d->m_started) { | ||
45 | return; | 46 | return; | ||
46 | } | 47 | } | ||
47 | d->m_started = true; | 48 | d->m_started = true; | ||
49 | | ||||
50 | // Do not race! | ||||
51 | // https://github.com/lathiat/avahi/issues/9 | ||||
52 | // Avahi's DBus API is incredibly racey with signals getting fired | ||||
53 | // immediately after a request was made even though we may not yet be | ||||
54 | // listening. In lieu of a proper upstream fix for this we'll unfortunately | ||||
55 | // have to resort to this hack: | ||||
56 | // We register to all signals regardless of path and then filter them once | ||||
57 | // we know what "our" path is. This is much more fragile than a proper | ||||
58 | // QDBusInterface assisted signal connection but unfortunately the only way | ||||
59 | // we can reliably prevent signals getting lost in the race. | ||||
60 | // This uses a fancy trick whereby using QDBusMessage as last argument will | ||||
61 | // give us the correct signal argument types as well as the underlying | ||||
62 | // message so that we may check the message path. | ||||
63 | QDBusConnection::systemBus() | ||||
64 | .connect("org.freedesktop.Avahi", | ||||
65 | "", | ||||
66 | "org.freedesktop.Avahi.DomainBrowser", | ||||
67 | "ItemNew", | ||||
68 | d, | ||||
69 | SLOT(gotGlobalItemNew(int,int,QString,uint,QDBusMessage))); | ||||
70 | QDBusConnection::systemBus() | ||||
71 | .connect("org.freedesktop.Avahi", | ||||
72 | "", | ||||
73 | "org.freedesktop.Avahi.DomainBrowser", | ||||
74 | "ItemRemove", | ||||
75 | d, | ||||
76 | SLOT(gotGlobalItemRemove(int,int,QString,uint,QDBusMessage))); | ||||
77 | QDBusConnection::systemBus() | ||||
78 | .connect("org.freedesktop.Avahi", | ||||
79 | "", | ||||
80 | "org.freedesktop.Avahi.DomainBrowser", | ||||
81 | "AllForNow", | ||||
82 | d, | ||||
83 | SLOT(gotGlobalAllForNow(QDBusMessage))); | ||||
84 | d->m_dbusObjectPath.clear(); | ||||
85 | | ||||
48 | org::freedesktop::Avahi::Server s(QStringLiteral("org.freedesktop.Avahi"), QStringLiteral("/"), QDBusConnection::systemBus()); | 86 | org::freedesktop::Avahi::Server s(QStringLiteral("org.freedesktop.Avahi"), QStringLiteral("/"), QDBusConnection::systemBus()); | ||
49 | QDBusReply<QDBusObjectPath> rep = s.DomainBrowserNew(-1, -1, QString(), (d->m_type == Browsing) ? | 87 | QDBusReply<QDBusObjectPath> rep = s.DomainBrowserNew(-1, -1, QString(), (d->m_type == Browsing) ? | ||
50 | AVAHI_DOMAIN_BROWSER_BROWSE : AVAHI_DOMAIN_BROWSER_REGISTER, 0); | 88 | AVAHI_DOMAIN_BROWSER_BROWSE : AVAHI_DOMAIN_BROWSER_REGISTER, 0); | ||
51 | | ||||
52 | if (!rep.isValid()) { | 89 | if (!rep.isValid()) { | ||
53 | return; | 90 | return; | ||
54 | } | 91 | } | ||
55 | org::freedesktop::Avahi::DomainBrowser *b = new org::freedesktop::Avahi::DomainBrowser(QStringLiteral("org.freedesktop.Avahi"), rep.value().path(), | 92 | | ||
56 | QDBusConnection::systemBus()); | 93 | d->m_dbusObjectPath = rep.value().path(); | ||
57 | connect(b, SIGNAL(ItemNew(int,int,QString,uint)), d, SLOT(gotNewDomain(int,int,QString,uint))); | 94 | | ||
58 | connect(b, SIGNAL(ItemRemove(int,int,QString,uint)), d, SLOT(gotRemoveDomain(int,int,QString,uint))); | 95 | // This is held because we need to explicitly Free it! | ||
59 | d->m_browser = b; | 96 | d->m_browser = new org::freedesktop::Avahi::DomainBrowser( | ||
97 | s.service(), | ||||
98 | d->m_dbusObjectPath, | ||||
99 | s.connection()); | ||||
100 | | ||||
60 | if (d->m_type == Browsing) { | 101 | if (d->m_type == Browsing) { | ||
61 | QString domains_evar = QString::fromLocal8Bit(qgetenv("AVAHI_BROWSE_DOMAINS")); | 102 | QString domains_evar = QString::fromLocal8Bit(qgetenv("AVAHI_BROWSE_DOMAINS")); | ||
62 | if (!domains_evar.isEmpty()) { | 103 | if (!domains_evar.isEmpty()) { | ||
63 | QStringList edomains = domains_evar.split(QLatin1Char(':')); | 104 | QStringList edomains = domains_evar.split(QLatin1Char(':')); | ||
64 | Q_FOREACH (const QString &s, edomains) { | 105 | Q_FOREACH (const QString &s, edomains) { | ||
65 | d->gotNewDomain(-1, -1, s, 0); | 106 | d->gotNewDomain(-1, -1, s, 0); | ||
66 | } | 107 | } | ||
67 | } | 108 | } | ||
68 | //FIXME: watch this file and restart browser if it changes | 109 | //FIXME: watch this file and restart browser if it changes | ||
69 | QString confDir = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); | 110 | QString confDir = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); | ||
70 | QFile domains_cfg(confDir + QStringLiteral("/avahi/browse-domains")); | 111 | QFile domains_cfg(confDir + QStringLiteral("/avahi/browse-domains")); | ||
71 | if (domains_cfg.open(QIODevice::ReadOnly | QIODevice::Text)) | 112 | if (domains_cfg.open(QIODevice::ReadOnly | QIODevice::Text)) | ||
72 | while (!domains_cfg.atEnd()) { | 113 | while (!domains_cfg.atEnd()) { | ||
73 | d->gotNewDomain(-1, -1, QString::fromUtf8(domains_cfg.readLine().data()).trimmed(), 0); | 114 | d->gotNewDomain(-1, -1, QString::fromUtf8(domains_cfg.readLine().data()).trimmed(), 0); | ||
74 | } | 115 | } | ||
116 | } | ||||
117 | } | ||||
75 | 118 | | |||
119 | void DomainBrowserPrivate::gotGlobalItemNew(int interface, | ||||
120 | int protocol, | ||||
121 | const QString &domain, | ||||
122 | uint flags, | ||||
123 | QDBusMessage msg) | ||||
124 | { | ||||
125 | if (!isOurMsg(msg)) { | ||||
126 | return; | ||||
127 | } | ||||
128 | gotNewDomain(interface, protocol, domain, flags); | ||||
76 | } | 129 | } | ||
77 | 130 | | |||
131 | void DomainBrowserPrivate::gotGlobalItemRemove(int interface, | ||||
132 | int protocol, | ||||
133 | const QString &domain, | ||||
134 | uint flags, | ||||
135 | QDBusMessage msg) | ||||
136 | { | ||||
137 | if (!isOurMsg(msg)) { | ||||
138 | return; | ||||
139 | } | ||||
140 | gotRemoveDomain(interface, protocol, domain, flags); | ||||
141 | } | ||||
142 | | ||||
143 | void DomainBrowserPrivate::gotGlobalAllForNow(QDBusMessage msg) | ||||
144 | { | ||||
145 | if (!isOurMsg(msg)) { | ||||
146 | return; | ||||
147 | } | ||||
78 | } | 148 | } | ||
79 | 149 | | |||
80 | void DomainBrowserPrivate::gotNewDomain(int, int, const QString &domain, uint) | 150 | void DomainBrowserPrivate::gotNewDomain(int, int, const QString &domain, uint) | ||
81 | { | 151 | { | ||
82 | QString decoded = DNSToDomain(domain); | 152 | QString decoded = DNSToDomain(domain); | ||
83 | if (m_domains.contains(decoded)) { | 153 | if (m_domains.contains(decoded)) { | ||
84 | return; | 154 | return; | ||
85 | } | 155 | } | ||
Show All 27 Lines |