/* * srvresolver.cpp - class to simplify SRV lookups * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "srvresolver.h" #include #include #include //Added by qt3to4: #include #include #include "safedelete.h" #include "psilogger.h" #ifndef NO_NDNS #include "ndns.h" #endif // CS_NAMESPACE_BEGIN bool serverLessThan(const Q3Dns::Server &s1, const Q3Dns::Server &s2) { int a = s1.priority; int b = s2.priority; int j = s1.weight; int k = s2.weight; return a < b || (a == b && j < k); } static void sortSRVList(QList &list) { qStableSort(list.begin(), list.end(), serverLessThan); } class SrvResolver::Private { public: Private() {} Q3Dns *qdns; #ifndef NO_NDNS NDns ndns; #endif bool failed; QHostAddress resultAddress; Q_UINT16 resultPort; bool srvonly; QString srv; QList servers; bool aaaa; QTimer t; SafeDelete sd; }; SrvResolver::SrvResolver(QObject *parent) :QObject(parent) { d = new Private; d->qdns = 0; #ifndef NO_NDNS connect(&d->ndns, SIGNAL(resultsReady()), SLOT(ndns_done())); #endif connect(&d->t, SIGNAL(timeout()), SLOT(t_timeout())); stop(); } SrvResolver::~SrvResolver() { stop(); delete d; } void SrvResolver::resolve(const QString &server, const QString &type, const QString &proto, bool srvOnly) { PsiLogger::instance()->log(QString("SrvResolver::resolve(%1, %2, %3, %4)").arg(server).arg(type).arg(proto).arg(srvOnly)); stop(); d->failed = false; d->srvonly = srvOnly; d->srv = QString("_") + type + "._" + proto + '.' + server; d->t.start(15000, true); d->qdns = new Q3Dns; connect(d->qdns, SIGNAL(resultsReady()), SLOT(qdns_done())); d->qdns->setRecordType(Q3Dns::Srv); d->qdns->setLabel(d->srv); } void SrvResolver::resolve(const QString &server, const QString &type, const QString &proto) { resolve(server, type, proto, false); } void SrvResolver::resolveSrvOnly(const QString &server, const QString &type, const QString &proto) { resolve(server, type, proto, true); } void SrvResolver::next() { if(d->servers.isEmpty()) return; tryNext(); } void SrvResolver::stop() { if(d->t.isActive()) d->t.stop(); if(d->qdns) { d->qdns->disconnect(this); d->sd.deleteLater(d->qdns); d->qdns = 0; } #ifndef NO_NDNS if(d->ndns.isBusy()) d->ndns.stop(); #endif d->resultAddress = QHostAddress(); d->resultPort = 0; d->servers.clear(); d->srv = ""; d->failed = true; } bool SrvResolver::isBusy() const { #ifndef NO_NDNS if(d->qdns || d->ndns.isBusy()) #else if(d->qdns) #endif return true; else return false; } QList SrvResolver::servers() const { return d->servers; } bool SrvResolver::failed() const { return d->failed; } QHostAddress SrvResolver::resultAddress() const { return d->resultAddress; } Q_UINT16 SrvResolver::resultPort() const { return d->resultPort; } void SrvResolver::tryNext() { #ifndef NO_NDNS PsiLogger::instance()->log(QString("SrvResolver(%1)::tryNext() d->ndns.resolve(%2)").arg(d->srv).arg(d->servers.first().name)); d->ndns.resolve(d->servers.first().name); #else d->qdns = new Q3Dns; connect(d->qdns, SIGNAL(resultsReady()), SLOT(ndns_done())); if(d->aaaa) d->qdns->setRecordType(Q3Dns::Aaaa); // IPv6 else d->qdns->setRecordType(Q3Dns::A); // IPv4 d->qdns->setLabel(d->servers.first().name); #endif } void SrvResolver::qdns_done() { PsiLogger::instance()->log(QString("SrvResolver(%1)::qdns_done() d->qdns = %2; d->qdns->isWorking() = %3; d->qdns->servers().count() = %4").arg(d->srv).arg((long)d->qdns).arg(d->qdns ? d->qdns->isWorking() : 0).arg(d->qdns ? d->qdns->servers().count() : 0)); if(!d->qdns) return; // apparently we sometimes get this signal even though the results aren't ready if(d->qdns->isWorking()) return; d->t.stop(); SafeDeleteLock s(&d->sd); // grab the server list and destroy the qdns object QList list; if(d->qdns->recordType() == Q3Dns::Srv) list = d->qdns->servers(); d->qdns->disconnect(this); d->sd.deleteLater(d->qdns); d->qdns = 0; if(list.isEmpty()) { stop(); resultsReady(); return; } sortSRVList(list); d->servers = list; if(d->srvonly) resultsReady(); else { // kick it off d->aaaa = true; tryNext(); } } void SrvResolver::ndns_done() { #ifndef NO_NDNS SafeDeleteLock s(&d->sd); QHostAddress r = d->ndns.result(); int port = d->servers.first().port; d->servers.remove(d->servers.begin()); PsiLogger::instance()->log(QString("SrvResolver(%1)::ndns_done() r.isNull = %2, r = %3, port = %4").arg(d->srv).arg(r.isNull()).arg(r.toString()).arg(port)); if(!r.isNull()) { d->resultAddress = r; d->resultPort = port; resultsReady(); } else { // failed? bail if last one if(d->servers.isEmpty()) { stop(); resultsReady(); return; } // otherwise try the next tryNext(); } #else if(!d->qdns) return; // apparently we sometimes get this signal even though the results aren't ready if(d->qdns->isWorking()) return; SafeDeleteLock s(&d->sd); // grab the address list and destroy the qdns object QList list; if(d->qdns->recordType() == Q3Dns::A || d->qdns->recordType() == Q3Dns::Aaaa) list = d->qdns->addresses(); d->qdns->disconnect(this); d->sd.deleteLater(d->qdns); d->qdns = 0; if(!list.isEmpty()) { int port = d->servers.first().port; d->servers.remove(d->servers.begin()); d->aaaa = true; d->resultAddress = list.first(); d->resultPort = port; resultsReady(); } else { if(!d->aaaa) d->servers.remove(d->servers.begin()); d->aaaa = !d->aaaa; // failed? bail if last one if(d->servers.isEmpty()) { stop(); resultsReady(); return; } // otherwise try the next tryNext(); } #endif } void SrvResolver::t_timeout() { SafeDeleteLock s(&d->sd); stop(); resultsReady(); } // CS_NAMESPACE_END