2
* Copyright (C) 2006 Justin Karneges
4
* This library is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU Lesser General Public
6
* License as published by the Free Software Foundation; either
7
* version 2.1 of the License, or (at your option) any later version.
9
* This library is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* Lesser General Public License for more details.
14
* You should have received a copy of the GNU Lesser General Public
15
* License along with this library; if not, write to the Free Software
16
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26
#include "irisnetglobal.h"
32
class IRISNET_EXPORT NetNames
35
// free any shared data, shutdown internal dns sessions if necessary.
36
static void cleanup();
38
// return current diagnostic text, clear the buffer.
39
static QString diagnosticText();
42
static QByteArray idnaFromString(const QString &in);
43
static QString idnaToString(const QByteArray &in);
46
static QByteArray escapeDomain(const QByteArray &in);
47
static QByteArray unescapeDomain(const QByteArray &in);
54
\brief Provides a DNS record
56
NameRecord provides a DNS (Domain Name System) record, which is information assicated with a domain name. For most purposes, the information is an IP address. However, DNS records are capable of holding a variety of data types, such as named pointers to other domain names and even arbitrary text strings. The results of a NameResolver operation are a list of NameRecords.
58
The most common type is the address record, "A", which contains an IPv4 address. Here is an example of how to get the IP address out of an address record:
61
NameRecord record = ... // obtain a record from somewhere
62
if(record.type() == NameRecord::A)
64
QHostAddress ip = record.address(); // get the IP
69
Getting the data out of a NameRecord involves calling the right retrieval functions, depending on the type. Many types share retrieval functions. For example, the "AAAA" type holds an IPv6 address, which is accessed the same way as the "A" type, by calling address(). See the NameRecord::Type enum for further information about which retrieval functions should be called for each type.
71
To create a NameRecord, use setOwner() and setTTL() as necessary, and then call one of the set<em>X</em> functions (where <em>X</em> is the desired type). For example, to set an A or AAAA record, use setAddress() like this:
74
// make example.com the owner, with 1 hour TTL
75
NameRecord record("example.com", 3600);
76
record.setAddress(QHostAddress("1.2.3.4"));
79
Note that in the case of setAddress(), the record type need not be specified. NameRecord will determine the type to use based on the given QHostAddress.
83
class IRISNET_EXPORT NameRecord
87
\brief The type of DNS record
89
The retrieval functions are shown for each type.
93
A, ///< IPv4 address. Use address().
94
Aaaa, ///< IPv6 address. Use address().
95
Mx, ///< Mail server. Use name() and priority().
96
Srv, ///< Generic server. Use name(), port(), priority(), and weight().
97
Cname, ///< Canonical name. Use name().
98
Ptr, ///< Pointer. Use name().
99
Txt, ///< List of text strings. Use texts().
100
Hinfo, ///< Host information. Use cpu() and os().
101
Ns, ///< Name server. Use name().
102
Null, ///< Null type. Use rawData().
103
Any ///< "Any record", for use with NameResolver::start() only. A NameRecord object will never be of this type.
107
\brief Constructs a null record object
114
\brief Constructs a partially initialized record object, with the given \a owner and \a ttl
116
For the record to be usable, call an appropriate set<em>X</em> function (where <em>X</em> is the desired type) afterwards.
118
NameRecord(const QByteArray &owner, int ttl);
121
\brief Constructs a copy of \a from
123
NameRecord(const NameRecord &from);
126
\brief Destroys the record object
131
\brief Assigns \a from to this object and returns a reference to this object
133
NameRecord & operator=(const NameRecord &from);
136
\brief Returns true if this record object is null, otherwise returns false
138
Be sure not to confuse a null object with the NULL type (NameRecord::Null). Don't ask why DNS has a type called NULL that contains valid data.
140
bool isNull() const; // don't confuse with Null type
143
\brief Returns the owner of this record
145
The owner is usually not a useful attribute, since it will be the same as the name searched for with NameResolver. For example, if the A record of "example.com" is looked up, then the resulting records will all have "example.com" as the owner.
149
QByteArray owner() const;
152
\brief Returns the TTL (time-to-live) of this record
154
This is the number of seconds the record should be considered valid, which is useful information when performing caching.
156
As a special exception, a TTL of 0 when performing a long-lived lookup indicates that a record is no longer available.
163
\brief Returns the type of this record
168
\brief Returns the IP address
170
For NameRecord::A and NameRecord::Aaaa types.
172
QHostAddress address() const;
175
\brief Returns the domain name
177
For NameRecord::Mx, NameRecord::Srv, NameRecord::Cname, NameRecord::Ptr, and NameRecord::Ns types.
179
QByteArray name() const;
182
\brief Returns the priority
184
For NameRecord::Mx and NameRecord::Srv types.
186
int priority() const;
189
\brief Returns the weight
191
For the NameRecord::Srv type.
196
\brief Returns the port
198
For the NameRecord::Srv type.
203
\brief Returns the list of text strings
205
For the NameRecord::Txt type.
207
QList<QByteArray> texts() const;
210
\brief Returns the architecture identifier string
212
For the NameRecord::Hinfo type.
214
QByteArray cpu() const;
217
\brief Returns the operating system identifier string
219
For the NameRecord::Hinfo type.
221
QByteArray os() const;
224
\brief Returns the raw data
226
For the NameRecord::Null type.
228
QByteArray rawData() const;
231
\brief Sets the owner of this record to \a name
235
void setOwner(const QByteArray &name);
238
\brief Sets the TTL (time-to-live) of this record to \a ttl seconds
242
void setTTL(int seconds);
245
\brief Set as A or AAAA record, with data \a a
247
The protocol of \a a determines whether the type will be NameRecord::A or NameRecord::Aaaa.
249
void setAddress(const QHostAddress &a);
252
\brief Set as MX record, with data \a name and \a priority
254
void setMx(const QByteArray &name, int priority);
257
\brief Set as SRV record, with data \a name, \a port, \a priority, and \a weight
259
void setSrv(const QByteArray &name, int port, int priority, int weight);
262
\brief Set as CNAME record, with data \a name
264
void setCname(const QByteArray &name);
267
\brief Set as PTR record, with data \a name
269
void setPtr(const QByteArray &name);
272
\brief Set as TXT record, with data \a texts
274
void setTxt(const QList<QByteArray> &texts);
277
\brief Set as HINFO record, with data \a cpu and \a os
279
void setHinfo(const QByteArray &cpu, const QByteArray &os);
282
\brief Set as NS record, with data \a name
284
void setNs(const QByteArray &name);
287
\brief Set as NULL record, with data \a rawData
289
void setNull(const QByteArray &rawData);
293
QSharedDataPointer<Private> d;
296
class IRISNET_EXPORT ServiceInstance
300
ServiceInstance(const QString &instance, const QString &type, const QString &domain, const QMap<QString,QByteArray> &attributes);
301
ServiceInstance(const ServiceInstance &from);
303
ServiceInstance & operator=(const ServiceInstance &from);
305
QString instance() const;
306
QString type() const;
307
QString domain() const;
308
QMap<QString,QByteArray> attributes() const;
309
QByteArray name() const; // full dns label
313
QSharedDataPointer<Private> d;
315
friend class NameManager;
319
\brief Performs a DNS lookup
321
NameResolver performs an asynchronous DNS lookup for a given domain name and record type. Call start() to begin. The resultsReady() signal is emitted on success, otherwise error() is emitted. To cancel a lookup, call stop().
323
For example, here is how to obtain the IPv4 addresses of a domain name:
325
NameResolver *resolver;
329
resolver = new NameResolver;
330
connect(resolver, SIGNAL(resultsReady(const QList<XMPP::NameRecord> &)),
331
SLOT(dns_resultsReady(const QList<XMPP::NameRecord> &)));
332
connect(resolver, SIGNAL(error(XMPP::NameResolver::Error)),
333
SLOT(dns_error(XMPP::NameResolver::Error)));
335
// look up affinix.com
336
resolver->start("affinix.com");
339
void dns_resultsReady(const QList<XMPP::NameRecord> &results)
341
// print IP addresses
342
foreach(NameRecord i, results)
343
printf("%s\n", qPrintable(i.address().toString()));
346
void dns_error(XMPP::NameResolver::Error error)
353
Yes, a domain name can have multiple IP addresses. Many applications ignore this fact, and use only one of the answers. A proper network application should try connecting to each IP address until one succeeds.
355
To lookup other types, pass the desired type to start(). For example, suppose you want to look up the MX record of a domain name:
358
// look up the MX record for affinix.com
359
resolver->start("affinix.com", NameRecord::Mx);
362
It is also possible to perform long-lived queries. This is generally useful for DNS Service Discovery. Long-lived queries are continuous, and resultsReady() may be emitted multiple times. Unlike a normal lookup, which stops once the results are returned, a long-lived query will keep going until stop() is called.
364
For example, suppose you want to scan the local network for SSH services. According to the DNS-SD protocol, this is done by querying for the name "_ssh._tcp.local." of type PTR.
367
// monitor for SSH services on the local network
368
resolver->start("_ssh._tcp.local.", NameRecord::Ptr, NameResolver::LongLived);
371
Don't be alarmed by the trailing dot (".") character in this last example. It is not well known, but all valid DNS domain names end with a dot. However, NameResolver, like most DNS programming interfaces, allows the dot to be left out. What this means is that if a trailing dot is missing in the input to start(), NameResolver will internally append one before performing the query.
375
class IRISNET_EXPORT NameResolver : public QObject
384
Single, ///< A normal DNS query with a single result set.
385
LongLived ///< An endless query, with multiple result sets allowed.
393
ErrorGeneric, ///< General failure during lookup, no further details.
394
ErrorNoName, ///< Name does not exist.
395
ErrorTimeout, ///< The operation timed out.
396
ErrorNoLocal, ///< The query is to the local network, but no mechanism for Multicast DNS is available.
397
ErrorNoLongLived ///< The query requires long-lived capability, but no mechanism for doing so is available.
401
\brief Constructs a new resolver object with the given \a parent
403
NameResolver(QObject *parent = 0);
406
\brief Destroys the resolver object
408
The lookup is, of course, stopped.
413
\brief Starts a lookup
415
A lookup for \a name of \a type is started. For normal queries, \a mode should be NameResolver::Single (this is the default). For long-lived queries, use NameResolver::LongLived.
419
void start(const QByteArray &name, NameRecord::Type type = NameRecord::A, Mode mode = Single);
422
\brief Stops a lookup
424
Use this function if you want to stop the current lookup, such that the resolver object may be reused again later. If you don't plan to reuse the object, then destroying the object is enough.
432
\brief Notification of result records
434
This signal is emitted when results of the lookup operation have arrived. The \a results parameter is a list of NameRecords. All records will be of the type queried for with start(), unless the NameRecord::Any type was specified, in which case the records may be of any type
436
When using the NameResolver::Single mode, the lookup is stopped once results are ready. However, with the NameResolver::LongLived mode, the lookup stays active, and in that case this signal may be emitted multiple times.
438
void resultsReady(const QList<XMPP::NameRecord> &results);
441
\brief Notification of error
443
This signal is emitted if an error has occurred while performing a lookup. The reason for error can be found in \a e. Regardless of the mode used, the lookup is stopped when an error occurs.
445
void error(XMPP::NameResolver::Error e);
449
friend class Private;
452
friend class NameManager;
455
class IRISNET_EXPORT ServiceBrowser : public QObject
459
ServiceBrowser(QObject *parent = 0);
462
void start(const QString &type, const QString &domain = "local");
466
void instanceAvailable(const XMPP::ServiceInstance &instance);
467
void instanceUnavailable(const XMPP::ServiceInstance &instance);
472
friend class Private;
475
friend class NameManager;
478
class IRISNET_EXPORT ServiceResolver : public QObject
482
ServiceResolver(QObject *parent = 0);
485
void startFromInstance(const QByteArray &name);
486
void startFromDomain(const QString &domain, const QString &type);
487
void startFromPlain(const QString &host, int port); // non-SRV
492
void resultsReady(const QHostAddress &address, int port);
494
void error(); // SRV lookup failed
498
friend class Private;
501
friend class NameManager;
504
class IRISNET_EXPORT ServiceLocalPublisher : public QObject
510
ErrorGeneric, // generic error
511
ErrorConflict, // name in use
512
ErrorNoLocal // unable to setup multicast dns
515
ServiceLocalPublisher(QObject *parent = 0);
516
~ServiceLocalPublisher();
518
void publish(const QString &instance, const QString &type, int port, const QMap<QString,QByteArray> &attributes);
519
void updateAttributes(const QMap<QString,QByteArray> &attributes);
520
void addRecord(const NameRecord &rec);
525
void error(XMPP::ServiceLocalPublisher::Error e);
529
friend class Private;
532
friend class NameManager;