diff options
Diffstat (limited to 'kopete/protocols/jabber/libiris/cutestuff/network/srvresolver.cpp')
-rw-r--r-- | kopete/protocols/jabber/libiris/cutestuff/network/srvresolver.cpp | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/kopete/protocols/jabber/libiris/cutestuff/network/srvresolver.cpp b/kopete/protocols/jabber/libiris/cutestuff/network/srvresolver.cpp new file mode 100644 index 00000000..0c454c49 --- /dev/null +++ b/kopete/protocols/jabber/libiris/cutestuff/network/srvresolver.cpp @@ -0,0 +1,320 @@ +/* + * 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<qcstring.h> +#include<qtimer.h> +#include<qdns.h> +#include"safedelete.h" + +#ifndef NO_NDNS +#include"ndns.h" +#endif + +// CS_NAMESPACE_BEGIN + +static void sortSRVList(QValueList<QDns::Server> &list) +{ + QValueList<QDns::Server> tmp = list; + list.clear(); + + while(!tmp.isEmpty()) { + QValueList<QDns::Server>::Iterator p = tmp.end(); + for(QValueList<QDns::Server>::Iterator it = tmp.begin(); it != tmp.end(); ++it) { + if(p == tmp.end()) + p = it; + else { + int a = (*it).priority; + int b = (*p).priority; + int j = (*it).weight; + int k = (*p).weight; + if(a < b || (a == b && j < k)) + p = it; + } + } + list.append(*p); + tmp.remove(p); + } +} + +class SrvResolver::Private +{ +public: + Private() {} + + QDns *qdns; +#ifndef NO_NDNS + NDns ndns; +#endif + + bool failed; + QHostAddress resultAddress; + Q_UINT16 resultPort; + + bool srvonly; + QString srv; + QValueList<QDns::Server> 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) +{ + stop(); + + d->failed = false; + d->srvonly = false; + d->srv = QString("_") + type + "._" + proto + '.' + server; + d->t.start(15000, true); + d->qdns = new QDns; + connect(d->qdns, SIGNAL(resultsReady()), SLOT(qdns_done())); + d->qdns->setRecordType(QDns::Srv); + d->qdns->setLabel(d->srv); +} + +void SrvResolver::resolveSrvOnly(const QString &server, const QString &type, const QString &proto) +{ + stop(); + + d->failed = false; + d->srvonly = true; + d->srv = QString("_") + type + "._" + proto + '.' + server; + d->t.start(15000, true); + d->qdns = new QDns; + connect(d->qdns, SIGNAL(resultsReady()), SLOT(qdns_done())); + d->qdns->setRecordType(QDns::Srv); + d->qdns->setLabel(d->srv); +} + +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; +} + +QValueList<QDns::Server> 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 + d->ndns.resolve(d->servers.first().name); +#else + d->qdns = new QDns; + connect(d->qdns, SIGNAL(resultsReady()), SLOT(ndns_done())); + if(d->aaaa) + d->qdns->setRecordType(QDns::Aaaa); // IPv6 + else + d->qdns->setRecordType(QDns::A); // IPv4 + d->qdns->setLabel(d->servers.first().name); +#endif +} + +void SrvResolver::qdns_done() +{ + 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 + QValueList<QDns::Server> list; + if(d->qdns->recordType() == QDns::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); + + uint r = d->ndns.result(); + int port = d->servers.first().port; + d->servers.remove(d->servers.begin()); + + if(r) { + d->resultAddress = QHostAddress(d->ndns.result()); + 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 + QValueList<QHostAddress> list; + if(d->qdns->recordType() == QDns::A || d->qdns->recordType() == QDns::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 + +#include "srvresolver.moc" |