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

« back to all changes in this revision

Viewing changes to protocols/jabber/libiris/src/jdns/qjdns.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) 2005-2008  Justin Karneges
 
3
 *
 
4
 * Permission is hereby granted, free of charge, to any person obtaining a
 
5
 * copy of this software and associated documentation files (the
 
6
 * "Software"), to deal in the Software without restriction, including
 
7
 * without limitation the rights to use, copy, modify, merge, publish,
 
8
 * distribute, sublicense, and/or sell copies of the Software, and to
 
9
 * permit persons to whom the Software is furnished to do so, subject to
 
10
 * the following conditions:
 
11
 *
 
12
 * The above copyright notice and this permission notice shall be included
 
13
 * in all copies or substantial portions of the Software.
 
14
 *
 
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 
16
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
17
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 
18
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 
19
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 
20
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 
21
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
22
 */
 
23
 
 
24
#include "qjdns.h"
 
25
 
 
26
#include <time.h>
 
27
#include "qjdns_sock.h"
 
28
#include "jdns.h"
 
29
 
 
30
// for fprintf
 
31
#include <stdio.h>
 
32
 
 
33
namespace {
 
34
 
 
35
// safeobj stuff, from qca
 
36
 
 
37
void releaseAndDeleteLater(QObject *owner, QObject *obj)
 
38
{
 
39
        obj->disconnect(owner);
 
40
        obj->setParent(0);
 
41
        obj->deleteLater();
 
42
}
 
43
 
 
44
class SafeTimer : public QObject
 
45
{
 
46
        Q_OBJECT
 
47
public:
 
48
        SafeTimer(QObject *parent = 0) :
 
49
                QObject(parent)
 
50
        {
 
51
                t = new QTimer(this);
 
52
                connect(t, SIGNAL(timeout()), SIGNAL(timeout()));
 
53
        }
 
54
 
 
55
        ~SafeTimer()
 
56
        {
 
57
                releaseAndDeleteLater(this, t);
 
58
        }
 
59
 
 
60
        int interval() const                { return t->interval(); }
 
61
        bool isActive() const               { return t->isActive(); }
 
62
        bool isSingleShot() const           { return t->isSingleShot(); }
 
63
        void setInterval(int msec)          { t->setInterval(msec); }
 
64
        void setSingleShot(bool singleShot) { t->setSingleShot(singleShot); }
 
65
        int timerId() const                 { return t->timerId(); }
 
66
 
 
67
public slots:
 
68
        void start(int msec)                { t->start(msec); }
 
69
        void start()                        { t->start(); }
 
70
        void stop()                         { t->stop(); }
 
71
 
 
72
signals:
 
73
        void timeout();
 
74
 
 
75
private:
 
76
        QTimer *t;
 
77
};
 
78
 
 
79
}
 
80
 
 
81
static jdns_string_t *qt2str(const QByteArray &in)
 
82
{
 
83
        jdns_string_t *out = jdns_string_new();
 
84
        jdns_string_set(out, (const unsigned char *)in.data(), in.size());
 
85
        return out;
 
86
}
 
87
 
 
88
static QByteArray str2qt(const jdns_string_t *in)
 
89
{
 
90
        return QByteArray((const char *)in->data, in->size);
 
91
}
 
92
 
 
93
static void qt2addr_set(jdns_address_t *addr, const QHostAddress &host)
 
94
{
 
95
        if(host.protocol() == QAbstractSocket::IPv6Protocol)
 
96
                jdns_address_set_ipv6(addr, host.toIPv6Address().c);
 
97
        else
 
98
                jdns_address_set_ipv4(addr, host.toIPv4Address());
 
99
}
 
100
 
 
101
static jdns_address_t *qt2addr(const QHostAddress &host)
 
102
{
 
103
        jdns_address_t *addr = jdns_address_new();
 
104
        qt2addr_set(addr, host);
 
105
        return addr;
 
106
}
 
107
 
 
108
static QHostAddress addr2qt(const jdns_address_t *addr)
 
109
{
 
110
        if(addr->isIpv6)
 
111
                return QHostAddress(addr->addr.v6);
 
112
        else
 
113
                return QHostAddress(addr->addr.v4);
 
114
}
 
115
 
 
116
static QJDns::Record import_record(const jdns_rr_t *in)
 
