~ubuntu-branches/ubuntu/saucy/kopete/saucy-proposed

« back to all changes in this revision

Viewing changes to protocols/jabber/libiris/src/irisnet/corelib/netnames.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-06-21 02:22:39 UTC
  • Revision ID: package-import@ubuntu.com-20130621022239-63l3zc8p0nf26pt6
Tags: upstream-4.10.80
ImportĀ upstreamĀ versionĀ 4.10.80

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2006  Justin Karneges
 
3
 * Copyright (C) 2009-2010  Dennis Schridde
 
4
 *
 
5
 * This library is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU Lesser General Public
 
7
 * License as published by the Free Software Foundation; either
 
8
 * version 2.1 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
 * Lesser General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU Lesser General Public
 
16
 * License along with this library; if not, write to the Free Software
 
17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 
18
 * 02110-1301  USA
 
19
 *
 
20
 */
 
21
 
 
22
#include "netnames.h"
 
23
 
 
24
#include <limits>
 
25
 
 
26
//#include <idna.h>
 
27
#include "irisnetplugin.h"
 
28
#include "irisnetglobal_p.h"
 
29
#include "addressresolver.h"
 
30
 
 
31
 
 
32
//#define NETNAMES_DEBUG
 
33
 
 
34
#ifdef NETNAMES_DEBUG
 
35
# define NNDEBUG (qDebug() << this << "#" << __FUNCTION__ << ":")
 
36
#endif
 
