~ubuntu-branches/ubuntu/oneiric/psi/oneiric

« back to all changes in this revision

Viewing changes to iris/src/irisnet/appledns/qdnssd.cpp

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

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2007,2008  Justin Karneges
 
3
 *
 
4
 * This library is free software; you can redistribute it and/or
 
5
 * modify it under the terms of the GNU Lesser General Public
 
6
 * License as published by the Free Software Foundation; either
 
7
 * version 2.1 of the License, or (at your option) any later version.
 
8
 *
 
9
 * This library is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
 * Lesser General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU Lesser General Public
 
15
 * License along with this library; if not, write to the Free Software
 
16
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 
17
 * 02110-1301  USA
 
18
 *
 
19
 */
 
20
 
 
21
#include "qdnssd.h"
 
22
 
 
23
#include <QtCore>
 
24
#include <stdio.h>
 
25
 
 
26
// for ntohs
 
27
#ifdef Q_OS_WIN
 
28
# include <windows.h>
 
29
#else
 
30
# include <netinet/in.h>
 
31
#endif
 
32
 
 
33
#include "dns_sd.h"
 
34
 
 
35
namespace {
 
36
 
 
37
// safeobj stuff, from qca
 
38
 
 
39
void releaseAndDeleteLater(QObject *owner, QObject *obj)
 
40
{
 
41
        obj->disconnect(owner);
 
42
        obj->setParent(0);
 
43
        obj->deleteLater();
 
44
}
 
45
 
 
46
class SafeTimer : public QObject
 
47
{
 
48
        Q_OBJECT
 
49
public:
 
50
        SafeTimer(QObject *parent = 0) :
 
51
                QObject(parent)
 
52
        {
 
53
                t = new QTimer(this);
 
54
                connect(t, SIGNAL(timeout()), SIGNAL(timeout()));
 
55
        }
 
56
 
 
57
        ~SafeTimer()
 
58
        {
 
59
                releaseAndDeleteLater(this, t);
 
60
        }
 
61
 
 
62
        int interval() const                { return t->interval(); }
 
63
        bool isActive() const               { return t->isActive(); }
 
64
        bool isSingleShot() const           { return t->isSingleShot(); }
 
65
        void setInterval(int msec)          { t->setInterval(msec); }
 
66
        void setSingleShot(bool singleShot) { t->setSingleShot(singleShot); }
 
67
        int timerId() const                 { return t->timerId(); }
 
68
 
 
69
public slots:
 
70
        void start(int msec)                { t->start(msec); }
 
71
        void start()                        { t->start(); }
 
72
        void stop()                         { t->stop(); }
 
73
 
 
74
signals:
 
75
        void timeout();
 
76
 
 
77
private:
 
78
        QTimer *t;
 
79
};
 
80
 
 
81
class SafeSocketNotifier : public QObject
 
82
{
 
83
        Q_OBJECT
 
84
public:
 
85
        SafeSocketNotifier(int socket, QSocketNotifier::Type type,
 
86
                QObject *parent = 0) :
 
87
                QObject(parent)
 
88
        {
 
89
                sn = new QSocketNotifier(socket, type, this);
 
90
                connect(sn, SIGNAL(activated(int)), SIGNAL(activated(int)));
 
91
        }
 
92
 
 
93
        ~SafeSocketNotifier()
 
94
        {
 
95
                sn->setEnabled(false);
 
96
                releaseAndDeleteLater(this, sn);
 
97
        }
 
98
 
 
99
        bool isEnabled() const             { return sn->isEnabled(); }
 
100
        int socket() const                 { return sn->socket(); }
 
101
        QSocketNotifier::Type type() const { return sn->type(); }
 
102
 
 
103
public slots:
 
104
        void setEnabled(bool enable)       { sn->setEnabled(enable); }
 
105
 
 
106
signals:
 
107
        void activated(int socket);
 
108
 
 
109
private:
 
110
        QSocketNotifier *sn;
 
111
};
 
112
 
 
113
// DNSServiceRef must be allocated by the user and initialized by the
 
114
//   API.  Additionally, it is unclear from the API whether or not
 
115
//   DNSServiceRef can be copied (it is an opaque data structure).
 
116
//   What we'll do is allocate DNSServiceRef on the heap, allowing us
 
117
//   to maintain a pointer which /can/ be copied.  Also, we'll keep
 
118
//   a flag to indicate whether the allocated DNSServiceRef has been
 
119
//   initialized yet.
 
120
class ServiceRef
 
121
{
 
122
private:
 
123
        DNSServiceRef *_p;
 
124
        bool _initialized;
 
125
 
 
126
public:
 
127
        ServiceRef() :
 
128
                _initialized(false)
 
129
        {
 
130
                _p = (DNSServiceRef *)malloc(sizeof(DNSServiceRef));
 
131
        }
 
132
 
 
133
        ~ServiceRef()
 
134
        {
 
135
                if(_initialized)
 
136
                        DNSServiceRefDeallocate(*_p);
 
137
                free(_p);
 
138
        }
 
139
 
 
140
        DNSServiceRef *data()
 
141
        {
 
142
                return _p;
 
143
        }
 
144
 
 
145
        void setInitialized()
 
146
        {
 
147
                _initialized = true;
 
148
        }
 
149
};
 
150
 
 
151
class RecordRef
 
152
{
 
153
private:
 
154
        DNSRecordRef *_p;
 
155
 
 
156
public:
 
157
        RecordRef()
 
158
        {
 
159
                _p = (DNSRecordRef *)malloc(sizeof(DNSRecordRef));
 
160
        }
 
161
 
 
162
        ~RecordRef()
 
163
        {
 
164
                free(_p);
 
165
        }
 
166
 
 
167
        DNSRecordRef *data()
 
168
        {
 
169
                return _p;
 
170
        }
 
171
};
 
172
 
 
173
class IdManager
 
174
{
 
175
private:
 
176
        QSet<int> set;
 
177
        int at;
 
178
 
 
179
        inline void bump_at()
 
180
        {
 
181
                if(at == 0x7fffffff)
 
182
                        at = 0;
 
183
                else
 
184
                        ++at;
 
185
        }
 
186
 
 
187
public:
 
188
        IdManager() :
 
189
                at(0)
 
190
        {
 
191
        }
 
192
 
 
193
        int reserveId()
 
194
        {
 
195
                while(1)
 
196
                {
 
197
                        if(!set.contains(at))
 
198
                        {
 
199
                                int id = at;
 
200
                                set.insert(id);
 
201
                                bump_at();
 
202
                                return id;
 
203
                        }
 
204
 
 
205
                        bump_at();
 
206
                }
 
207
        }
 
208
 
 
209
        void releaseId(int id)
 
210
        {
 
211
                set.remove(id);
 
212
        }
 
213
};
 
214
 
 
215
}
 