117
{
 
118
        QJDns::Record out;
 
119
 
 
120
        out.owner = QByteArray((const char *)in->owner);
 
121
        out.ttl = in->ttl;
 
122
        out.type = in->type;
 
123
        out.rdata = QByteArray((const char *)in->rdata, in->rdlength);
 
124
 
 
125
        // known
 
126
        if(in->haveKnown)
 
127
        {
 
128
                int type = in->type;
 
129
 
 
130
                if(type == QJDns::A || type == QJDns::Aaaa)
 
131
                {
 
132
                        out.haveKnown = true;
 
133
                        out.address = addr2qt(in->data.address);
 
134
                }
 
135
                else if(type == QJDns::Mx)
 
136
                {
 
137
                        out.haveKnown = true;
 
138
                        out.name = QByteArray((const char *)in->data.server->name);
 
139
                        out.priority = in->data.server->priority;
 
140
                }
 
141
                else if(type == QJDns::Srv)
 
142
                {
 
143
                        out.haveKnown = true;
 
144
                        out.name = QByteArray((const char *)in->data.server->name);
 
145
                        out.priority = in->data.server->priority;
 
146
                        out.weight = in->data.server->weight;
 
147
                        out.port = in->data.server->port;
 
148
                }
 
149
                else if(type == QJDns::Cname || type == QJDns::Ptr || type == QJDns::Ns)
 
150
                {
 
151
                        out.haveKnown = true;
 
152
                        out.name = QByteArray((const char *)in->data.name);
 
153
                }
 
154
                else if(type == QJDns::Txt)
 
155
                {
 
156
                        out.haveKnown = true;
 
157
                        out.texts.clear();
 
158
                        for(int n = 0; n < in->data.texts->count; ++n)
 
159
                                out.texts += str2qt(in->data.texts->item[n]);
 
160
                }
 
161
                else if(type == QJDns::Hinfo)
 
162
                {
 
163
                        out.haveKnown = true;
 
164
                        out.cpu = str2qt(in->data.hinfo.cpu);
 
165
                        out.os = str2qt(in->data.hinfo.os);
 
166
                }
 
167
        }
 
168
 
 
169
        return out;
 
170
}
 
171
 
 
172
static jdns_rr_t *export_record(const QJDns::Record &in)
 
173
{
 
174
        jdns_rr_t *out = jdns_rr_new();
 
175
 
 
176
        jdns_rr_set_owner(out, (const unsigned char *)in.owner.data());
 
177
        out->ttl = in.ttl;
 
178
 
 
179
        // if we have known, use that
 
180
        if(in.haveKnown)
 
181
        {
 
182
                int type = in.type;
 
183
 
 
184
                if(type == QJDns::A)
 
185
                {
 
186
                        jdns_address_t *addr = qt2addr(in.address);
 
187
                        jdns_rr_set_A(out, addr);
 
188
                        jdns_address_delete(addr);
 
189
                }
 
190
                else if(type == QJDns::Aaaa)
 
191
                {
 
192
                        jdns_address_t *addr = qt2addr(in.address);
 
193
                        jdns_rr_set_AAAA(out, addr);
 
194
                        jdns_address_delete(addr);
 
195
                }
 
196
                else if(type == QJDns::Mx)
 
197
                {
 
198
                        jdns_rr_set_MX(out, (const unsigned char *)in.name.data(), in.priority);
 
199
                }
 
200
                else if(type == QJDns::Srv)
 
201
                {
 
202
                        jdns_rr_set_SRV(out, (const unsigned char *)in.name.data(), in.port, in.priority, in.weight);
 
203
                }
 
204
                else if(type == QJDns::Cname)
 
205
                {
 
206
                        jdns_rr_set_CNAME(out, (const unsigned char *)in.name.data());
 
207
                }
 
208
                else if(type == QJDns::Ptr)
 
209
                {
 
210
                        jdns_rr_set_PTR(out, (const unsigned char *)in.name.data());
 
211
                }
 
212
                else if(type == QJDns::Txt)
 
213
                {
 
214
                        jdns_stringlist_t *list = jdns_stringlist_new();
 
215
                        for(int n = 0; n < in.texts.count(); ++n)
 
216
                        {
 
217
                                jdns_string_t *str = qt2str(in.texts[n]);
 
218
                                jdns_stringlist_append(list, str);
 
219
                                jdns_string_delete(str);
 
220
                        }
 
221
                        jdns_rr_set_TXT(out, list);
 
222
                        jdns_stringlist_delete(list);
 
223
                }
 
224
                else if(type == QJDns::Hinfo)
 
225
                {
 
226
                        jdns_string_t *cpu = qt2str(in.cpu);
 
227
                        jdns_string_t *os = qt2str(in.os);
 
228
                        jdns_rr_set_HINFO(out, cpu, os);
 
229
                        jdns_string_delete(cpu);
 
230
                        jdns_string_delete(os);
 
231
                }
 
232
                else if(type == QJDns::Ns)
 
233
                {
 
234
                        jdns_rr_set_NS(out, (const unsigned char *)in.name.data());
 
235
                }
 
236
        }
 
237
        else
 
238
                jdns_rr_set_record(out, in.type, (const unsigned char *)in.rdata.data(), in.rdata.size());
 
239
 
 
240
        return out;
 
241
}
 
242
 
 
243
//----------------------------------------------------------------------------
 
244
// QJDns::NameServer
 
245
//----------------------------------------------------------------------------
 
246
QJDns::NameServer::NameServer()
 
247
{
 
248
        port = JDNS_UNICAST_PORT;
 
249
}
 