37
 
 
38
 
 
39
namespace XMPP {
 
40
 
 
41
//----------------------------------------------------------------------------
 
42
// NameRecord
 
43
//----------------------------------------------------------------------------
 
44
class NameRecord::Private : public QSharedData
 
45
{
 
46
public:
 
47
        QByteArray owner;
 
48
        NameRecord::Type type;
 
49
        int ttl;
 
50
 
 
51
        QHostAddress address;
 
52
        QByteArray name;
 
53
        int priority, weight, port;
 
54
        QList<QByteArray> texts;
 
55
        QByteArray cpu, os;
 
56
        QByteArray rawData;
 
57
};
 
58
 
 
59
#define ENSURE_D { if(!d) d = new Private; }
 
60
 
 
61
NameRecord::NameRecord()
 
62
{
 
63
        d = 0;
 
64
}
 
65
 
 
66
NameRecord::NameRecord(const QByteArray &owner, int ttl)
 
67
{
 
68
        d = 0;
 
69
        setOwner(owner);
 
70
        setTtl(ttl);
 
71
}
 
72
 
 
73
NameRecord::NameRecord(const NameRecord &from)
 
74
{
 
75
        d = 0;
 
76
        *this = from;
 
77
}
 
78
 
 
79
NameRecord::~NameRecord()
 
80
{
 
81
}
 
82
 
 
83
NameRecord & NameRecord::operator=(const NameRecord &from)
 
84
{
 
85
        d = from.d;
 
86
        return *this;
 
87
}
 
88
 
 
89
bool NameRecord::operator==(const NameRecord &o) {
 
90
        if (isNull() != o.isNull() || owner() != o.owner() || ttl() != o.ttl() || type() != o.type()) {
 
91
                return false;
 
92
        }
 
93
 
 
94
        switch (type()) {
 
95
                case XMPP::NameRecord::A:
 
96
                case XMPP::NameRecord::Aaaa:
 
97
                        return address() == o.address();
 
98
                case XMPP::NameRecord::Mx:
 
99
                        return name() == o.name() && priority() == o.priority();
 
100
                case XMPP::NameRecord::Srv:
 
101
                        return name() == o.name() && port() == o.port() && priority() == o.priority() && weight() == o.weight();
 
102
                case XMPP::NameRecord::Cname:
 
103
                case XMPP::NameRecord::Ptr:
 
104
                case XMPP::NameRecord::Ns:
 
105
                        return name() == o.name();
 
106
                case XMPP::NameRecord::Txt:
 
107
                        return texts() == o.texts();
 
108
                case XMPP::NameRecord::Hinfo:
 
109
                        return cpu() == o.cpu() && os() == o.os();
 
110
                case XMPP::NameRecord::Null:
 
111
                        return rawData() == o.rawData();
 
112
                case XMPP::NameRecord::Any:
 
113
                        return false;
 
114
        }
 
115
 
 
116
        return false;
 
117
}
 
118
 
 
119
bool NameRecord::isNull() const
 
120
{
 
121
        return (d ? false : true);
 
122
}
 
123
 
 
124
QByteArray NameRecord::owner() const
 
125
{
 
126
        Q_ASSERT(d);
 
127
        return d->owner;
 
128
}
 
129
 
 
130
int NameRecord::ttl() const
 
131
{
 
132
        Q_ASSERT(d);
 
133
        return d->ttl;
 
134
}
 
135
 
 
136
NameRecord::Type NameRecord::type() const
 
137
{
 
138
        Q_ASSERT(d);
 
139
        return d->type;
 
140
}
 
141
 
 
142
QHostAddress NameRecord::address() const
 
143
{
 
144
        Q_ASSERT(d);
 
145
        return d->address;
 
146
}
 
147
 
 
148
QByteArray NameRecord::name() const
 
149
{
 
150
        Q_ASSERT(d);
 
151
        return d->name;
 
152
}
 
153
 
 
154
int NameRecord::priority() const
 
155
{
 
156
        Q_ASSERT(d);
 
157
        return d->priority;
 
158
}
 
159
 
 
160
int NameRecord::weight() const
 
161
{
 
162
        Q_ASSERT(d);
 
163
        return d->weight;
 
164
}
 
165
 
 
166
int NameRecord::port() const
 
167
{
 
168
        Q_ASSERT(d);
 
169
        return d->port;
 
170
}
 
171
 
 
172
QList<QByteArray> NameRecord::texts() const
 
173
{
 
174
        Q_ASSERT(d);
 
175
        return d->texts;
 
176
}
 
177
 
 
178
QByteArray NameRecord::cpu() const
 
179
{
 
180
        Q_ASSERT(d);
 
181
        return d->cpu;
 
182
}
 
183
 
 
184
QByteArray NameRecord::os() const
 
185
{
 
186
        Q_ASSERT(d);
 
187
        return d->os;
 
188
}
 
189
 
 
190
QByteArray NameRecord::rawData() const
 
191
{
 
192
        Q_ASSERT(d);
 
193
        return d->rawData;
 
194
}
 
195
 
 
196
void NameRecord::setOwner(const QByteArray &name)
 
197
{
 
198
        ENSURE_D
 
199
        d->owner = name;
 
200
}
 
201
 
 
202
void NameRecord::setTtl(int seconds)
 
203
{
 
204
        ENSURE_D
 
205
        d->ttl = seconds;
 
206
}
 
207
 
 
208
void NameRecord::setAddress(const QHostAddress &a)
 
209
{
 
210
        ENSURE_D
 
211
        if(a.protocol() == QAbstractSocket::IPv6Protocol)
 
212
                d->type = NameRecord::Aaaa;
 
213
        else
 
214
                d->type = NameRecord::A;
 
215
        d->address = a;
 
216
}
 
217
 
 
218
void NameRecord::setMx(const QByteArray &name, int priority)
 
219
{
 
220
        ENSURE_D
 
221
        d->type = NameRecord::Mx;
 
222
        d->name = name;
 
223
        d->priority = priority;
 
224
}
 
225
 
 
226
void NameRecord::setSrv(const QByteArray &name, int port, int priority, int weight)
 
227
{
 
228
        ENSURE_D
 
229
        d->type = NameRecord::Srv;
 
230
        d->name = name;
 
231
        d->port = port;
 
232
        d->priority = priority;
 
233
        d->weight = weight;
 
234
}
 
235
 
 
236
void NameRecord::setCname(const QByteArray &name)
 
237
{
 
238
        ENSURE_D
 
239
        d->type = NameRecord::Cname;
 
240
        d->name = name;
 
241
}
 
242
 
 
243
void NameRecord::setPtr(const QByteArray &name)
 
244
{
 
245
        ENSURE_D
 
246
        d->type = NameRecord::Ptr;
 
247
        d->name = name;
 
248
}
 
249
 
 
250
void NameRecord::setTxt(const QList<QByteArray> &texts)
 
251
{
 
252
        ENSURE_D
 
253
        d->type = NameRecord::Txt;
 
254
        d->texts = texts;
 
255
}
 
256
 
 
257
void NameRecord::setHinfo(const QByteArray &cpu, const QByteArray &os)
 
258
{
 
259
        ENSURE_D
 
260
        d->type = NameRecord::Hinfo;
 
261
        d->cpu = cpu;
 
262
        d->os = os;
 
263
}
 
264
 
 
265
void NameRecord::setNs(const QByteArray &name)
 
266
{
 
267
        ENSURE_D
 
268
        d->type = NameRecord::Ns;
 
269
        d->name = name;
 
270
}
 
271
 
 
272
void NameRecord::setNull(const QByteArray &rawData)
 
273
{
 
274
        ENSURE_D
 
275
        d->type = NameRecord::Null;
 
276
        d->rawData = rawData;
 
277
}
 
278
 
 
279
QDebug operator<<(QDebug dbg, XMPP::NameRecord::Type type)
 
280
{
 
281
        dbg.nospace() << "XMPP::NameRecord::";
 
282
 
 
283
        switch(type)
 
284
        {
 
285
                case XMPP::NameRecord::A:
 
286
                        dbg.nospace() << "A";
 
287
                        break;
 
288
                case XMPP::NameRecord::Aaaa:
 
289
                        dbg.nospace() << "Aaaa";
 
290
                        break;
 
291
                case XMPP::NameRecord::Mx:
 
292
                        dbg.nospace() << "Mx";
 
293
                        break;
 
294
                case XMPP::NameRecord::Srv:
 
295
                        dbg.nospace() << "Srv";
 
296
                        break;
 
297
                case XMPP::NameRecord::Cname:
 
298
                        dbg.nospace() << "Cname";
 
299
                        break;
 
300
                case XMPP::NameRecord::Ptr:
 
301
                        dbg.nospace() << "Ptr";
 
302
                        break;
 
303
                case XMPP::NameRecord::Txt:
 
304
                        dbg.nospace() << "Txt";
 
305
                        break;
 
306
                case XMPP::NameRecord::Hinfo:
 
307
                        dbg.nospace() << "Hinfo";
 
308
                        break;
 
309
                case XMPP::NameRecord::Ns:
 
310
                        dbg.nospace() << "Ns";
 
311
                        break;
 
312
                case XMPP::NameRecord::Null:
 
313
                        dbg.nospace() << "Null";
 
314
                        break;
 
315
                case XMPP::NameRecord::Any:
 
316
                        dbg.nospace() << "Any";
 
317
                        break;
 
318
        }
 
319
 
 
320
        return dbg;
 
321
}
 
322
 
 
323
QDebug operator<<(QDebug dbg, const XMPP::NameRecord &record)
 
324
{
 
325
        dbg.nospace() << "XMPP::NameRecord("
 
326
                << "owner=" << record.owner()
 
327
                << ", ttl=" << record.ttl()
 
328
                << ", type=" << record.type();
 
329
 
 
330
        switch(record.type())
 
331
        {
 
332
                case XMPP::NameRecord::A:
 
333
                case XMPP::NameRecord::Aaaa:
 
334
                        dbg.nospace() << ", address=" << record.address();
 
335
                        break;
 
336
                case XMPP::NameRecord::Mx:
 
337
                        dbg.nospace()
 
338
                                << ", name=" << record.name()
 
339
                                << ", priority=" << record.priority();
 
340
                        break;
 
341
                case XMPP::NameRecord::Srv:
 
342
                        dbg.nospace()
 
343
                                << ", name=" << record.name()
 
344
                                << ", port=" << record.port()
 
345
                                << ", priority=" << record.priority()
 
346
                                << ", weight=" << record.weight();
 
347
                        break;
 
348
                case XMPP::NameRecord::Cname:
 
349
                case XMPP::NameRecord::Ptr:
 
350
                case XMPP::NameRecord::Ns:
 
351
                        dbg.nospace() << ", name=" << record.name();
 
352
                        break;
 
353
                case XMPP::NameRecord::Txt:
 
354
                        dbg.nospace() << ", texts={" << record.texts() << "}";
 
355
                        break;
 
356
                case XMPP::NameRecord::Hinfo:
 
357
                        dbg.nospace() << ", cpu=" << record.cpu() << ", os=" << record.os();
 
358
                        break;
 
359
                case XMPP::NameRecord::Null:
 
360
                        dbg.nospace() << ", size=" << record.rawData().size();
 
361
                        break;
 
362
                case XMPP::NameRecord::Any:
 
363
                        dbg.nospace() << ", <unknown>";
 
364
                        // should not happen
 
365
                        Q_ASSERT(false);
 
366
                        break;
 
367
        }
 
368
 
 
369
        dbg.nospace() << ")";
 
370
 
 
371
        return dbg;
 
372
}
 
373
 
 
374
//----------------------------------------------------------------------------
 
375
// ServiceInstance
 
376
//----------------------------------------------------------------------------
 
377
class ServiceInstance::Private : public QSharedData
 
378
{
 
379
public:
 
380
        QString instance, type, domain;
 
381
        QMap<QString,QByteArray> attribs;
 
382
        QByteArray name;
 
383
};
 
384
 
 
385
ServiceInstance::ServiceInstance()
 
386
{
 
387
        d = new Private;
 
388
}
 
389
 
 
390
ServiceInstance::ServiceInstance(const QString &instance, const QString &type, const QString &domain, const QMap<QString,QByteArray> &attribs)
 
391
{
 
392
        d = new Private;
 
393
        d->instance = instance;
 
394
        d->type = type;
 
395
        d->domain = domain;
 
396
        d->attribs = attribs;
 
397
 
 
398
        // FIXME: escape the items
 
399
        d->name = instance.toLatin1() + '.' + type.toLatin1() + '.' + domain.toLatin1();
 
400
}
 
401
 
 
402
ServiceInstance::ServiceInstance(const ServiceInstance &from)
 
403
{
 
404
        d = 0;
 
405
        *this = from;
 
406
}
 
407
 
 
408
ServiceInstance::~ServiceInstance()
 
409
{
 
410
}
 
411
 
 
412
ServiceInstance & ServiceInstance::operator=(const ServiceInstance &from)
 
413
{
 
414
        d = from.d;
 
415
        return *this;
 
416
}
 
417
 
 
418
QString ServiceInstance::instance() const
 
419
{
 
420
        return d->instance;
 
421
}
 
422
 
 
423
QString ServiceInstance::type() const
 
424
{
 
425
        return d->type;
 
426
}
 
427
 
 
428
QString ServiceInstance::domain() const
 
429
{
 
430
        return d->domain;
 
431
}
 
432
 
 
433
QMap<QString,QByteArray> ServiceInstance::attributes() const
 
434
{
 
435
        return d->attribs;
 
436
}
 
437
 
 
438
QByteArray ServiceInstance::name() const
 
439
{
 
440
        return d->name;
 
441
}
 
442
 
 
443
//----------------------------------------------------------------------------
 
444
// NameManager
 
445
//----------------------------------------------------------------------------
 
446
class NameManager;
 
447
 
 
448
Q_GLOBAL_STATIC(QMutex, nman_mutex)
 
449
static NameManager *g_nman = 0;
 
450
 
 
451
class NameResolver::Private
 
452
{
 
453
public:
 
454
        NameResolver *q;
 
455
 
 
456
        int type;
 
457
        bool longLived;
 
458
        int id;
 
459
 
 
460
        Private(NameResolver *_q) : q(_q)
 
461
        {
 
462
        }
 
463
};
 
464
 
 
465
class ServiceBrowser::Private
 
466
{
 
467
public:
 
468
        ServiceBrowser *q;
 
469
 
 
470
        int id;
 
471
 
 
472
        Private(ServiceBrowser *_q) : q(_q)
 
473
        {
 
474
        }
 
475
};
 
476
 
 
477
class ServiceResolver::Private : public QObject
 
478
{
 
479
        Q_OBJECT
 
480
public:
 
481
        Private(ServiceResolver *parent)
 
482
         : q(parent), dns_sd_resolve_id(0), requestedProtocol(IPv6_IPv4), port(0), protocol(QAbstractSocket::IPv6Protocol)
 
483
        {
 
484
        }
 
485
 
 
486
        /* DNS-SD interaction with NameManager */
 
487
        ServiceResolver *q; //!< Pointing upwards, so NameManager can call its signals
 
488
        int dns_sd_resolve_id; //!< DNS-SD lookup id, set by NameManager
 
489
 
 
490
        /* configuration */
 
491
        Protocol requestedProtocol; //!< IP protocol requested by user
 
492
 
 
493
        /* state trackers */
 
494
        QString domain; //!< Domain we are currently looking up
 
495
        QString host; //!< Hostname we are currently looking up
 
496
        QHostAddress address; //!< IP address we are currently looking up
 
497
        quint16 port; //!< Port we are currently looking up
 
498
        QAbstractSocket::NetworkLayerProtocol protocol; //!< IP protocol we are currently looking up
 
499
 
 
500
        XMPP::WeightedNameRecordList srvList; //!< List of resolved SRV names
 
501
        QList<XMPP::NameRecord> hostList; //!< List or resolved hostnames for current SRV name
 
502
        QList<XMPP::NameResolver*> resolverList; //!< NameResolvers currently in use, needed for cleanup
 
503
 
 
504
};
 
505
 
 
506
 
 
507
WeightedNameRecordList::WeightedNameRecordList()
 
508
        : currentPriorityGroup(priorityGroups.end()) /* void current state */
 
509
{}
 
510
 
 
511
WeightedNameRecordList::WeightedNameRecordList(const QList<XMPP::NameRecord> &list)
 
512
{
 
513
        append(list);
 
514
}
 
515
 
 
516
WeightedNameRecordList::~WeightedNameRecordList() {
 
517
}
 
518
 
 
519
bool WeightedNameRecordList::isEmpty() const {
 
520
        return currentPriorityGroup == const_cast<WeightedNameRecordList *>(this)->priorityGroups.end();
 
521
}
 
522
 
 
523
XMPP::NameRecord WeightedNameRecordList::takeNext() {
 
524
        /* Find the next useful priority group */
 
525
        while (currentPriorityGroup != priorityGroups.end() && currentPriorityGroup->empty()) {
 
526
                currentPriorityGroup++;
 
527
        }
 
528
        /* There are no priority groups left, return failure */
 
529
        if (currentPriorityGroup == priorityGroups.end()) {
 
530
#ifdef NETNAMES_DEBUG
 
531
                NNDEBUG << "No more SRV records left";
 
532
#endif
 
533
                return XMPP::NameRecord();
 
534
        }
 
535
 
 
536
        /* Find the new total weight of this priority group */
 
537
        int totalWeight = 0;
 
538
        foreach (const XMPP::NameRecord &record, *currentPriorityGroup) {
 
539
                totalWeight += record.weight();
 
540
        }
 
541
 
 
542
#ifdef NETNAMES_DEBUG
 
543
        NNDEBUG << "Total weight:" << totalWeight;
 
544
#endif
 
545
 
 
546
        /* Pick a random entry */
 
547
        int randomWeight = qrand()/static_cast<float>(RAND_MAX)*totalWeight;
 
548
 
 
549
#ifdef NETNAMES_DEBUG
 
550
        NNDEBUG << "Picked weight:" << randomWeight;
 
551
#endif
 
552
 
 
553
        /* Iterate through the priority group until we found the randomly selected entry */
 
554
        WeightedNameRecordPriorityGroup::iterator it(currentPriorityGroup->begin());
 
555
        for (int currentWeight = it->weight(); currentWeight < randomWeight; currentWeight += (++it)->weight()) {}
 
556
        Q_ASSERT(it != currentPriorityGroup->end());
 
557
 
 
558
        /* We are going to delete the entry in the list, so save it */
 
559
        XMPP::NameRecord result(*it);
 
560
 
 
561
#ifdef NETNAMES_DEBUG
 
562
        NNDEBUG << "Picked record:" << result;
 
563
#endif
 
564
 
 
565
        /* Delete the entry from list, to prevent it from being tried multiple times */
 
566
        currentPriorityGroup->remove(it->weight(), *it);
 
567
        if (currentPriorityGroup->isEmpty()) {
 
568
                priorityGroups.erase(currentPriorityGroup++);
 
569
        }
 
570
 
 
571
        return result;
 
572
}
 
573
 
 
574
void WeightedNameRecordList::clear() {
 
575
        priorityGroups.clear();
 
576
 
 
577
        /* void current state */
 
578
        currentPriorityGroup = priorityGroups.end();
 
579
}
 
580
 
 
581
void WeightedNameRecordList::append(const XMPP::WeightedNameRecordList &list) {
 
582
        /* Copy over all records from all groups */
 
583
        foreach (const WeightedNameRecordPriorityGroup &group, list.priorityGroups) {
 
584
                foreach(const NameRecord& record, group) {
 
585
                        append(record);
 
586
                }
 
587
        }
 
588
 
 
589
        /* Reset to beginning */
 
590
        currentPriorityGroup = priorityGroups.begin();
 
591
}
 
592
 
 
593
void WeightedNameRecordList::append(const QList<XMPP::NameRecord> &list) {
 
594
        foreach (const XMPP::NameRecord &record, list) {
 
595
                WeightedNameRecordPriorityGroup group(priorityGroups.value(record.priority()));
 
596
 
 
597
                group.insert(record.weight(), record);
 
598
 
 
599
                if (!priorityGroups.contains(record.priority())) {
 
600
                        priorityGroups.insert(record.priority(), group);
 
601
                }
 
602
        }
 
603
 
 
604
        /* Reset to beginning */
 
605
        currentPriorityGroup = priorityGroups.begin();
 
606
}
 
607
 
 
608
void WeightedNameRecordList::append(const XMPP::NameRecord &record) {
 
609
        WeightedNameRecordPriorityGroup group(priorityGroups.value(record.priority()));
 
610
 
 
611
        group.insert(record.weight(), record);
 
612
 
 
613
        if (!priorityGroups.contains(record.priority())) {
 
614
                priorityGroups.insert(record.priority(), group);
 
615
        }
 
616
 
 
617
        /* Reset to beginning */
 
618
        currentPriorityGroup = priorityGroups.begin();
 
619
}
 
620
 
 
621
void WeightedNameRecordList::append(const QString &hostname, quint16 port) {
 
622
        NameRecord record(hostname.toLocal8Bit(), std::numeric_limits<int>::max());
 
623
        record.setSrv(hostname.toLocal8Bit(), port, std::numeric_limits<int>::max(), 0);
 
624
 
 
625
        append(record);
 
626
 
 
627
        /* Reset to beginning */
 
628
        currentPriorityGroup = priorityGroups.begin();
 
629
}
 
630
 
 
631
XMPP::WeightedNameRecordList& WeightedNameRecordList::operator<<(const XMPP::WeightedNameRecordList &list) {
 
632
        append(list);
 
633
        return *this;
 
634
}
 
635
 
 
636
WeightedNameRecordList& WeightedNameRecordList::operator<<(const QList<NameRecord> &list) {
 
637
        append(list);
 
638
        return *this;
 
639
}
 
640
 
 
641
XMPP::WeightedNameRecordList& WeightedNameRecordList::operator<<(const XMPP::NameRecord &record) {
 
642
        append(record);
 
643
        return *this;
 
644
}
 
645
 
 
646
 
 
647
QDebug operator<<(QDebug dbg, const XMPP::WeightedNameRecordList &list) {
 
648
        dbg.nospace() << "XMPP::WeightedNameRecordList(\n";
 
649
 
 
650
        /* operator(QDebug, QMap const&) has a bug which makes it crash when trying to print the dereferenced end() iterator */
 
651
        if (!list.isEmpty()) {
 
652
                dbg.nospace() << "current=" << *list.currentPriorityGroup << endl;
 
653
        }
 
654
 
 
655
        dbg.nospace() << "{";
 
656
 
 
657
        foreach(int priority, list.priorityGroups.keys()) {
 
658
                dbg.nospace() << "\t" << priority << "->" << list.priorityGroups.value(priority) << endl;
 
659
        }
 
660
 
 
661
        dbg.nospace() << "})";
 
662
        return dbg;
 
663
}
 
664
 
 
665
 
 
666
class ServiceLocalPublisher::Private
 
667
{
 
668
public:
 
669
        ServiceLocalPublisher *q;
 
670
 
 
671
        int id;
 
672
 
 
673
        Private(ServiceLocalPublisher *_q) : q(_q)
 
674
        {
 
675
        }
 
676
};
 
677
 
 
678
class NameManager : public QObject
 
679
{
 
680
        Q_OBJECT
 
681
public:
 
682
        NameProvider *p_net, *p_local;
 
683
        ServiceProvider *p_serv;
 
684
        QHash<int,NameResolver::Private*> res_instances;
 
685
        QHash<int,int> res_sub_instances;
 
686
 
 
687
        QHash<int,ServiceBrowser::Private*> br_instances;
 
688
        QHash<int,ServiceResolver::Private*> sres_instances;
 
689
        QHash<int,ServiceLocalPublisher::Private*> slp_instances;
 
690
 
 
691
        NameManager(QObject *parent = 0) : QObject(parent)
 
692
        {
 
693
                p_net = 0;
 
694
                p_local = 0;
 
695
                p_serv = 0;
 
696
        }
 
697
 
 
698
        ~NameManager()
 
699
        {
 
700
                delete p_net;
 
701
                delete p_local;
 
702
                delete p_serv;
 
703
        }
 
704
 
 
705
        static NameManager *instance()
 
706
        {
 
707
                QMutexLocker locker(nman_mutex());
 
708
                if(!g_nman)
 
709
                {
 
710
                        g_nman = new NameManager;
 
711
                        irisNetAddPostRoutine(NetNames::cleanup);
 
712
                }
 
713
                return g_nman;
 
714
        }
 
715
 
 
716
        static void cleanup()
 
717
        {
 
718
                delete g_nman;
 
719
                g_nman = 0;
 
720
        }
 
721
 
 
722
        void resolve_start(NameResolver::Private *np, const QByteArray &name, int qType, bool longLived)
 
723
        {
 
724
                QMutexLocker locker(nman_mutex());
 
725
 
 
726
                np->type = qType;
 
727
                np->longLived = longLived;
 
728
                if(!p_net)
 
729
                {
 
730
                        NameProvider *c = 0;
 
731
                        QList<IrisNetProvider*> list = irisNetProviders();
 
732
                        for(int n = 0; n < list.count(); ++n)
 
733
                        {
 
734
                                IrisNetProvider *p = list[n];
 
735
                                c = p->createNameProviderInternet();
 
736
                                if(c)
 
737
                                        break;
 
738
                        }
 
739
                        Q_ASSERT(c); // we have built-in support, so this should never fail
 
740
                        p_net = c;
 
741
 
 
742
                        // use queued connections
 
743
                        qRegisterMetaType< QList<XMPP::NameRecord> >("QList<XMPP::NameRecord>");
 
744
                        qRegisterMetaType<XMPP::NameResolver::Error>("XMPP::NameResolver::Error");
 
745
                        connect(p_net, SIGNAL(resolve_resultsReady(int, const QList<XMPP::NameRecord> &)), SLOT(provider_resolve_resultsReady(int, const QList<XMPP::NameRecord> &)));
 
746
                        connect(p_net, SIGNAL(resolve_error(int, XMPP::NameResolver::Error)), SLOT(provider_resolve_error(int, XMPP::NameResolver::Error)));
 
747
                        connect(p_net, SIGNAL(resolve_useLocal(int, const QByteArray &)), SLOT(provider_resolve_useLocal(int, const QByteArray &)));
 
748
                }
 
749
 
 
750
                np->id = p_net->resolve_start(name, qType, longLived);
 
751
 
 
752
                //printf("assigning %d to %p\n", req_id, np);
 
753
                res_instances.insert(np->id, np);
 
754
        }
 
755
 
 
756
        void resolve_stop(NameResolver::Private *np)
 
757
        {
 
758
                // FIXME: stop sub instances?
 
759
                p_net->resolve_stop(np->id);
 
760
                resolve_cleanup(np);
 
761
        }
 
762
 
 
763
        void resolve_cleanup(NameResolver::Private *np)
 
764
        {
 
765
                // clean up any sub instances
 
766
 
 
767
                QList<int> sub_instances_to_remove;
 
768
                QHashIterator<int, int> it(res_sub_instances);
 
769
                while(it.hasNext())
 
770
                {
 
771
                        it.next();
 
772
                        if(it.value() == np->id)
 
773
                                sub_instances_to_remove += it.key();
 
774
                }
 
775
 
 
776
                foreach(int res_sub_id, sub_instances_to_remove)
 
777
                {
 
778
                        res_sub_instances.remove(res_sub_id);
 
779
                        p_local->resolve_stop(res_sub_id);
 
780
                }
 
781
 
 
782
                // clean up primary instance
 
783
 
 
784
                res_instances.remove(np->id);
 
785
                NameResolver *q = np->q;
 
786
                delete q->d;
 
787
                q->d = 0;
 
788
        }
 
789
 
 
790
        void browse_start(ServiceBrowser::Private *np, const QString &type, const QString &domain)
 
791
        {
 
792
                QMutexLocker locker(nman_mutex());
 
793
 
 
794
                if(!p_serv)
 
795
                {
 
796
                        ServiceProvider *c = 0;
 
797
                        QList<IrisNetProvider*> list = irisNetProviders();
 
798
                        for(int n = 0; n < list.count(); ++n)
 
799
                        {
 
800
                                IrisNetProvider *p = list[n];
 
801
                                c = p->createServiceProvider();
 
802
                                if(c)
 
803
                                        break;
 
804
                        }
 
805
                        Q_ASSERT(c); // we have built-in support, so this should never fail
 
806
                        p_serv = c;
 
807
 
 
808
                        // use queued connections
 
809
                        qRegisterMetaType<XMPP::ServiceInstance>("XMPP::ServiceInstance");
 
810
                        qRegisterMetaType<XMPP::ServiceBrowser::Error>("XMPP::ServiceBrowser::Error");
 
811
 
 
812
                        connect(p_serv, SIGNAL(browse_instanceAvailable(int, const XMPP::ServiceInstance &)), SLOT(provider_browse_instanceAvailable(int, const XMPP::ServiceInstance &)), Qt::QueuedConnection);
 
813
                        connect(p_serv, SIGNAL(browse_instanceUnavailable(int, const XMPP::ServiceInstance &)), SLOT(provider_browse_instanceUnavailable(int, const XMPP::ServiceInstance &)), Qt::QueuedConnection);
 
814
                        connect(p_serv, SIGNAL(browse_error(int, XMPP::ServiceBrowser::Error)), SLOT(provider_browse_error(int, XMPP::ServiceBrowser::Error)), Qt::QueuedConnection);
 
815
                }
 
816
 
 
817
                /*np->id = */
 
818
 
 
819
                np->id = p_serv->browse_start(type, domain);
 
820
 
 
821
                br_instances.insert(np->id, np);
 
822
        }
 
823
 
 
824
        void resolve_instance_start(ServiceResolver::Private *np, const QByteArray &name)
 
825
        {
 
826
                QMutexLocker locker(nman_mutex());
 
827
 
 
828
                if(!p_serv)
 
829
                {
 
830
                        ServiceProvider *c = 0;
 
831
                        QList<IrisNetProvider*> list = irisNetProviders();
 
832
                        for(int n = 0; n < list.count(); ++n)
 
833
                        {
 
834
                                IrisNetProvider *p = list[n];
 
835
                                c = p->createServiceProvider();
 
836
                                if(c)
 
837
                                        break;
 
838
                        }
 
839
                        Q_ASSERT(c); // we have built-in support, so this should never fail
 
840
                        p_serv = c;
 
841
 
 
842
                        // use queued connections
 
843
                        qRegisterMetaType<QHostAddress>("QHostAddress");
 
844
                        qRegisterMetaType< QList<XMPP::ServiceProvider::ResolveResult> >("QList<XMPP::ServiceProvider::ResolveResult>");
 
845
                        connect(p_serv, SIGNAL(resolve_resultsReady(int, const QList<XMPP::ServiceProvider::ResolveResult> &)), SLOT(provider_resolve_resultsReady(int, const QList<XMPP::ServiceProvider::ResolveResult> &)), Qt::QueuedConnection);
 
846
                }
 
847
 
 
848
                /* store the id so we can stop it later */
 
849
                np->dns_sd_resolve_id = p_serv->resolve_start(name);
 
850
 
 
851
                sres_instances.insert(np->dns_sd_resolve_id, np);
 
852
        }
 
853
 
 
854
        void publish_start(ServiceLocalPublisher::Private *np, const QString &instance, const QString &type, int port, const QMap<QString,QByteArray> &attribs)
 
855
        {
 
856
                QMutexLocker locker(nman_mutex());
 
857
 
 
858
                if(!p_serv)
 
859
                {
 
860
                        ServiceProvider *c = 0;
 
861
                        QList<IrisNetProvider*> list = irisNetProviders();
 
862
                        for(int n = 0; n < list.count(); ++n)
 
863
                        {
 
864
                                IrisNetProvider *p = list[n];
 
865
                                c = p->createServiceProvider();
 
866
                                if(c)
 
867
                                        break;
 
868
                        }
 
869
                        Q_ASSERT(c); // we have built-in support, so this should never fail
 
870
                        p_serv = c;
 
871
 
 
872
                        // use queued connections
 
873
                        qRegisterMetaType<XMPP::ServiceLocalPublisher::Error>("XMPP::ServiceLocalPublisher::Error");
 
874
                        connect(p_serv, SIGNAL(publish_published(int)), SLOT(provider_publish_published(int)), Qt::QueuedConnection);
 
875
                        connect(p_serv, SIGNAL(publish_extra_published(int)), SLOT(provider_publish_extra_published(int)), Qt::QueuedConnection);
 
876
                }
 
877
 
 
878
                /*np->id = */
 
879
 
 
880
                np->id = p_serv->publish_start(instance, type, port, attribs);
 
881
 
 
882
                slp_instances.insert(np->id, np);
 
883
        }
 
884
 
 
885
        void publish_extra_start(ServiceLocalPublisher::Private *np, const NameRecord &rec)
 
886
        {
 
887
                np->id = p_serv->publish_extra_start(np->id, rec);
 
888
        }
 
889
 
 
890
private slots:
 
891
        void provider_resolve_resultsReady(int id, const QList<XMPP::NameRecord> &results)
 
892
        {
 
893
                NameResolver::Private *np = res_instances.value(id);
 
894
                NameResolver *q = np->q; // resolve_cleanup deletes np
 
895
                if(!np->longLived)
 
896
                        resolve_cleanup(np);
 
897
                emit q->resultsReady(results);
 
898
        }
 
899
 
 
900
        void provider_resolve_error(int id, XMPP::NameResolver::Error e)
 
901
        {
 
902
                NameResolver::Private *np = res_instances.value(id);
 
903
                NameResolver *q = np->q; // resolve_cleanup deletes np
 
904
                resolve_cleanup(np);
 
905
                emit q->error(e);
 
906
        }
 
907
 
 
908
        void provider_local_resolve_resultsReady(int id, const QList<XMPP::NameRecord> &results)
 
909
        {
 
910
                int par_id = res_sub_instances.value(id);
 
911
                NameResolver::Private *np = res_instances.value(par_id);
 
912
                if(!np->longLived)
 
913
                        res_sub_instances.remove(id);
 
914
                p_net->resolve_localResultsReady(par_id, results);
 
915
        }
 
916
 
 
917
        void provider_local_resolve_error(int id, XMPP::NameResolver::Error e)
 
918
        {
 
919
                int par_id = res_sub_instances.value(id);
 
920
                res_sub_instances.remove(id);
 
921
                p_net->resolve_localError(par_id, e);
 
922
        }
 
923
 
 
924
        void provider_resolve_useLocal(int id, const QByteArray &name)
 
925
        {
 
926
                // transfer to local
 
927
                if(!p_local)
 
928
                {
 
929
                        NameProvider *c = 0;
 
930
                        QList<IrisNetProvider*> list = irisNetProviders();
 
931
                        for(int n = 0; n < list.count(); ++n)
 
932
                        {
 
933
                                IrisNetProvider *p = list[n];
 
934
                                c = p->createNameProviderLocal();
 
935
                                if(c)
 
936
                                        break;
 
937
                        }
 
938
                        Q_ASSERT(c); // we have built-in support, so this should never fail
 
939
                        // FIXME: not true, binding can fail
 
940
                        p_local = c;
 
941
 
 
942
                        // use queued connections
 
943
                        qRegisterMetaType< QList<XMPP::NameRecord> >("QList<XMPP::NameRecord>");
 
944
                        qRegisterMetaType<XMPP::NameResolver::Error>("XMPP::NameResolver::Error");
 
945
                        connect(p_local, SIGNAL(resolve_resultsReady(int, const QList<XMPP::NameRecord> &)), SLOT(provider_local_resolve_resultsReady(int, const QList<XMPP::NameRecord> &)), Qt::QueuedConnection);
 
946
                        connect(p_local, SIGNAL(resolve_error(int, XMPP::NameResolver::Error)), SLOT(provider_local_resolve_error(int, XMPP::NameResolver::Error)), Qt::QueuedConnection);
 
947
                }
 
948
 
 
949
                NameResolver::Private *np = res_instances.value(id);
 
950
 
 
951
                /*// transfer to local only
 
952
                if(np->longLived)
 
953
                {
 
954
                        res_instances.remove(np->id);
 
955
 
 
956
                        np->id = p_local->resolve_start(name, np->type, true);
 
957
                        res_instances.insert(np->id, np);
 
958
                }
 
959
                // sub request
 
960
                else
 
961
                {
 
962
                        int req_id = p_local->resolve_start(name, np->type, false);
 
963
 
 
964
                        res_sub_instances.insert(req_id, np->id);
 
965
                }*/
 
966
 
 
967
                int req_id = p_local->resolve_start(name, np->type, np->longLived);
 
968
                res_sub_instances.insert(req_id, np->id);
 
969
        }
 
970
 
 
971
        void provider_browse_instanceAvailable(int id, const XMPP::ServiceInstance &i)
 
972
        {
 
973
                ServiceBrowser::Private *np = br_instances.value(id);
 
974
                emit np->q->instanceAvailable(i);
 
975
        }
 
976
 
 
977
        void provider_browse_instanceUnavailable(int id, const XMPP::ServiceInstance &i)
 
978
        {
 
979
                ServiceBrowser::Private *np = br_instances.value(id);
 
980
                emit np->q->instanceUnavailable(i);
 
981
        }
 
982
 
 
983
        void provider_browse_error(int id, XMPP::ServiceBrowser::Error e)
 
984
        {
 
985
                Q_UNUSED(e);
 
986
                ServiceBrowser::Private *np = br_instances.value(id);
 
987
                // TODO
 
988
                emit np->q->error();
 
989
        }
 
990
 
 
991
        void provider_resolve_resultsReady(int id, const QList<XMPP::ServiceProvider::ResolveResult> &results)
 
992
        {
 
993
                ServiceResolver::Private *np = sres_instances.value(id);
 
994
                emit np->q->resultReady(results[0].address, results[0].port);
 
995
        }
 
996
 
 
997
        void provider_publish_published(int id)
 
998
        {
 
999
                ServiceLocalPublisher::Private *np = slp_instances.value(id);
 
1000
                emit np->q->published();
 
1001
        }
 
1002
 
 
1003
        void provider_publish_extra_published(int id)
 
1004
        {
 
1005
                Q_UNUSED(id);
 
1006
                //ServiceLocalPublisher::Private *np = slp_instances.value(id);
 
1007
                //emit np->q->published();
 
1008
        }
 
1009
};
 
1010
 
 
1011
//----------------------------------------------------------------------------
 
1012
// NameResolver
 
1013
//----------------------------------------------------------------------------
 
1014
 
 
1015
// copied from JDNS
 
1016
#define JDNS_RTYPE_A         1
 
1017
#define JDNS_RTYPE_AAAA     28
 
1018
#define JDNS_RTYPE_MX       15
 
1019
#define JDNS_RTYPE_SRV      33
 
1020
#define JDNS_RTYPE_CNAME     5
 
1021
#define JDNS_RTYPE_PTR      12
 
1022
#define JDNS_RTYPE_TXT      16
 
1023
#define JDNS_RTYPE_HINFO    13
 
1024
#define JDNS_RTYPE_NS        2
 
1025
#define JDNS_RTYPE_ANY     255
 
1026
 
 
1027
static int recordType2Rtype(NameRecord::Type type)
 
1028
{
 
1029
        switch(type)
 
1030
        {
 
1031
                case NameRecord::A:     return JDNS_RTYPE_A;
 
1032
                case NameRecord::Aaaa:  return JDNS_RTYPE_AAAA;
 
1033
                case NameRecord::Mx:    return JDNS_RTYPE_MX;
 
1034
                case NameRecord::Srv:   return JDNS_RTYPE_SRV;
 
1035
                case NameRecord::Cname: return JDNS_RTYPE_CNAME;
 
1036
                case NameRecord::Ptr:   return JDNS_RTYPE_PTR;
 
1037
                case NameRecord::Txt:   return JDNS_RTYPE_TXT;
 
1038
                case NameRecord::Hinfo: return JDNS_RTYPE_HINFO;
 
1039
                case NameRecord::Ns:    return JDNS_RTYPE_NS;
 
1040
                case NameRecord::Null:  return 10;
 
1041
                case NameRecord::Any:   return JDNS_RTYPE_ANY;
 
1042
        }
 
1043
        return -1;
 
1044
}
 
1045
 
 
1046
NameResolver::NameResolver(QObject *parent)
 
1047
:QObject(parent)
 
1048
{
 
1049
        d = 0;
 
1050
}
 
1051
 
 
1052
NameResolver::~NameResolver()
 
1053
{
 
1054
        stop();
 
1055
}
 
1056
 
 
1057
void NameResolver::start(const QByteArray &name, NameRecord::Type type, Mode mode)
 
1058
{
 
1059
        stop();
 
1060
        d = new Private(this);
 
1061
        int qType = recordType2Rtype(type);
 
1062
        if(qType == -1)
 
1063
                qType = JDNS_RTYPE_A;
 
1064
        NameManager::instance()->resolve_start(d, name, qType, mode == NameResolver::LongLived ? true : false);
 
1065
}
 
1066
 
 
1067
void NameResolver::stop()
 
1068
{
 
1069
        if(d)
 
1070
        {
 
1071
                NameManager::instance()->resolve_stop(d);
 
1072
                delete d;
 
1073
                d = 0;
 
1074
        }
 
1075
}
 
1076
 
 
1077
QDebug operator<<(QDebug dbg, XMPP::NameResolver::Error e)
 
1078
{
 
1079
        dbg.nospace() << "XMPP::NameResolver::";
 
1080
 
 
1081
        switch(e)
 
1082
        {
 
1083
                case XMPP::NameResolver::ErrorGeneric:
 
1084
                        dbg.nospace() << "ErrorGeneric";
 
1085
                        break;
 
1086
                case XMPP::NameResolver::ErrorNoName:
 
1087
                        dbg.nospace() << "ErrorNoName";
 
1088
                        break;
 
1089
                case XMPP::NameResolver::ErrorTimeout:
 
1090
                        dbg.nospace() << "ErrorTimeout";
 
1091
                        break;
 
1092
                case XMPP::NameResolver::ErrorNoLocal:
 
1093
                        dbg.nospace() << "ErrorNoLocal";
 
1094
                        break;
 
1095
                case XMPP::NameResolver::ErrorNoLongLived:
 
1096
                        dbg.nospace() << "ErrorNoLongLived";
 
1097
                        break;
 
1098
        }
 
1099
 
 
1100
        return dbg;
 
1101
}
 
1102
 
 
1103
 
 
1104
//----------------------------------------------------------------------------
 
1105
// ServiceBrowser
 
1106
//----------------------------------------------------------------------------
 
1107
ServiceBrowser::ServiceBrowser(QObject *parent)
 
1108
:QObject(parent)
 
1109
{
 
1110
        d = new Private(this);
 
1111
}
 
1112
 
 
1113
ServiceBrowser::~ServiceBrowser()
 
1114
{
 
1115
        delete d;
 
1116
}
 
1117
 
 
1118
void ServiceBrowser::start(const QString &type, const QString &domain)
 
1119
{
 
1120
        NameManager::instance()->browse_start(d, type, domain);
 
1121
}
 
1122
 
 
1123
void ServiceBrowser::stop()
 
1124
{
 
1125
}
 
1126
 
 
1127
 
 
1128
//----------------------------------------------------------------------------
 
1129
// ServiceResolver
 
1130
//----------------------------------------------------------------------------
 
1131
ServiceResolver::ServiceResolver(QObject *parent)
 
1132
        : QObject(parent)
 
1133
{
 
1134
#ifdef NETNAMES_DEBUG
 
1135
        NNDEBUG;
 
1136
#endif
 
1137
 
 
1138
        d = new Private(this);
 
1139
}
 
1140
 
 
1141
ServiceResolver::~ServiceResolver()
 
1142
{
 
1143
        delete d;
 
1144
}
 
1145
 
 
1146
void ServiceResolver::clear_resolvers()
 
1147
{
 
1148
#ifdef NETNAMES_DEBUG
 
1149
        NNDEBUG;
 
1150
#endif
 
1151
 
 
1152
        /* cleanup all resolvers */
 
1153
        foreach (XMPP::NameResolver *resolver, d->resolverList) {
 
1154
                cleanup_resolver(resolver);
 
1155
        }
 
1156
}
 
1157
 
 
1158
void ServiceResolver::cleanup_resolver(XMPP::NameResolver *resolver)
 
1159
{
 
1160
#ifdef NETNAMES_DEBUG
 
1161
        NNDEBUG << "r:" << resolver;
 
1162
#endif
 
1163
 
 
1164
        if (resolver) {
 
1165
                /*
 
1166
                do not just "delete", because we might have been called from a slot
 
1167
                that was invoked by the resolver, and we do not want to create a mess
 
1168
                there.
 
1169
                */
 
1170
                disconnect(resolver);
 
1171
                resolver->stop();
 
1172
                resolver->deleteLater();
 
1173
 
 
1174
                d->resolverList.removeAll(resolver);
 
1175
        }
 
1176
}
 
1177
 
 
1178
ServiceResolver::Protocol ServiceResolver::protocol() const {
 
1179
        return d->requestedProtocol;
 
1180
}
 
1181
 
 
1182
void ServiceResolver::setProtocol(ServiceResolver::Protocol p) {
 
1183
        d->requestedProtocol = p;
 
1184
}
 
1185
 
 
1186
/* DNS-SD lookup */
 
1187
void ServiceResolver::start(const QByteArray &name) {
 
1188
        NameManager::instance()->resolve_instance_start(d, name);
 
1189
}
 
1190
 
 
1191
/* normal host lookup */
 
1192
void ServiceResolver::start(const QString &host, quint16 port)
 
1193
{
 
1194
#ifdef NETNAMES_DEBUG
 
1195
        NNDEBUG << "h:" << host << "p:" << port;
 
1196
#endif
 
1197
 
 
1198
        /* clear host list */
 
1199
        d->hostList.clear();
 
1200
 
 
1201
        d->protocol = (d->requestedProtocol == IPv6_IPv4 || d->requestedProtocol == IPv6 ? QAbstractSocket::IPv6Protocol : QAbstractSocket::IPv4Protocol);
 
1202
        d->host = host;
 
1203
        d->port = port;
 
1204
 
 
1205
#ifdef NETNAMES_DEBUG
 
1206
        NNDEBUG << "d->p:" << d->protocol;
 
1207
#endif
 
1208
 
 
1209
        /* initiate the host lookup */
 
1210
        XMPP::NameRecord::Type querytype = (d->protocol == QAbstractSocket::IPv6Protocol ? XMPP::NameRecord::Aaaa : XMPP::NameRecord::A);
 
1211
        XMPP::NameResolver *resolver = new XMPP::NameResolver;
 
1212
        connect(resolver, SIGNAL(resultsReady(QList<XMPP::NameRecord>)), this, SLOT(handle_host_ready(QList<XMPP::NameRecord>)));
 
1213
        connect(resolver, SIGNAL(error(XMPP::NameResolver::Error)), this, SLOT(handle_host_error(XMPP::NameResolver::Error)));
 
1214
        resolver->start(host.toLocal8Bit(), querytype);
 
1215
        d->resolverList << resolver;
 
1216
}
 
1217
 
 
1218
/* SRV lookup */
 
1219
void ServiceResolver::start(const QString &service, const QString &transport, const QString &domain, int port)
 
1220
{
 
1221
#ifdef NETNAMES_DEBUG
 
1222
        NNDEBUG << "s:" << service << "t:" << transport << "d:" << domain << "p:" << port;
 
1223
#endif
 
1224
 
 
1225
        QString srv_request("_" + service + "._" + transport + "." + domain + ".");
 
1226
 
 
1227
        /* clear SRV list */
 
1228
        d->srvList.clear();
 
1229
 
 
1230
        d->domain = domain;
 
1231
 
 
1232
        /* after we tried all SRV hosts, we shall connect directly (if requested) */
 
1233
        if (port < std::numeric_limits<quint16>::max()) {
 
1234
                d->srvList.append(domain.toLocal8Bit(), port);
 
1235
        }
 
1236
        else {
 
1237
                /* The only "valid" port above the valid port range is our specification of an invalid port */
 
1238
                Q_ASSERT(port == std::numeric_limits<int>::max());
 
1239
        }
 
1240
 
 
1241
        /* initiate the SRV lookup */
 
1242
        XMPP::NameResolver *resolver = new XMPP::NameResolver;
 
1243
        connect(resolver, SIGNAL(resultsReady(QList<XMPP::NameRecord>)), this, SLOT(handle_srv_ready(QList<XMPP::NameRecord>)));
 
1244
        connect(resolver, SIGNAL(error(XMPP::NameResolver::Error)), this, SLOT(handle_srv_error(XMPP::NameResolver::Error)));
 
1245
        resolver->start(srv_request.toLocal8Bit(), XMPP::NameRecord::Srv);
 
1246
        d->resolverList << resolver;
 
1247
}
 
1248
 
 
1249
/* SRV request resolved, now try to connect to the hosts */
 
1250
void ServiceResolver::handle_srv_ready(const QList<XMPP::NameRecord> &r)
 
1251
{
 
1252
#ifdef NETNAMES_DEBUG
 
1253
        NNDEBUG << "sl:" << r;
 
1254
#endif
 
1255
 
 
1256
        /* cleanup resolver */
 
1257
        cleanup_resolver(static_cast<XMPP::NameResolver*>(sender()));
 
1258
 
 
1259
        /* lookup srv pointers */
 
1260
        d->srvList << r;
 
1261
        try_next_srv();
 
1262
}
 
1263
 
 
1264
/* failed the srv lookup, but we might have a fallback host in the srvList */
 
1265
void ServiceResolver::handle_srv_error(XMPP::NameResolver::Error e)
 
1266
{
 
1267
#ifdef NETNAMES_DEBUG
 
1268
        NNDEBUG << "e:" << e;
 
1269
#else
 
1270
        Q_UNUSED(e)
 
1271
#endif
 
1272
 
 
1273
        /* cleanup resolver */
 
1274
        cleanup_resolver(static_cast<XMPP::NameResolver*>(sender()));
 
1275
 
 
1276
        /* srvList already contains a failsafe host, try that */
 
1277
        try_next_srv();
 
1278
}
 
1279
 
 
1280
/* hosts resolved, now try to connect to them */
 
1281
void ServiceResolver::handle_host_ready(const QList<XMPP::NameRecord> &r)
 
1282
{
 
1283
#ifdef NETNAMES_DEBUG
 
1284
        NNDEBUG << "hl:" << r;
 
1285
#endif
 
1286
 
 
1287
        /* cleanup resolver */
 
1288
        cleanup_resolver(static_cast<XMPP::NameResolver*>(sender()));
 
1289
 
 
1290
        /* connect to host */
 
1291
        d->hostList << r;
 
1292
        try_next_host();
 
1293
}
 
1294
 
 
1295
/* failed to lookup the primary record (A or AAAA, depending on user choice) */
 
1296
void ServiceResolver::handle_host_error(XMPP::NameResolver::Error e)
 
1297
{
 
1298
#ifdef NETNAMES_DEBUG
 
1299
        NNDEBUG << "e:" << e;
 
1300
#endif
 
1301
 
 
1302
        /* cleanup resolver */
 
1303
        cleanup_resolver(static_cast<XMPP::NameResolver*>(sender()));
 
1304
 
 
1305
        /* try a fallback lookup if requested*/
 
1306
        if (!lookup_host_fallback()) {
 
1307
                /* no-fallback should behave the same as a failed fallback */
 
1308
                handle_host_fallback_error(e);
 
1309
        }
 
1310
}
 
1311
 
 
1312
/* failed to lookup the fallback record (A or AAAA, depending on user choice) */
 
1313
void ServiceResolver::handle_host_fallback_error(XMPP::NameResolver::Error e)
 
1314
{
 
1315
#ifdef NETNAMES_DEBUG
 
1316
        NNDEBUG << "e:" << e;
 
1317
#else
 
1318
        Q_UNUSED(e)
 
1319
#endif
 
1320
 
 
1321
        /* cleanup resolver */
 
1322
        cleanup_resolver(static_cast<XMPP::NameResolver*>(sender()));
 
1323
 
 
1324
        /* lookup next SRV */
 
1325
        try_next_srv();
 
1326
}
 
1327
 
 
1328
/* check whether a fallback is needed in the current situation */
 
1329
bool ServiceResolver::check_protocol_fallback()
 
1330
{
 
1331
        return (d->requestedProtocol == IPv6_IPv4 && d->protocol == QAbstractSocket::IPv6Protocol)
 
1332
                || (d->requestedProtocol == IPv4_IPv6 && d->protocol == QAbstractSocket::IPv4Protocol);
 
1333
}
 
1334
 
 
1335
/* lookup the fallback host */
 
1336
bool ServiceResolver::lookup_host_fallback() {
 
1337
#ifdef NETNAMES_DEBUG
 
1338
        NNDEBUG;
 
1339
#endif
 
1340
 
 
1341
        /* if a fallback is desired, otherwise we must fail immediately */
 
1342
        if (!check_protocol_fallback()) {
 
1343
                return false;
 
1344
        }
 
1345
 
 
1346
        d->protocol = (d->protocol == QAbstractSocket::IPv6Protocol ? QAbstractSocket::IPv4Protocol : QAbstractSocket::IPv6Protocol);
 
1347
 
 
1348
#ifdef NETNAMES_DEBUG
 
1349
        NNDEBUG << "d->p:" << d->protocol;
 
1350
#endif
 
1351
 
 
1352
        /* initiate the fallback host lookup */
 
1353
        XMPP::NameRecord::Type querytype = (d->protocol == QAbstractSocket::IPv6Protocol ? XMPP::NameRecord::Aaaa : XMPP::NameRecord::A);
 
1354
        XMPP::NameResolver *resolver = new XMPP::NameResolver;
 
1355
        connect(resolver, SIGNAL(resultsReady(QList<XMPP::NameRecord>)), this, SLOT(handle_host_ready(QList<XMPP::NameRecord>)));
 
1356
        connect(resolver, SIGNAL(error(XMPP::NameResolver::Error)), this, SLOT(handle_host_fallback_error(XMPP::NameResolver::Error)));
 
1357
        resolver->start(d->host.toLocal8Bit(), querytype);
 
1358
        d->resolverList << resolver;
 
1359
 
 
1360
        return true;
 
1361
}
 
1362
 
 
1363
/* notify user about next host */
 
1364
bool ServiceResolver::try_next_host() {
 
1365
#ifdef NETNAMES_DEBUG
 
1366
        NNDEBUG << "hl:" << d->hostList;
 
1367
#endif
 
1368
 
 
1369
        /* if there is a host left for current protocol (AAAA or A) */
 
1370
        if (!d->hostList.empty()) {
 
1371
                XMPP::NameRecord record(d->hostList.takeFirst());
 
1372
                /* emit found address and the port specified earlier */
 
1373
                emit resultReady(record.address(), d->port);
 
1374
                return true;
 
1375
        }
 
1376
 
 
1377
        /* otherwise try the fallback protocol */
 
1378
        return lookup_host_fallback();
 
1379
}
 
1380
 
 
1381
/* lookup the next SRV record in line */
 
1382
void ServiceResolver::try_next_srv()
 
1383
{
 
1384
#ifdef NETNAMES_DEBUG
 
1385
        NNDEBUG << "sl:" << d->srvList;
 
1386
#endif
 
1387
 
 
1388
        /* if there are still hosts we did not try */
 
1389
        if (!d->srvList.isEmpty()) {
 
1390
                XMPP::NameRecord record(d->srvList.takeNext());
 
1391
                /* lookup host by name and specify port for later use */
 
1392
                start(record.name(), record.port());
 
1393
        }
 
1394
        else {
 
1395
#ifdef NETNAMES_DEBUG
 
1396
                NNDEBUG << "SRV list empty, failing";
 
1397
#endif
 
1398
                /* no more SRV hosts to try, fail */
 
1399
                emit error(NoHostLeft);
 
1400
        }
 
1401
}
 
1402
 
 
1403
void ServiceResolver::tryNext() {
 
1404
        /* if the host list cannot help, try the SRV list */
 
1405
        if (!try_next_host()) {
 
1406
                 try_next_srv();
 
1407
        }
 
1408
}
 
1409
 
 
1410
void ServiceResolver::stop() {
 
1411
        clear_resolvers();
 
1412
}
 
1413
 
 
1414
bool ServiceResolver::hasPendingSrv() const
 
1415
{
 
1416
        return !d->srvList.isEmpty();
 
1417
}
 
1418
 
 
1419
 
 
1420
//----------------------------------------------------------------------------
 
1421
// ServiceLocalPublisher
 
1422
//----------------------------------------------------------------------------
 
1423
ServiceLocalPublisher::ServiceLocalPublisher(QObject *parent)
 
1424
:QObject(parent)
 
1425
{
 
1426
        d = new Private(this);
 
1427
}
 
1428
 
 
1429
ServiceLocalPublisher::~ServiceLocalPublisher()
 
1430
{
 
1431
        delete d;
 
1432
}
 
1433
 
 
1434
void ServiceLocalPublisher::publish(const QString &instance, const QString &type, int port, const QMap<QString,QByteArray> &attributes)
 
1435
{
 
1436
        NameManager::instance()->publish_start(d, instance, type, port, attributes);
 
1437
}
 
1438
 
 
1439
void ServiceLocalPublisher::updateAttributes(const QMap<QString,QByteArray> &attributes)
 
1440
{
 
1441
        Q_UNUSED(attributes);
 
1442
}
 
1443
 
 
1444
void ServiceLocalPublisher::addRecord(const NameRecord &rec)
 
1445
{
 
1446
        NameManager::instance()->publish_extra_start(d, rec);
 
1447
}
 
1448
 
 
1449
void ServiceLocalPublisher::cancel()
 
1450
{
 
1451
}
 
1452
 
 
1453
//----------------------------------------------------------------------------
 
1454
// NetNames
 
1455
//----------------------------------------------------------------------------
 
1456
void NetNames::cleanup()
 
1457
{
 
1458
        NameManager::cleanup();
 
1459
}
 
1460
 
 
1461
QString NetNames::diagnosticText()
 
1462
{
 
1463
        // TODO
 
1464
        return QString();
 
1465
}
 
1466
 
 
1467
QByteArray NetNames::idnaFromString(const QString &in)
 
1468
{
 
1469
        // TODO
 
1470
        Q_UNUSED(in);
 
1471
        return QByteArray();
 
1472
}
 
1473
 
 
1474
QString NetNames::idnaToString(const QByteArray &in)
 
1475
{
 
1476
        // TODO
 
1477
        Q_UNUSED(in);
 
1478
        return QString();
 
1479
}
 
1480
 
 
1481
QByteArray NetNames::escapeDomain(const QByteArray &in)
 
1482
{
 
1483
        // TODO
 
1484
        Q_UNUSED(in);
 
1485
        return QByteArray();
 
1486
}
 
1487
 
 
1488
QByteArray NetNames::unescapeDomain(const QByteArray &in)
 
1489
{
 
1490
        // TODO
 
1491
        Q_UNUSED(in);
 
1492
        return QByteArray();
 
1493
}
 
1494
 
 
1495
}
 
1496
 
 
1497
#include "netnames.moc"