File indexing completed on 2024-05-19 04:06:39
0001 /* 0002 * Copyright (C) 2005-2008 Justin Karneges 0003 * 0004 * Permission is hereby granted, free of charge, to any person obtaining a 0005 * copy of this software and associated documentation files (the 0006 * "Software"), to deal in the Software without restriction, including 0007 * without limitation the rights to use, copy, modify, merge, publish, 0008 * distribute, sublicense, and/or sell copies of the Software, and to 0009 * permit persons to whom the Software is furnished to do so, subject to 0010 * the following conditions: 0011 * 0012 * The above copyright notice and this permission notice shall be included 0013 * in all copies or substantial portions of the Software. 0014 * 0015 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 0016 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 0017 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 0018 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 0019 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 0020 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 0021 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 0022 */ 0023 0024 #include "qjdns.h" 0025 0026 #include <time.h> 0027 #include "qjdns_sock.h" 0028 #include "jdns.h" 0029 0030 // for fprintf 0031 #include <stdio.h> 0032 0033 namespace { 0034 0035 // safeobj stuff, from qca 0036 0037 void releaseAndDeleteLater(QObject *owner, QObject *obj) 0038 { 0039 obj->disconnect(owner); 0040 obj->setParent(0); 0041 obj->deleteLater(); 0042 } 0043 0044 class SafeTimer : public QObject 0045 { 0046 Q_OBJECT 0047 public: 0048 SafeTimer(QObject *parent = 0) : 0049 QObject(parent) 0050 { 0051 t = new QTimer(this); 0052 connect(t, &QTimer::timeout, this, &SafeTimer::timeout); 0053 } 0054 0055 ~SafeTimer() override 0056 { 0057 releaseAndDeleteLater(this, t); 0058 } 0059 0060 int interval() const { return t->interval(); } 0061 bool isActive() const { return t->isActive(); } 0062 bool isSingleShot() const { return t->isSingleShot(); } 0063 void setInterval(int msec) { t->setInterval(msec); } 0064 void setSingleShot(bool singleShot) { t->setSingleShot(singleShot); } 0065 int timerId() const { return t->timerId(); } 0066 0067 public slots: 0068 void start(int msec) { t->start(msec); } 0069 void start() { t->start(); } 0070 void stop() { t->stop(); } 0071 0072 signals: 0073 void timeout(); 0074 0075 private: 0076 QTimer *t; 0077 }; 0078 0079 } 0080 0081 static jdns_string_t *qt2str(const QByteArray &in) 0082 { 0083 jdns_string_t *out = jdns_string_new(); 0084 jdns_string_set(out, (const unsigned char *)in.data(), in.size()); 0085 return out; 0086 } 0087 0088 static QByteArray str2qt(const jdns_string_t *in) 0089 { 0090 return QByteArray((const char *)in->data, in->size); 0091 } 0092 0093 static void qt2addr_set(jdns_address_t *addr, const QHostAddress &host) 0094 { 0095 if(host.protocol() == QAbstractSocket::IPv6Protocol) 0096 jdns_address_set_ipv6(addr, host.toIPv6Address().c); 0097 else 0098 jdns_address_set_ipv4(addr, host.toIPv4Address()); 0099 } 0100 0101 static jdns_address_t *qt2addr(const QHostAddress &host) 0102 { 0103 jdns_address_t *addr = jdns_address_new(); 0104 qt2addr_set(addr, host); 0105 return addr; 0106 } 0107 0108 static QHostAddress addr2qt(const jdns_address_t *addr) 0109 { 0110 if(addr->isIpv6) 0111 return QHostAddress(addr->addr.v6); 0112 else 0113 return QHostAddress(addr->addr.v4); 0114 } 0115 0116 static QJDns::Record import_record(const jdns_rr_t *in) 0117 { 0118 QJDns::Record out; 0119 0120 out.owner = QByteArray((const char *)in->owner); 0121 out.ttl = in->ttl; 0122 out.type = in->type; 0123 out.rdata = QByteArray((const char *)in->rdata, in->rdlength); 0124 0125 // known 0126 if(in->haveKnown) 0127 { 0128 int type = in->type; 0129 0130 if(type == QJDns::A || type == QJDns::Aaaa) 0131 { 0132 out.haveKnown = true; 0133 out.address = addr2qt(in->data.address); 0134 } 0135 else if(type == QJDns::Mx) 0136 { 0137 out.haveKnown = true; 0138 out.name = QByteArray((const char *)in->data.server->name); 0139 out.priority = in->data.server->priority; 0140 } 0141 else if(type == QJDns::Srv) 0142 { 0143 out.haveKnown = true; 0144 out.name = QByteArray((const char *)in->data.server->name); 0145 out.priority = in->data.server->priority; 0146 out.weight = in->data.server->weight; 0147 out.port = in->data.server->port; 0148 } 0149 else if(type == QJDns::Cname || type == QJDns::Ptr || type == QJDns::Ns) 0150 { 0151 out.haveKnown = true; 0152 out.name = QByteArray((const char *)in->data.name); 0153 } 0154 else if(type == QJDns::Txt) 0155 { 0156 out.haveKnown = true; 0157 out.texts.clear(); 0158 for(int n = 0; n < in->data.texts->count; ++n) 0159 out.texts += str2qt(in->data.texts->item[n]); 0160 } 0161 else if(type == QJDns::Hinfo) 0162 { 0163 out.haveKnown = true; 0164 out.cpu = str2qt(in->data.hinfo.cpu); 0165 out.os = str2qt(in->data.hinfo.os); 0166 } 0167 } 0168 0169 return out; 0170 } 0171 0172 static jdns_rr_t *export_record(const QJDns::Record &in) 0173 { 0174 jdns_rr_t *out = jdns_rr_new(); 0175 0176 jdns_rr_set_owner(out, (const unsigned char *)in.owner.data()); 0177 out->ttl = in.ttl; 0178 0179 // if we have known, use that 0180 if(in.haveKnown) 0181 { 0182 int type = in.type; 0183 0184 if(type == QJDns::A) 0185 { 0186 jdns_address_t *addr = qt2addr(in.address); 0187 jdns_rr_set_A(out, addr); 0188 jdns_address_delete(addr); 0189 } 0190 else if(type == QJDns::Aaaa) 0191 { 0192 jdns_address_t *addr = qt2addr(in.address); 0193 jdns_rr_set_AAAA(out, addr); 0194 jdns_address_delete(addr); 0195 } 0196 else if(type == QJDns::Mx) 0197 { 0198 jdns_rr_set_MX(out, (const unsigned char *)in.name.data(), in.priority); 0199 } 0200 else if(type == QJDns::Srv) 0201 { 0202 jdns_rr_set_SRV(out, (const unsigned char *)in.name.data(), in.port, in.priority, in.weight); 0203 } 0204 else if(type == QJDns::Cname) 0205 { 0206 jdns_rr_set_CNAME(out, (const unsigned char *)in.name.data()); 0207 } 0208 else if(type == QJDns::Ptr) 0209 { 0210 jdns_rr_set_PTR(out, (const unsigned char *)in.name.data()); 0211 } 0212 else if(type == QJDns::Txt) 0213 { 0214 jdns_stringlist_t *list = jdns_stringlist_new(); 0215 for(int n = 0; n < in.texts.count(); ++n) 0216 { 0217 jdns_string_t *str = qt2str(in.texts[n]); 0218 jdns_stringlist_append(list, str); 0219 jdns_string_delete(str); 0220 } 0221 jdns_rr_set_TXT(out, list); 0222 jdns_stringlist_delete(list); 0223 } 0224 else if(type == QJDns::Hinfo) 0225 { 0226 jdns_string_t *cpu = qt2str(in.cpu); 0227 jdns_string_t *os = qt2str(in.os); 0228 jdns_rr_set_HINFO(out, cpu, os); 0229 jdns_string_delete(cpu); 0230 jdns_string_delete(os); 0231 } 0232 else if(type == QJDns::Ns) 0233 { 0234 jdns_rr_set_NS(out, (const unsigned char *)in.name.data()); 0235 } 0236 } 0237 else 0238 jdns_rr_set_record(out, in.type, (const unsigned char *)in.rdata.data(), in.rdata.size()); 0239 0240 return out; 0241 } 0242 0243 //---------------------------------------------------------------------------- 0244 // QJDns::NameServer 0245 //---------------------------------------------------------------------------- 0246 QJDns::NameServer::NameServer() 0247 { 0248 port = JDNS_UNICAST_PORT; 0249 } 0250 0251 //---------------------------------------------------------------------------- 0252 // QJDns::Record 0253 //---------------------------------------------------------------------------- 0254 QJDns::Record::Record() 0255 { 0256 ttl = 0; 0257 type = -1; 0258 haveKnown = false; 0259 } 0260 0261 bool QJDns::Record::verify() const 0262 { 0263 jdns_rr_t *rr = export_record(*this); 0264 int ok = jdns_rr_verify(rr); 0265 jdns_rr_delete(rr); 0266 return (ok ? true : false); 0267 } 0268 0269 //---------------------------------------------------------------------------- 0270 // QJDns 0271 //---------------------------------------------------------------------------- 0272 static int my_srand_done = 0; 0273 0274 static void my_srand() 0275 { 0276 if(my_srand_done) 0277 return; 0278 0279 // lame attempt at randomizing without srand 0280 int count = ::time(NULL) % 128; 0281 for(int n = 0; n < count; ++n) 0282 rand(); 0283 0284 my_srand_done = 1; 0285 } 0286 0287 class QJDns::Private : public QObject 0288 { 0289 Q_OBJECT 0290 public: 0291 class LateError 0292 { 0293 public: 0294 int source_type; // 0 for query, 1 for publish 0295 int id; 0296 Error error; 0297 }; 0298 0299 class LateResponse 0300 { 0301 public: 0302 int id; 0303 QJDns::Response response; 0304 bool do_cancel; 0305 }; 0306 0307 QJDns *q; 0308 QJDns::Mode mode; 0309 jdns_session_t *sess; 0310 bool shutting_down; 0311 SafeTimer stepTrigger, debugTrigger; 0312 SafeTimer stepTimeout; 0313 QElapsedTimer clock; 0314 QStringList debug_strings; 0315 bool new_debug_strings; 0316 int next_handle; 0317 bool need_handle; 0318 QHash<int,QUdpSocket*> socketForHandle; 0319 QHash<QUdpSocket*,int> handleForSocket; 0320 int pending; 0321 bool pending_wait; 0322 bool complete_shutdown; 0323 0324 // pointers that will point to things we are currently signalling 0325 // about. when a query or publish is cancelled, we can use these 0326 // pointers to extract anything we shouldn't signal. 0327 QList<LateError> *pErrors; 0328 QList<int> *pPublished; 0329 QList<LateResponse> *pResponses; 0330 0331 Private(QJDns *_q) : 0332 QObject(_q), 0333 q(_q), 0334 stepTrigger(this), 0335 debugTrigger(this), 0336 stepTimeout(this), 0337 pErrors(0), 0338 pPublished(0), 0339 pResponses(0) 0340 { 0341 sess = 0; 0342 shutting_down = false; 0343 new_debug_strings = false; 0344 pending = 0; 0345 0346 connect(&stepTrigger, &SafeTimer::timeout, this, &Private::doNextStepSlot); 0347 stepTrigger.setSingleShot(true); 0348 0349 connect(&debugTrigger, &SafeTimer::timeout, this, &Private::doDebug); 0350 debugTrigger.setSingleShot(true); 0351 0352 connect(&stepTimeout, &SafeTimer::timeout, this, &Private::st_timeout); 0353 stepTimeout.setSingleShot(true); 0354 0355 my_srand(); 0356 0357 clock.start(); 0358 } 0359 0360 ~Private() override 0361 { 0362 cleanup(); 0363 } 0364 0365 void cleanup() 0366 { 0367 if(sess) 0368 { 0369 jdns_session_delete(sess); 0370 sess = 0; 0371 } 0372 0373 shutting_down = false; 0374 pending = 0; 0375 0376 // it is safe to delete the QUdpSocket objects here without 0377 // deleteLater, since this code path never occurs when 0378 // a signal from those objects is on the stack 0379 qDeleteAll(socketForHandle); 0380 socketForHandle.clear(); 0381 handleForSocket.clear(); 0382 0383 stepTrigger.stop(); 0384 stepTimeout.stop(); 0385 need_handle = 0; 0386 } 0387 0388 bool init(QJDns::Mode _mode, const QHostAddress &address) 0389 { 0390 mode = _mode; 0391 0392 jdns_callbacks_t callbacks; 0393 callbacks.app = this; 0394 callbacks.time_now = cb_time_now; 0395 callbacks.rand_int = cb_rand_int; 0396 callbacks.debug_line = cb_debug_line; 0397 callbacks.udp_bind = cb_udp_bind; 0398 callbacks.udp_unbind = cb_udp_unbind; 0399 callbacks.udp_read = cb_udp_read; 0400 callbacks.udp_write = cb_udp_write; 0401 sess = jdns_session_new(&callbacks); 0402 jdns_set_hold_ids_enabled(sess, 1); 0403 next_handle = 1; 0404 need_handle = false; 0405 0406 int ret; 0407 0408 jdns_address_t *baddr = qt2addr(address); 0409 if(mode == Unicast) 0410 { 0411 ret = jdns_init_unicast(sess, baddr, 0); 0412 } 0413 else 0414 { 0415 jdns_address_t *maddr; 0416 if(address.protocol() == QAbstractSocket::IPv6Protocol) 0417 maddr = jdns_address_multicast6_new(); 0418 else 0419 maddr = jdns_address_multicast4_new(); 0420 ret = jdns_init_multicast(sess, baddr, JDNS_MULTICAST_PORT, maddr); 0421 jdns_address_delete(maddr); 0422 } 0423 jdns_address_delete(baddr); 0424 0425 if(!ret) 0426 { 0427 jdns_session_delete(sess); 0428 sess = 0; 0429 return false; 0430 } 0431 return true; 0432 } 0433 0434 void setNameServers(const QList<NameServer> &nslist) 0435 { 0436 jdns_nameserverlist_t *addrs = jdns_nameserverlist_new(); 0437 for(int n = 0; n < nslist.count(); ++n) 0438 { 0439 jdns_address_t *addr = qt2addr(nslist[n].address); 0440 jdns_nameserverlist_append(addrs, addr, nslist[n].port); 0441 jdns_address_delete(addr); 0442 } 0443 jdns_set_nameservers(sess, addrs); 0444 jdns_nameserverlist_delete(addrs); 0445 } 0446 0447 void process() 0448 { 0449 if(!stepTrigger.isActive()) 0450 { 0451 stepTimeout.stop(); 0452 stepTrigger.start(); 0453 } 0454 } 0455 0456 void processDebug() 0457 { 0458 new_debug_strings = true; 0459 if(!debugTrigger.isActive()) 0460 debugTrigger.start(); 0461 } 0462 0463 void doNextStep() 0464 { 0465 if(shutting_down && complete_shutdown) 0466 { 0467 cleanup(); 0468 emit q->shutdownFinished(); 0469 return; 0470 } 0471 0472 QPointer<QObject> self = this; 0473 0474 int ret = jdns_step(sess); 0475 0476 QList<LateError> errors; 0477 QList<int> published; 0478 QList<LateResponse> responses; 0479 bool finish_shutdown = false; 0480 0481 pErrors = &errors; 0482 pPublished = &published; 0483 pResponses = &responses; 0484 0485 while(1) 0486 { 0487 jdns_event_t *e = jdns_next_event(sess); 0488 if(!e) 0489 break; 0490 0491 if(e->type == JDNS_EVENT_SHUTDOWN) 0492 { 0493 finish_shutdown = true; 0494 } 0495 else if(e->type == JDNS_EVENT_PUBLISH) 0496 { 0497 if(e->status != JDNS_STATUS_SUCCESS) 0498 { 0499 QJDns::Error error; 0500 if(e->status == JDNS_STATUS_CONFLICT) 0501 error = QJDns::ErrorConflict; 0502 else 0503 error = QJDns::ErrorGeneric; 0504 LateError le; 0505 le.source_type = 1; 0506 le.id = e->id; 0507 le.error = error; 0508 errors += le; 0509 } 0510 else 0511 { 0512 published += e->id; 0513 } 0514 } 0515 else if(e->type == JDNS_EVENT_RESPONSE) 0516 { 0517 if(e->status != JDNS_STATUS_SUCCESS) 0518 { 0519 QJDns::Error error; 0520 if(e->status == JDNS_STATUS_NXDOMAIN) 0521 error = QJDns::ErrorNXDomain; 0522 else if(e->status == JDNS_STATUS_TIMEOUT) 0523 error = QJDns::ErrorTimeout; 0524 else 0525 error = QJDns::ErrorGeneric; 0526 LateError le; 0527 le.source_type = 0; 0528 le.id = e->id; 0529 le.error = error; 0530 errors += le; 0531 } 0532 else 0533 { 0534 QJDns::Response out_response; 0535 for(int n = 0; n < e->response->answerCount; ++n) 0536 out_response.answerRecords += import_record(e->response->answerRecords[n]); 0537 LateResponse lr; 0538 lr.id = e->id; 0539 lr.response = out_response; 0540 if(mode == Unicast) 0541 lr.do_cancel = true; 0542 else 0543 lr.do_cancel = false; 0544 responses += lr; 0545 } 0546 } 0547 0548 jdns_event_delete(e); 0549 } 0550 0551 if(ret & JDNS_STEP_TIMER) 0552 stepTimeout.start(jdns_next_timer(sess)); 0553 else 0554 stepTimeout.stop(); 0555 0556 need_handle = (ret & JDNS_STEP_HANDLE); 0557 0558 // read the lists safely enough so that items can be deleted 0559 // behind our back 0560 0561 while(!errors.isEmpty()) 0562 { 0563 LateError i = errors.takeFirst(); 0564 if(i.source_type == 0) 0565 jdns_cancel_query(sess, i.id); 0566 else 0567 jdns_cancel_publish(sess, i.id); 0568 emit q->error(i.id, i.error); 0569 if(!self) 0570 return; 0571 } 0572 0573 while(!published.isEmpty()) 0574 { 0575 int i = published.takeFirst(); 0576 emit q->published(i); 0577 if(!self) 0578 return; 0579 } 0580 0581 while(!responses.isEmpty()) 0582 { 0583 LateResponse i = responses.takeFirst(); 0584 if(i.do_cancel) 0585 jdns_cancel_query(sess, i.id); 0586 emit q->resultsReady(i.id, i.response); 0587 if(!self) 0588 return; 0589 } 0590 0591 if(finish_shutdown) 0592 { 0593 // if we have pending udp packets to write, stick around 0594 if(pending > 0) 0595 { 0596 pending_wait = true; 0597 } 0598 else 0599 { 0600 complete_shutdown = true; 0601 process(); 0602 } 0603 } 0604 0605 pErrors = 0; 0606 pPublished = 0; 0607 pResponses = 0; 0608 } 0609 0610 void removeCancelled(int id) 0611 { 0612 if(pErrors) 0613 { 0614 for(int n = 0; n < pErrors->count(); ++n) 0615 { 0616 if(pErrors->at(n).id == id) 0617 { 0618 pErrors->removeAt(n); 0619 --n; // adjust position 0620 } 0621 } 0622 } 0623 0624 if(pPublished) 0625 { 0626 for(int n = 0; n < pPublished->count(); ++n) 0627 { 0628 if(pPublished->at(n) == id) 0629 { 0630 pPublished->removeAt(n); 0631 --n; // adjust position 0632 } 0633 } 0634 } 0635 0636 if(pResponses) 0637 { 0638 for(int n = 0; n < pResponses->count(); ++n) 0639 { 0640 if(pResponses->at(n).id == id) 0641 { 0642 pResponses->removeAt(n); 0643 --n; // adjust position 0644 } 0645 } 0646 } 0647 } 0648 0649 private slots: 0650 void udp_readyRead() 0651 { 0652 QUdpSocket *sock = (QUdpSocket *)sender(); 0653 int handle = handleForSocket.value(sock); 0654 0655 if(need_handle) 0656 { 0657 jdns_set_handle_readable(sess, handle); 0658 process(); 0659 } 0660 else 0661 { 0662 // eat packet 0663 QByteArray buf(4096, 0); 0664 QHostAddress from_addr; 0665 quint16 from_port; 0666 sock->readDatagram(buf.data(), buf.size(), &from_addr, &from_port); 0667 } 0668 } 0669 0670 void udp_bytesWritten(qint64) 0671 { 0672 if(pending > 0) 0673 { 0674 --pending; 0675 if(shutting_down && pending_wait && pending == 0) 0676 { 0677 pending_wait = false; 0678 complete_shutdown = true; 0679 process(); 0680 } 0681 } 0682 } 0683 0684 void st_timeout() 0685 { 0686 doNextStep(); 0687 } 0688 0689 void doNextStepSlot() 0690 { 0691 doNextStep(); 0692 } 0693 0694 void doDebug() 0695 { 0696 if(new_debug_strings) 0697 { 0698 new_debug_strings = false; 0699 if(!debug_strings.isEmpty()) 0700 emit q->debugLinesReady(); 0701 } 0702 } 0703 0704 private: 0705 // jdns callbacks 0706 static int cb_time_now(jdns_session_t *, void *app) 0707 { 0708 QJDns::Private *self = (QJDns::Private *)app; 0709 0710 return self->clock.elapsed(); 0711 } 0712 0713 static int cb_rand_int(jdns_session_t *, void *) 0714 { 0715 return rand() % 65536; 0716 } 0717 0718 static void cb_debug_line(jdns_session_t *, void *app, const char *str) 0719 { 0720 QJDns::Private *self = (QJDns::Private *)app; 0721 0722 self->debug_strings += QString::fromLatin1(str); 0723 self->processDebug(); 0724 } 0725 0726 static int cb_udp_bind(jdns_session_t *, void *app, const jdns_address_t *addr, int port, const jdns_address_t *maddr) 0727 { 0728 QJDns::Private *self = (QJDns::Private *)app; 0729 0730 // we always pass non-null to jdns_init, so this should be a valid address 0731 QHostAddress host = addr2qt(addr); 0732 0733 QUdpSocket *sock = new QUdpSocket(self); 0734 self->connect(sock, &QIODevice::readyRead, self, &Private::udp_readyRead); 0735 0736 // use queued for bytesWritten, since qt is evil and emits before writeDatagram returns 0737 qRegisterMetaType<qint64>("qint64"); 0738 self->connect(sock, &QIODevice::bytesWritten, self, &Private::udp_bytesWritten, Qt::QueuedConnection); 0739 0740 QUdpSocket::BindMode mode; 0741 mode |= QUdpSocket::ShareAddress; 0742 mode |= QUdpSocket::ReuseAddressHint; 0743 if(!sock->bind(host, port, mode)) 0744 { 0745 delete sock; 0746 return 0; 0747 } 0748 0749 if(maddr) 0750 { 0751 int sd = sock->socketDescriptor(); 0752 bool ok; 0753 int errorCode; 0754 if(maddr->isIpv6) 0755 ok = qjdns_sock_setMulticast6(sd, maddr->addr.v6, &errorCode); 0756 else 0757 ok = qjdns_sock_setMulticast4(sd, maddr->addr.v4, &errorCode); 0758 0759 if(!ok) 0760 { 0761 delete sock; 0762 0763 self->debug_strings += QStringLiteral("failed to setup multicast on the socket (errorCode=%1)").arg(errorCode); 0764 self->processDebug(); 0765 return 0; 0766 } 0767 0768 if(maddr->isIpv6) 0769 { 0770 qjdns_sock_setTTL6(sd, 255); 0771 qjdns_sock_setIPv6Only(sd); 0772 } 0773 else 0774 qjdns_sock_setTTL4(sd, 255); 0775 } 0776 0777 int handle = self->next_handle++; 0778 self->socketForHandle.insert(handle, sock); 0779 self->handleForSocket.insert(sock, handle); 0780 return handle; 0781 } 0782 0783 static void cb_udp_unbind(jdns_session_t *, void *app, int handle) 0784 { 0785 QJDns::Private *self = (QJDns::Private *)app; 0786 0787 QUdpSocket *sock = self->socketForHandle.value(handle); 0788 if(!sock) 0789 return; 0790 0791 self->socketForHandle.remove(handle); 0792 self->handleForSocket.remove(sock); 0793 delete sock; 0794 } 0795 0796 static int cb_udp_read(jdns_session_t *, void *app, int handle, jdns_address_t *addr, int *port, unsigned char *buf, int *bufsize) 0797 { 0798 QJDns::Private *self = (QJDns::Private *)app; 0799 0800 QUdpSocket *sock = self->socketForHandle.value(handle); 0801 if(!sock) 0802 return 0; 0803 0804 // nothing to read? 0805 if(!sock->hasPendingDatagrams()) 0806 return 0; 0807 0808 QHostAddress from_addr; 0809 quint16 from_port; 0810 int ret = sock->readDatagram((char *)buf, *bufsize, &from_addr, &from_port); 0811 if(ret == -1) 0812 return 0; 0813 0814 qt2addr_set(addr, from_addr); 0815 *port = (int)from_port; 0816 *bufsize = ret; 0817 return 1; 0818 } 0819 0820 static int cb_udp_write(jdns_session_t *, void *app, int handle, const jdns_address_t *addr, int port, unsigned char *buf, int bufsize) 0821 { 0822 QJDns::Private *self = (QJDns::Private *)app; 0823 0824 QUdpSocket *sock = self->socketForHandle.value(handle); 0825 if(!sock) 0826 return 0; 0827 0828 QHostAddress host = addr2qt(addr); 0829 int ret = sock->writeDatagram((const char *)buf, bufsize, host, port); 0830 if(ret == -1) 0831 { 0832 // this can happen if the datagram to send is too big. i'm not sure what else 0833 // may cause this. if we return 0, then jdns may try to resend the packet, 0834 // which might not work if it is too large (causing the same error over and 0835 // over). we'll return success to jdns, so the result is as if the packet 0836 // was dropped. 0837 return 1; 0838 } 0839 0840 ++self->pending; 0841 return 1; 0842 } 0843 }; 0844 0845 QJDns::QJDns(QObject *parent) 0846 :QObject(parent) 0847 { 0848 d = new Private(this); 0849 } 0850 0851 QJDns::~QJDns() 0852 { 0853 delete d; 0854 } 0855 0856 bool QJDns::init(Mode mode, const QHostAddress &address) 0857 { 0858 return d->init(mode, address); 0859 } 0860 0861 void QJDns::shutdown() 0862 { 0863 d->shutting_down = true; 0864 d->pending_wait = false; 0865 d->complete_shutdown = false; 0866 jdns_shutdown(d->sess); 0867 d->process(); 0868 } 0869 0870 QStringList QJDns::debugLines() 0871 { 0872 QStringList tmp = d->debug_strings; 0873 d->debug_strings.clear(); 0874 return tmp; 0875 } 0876 0877 QJDns::SystemInfo QJDns::systemInfo() 0878 { 0879 SystemInfo out; 0880 jdns_dnsparams_t *params = jdns_system_dnsparams(); 0881 for(int n = 0; n < params->nameservers->count; ++n) 0882 { 0883 NameServer ns; 0884 ns.address = addr2qt(params->nameservers->item[n]->address); 0885 out.nameServers += ns; 0886 } 0887 for(int n = 0; n < params->domains->count; ++n) 0888 out.domains += str2qt(params->domains->item[n]); 0889 for(int n = 0; n < params->hosts->count; ++n) 0890 { 0891 DnsHost h; 0892 h.name = str2qt(params->hosts->item[n]->name); 0893 h.address = addr2qt(params->hosts->item[n]->address); 0894 out.hosts += h; 0895 } 0896 jdns_dnsparams_delete(params); 0897 return out; 0898 } 0899 0900 #define PROBE_BASE 20000 0901 #define PROBE_RANGE 100 0902 0903 QHostAddress QJDns::detectPrimaryMulticast(const QHostAddress &address) 0904 { 0905 my_srand(); 0906 0907 QUdpSocket *sock = new QUdpSocket; 0908 QUdpSocket::BindMode mode; 0909 mode |= QUdpSocket::ShareAddress; 0910 mode |= QUdpSocket::ReuseAddressHint; 0911 int port = -1; 0912 for(int n = 0; n < PROBE_RANGE; ++n) 0913 { 0914 if(sock->bind(address, PROBE_BASE + n, mode)) 0915 { 0916 port = PROBE_BASE + n; 0917 break; 0918 } 0919 } 0920 if(port == -1) 0921 { 0922 delete sock; 0923 return QHostAddress(); 0924 } 0925 0926 jdns_address_t *a; 0927 if(address.protocol() == QAbstractSocket::IPv6Protocol) 0928 a = jdns_address_multicast6_new(); 0929 else 0930 a = jdns_address_multicast4_new(); 0931 QHostAddress maddr = addr2qt(a); 0932 jdns_address_delete(a); 0933 0934 if(address.protocol() == QAbstractSocket::IPv6Protocol) 0935 { 0936 int x; 0937 if(!qjdns_sock_setMulticast6(sock->socketDescriptor(), maddr.toIPv6Address().c, &x)) 0938 { 0939 delete sock; 0940 return QHostAddress(); 0941 } 0942 qjdns_sock_setTTL6(sock->socketDescriptor(), 0); 0943 } 0944 else 0945 { 0946 int x; 0947 if(!qjdns_sock_setMulticast4(sock->socketDescriptor(), maddr.toIPv4Address(), &x)) 0948 { 0949 delete sock; 0950 return QHostAddress(); 0951 } 0952 qjdns_sock_setTTL4(sock->socketDescriptor(), 0); 0953 } 0954 0955 QHostAddress result; 0956 QByteArray out(128, 0); 0957 for(int n = 0; n < out.size(); ++n) 0958 out[n] = rand(); 0959 if(sock->writeDatagram(out.data(), out.size(), maddr, port) == -1) 0960 { 0961 delete sock; 0962 return QHostAddress(); 0963 } 0964 while(1) 0965 { 0966 if(!sock->waitForReadyRead(1000)) 0967 { 0968 fprintf(stderr, "QJDns::detectPrimaryMulticast: timeout while checking %s\n", qPrintable(address.toString())); 0969 delete sock; 0970 return QHostAddress(); 0971 } 0972 QByteArray in(128, 0); 0973 QHostAddress from_addr; 0974 quint16 from_port; 0975 int ret = sock->readDatagram(in.data(), in.size(), &from_addr, &from_port); 0976 if(ret == -1) 0977 { 0978 delete sock; 0979 return QHostAddress(); 0980 } 0981 0982 if(from_port != port) 0983 continue; 0984 in.resize(ret); 0985 if(in != out) 0986 continue; 0987 0988 result = from_addr; 0989 break; 0990 } 0991 delete sock; 0992 0993 return result; 0994 } 0995 0996 void QJDns::setNameServers(const QList<NameServer> &list) 0997 { 0998 d->setNameServers(list); 0999 } 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"