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