216
 
 
217
//----------------------------------------------------------------------------
 
218
// QDnsSd
 
219
//----------------------------------------------------------------------------
 
220
class QDnsSd::Private : public QObject
 
221
{
 
222
        Q_OBJECT
 
223
public:
 
224
        QDnsSd *q;
 
225
        IdManager idManager;
 
226
 
 
227
        class SubRecord
 
228
        {
 
229
        public:
 
230
                Private *_self;
 
231
                int _id;
 
232
                RecordRef *_sdref;
 
233
 
 
234
                SubRecord(Private *self) :
 
235
                        _self(self),
 
236
                        _id(-1),
 
237
                        _sdref(0)
 
238
                {
 
239
                }
 
240
 
 
241
                ~SubRecord()
 
242
                {
 
243
                        delete _sdref;
 
244
                        _self->idManager.releaseId(_id);
 
245
                }
 
246
        };
 
247
 
 
248
        class Request
 
249
        {
 
250
        public:
 
251
                enum Type
 
252
                {
 
253
                        Query,
 
254
                        Browse,
 
255
                        Resolve,
 
256
                        Reg
 
257
                };
 
258
 
 
259
                Private *_self;
 
260
                int _type;
 
261
                int _id;
 
262
                ServiceRef *_sdref;
 
263
                int _sockfd;
 
264
                SafeSocketNotifier *_sn_read;
 
265
                SafeTimer *_errorTrigger;
 
266
 
 
267
                bool _doSignal;
 
268
                LowLevelError _lowLevelError;
 
269
                QList<QDnsSd::Record> _queryRecords;
 
270
                QList<QDnsSd::BrowseEntry> _browseEntries;
 
271
                QByteArray _resolveFullName;
 
272
                QByteArray _resolveHost;
 
273
                int _resolvePort;
 
274
                QByteArray _resolveTxtRecord;
 
275
                QByteArray _regDomain;
 
276
                bool _regConflict;
 
277
 
 
278
                QList<SubRecord*> _subRecords;
 
279
 
 
280
                Request(Private *self) :
 
281
                        _self(self),
 
282
                        _id(-1),
 
283
                        _sdref(0),
 
284
                        _sockfd(-1),
 
285
                        _sn_read(0),
 
286
                        _errorTrigger(0),
 
287
                        _doSignal(false)
 
288
                {
 
289
                }
 
290
 
 
291
                ~Request()
 
292
                {
 
293
                        qDeleteAll(_subRecords);
 
294
 
 
295
                        delete _errorTrigger;
 
296
                        delete _sn_read;
 
297
                        delete _sdref;
 
298
                        _self->idManager.releaseId(_id);
 
299
                }
 
300
 
 
301
                int subRecordIndexById(int rec_id) const
 
302
                {
 
303
                        for(int n = 0; n < _subRecords.count(); ++n)
 
304
                        {
 
305
                                if(_subRecords[n]->_id == rec_id)
 
306
                                        return n;
 
307
                        }
 
308
                        return -1;
 
309
                }
 
310
        };
 
311
 
 
312
        QHash<int,Request*> _requestsById;
 
313
        QHash<SafeSocketNotifier*,Request*> _requestsBySocket;
 
314
        QHash<SafeTimer*,Request*> _requestsByTimer;
 
315
        QHash<int,Request*> _requestsByRecId;
 
316
 
 
317
        Private(QDnsSd *_q) :
 
318
                QObject(_q),
 
319
                q(_q)
 
320
        {
 
321
        }
 
322
 
 
323
        ~Private()
 
324
        {
 
325
                qDeleteAll(_requestsById);
 
326
        }
 
327
 
 
328
        void setDelayedError(Request *req, const LowLevelError &lowLevelError)
 
329
        {
 
330
                delete req->_sdref;
 
331
                req->_sdref = 0;
 
332
 
 
333
                req->_lowLevelError = lowLevelError;
 
334
 
 
335
                req->_errorTrigger = new SafeTimer(this);
 
336
                connect(req->_errorTrigger, SIGNAL(timeout()), SLOT(doError()));
 
337
                req->_errorTrigger->setSingleShot(true);
 
338
 
 
339
                _requestsByTimer.insert(req->_errorTrigger, req);
 
340
 
 
341
                req->_errorTrigger->start();
 
342
        }
 
343
 
 
344
        void removeRequest(Request *req)
 
345
        {
 
346
                foreach(const SubRecord *srec, req->_subRecords)
 
347
                        _requestsByRecId.remove(srec->_id);
 
348
                if(req->_errorTrigger)
 
349
                        _requestsByTimer.remove(req->_errorTrigger);
 
350
                if(req->_sn_read)
 
351
                        _requestsBySocket.remove(req->_sn_read);
 
352
                _requestsById.remove(req->_id);
 
353
                delete req;
 
354
        }
 
355
 
 
356
        int regIdForRecId(int rec_id) const
 
357
        {
 
358
                Request *req = _requestsByRecId.value(rec_id);
 
359
                if(req)
 
360
                        return req->_id;
 
361
                return -1;
 
362
        }
 
363
 
 
364
        int query(const QByteArray &name, int qType)
 
365
        {
 
366
                int id = idManager.reserveId();
 
367
 
 
368
                Request *req = new Request(this);
 
369
                req->_type = Request::Query;
 
370
                req->_id = id;
 
371
                req->_sdref = new ServiceRef;
 
372
 
 
373
                DNSServiceErrorType err = DNSServiceQueryRecord(
 
374
                        req->_sdref->data(), kDNSServiceFlagsLongLivedQuery,
 
375
                        0, name.constData(), qType, kDNSServiceClass_IN,
 
376
                        cb_queryRecordReply, req);
 
377
                if(err != kDNSServiceErr_NoError)
 
378
                {
 
379
                        setDelayedError(req, LowLevelError(
 
380
                                "DNSServiceQueryRecord", err));
 
381
                        return id;
 
382
                }
 
383
 
 
384
                req->_sdref->setInitialized();
 
385
 
 
386
                int sockfd = DNSServiceRefSockFD(*(req->_sdref->data()));
 
387
                if(sockfd == -1)
 
388
                {
 
389
                        setDelayedError(req, LowLevelError(
 
390
                                "DNSServiceRefSockFD", -1));
 
391
                        return id;
 
392
                }
 
393
 
 
394
                req->_sockfd = sockfd;
 
395
                req->_sn_read = new SafeSocketNotifier(sockfd, QSocketNotifier::Read, this);
 
396
                connect(req->_sn_read, SIGNAL(activated(int)), SLOT(sn_activated()));
 
397
                _requestsById.insert(id, req);
 
398
                _requestsBySocket.insert(req->_sn_read, req);
 
399
 
 
400
                return id;
 
401
        }
 
402
 
 
403
        int browse(const QByteArray &serviceType, const QByteArray &domain)
 
404
        {
 
405
                int id = idManager.reserveId();
 
406
 
 
407
                Request *req = new Request(this);
 
408
                req->_type = Request::Browse;
 
409
                req->_id = id;
 
410
                req->_sdref = new ServiceRef;
 
411
 
 
412
                DNSServiceErrorType err = DNSServiceBrowse(
 
413
                        req->_sdref->data(), 0, 0, serviceType.constData(),
 
414
                        !domain.isEmpty() ? domain.constData() : NULL,
 
415
                        cb_browseReply, req);
 
416
                if(err != kDNSServiceErr_NoError)
 
417
                {
 
418
                        setDelayedError(req, LowLevelError(
 
419
                                "DNSServiceBrowse", err));
 
420
                        return id;
 
421
                }
 
422
 
 
423
                req->_sdref->setInitialized();
 
424
 
 
425
                int sockfd = DNSServiceRefSockFD(*(req->_sdref->data()));
 
426
                if(sockfd == -1)
 
427
                {
 
428
                        setDelayedError(req, LowLevelError(
 
429
                                "DNSServiceRefSockFD", -1));
 
430
                        return id;
 
431
                }
 
432
 
 
433
                req->_sockfd = sockfd;
 
434
                req->_sn_read = new SafeSocketNotifier(sockfd, QSocketNotifier::Read, this);
 
435
                connect(req->_sn_read, SIGNAL(activated(int)), SLOT(sn_activated()));
 
436
                _requestsById.insert(id, req);
 
437
                _requestsBySocket.insert(req->_sn_read, req);
 
438
 
 
439
                return id;
 
440
        }
 
441
 
 
442
        int resolve(const QByteArray &serviceName, const QByteArray &serviceType, const QByteArray &domain)
 
443
        {
 
444
                int id = idManager.reserveId();
 
445
 
 
446
                Request *req = new Request(this);
 
447
                req->_type = Request::Resolve;
 
448
                req->_id = id;
 
449
                req->_sdref = new ServiceRef;
 
450
 
 
451
                DNSServiceErrorType err = DNSServiceResolve(
 
452
                        req->_sdref->data(), 0, 0, serviceName.constData(),
 
453
                        serviceType.constData(), domain.constData(),
 
454
                        (DNSServiceResolveReply)cb_resolveReply, req);
 
455
                if(err != kDNSServiceErr_NoError)
 
456
                {
 
457
                        setDelayedError(req, LowLevelError(
 
458
                                "DNSServiceResolve", err));
 
459
                        return id;
 
460
                }
 
461
 
 
462
                req->_sdref->setInitialized();
 
463
 
 
464
                int sockfd = DNSServiceRefSockFD(*(req->_sdref->data()));
 
465
                if(sockfd == -1)
 
466
                {
 
467
                        setDelayedError(req, LowLevelError(
 
468
                                "DNSServiceRefSockFD", -1));
 
469
                        return id;
 
470
                }
 
471
 
 
472
                req->_sockfd = sockfd;
 
473
                req->_sn_read = new SafeSocketNotifier(sockfd, QSocketNotifier::Read, this);
 
474
                connect(req->_sn_read, SIGNAL(activated(int)), SLOT(sn_activated()));
 
475
                _requestsById.insert(id, req);
 
476
                _requestsBySocket.insert(req->_sn_read, req);
 
477
 
 
478
                return id;
 
479
        }
 
480
 
 
481
        int reg(const QByteArray &serviceName, const QByteArray &serviceType, const QByteArray &domain, int port, const QByteArray &txtRecord)
 
482
        {
 
483
                int id = idManager.reserveId();
 
484
 
 
485
                Request *req = new Request(this);
 
486
                req->_type = Request::Reg;
 
487
                req->_id = id;
 
488
 
 
489
                if(port < 1 || port > 0xffff)
 
490
                {
 
491
                        setDelayedError(req, LowLevelError());
 
492
                        return id;
 
493
                }
 
494
 
 
495
                uint16_t sport = port;
 
496
                sport = htons(sport);
 
497
 
 
498
                req->_sdref = new ServiceRef;
 
499
 
 
500
                DNSServiceErrorType err = DNSServiceRegister(
 
501
                        req->_sdref->data(), kDNSServiceFlagsNoAutoRename, 0,
 
502
                        serviceName.constData(), serviceType.constData(),
 
503
                        domain.constData(), NULL, sport, txtRecord.size(),
 
504
                        txtRecord.data(), cb_regReply, req);
 
505
                if(err != kDNSServiceErr_NoError)
 
506
                {
 
507
                        setDelayedError(req, LowLevelError(
 
508
                                "DNSServiceRegister", err));
 
509
                        return id;
 
510
                }
 
511
 
 
512
                req->_sdref->setInitialized();
 
513
 
 
514
                int sockfd = DNSServiceRefSockFD(*(req->_sdref->data()));
 
515
                if(sockfd == -1)
 
516
                {
 
517
                        setDelayedError(req, LowLevelError(
 
518
                                "DNSServiceRefSockFD", -1));
 
519
                        return id;
 
520
                }
 
521
 
 
522
                req->_sockfd = sockfd;
 
523
                req->_sn_read = new SafeSocketNotifier(sockfd, QSocketNotifier::Read, this);
 
524
                connect(req->_sn_read, SIGNAL(activated(int)), SLOT(sn_activated()));
 
525
                _requestsById.insert(id, req);
 
526
                _requestsBySocket.insert(req->_sn_read, req);
 
527
 
 
528
                return id;
 
529
        }
 
530
 
 
531
        int recordAdd(int reg_id, const Record &rec, LowLevelError *lowLevelError)
 
532
        {
 
533
                Request *req = _requestsById.value(reg_id);
 
534
                if(!req)
 
535
                {
 
536
                        if(lowLevelError)
 
537
                                *lowLevelError = LowLevelError();
 
538
                        return -1;
 
539
                }
 
540
 
 
541
                RecordRef *recordRef = new RecordRef;
 
542
 
 
543
                DNSServiceErrorType err = DNSServiceAddRecord(
 
544
                        *(req->_sdref->data()), recordRef->data(), 0,
 
545
                        rec.rrtype, rec.rdata.size(), rec.rdata.data(),
 
546
                        rec.ttl);
 
547
                if(err != kDNSServiceErr_NoError)
 
548
                {
 
549
                        if(lowLevelError)
 
550
                                *lowLevelError = LowLevelError("DNSServiceAddRecord", err);
 
551
                        delete recordRef;
 
552
                        return -1;
 
553
                }
 
554
 
 
555
                int id = idManager.reserveId();
 
556
                SubRecord *srec = new SubRecord(this);
 
557
                srec->_id = id;
 
558
                srec->_sdref = recordRef;
 
559
                req->_subRecords += srec;
 
560
                _requestsByRecId.insert(id, req);
 
561
 
 
562
                return id;
 
563
        }
 
564
 
 
565
        bool recordUpdate(int reg_id, int rec_id, const Record &rec, LowLevelError *lowLevelError)
 
566
        {
 
567
                Request *req = _requestsById.value(reg_id);
 
568
                if(!req)
 
569
                {
 
570
                        if(lowLevelError)
 
571
                                *lowLevelError = LowLevelError();
 
572
                        return false;
 
573
                }
 
574
 
 
575
                SubRecord *srec = 0;
 
576
                if(rec_id != -1)
 
577
                {
 
578
                        int at = req->subRecordIndexById(rec_id);
 
579
                        if(at == -1)
 
580
                        {
 
581
                                if(lowLevelError)
 
582
                                        *lowLevelError = LowLevelError();
 
583
                                return false;
 
584
                        }
 
585
                        srec = req->_subRecords[at];
 
586
                }
 
587
 
 
588
                DNSServiceErrorType err = DNSServiceUpdateRecord(
 
589
                        *(req->_sdref->data()),
 
590
                        srec ? *(srec->_sdref->data()) : NULL, 0,
 
591
                        rec.rdata.size(), rec.rdata.data(), rec.ttl);
 
592
                if(err != kDNSServiceErr_NoError)
 
593
                {
 
594
                        if(lowLevelError)
 
595
                                *lowLevelError = LowLevelError("DNSServiceUpdateRecord", err);
 
596
                        return false;
 
597
                }
 
598
 
 
599
                return true;
 
600
        }
 
601
 
 
602
        void recordRemove(int rec_id)
 
603
        {
 
604
                Request *req = _requestsByRecId.value(rec_id);
 
605
                if(!req)
 
606
                        return;
 
607
 
 
608
                // this can't fail
 
609
                int at = req->subRecordIndexById(rec_id);
 
610
 
 
611
                SubRecord *srec = req->_subRecords[at];
 
612
                DNSServiceRemoveRecord(*(req->_sdref->data()), *(srec->_sdref->data()), 0);
 
613
                _requestsByRecId.remove(srec->_id);
 
614
                req->_subRecords.removeAt(at);
 
615
                delete srec;
 
616
        }
 
617
 
 
618
        void stop(int id)
 
619
        {
 
620
                Request *req = _requestsById.value(id);
 
621
                if(req)
 
622
                        removeRequest(req);
 
623
        }
 
624
 
 
625
private slots:
 
626
        void sn_activated()
 
627
        {
 
628
                SafeSocketNotifier *sn_read = (SafeSocketNotifier *)sender();
 
629
                Request *req = _requestsBySocket.value(sn_read);
 
630
                if(!req)
 
631
                        return;
 
632
 
 
633
                int id = req->_id;
 
634
 
 
635
                DNSServiceErrorType err = DNSServiceProcessResult(*(req->_sdref->data()));
 
636
 
 
637
                // do error if the above function returns an error, or if we
 
638
                //   collected an error during a callback
 
639
                if(err != kDNSServiceErr_NoError || !req->_lowLevelError.func.isEmpty())
 
640
                {
 
641
                        LowLevelError lowLevelError;
 
642
                        if(err != kDNSServiceErr_NoError)
 
643
                                lowLevelError = LowLevelError("DNSServiceProcessResult", err);
 
644
                        else
 
645
                                lowLevelError = req->_lowLevelError;
 
646
 
 
647
                        // reg conflict indicated via callback
 
648
                        bool regConflict = false;
 
649
                        if(req->_type == Request::Reg && !req->_lowLevelError.func.isEmpty())
 
650
                                regConflict = req->_regConflict;
 
651
 
 
652
                        removeRequest(req);
 
653
 
 
654
                        if(req->_type == Request::Query)
 
655
                        {
 
656
                                QDnsSd::QueryResult r;
 
657
                                r.success = false;
 
658
                                r.lowLevelError = lowLevelError;
 
659
                                emit q->queryResult(id, r);
 
660
                        }
 
661
                        else if(req->_type == Request::Browse)
 
662
                        {
 
663
                                QDnsSd::BrowseResult r;
 
664
                                r.success = false;
 
665
                                r.lowLevelError = lowLevelError;
 
666
                                emit q->browseResult(id, r);
 
667
                        }
 
668
                        else if(req->_type == Request::Resolve)
 
669
                        {
 
670
                                QDnsSd::ResolveResult r;
 
671
                                r.success = false;
 
672
                                r.lowLevelError = lowLevelError;
 
673
                                emit q->resolveResult(id, r);
 
674
                        }
 
675
                        else // Reg
 
676
                        {
 
677
                                QDnsSd::RegResult r;
 
678
                                r.success = false;
 
679
                                if(regConflict)
 
680
                                        r.errorCode = QDnsSd::RegResult::ErrorConflict;
 
681
                                else
 
682
                                        r.errorCode = QDnsSd::RegResult::ErrorGeneric;
 
683
                                r.lowLevelError = lowLevelError;
 
684
                                emit q->regResult(id, r);
 
685
                        }
 
686
 
 
687
                        return;
 
688
                }
 
689
 
 
690
                // handle success
 
691
 
 
692
                if(req->_type == Request::Query)
 
693
                {
 
694
                        if(req->_doSignal)
 
695
                        {
 
696
                                QDnsSd::QueryResult r;
 
697
                                r.success = true;
 
698
                                r.records = req->_queryRecords;
 
699
                                req->_queryRecords.clear();
 
700
                                req->_doSignal = false;
 
701
                                emit q->queryResult(id, r);
 
702
                        }
 
703
                }
 
704
                else if(req->_type == Request::Browse)
 
705
                {
 
706
                        if(req->_doSignal)
 
707
                        {
 
708
                                QDnsSd::BrowseResult r;
 
709
                                r.success = true;
 
710
                                r.entries = req->_browseEntries;
 
711
                                req->_browseEntries.clear();
 
712
                                req->_doSignal = false;
 
713
                                emit q->browseResult(id, r);
 
714
                        }
 
715
                }
 
716
                else if(req->_type == Request::Resolve)
 
717
                {
 
718
                        if(req->_doSignal)
 
719
                        {
 
720
                                QDnsSd::ResolveResult r;
 
721
                                r.success = true;
 
722
                                r.fullName = req->_resolveFullName;
 
723
                                r.hostTarget = req->_resolveHost;
 
724
                                r.port = req->_resolvePort;
 
725
                                r.txtRecord = req->_resolveTxtRecord;
 
726
                                req->_doSignal = false;
 
727
 
 
728
                                // there is only one response
 
729
                                removeRequest(req);
 
730
 
 
731
                                emit q->resolveResult(id, r);
 
732
                        }
 
733
                }
 
734
                else // Reg
 
735
                {
 
736
                        if(req->_doSignal)
 
737
                        {
 
738
                                QDnsSd::RegResult r;
 
739
                                r.success = true;
 
740
                                r.domain = req->_regDomain;
 
741
                                req->_doSignal = false;
 
742
 
 
743
                                emit q->regResult(id, r);
 
744
                        }
 
745
                }
 
746
        }
 
747
 
 
748
        void doError()
 
749
        {
 
750
                SafeTimer *t = (SafeTimer *)sender();
 
751
                Request *req = _requestsByTimer.value(t);
 
752
                if(!req)
 
753
                        return;
 
754
 
 
755
                int id = req->_id;
 
756
                int type = req->_type;
 
757
                removeRequest(req);
 
758
 
 
759
                if(type == Request::Query)
 
760
                {
 
761
                        QDnsSd::QueryResult r;
 
762
                        r.success = false;
 
763
                        r.lowLevelError = req->_lowLevelError;
 
764
                        emit q->queryResult(id, r);
 
765
                }
 
766
                else if(type == Request::Browse)
 
767
                {
 
768
                        QDnsSd::BrowseResult r;
 
769
                        r.success = false;
 
770
                        r.lowLevelError = req->_lowLevelError;
 
771
                        emit q->browseResult(id, r);
 
772
                }
 
773
                else if(type == Request::Resolve)
 
774
                {
 
775
                        QDnsSd::ResolveResult r;
 
776
                        r.success = false;
 
777
                        r.lowLevelError = req->_lowLevelError;
 
778
                        emit q->resolveResult(id, r);
 
779
                }
 
780
                else // Reg
 
781
                {
 
782
                        QDnsSd::RegResult r;
 
783
                        r.success = false;
 
784
                        r.errorCode = QDnsSd::RegResult::ErrorGeneric;
 
785
                        r.lowLevelError = req->_lowLevelError;
 
786
                        emit q->regResult(id, r);
 
787
                }
 
788
        }
 
789
 
 
790
private:
 
791
        static void cb_queryRecordReply(DNSServiceRef ref,
 
792
                DNSServiceFlags flags, uint32_t interfaceIndex,
 
793
                DNSServiceErrorType errorCode, const char *fullname,
 
794
                uint16_t rrtype, uint16_t rrclass, uint16_t rdlen,
 
795
                const void *rdata, uint32_t ttl, void *context)
 
796
        {
 
797
                Q_UNUSED(ref);
 
798
                Q_UNUSED(interfaceIndex);
 
799
                Q_UNUSED(rrclass);
 
800
 
 
801
                Request *req = static_cast<Request *>(context);
 
802
                req->_self->handle_queryRecordReply(req, flags, errorCode,
 
803
                        fullname, rrtype, rdlen, (const char *)rdata, ttl);
 
804
        }
 
805
 
 
806
        static void cb_browseReply(DNSServiceRef ref,
 
807
                DNSServiceFlags flags, uint32_t interfaceIndex,
 
808
                DNSServiceErrorType errorCode, const char *serviceName,
 
809
                const char *regtype, const char *replyDomain, void *context)
 
810
        {
 
811
                Q_UNUSED(ref);
 
812
                Q_UNUSED(interfaceIndex);
 
813
 
 
814
                Request *req = static_cast<Request *>(context);
 
815
                req->_self->handle_browseReply(req, flags, errorCode,
 
816
                        serviceName, regtype, replyDomain);
 
817
        }
 
818
 
 
819
        static void cb_resolveReply(DNSServiceRef ref,
 
820
                DNSServiceFlags flags, uint32_t interfaceIndex,
 
821
                DNSServiceErrorType errorCode, const char *fullname,
 
822
                const char *hosttarget, uint16_t port, uint16_t txtLen,
 
823
                const unsigned char *txtRecord, void *context)
 
824
        {
 
825
                Q_UNUSED(ref);
 
826
                Q_UNUSED(flags);
 
827
                Q_UNUSED(interfaceIndex);
 
828
 
 
829
                Request *req = static_cast<Request *>(context);
 
830
                req->_self->handle_resolveReply(req, errorCode, fullname,
 
831
                        hosttarget, port, txtLen, txtRecord);
 
832
        }
 
833
 
 
834
        static void cb_regReply(DNSServiceRef ref,
 
835
                DNSServiceFlags flags, DNSServiceErrorType errorCode,
 
836
                const char *name, const char *regtype, const char *domain,
 
837
                void *context)
 
838
        {
 
839
                Q_UNUSED(ref);
 
840
                Q_UNUSED(flags);
 
841
 
 
842
                Request *req = static_cast<Request *>(context);
 
843
                req->_self->handle_regReply(req, errorCode, name, regtype,
 
844
                        domain);
 
845
        }
 
846
 
 
847
        void handle_queryRecordReply(Request *req, DNSServiceFlags flags,
 
848
                DNSServiceErrorType errorCode, const char *fullname,
 
849
                uint16_t rrtype, uint16_t rdlen, const char *rdata,
 
850
                uint16_t ttl)
 
851
        {
 
852
                if(errorCode != kDNSServiceErr_NoError)
 
853
                {
 
854
                        req->_doSignal = true;
 
855
                        req->_lowLevelError = LowLevelError("DNSServiceQueryRecordReply", errorCode);
 
856
                        return;
 
857
                }
 
858
 
 
859
                QDnsSd::Record rec;
 
860
                rec.added = (flags & kDNSServiceFlagsAdd) ? true: false;
 
861
                rec.name = QByteArray(fullname);
 
862
                rec.rrtype = rrtype;
 
863
                rec.rdata = QByteArray(rdata, rdlen);
 
864
                rec.ttl = ttl;
 
865
                req->_queryRecords += rec;
 
866
 
 
867
                if(!(flags & kDNSServiceFlagsMoreComing))
 
868
                        req->_doSignal = true;
 
869
        }
 
870
 
 
871
        void handle_browseReply(Request *req, DNSServiceFlags flags,
 
872
                DNSServiceErrorType errorCode, const char *serviceName,
 
873
                const char *regtype, const char *replyDomain)
 
874
        {
 
875
                if(errorCode != kDNSServiceErr_NoError)
 
876
                {
 
877
                        req->_doSignal = true;
 
878
                        req->_lowLevelError = LowLevelError("DNSServiceBrowseReply", errorCode);
 
879
                        return;
 
880
                }
 
881
 
 
882
                QDnsSd::BrowseEntry e;
 
883
                e.added = (flags & kDNSServiceFlagsAdd) ? true: false;
 
884
                e.serviceName = QByteArray(serviceName);
 
885
                e.serviceType = QByteArray(regtype);
 
886
                e.replyDomain = QByteArray(replyDomain);
 
887
                req->_browseEntries += e;
 
888
 
 
889
                if(!(flags & kDNSServiceFlagsMoreComing))
 
890
                        req->_doSignal = true;
 
891
        }
 
892
 
 
893
        void handle_resolveReply(Request *req, DNSServiceErrorType errorCode,
 
894
                const char *fullname, const char *hosttarget, uint16_t port,
 
895
                uint16_t txtLen, const unsigned char *txtRecord)
 
896
        {
 
897
                if(errorCode != kDNSServiceErr_NoError)
 
898
                {
 
899
                        req->_doSignal = true;
 
900
                        req->_lowLevelError = LowLevelError("DNSServiceResolveReply", errorCode);
 
901
                        return;
 
902
                }
 
903
 
 
904
                req->_resolveFullName = QByteArray(fullname);
 
905
                req->_resolveHost = QByteArray(hosttarget);
 
906
                req->_resolvePort = ntohs(port);
 
907
                req->_resolveTxtRecord = QByteArray((const char *)txtRecord, txtLen);
 
908
 
 
909
                req->_doSignal = true;
 
910
        }
 
911
 
 
912
        void handle_regReply(Request *req, DNSServiceErrorType errorCode,
 
913
                const char *name, const char *regtype, const char *domain)
 
914
        {
 
915
                Q_UNUSED(name);
 
916
                Q_UNUSED(regtype);
 
917
 
 
918
                if(errorCode != kDNSServiceErr_NoError)
 
919
                {
 
920
                        req->_doSignal = true;
 
921
                        req->_lowLevelError = LowLevelError("DNSServiceRegisterReply", errorCode);
 
922
 
 
923
                        if(errorCode == kDNSServiceErr_NameConflict)
 
924
                                req->_regConflict = true;
 
925
                        else
 
926
                                req->_regConflict = false;
 
927
                        return;
 
928
                }
 
929
 
 
930
                req->_regDomain = QByteArray(domain);
 
931
                req->_doSignal = true;
 
932
        }
 
933
};
 
