summaryrefslogtreecommitdiffstats
path: root/kopete/protocols/jabber/libiris/cutestuff/network/srvresolver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kopete/protocols/jabber/libiris/cutestuff/network/srvresolver.cpp')
-rw-r--r--kopete/protocols/jabber/libiris/cutestuff/network/srvresolver.cpp320
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"