~ubuntu-branches/ubuntu/quantal/psi/quantal

« back to all changes in this revision

Viewing changes to iris/src/irisnet/corelib/netnames.h

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2009-09-25 17:49:51 UTC
  • mfrom: (6.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20090925174951-lvm7kdap82o8xhn3
Tags: 0.13-1
* Updated to upstream version 0.13
* Set Standards-Version to 3.8.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2006,2008  Justin Karneges
 
3
 *
 
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.
 
8
 *
 
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.
 
13
 *
 
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
 
17
 * 02110-1301  USA
 
18
 *
 
19
 */
 
20
 
 
21
#ifndef NETNAMES_H
 
22
#define NETNAMES_H
 
23
 
 
24
#include <QtCore>
 
25
#include <QtNetwork>
 
26
#include "irisnetglobal.h"
 
27
 
 
28
namespace XMPP {
 
29
 
 
30
class NameManager;
 
31
 
 
32
class IRISNET_EXPORT NetNames
 
33
{
 
34
public:
 
35
        // free any shared data, shutdown internal dns sessions if necessary.
 
36
        static void cleanup();
 
37
 
 
38
        // return current diagnostic text, clear the buffer.
 
39
        static QString diagnosticText();
 
40
 
 
41
        // convert idn names
 
42
        static QByteArray idnaFromString(const QString &in);
 
43
        static QString idnaToString(const QByteArray &in);
 
44
 
 
45
        // dns escaping
 
46
        static QByteArray escapeDomain(const QByteArray &in);
 
47
        static QByteArray unescapeDomain(const QByteArray &in);
 
48
 
 
49
private:
 
50
        NetNames();
 
51
};
 
52
 
 
53
/**
 
54
   \brief Provides a DNS record
 
55
 
 
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.
 
57
 
 
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:
 
59
 
 
60
\code
 
61
NameRecord record = ... // obtain a record from somewhere
 
62
if(record.type() == NameRecord::A)
 
63
{
 
64
        QHostAddress ip = record.address(); // get the IP
 
65
        ...
 
66
}
 
67
\endcode
 
68
 
 
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.
 
70
 
 
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:
 
72
 
 
73
\code
 
74
// make example.com the owner, with 1 hour TTL
 
75
NameRecord record("example.com", 3600);
 
76
record.setAddress(QHostAddress("1.2.3.4"));
 
77
\endcode
 
78
 
 
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.
 
80
 
 
81
   \sa NameResolver
 
82
*/
 
83
class IRISNET_EXPORT NameRecord
 
84
{
 
85
public:
 
86
        /**
 
87
                \brief The type of DNS record
 
88
 
 
89
                The retrieval functions are shown for each type.
 
90
        */
 
91
        enum Type
 
92
        {
 
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.
 
104
        };
 
105
 
 
106
        /**
 
107
           \brief Constructs a null record object
 
108
 
 
109
           \sa isNull
 
110
        */
 
111
        NameRecord();
 
112
 
 
113
        /**
 
114
           \brief Constructs a partially initialized record object, with the given \a owner and \a ttl
 
115
 
 
116
           For the record to be usable, call an appropriate set<em>X</em> function (where <em>X</em> is the desired type) afterwards.
 
117
        */
 
118
        NameRecord(const QByteArray &owner, int ttl);
 
119
 
 
120
        /**
 
121
           \brief Constructs a copy of \a from
 
122
        */
 
123
        NameRecord(const NameRecord &from);
 
124
 
 
125
        /**
 
126
           \brief Destroys the record object
 
127
        */
 
128
        ~NameRecord();
 
129
 
 
130
        /**
 
131
           \brief Assigns \a from to this object and returns a reference to this object
 
132
        */
 
133
        NameRecord & operator=(const NameRecord &from);
 
134
 
 
135
        /**
 
136
           \brief Returns true if this record object is null, otherwise returns false
 
137
 
 
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.
 
139
        */
 
140
        bool isNull() const; // don't confuse with Null type
 
141
 
 
142
        /**
 
143
           \brief Returns the owner of this record
 
144
 
 
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.
 
146
 
 
147
           \sa setOwner
 
148
        */
 
149
        QByteArray owner() const;
 
150
 
 
151
        /**
 
152
           \brief Returns the TTL (time-to-live) of this record
 
153
 
 
154
           This is the number of seconds the record should be considered valid, which is useful information when performing caching.
 
155
 
 
156
           As a special exception, a TTL of 0 when performing a long-lived lookup indicates that a record is no longer available.
 
157
 
 
158
           \sa setTtl
 
159
        */
 
160
        int ttl() const;
 
161
 
 
162
        /**
 
163
           \brief Returns the type of this record
 
164
        */
 
165
        Type type() const;
 
166
 
 
167
        /**
 
168
           \brief Returns the IP address
 
169
 
 
170
           For NameRecord::A and NameRecord::Aaaa types.
 
171
        */
 
172
        QHostAddress address() const;
 
173
 
 
174
        /**
 
175
           \brief Returns the domain name
 
176
 
 
177
           For NameRecord::Mx, NameRecord::Srv, NameRecord::Cname, NameRecord::Ptr, and NameRecord::Ns types.
 
178
        */
 
179
        QByteArray name() const;
 
180
 
 
181
        /**
 
182
           \brief Returns the priority
 
183
 
 
184
           For NameRecord::Mx and NameRecord::Srv types.
 
185
        */
 
186
        int priority() const;
 
187
 
 
188
        /**
 
189
           \brief Returns the weight
 
190
 
 
191
           For the NameRecord::Srv type.
 
192
        */
 
193
        int weight() const;
 
194
 
 
195
        /**
 
196
           \brief Returns the port
 
197
 
 
198
           For the NameRecord::Srv type.
 
199
        */
 
200
        int port() const;
 
201
 
 
202
        /**
 
203
           \brief Returns the list of text strings
 
204
 
 
205
           For the NameRecord::Txt type.
 
206
        */
 
207
        QList<QByteArray> texts() const;
 
208
 
 
209
        /**
 
210
           \brief Returns the architecture identifier string
 
211
 
 
212
           For the NameRecord::Hinfo type.
 
213
        */
 
214
        QByteArray cpu() const;
 
215
 
 
216
        /**
 
217
           \brief Returns the operating system identifier string
 
218
 
 
219
           For the NameRecord::Hinfo type.
 
220
        */
 
221
        QByteArray os() const;
 
222
 
 
223
        /**
 
224
           \brief Returns the raw data
 
225
 
 
226
           For the NameRecord::Null type.
 
227
        */
 
228
        QByteArray rawData() const;
 
229
 
 
230
        /**
 
231
           \brief Sets the owner of this record to \a name
 
232
 
 
233
           \sa owner
 
234
        */
 
235
        void setOwner(const QByteArray &name);
 
236
 
 
237
        /**
 
238
           \brief Sets the TTL (time-to-live) of this record to \a ttl seconds
 
239
 
 
240
           \sa ttl
 
241
        */
 
242
        void setTtl(int seconds);
 
243
 
 
244
        /**
 
245
           \brief Set as A or AAAA record, with data \a a
 
246
 
 
247
           The protocol of \a a determines whether the type will be NameRecord::A or NameRecord::Aaaa.
 
248
        */
 
249
        void setAddress(const QHostAddress &a);
 
250
 
 
251
        /**
 
252
           \brief Set as MX record, with data \a name and \a priority
 
253
        */
 
254
        void setMx(const QByteArray &name, int priority);
 
255
 
 
256
        /**
 
257
           \brief Set as SRV record, with data \a name, \a port, \a priority, and \a weight
 
258
        */
 
259
        void setSrv(const QByteArray &name, int port, int priority, int weight);
 
260
 
 
261
        /**
 
262
           \brief Set as CNAME record, with data \a name
 
263
        */
 
264
        void setCname(const QByteArray &name);
 
265
 
 
266
        /**
 
267
           \brief Set as PTR record, with data \a name
 
268
        */
 
269
        void setPtr(const QByteArray &name);
 
270
 
 
271
        /**
 
272
           \brief Set as TXT record, with data \a texts
 
273
        */
 
274
        void setTxt(const QList<QByteArray> &texts);
 
275
 
 
276
        /**
 
277
           \brief Set as HINFO record, with data \a cpu and \a os
 
278
        */
 
279
        void setHinfo(const QByteArray &cpu, const QByteArray &os);
 
280
 
 
281
        /**
 
282
           \brief Set as NS record, with data \a name
 
283
        */
 
284
        void setNs(const QByteArray &name);
 
285
 
 
286
        /**
 
287
           \brief Set as NULL record, with data \a rawData
 
288
        */
 
289
        void setNull(const QByteArray &rawData);
 
290
 
 
291
private:
 
292
        class Private;
 
293
        QSharedDataPointer<Private> d;
 
294
};
 
295
 
 
296
class IRISNET_EXPORT ServiceInstance
 
297
{
 
298
public:
 
299
        ServiceInstance();
 
300
        ServiceInstance(const QString &instance, const QString &type, const QString &domain, const QMap<QString,QByteArray> &attributes);
 
301
        ServiceInstance(const ServiceInstance &from);
 
302
        ~ServiceInstance();
 
303
        ServiceInstance & operator=(const ServiceInstance &from);
 
304
 
 
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
 
310
 
 
311
private:
 
312
        class Private;
 
313
        QSharedDataPointer<Private> d;
 
314
 
 
315
        friend class NameManager;
 
316
};
 
317
 
 
318
/**
 
319
   \brief Performs a DNS lookup
 
320
 
 
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().
 
322
 
 
323
   For example, here is how to obtain the IPv4 addresses of a domain name:
 
324
\code
 
325
NameResolver *resolver;
 
326
 
 
327
void do_lookup()
 
328
{
 
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)));
 
334
 
 
335
        // look up affinix.com
 
336
        resolver->start("affinix.com");
 
337
}
 
338
 
 
339
void dns_resultsReady(const QList<XMPP::NameRecord> &results)
 
340
{
 
341
        // print IP addresses
 
342
        foreach(NameRecord i, results)
 
343
                printf("%s\n", qPrintable(i.address().toString()));
 
344
}
 
345
 
 
346
void dns_error(XMPP::NameResolver::Error error)
 
347
{
 
348
        // handle error
 
349
        ...
 
350
}
 
351
\endcode
 
352
 
 
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.
 
354
 
 
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:
 
356
 
 
357
\code
 
358
// look up the MX record for affinix.com
 
359
resolver->start("affinix.com", NameRecord::Mx);
 
360
\endcode
 
361
 
 
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.
 
363
 
 
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.
 
365
 
 
366
\code
 
367
// monitor for SSH services on the local network
 
368
resolver->start("_ssh._tcp.local.", NameRecord::Ptr, NameResolver::LongLived);
 
369
\endcode
 
370
 
 
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.
 
372
 
 
373
   \sa NameRecord
 
374
*/
 
375
class IRISNET_EXPORT NameResolver : public QObject
 
376
{
 
377
        Q_OBJECT
 
378
public:
 
379
        /**
 
380
           \brief Resolve mode
 
381
        */
 
382
        enum Mode
 
383
        {
 
384
                Single,       ///< A normal DNS query with a single result set.
 
385
                LongLived     ///< An endless query, with multiple result sets allowed.
 
386
        };
 
387
 
 
388
        /**
 
389
           \brief Resolve error
 
390
        */
 
391
        enum Error
 
392
        {
 
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.
 
398
        };
 
399
 
 
400
        /**
 
401
           \brief Constructs a new resolver object with the given \a parent
 
402
        */
 
403
        NameResolver(QObject *parent = 0);
 
404
 
 
405
        /**
 
406
           \brief Destroys the resolver object
 
407
 
 
408
           The lookup is, of course, stopped.
 
409
        */
 
410
        ~NameResolver();
 
411
 
 
412
        /**
 
413
           \brief Starts a lookup
 
414
 
 
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.
 
416
 
 
417
           \sa stop
 
418
        */
 
419
        void start(const QByteArray &name, NameRecord::Type type = NameRecord::A, Mode mode = Single);
 
420
 
 
421
        /**
 
422
           \brief Stops a lookup
 
423
 
 
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.
 
425
 
 
426
           \sa start
 
427
        */
 
428
        void stop();
 
429
 
 
430
signals:
 
431
        /**
 
432
           \brief Notification of result records
 
433
 
 
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
 
435
 
 
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.
 
437
        */
 
438
        void resultsReady(const QList<XMPP::NameRecord> &results);
 
439
 
 
440
        /**
 
441
           \brief Notification of error
 
442
 
 
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.
 
444
        */
 
445
        void error(XMPP::NameResolver::Error e);
 
446
 
 
447
private:
 
448
        class Private;
 
449
        friend class Private;
 
450
        Private *d;
 
451
 
 
452
        friend class NameManager;
 
453
};
 
454
 
 
455
class IRISNET_EXPORT ServiceBrowser : public QObject
 
456
{
 
457
        Q_OBJECT
 
458
public:
 
459
        enum Error
 
460
        {
 
461
                ErrorGeneric,
 
462
                ErrorNoLocal,
 
463
                ErrorNoWide
 
464
        };
 
465
 
 
466
        ServiceBrowser(QObject *parent = 0);
 
467
        ~ServiceBrowser();
 
468
 
 
469
        void start(const QString &type, const QString &domain = "local");
 
470
        void stop();
 
471
 
 
472
signals:
 
473
        void instanceAvailable(const XMPP::ServiceInstance &instance);
 
474
        void instanceUnavailable(const XMPP::ServiceInstance &instance);
 
475
        void error();
 
476
 
 
477
private:
 
478
        class Private;
 
479
        friend class Private;
 
480
        Private *d;
 
481
 
 
482
        friend class NameManager;
 
483
};
 
484
 
 
485
class IRISNET_EXPORT ServiceResolver : public QObject
 
486
{
 
487
        Q_OBJECT
 
488
public:
 
489
        enum Error
 
490
        {
 
491
                ErrorGeneric,
 
492
                ErrorTimeout,
 
493
                ErrorNoLocal
 
494
        };
 
495
 
 
496
        ServiceResolver(QObject *parent = 0);
 
497
        ~ServiceResolver();
 
498
 
 
499
        void startFromInstance(const QByteArray &name);
 
500
        void startFromDomain(const QString &domain, const QString &type);
 
501
        void startFromPlain(const QString &host, int port); // non-SRV
 
502
        void tryNext();
 
503
        void stop();
 
504
 
 
505
signals:
 
506
        void resultsReady(const QHostAddress &address, int port);
 
507
        void finished();
 
508
        void error(); // SRV lookup failed
 
509
 
 
510
private:
 
511
        class Private;
 
512
        friend class Private;
 
513
        Private *d;
 
514
 
 
515
        friend class NameManager;
 
516
};
 
517
 
 
518
class IRISNET_EXPORT ServiceLocalPublisher : public QObject
 
519
{
 
520
        Q_OBJECT
 
521
public:
 
522
        enum Error
 
523
        {
 
524
                ErrorGeneric,  // generic error
 
525
                ErrorConflict, // name in use
 
526
                ErrorNoLocal   // unable to setup multicast dns
 
527
        };
 
528
 
 
529
        ServiceLocalPublisher(QObject *parent = 0);
 
530
        ~ServiceLocalPublisher();
 
531
 
 
532
        void publish(const QString &instance, const QString &type, int port, const QMap<QString,QByteArray> &attributes);
 
533
        void updateAttributes(const QMap<QString,QByteArray> &attributes);
 
534
        void addRecord(const NameRecord &rec);
 
535
        void cancel();
 
536
 
 
537
signals:
 
538
        void published();
 
539
        void error(XMPP::ServiceLocalPublisher::Error e);
 
540
 
 
541
private:
 
542
        class Private;
 
543
        friend class Private;
 
544
        Private *d;
 
545
 
 
546
        friend class NameManager;
 
547
};
 
548
 
 
549
}
 
550
 
 
551
#endif