934
 
 
935
QDnsSd::QDnsSd(QObject *parent) :
 
936
        QObject(parent)
 
937
{
 
938
        d = new Private(this);
 
939
}
 
940
 
 
941
QDnsSd::~QDnsSd()
 
942
{
 
943
        delete d;
 
944
}
 
945
 
 
946
int QDnsSd::query(const QByteArray &name, int qType)
 
947
{
 
948
        return d->query(name, qType);
 
949
}
 
950
 
 
951
int QDnsSd::browse(const QByteArray &serviceType, const QByteArray &domain)
 
952
{
 
953
        return d->browse(serviceType, domain);
 
954
}
 
955
 
 
956
int QDnsSd::resolve(const QByteArray &serviceName, const QByteArray &serviceType, const QByteArray &domain)
 
957
{
 
958
        return d->resolve(serviceName, serviceType, domain);
 
959
}
 
960
 
 
961
int QDnsSd::reg(const QByteArray &serviceName, const QByteArray &serviceType, const QByteArray &domain, int port, const QByteArray &txtRecord)
 
962
{
 
963
        return d->reg(serviceName, serviceType, domain, port, txtRecord);
 
964
}
 
965
 
 
966
int QDnsSd::recordAdd(int reg_id, const Record &rec, LowLevelError *lowLevelError)
 
