KDNSSD

mdnsd-servicebrowser.cpp
1/*
2 This file is part of the KDE project
3
4 SPDX-FileCopyrightText: 2004 Jakub Stachowski <qbast@go2.pl>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7*/
8
9#include "domainbrowser.h"
10#include "mdnsd-responder.h"
11#include "mdnsd-sdevent.h"
12#include "mdnsd-servicebrowser_p.h"
13#include "remoteservice.h"
14#include "servicebrowser.h"
15#include <QCoreApplication>
16#include <QHash>
17#include <QHostInfo>
18#include <QStringList>
19#include <QTimer>
20#include <dns_sd.h>
21
22#define TIMEOUT_WAN 2000
23#define TIMEOUT_LAN 200
24
25namespace KDNSSD
26{
27void query_callback(DNSServiceRef,
28 DNSServiceFlags flags,
29 uint32_t,
30 DNSServiceErrorType errorCode,
31 const char *serviceName,
32 const char *regtype,
33 const char *replyDomain,
34 void *context);
35
36ServiceBrowser::ServiceBrowser(const QString &type, bool autoResolve, const QString &domain, const QString &subtype)
37 : d(new ServiceBrowserPrivate(this))
38{
39 Q_D(ServiceBrowser);
40 d->m_type = type;
41 d->m_autoResolve = autoResolve;
42 d->m_domain = domain;
43 d->m_subtype = subtype;
44 d->timeout.setSingleShot(true);
45 connect(&d->timeout, SIGNAL(timeout()), d, SLOT(onTimeout()));
46}
47
48ServiceBrowser::State ServiceBrowser::isAvailable()
49{
50 // DNSServiceRef ref;
51 // bool ok (DNSServiceCreateConnection(&ref)==kDNSServiceErr_NoError);
52 // if (ok) DNSServiceRefDeallocate(ref);
53 // return (ok) ? Working : Stopped;
54 return Working;
55}
56
57ServiceBrowser::~ServiceBrowser() = default;
58
59bool ServiceBrowser::isAutoResolving() const
60{
61 Q_D(const ServiceBrowser);
62 return d->m_autoResolve;
63}
64
65void ServiceBrowserPrivate::serviceResolved(bool success)
66{
67 QObject *sender_obj = const_cast<QObject *>(sender());
68 RemoteService *svr = static_cast<RemoteService *>(sender_obj);
69 disconnect(svr, SIGNAL(resolved(bool)), this, SLOT(serviceResolved(bool)));
70 QList<RemoteService::Ptr>::Iterator it = m_duringResolve.begin();
71 QList<RemoteService::Ptr>::Iterator itEnd = m_duringResolve.end();
72 while (it != itEnd && svr != (*it).data()) {
73 ++it;
74 }
75 if (it != itEnd) {
76 if (success) {
77 m_services += (*it);
78 Q_EMIT m_parent->serviceAdded(RemoteService::Ptr(svr));
79 }
80 m_duringResolve.erase(it);
81 queryFinished();
82 }
83}
84
85void ServiceBrowser::startBrowse()
86{
87 Q_D(ServiceBrowser);
88 if (d->isRunning()) {
89 return;
90 }
91 d->m_finished = false;
92 DNSServiceRef ref;
93 QString fullType = d->m_type;
94 if (!d->m_subtype.isEmpty()) {
95 fullType = d->m_subtype + "._sub." + d->m_type;
96 }
97 if (DNSServiceBrowse(&ref, 0, 0, fullType.toLatin1().constData(), domainToDNS(d->m_domain).constData(), query_callback, reinterpret_cast<void *>(d))
98 == kDNSServiceErr_NoError) {
99 d->setRef(ref);
100 }
101 if (!d->isRunning()) {
102 Q_EMIT finished();
103 } else {
104 d->timeout.start(domainIsLocal(d->m_domain) ? TIMEOUT_LAN : TIMEOUT_WAN);
105 }
106}
107
108void ServiceBrowserPrivate::queryFinished()
109{
110 if (!m_duringResolve.count() && m_finished) {
111 Q_EMIT m_parent->finished();
112 }
113}
114
115QList<RemoteService::Ptr> ServiceBrowser::services() const
116{
117 Q_D(const ServiceBrowser);
118 return d->m_services;
119}
120
121void ServiceBrowser::virtual_hook(int, void *)
122{
123}
124
125RemoteService::Ptr ServiceBrowserPrivate::find(RemoteService::Ptr s, const QList<RemoteService::Ptr> &where) const
126{
127 for (const RemoteService::Ptr &i : where)
128 if (*s == *i) {
129 return i;
130 }
131 return RemoteService::Ptr();
132}
133
134void ServiceBrowserPrivate::customEvent(QEvent *event)
135{
136 if (event->type() == QEvent::User + SD_ERROR) {
137 stop();
138 m_finished = false;
139 queryFinished();
140 }
141 if (event->type() == QEvent::User + SD_ADDREMOVE) {
142 AddRemoveEvent *aev = static_cast<AddRemoveEvent *>(event);
143 // m_type has useless trailing dot
144 RemoteService::Ptr svr(new RemoteService(aev->m_name, aev->m_type.left(aev->m_type.length() - 1), aev->m_domain));
145 if (aev->m_op == AddRemoveEvent::Add) {
146 if (m_autoResolve) {
147 connect(svr.data(), SIGNAL(resolved(bool)), this, SLOT(serviceResolved(bool)));
148 m_duringResolve += svr;
149 svr->resolveAsync();
150 } else {
151 m_services += svr;
152 Q_EMIT m_parent->serviceAdded(svr);
153 }
154 } else {
155 RemoteService::Ptr found = find(svr, m_duringResolve);
156 if (found) {
157 m_duringResolve.removeAll(found);
158 } else {
159 found = find(svr, m_services);
160 if (found) {
161 Q_EMIT m_parent->serviceRemoved(found);
162 m_services.removeAll(found);
163 }
164 }
165 }
166 m_finished = aev->m_last;
167 if (m_finished) {
168 queryFinished();
169 }
170 }
171}
172
173void ServiceBrowserPrivate::onTimeout()
174{
175 m_finished = true;
176 queryFinished();
177}
178
179void query_callback(DNSServiceRef,
180 DNSServiceFlags flags,
181 uint32_t,
182 DNSServiceErrorType errorCode,
183 const char *serviceName,
184 const char *regtype,
185 const char *replyDomain,
186 void *context)
187{
188 QObject *obj = reinterpret_cast<QObject *>(context);
189 if (errorCode != kDNSServiceErr_NoError) {
190 ErrorEvent err;
192 } else {
193 AddRemoveEvent arev((flags & kDNSServiceFlagsAdd) ? AddRemoveEvent::Add : AddRemoveEvent::Remove,
194 QString::fromUtf8(serviceName),
195 regtype,
196 DNSToDomain(replyDomain),
197 !(flags & kDNSServiceFlagsMoreComing));
198 QCoreApplication::sendEvent(obj, &arev);
199 }
200}
201
202// TODO: Please Implement Me - Using a KResolver (if not natively)
203QHostAddress ServiceBrowser::resolveHostName(const QString &hostname)
204{
205 return QHostAddress();
206}
207
208QString ServiceBrowser::getLocalHostName()
209{
211}
212
213}
214
215#include "moc_mdnsd-servicebrowser_p.cpp"
216#include "moc_servicebrowser.cpp"
ServiceBrowser(const QString &type, bool autoResolve=false, const QString &domain=QString(), const QString &subtype=QString())
Create a ServiceBrowser for a particular service type.
void stop(Ekos::AlignState mode)
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
Type type(const QSqlDatabase &db)
const QList< QKeySequence > & find()
const char * constData() const const
bool sendEvent(QObject *receiver, QEvent *event)
QString localHostName()
iterator begin()
iterator end()
iterator erase(const_iterator begin, const_iterator end)
const QChar * constData() const const
QByteArray toLatin1() const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
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.