250
 
 
251
//----------------------------------------------------------------------------
 
252
// QJDns::Record
 
253
//----------------------------------------------------------------------------
 
254
QJDns::Record::Record()
 
255
{
 
256
        ttl = 0;
 
257
        type = -1;
 
258
        haveKnown = false;
 
259
}
 
260
 
 
261
bool QJDns::Record::verify() const
 
262
{
 
263
        jdns_rr_t *rr = export_record(*this);
 
264
        int ok = jdns_rr_verify(rr);
 
265
        jdns_rr_delete(rr);
 
266
        return (ok ? true : false);
 
267
}
 
268
 
 
269
//----------------------------------------------------------------------------
 
270
// QJDns
 
271
//----------------------------------------------------------------------------
 
272
static int my_srand_done = 0;
 
273
 
 
274
static void my_srand()
 
275
{
 
276
        if(my_srand_done)
 
277
                return;
 
278
 
 
279
        // lame attempt at randomizing without srand
 
280
        int count = ::time(NULL) % 128;
 
281
        for(int n = 0; n < count; ++n)
 
282
                rand();
 
283
 
 
284
        my_srand_done = 1;
 
285
}
 
286
 
 
287
class QJDns::Private : public QObject
 
288
{
 
289
        Q_OBJECT
 
290
public:
 
291
        class LateError
 
292
        {
 
293
        public:
 
294
                int source_type; // 0 for query, 1 for publish
 
295
                int id;
 
296
                Error error;
 
297
        };
 
298
 
 
299
        class LateResponse
 
300
        {
 
301
        public:
 
302
                int id;
 
303
                QJDns::Response response;
 
304
                bool do_cancel;
 
305
        };
 
306
 
 
307
        QJDns *q;
 
308
        QJDns::Mode mode;
 
309
        jdns_session_t *sess;
 
310
        bool shutting_down;
 
311
        SafeTimer stepTrigger, debugTrigger;
 
312
        SafeTimer stepTimeout;
 
313
        QTime clock;
 
314
        QStringList debug_strings;
 
315
        bool new_debug_strings;
 
316
        int next_handle;
 
317
        bool need_handle;
 
318
        QHash<int,QUdpSocket*> socketForHandle;
 
319
        QHash<QUdpSocket*,int> handleForSocket;
 
320
        int pending;
 
321
        bool pending_wait;
 
322
        bool complete_shutdown;
 
323
 
 
324
        // pointers that will point to things we are currently signalling
 
325
        //   about.  when a query or publish is cancelled, we can use these
 
326
        //   pointers to extract anything we shouldn't signal.
 
327
        QList<LateError> *pErrors;
 
328
        QList<int> *pPublished;
 
329
        QList<LateResponse> *pResponses;
 
330
 
 
331
        Private(QJDns *_q) :
 
332
                QObject(_q),
 
333
                q(_q),
 
334
                stepTrigger(this),
 
335
                debugTrigger(this),
 
336
                stepTimeout(this),
 
337
                pErrors(0),
 
338
                pPublished(0),
 
339
                pResponses(0)
 
340
        {
 
341
                sess = 0;
 
342
                shutting_down = false;
 
343
                new_debug_strings = false;
 
344
                pending = 0;
 
345
 
 
346
                connect(&stepTrigger, SIGNAL(timeout()), SLOT(doNextStepSlot()));
 
347
                stepTrigger.setSingleShot(true);
 
348
 
 
349
                connect(&debugTrigger, SIGNAL(timeout()), SLOT(doDebug()));
 
350
                debugTrigger.setSingleShot(true);
 
351
 
 
352
                connect(&stepTimeout, SIGNAL(timeout()), SLOT(st_timeout()));
 
353
                stepTimeout.setSingleShot(true);
 
354
 
 
355
                my_srand();
 
356
 
 
357
                clock.start();
 
358
        }
 
359
 
 
360
        ~Private()
 
361
        {
 
362
                cleanup();
 
363
        }
 
364
 
 
365
        void cleanup()
 
366
        {
 
367
                if(sess)
 
368
                {
 
369
                        jdns_session_delete(sess);
 
370
                        sess = 0;
 
371
                }
 
372
 
 
373
                shutting_down = false;
 
374
                pending = 0;
 
375
 
 
376
                // it is safe to delete the QUdpSocket objects here without
 
377
                //   deleteLater, since this code path never occurs when
 
378
                //   a signal from those objects is on the stack
 
379
                qDeleteAll(socketForHandle);
 
380
                socketForHandle.clear();
 
381
                handleForSocket.clear();
 
382
 
 
383
                stepTrigger.stop();
 
384
                stepTimeout.stop();
 
385
                need_handle = 0;
 
386
        }
 
387
 
 
388
        bool init(QJDns::Mode _mode, const QHostAddress &address)
 
389
        {
 
390
                mode = _mode;
 
391
 
 
392
                jdns_callbacks_t callbacks;
 
393
                callbacks.app = this;
 
394
                callbacks.time_now = cb_time_now;
 
395
                callbacks.rand_int = cb_rand_int;
 
396
                callbacks.debug_line = cb_debug_line;
 
397
                callbacks.udp_bind = cb_udp_bind;
 
398
                callbacks.udp_unbind = cb_udp_unbind;
 
399
                callbacks.udp_read = cb_udp_read;
 
400
                callbacks.udp_write = cb_udp_write;
 
401
                sess = jdns_session_new(&callbacks);
 
402
                jdns_set_hold_ids_enabled(sess, 1);
 
403
                next_handle = 1;
 
404
                need_handle = false;
 
405
 
 
406
                int ret;
 
407
 
 
408
                jdns_address_t *baddr = qt2addr(address);
 
409
                if(mode == Unicast)
 
410
                {
 
411
                        ret = jdns_init_unicast(sess, baddr, 0);
 
412
                }
 
413
                else
 
414
                {
 
415
                        jdns_address_t *maddr;
 
416
                        if(address.protocol() == QAbstractSocket::IPv6Protocol)
 
417
                                maddr = jdns_address_multicast6_new();
 
418
                        else
 
419
                                maddr = jdns_address_multicast4_new();
 
420
                        ret = jdns_init_multicast(sess, baddr, JDNS_MULTICAST_PORT, maddr);
 
421
                        jdns_address_delete(maddr);
 
422
                }
 
423
                jdns_address_delete(baddr);
 
424
 
 
425
                if(!ret)
 
426
                {
 
427
                        jdns_session_delete(sess);
 
428
                        sess = 0;
 
429
                        return false;
 
430
                }
 
431
                return true;
 
432
        }
 
433
 
 
434
        void setNameServers(const QList<NameServer> &nslist)
 
435
        {
 
436
                jdns_nameserverlist_t *addrs = jdns_nameserverlist_new();
 
437
                for(int n = 0; n < nslist.count(); ++n)
 
438
                {
 
439
                        jdns_address_t *addr = qt2addr(nslist[n].address);
 
440
                        jdns_nameserverlist_append(addrs, addr, nslist[n].port);
 
441
                        jdns_address_delete(addr);
 
442
                }
 
443
                jdns_set_nameservers(sess, addrs);
 
444
                jdns_nameserverlist_delete(addrs);
 
445
        }
 
446
 
 
447
        void process()
 
448
        {
 
449
                if(!stepTrigger.isActive())
 
450
                {
 
451
                        stepTimeout.stop();
 
452
                        stepTrigger.start();
 
453
                }
 
454
        }
 
455
 
 
456
        void processDebug()
 
457
        {
 
458
                new_debug_strings = true;
 
459
                if(!debugTrigger.isActive())
 
460
                        debugTrigger.start();
 
461
        }
 
462
 
 
463
        void doNextStep()
 
464
        {
 
465
                if(shutting_down && complete_shutdown)
 
466
                {
 
467
                        cleanup();
 
468
                        emit q->shutdownFinished();
 
469
                        return;
 
470
                }
 
471
 
 
472
                QPointer<QObject> self = this;
 
473
 
 
474
                int ret = jdns_step(sess);
 
475
 
 
476
                QList<LateError> errors;
 
477
                QList<int> published;
 
478
                QList<LateResponse> responses;
 
479
                bool finish_shutdown = false;
 
480
 
 
481
                pErrors = &errors;
 
482
                pPublished = &published;
 
483
                pResponses = &responses;
 
484
 
 
485
                while(1)
 
486
                {
 
487
                        jdns_event_t *e = jdns_next_event(sess);
 
488
                        if(!e)
 
489
                                break;
 
490
 
 
491
                        if(e->type == JDNS_EVENT_SHUTDOWN)
 
492
                        {
 
493
                                finish_shutdown = true;
 
494
                        }
 
495
                        else if(e->type == JDNS_EVENT_PUBLISH)
 
496
                        {
 
497
                                if(e->status != JDNS_STATUS_SUCCESS)
 
498
                                {
 
499
                                        QJDns::Error error;
 
500
                                        if(e->status == JDNS_STATUS_CONFLICT)
 
501
                                                error = QJDns::ErrorConflict;
 
502
                                        else
 
503
                                                error = QJDns::ErrorGeneric;
 
504
                                        LateError le;
 
505
                                        le.source_type = 1;
 
506
                                        le.id = e->id;
 
507
                                        le.error = error;
 
508
                                        errors += le;
 
509
                                }
 
510
                                else
 
511
                                {
 
512
                                        published += e->id;
 
513
                                }
 
514
                        }
 
515
                        else if(e->type == JDNS_EVENT_RESPONSE)
 
516
                        {
 
517
                                if(e->status != JDNS_STATUS_SUCCESS)
 
518
                                {
 
519
                                        QJDns::Error error;
 
520
                                        if(e->status == JDNS_STATUS_NXDOMAIN)
 
521
                                                error = QJDns::ErrorNXDomain;
 
522
                                        else if(e->status == JDNS_STATUS_TIMEOUT)
 
523
                                                error = QJDns::ErrorTimeout;
 
524
                                        else
 
525
                                                error = QJDns::ErrorGeneric;
 
526
                                        LateError le;
 
527
                                        le.source_type = 0;
 
528
                                        le.id = e->id;
 
529
                                        le.error = error;
 
530
                                        errors += le;
 
531
                                }
 
532
                                else
 
533
                                {
 
534
                                        QJDns::Response out_response;
 
535
                                        for(int n = 0; n < e->response->answerCount; ++n)
 
536
                                                out_response.answerRecords += import_record(e->response->answerRecords[n]);
 
537
                                        LateResponse lr;
 
538
                                        lr.id = e->id;
 
539
                                        lr.response = out_response;
 
540
                                        if(mode == Unicast)
 
541
                                                lr.do_cancel = true;
 
542
                                        else
 
543
                                                lr.do_cancel = false;
 
544
                                        responses += lr;
 
545
                                }
 
546
                        }
 
547
 
 
548
                        jdns_event_delete(e);
 
549
                }
 
550
 
 
551
                if(ret & JDNS_STEP_TIMER)
 
552
                        stepTimeout.start(jdns_next_timer(sess));
 
553
                else
 
554
                        stepTimeout.stop();
 
555
 
 
556
                need_handle = (ret & JDNS_STEP_HANDLE);
 
557
 
 
558
                // read the lists safely enough so that items can be deleted
 
559
                //   behind our back
 
560
 
 
561
                while(!errors.isEmpty())
 
562
                {
 
563
                        LateError i = errors.takeFirst();
 
564
                        if(i.source_type == 0)
 
565
                                jdns_cancel_query(sess, i.id);
 
566
                        else
 
567
                                jdns_cancel_publish(sess, i.id);
 
568
                        emit q->error(i.id, i.error);
 
569
                        if(!self)
 
570
                                return;
 
571
                }
 
572
 
 
573
                while(!published.isEmpty())
 
574
                {
 
575
                        int i = published.takeFirst();
 
576
                        emit q->published(i);
 
577
                        if(!self)
 
578
                                return;
 
579
                }
 
580
 
 
581
                while(!responses.isEmpty())
 
582
                {
 
583
                        LateResponse i = responses.takeFirst();
 
584
                        if(i.do_cancel)
 
585
                                jdns_cancel_query(sess, i.id);
 
586
                        emit q->resultsReady(i.id, i.response);
 
587
                        if(!self)
 
588
                                return;
 
589
                }
 
590
 
 
591
                if(finish_shutdown)
 
592
                {
 
593
                        // if we have pending udp packets to write, stick around
 
594
                        if(pending > 0)
 
595
                        {
 
596
                                pending_wait = true;
 
597
                        }
 
598
                        else
 
599
                        {
 
600
                                complete_shutdown = true;
 
601
                                process();
 
602
                        }
 
603
                }
 
604
 
 
605
                pErrors = 0;
 
606
                pPublished = 0;
 
607
                pResponses = 0;
 
608
        }
 
609
 
 
610
        void removeCancelled(int id)
 
611
        {
 
612
                if(pErrors)
 
613
                {
 
614
                        for(int n = 0; n < pErrors->count(); ++n)
 
615
                        {
 
616
                                if(pErrors->at(n).id == id)
 
617
                                {
 
618
                                        pErrors->removeAt(n);
 
619
                                        --n; // adjust position
 
620
                                }
 
621
                        }
 
622
                }
 
623
 
 
624
                if(pPublished)
 
625
                {
 
626
                        for(int n = 0; n < pPublished->count(); ++n)
 
627
                        {
 
628
                                if(pPublished->at(n) == id)
 
629
                                {
 
630
                                        pPublished->removeAt(n);
 
631
                                        --n; // adjust position
 
632
                                }
 
633
                        }
 
634
                }
 
635
 
 
636
                if(pResponses)
 
637
                {
 
638
                        for(int n = 0; n < pResponses->count(); ++n)
 
639
                        {
 
640
                                if(pResponses->at(n).id == id)
 
641
                                {
 
642
                                        pResponses->removeAt(n);
 
643
                                        --n; // adjust position
 
644
                                }
 
645
                        }
 
646
                }
 
647
        }
 
648
 
 
649
private slots:
 
650
        void udp_readyRead()
 
651
        {
 
652
                QUdpSocket *sock = (QUdpSocket *)sender();
 
653
                int handle = handleForSocket.value(sock);
 
654
 
 
655
                if(need_handle)
 
656
                {
 
657
                        jdns_set_handle_readable(sess, handle);
 
658
                        process();
 
659
                }
 
660
                else
 
661
                {
 
662
                        // eat packet
 
663
                        QByteArray buf(4096, 0);
 
664
                        QHostAddress from_addr;
 
665
                        quint16 from_port;
 
666
                        sock->readDatagram(buf.data(), buf.size(), &from_addr, &from_port);
 
667
                }
 
668
        }
 
669
 
 
670
        void udp_bytesWritten(qint64)
 
671
        {
 
672
                if(pending > 0)
 
673
                {
 
674
                        --pending;
 
675
                        if(shutting_down && pending_wait && pending == 0)
 
676
                        {
 
677
                                pending_wait = false;
 
678
                                complete_shutdown = true;
 
679
                                process();
 
680
                        }
 
681
                }
 
682
        }
 
683
 
 
684
        void st_timeout()
 
685
        {
 
686
                doNextStep();
 
687
        }
 
688
 
 
689
        void doNextStepSlot()
 
690
        {
 
691
                doNextStep();
 
692
        }
 
693
 
 
694
        void doDebug()
 
695
        {
 
696
                if(new_debug_strings)
 
697
                {
 
698
                        new_debug_strings = false;
 
699
                        if(!debug_strings.isEmpty())
 
700
                                emit q->debugLinesReady();
 
701
                }
 
702
        }
 
703
 
 
704
private:
 
705
        // jdns callbacks
 
706
        static int cb_time_now(jdns_session_t *, void *app)
 
707
        {
 
708
                QJDns::Private *self = (QJDns::Private *)app;
 
709
 
 
710
                return self->clock.elapsed();
 
711
        }
 
712
 
 
713
        static int cb_rand_int(jdns_session_t *, void *)
 
714
        {
 
715
                return rand() % 65536;
 
716
        }
 
717
 
 
718
        static void cb_debug_line(jdns_session_t *, void *app, const char *str)
 
719
        {
 
720
                QJDns::Private *self = (QJDns::Private *)app;
 
721
 
 
722
                self->debug_strings += QString::fromLatin1(str);
 
723
                self->processDebug();
 
724
        }
 
725
 
 
726
        static int cb_udp_bind(jdns_session_t *, void *app, const jdns_address_t *addr, int port, const jdns_address_t *maddr)
 
727
        {
 
728
                QJDns::Private *self = (QJDns::Private *)app;
 
729
 
 
730
                // we always pass non-null to jdns_init, so this should be a valid address
 
731
                QHostAddress host = addr2qt(addr);
 
732
 
 
733
                QUdpSocket *sock = new QUdpSocket(self);
 
734
                self->connect(sock, SIGNAL(readyRead()), SLOT(udp_readyRead()));
 
735
 
 
736
                // use queued for bytesWritten, since qt is evil and emits before writeDatagram returns
 
737
                qRegisterMetaType<qint64>("qint64");
 
738
                self->connect(sock, SIGNAL(bytesWritten(qint64)), SLOT(udp_bytesWritten(qint64)), Qt::QueuedConnection);
 
739
 
 
740
                QUdpSocket::BindMode mode;
 
741
                mode |= QUdpSocket::ShareAddress;
 
742
                mode |= QUdpSocket::ReuseAddressHint;
 
743
                if(!sock->bind(host, port, mode))
 
744
                {
 
745
                        delete sock;
 
746
                        return 0;
 
747
                }
 
748
 
 
749
                if(maddr)
 
750
                {
 
751
                        int sd = sock->socketDescriptor();
 
752
                        bool ok;
 
753
                        int errorCode;
 
754
                        if(maddr->isIpv6)
 
755
                                ok = qjdns_sock_setMulticast6(sd, maddr->addr.v6, &errorCode);
 
756
                        else
 
757
                                ok = qjdns_sock_setMulticast4(sd, maddr->addr.v4, &errorCode);
 
758
 
 
759
                        if(!ok)
 
760
                        {
 
761
                                delete sock;
 
762
 
 
763
                                self->debug_strings += QString("failed to setup multicast on the socket (errorCode=%1)").arg(errorCode);
 
764
                                self->processDebug();
 
765
                                return 0;
 
766
                        }
 
767
 
 
768
                        if(maddr->isIpv6)
 
769
                        {
 
770
                                qjdns_sock_setTTL6(sd, 255);
 
771
                                qjdns_sock_setIPv6Only(sd);
 
772
                        }
 
773
                        else
 
774
                                qjdns_sock_setTTL4(sd, 255);
 
775
                }
 
776
 
 
777
                int handle = self->next_handle++;
 
778
                self->socketForHandle.insert(handle, sock);
 
779
                self->handleForSocket.insert(sock, handle);
 
780
                return handle;
 
781
        }
 
782
 
 
783
        static void cb_udp_unbind(jdns_session_t *, void *app, int handle)
 
784
        {
 
785
                QJDns::Private *self = (QJDns::Private *)app;
 
786
 
 
787
                QUdpSocket *sock = self->socketForHandle.value(handle);
 
788
                if(!sock)
 
789
                        return;
 
790
 
 
791
                self->socketForHandle.remove(handle);
 
792
                self->handleForSocket.remove(sock);
 
793
                delete sock;
 
794
        }
 
795
 
 
796
        static int cb_udp_read(jdns_session_t *, void *app, int handle, jdns_address_t *addr, int *port, unsigned char *buf, int *bufsize)
 
797
        {
 
798
                QJDns::Private *self = (QJDns::Private *)app;
 
799
 
 
800
                QUdpSocket *sock = self->socketForHandle.value(handle);
 
801
                if(!sock)
 
802
                        return 0;
 
803
 
 
804
                // nothing to read?
 
805
                if(!sock->hasPendingDatagrams())
 
806
                        return 0;
 
807
 
 
808
                QHostAddress from_addr;
 
809
                quint16 from_port;
 
810
                int ret = sock->readDatagram((char *)buf, *bufsize, &from_addr, &from_port);
 
811
                if(ret == -1)
 
812
                        return 0;
 
813
 
 
814
                qt2addr_set(addr, from_addr);
 
815
                *port = (int)from_port;
 
816
                *bufsize = ret;
 
817
                return 1;
 
818
        }
 
819
 
 
820
        static int cb_udp_write(jdns_session_t *, void *app, int handle, const jdns_address_t *addr, int port, unsigned char *buf, int bufsize)
 
821
        {
 
822
                QJDns::Private *self = (QJDns::Private *)app;
 
823
 
 
824
                QUdpSocket *sock = self->socketForHandle.value(handle);
 
825
                if(!sock)
 
826
                        return 0;
 
827
 
 
828
                QHostAddress host = addr2qt(addr);
 
829
                int ret = sock->writeDatagram((const char *)buf, bufsize, host, port);
 
830
                if(ret == -1)
 
831
                {
 
832
                        // this can happen if the datagram to send is too big.  i'm not sure what else
 
833
                        //   may cause this.  if we return 0, then jdns may try to resend the packet,
 
834
                        //   which might not work if it is too large (causing the same error over and
 
835
                        //   over).  we'll return success to jdns, so the result is as if the packet
 
836
                        //   was dropped.
 
837
                        return 1;
 
838
                }
 
839
 
 
840
                ++self->pending;
 
841
                return 1;
 
842
        }
 
843
};
 