967
{
 
968
        return d->recordAdd(reg_id, rec, lowLevelError);
 
969
}
 
970
 
 
971
bool QDnsSd::recordUpdate(int rec_id, const Record &rec, LowLevelError *lowLevelError)
 
972
{
 
973
        int reg_id = d->regIdForRecId(rec_id);
 
974
        if(reg_id == -1)
 
975
                return false;
 
976
 
 
977
        return d->recordUpdate(reg_id, rec_id, rec, lowLevelError);
 
978
}
 
979
 
 
980
bool QDnsSd::recordUpdateTxt(int reg_id, const QByteArray &txtRecord, quint32 ttl, LowLevelError *lowLevelError)
 
981
{
 
982
        Record rec;
 
983
        rec.rrtype = kDNSServiceType_TXT;
 
984
        rec.rdata = txtRecord;
 
985
        rec.ttl = ttl;
 
986
        return d->recordUpdate(reg_id, -1, rec, lowLevelError);
 
987
}
 
988
 
 
989
void QDnsSd::recordRemove(int rec_id)
 
990
{
 
991
        d->recordRemove(rec_id);
 
992
}
 
993
 
 
994
void QDnsSd::stop(int id)
 
995
{
 
996
        d->stop(id);
 
997
}
 
998
 
 
999
QByteArray QDnsSd::createTxtRecord(const QList<QByteArray> &strings)
 
