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#ifndef KDNSSDSERVICEBROWSER_H
10#define KDNSSDSERVICEBROWSER_H
11
12#include "remoteservice.h"
13#include <QHostAddress>
14#include <QObject>
15
16#include <memory>
17
18namespace KDNSSD
19{
20class DomainBrowser;
21class ServiceBrowserPrivate;
22
23/*!
24 * \class KDNSSD::ServiceBrowser
25 * \inmodule KDNSSD
26 * \inheaderfile KDNSSD/ServiceBrowser
27 *
28 * \brief Browses for network services advertised over DNS-SD.
29 *
30 * This is the central class in the KDNSSD library for applications
31 * that want to discover services on network.
32 *
33 * Suppose that you need list of web servers running. Then you
34 * might do something like:
35 * \code
36 * KDNSSD::ServiceBrowser *browser = new KDNSSD::ServiceBrowser(QStringLiteral("_http._tcp"));
37 * connect(browser, &KDNSSD::ServiceBrowser::serviceAdded,
38 * this, [](KDNSSD::RemoteService::Ptr service) {
39 * });
40 * connect(browser, &KDNSSD::ServiceBrowser::serviceRemoved,
41 * this, [](KDNSSD::RemoteService::Ptr service) {
42 * });
43 * browser->startBrowse();
44 * \endcode
45 *
46 * In above example addService() will be called for every web server
47 * already running and for every web service that subsequently
48 * appears on the network and delService() will be called when
49 * a server previously advertised is stopped.
50 *
51 * Because no domain was passed to constructor, the default domain
52 * will be searched. To find other domains to browse for services on,
53 * use DomainBrowser.
54 */
55class KDNSSD_EXPORT ServiceBrowser : public QObject
56{
57 Q_OBJECT
58
59public:
60 /*!
61 * \enum KDNSSD::ServiceBrowser::State
62 * \brief Availability of DNS-SD services.
63 *
64 * \value Working
65 * The DNS-SD services are available.
66 * \value Stopped
67 * Not available because mDnsd or Avahi daemon is not running.
68 * \value Unsupported
69 * Not available because KDE was compiled without DNS-SD support.
70 */
71 enum State {
72 Working,
73 Stopped,
74 Unsupported,
75 };
76
77 /*!
78 * Creates a ServiceBrowser for a particular service type.
79 *
80 * DomainBrowser can be used to find other domains to browse on.
81 * If no domain is given, the default domain is used.
82 *
83 * The service type is the high-level protocol type, followed by a dot,
84 * followed by the transport protocol type (\c _tcp or \c _udp).
85 * The \l {http://www.dns-sd.org} {DNS-SD website} maintains
86 * \l {http://www.dns-sd.org/ServiceTypes.html} {a full list}
87 * of service types.
88 *
89 * The \a subtype parameter allows you to do more fine-grained filtering
90 * on the services you are interested in. So you might request only
91 * FTP servers that allow anonymous access by passing \c "_ftp._tcp" as the
92 * \a type and \c "_anon" as the \a subtype. Subtypes are particularly
93 * important for types like \c _soap and \c _upnp, which are far too generic
94 * for most applications. In these cases, the subtype can be used to
95 * specify the particular SOAP or UPnP protocol they want.
96 *
97 * \warning
98 * Enabling \a autoResolve will increase network usage by resolving
99 * all services, so this feature should be used only when necessary.
100 *
101 * \a type is the service type to browse for (example: "_http._tcp")
102 *
103 * \a autoResolve if true, discovered services will be resolved before being
104 * reported with the serviceAdded() signal
105 *
106 * \a domain is the domain to search on instead of the default one
107 *
108 * \a subtype if not an empty string, only browse for a specific subtype
109 *
110 * \sa startBrowse() and isAvailable()
111 */
112 explicit ServiceBrowser(const QString &type, bool autoResolve = false, const QString &domain = QString(), const QString &subtype = QString());
113
114 ~ServiceBrowser() override;
115
116 /*!
117 * The currently known services of the specified type.
118 *
119 * Returns a list of RemoteService pointers
120 *
121 * \sa serviceAdded() and serviceRemoved()
122 */
123 QList<RemoteService::Ptr> services() const;
124
125 /*!
126 * Starts browsing for services.
127 *
128 * \note Only the first call to this function will have any effect.
129 *
130 * Browsing stops when the ServiceBrowser object is destroyed.
131 *
132 * \warning The serviceAdded() signal may be emitted before this
133 * function returns.
134 *
135 * \sa serviceAdded(), serviceRemoved() and finished()
136 */
137 virtual void startBrowse();
138
139 /*!
140 * Checks availability of DNS-SD services.
141 *
142 * \note Although this method is part of ServiceBrowser, none of the classes
143 * in this library will be able to perform their intended function
144 * if this method does not return \l Working.
145 *
146 * If this method does not return \l Working, it is still safe to call
147 * any of the methods in this library. However, no services will be
148 * found or published and no domains will be found.
149 *
150 * If you use this function to report an error to the user, below
151 * is a suggestion on how to word the errors when publishing a
152 * service. The first line of each error message can also be
153 * used for reporting errors when browsing for services.
154 *
155 * \code
156 * switch(KDNSSD::ServiceBrowser::isAvailable()) {
157 * case KDNSSD::ServiceBrowser::Working:
158 * return "";
159 * case KDNSSD::ServiceBrowser::Stopped:
160 * return i18n("<p>The Zeroconf daemon is not running. See the Service"
161 * " Discovery Handbook for more information.<br/>"
162 * "Other users will not see the services provided by this
163 * " system when browsing the network via zeroconf, but "
164 * " normal access will still work.</p>");
165 * case KDNSSD::ServiceBrowser::Unsupported:
166 * return i18n("<p>Zeroconf support is not available in this version of KDE."
167 * " See the Service Discovery Handbook for more information.<br/>"
168 * "Other users will not see the services provided by this
169 * " application when browsing the network via zeroconf, but "
170 * " normal access will still work.</p>");
171 * default:
172 * return i18n("<p>Unknown error with Zeroconf.<br/>"
173 * "Other users will not see the services provided by this
174 * " application when browsing the network via zeroconf, but "
175 * " normal access will still work.</p>");
176 * }
177 * \endcode
178 *
179 * Returns the mDNS-SD service state.
180 */
181 static State isAvailable();
182
183 /*!
184 * Whether discovered services are resolved before being reported.
185 *
186 * Returns the value of the autoResolve parameter passed to the constructor.
187 *
188 * \since 4.1
189 */
190 bool isAutoResolving() const;
191
192 /*!
193 * Resolves an mDNS hostname into an IP address.
194 *
195 * \note This function is very rarely useful, since a properly configured
196 * system is able to resolve an mDNS-based host name using the system
197 * resolver (ie: you can just pass the mDNS hostname to KIO or other
198 * library).
199 *
200 * \a hostname the hostname to be resolved
201 *
202 * Returns a QHostAddress containing the IP address, or QHostAddress() if
203 * resolution failed
204 *
205 * \since 4.2
206 */
207 static QHostAddress resolveHostName(const QString &hostname);
208
209 /*!
210 * The mDNS hostname of the local machine.
211 *
212 * Usually this will return the same as QHostInfo::localHostName(),
213 * but it may be changed to something different
214 * in the Avahi configuration file (if using the Avahi backend).
215 *
216 * Returns the hostname, or an empty string on failure
217 *
218 * \since 4.2
219 */
220 static QString getLocalHostName();
221
222Q_SIGNALS:
223 /*!
224 * Emitted when new service is discovered.
225 *
226 * If isAutoResolving() returns \c true, this will not be emitted
227 * until the service has been resolved.
228 *
229 * \a service is a RemoteService object describing the service
230 *
231 * \sa serviceRemoved() and finished()
232 */
233 void serviceAdded(KDNSSD::RemoteService::Ptr service);
234
235 /*!
236 * Emitted when a service is no longer published over DNS-SD.
237 *
238 * The RemoteService object is removed from the services() list
239 * and deleted immediately after this signal returns.
240 *
241 * \warning
242 * Do \b not use a delayed connection with this signal.
243 *
244 * \a service a RemoteService object describing the service
245 *
246 * \sa serviceAdded() and finished()
247 */
248 void serviceRemoved(KDNSSD::RemoteService::Ptr service);
249
250 /*!
251 * Emitted when the list of published services has settled.
252 *
253 * \note
254 * This signal is emitted once after startBrowse() is called
255 * when all the services of the requested type that are
256 * currently published have been reported (even if none
257 * are available or the DNS-SD service is not available).
258 * It is emitted again when a new batch of services become
259 * available or disappear.
260 *
261 * For example, if a new host is connected to network and
262 * announces some services watched for by this ServiceBrowser,
263 * they will be reported by one or more serviceAdded() signals
264 * and the whole batch will be concluded by finished().
265 *
266 * This signal can be used by applications that just want to
267 * get a list of the currently available services
268 * (similar to a directory listing) and do not care about
269 * adding or removing services that appear or disappear later.
270 *
271 * \warning
272 * There is no guarantee any RemoteService
273 * pointers received by serviceAdded() will be valid
274 * by the time this signal is emitted, so you should either
275 * do all your work involving them in the slot receiving
276 * the serviceAdded() signal, or you should listen to
277 * serviceRemoved() as well.
278 *
279 * \sa serviceAdded() and serviceRemoved()
280 */
281 void finished();
282
283protected:
284 virtual void virtual_hook(int, void *);
285
286private:
287 friend class ServiceBrowserPrivate;
288 std::unique_ptr<ServiceBrowserPrivate> const d;
289 Q_DECLARE_PRIVATE_D(d, ServiceBrowser)
290};
291
292}
293
294#endif
295

source code of kdnssd/src/servicebrowser.h