844
 
 
845
QJDns::QJDns(QObject *parent)
 
846
:QObject(parent)
 
847
{
 
848
        d = new Private(this);
 
849
}
 
850
 
 
851
QJDns::~QJDns()
 
852
{
 
853
        delete d;
 
854
}
 
855
 
 
856
bool QJDns::init(Mode mode, const QHostAddress &address)
 
857
{
 
858
        return d->init(mode, address);
 
859
}
 
860
 
 
861
void QJDns::shutdown()
 
862
{
 
863
        d->shutting_down = true;
 
864
        d->pending_wait = false;
 
865
        d->complete_shutdown = false;
 
866
        jdns_shutdown(d->sess);
 
867
        d->process();
 
868
}
 
869
 
 
870
QStringList QJDns::debugLines()
 
871
{
 
872
        QStringList tmp = d->debug_strings;
 
873
        d->debug_strings.clear();
 
874
        return tmp;
 
875
}
 
876
 
 
877
QJDns::SystemInfo QJDns::systemInfo()
 
878
{
 
879
        SystemInfo out;
 
880
        jdns_dnsparams_t *params = jdns_system_dnsparams();
 
881
        for(int n = 0; n < params->nameservers->count; ++n)
 
882
        {
 
883
                NameServer ns;
 
884
                ns.address = addr2qt(params->nameservers->item[n]->address);
 
885
                out.nameServers += ns;
 
886
        }
 
887
        for(int n = 0; n < params->domains->count; ++n)
 
888
                out.domains += str2qt(params->domains->item[n]);
 
889
        for(int n = 0; n < params->hosts->count; ++n)
 
890
        {
 
891
                DnsHost h;
 
892
                h.name = str2qt(params->hosts->item[n]->name);
 
893
                h.address = addr2qt(params->hosts->item[n]->address);
 
894
                out.hosts += h;
 
895
        }
 
896
        jdns_dnsparams_delete(params);
 
897
        return out;
 
898
}
 