1000
{
 
1001
        // split into var/val and validate
 
1002
        QList<QByteArray> vars;
 
1003
        QList<QByteArray> vals; // null = no value, empty = empty value
 
1004
        foreach(const QByteArray &i, strings)
 
1005
        {
 
1006
                QByteArray var;
 
1007
                QByteArray val;
 
1008
                int n = i.indexOf('=');
 
1009
                if(n != -1)
 
1010
                {
 
1011
                        var = i.mid(0, n);
 
1012
                        val = i.mid(n + 1);
 
1013
                }
 
1014
                else
 
1015
                        var = i;
 
1016
 
 
1017
                for(int n = 0; n < var.size(); ++n)
 
1018
                {
 
1019
                        unsigned char c = var[n];
 
1020
                        if(c < 0x20 || c > 0x7e)
 
1021
                                return QByteArray();
 
1022
                }
 
1023
 
 
1024
                vars += var;
 
1025
                vals += val;
 
1026
        }
 
1027
 
 
1028
        TXTRecordRef ref;
 
1029
        QByteArray buf(256, 0);
 
1030
        TXTRecordCreate(&ref, buf.size(), buf.data());
 
1031
        for(int n = 0; n < vars.count(); ++n)
 
1032
        {
 
1033
                int valueSize = vals[n].size();
 
1034
                char *value;
 
1035
                if(!vals[n].isNull())
 
1036
                        value = vals[n].data();
 
1037
                else
 
1038
                        value = 0;
 
1039
 
 
1040
                DNSServiceErrorType err = TXTRecordSetValue(&ref,
 
1041
                        vars[n].data(), valueSize, value);
 
1042
                if(err != kDNSServiceErr_NoError)
 
1043
                {
 
1044
                        TXTRecordDeallocate(&ref);
 
1045
                        return QByteArray();
 
1046
                }
 
1047
        }
 
1048
        QByteArray out((const char *)TXTRecordGetBytesPtr(&ref), TXTRecordGetLength(&ref));
 
1049
        TXTRecordDeallocate(&ref);
 
1050
        return out;
 
1051
}
 
