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

source code of kdnssd/src/servicebrowser.h