Changeset View
Changeset View
Standalone View
Standalone View
src/avahi-servicetypebrowser.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,2007 Jakub Stachowski <qbast@go2.pl> | 3 | * Copyright (C) 2004,2007 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 ServiceTypeBrowser::startBrowse() | 43 | void ServiceTypeBrowser::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.ServiceTypeBrowser", | ||||
67 | "ItemNew", | ||||
68 | d, | ||||
69 | SLOT(gotGlobalItemNew(int,int,QString,QString,uint,QDBusMessage))); | ||||
70 | QDBusConnection::systemBus() | ||||
71 | .connect("org.freedesktop.Avahi", | ||||
72 | "", | ||||
73 | "org.freedesktop.Avahi.ServiceTypeBrowser", | ||||
74 | "ItemRemove", | ||||
75 | d, | ||||
76 | SLOT(gotGlobalItemRemove(int,int,QString,QString,uint,QDBusMessage))); | ||||
77 | QDBusConnection::systemBus() | ||||
78 | .connect("org.freedesktop.Avahi", | ||||
79 | "", | ||||
80 | "org.freedesktop.Avahi.ServiceTypeBrowser", | ||||
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.ServiceTypeBrowserNew(-1, -1, d->m_domain, 0); | | |||
50 | 87 | | |||
88 | QDBusReply<QDBusObjectPath> rep = s.ServiceTypeBrowserNew(-1, -1, d->m_domain, 0); | ||||
51 | if (!rep.isValid()) { | 89 | if (!rep.isValid()) { | ||
52 | return; | 90 | return; | ||
53 | } | 91 | } | ||
54 | org::freedesktop::Avahi::ServiceTypeBrowser *b = new org::freedesktop::Avahi::ServiceTypeBrowser(QStringLiteral("org.freedesktop.Avahi"), rep.value().path(), | 92 | | ||
55 | QDBusConnection::systemBus()); | 93 | d->m_dbusObjectPath = rep.value().path(); | ||
56 | connect(b, SIGNAL(ItemNew(int,int,QString,QString,uint)), d, SLOT(gotNewServiceType(int,int,QString,QString,uint))); | 94 | | ||
57 | connect(b, SIGNAL(ItemRemove(int,int,QString,QString,uint)), d, SLOT(gotRemoveServiceType(int,int,QString,QString,uint))); | 95 | // This is held because we need to explicitly Free it! | ||
58 | connect(b, SIGNAL(AllForNow()), d, SLOT(finished())); | 96 | d->m_browser = new org::freedesktop::Avahi::ServiceTypeBrowser( | ||
97 | s.service(), | ||||
98 | d->m_dbusObjectPath, | ||||
99 | s.connection()); | ||||
100 | | ||||
59 | connect(&d->m_timer, SIGNAL(timeout()), d, SLOT(finished())); | 101 | connect(&d->m_timer, SIGNAL(timeout()), d, SLOT(finished())); | ||
60 | d->m_browser = b; | | |||
61 | d->m_timer.start(domainIsLocal(d->m_domain) ? TIMEOUT_LAST_SERVICE : TIMEOUT_START_WAN); | 102 | d->m_timer.start(domainIsLocal(d->m_domain) ? TIMEOUT_LAST_SERVICE : TIMEOUT_START_WAN); | ||
62 | } | 103 | } | ||
63 | 104 | | |||
64 | void ServiceTypeBrowserPrivate::finished() | 105 | void ServiceTypeBrowserPrivate::finished() | ||
65 | { | 106 | { | ||
66 | m_timer.stop(); | 107 | m_timer.stop(); | ||
67 | emit m_parent->finished(); | 108 | emit m_parent->finished(); | ||
68 | } | 109 | } | ||
69 | 110 | | |||
111 | void ServiceTypeBrowserPrivate::gotGlobalItemNew(int interface, | ||||
112 | int protocol, | ||||
113 | const QString &type, | ||||
114 | const QString &domain, | ||||
115 | uint flags, | ||||
116 | QDBusMessage msg) | ||||
117 | { | ||||
118 | if (!isOurMsg(msg)) { | ||||
119 | return; | ||||
120 | } | ||||
121 | gotNewServiceType(interface, protocol, type, domain, flags); | ||||
122 | } | ||||
123 | | ||||
124 | void ServiceTypeBrowserPrivate::gotGlobalItemRemove(int interface, | ||||
125 | int protocol, | ||||
126 | const QString &type, | ||||
127 | const QString &domain, | ||||
128 | uint flags, | ||||
129 | QDBusMessage msg) | ||||
130 | { | ||||
131 | if (!isOurMsg(msg)) { | ||||
132 | return; | ||||
133 | } | ||||
134 | gotRemoveServiceType(interface, protocol, type, domain, flags); | ||||
135 | } | ||||
136 | | ||||
137 | void ServiceTypeBrowserPrivate::gotGlobalAllForNow(QDBusMessage msg) | ||||
138 | { | ||||
139 | if (!isOurMsg(msg)) { | ||||
140 | return; | ||||
141 | } | ||||
142 | finished(); | ||||
143 | } | ||||
144 | | ||||
70 | void ServiceTypeBrowserPrivate::gotNewServiceType(int, int, const QString &type, const QString &, uint) | 145 | void ServiceTypeBrowserPrivate::gotNewServiceType(int, int, const QString &type, const QString &, uint) | ||
71 | { | 146 | { | ||
72 | m_timer.start(TIMEOUT_LAST_SERVICE); | 147 | m_timer.start(TIMEOUT_LAST_SERVICE); | ||
73 | m_servicetypes += type; | 148 | m_servicetypes += type; | ||
74 | emit m_parent->serviceTypeAdded(type); | 149 | emit m_parent->serviceTypeAdded(type); | ||
75 | } | 150 | } | ||
76 | 151 | | |||
77 | void ServiceTypeBrowserPrivate::gotRemoveServiceType(int, int, const QString &type, const QString &, uint) | 152 | void ServiceTypeBrowserPrivate::gotRemoveServiceType(int, int, const QString &type, const QString &, uint) | ||
Show All 14 Lines |