1052
 
 
1053
QList<QByteArray> QDnsSd::parseTxtRecord(const QByteArray &txtRecord)
 
1054
{
 
1055
        QList<QByteArray> out;
 
1056
        int count = TXTRecordGetCount(txtRecord.size(), txtRecord.data());
 
1057
        for(int n = 0; n < count; ++n)
 
1058
        {
 
1059
                QByteArray keyBuf(256, 0);
 
1060
                uint8_t valueLen;
 
1061
                const void *value;
 
1062
                DNSServiceErrorType err = TXTRecordGetItemAtIndex(
 
1063
                        txtRecord.size(), txtRecord.data(), n, keyBuf.size(),
 
1064
                        keyBuf.data(), &valueLen, &value);
 
1065
                if(err != kDNSServiceErr_NoError)
 
1066
                        return QList<QByteArray>();
 
1067
 
 
1068
                keyBuf.resize(qstrlen(keyBuf.data()));
 
1069
 
 
1070
                QByteArray entry = keyBuf;
 
1071
                if(value)
 
1072
                {
 
1073
                        entry += '=';
 
1074
                        entry += QByteArray((const char *)value, valueLen);
 
1075
                }
 
1076
                out += entry;
 
1077
        }
 
1078
        return out;
 
1079
}
 
1080
 
 
1081
#include "qdnssd.moc"