~ubuntu-branches/ubuntu/jaunty/psi/jaunty

« back to all changes in this revision

Viewing changes to iris/irisnet/netnames_jdns.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2008-04-14 18:57:30 UTC
  • mfrom: (2.1.9 hardy)
  • Revision ID: james.westby@ubuntu.com-20080414185730-528re3zp0m2hdlhi
Tags: 0.11-8
* added CONFIG -= link_prl to .pro files and removed dependencies
  which are made unnecessary by this change
* Fix segfault when closing last chat tab with qt4.4
  (This is from upstream svn, rev. 1101) (Closes: Bug#476122)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2005  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
17
 *
 
18
 */
 
19
 
 
20
#include "irisnetplugin.h"
 
21
 
 
22
#include "jdnsshared.h"
 
23
#include "netinterface.h"
 
24
 
 
25
namespace XMPP {
 
26
 
 
27
NameRecord importJDNSRecord(const QJDns::Record &in)
 
28
{
 
29
        NameRecord out;
 
30
        switch(in.type)
 
31
        {
 
32
                case QJDns::A:     out.setAddress(in.address); break;
 
33
                case QJDns::Aaaa:  out.setAddress(in.address); break;
 
34
                case QJDns::Mx:    out.setMx(in.name, in.priority); break;
 
35
                case QJDns::Srv:   out.setSrv(in.name, in.port, in.priority, in.weight); break;
 
36
                case QJDns::Cname: out.setCname(in.name); break;
 
37
                case QJDns::Ptr:   out.setPtr(in.name); break;
 
38
                case QJDns::Txt:   out.setTxt(in.texts); break;
 
39
                case QJDns::Hinfo: out.setHinfo(in.cpu, in.os); break;
 
40
                case QJDns::Ns:    out.setNs(in.name); break;
 
41
                case 10:           out.setNull(in.rdata); break;
 
42
                default:
 
43
                        return out;
 
44
        }
 
45
        out.setOwner(in.owner);
 
46
        out.setTTL(in.ttl);
 
47
        return out;
 
48
}
 
49
 
 
50
QJDns::Record exportJDNSRecord(const NameRecord &in)
 
51
{
 
52
        QJDns::Record out;
 
53
        switch(in.type())
 
54
        {
 
55
                case NameRecord::A:
 
56
                        out.type = QJDns::A;
 
57
                        out.haveKnown = true;
 
58
                        out.address = in.address();
 
59
                        break;
 
60
                case NameRecord::Aaaa:
 
61
                        out.type = QJDns::Aaaa;
 
62
                        out.haveKnown = true;
 
63
                        out.address = in.address();
 
64
                        break;
 
65
                case NameRecord::Mx:
 
66
                        out.type = QJDns::Mx;
 
67
                        out.haveKnown = true;
 
68
                        out.name = in.name();
 
69
                        out.priority = in.priority();
 
70
                        break;
 
71
                case NameRecord::Srv:
 
72
                        out.type = QJDns::Srv;
 
73
                        out.haveKnown = true;
 
74
                        out.name = in.name();
 
75
                        out.port = in.port();
 
76
                        out.priority = in.priority();
 
77
                        out.weight = in.weight();
 
78
                        break;
 
79
                case NameRecord::Cname:
 
80
                        out.type = QJDns::Cname;
 
81
                        out.haveKnown = true;
 
82
                        out.name = in.name();
 
83
                        break;
 
84
                case NameRecord::Ptr:
 
85
                        out.type = QJDns::Ptr;
 
86
                        out.haveKnown = true;
 
87
                        out.name = in.name();
 
88
                        break;
 
89
                case NameRecord::Txt:
 
90
                        out.type = QJDns::Txt;
 
91
                        out.haveKnown = true;
 
92
                        out.texts = in.texts();
 
93
                        break;
 
94
                case NameRecord::Hinfo:
 
95
                        out.type = QJDns::Hinfo;
 
96
                        out.haveKnown = true;
 
97
                        out.cpu = in.cpu();
 
98
                        out.os = in.os();
 
99
                        break;
 
100
                case NameRecord::Ns:
 
101
                        out.type = QJDns::Ns;
 
102
                        out.haveKnown = true;
 
103
                        out.name = in.name();
 
104
                        break;
 
105
                case NameRecord::Null:
 
106
                        out.type = 10;
 
107
                        out.rdata = in.rawData();
 
108
                        break;
 
109
                default:
 
110
                        return out;
 
111
        }
 
112
        out.owner = in.owner();
 
113
        out.ttl = in.ttl();
 
114
        return out;
 
115
}
 
116
 
 
117
//----------------------------------------------------------------------------
 
118
// JDnsGlobal
 
119
//----------------------------------------------------------------------------
 
120
class JDnsGlobal : public QObject
 
121
{
 
122
        Q_OBJECT
 
123
public:
 
124
        JDnsSharedDebug db;
 
125
        JDnsShared *uni_net, *uni_local, *mul;
 
126
        QHostAddress mul_addr4, mul_addr6;
 
127
 
 
128
        JDnsGlobal()
 
129
        {
 
130
                uni_net = 0;
 
131
                uni_local = 0;
 
132
                mul = 0;
 
133
 
 
134
                connect(&db, SIGNAL(readyRead()), SLOT(jdns_debugReady()));
 
135
        }
 
136
 
 
137
        ~JDnsGlobal()
 
138
        {
 
139
                QList<JDnsShared*> list;
 
140
                if(uni_net)
 
141
                        list += uni_net;
 
142
                if(uni_local)
 
143
                        list += uni_local;
 
144
                if(mul)
 
145
                        list += mul;
 
146
 
 
147
                // calls shutdown on the list, waits for shutdownFinished, deletes
 
148
                JDnsShared::waitForShutdown(list);
 
149
 
 
150
                // get final debug
 
151
                jdns_debugReady();
 
152
        }
 
153
 
 
154
        JDnsShared *ensure_uni_net()
 
155
        {
 
156
                if(!uni_net)
 
157
                {
 
158
                        uni_net = new JDnsShared(JDnsShared::UnicastInternet, this);
 
159
                        uni_net->setDebug(&db, "U");
 
160
                        bool ok4 = uni_net->addInterface(QHostAddress::Any);
 
161
                        bool ok6 = uni_net->addInterface(QHostAddress::AnyIPv6);
 
162
                        if(!ok4 && !ok6)
 
163
                        {
 
164
                                delete uni_net;
 
165
                                uni_net = 0;
 
166
                        }
 
167
                }
 
168
                return uni_net;
 
169
        }
 
170
 
 
171
        JDnsShared *ensure_uni_local()
 
172
        {
 
173
                if(!uni_local)
 
174
                {
 
175
                        uni_local = new JDnsShared(JDnsShared::UnicastLocal, this);
 
176
                        uni_local->setDebug(&db, "L");
 
177
                        bool ok4 = uni_local->addInterface(QHostAddress::Any);
 
178
                        bool ok6 = uni_local->addInterface(QHostAddress::AnyIPv6);
 
179
                        if(!ok4 && !ok6)
 
180
                        {
 
181
                                delete uni_local;
 
182
                                uni_local = 0;
 
183
                        }
 
184
                }
 
185
                return uni_local;
 
186
        }
 
187
 
 
188
        JDnsShared *ensure_mul()
 
189
        {
 
190
                if(!mul)
 
191
                {
 
192
                        mul = new JDnsShared(JDnsShared::Multicast, this);
 
193
                        mul->setDebug(&db, "M");
 
194
 
 
195
                        updateMulticastInterfaces();
 
196
                }
 
197
                return mul;
 
198
        }
 
199
 
 
200
signals:
 
201
        void debug(const QStringList &lines);
 
202
 
 
203
public slots:
 
204
        // TODO: call this when the network changes
 
205
        void updateMulticastInterfaces()
 
206
        {
 
207
                QHostAddress addr4 = QJDns::detectPrimaryMulticast(QHostAddress::Any);
 
208
                QHostAddress addr6 = QJDns::detectPrimaryMulticast(QHostAddress::AnyIPv6);
 
209
 
 
210
                if(!(addr4 == mul_addr4))
 
211
                {
 
212
                        if(!mul_addr4.isNull())
 
213
                                mul->removeInterface(mul_addr4);
 
214
                        mul_addr4 = addr4;
 
215
                        if(!mul_addr4.isNull())
 
216
                        {
 
217
                                if(!mul->addInterface(mul_addr4))
 
218
                                        mul_addr4 = QHostAddress();
 
219
                        }
 
220
                }
 
221
 
 
222
                if(!(addr6 == mul_addr6))
 
223
                {
 
224
                        if(!mul_addr6.isNull())
 
225
                                mul->removeInterface(mul_addr6);
 
226
                        mul_addr6 = addr6;
 
227
                        if(!mul_addr6.isNull())
 
228
                        {
 
229
                                if(!mul->addInterface(mul_addr6))
 
230
                                        mul_addr6 = QHostAddress();
 
231
                        }
 
232
                }
 
233
        }
 
234
 
 
235
private slots:
 
236
        void jdns_debugReady()
 
237
        {
 
238
                QStringList lines = db.readDebugLines();
 
239
                Q_UNUSED(lines);
 
240
                //for(int n = 0; n < lines.count(); ++n)
 
241
                //      printf("jdns: %s\n", qPrintable(lines[n]));
 
242
                //emit debug(lines);
 
243
        }
 
244
};
 
245
 
 
246
//----------------------------------------------------------------------------
 
247
// JDnsNameProvider
 
248
//----------------------------------------------------------------------------
 
249
static int next_id = 1;
 
250
class JDnsNameProvider : public NameProvider
 
251
{
 
252
        Q_OBJECT
 
253
        Q_INTERFACES(XMPP::NameProvider);
 
254
public:
 
255
        enum Mode { Internet, Local };
 
256
 
 
257
        JDnsGlobal *global;
 
258
 
 
259
        Mode mode;
 
260
        class Item
 
261
        {
 
262
        public:
 
263
                JDnsSharedRequest *req;
 
264
                QByteArray name;
 
265
                int type;
 
266
                bool longLived;
 
267
                int id;
 
268
 
 
269
                Item()
 
270
                {
 
271
                        req = 0;
 
272
                }
 
273
 
 
274
                ~Item()
 
275
                {
 
276
                        delete req;
 
277
                }
 
278
        };
 
279
        QList<Item*> items;
 
280
 
 
281
        static JDnsNameProvider *create(JDnsGlobal *global, Mode mode, QObject *parent = 0)
 
282
        {
 
283
                if(mode == Internet)
 
284
                {
 
285
                        if(!global->ensure_uni_net())
 
286
                                return 0;
 
287
                }
 
288
                else
 
289
                {
 
290
                        if(!global->ensure_uni_local())
 
291
                                return 0;
 
292
                }
 
293
 
 
294
                return new JDnsNameProvider(global, mode, parent);
 
295
        }
 
296
 
 
297
        JDnsNameProvider(JDnsGlobal *_global, Mode _mode, QObject *parent = 0) : NameProvider(parent)
 
298
        {
 
299
                global = _global;
 
300
                mode = _mode;
 
301
        }
 
302
 
 
303
        ~JDnsNameProvider()
 
304
        {
 
305
        }
 
306
 
 
307
        virtual int resolve_start(const QByteArray &name, int qType, bool longLived)
 
308
        {
 
309
                if(mode == Internet)
 
310
                {
 
311
                        if(name.right(6) == ".local" || name.right(7) == ".local.")
 
312
                        {
 
313
                                Item *i = new Item;
 
314
                                i->id = next_id++;
 
315
                                i->name = name;
 
316
                                i->longLived = longLived;
 
317
                                items += i;
 
318
                                QMetaObject::invokeMethod(this, "do_local", Qt::QueuedConnection, Q_ARG(int, i->id));
 
319
                                return i->id;
 
320
                        }
 
321
 
 
322
                        if(longLived)
 
323
                        {
 
324
                                Item *i = new Item;
 
325
                                i->id = next_id++;
 
326
                                items += i;
 
327
                                QMetaObject::invokeMethod(this, "do_error", Qt::QueuedConnection, Q_ARG(int, i->id));
 
328
                                return i->id;
 
329
                        }
 
330
 
 
331
                        Item *i = new Item;
 
332
                        i->req = new JDnsSharedRequest(global->uni_net);
 
333
                        connect(i->req, SIGNAL(resultsReady()), SLOT(req_resultsReady()));
 
334
                        i->longLived = false;
 
335
                        i->id = next_id++;
 
336
                        items += i;
 
337
                        i->req->query(name, qType);
 
338
                        return i->id;
 
339
                }
 
340
                else
 
341
                {
 
342
                        Item *i = new Item;
 
343
                        if(longLived)
 
344
                        {
 
345
                                if(!global->ensure_mul())
 
346
                                {
 
347
                                        Item *i = new Item;
 
348
                                        i->id = next_id++;
 
349
                                        items += i;
 
350
                                        QMetaObject::invokeMethod(this, "do_nolocal", Qt::QueuedConnection, Q_ARG(int, i->id));
 
351
                                        return i->id;
 
352
                                }
 
353
 
 
354
                                i->req = new JDnsSharedRequest(global->mul);
 
355
                                i->longLived = true;
 
356
                        }
 
357
                        else
 
358
                        {
 
359
                                i->req = new JDnsSharedRequest(global->uni_local);
 
360
                                i->longLived = false;
 
361
                        }
 
362
                        connect(i->req, SIGNAL(resultsReady()), SLOT(req_resultsReady()));
 
363
                        i->id = next_id++;
 
364
                        items += i;
 
365
                        i->req->query(name, qType);
 
366
                        return i->id;
 
367
                }
 
368
        }
 
369
 
 
370
        virtual void resolve_stop(int id)
 
371
        {
 
372
                Item *i = 0;
 
373
                for(int n = 0; n < items.count(); ++n)
 
374
                {
 
375
                        if(items[n]->id == id)
 
376
                        {
 
377
                                i = items[n];
 
378
                                break;
 
379
                        }
 
380
                }
 
381
                if(!i)
 
382
                        return;
 
383
 
 
384
                i->req->cancel();
 
385
 
 
386
                items.removeAll(i);
 
387
                delete i;
 
388
        }
 
389
 
 
390
        virtual void resolve_localResultsReady(int id, const QList<XMPP::NameRecord> &results)
 
391
        {
 
392
                Item *i = 0;
 
393
                for(int n = 0; n < items.count(); ++n)
 
394
                {
 
395
                        if(items[n]->id == id)
 
396
                        {
 
397
                                i = items[n];
 
398
                                break;
 
399
                        }
 
400
                }
 
401
                if(!i)
 
402
                        return;
 
403
 
 
404
                // not long-lived, so delete it (long-lived doesn't get looped through here)
 
405
                items.removeAll(i);
 
406
                delete i;
 
407
 
 
408
                QMetaObject::invokeMethod(this, "resolve_resultsReady", Qt::QueuedConnection,
 
409
                        Q_ARG(int, id), Q_ARG(QList<XMPP::NameRecord>, results));
 
410
        }
 
411
 
 
412
        virtual void resolve_localError(int id, XMPP::NameResolver::Error e)
 
413
        {
 
414
                Item *i = 0;
 
415
                for(int n = 0; n < items.count(); ++n)
 
416
                {
 
417
                        if(items[n]->id == id)
 
418
                        {
 
419
                                i = items[n];
 
420
                                break;
 
421
                        }
 
422
                }
 
423
                if(!i)
 
424
                        return;
 
425
 
 
426
                items.removeAll(i);
 
427
                delete i;
 
428
 
 
429
                QMetaObject::invokeMethod(this, "resolve_error", Qt::QueuedConnection,
 
430
                        Q_ARG(int, id), Q_ARG(XMPP::NameResolver::Error, e));
 
431
        }
 
432
 
 
433
private slots:
 
434
        void req_resultsReady()
 
435
        {
 
436
                JDnsSharedRequest *req = (JDnsSharedRequest *)sender();
 
437
 
 
438
                Item *i = 0;
 
439
                for(int n = 0; n < items.count(); ++n)
 
440
                {
 
441
                        if(items[n]->req == req)
 
442
                        {
 
443
                                i = items[n];
 
444
                                break;
 
445
                        }
 
446
                }
 
447
                if(!i)
 
448
                        return;
 
449
 
 
450
                int id = i->id;
 
451
 
 
452
                if(req->success())
 
453
                {
 
454
                        QList<NameRecord> out;
 
455
                        QList<QJDns::Record> results = req->results();
 
456
                        for(int n = 0; n < results.count(); ++n)
 
457
                                out += importJDNSRecord(results[n]);
 
458
                        if(!i->longLived)
 
459
                        {
 
460
                                items.removeAll(i);
 
461
                                delete i;
 
462
                        }
 
463
                        emit resolve_resultsReady(id, out);
 
464
                }
 
465
                else
 
466
                {
 
467
                        JDnsSharedRequest::Error e = req->error();
 
468
                        items.removeAll(i);
 
469
                        delete i;
 
470
 
 
471
                        NameResolver::Error error = NameResolver::ErrorGeneric;
 
472
                        if(e == JDnsSharedRequest::ErrorNXDomain)
 
473
                                error = NameResolver::ErrorNoName;
 
474
                        else if(e == JDnsSharedRequest::ErrorTimeout)
 
475
                                error = NameResolver::ErrorTimeout;
 
476
                        else // ErrorGeneric or ErrorNoNet
 
477
                                error = NameResolver::ErrorGeneric;
 
478
                        emit resolve_error(id, error);
 
479
                }
 
480
        }
 
481
 
 
482
        void do_local(int id)
 
483
        {
 
484
                Item *i = 0;
 
485
                for(int n = 0; n < items.count(); ++n)
 
486
                {
 
487
                        if(items[n]->id == id)
 
488
                        {
 
489
                                i = items[n];
 
490
                                break;
 
491
                        }
 
492
                }
 
493
                if(!i)
 
494
                        return;
 
495
 
 
496
                QByteArray name = i->name;
 
497
                if(i->longLived) // longlived is a handoff, so delete our instance
 
498
                {
 
499
                        items.removeAll(i);
 
500
                        delete i;
 
501
                }
 
502
 
 
503
                emit resolve_useLocal(id, name);
 
504
        }
 
505
 
 
506
        void do_error(int id)
 
507
        {
 
508
                Item *i = 0;
 
509
                for(int n = 0; n < items.count(); ++n)
 
510
                {
 
511
                        if(items[n]->id == id)
 
512
                        {
 
513
                                i = items[n];
 
514
                                break;
 
515
                        }
 
516
                }
 
517
                if(!i)
 
518
                        return;
 
519
 
 
520
                items.removeAll(i);
 
521
                delete i;
 
522
 
 
523
                emit resolve_error(id, NameResolver::ErrorNoLongLived);
 
524
        }
 
525
 
 
526
        void do_nolocal(int id)
 
527
        {
 
528
                Item *i = 0;
 
529
                for(int n = 0; n < items.count(); ++n)
 
530
                {
 
531
                        if(items[n]->id == id)
 
532
                        {
 
533
                                i = items[n];
 
534
                                break;
 
535
                        }
 
536
                }
 
537
                if(!i)
 
538
                        return;
 
539
 
 
540
                items.removeAll(i);
 
541
                delete i;
 
542
 
 
543
                emit resolve_error(id, NameResolver::ErrorNoLocal);
 
544
        }
 
545
};
 
546
 
 
547
//----------------------------------------------------------------------------
 
548
// JDnsServiceProvider
 
549
//----------------------------------------------------------------------------
 
550
class JDnsBrowseLookup : public QObject
 
551
{
 
552
        Q_OBJECT
 
553
public:
 
554
        JDnsShared *jdns;
 
555
        JDnsSharedRequest *req;
 
556
 
 
557
        bool success; // TODO: use this variable
 
558
        bool mode2;
 
559
        QByteArray name;
 
560
        QByteArray instance;
 
561
        bool haveSrv;
 
562
        QByteArray srvhost;
 
563
        int srvport;
 
564
        QList<QByteArray> attribs;
 
565
        QHostAddress addr;
 
566
 
 
567
        JDnsBrowseLookup(JDnsShared *_jdns)
 
568
        {
 
569
                req = 0;
 
570
                jdns = _jdns;
 
571
        }
 
572
 
 
573
        ~JDnsBrowseLookup()
 
574
        {
 
575
                delete req;
 
576
        }
 
577
 
 
578
        void start(const QByteArray &_name)
 
579
        {
 
580
                success = false;
 
581
                mode2 = false;
 
582
                name = _name;
 
583
                haveSrv = false;
 
584
 
 
585
                req = new JDnsSharedRequest(jdns);
 
586
                connect(req, SIGNAL(resultsReady()), SLOT(jdns_resultsReady()));
 
587
                req->query(name, QJDns::Srv);
 
588
        }
 
589
 
 
590
        void start2(const QByteArray &_name)
 
591
        {
 
592
                success = false;
 
593
                mode2 = true;
 
594
                name = _name;
 
595
                haveSrv = false;
 
596
 
 
597
                req = new JDnsSharedRequest(jdns);
 
598
                connect(req, SIGNAL(resultsReady()), SLOT(jdns_resultsReady()));
 
599
                req->query(name, QJDns::Srv);
 
600
        }
 
601
 
 
602
signals:
 
603
        void finished();
 
604
 
 
605
private slots:
 
606
        void jdns_resultsReady()
 
607
        {
 
608
                if(!haveSrv)
 
609
                {
 
610
                        QJDns::Record rec = req->results().first();
 
611
 
 
612
                        haveSrv = true;
 
613
                        srvhost = rec.name;
 
614
                        srvport = rec.port;
 
615
 
 
616
                        //printf("  Server: [%s] port=%d\n", srvhost.data(), srvport);
 
617
                        req->cancel();
 
618
 
 
619
                        if(mode2)
 
620
                                req->query(srvhost, QJDns::A); // TODO: ipv6?
 
621
                        else
 
622
                                req->query(name, QJDns::Txt);
 
623
                }
 
624
                else
 
625
                {
 
626
                        if(mode2)
 
627
                        {
 
628
                                QJDns::Record rec = req->results().first();
 
629
 
 
630
                                addr = rec.address;
 
631
 
 
632
                                delete req;
 
633
                                req = 0;
 
634
 
 
635
                                //printf("resolve done\n");
 
636
                                emit finished();
 
637
                                return;
 
638
                        }
 
639
 
 
640
                        QJDns::Record rec = req->results().first();
 
641
 
 
642
                        attribs.clear();
 
643
                        if(!rec.texts.isEmpty())
 
644
                        {
 
645
                                if(rec.texts.count() != 1 || !rec.texts[0].isEmpty())
 
646
                                        attribs = rec.texts;
 
647
                        }
 
648
 
 
649
                        /*if(attribs.isEmpty())
 
650
                        {
 
651
                                printf("  No attributes\n");
 
652
                        }
 
653
                        else
 
654
                        {
 
655
                                printf("  Attributes:\n", attribs.count());
 
656
                                for(int n = 0; n < attribs.count(); ++n)
 
657
                                        printf("    [%s]\n", attribs[n].data());
 
658
                        }*/
 
659
 
 
660
                        delete req;
 
661
                        req = 0;
 
662
 
 
663
                        //printf("Instance Available!\n");
 
664
                        emit finished();
 
665
                }
 
666
        }
 
667
};
 
668
 
 
669
class JDnsBrowseInfo
 
670
{
 
671
public:
 
672
        QByteArray name;
 
673
        QByteArray instance;
 
674
        QByteArray srvhost;
 
675
        int srvport;
 
676
        QList<QByteArray> attribs;
 
677
};
 
678
 
 
679
class JDnsBrowse : public QObject
 
680
{
 
681
        Q_OBJECT
 
682
public:
 
683
        int id;
 
684
 
 
685
        JDnsShared *jdns;
 
686
        JDnsSharedRequest *req;
 
687
        QByteArray type;
 
688
        QList<JDnsBrowseLookup*> lookups;
 
689
 
 
690
        JDnsBrowse(JDnsShared *_jdns)
 
691
        {
 
692
                req = 0;
 
693
                jdns = _jdns;
 
694
        }
 
695
 
 
696
        ~JDnsBrowse()
 
697
        {
 
698
                qDeleteAll(lookups);
 
699
                delete req;
 
700
        }
 
701
 
 
702
        void start(const QByteArray &_type)
 
703
        {
 
704
                type = _type;
 
705
                req = new JDnsSharedRequest(jdns);
 
706
                connect(req, SIGNAL(resultsReady()), SLOT(jdns_resultsReady()));
 
707
                req->query(type + ".local.", QJDns::Ptr);
 
708
        }
 
709
 
 
710
signals:
 
711
        void available(const JDnsBrowseInfo &i);
 
712
        void unavailable(const QByteArray &instance);
 
713
 
 
714
private slots:
 
715
        void jdns_resultsReady()
 
716
        {
 
717
                QJDns::Record rec = req->results().first();
 
718
                QByteArray name = rec.name;
 
719
 
 
720
                // FIXME: this is wrong, it should search backwards
 
721
                int x = name.indexOf('.');
 
722
                QByteArray instance = name.mid(0, x);
 
723
 
 
724
                if(rec.ttl == 0)
 
725
                {
 
726
                        // stop any lookups
 
727
                        JDnsBrowseLookup *bl = 0;
 
728
                        for(int n = 0; n < lookups.count(); ++n)
 
729
                        {
 
730
                                if(lookups[n]->name == name)
 
731
                                {
 
732
                                        bl = lookups[n];
 
733
                                        break;
 
734
                                }
 
735
                        }
 
736
                        if(bl)
 
737
                        {
 
738
                                lookups.removeAll(bl);
 
739
                                delete bl;
 
740
                        }
 
741
 
 
742
                        //printf("Instance Gone: [%s]\n", instance.data());
 
743
                        emit unavailable(instance);
 
744
                        return;
 
745
                }
 
746
 
 
747
                //printf("Instance Found: [%s]\n", instance.data());
 
748
 
 
749
                //printf("Lookup starting\n");
 
750
                JDnsBrowseLookup *bl = new JDnsBrowseLookup(jdns);
 
751
                connect(bl, SIGNAL(resultsReady()), SLOT(bl_resultsReady()));
 
752
                lookups += bl;
 
753
                bl->instance = instance;
 
754
                bl->start(name);
 
755
        }
 
756
 
 
757
        void bl_resultsReady()
 
758
        {
 
759
                JDnsBrowseLookup *bl = (JDnsBrowseLookup *)sender();
 
760
 
 
761
                JDnsBrowseInfo i;
 
762
                i.name = bl->name;
 
763
                i.instance = bl->instance;
 
764
                i.srvhost = bl->srvhost;
 
765
                i.srvport = bl->srvport;
 
766
                i.attribs = bl->attribs;
 
767
 
 
768
                lookups.removeAll(bl);
 
769
                delete bl;
 
770
 
 
771
                //printf("Lookup finished\n");
 
772
                emit available(i);
 
773
        }
 
774
};
 
775
 
 
776
/*void JDnsShared::net_available(const QString &id)
 
777
{
 
778
        NetInterface *iface = new NetInterface(id);
 
779
        connect(iface, SIGNAL(unavailable()), SLOT(net_unavailable()));
 
780
        ifaces += iface;
 
781
 
 
782
        QList<QHostAddress> addrlist = iface->addresses();
 
783
 
 
784
        if(!instances.isEmpty())
 
785
                return;
 
786
 
 
787
        // prefer using just ipv4
 
788
        QHostAddress addr;
 
789
        for(int n = 0; n < addrlist.count(); ++n)
 
790
        {
 
791
                if(addrlist[n].protocol() == QAbstractSocket::IPv4Protocol)
 
792
                {
 
793
                        addr = addrlist[n];
 
794
                        break;
 
795
                }
 
796
        }
 
797
 
 
798
        if(addr.isNull())
 
799
                return;
 
800
 
 
801
        addr = QHostAddress("192.168.1.150");
 
802
}
 
803
 
 
804
void JDnsShared::net_unavailable()
 
805
{
 
806
        // TODO
 
807
}*/
 
808
 
 
809
class JDnsServiceProvider : public ServiceProvider
 
810
{
 
811
        Q_OBJECT
 
812
public:
 
813
        JDnsGlobal *global;
 
814
 
 
815
        QList<JDnsBrowse*> list;
 
816
        QHash<QByteArray,ServiceInstance> items;
 
817
 
 
818
        QList<JDnsSharedRequest*> pubitems;
 
819
        QByteArray _servname;
 
820
 
 
821
        static JDnsServiceProvider *create(JDnsGlobal *global, QObject *parent = 0)
 
822
        {
 
823
                JDnsServiceProvider *p = new JDnsServiceProvider(global, parent);
 
824
                return p;
 
825
        }
 
826
 
 
827
        JDnsServiceProvider(JDnsGlobal *_global, QObject *parent = 0) : ServiceProvider(parent)
 
828
        {
 
829
                global = _global;
 
830
        }
 
831
 
 
832
        ~JDnsServiceProvider()
 
833
        {
 
834
                qDeleteAll(pubitems);
 
835
        }
 
836
 
 
837
        virtual int browse_start(const QString &type, const QString &domain)
 
838
        {
 
839
                // no support for non-local domains
 
840
                if(!domain.isEmpty() && (domain != ".local." && domain != ".local" && domain != "."))
 
841
                {
 
842
                        // TODO
 
843
                }
 
844
 
 
845
                if(!global->ensure_mul())
 
846
                {
 
847
                        // TODO
 
848
                }
 
849
 
 
850
                JDnsBrowse *b = new JDnsBrowse(global->mul);
 
851
                connect(b, SIGNAL(available(const JDnsBrowseInfo &)), SLOT(jb_available(const JDnsBrowseInfo &)));
 
852
                connect(b, SIGNAL(unavailable(const QByteArray &)), SLOT(jb_unavailable(const QByteArray &)));
 
853
                b->start(type.toLatin1());
 
854
 
 
855
                return 1;
 
856
        }
 
857
 
 
858
        virtual void browse_stop(int id)
 
859
        {
 
860
                // TODO
 
861
                Q_UNUSED(id);
 
862
        }
 
863
 
 
864
        virtual int resolve_start(const QByteArray &name)
 
865
        {
 
866
                if(!global->ensure_mul())
 
867
                {
 
868
                        // TODO
 
869
                }
 
870
 
 
871
                JDnsBrowseLookup *bl = new JDnsBrowseLookup(global->mul);
 
872
                connect(bl, SIGNAL(finished()), SLOT(bl_finished()));
 
873
                bl->start2(name);
 
874
 
 
875
                return 1;
 
876
        }
 
877
 
 
878
        virtual void resolve_stop(int id)
 
879
        {
 
880
                // TODO
 
881
                Q_UNUSED(id);
 
882
        }
 
883
 
 
884
        virtual int publish_start(const QString &instance, const QString &type, int port, const QMap<QString,QByteArray> &attributes)
 
885
        {
 
886
                if(!global->ensure_mul())
 
887
                {
 
888
                        // TODO
 
889
                }
 
890
 
 
891
                QString me = QHostInfo::localHostName();
 
892
                //QHostInfo hi = QHostInfo::fromName(me);
 
893
                QByteArray melocal = me.toLatin1() + ".local.";
 
894
                QByteArray servname = instance.toLatin1() + '.' + type.toLatin1() + ".local.";
 
895
 
 
896
                JDnsSharedRequest *req = new JDnsSharedRequest(global->mul);
 
897
                QJDns::Record rec;
 
898
                rec.type = QJDns::A;
 
899
                rec.owner = melocal;
 
900
                rec.ttl = 120;
 
901
                rec.haveKnown = true;
 
902
                rec.address = QHostAddress(); // null address, will be filled in
 
903
                req->publish(QJDns::Unique, rec);
 
904
                pubitems += req;
 
905
 
 
906
                /*JDnsSharedRequest *req = new JDnsSharedRequest(global->mul);
 
907
                QJDns::Record rec;
 
908
                rec.type = QJDns::Aaaa;
 
909
                rec.owner = melocal;
 
910
                rec.ttl = 120;
 
911
                rec.haveKnown = true;
 
912
                rec.address = QHostAddress(); // null address, will be filled in
 
913
                req->publish(QJDns::Unique, rec);
 
914
                pubitems += req;*/
 
915
 
 
916
                req = new JDnsSharedRequest(global->mul);
 
917
                rec = QJDns::Record();
 
918
                rec.type = QJDns::Srv;
 
919
                rec.owner = servname;
 
920
                rec.ttl = 120;
 
921
                rec.haveKnown = true;
 
922
                rec.name = melocal;
 
923
                rec.port = port;
 
924
                rec.priority = 0;
 
925
                rec.weight = 0;
 
926
                req->publish(QJDns::Unique, rec);
 
927
                pubitems += req;
 
928
 
 
929
                req = new JDnsSharedRequest(global->mul);
 
930
                rec = QJDns::Record();
 
931
                rec.type = QJDns::Txt;
 
932
                rec.owner = servname;
 
933
                rec.ttl = 4500;
 
934
                rec.haveKnown = true;
 
935
                QMapIterator<QString,QByteArray> it(attributes);
 
936
                while(it.hasNext())
 
937
                {
 
938
                        it.next();
 
939
                        rec.texts += it.key().toLatin1() + '=' + it.value();
 
940
                }
 
941
                if(rec.texts.isEmpty())
 
942
                        rec.texts += QByteArray();
 
943
                req->publish(QJDns::Unique, rec);
 
944
                pubitems += req;
 
945
 
 
946
                req = new JDnsSharedRequest(global->mul);
 
947
                rec = QJDns::Record();
 
948
                rec.type = QJDns::Ptr;
 
949
                rec.owner = type.toLatin1() + ".local.";
 
950
                rec.ttl = 4500;
 
951
                rec.haveKnown = true;
 
952
                rec.name = servname;
 
953
                req->publish(QJDns::Shared, rec);
 
954
                pubitems += req;
 
955
 
 
956
                _servname = servname;
 
957
 
 
958
                QMetaObject::invokeMethod(this, "publish_published", Qt::QueuedConnection, Q_ARG(int, 1));
 
959
 
 
960
                return 1;
 
961
        }
 
962
 
 
963
        virtual int publish_update(const QMap<QString,QByteArray> &attributes)
 
964
        {
 
965
                // TODO
 
966
                Q_UNUSED(attributes);
 
967
                return 0;
 
968
        }
 
969
 
 
970
        virtual void publish_cancel(int id)
 
971
        {
 
972
                // TODO
 
973
                Q_UNUSED(id);
 
974
        }
 
975
 
 
976
        virtual int publish_extra_start(int pub_id, const NameRecord &name)
 
977
        {
 
978
                // TODO
 
979
                Q_UNUSED(pub_id);
 
980
 
 
981
                JDnsSharedRequest *req = new JDnsSharedRequest(global->mul);
 
982
                QJDns::Record rec;
 
983
                rec.type = 10;
 
984
                rec.owner = _servname;
 
985
                rec.ttl = 4500;
 
986
                rec.rdata = name.rawData();
 
987
                req->publish(QJDns::Unique, rec);
 
988
                pubitems += req;
 
989
 
 
990
                QMetaObject::invokeMethod(this, "publish_extra_published", Qt::QueuedConnection, Q_ARG(int, 2));
 
991
 
 
992
                return 2;
 
993
        }
 
994
 
 
995
        virtual int publish_extra_update(int id, const NameRecord &name)
 
996
        {
 
997
                // TODO
 
998
                Q_UNUSED(id);
 
999
                Q_UNUSED(name);
 
1000
                return 0;
 
1001
        }
 
1002
 
 
1003
        virtual void publish_extra_cancel(int id)
 
1004
        {
 
1005
                // TODO
 
1006
                Q_UNUSED(id);
 
1007
        }
 
1008
 
 
1009
private slots:
 
1010
        void jb_available(const JDnsBrowseInfo &i)
 
1011
        {
 
1012
                //printf("jb_available: [%s]\n", i.instance.data());
 
1013
                JDnsBrowse *b = (JDnsBrowse *)sender();
 
1014
                QMap<QString,QByteArray> map;
 
1015
                for(int n = 0; n < i.attribs.count(); ++n)
 
1016
                {
 
1017
                        const QByteArray &a = i.attribs[n];
 
1018
                        QString key;
 
1019
                        QByteArray value;
 
1020
                        int x = a.indexOf('=');
 
1021
                        if(x != -1)
 
1022
                        {
 
1023
                                key = QString::fromLatin1(a.mid(0, x));
 
1024
                                value = a.mid(x + 1);
 
1025
                        }
 
1026
                        else
 
1027
                        {
 
1028
                                key = QString::fromLatin1(a);
 
1029
                        }
 
1030
 
 
1031
                        map.insert(key, value);
 
1032
                }
 
1033
                ServiceInstance si(QString::fromLatin1(i.instance), QString::fromLatin1(b->type), "local.", map);
 
1034
                items.insert(i.name, si);
 
1035
                emit browse_instanceAvailable(1, si);
 
1036
        }
 
1037
 
 
1038
        void jb_unavailable(const QByteArray &instance)
 
1039
        {
 
1040
                //printf("jb_unavailable: [%s]\n", instance.data());
 
1041
                JDnsBrowse *b = (JDnsBrowse *)sender();
 
1042
                QByteArray name = instance + '.' + b->type + ".local.";
 
1043
                if(!items.contains(name))
 
1044
                        return;
 
1045
 
 
1046
                ServiceInstance si = items.value(name);
 
1047
                items.remove(name);
 
1048
                emit browse_instanceUnavailable(1, si);
 
1049
        }
 
1050
 
 
1051
        void bl_finished()
 
1052
        {
 
1053
                JDnsBrowseLookup *bl = (JDnsBrowseLookup *)sender();
 
1054
                QHostAddress addr = bl->addr;
 
1055
                int port = bl->srvport;
 
1056
                delete bl;
 
1057
                emit resolve_resultsReady(1, addr, port);
 
1058
        }
 
1059
 
 
1060
                //connect(&jdns, SIGNAL(published(int)), SLOT(jdns_published(int)));
 
1061
 
 
1062
        /*virtual int publish_start(NameLocalPublisher::Mode pmode, const NameRecord &name)
 
1063
        {
 
1064
                if(mode == Unicast)
 
1065
                        return -1;
 
1066
 
 
1067
                QJDns::Response response;
 
1068
                QJDns::Record record = exportJDNSRecord(name);
 
1069
                response.answerRecords += record;
 
1070
                QJDns::PublishMode m = (pmode == NameLocalPublisher::Unique ? QJDns::Unique : QJDns::Shared);
 
1071
                return jdns.publishStart(m, record.owner, record.type, response);
 
1072
        }
 
1073
 
 
1074
        virtual void publish_update(int id, const NameRecord &name)
 
1075
        {
 
1076
                QJDns::Response response;
 
1077
                QJDns::Record record = exportJDNSRecord(name);
 
1078
                response.answerRecords += record;
 
1079
                return jdns.publishUpdate(id, response);
 
1080
        }
 
1081
 
 
1082
        virtual void publish_stop(int id)
 
1083
        {
 
1084
                jdns.publishCancel(id);
 
1085
        }*/
 
1086
 
 
1087
                //else if(e == QJDns::ErrorConflict)
 
1088
                //      error = NameResolver::ErrorConflict;
 
1089
 
 
1090
                //if(mode == Multicast)
 
1091
                //      jdns.queryCancel(id);
 
1092
};
 
1093
 
 
1094
//----------------------------------------------------------------------------
 
1095
// JDnsProvider
 
1096
//----------------------------------------------------------------------------
 
1097
class JDnsProvider : public IrisNetProvider
 
1098
{
 
1099
        Q_OBJECT
 
1100
        Q_INTERFACES(XMPP::IrisNetProvider);
 
1101
public:
 
1102
        JDnsGlobal *global;
 
1103
 
 
1104
        JDnsProvider()
 
1105
        {
 
1106
                global = 0;
 
1107
        }
 
1108
 
 
1109
        ~JDnsProvider()
 
1110
        {
 
1111
                delete global;
 
1112
        }
 
1113
 
 
1114
        virtual NameProvider *createNameProviderInternet()
 
1115
        {
 
1116
                if(!global)
 
1117
                        global = new JDnsGlobal;
 
1118
                return JDnsNameProvider::create(global, JDnsNameProvider::Internet);
 
1119
        }
 
1120
 
 
1121
        virtual NameProvider *createNameProviderLocal()
 
1122
        {
 
1123
                if(!global)
 
1124
                        global = new JDnsGlobal;
 
1125
                return JDnsNameProvider::create(global, JDnsNameProvider::Local);
 
1126
        }
 
1127
 
 
1128
        virtual ServiceProvider *createServiceProvider()
 
1129
        {
 
1130
                if(!global)
 
1131
                        global = new JDnsGlobal;
 
1132
                return JDnsServiceProvider::create(global);
 
1133
        }
 
1134
};
 
1135
 
 
1136
IrisNetProvider *irisnet_createJDnsProvider()
 
1137
{
 
1138
        return new JDnsProvider;
 
1139
}
 
1140
 
 
1141
}
 
1142
 
 
1143
#include "netnames_jdns.moc"