899
 
 
900
#define PROBE_BASE  20000
 
901
#define PROBE_RANGE   100
 
902
 
 
903
QHostAddress QJDns::detectPrimaryMulticast(const QHostAddress &address)
 
904
{
 
905
        my_srand();
 
906
 
 
907
        QUdpSocket *sock = new QUdpSocket;
 
908
        QUdpSocket::BindMode mode;
 
909
        mode |= QUdpSocket::ShareAddress;
 
910
        mode |= QUdpSocket::ReuseAddressHint;
 
911
        int port = -1;
 
912
        for(int n = 0; n < PROBE_RANGE; ++n)
 
913
        {
 
914
                if(sock->bind(address, PROBE_BASE + n, mode))
 
915
                {
 
916
                        port = PROBE_BASE + n;
 
917
                        break;
 
918
                }
 
919
        }
 
920
        if(port == -1)
 
921
        {
 
922
                delete sock;
 
923
                return QHostAddress();
 
924
        }
 
925
 
 
926
        jdns_address_t *a;
 
927
        if(address.protocol() == QAbstractSocket::IPv6Protocol)
 
928
                a = jdns_address_multicast6_new();
 
929
        else
 
930
                a = jdns_address_multicast4_new();
 
931
        QHostAddress maddr = addr2qt(a);
 
932
        jdns_address_delete(a);
 
933
 
 
934
        if(address.protocol() == QAbstractSocket::IPv6Protocol)
 
935
        {
 
936
                int x;
 
937
                if(!qjdns_sock_setMulticast6(sock->socketDescriptor(), maddr.toIPv6Address().c, &x))
 
938
                {
 
939
                        delete sock;
 
940
                        return QHostAddress();
 
941
                }
 
942
                qjdns_sock_setTTL6(sock->socketDescriptor(), 0);
 
943
        }
 
944
        else
 
945
        {
 
946
                int x;
 
947
                if(!qjdns_sock_setMulticast4(sock->socketDescriptor(), maddr.toIPv4Address(), &x))
 
948
                {
 
949
                        delete sock;
 
950
                        return QHostAddress();
 
951
                }
 
952
                qjdns_sock_setTTL4(sock->socketDescriptor(), 0);
 
953
        }
 
954
 
 
955
        QHostAddress result;
 
956
        QByteArray out(128, 0);
 
957
        for(int n = 0; n < out.size(); ++n)
 
958
                out[n] = rand();
 
959
        if(sock->writeDatagram(out.data(), out.size(), maddr, port) == -1)
 
960
        {
 
961
                delete sock;
 
962
                return QHostAddress();
 
963
        }
 
964
        while(1)
 
965
        {
 
966
                if(!sock->waitForReadyRead(1000))
 
967
                {
 
968
                        fprintf(stderr, "QJDns::detectPrimaryMulticast: timeout while checking %s\n", qPrintable(address.toString()));
 
969
                        delete sock;
 
970
                        return QHostAddress();
 
971
                }
 
972
                QByteArray in(128, 0);
 
973
                QHostAddress from_addr;
 
974
                quint16 from_port;
 
975
                int ret = sock->readDatagram(in.data(), in.size(), &from_addr, &from_port);
 
976
                if(ret == -1)
 
977
                {
 
978
                        delete sock;
 
979
                        return QHostAddress();
 
980
                }
 
981
 
 
982
                if(from_port != port)
 
983
                        continue;
 
984
                in.resize(ret);
 
985
                if(in != out)
 
986
                        continue;
 
987
 
 
988
                result = from_addr;
 
989
                break;
 
990
        }
 
991
        delete sock;
 
992
 
 
993
        return result;
 
994
}
 
