You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
321 lines
6.1 KiB
321 lines
6.1 KiB
/*
|
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
*/
|
|
|
|
#include "srvresolver.h"
|
|
|
|
#include <tqcstring.h>
|
|
#include <tqtimer.h>
|
|
#include <tqdns.h>
|
|
#include "safedelete.h"
|
|
|
|
#ifndef NO_NDNS
|
|
#include "ndns.h"
|
|
#endif
|
|
|
|
// CS_NAMESPACE_BEGIN
|
|
|
|
static void sortSRVList(TQValueList<TQDns::Server> &list)
|
|
{
|
|
TQValueList<TQDns::Server> tmp = list;
|
|
list.clear();
|
|
|
|
while(!tmp.isEmpty()) {
|
|
TQValueList<TQDns::Server>::Iterator p = tmp.end();
|
|
for(TQValueList<TQDns::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() {}
|
|
|
|
TQDns *qdns;
|
|
#ifndef NO_NDNS
|
|
NDns ndns;
|
|
#endif
|
|
|
|
bool failed;
|
|
TQHostAddress resultAddress;
|
|
TQ_UINT16 resultPort;
|
|
|
|
bool srvonly;
|
|
TQString srv;
|
|
TQValueList<TQDns::Server> servers;
|
|
bool aaaa;
|
|
|
|
TQTimer t;
|
|
SafeDelete sd;
|
|
};
|
|
|
|
SrvResolver::SrvResolver(TQObject *parent)
|
|
:TQObject(parent)
|
|
{
|
|
d = new Private;
|
|
d->qdns = 0;
|
|
|
|
#ifndef NO_NDNS
|
|
connect(&d->ndns, TQT_SIGNAL(resultsReady()), TQT_SLOT(ndns_done()));
|
|
#endif
|
|
connect(&d->t, TQT_SIGNAL(timeout()), TQT_SLOT(t_timeout()));
|
|
stop();
|
|
}
|
|
|
|
SrvResolver::~SrvResolver()
|
|
{
|
|
stop();
|
|
delete d;
|
|
}
|
|
|
|
void SrvResolver::resolve(const TQString &server, const TQString &type, const TQString &proto)
|
|
{
|
|
stop();
|
|
|
|
d->failed = false;
|
|
d->srvonly = false;
|
|
d->srv = TQString("_") + type + "._" + proto + '.' + server;
|
|
d->t.start(15000, true);
|
|
d->qdns = new TQDns;
|
|
connect(d->qdns, TQT_SIGNAL(resultsReady()), TQT_SLOT(qdns_done()));
|
|
d->qdns->setRecordType(TQDns::Srv);
|
|
d->qdns->setLabel(d->srv);
|
|
}
|
|
|
|
void SrvResolver::resolveSrvOnly(const TQString &server, const TQString &type, const TQString &proto)
|
|
{
|
|
stop();
|
|
|
|
d->failed = false;
|
|
d->srvonly = true;
|
|
d->srv = TQString("_") + type + "._" + proto + '.' + server;
|
|
d->t.start(15000, true);
|
|
d->qdns = new TQDns;
|
|
connect(d->qdns, TQT_SIGNAL(resultsReady()), TQT_SLOT(qdns_done()));
|
|
d->qdns->setRecordType(TQDns::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 = TQHostAddress();
|
|
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;
|
|
}
|
|
|
|
TQValueList<TQDns::Server> SrvResolver::servers() const
|
|
{
|
|
return d->servers;
|
|
}
|
|
|
|
bool SrvResolver::failed() const
|
|
{
|
|
return d->failed;
|
|
}
|
|
|
|
TQHostAddress SrvResolver::resultAddress() const
|
|
{
|
|
return d->resultAddress;
|
|
}
|
|
|
|
TQ_UINT16 SrvResolver::resultPort() const
|
|
{
|
|
return d->resultPort;
|
|
}
|
|
|
|
void SrvResolver::tryNext()
|
|
{
|
|
#ifndef NO_NDNS
|
|
d->ndns.resolve(d->servers.first().name);
|
|
#else
|
|
d->qdns = new TQDns;
|
|
connect(d->qdns, TQT_SIGNAL(resultsReady()), TQT_SLOT(ndns_done()));
|
|
if(d->aaaa)
|
|
d->qdns->setRecordType(TQDns::Aaaa); // IPv6
|
|
else
|
|
d->qdns->setRecordType(TQDns::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
|
|
TQValueList<TQDns::Server> list;
|
|
if(d->qdns->recordType() == TQDns::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 = TQHostAddress(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
|
|
TQValueList<TQHostAddress> list;
|
|
if(d->qdns->recordType() == TQDns::A || d->qdns->recordType() == TQDns::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"
|