995
 
 
996
void QJDns::setNameServers(const QList<NameServer> &list)
 
997
{
 
998
        d->setNameServers(list);
 
999
}
 
1000
 
 
1001
int QJDns::queryStart(const QByteArray &name, int type)
 
1002
{
 
1003
        int id = jdns_query(d->sess, (const unsigned char *)name.data(), type);
 
1004
        d->process();
 
1005
        return id;
 
1006
}
 
1007
 
 
1008
void QJDns::queryCancel(int id)
 
1009
{
 
1010
        jdns_cancel_query(d->sess, id);
 
1011
        d->removeCancelled(id);
 
1012
        d->process();
 
1013
}
 
1014
 
 
1015
int QJDns::publishStart(PublishMode m, const Record &record)
 
1016
{
 
1017
        jdns_rr_t *rr = export_record(record);
 
1018
 
 
1019
        int pubmode;
 
1020
        if(m == QJDns::Unique)
 
1021
                pubmode = JDNS_PUBLISH_UNIQUE;
 
1022
        else
 
1023
                pubmode = JDNS_PUBLISH_SHARED;
 
1024
 
 
1025
        int id = jdns_publish(d->sess, pubmode, rr);
 
1026
        jdns_rr_delete(rr);
 
1027
        d->process();
 
1028
        return id;
 
1029
}
 
1030
 
 
1031
void QJDns::publishUpdate(int id, const Record &record)
 
1032
{
 
1033
        jdns_rr_t *rr = export_record(record);
 
1034
 
 
1035
        jdns_update_publish(d->sess, id, rr);
 
1036
        jdns_rr_delete(rr);
 
1037
        d->process();
 
1038
}
 
1039
 
 
1040
void QJDns::publishCancel(int id)
 
1041
{
 
1042
        jdns_cancel_publish(d->sess, id);
 
1043
        d->removeCancelled(id);
 
1044
        d->process();
 
1045
}
 
1046
 
 
1047
#include "qjdns.moc"