summaryrefslogtreecommitdiffstats
path: root/tqtinterface/qt4/src/network/tqdns.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tqtinterface/qt4/src/network/tqdns.cpp')
-rw-r--r--tqtinterface/qt4/src/network/tqdns.cpp5294
1 files changed, 0 insertions, 5294 deletions
diff --git a/tqtinterface/qt4/src/network/tqdns.cpp b/tqtinterface/qt4/src/network/tqdns.cpp
deleted file mode 100644
index 4ba3a85..0000000
--- a/tqtinterface/qt4/src/network/tqdns.cpp
+++ /dev/null
@@ -1,5294 +0,0 @@
-#include "tqtglobaldefines.h"
-
-#ifdef USE_QT4
-
-/****************************************************************************
-**
-** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the Qt3Support module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial Usage
-** Licensees holding valid Qt Commercial licenses may use this file in
-** accordance with the Qt Commercial License Agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Nokia.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-// #include "Qt/qplatformdefs.h"
-
-#include "Qt/qbytearray.h"
-#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) || defined(Q_OS_CYGWIN)
-# include "qt_windows.h"
-#else
-# include <sys/types.h>
-# include <netinet/in.h>
-# include <arpa/nameser.h>
-# include <resolv.h>
-extern "C" int res_init();
-#endif
-
-// POSIX Large File Support redefines open -> open64
-#if defined(open)
-# undef open
-#endif
-
-// POSIX Large File Support redefines truncate -> truncate64
-#if defined(truncate)
-# undef truncate
-#endif
-
-// Solaris redefines connect -> __xnet_connect with _XOPEN_SOURCE_EXTENDED.
-#if defined(connect)
-# undef connect
-#endif
-
-// UnixWare 7 redefines socket -> _socket
-#if defined(socket)
-# undef socket
-#endif
-
-#include "tqdns.h"
-
-#ifndef QT_NO_DNS
-
-#include "Qt/qdatetime.h"
-#include "tqdict.h"
-#include "tqptrlist.h"
-#include "Qt/qstring.h"
-#include "Qt/qtimer.h"
-#include "Qt/qapplication.h"
-#include "tqptrvector.h"
-#include "tqstrlist.h"
-#include "tqptrdict.h"
-#include "Qt/qfile.h"
-#include "Qt/qtextstream.h"
-#include "tqsocketdevice.h"
-#include "tqcleanuphandler.h"
-#include <limits.h>
-
-// #include "Qt/qhostaddress.h"
-// #include "Qt/qsocketnotifier.h"
-
-QT_BEGIN_NAMESPACE
-
-//#define TQDNS_DEBUG
-
-static Q_UINT16 theId; // ### seeded started by now()
-
-
-static QDateTime * originOfTime = 0;
-
-static TQCleanupHandler<QDateTime> q3dns_cleanup_time;
-
-static Q_UINT32 now()
-{
- if ( originOfTime )
- return originOfTime->secsTo( QDateTime::currentDateTime() );
-
- originOfTime = new QDateTime( QDateTime::currentDateTime() );
- theId = originOfTime->time().msec() * 60 + originOfTime->time().second();
- q3dns_cleanup_time.add( &originOfTime );
- return 0;
-}
-
-
-static TQPtrList<TQHostAddress> * theNs = 0;
-static TQStrList * theDomains = 0;
-static bool ipv6support = false;
-
-class TQDnsPrivate {
-public:
- TQDnsPrivate() : queryTimer( 0 ), noNames(false)
- {
-#if defined(Q_DNS_SYNCHRONOUS)
-#if defined(Q_OS_UNIX)
- noEventLoop = qApp==0 || qApp->loopLevel()==0;
-#else
- noEventLoop = false;
-#endif
-#endif
- }
- ~TQDnsPrivate()
- {
- delete queryTimer;
- }
-private:
- TQTimer * queryTimer;
- bool noNames;
-#if defined(Q_DNS_SYNCHRONOUS)
- bool noEventLoop;
-#endif
-
- friend class TQDns;
- friend class TQDnsAnswer;
-};
-
-
-class TQDnsRR;
-class TQDnsDomain;
-
-
-
-// TQDnsRR is the class used to store a single RR. TQDnsRR can store
-// all of the supported RR types. a TQDnsRR is always cached.
-
-// TQDnsRR is mostly constructed from the outside. a but hacky, but
-// permissible since the entire class is internal.
-
-class TQDnsRR {
-public:
- TQDnsRR( const TQString & label );
- ~TQDnsRR();
-
-public:
- TQDnsDomain * domain;
- TQDns::RecordType t;
- bool nxdomain;
- bool current;
- Q_UINT32 expireTime;
- Q_UINT32 deleteTime;
- // somewhat space-wasting per-type data
- // a / aaaa
- TQHostAddress address;
- // cname / mx / srv / ptr
- TQString target;
- // mx / srv
- Q_UINT16 priority;
- // srv
- Q_UINT16 weight;
- Q_UINT16 port;
- // txt
- TQString text; // could be overloaded into target...
-private:
-
-};
-
-
-class TQDnsDomain {
-public:
- TQDnsDomain( const TQString & label );
- ~TQDnsDomain();
-
- static void add( const TQString & label, TQDnsRR * );
- static TQPtrList<TQDnsRR> * cached( const TQDns * );
-
- void take( TQDnsRR * );
-
- void sweep( Q_UINT32 thisSweep );
-
- bool isEmpty() const { return rrs == 0 || rrs->isEmpty(); }
-
- TQString name() const { return l; }
-
-public:
- TQString l;
- TQPtrList<TQDnsRR> * rrs;
-};
-
-
-class TQDnsQuery: public TQTimer { // this inheritance is a very evil hack
-public:
- TQDnsQuery():
- id( 0 ), t( TQDns::None ), step(0), started(0),
- dns( new TQPtrDict<void>(17) ) {}
- ~TQDnsQuery() { delete dns; }
- Q_UINT16 id;
- TQDns::RecordType t;
- TQString l;
-
- uint step;
- Q_UINT32 started;
-
- TQPtrDict<void> * dns;
-};
-
-
-
-class TQDnsAnswer {
-public:
- TQDnsAnswer( TQDnsQuery * );
- TQDnsAnswer( const TQByteArray &, TQDnsQuery * );
- ~TQDnsAnswer();
-
- void parse();
- void notify();
-
- bool ok;
-
-private:
- TQDnsQuery * query;
-
- Q_UINT8 * answer;
- int size;
- int pp;
-
- TQPtrList<TQDnsRR> * rrs;
-
- // convenience
- int next;
- int ttl;
- TQString label;
- TQDnsRR * rr;
-
- TQString readString(bool multipleLabels = true);
- void parseA();
- void parseAaaa();
- void parseMx();
- void parseSrv();
- void parseCname();
- void parsePtr();
- void parseTxt();
- void parseNs();
-};
-
-
-TQDnsRR::TQDnsRR( const TQString & label )
- : domain( 0 ), t( TQDns::None ),
- nxdomain( false ), current( false ),
- expireTime( 0 ), deleteTime( 0 ),
- priority( 0 ), weight( 0 ), port( 0 )
-{
- TQDnsDomain::add( label, this );
-}
-
-
-// not supposed to be deleted except by TQDnsDomain
-TQDnsRR::~TQDnsRR()
-{
- // nothing is necessary
-}
-
-
-// this one just sticks in a NXDomain
-TQDnsAnswer::TQDnsAnswer( TQDnsQuery * query_ )
-{
- ok = true;
-
- answer = 0;
- size = 0;
- query = query_;
- pp = 0;
- rrs = new TQPtrList<TQDnsRR>;
- rrs->setAutoDelete( false );
- next = size;
- ttl = 0;
- label.clear();
- rr = 0;
-
- TQDnsRR * newrr = new TQDnsRR( query->l );
- newrr->t = query->t;
- newrr->deleteTime = query->started + 10;
- newrr->expireTime = query->started + 10;
- newrr->nxdomain = true;
- newrr->current = true;
- rrs->append( newrr );
-}
-
-
-TQDnsAnswer::TQDnsAnswer( const TQByteArray& answer_,
- TQDnsQuery * query_ )
-{
- ok = true;
-
- answer = (Q_UINT8 *)(answer_.data());
- size = (int)answer_.size();
- query = query_;
- pp = 0;
- rrs = new TQPtrList<TQDnsRR>;
- rrs->setAutoDelete( false );
- next = size;
- ttl = 0;
- label.clear();
- rr = 0;
-}
-
-
-TQDnsAnswer::~TQDnsAnswer()
-{
- if ( !ok && rrs ) {
- TQPtrListIterator<TQDnsRR> it( *rrs );
- TQDnsRR * tmprr;
- while( (tmprr=it.current()) != 0 ) {
- ++it;
- tmprr->t = TQDns::None; // will be deleted soonish
- }
- }
- delete rrs;
-}
-
-
-TQString TQDnsAnswer::readString(bool multipleLabels)
-{
- int p = pp;
- TQString r;
- Q_UINT8 b;
- for( ;; ) {
- b = 128;
- // Read one character
- if ( p >= 0 && p < size )
- b = answer[p];
-
- switch( b >> 6 ) {
- case 0:
- // b is less than 64
- p++;
-
- // Detect end of data
- if ( b == 0 ) {
- if ( p > pp )
- pp = p;
- return r.isNull() ? TQT_TQSTRING(TQLatin1String( "." )) : r;
- }
-
- // Read a label of size 'b' characters
- if ( !r.isNull() )
- r += QLatin1Char('.');
- while( b-- > 0 )
- r += QLatin1Char( answer[p++] );
-
- // Return immediately if we were only supposed to read one
- // label.
- if (!multipleLabels)
- return r;
-
- break;
- default:
- // Ignore unrecognized control character, or p was out of
- // range.
- goto not_ok;
- case 3:
- // Use the next character to determine the relative offset
- // to jump to before continuing the packet parsing.
- int q = ( (answer[p] & 0x3f) << 8 ) + answer[p+1];
-
- if ( q >= pp || q >= p )
- goto not_ok;
- if ( p >= pp )
- pp = p + 2;
- p = q;
- }
- }
-not_ok:
- ok = false;
- return TQString();
-}
-
-
-
-void TQDnsAnswer::parseA()
-{
- if ( next != pp + 4 ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw %d bytes long IN A for %s",
- next - pp, label.ascii() );
-#endif
- return;
- }
-
- rr = new TQDnsRR( label );
- rr->t = TQDns::A;
- rr->address = TQHostAddress( ( answer[pp+0] << 24 ) +
- ( answer[pp+1] << 16 ) +
- ( answer[pp+2] << 8 ) +
- ( answer[pp+3] ) );
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw %s IN A %s (ttl %d)", label.ascii(),
- rr->address.toString().ascii(), ttl );
-#endif
-}
-
-
-void TQDnsAnswer::parseAaaa()
-{
- if ( next != pp + 16 ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw %d bytes long IN Aaaa for %s",
- next - pp, label.ascii() );
-#endif
- return;
- }
-
- rr = new TQDnsRR( label );
- rr->t = TQDns::Aaaa;
- rr->address = TQHostAddress( answer+pp );
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw %s IN Aaaa %s (ttl %d)", label.ascii(),
- rr->address.toString().ascii(), ttl );
-#endif
-}
-
-
-
-void TQDnsAnswer::parseMx()
-{
- if ( next < pp + 2 ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw %d bytes long IN MX for %s",
- next - pp, label.ascii() );
-#endif
- return;
- }
-
- rr = new TQDnsRR( label );
- rr->priority = (answer[pp] << 8) + answer[pp+1];
- pp += 2;
- rr->target = readString().lower();
- if ( !ok ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw bad string in MX for %s", label.ascii() );
-#endif
- return;
- }
- rr->t = TQDns::Mx;
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw %s IN MX %d %s (ttl %d)", label.ascii(),
- rr->priority, rr->target.ascii(), ttl );
-#endif
-}
-
-
-void TQDnsAnswer::parseSrv()
-{
- if ( next < pp + 6 ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw %d bytes long IN SRV for %s",
- next - pp, label.ascii() );
-#endif
- return;
- }
-
- rr = new TQDnsRR( label );
- rr->priority = (answer[pp] << 8) + answer[pp+1];
- rr->weight = (answer[pp+2] << 8) + answer[pp+3];
- rr->port = (answer[pp+4] << 8) + answer[pp+5];
- pp += 6;
- rr->target = readString().lower();
- if ( !ok ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw bad string in SRV for %s", label.ascii() );
-#endif
- return;
- }
- rr->t = TQDns::Srv;
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw %s IN SRV %d %d %d %s (ttl %d)", label.ascii(),
- rr->priority, rr->weight, rr->port, rr->target.ascii(), ttl );
-#endif
-}
-
-
-void TQDnsAnswer::parseCname()
-{
- TQString target = readString().lower();
- if ( !ok ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw bad cname for for %s", label.ascii() );
-#endif
- return;
- }
-
- rr = new TQDnsRR( label );
- rr->t = TQDns::Cname;
- rr->target = target;
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw %s IN CNAME %s (ttl %d)", label.ascii(),
- rr->target.ascii(), ttl );
-#endif
-}
-
-
-void TQDnsAnswer::parseNs()
-{
- TQString target = readString().lower();
- if ( !ok ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw bad cname for for %s", label.ascii() );
-#endif
- return;
- }
-
- // parse, but ignore
-
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw %s IN NS %s (ttl %d)", label.ascii(),
- target.ascii(), ttl );
-#endif
-}
-
-
-void TQDnsAnswer::parsePtr()
-{
- TQString target = readString().lower();
- if ( !ok ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw bad PTR for for %s", label.ascii() );
-#endif
- return;
- }
-
- rr = new TQDnsRR( label );
- rr->t = TQDns::Ptr;
- rr->target = target;
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw %s IN PTR %s (ttl %d)", label.ascii(),
- rr->target.ascii(), ttl );
-#endif
-}
-
-
-void TQDnsAnswer::parseTxt()
-{
- TQString text = readString(false);
- if ( !ok ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw bad TXT for for %s", label.ascii() );
-#endif
- return;
- }
-
- rr = new TQDnsRR( label );
- rr->t = TQDns::Txt;
- rr->text = text;
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw %s IN TXT \"%s\" (ttl %d)", label.ascii(),
- rr->text.ascii(), ttl );
-#endif
-}
-
-
-void TQDnsAnswer::parse()
-{
- // okay, do the work...
- if ( (answer[2] & 0x78) != 0 ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "DNS Manager: answer to wrong query type (%d)", answer[1] );
-#endif
- ok = false;
- return;
- }
-
- // AA
- bool aa = (answer[2] & 4) != 0;
-
- // TC
- if ( (answer[2] & 2) != 0 ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "DNS Manager: truncated answer; pressing on" );
-#endif
- }
-
- // RD
- bool rd = (answer[2] & 1) != 0;
-
- // we don't test RA
- // we don't test the MBZ fields
-
- if ( (answer[3] & 0x0f) == 3 ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "DNS Manager: saw NXDomain for %s", query->l.ascii() );
-#endif
- // NXDomain. cache that for one minute.
- rr = new TQDnsRR( query->l );
- rr->t = query->t;
- rr->deleteTime = query->started + 60;
- rr->expireTime = query->started + 60;
- rr->nxdomain = true;
- rr->current = true;
- rrs->append( rr );
- return;
- }
-
- if ( (answer[3] & 0x0f) != 0 ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "DNS Manager: error code %d", answer[3] & 0x0f );
-#endif
- ok = false;
- return;
- }
-
- int qdcount = ( answer[4] << 8 ) + answer[5];
- int ancount = ( answer[6] << 8 ) + answer[7];
- int nscount = ( answer[8] << 8 ) + answer[9];
- int adcount = (answer[10] << 8 ) +answer[11];
-
- pp = 12;
-
- // read query
- while( qdcount > 0 && pp < size ) {
- // should I compare the string against query->l?
- (void)readString();
- if ( !ok )
- return;
- pp += 4;
- qdcount--;
- }
-
- // answers and stuff
- int rrno = 0;
- // if we parse the answer completely, but there are no answers,
- // ignore the entire thing.
- int answers = 0;
- while( ( rrno < ancount ||
- ( ok && answers >0 && rrno < ancount + nscount + adcount ) ) &&
- pp < size ) {
- label = readString().lower();
- if ( !ok )
- return;
- int rdlength = 0;
- if ( pp + 10 <= size )
- rdlength = ( answer[pp+8] << 8 ) + answer[pp+9];
- if ( pp + 10 + rdlength > size ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "DNS Manager: ran out of stuff to parse (%d+%d>%d (%d)",
- pp, rdlength, size, rrno < ancount );
-#endif
- // if we're still in the AN section, we should go back and
- // at least down the TTLs. probably best to invalidate
- // the results.
- // the rrs list is good for this
- ok = ( rrno < ancount );
- return;
- }
- uint type, clas;
- type = ( answer[pp+0] << 8 ) + answer[pp+1];
- clas = ( answer[pp+2] << 8 ) + answer[pp+3];
- ttl = ( answer[pp+4] << 24 ) + ( answer[pp+5] << 16 ) +
- ( answer[pp+6] << 8 ) + answer[pp+7];
- pp = pp + 10;
- if ( clas != 1 ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "DNS Manager: class %d (not internet) for %s",
- clas, label.isNull() ? "." : label.ascii() );
-#endif
- } else {
- next = pp + rdlength;
- rr = 0;
- switch( type ) {
- case 1:
- parseA();
- break;
- case 28:
- parseAaaa();
- break;
- case 15:
- parseMx();
- break;
- case 33:
- parseSrv();
- break;
- case 5:
- parseCname();
- break;
- case 12:
- parsePtr();
- break;
- case 16:
- parseTxt();
- break;
- case 2:
- parseNs();
- break;
- default:
- // something we don't know
-#if defined(TQDNS_DEBUG)
- qDebug( "DNS Manager: type %d for %s", type,
- label.isNull() ? "." : label.ascii() );
-#endif
- break;
- }
- if ( rr ) {
- rr->deleteTime = 0;
- if ( ttl > 0 )
- rr->expireTime = query->started + ttl;
- else
- rr->expireTime = query->started + 20;
- if ( rrno < ancount ) {
- answers++;
- rr->deleteTime = rr->expireTime;
- }
- rr->current = true;
- rrs->append( rr );
- }
- }
- if ( !ok )
- return;
- pp = next;
- next = size;
- rrno++;
- }
- if ( answers == 0 ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "DNS Manager: answer contained no answers" );
-#endif
- ok = ( aa && rd );
- }
-
- // now go through the list and mark all the As that are referenced
- // by something we care about. we want to cache such As.
- rrs->first();
- TQDict<void> used( 17 );
- used.setAutoDelete( false );
- while( (rr=rrs->current()) != 0 ) {
- rrs->next();
- if ( rr->target.length() && rr->deleteTime > 0 && rr->current )
- used.insert( rr->target, (void*)42 );
- if ( ( rr->t == TQDns::A || rr->t == TQDns::Aaaa ) &&
- used.find( rr->domain->name() ) != 0 )
- rr->deleteTime = rr->expireTime;
- }
-
- // next, for each RR, delete any older RRs that are equal to it
- rrs->first();
- while( (rr=rrs->current()) != 0 ) {
- rrs->next();
- if ( rr && rr->domain && rr->domain->rrs ) {
- TQPtrList<TQDnsRR> * drrs = rr->domain->rrs;
- drrs->first();
- TQDnsRR * older;
- while( (older=drrs->current()) != 0 ) {
- if ( older != rr &&
- older->t == rr->t &&
- older->nxdomain == rr->nxdomain &&
- older->address == rr->address &&
- older->target == rr->target &&
- older->priority == rr->priority &&
- older->weight == rr->weight &&
- older->port == rr->port &&
- older->text == rr->text ) {
- // well, it's equal, but it's not the same. so we kill it,
- // but use its expiry time.
-#if defined(TQDNS_DEBUG)
- qDebug( "killing off old %d for %s, expire was %d",
- older->t, older->domain->name().latin1(),
- rr->expireTime );
-#endif
- older->t = TQDns::None;
- rr->expireTime = QMAX( older->expireTime, rr->expireTime );
- rr->deleteTime = QMAX( older->deleteTime, rr->deleteTime );
- older->deleteTime = 0;
-#if defined(TQDNS_DEBUG)
- qDebug( " adjusted expire is %d", rr->expireTime );
-#endif
- }
- drrs->next();
- }
- }
- }
-
-#if defined(TQDNS_DEBUG)
- //qDebug( "DNS Manager: ()" );
-#endif
-}
-
-
-class TQDnsUgleHack: public TQDns {
-public:
- void ugle( bool emitAnyway=false );
-};
-
-
-void TQDnsAnswer::notify()
-{
- if ( !rrs || !ok || !query || !query->dns )
- return;
-
- TQPtrDict<void> notified;
- notified.setAutoDelete( false );
-
- TQPtrDictIterator<void> it( *query->dns );
- TQDns * dns;
- it.toFirst();
- while( (dns=(TQDns*)(it.current())) != 0 ) {
- ++it;
- if ( notified.find( (void*)dns ) == 0 ) {
- notified.insert( (void*)dns, (void*)42 );
- if ( rrs->count() == 0 ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "DNS Manager: found no answers!" );
-#endif
- dns->d->noNames = true;
- ((TQDnsUgleHack*)dns)->ugle( true );
- } else {
- TQStringList n = dns->qualifiedNames();
- if ( query && n.contains(query->l) )
- ((TQDnsUgleHack*)dns)->ugle();
-#if defined(TQDNS_DEBUG)
- else
- qDebug( "DNS Manager: DNS thing %s not notified for %s",
- dns->label().ascii(), query->l.ascii() );
-#endif
- }
- }
- }
-}
-
-
-//
-//
-// TQDnsManager
-//
-//
-
-
-class TQDnsManager: public TQDnsSocket {
-private:
-public: // just to silence the moronic g++.
- TQDnsManager();
- ~TQDnsManager();
-public:
- static TQDnsManager * manager();
-
- TQDnsDomain * domain( const TQString & );
-
- void transmitQuery( TQDnsQuery * );
- void transmitQuery( int );
-
- // reimplementation of the slots
- void cleanCache();
- void retransmit();
- void answer();
-
-public:
- TQPtrVector<TQDnsQuery> queries;
- TQDict<TQDnsDomain> cache;
- TQSocketDevice * ipv4Socket;
-#if !defined (QT_NO_IPV6)
- TQSocketDevice * ipv6Socket;
-#endif
-};
-
-
-
-static TQDnsManager * globalManager = 0;
-
-static void cleanupDns()
-{
- delete globalManager;
- globalManager = 0;
-}
-
-TQDnsManager * TQDnsManager::manager()
-{
- if ( !globalManager ) {
- qAddPostRoutine(cleanupDns);
- new TQDnsManager();
- }
- return globalManager;
-}
-
-
-void TQDnsUgleHack::ugle( bool emitAnyway)
-{
- if ( emitAnyway || !isWorking() ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "DNS Manager: status change for %s (type %d)",
- label().ascii(), recordType() );
-#endif
- emit resultsReady();
- }
-}
-
-
-TQDnsManager::TQDnsManager()
- : TQDnsSocket( qApp, "Internal DNS manager" ),
- queries( TQPtrVector<TQDnsQuery>( 0 ) ),
- cache( TQDict<TQDnsDomain>( 83, false ) ),
- ipv4Socket( new TQSocketDevice( TQSocketDevice::Datagram, TQSocketDevice::IPv4, 0 ) )
-#if !defined (QT_NO_IPV6)
- , ipv6Socket( new TQSocketDevice( TQSocketDevice::Datagram, TQSocketDevice::IPv6, 0 ) )
-#endif
-{
- cache.setAutoDelete( true );
- globalManager = this;
-
- TQTimer * sweepTimer = new TQTimer( this );
- sweepTimer->start( 1000 * 60 * 3 );
- connect( sweepTimer, TQT_SIGNAL(timeout()),
- this, TQT_SLOT(cleanCache()) );
-
- TQSocketNotifier * rn4 = new TQSocketNotifier( ipv4Socket->socket(),
- TQSocketNotifier::Read,
- TQT_TQOBJECT(this), "dns IPv4 socket watcher" );
- ipv4Socket->setAddressReusable( false );
- ipv4Socket->setBlocking( false );
- connect( rn4, TQT_SIGNAL(activated(int)), TQT_SLOT(answer()) );
-
-#if !defined (QT_NO_IPV6)
- // Don't connect the IPv6 socket notifier if the host does not
- // support IPv6.
- if ( ipv6Socket->socket() != -1 ) {
- TQSocketNotifier * rn6 = new TQSocketNotifier( ipv6Socket->socket(),
- TQSocketNotifier::Read,
- TQT_TQOBJECT(this), "dns IPv6 socket watcher" );
-
- ipv6support = true;
- ipv6Socket->setAddressReusable( false );
- ipv6Socket->setBlocking( false );
- connect( rn6, TQT_SIGNAL(activated(int)), TQT_SLOT(answer()) );
- }
-#endif
-
- if ( !theNs )
- TQDns::doResInit();
-
- // O(n*n) stuff here. but for 3 and 6, O(n*n) with a low k should
- // be perfect. the point is to eliminate any duplicates that
- // might be hidden in the lists.
- TQPtrList<TQHostAddress> * ns = new TQPtrList<TQHostAddress>;
-
- theNs->first();
- TQHostAddress * h;
- while( (h=theNs->current()) != 0 ) {
- ns->first();
- while( ns->current() != 0 && !(*ns->current() == *h) )
- ns->next();
- if ( !ns->current() ) {
- ns->append( new TQHostAddress(*h) );
-#if defined(TQDNS_DEBUG)
- qDebug( "using name server %s", h->toString().latin1() );
- } else {
- qDebug( "skipping address %s", h->toString().latin1() );
-#endif
- }
- theNs->next();
- }
-
- delete theNs;
- theNs = ns;
- theNs->setAutoDelete( true );
-
- TQStrList * domains = new TQStrList( true );
-
- theDomains->first();
- const char * s;
- while( (s=theDomains->current()) != 0 ) {
- domains->first();
- while( domains->current() != 0 && qstrcmp( domains->current(), s ) )
- domains->next();
- if ( !domains->current() ) {
- domains->append( s );
-#if defined(TQDNS_DEBUG)
- qDebug( "searching domain %s", s );
- } else {
- qDebug( "skipping domain %s", s );
-#endif
- }
- theDomains->next();
- }
-
- delete theDomains;
- theDomains = domains;
- theDomains->setAutoDelete( true );
-}
-
-
-TQDnsManager::~TQDnsManager()
-{
- if ( globalManager )
- globalManager = 0;
- queries.setAutoDelete( true );
- cache.setAutoDelete( true );
- delete ipv4Socket;
-#if !defined (QT_NO_IPV6)
- delete ipv6Socket;
-#endif
-}
-
-static Q_UINT32 lastSweep = 0;
-
-void TQDnsManager::cleanCache()
-{
- bool again = false;
- TQDictIterator<TQDnsDomain> it( cache );
- TQDnsDomain * d;
- Q_UINT32 thisSweep = now();
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDnsManager::cleanCache(: Called, time is %u, last was %u",
- thisSweep, lastSweep );
-#endif
-
- while( (d=it.current()) != 0 ) {
- ++it;
- d->sweep( thisSweep ); // after this, d may be empty
- if ( !again )
- again = !d->isEmpty();
- }
- if ( !again )
- delete this;
- lastSweep = thisSweep;
-}
-
-
-void TQDnsManager::retransmit()
-{
- const TQT_BASE_OBJECT_NAME * o = sender();
- if ( o == 0 || globalManager == 0 || this != globalManager )
- return;
- uint q = 0;
- while( q < queries.size() && queries[q] != o )
- q++;
- if ( q < queries.size() )
- transmitQuery( q );
-}
-
-
-void TQDnsManager::answer()
-{
- TQByteArray a( 16383 ); // large enough for anything, one suspects
-
- int r;
-#if defined (QT_NO_IPV6)
- r = ipv4Socket->readBlock(a.data(), a.size());
-#else
- if (((TQSocketNotifier *)sender())->socket() == ipv4Socket->socket())
- r = ipv4Socket->readBlock(a.data(), a.size());
- else
- r = ipv6Socket->readBlock(a.data(), a.size());
-#endif
-#if defined(TQDNS_DEBUG)
-#if !defined (QT_NO_IPV6)
- qDebug("DNS Manager: answer arrived: %d bytes from %s:%d", r,
- useIpv4Socket ? ipv4Socket->peerAddress().toString().ascii()
- : ipv6Socket->peerAddress().toString().ascii(),
- useIpv4Socket ? ipv4Socket->peerPort() : ipv6Socket->peerPort() );
-#else
- qDebug("DNS Manager: answer arrived: %d bytes from %s:%d", r,
- ipv4Socket->peerAddress().toString().ascii(), ipv4Socket->peerPort());;
-#endif
-#endif
- if ( r < 12 )
- return;
- // maybe we should check that the answer comes from port 53 on one
- // of our name servers...
- a.resize( r );
-
- Q_UINT16 aid = (((Q_UINT8)a[0]) << 8) + ((Q_UINT8)a[1]);
- uint i = 0;
- while( i < queries.size() &&
- !( queries[i] && queries[i]->id == aid ) )
- i++;
- if ( i == queries.size() ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "DNS Manager: bad id (0x%04x) %d", aid, i );
-#endif
- return;
- }
-
- // at this point queries[i] is whatever we asked for.
-
- if ( ( (Q_UINT8)(a[2]) & 0x80 ) == 0 ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "DNS Manager: received a query" );
-#endif
- return;
- }
-
- TQDnsQuery * q = queries[i];
- TQDnsAnswer answer( a, q );
- answer.parse();
- if ( answer.ok ) {
- queries.take( i );
- answer.notify();
- delete q;
- }
-}
-
-
-void TQDnsManager::transmitQuery( TQDnsQuery * query_ )
-{
- if ( !query_ )
- return;
-
- uint i = 0;
- while( i < queries.size() && queries[i] != 0 )
- i++;
- if ( i == queries.size() )
- queries.resize( i+1 );
- queries.insert( i, query_ );
- transmitQuery( i );
-}
-
-
-void TQDnsManager::transmitQuery( int i )
-{
- if ( i < 0 || i >= (int)queries.size() )
- return;
- TQDnsQuery * q = queries[i];
-
- if ( q && q->step > 8 ) {
- // okay, we've run out of retransmissions. we fake an NXDomain
- // with a very short life time...
- TQDnsAnswer answer( q );
- answer.notify();
- // and then get rid of the query
- queries.take( i );
-#if defined(TQDNS_DEBUG)
- qDebug( "DNS Manager: giving up on query 0x%04x", q->id );
-#endif
- delete q;
- TQTimer::singleShot( 0, TQDnsManager::manager(), TQT_SLOT(cleanCache()) );
- // and don't process anything more
- return;
- }
-
- if ((q && !q->dns) || q->dns->isEmpty())
- // no one currently wants the answer, so there's no point in
- // retransmitting the query. we keep it, though. an answer may
- // arrive for an earlier query transmission, and if it does we
- // may benefit from caching the result.
- return;
-
- TQByteArray p( 12 + q->l.length() + 2 + 4 );
- if ( p.size() > 500 )
- return; // way over the limit, so don't even try
-
- // header
- // id
- p[0] = (q->id & 0xff00) >> 8;
- p[1] = q->id & 0x00ff;
- p[2] = 1; // recursion desired, rest is 0
- p[3] = 0; // all is 0
- // one query
- p[4] = 0;
- p[5] = 1;
- // no answers, name servers or additional data
- p[6] = p[7] = p[8] = p[9] = p[10] = p[11] = 0;
-
- // the name is composed of several components. each needs to be
- // written by itself... so we write...
- // oh, and we assume that there's no funky characters in there.
- int pp = 12;
- uint lp = 0;
- while( lp < (uint) q->l.length() ) {
- int le = q->l.find( QLatin1Char('.'), lp );
- if ( le < 0 )
- le = q->l.length();
- TQString component = q->l.mid( lp, le-lp );
- p[pp++] = component.length();
- int cp;
- for( cp=0; cp < (int)component.length(); cp++ )
- p[pp++] = component[cp].latin1();
- lp = le + 1;
- }
- // final null
- p[pp++] = 0;
- // query type
- p[pp++] = 0;
- switch( q->t ) {
- case TQDns::A:
- p[pp++] = 1;
- break;
- case TQDns::Aaaa:
- p[pp++] = 28;
- break;
- case TQDns::Mx:
- p[pp++] = 15;
- break;
- case TQDns::Srv:
- p[pp++] = 33;
- break;
- case TQDns::Cname:
- p[pp++] = 5;
- break;
- case TQDns::Ptr:
- p[pp++] = 12;
- break;
- case TQDns::Txt:
- p[pp++] = 16;
- break;
- default:
- p[pp++] = (char)255; // any
- break;
- }
- // query class (always internet)
- p[pp++] = 0;
- p[pp++] = 1;
-
- // if we have no name servers, we should regenerate ns in case
- // name servers have recently been defined (like on windows,
- // plugging/unplugging the network cable will change the name
- // server entries)
- if ( !theNs || theNs->isEmpty() )
- TQDns::doResInit();
-
- if ( !theNs || theNs->isEmpty() ) {
- // we don't find any name servers. We fake an NXDomain
- // with a very short life time...
- TQDnsAnswer answer( q );
- answer.notify();
- // and then get rid of the query
- queries.take( i );
-#if defined(TQDNS_DEBUG)
- qDebug( "DNS Manager: no DNS server found on query 0x%04x", q->id );
-#endif
- delete q;
- TQTimer::singleShot( 1000*10, TQDnsManager::manager(), TQT_SLOT(cleanCache()) );
- // and don't process anything more
- return;
- }
-
- TQHostAddress receiver = *theNs->at( q->step % theNs->count() );
- if (receiver.isIPv4Address())
- ipv4Socket->writeBlock( p.data(), pp, receiver, 53 );
-#if !defined (QT_NO_IPV6)
- else
- ipv6Socket->writeBlock( p.data(), pp, receiver, 53 );
-#endif
-#if defined(TQDNS_DEBUG)
- qDebug( "issuing query 0x%04x (%d) about %s type %d to %s",
- q->id, q->step, q->l.ascii(), q->t,
- ns->at( q->step % ns->count() )->toString().ascii() );
-#endif
- if ( theNs->count() > 1 && q->step == 0 && queries.count() == 1 ) {
- // if it's the first time, and we don't have any other
- // outstanding queries, send nonrecursive queries to the other
- // name servers too.
- p[2] = 0;
- TQHostAddress * server;
- while( (server=theNs->next()) != 0 ) {
- if (server->isIPv4Address())
- ipv4Socket->writeBlock( p.data(), pp, *server, 53 );
-#if !defined (QT_NO_IPV6)
- else
- ipv6Socket->writeBlock( p.data(), pp, *server, 53 );
-#endif
-#if defined(TQDNS_DEBUG)
- qDebug( "copying query to %s", server->toString().ascii() );
-#endif
- }
- }
- q->step++;
- // some testing indicates that normal dns queries take up to 0.6
- // seconds. the graph becomes steep around that point, and the
- // number of errors rises... so it seems good to retry at that
- // point.
- q->start( q->step < theNs->count() ? 800 : 1500, true );
-}
-
-
-TQDnsDomain * TQDnsManager::domain( const TQString & label )
-{
- TQDnsDomain * d = cache.find( label );
- if ( !d ) {
- d = new TQDnsDomain( label );
- cache.insert( label, d );
- }
- return d;
-}
-
-
-//
-//
-// the TQDnsDomain class looks after and coordinates queries for TQDnsRRs for
-// each domain, and the cached TQDnsRRs. (A domain, in DNS terminology, is
-// a node in the DNS. "no", "trolltech.com" and "lupinella.troll.no" are
-// all domains.)
-//
-//
-
-
-TQDnsDomain::TQDnsDomain( const TQString & label )
-{
- l = label;
- rrs = 0;
-}
-
-
-TQDnsDomain::~TQDnsDomain()
-{
- delete rrs;
- rrs = 0;
-}
-
-
-void TQDnsDomain::add( const TQString & label, TQDnsRR * rr )
-{
- TQDnsDomain * d = TQDnsManager::manager()->domain( label );
- if ( !d->rrs ) {
- d->rrs = new TQPtrList<TQDnsRR>;
- d->rrs->setAutoDelete( true );
- }
- d->rrs->append( rr );
- rr->domain = d;
-}
-
-
-TQPtrList<TQDnsRR> * TQDnsDomain::cached( const TQDns * r )
-{
- TQPtrList<TQDnsRR> * l = new TQPtrList<TQDnsRR>;
-
- // test at first if you have to start a query at all
- if ( r->recordType() == TQDns::A ) {
- if ( r->label().lower() == TQLatin1String("localhost") ) {
- // undocumented hack. ipv4-specific. also, may be a memory
- // leak? not sure. would be better to do this in doResInit(),
- // anyway.
- TQDnsRR *rrTmp = new TQDnsRR( r->label() );
- rrTmp->t = TQDns::A;
- rrTmp->address = TQHostAddress( 0x7f000001 );
- rrTmp->current = true;
- l->append( rrTmp );
- return l;
- }
- TQHostAddress tmp;
- if ( tmp.setAddress( r->label() ) ) {
- TQDnsRR *rrTmp = new TQDnsRR( r->label() );
- if ( tmp.isIPv4Address() ) {
- rrTmp->t = TQDns::A;
- rrTmp->address = tmp;
- rrTmp->current = true;
- l->append( rrTmp );
- } else {
- rrTmp->nxdomain = true;
- }
- return l;
- }
- }
- if ( r->recordType() == TQDns::Aaaa ) {
- TQHostAddress tmp;
- if ( tmp.setAddress(r->label()) ) {
- TQDnsRR *rrTmp = new TQDnsRR( r->label() );
- if ( tmp.isIPv6Address() ) {
- rrTmp->t = TQDns::Aaaa;
- rrTmp->address = tmp;
- rrTmp->current = true;
- l->append( rrTmp );
- } else {
- rrTmp->nxdomain = true;
- }
- return l;
- }
- }
-
- // if you reach this point, you have to do the query
- TQDnsManager * m = TQDnsManager::manager();
- TQStringList n = r->qualifiedNames();
- bool nxdomain;
- int cnamecount = 0;
- int it = 0;
- while( it < n.count() ) {
- TQString s = *(n.at(it++));
- nxdomain = false;
-#if defined(TQDNS_DEBUG)
- qDebug( "looking at cache for %s (%s %d)",
- s.ascii(), r->label().ascii(), r->recordType() );
-#endif
- TQDnsDomain * d = m->domain( s );
-#if defined(TQDNS_DEBUG)
- qDebug( " - found %d RRs", d && d->rrs ? d->rrs->count() : 0 );
-#endif
- if ( d->rrs )
- d->rrs->first();
- TQDnsRR * rr;
- bool answer = false;
- while( d->rrs && (rr=d->rrs->current()) != 0 ) {
- if ( rr->t == TQDns::Cname && r->recordType() != TQDns::Cname &&
- !rr->nxdomain && cnamecount < 16 ) {
- // cname. if the code is ugly, that may just
- // possibly be because the concept is.
-#if defined(TQDNS_DEBUG)
- qDebug( "found cname from %s to %s",
- r->label().ascii(), rr->target.ascii() );
-#endif
- s = rr->target;
- d = m->domain( s );
- if ( d->rrs )
- d->rrs->first();
- it = n.count();
- // we've elegantly moved over to whatever the cname
- // pointed to. well, not elegantly. let's remember
- // that we've done something, anyway, so we can't be
- // fooled into an infinte loop as well.
- cnamecount++;
- } else {
- if ( rr->t == r->recordType() ) {
- if ( rr->nxdomain )
- nxdomain = true;
- else
- answer = true;
- l->append( rr );
- if ( rr->deleteTime <= lastSweep ) {
- // we're returning something that'll be
- // deleted soon. we assume that if the client
- // wanted it twice, it'll want it again, so we
- // ask the name server again right now.
- TQDnsQuery * query = new TQDnsQuery;
- query->started = now();
- query->id = ++theId;
- query->t = rr->t;
- query->l = rr->domain->name();
- // note that here, we don't bother about
- // notification. but we do bother about
- // timeouts: we make sure to use high timeouts
- // and few tramsissions.
- query->step = theNs->count();
- TQT_BASE_OBJECT_NAME::connect( query, TQT_SIGNAL(timeout()),
- TQDnsManager::manager(),
- TQT_SLOT(retransmit()) );
- TQDnsManager::manager()->transmitQuery( query );
- }
- }
- d->rrs->next();
- }
- }
- // if we found a positive result, return quickly
- if ( answer && l->count() ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "found %d records for %s",
- l->count(), r->label().ascii() );
- l->first();
- while( l->current() ) {
- qDebug( " type %d target %s address %s",
- l->current()->t,
- l->current()->target.latin1(),
- l->current()->address.toString().latin1() );
- l->next();
- }
-#endif
- l->first();
- return l;
- }
-
-#if defined(TQDNS_DEBUG)
- if ( nxdomain )
- qDebug( "found NXDomain %s", s.ascii() );
-#endif
-
- if ( !nxdomain ) {
- // if we didn't, and not a negative result either, perhaps
- // we need to transmit a query.
- uint q = 0;
- while ( q < m->queries.size() &&
- ( m->queries[q] == 0 ||
- m->queries[q]->t != r->recordType() ||
- m->queries[q]->l != s ) )
- q++;
- // we haven't done it before, so maybe we should. but
- // wait - if it's an unqualified name, only ask when all
- // the other alternatives are exhausted.
- if ( q == m->queries.size() && ( s.find( QLatin1Char('.') ) >= 0 ||
- int(l->count()) >= n.count()-1 ) ) {
- TQDnsQuery * query = new TQDnsQuery;
- query->started = now();
- query->id = ++theId;
- query->t = r->recordType();
- query->l = s;
- query->dns->replace( (void*)r, (void*)r );
- TQT_BASE_OBJECT_NAME::connect( query, TQT_SIGNAL(timeout()),
- TQDnsManager::manager(), TQT_SLOT(retransmit()) );
- TQDnsManager::manager()->transmitQuery( query );
- } else if ( q < m->queries.size() ) {
- // if we've found an earlier query for the same
- // domain/type, subscribe to its answer
- m->queries[q]->dns->replace( (void*)r, (void*)r );
- }
- }
- }
- l->first();
- return l;
-}
-
-
-void TQDnsDomain::sweep( Q_UINT32 thisSweep )
-{
- if ( !rrs )
- return;
-
- TQDnsRR * rr;
- rrs->first();
- while( (rr=rrs->current()) != 0 ) {
- if ( !rr->deleteTime )
- rr->deleteTime = thisSweep; // will hit next time around
-
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns::sweep: %s type %d expires %u %u - %s / %s",
- rr->domain->name().latin1(), rr->t,
- rr->expireTime, rr->deleteTime,
- rr->target.latin1(), rr->address.toString().latin1());
-#endif
- if ( rr->current == false ||
- rr->t == TQDns::None ||
- rr->deleteTime <= thisSweep ||
- rr->expireTime <= thisSweep )
- rrs->remove();
- else
- rrs->next();
- }
-
- if ( rrs->isEmpty() ) {
- delete rrs;
- rrs = 0;
- }
-}
-
-
-
-
-// the itsy-bitsy little socket class I don't really need except for
-// so I can subclass and reimplement the slots.
-
-
-TQDnsSocket::TQDnsSocket( TQT_BASE_OBJECT_NAME * parent, const char * name )
- : TQObject( parent, name )
-{
- // nothing
-}
-
-
-TQDnsSocket::~TQDnsSocket()
-{
- // nothing
-}
-
-
-void TQDnsSocket::cleanCache()
-{
- // nothing
-}
-
-
-void TQDnsSocket::retransmit()
-{
- // nothing
-}
-
-
-void TQDnsSocket::answer()
-{
- // nothing
-}
-
-
-/*!
- \class TQDns
- \brief The TQDns class provides asynchronous DNS lookups.
-
- \compat
-
- Both Windows and Unix provide synchronous DNS lookups; Windows
- provides some asynchronous support too. At the time of writing
- neither operating system provides asynchronous support for
- anything other than hostname-to-address mapping.
-
- TQDns rectifies this shortcoming, by providing asynchronous caching
- lookups for the record types that we expect modern GUI
- applications to need in the near future.
-
- The class is \e not straightforward to use (although it is much
- simpler than the native APIs); TQSocket provides much easier to use
- TCP connection facilities. The aim of TQDns is to provide a correct
- and small API to the DNS and nothing more. (We use "correctness"
- to mean that the DNS information is correctly cached, and
- correctly timed out.)
-
- The API comprises a constructor, functions to set the DNS node
- (the domain in DNS terminology) and record type (setLabel() and
- setRecordType()), the corresponding get functions, an isWorking()
- function to determine whether TQDns is working or reading, a
- resultsReady() signal and query functions for the result.
-
- There is one query function for each RecordType, namely
- addresses(), mailServers(), servers(), hostNames() and texts().
- There are also two generic query functions: canonicalName()
- returns the name you'll presumably end up using (the exact meaning
- of this depends on the record type) and qualifiedNames() returns a
- list of the fully qualified names label() maps to.
-
- \sa TQSocket
-*/
-
-/*!
- Constructs a DNS query object with invalid settings for both the
- label and the search type.
-*/
-
-TQDns::TQDns()
-{
- d = new TQDnsPrivate;
- t = None;
-}
-
-
-
-
-/*!
- Constructs a DNS query object that will return record type \a rr
- information about \a label.
-
- The DNS lookup is started the next time the application enters the
- event loop. When the result is found the signal resultsReady() is
- emitted.
-
- \a rr defaults to \c A, IPv4 addresses.
-*/
-
-TQDns::TQDns( const TQString & label, RecordType rr )
-{
- d = new TQDnsPrivate;
- t = rr;
- setLabel( label );
- setStartQueryTimer(); // start query the next time we enter event loop
-}
-
-
-
-/*!
- Constructs a DNS query object that will return record type \a rr
- information about host address \a address. The label is set to the
- IN-ADDR.ARPA domain name. This is useful in combination with the
- \c Ptr record type (e.g. if you want to look up a hostname for a
- given address).
-
- The DNS lookup is started the next time the application enters the
- event loop. When the result is found the signal resultsReady() is
- emitted.
-
- \a rr defaults to \c Ptr, that maps addresses to hostnames.
-*/
-
-TQDns::TQDns( const TQHostAddress & address, RecordType rr )
-{
- d = new TQDnsPrivate;
- t = rr;
- setLabel( address );
- setStartQueryTimer(); // start query the next time we enter event loop
-}
-
-
-
-
-/*!
- Destroys the DNS query object and frees its allocated resources.
-*/
-
-TQDns::~TQDns()
-{
- if ( globalManager ) {
- uint q = 0;
- TQDnsManager * m = globalManager;
- while( q < m->queries.size() ) {
- TQDnsQuery * query=m->queries[q];
- if ( query && query->dns )
- (void)query->dns->take( (void*) this );
- q++;
- }
-
- }
-
- delete d;
- d = 0;
-}
-
-
-
-
-/*!
- Sets this DNS query object to query for information about \a
- label.
-
- This does not change the recordType(), but its isWorking() status
- will probably change as a result.
-
- The DNS lookup is started the next time the application enters the
- event loop. When the result is found the signal resultsReady() is
- emitted.
-*/
-
-void TQDns::setLabel( const TQString & label )
-{
- l = label;
- d->noNames = false;
-
- // construct a list of qualified names
- n.clear();
- if ( l.length() > 1 && l[(int)l.length()-1] == QLatin1Char('.') ) {
- n.append( TQT_TQSTRING(l.left( l.length()-1 )).lower() );
- } else {
- int i = l.length();
- int dots = 0;
- const int maxDots = 2;
- while( i && dots < maxDots ) {
- if ( l[--i] == QLatin1Char('.') )
- dots++;
- }
- if ( dots < maxDots ) {
- (void)TQDnsManager::manager(); // create a TQDnsManager, if it is not already there
- TQStrListIterator it( *theDomains );
- const char * dom;
- while( (dom=it.current()) != 0 ) {
- ++it;
- n.append( l.lower() + QLatin1Char('.') + TQLatin1String(dom) );
- }
- }
- n.append( l.lower() );
- }
-
-#if defined(Q_DNS_SYNCHRONOUS)
- if ( d->noEventLoop ) {
- doSynchronousLookup();
- } else {
- setStartQueryTimer(); // start query the next time we enter event loop
- }
-#else
- setStartQueryTimer(); // start query the next time we enter event loop
-#endif
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns::setLabel: %d address(es) for %s", n.count(), l.ascii() );
- int i = 0;
- for( i = 0; i < (int)n.count(); i++ )
- qDebug( "TQDns::setLabel: %d: %s", i, n[i].ascii() );
-#endif
-}
-
-
-/*!
- \overload
-
- Sets this DNS query object to query for information about the host
- address \a address. The label is set to the IN-ADDR.ARPA domain
- name. This is useful in combination with the \c Ptr record type
- (e.g. if you want to look up a hostname for a given address).
-*/
-
-void TQDns::setLabel( const TQHostAddress & address )
-{
- setLabel( toInAddrArpaDomain( address ) );
-}
-
-
-/*!
- \fn TQStringList TQDns::qualifiedNames() const
-
- Returns a list of the fully qualified names label() maps to.
-
- Note that if you want to iterate over the list, you should iterate
- over a copy, e.g.
- \snippet doc/src/snippets/code/src_qt3support_network_q3dns.cpp 0
-
-*/
-
-
-/*!
- \fn TQString TQDns::label() const
-
- Returns the domain name for which this object returns information.
-
- \sa setLabel()
-*/
-
-/*!
- \enum TQDns::RecordType
-
- This enum type defines the record types TQDns can handle. The DNS
- provides many more; these are the ones we've judged to be in
- current use, useful for GUI programs and important enough to
- support right away:
-
- \value None No information. This exists only so that TQDns can
- have a default.
-
- \value A IPv4 addresses. By far the most common type.
-
- \value Aaaa IPv6 addresses. So far mostly unused.
-
- \value Mx Mail eXchanger names. Used for mail delivery.
-
- \value Srv SeRVer names. Generic record type for finding
- servers. So far mostly unused.
-
- \value Cname Canonical names. Maps from nicknames to the true
- name (the canonical name) for a host.
-
- \value Ptr name PoinTeRs. Maps from IPv4 or IPv6 addresses to hostnames.
-
- \value Txt arbitrary TeXT for domains.
-
- We expect that some support for the
- \l{http://www.rfc-editor.org/rfc/rfc2535.txt}{RFC 2535}
- extensions will be added in future versions.
-*/
-
-/*!
- Sets this object to query for record type \a rr records.
-
- The DNS lookup is started the next time the application enters the
- event loop. When the result is found the signal resultsReady() is
- emitted.
-
- \sa RecordType
-*/
-
-void TQDns::setRecordType( RecordType rr )
-{
- t = rr;
- d->noNames = false;
- setStartQueryTimer(); // start query the next time we enter event loop
-}
-
-/*!
- \internal
-
- Private slot for starting the query.
-*/
-void TQDns::startQuery()
-{
- // isWorking() starts the query (if necessary)
- if ( !isWorking() )
- emit resultsReady();
-}
-
-/*!
- The three functions TQDns::TQDns(TQString, RecordType),
- TQDns::setLabel() and TQDns::setRecordType() may start a DNS lookup.
- This function handles setting up the single shot timer.
-*/
-void TQDns::setStartQueryTimer()
-{
-#if defined(Q_DNS_SYNCHRONOUS)
- if ( !d->queryTimer && !d->noEventLoop )
-#else
- if ( !d->queryTimer )
-#endif
- {
- // start the query the next time we enter event loop
- d->queryTimer = new TQTimer( this );
- connect( d->queryTimer, TQT_SIGNAL(timeout()),
- this, TQT_SLOT(startQuery()) );
- d->queryTimer->start( 0, true );
- }
-}
-
-/*
- Transforms the host address \a address to the IN-ADDR.ARPA domain
- name. Returns something indeterminate if you're sloppy or
- naughty. This function has an IPv4-specific name, but works for
- IPv6 too.
-*/
-TQString TQDns::toInAddrArpaDomain( const TQHostAddress &address )
-{
- TQString s;
- if ( address.isNull() ) {
- // if the address isn't valid, neither of the other two make
- // cases make sense. better to just return.
- } else if ( address.isIp4Addr() ) {
- Q_UINT32 i = address.ip4Addr();
- s.sprintf( "%d.%d.%d.%d.IN-ADDR.ARPA",
- i & 0xff, (i >> 8) & 0xff, (i>>16) & 0xff, (i>>24) & 0xff );
- } else {
- // RFC 3152. (1886 is deprecated, and clients no longer need to
- // support it, in practice).
- Q_IPV6ADDR i = address.toIPv6Address();
- s = TQLatin1String("ip6.arpa");
- uint b = 0;
- while( b < 16 ) {
- s = TQString::number( i.c[b]%16, 16 ) + QLatin1Char('.') +
- TQString::number( i.c[b]/16, 16 ) + QLatin1Char('.') + s;
- b++;
- }
- }
- return s;
-}
-
-
-/*!
- \fn TQDns::RecordType TQDns::recordType() const
-
- Returns the record type of this DNS query object.
-
- \sa setRecordType() RecordType
-*/
-
-/*!
- \fn void TQDns::resultsReady()
-
- This signal is emitted when results are available for one of the
- qualifiedNames().
-*/
-
-/*!
- Returns true if TQDns is doing a lookup for this object (i.e. if it
- does not already have the necessary information); otherwise
- returns false.
-
- TQDns emits the resultsReady() signal when the status changes to false.
-*/
-
-bool TQDns::isWorking() const
-{
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns::isWorking (%s, %d)", l.ascii(), t );
-#endif
- if ( t == None )
- return false;
-
-#if defined(Q_DNS_SYNCHRONOUS)
- if ( d->noEventLoop )
- return true;
-#endif
-
- TQPtrList<TQDnsRR> * ll = TQDnsDomain::cached( this );
- Q_LONG queries = n.count();
- while( ll->current() != 0 ) {
- if ( ll->current()->nxdomain ) {
- queries--;
- } else {
- delete ll;
- return false;
- }
- ll->next();
- }
- delete ll;
-
- if ( queries <= 0 )
- return false;
- if ( d->noNames )
- return false;
- return true;
-}
-
-
-/*!
- Returns a list of the addresses for this name if this TQDns object
- has a recordType() of TQDns::A or TQDns::Aaaa and the answer
- is available; otherwise returns an empty list.
-
- As a special case, if label() is a valid numeric IP address, this
- function returns that address.
-
- Note that if you want to iterate over the list, you should iterate
- over a copy, e.g.
- \snippet doc/src/snippets/code/src_qt3support_network_q3dns.cpp 1
-
-*/
-
-TQValueList<TQHostAddress> TQDns::addresses() const
-{
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns::addresses (%s)", l.ascii() );
-#endif
- TQValueList<TQHostAddress> result;
- if ( t != A && t != Aaaa )
- return result;
-
- TQPtrList<TQDnsRR> * cached = TQDnsDomain::cached( this );
-
- TQDnsRR * rr;
- while( (rr=cached->current()) != 0 ) {
- if ( rr->current && !rr->nxdomain )
- result.append( rr->address );
- cached->next();
- }
- delete cached;
- return result;
-}
-
-
-/*!
- \class TQDns::MailServer
- \brief The TQDns::MailServer class is described in TQDns::mailServers().
-
- \internal
-*/
-
-/*!
- Returns a list of mail servers if the record type is \c Mx. The
- class TQDns::MailServer contains the following public variables:
- \list
- \i TQString TQDns::MailServer::name
- \i Q_UINT16 TQDns::MailServer::priority
- \endlist
-
- Note that if you want to iterate over the list, you should iterate
- over a copy, e.g.
- \snippet doc/src/snippets/code/src_qt3support_network_q3dns.cpp 2
-
-*/
-TQValueList<TQDns::MailServer> TQDns::mailServers() const
-{
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns::mailServers (%s)", l.ascii() );
-#endif
- TQValueList<TQDns::MailServer> result;
- if ( t != Mx )
- return result;
-
- TQPtrList<TQDnsRR> * cached = TQDnsDomain::cached( this );
-
- TQDnsRR * rr;
- while( (rr=cached->current()) != 0 ) {
- if ( rr->current && !rr->nxdomain ) {
- MailServer ms( rr->target, rr->priority );
- result.append( ms );
- }
- cached->next();
- }
- delete cached;
- return result;
-}
-
-
-/*!
- \class TQDns::Server
- \brief The TQDns::Server class is described in TQDns::servers().
-
- \internal
-*/
-
-/*!
- Returns a list of servers if the record type is \c Srv. The class
- TQDns::Server contains the following public variables:
- \list
- \i TQString TQDns::Server::name
- \i Q_UINT16 TQDns::Server::priority
- \i Q_UINT16 TQDns::Server::weight
- \i Q_UINT16 TQDns::Server::port
- \endlist
-
- Note that if you want to iterate over the list, you should iterate
- over a copy, e.g.
- \snippet doc/src/snippets/code/src_qt3support_network_q3dns.cpp 3
-*/
-TQValueList<TQDns::Server> TQDns::servers() const
-{
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns::servers (%s)", l.ascii() );
-#endif
- TQValueList<TQDns::Server> result;
- if ( t != Srv )
- return result;
-
- TQPtrList<TQDnsRR> * cached = TQDnsDomain::cached( this );
-
- TQDnsRR * rr;
- while( (rr=cached->current()) != 0 ) {
- if ( rr->current && !rr->nxdomain ) {
- Server s( rr->target, rr->priority, rr->weight, rr->port );
- result.append( s );
- }
- cached->next();
- }
- delete cached;
- return result;
-}
-
-
-/*!
- Returns a list of host names if the record type is \c Ptr.
-
- Note that if you want to iterate over the list, you should iterate
- over a copy, e.g.
- \snippet doc/src/snippets/code/src_qt3support_network_q3dns.cpp 4
-
-*/
-TQStringList TQDns::hostNames() const
-{
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns::hostNames (%s)", l.ascii() );
-#endif
- TQStringList result;
- if ( t != Ptr )
- return result;
-
- TQPtrList<TQDnsRR> * cached = TQDnsDomain::cached( this );
-
- TQDnsRR * rr;
- while( (rr=cached->current()) != 0 ) {
- if ( rr->current && !rr->nxdomain ) {
- TQString str( rr->target );
- result.append( str );
- }
- cached->next();
- }
- delete cached;
- return result;
-}
-
-
-/*!
- Returns a list of texts if the record type is \c Txt.
-
- Note that if you want to iterate over the list, you should iterate
- over a copy, e.g.
- \snippet doc/src/snippets/code/src_qt3support_network_q3dns.cpp 5
-*/
-TQStringList TQDns::texts() const
-{
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns::texts (%s)", l.ascii() );
-#endif
- TQStringList result;
- if ( t != Txt )
- return result;
-
- TQPtrList<TQDnsRR> * cached = TQDnsDomain::cached( this );
-
- TQDnsRR * rr;
- while( (rr=cached->current()) != 0 ) {
- if ( rr->current && !rr->nxdomain ) {
- TQString str( rr->text );
- result.append( str );
- }
- cached->next();
- }
- delete cached;
- return result;
-}
-
-
-/*!
- Returns the canonical name for this DNS node. (This works
- regardless of what recordType() is set to.)
-
- If the canonical name isn't known, this function returns a null
- string.
-
- The canonical name of a DNS node is its full name, or the full
- name of the target of its CNAME. For example, if l.trolltech.com
- is a CNAME to lillian.troll.no, and the search path for TQDns is
- "trolltech.com", then the canonical name for all of "lillian",
- "l", "lillian.troll.no." and "l.trolltech.com" is
- "lillian.troll.no.".
-*/
-
-TQString TQDns::canonicalName() const
-{
- // the cname should work regardless of the recordType(), so set the record
- // type temporarily to cname when you look at the cache
- TQDns *that = (TQDns*) this; // mutable function
- RecordType oldType = t;
- that->t = Cname;
- TQPtrList<TQDnsRR> * cached = TQDnsDomain::cached( that );
- that->t = oldType;
-
- TQDnsRR * rr;
- while( (rr=cached->current()) != 0 ) {
- if ( rr->current && !rr->nxdomain && rr->domain ) {
- delete cached;
- return rr->target;
- }
- cached->next();
- }
- delete cached;
- return TQString();
-}
-
-#if defined(Q_DNS_SYNCHRONOUS)
-/*! \reimp
-*/
-void TQDns::connectNotify( const char *signal )
-{
- if ( d->noEventLoop && qstrcmp(signal,TQT_SIGNAL(resultsReady()) )==0 ) {
- doSynchronousLookup();
- }
-}
-#endif
-
-#if defined(Q_OS_WIN32) || defined(Q_OS_CYGWIN)
-
-#if defined(Q_DNS_SYNCHRONOUS)
-void TQDns::doSynchronousLookup()
-{
- // ### not implemented yet
-}
-#endif
-
-// the following typedefs are needed for GetNetworkParams() API call
-#ifndef IP_TYPES_INCLUDED
-#define MAX_HOSTNAME_LEN 128
-#define MAX_DOMAIN_NAME_LEN 128
-#define MAX_SCOPE_ID_LEN 256
-typedef struct {
- char String[4 * 4];
-} IP_ADDRESS_STRING, *PIP_ADDRESS_STRING, IP_MASK_STRING, *PIP_MASK_STRING;
-typedef struct _IP_ADDR_STRING {
- struct _IP_ADDR_STRING* Next;
- IP_ADDRESS_STRING IpAddress;
- IP_MASK_STRING IpMask;
- DWORD Context;
-} IP_ADDR_STRING, *PIP_ADDR_STRING;
-typedef struct {
- char HostName[MAX_HOSTNAME_LEN + 4] ;
- char DomainName[MAX_DOMAIN_NAME_LEN + 4];
- PIP_ADDR_STRING CurrentDnsServer;
- IP_ADDR_STRING DnsServerList;
- UINT NodeType;
- char ScopeId[MAX_SCOPE_ID_LEN + 4];
- UINT EnableRouting;
- UINT EnableProxy;
- UINT EnableDns;
-} FIXED_INFO, *PFIXED_INFO;
-#endif
-typedef DWORD (WINAPI *GNP)( PFIXED_INFO, PULONG );
-
-// ### FIXME: this code is duplicated in qfiledialog.cpp
-static TQString getWindowsRegString(HKEY key, const TQString &subKey)
-{
- TQString s;
-
- wchar_t buf[1024];
- DWORD bsz = sizeof(buf) / sizeof(wchar_t);
- int r = RegQueryValueEx(key, (wchar_t*)subKey.utf16(), 0, 0, (LPBYTE)buf, &bsz);
- if (r == ERROR_SUCCESS) {
- s = TQString::fromWCharArray(buf);
- } else if (r == ERROR_MORE_DATA) {
- char *ptr = new char[bsz+1];
- r = RegQueryValueEx(key, (wchar_t*)subKey.utf16(), 0, 0, (LPBYTE)ptr, &bsz);
- if (r == ERROR_SUCCESS)
- s = TQLatin1String(ptr);
- delete [] ptr;
- }
-
- return s;
-}
-
-static bool getDnsParamsFromRegistry( const TQString &path,
- TQString *domainName, TQString *nameServer, TQString *searchList )
-{
- HKEY k;
- int r = RegOpenKeyEx( HKEY_LOCAL_MACHINE, (wchar_t*)path.utf16(), 0, KEY_READ, &k );
-
- if ( r == ERROR_SUCCESS ) {
- *domainName = getWindowsRegString( k, TQLatin1String("DhcpDomain") );
- if ( domainName->isEmpty() )
- *domainName = getWindowsRegString( k, TQLatin1String("Domain") );
-
- *nameServer = getWindowsRegString( k, TQLatin1String("DhcpNameServer") );
- if ( nameServer->isEmpty() )
- *nameServer = getWindowsRegString( k, TQLatin1String("NameServer") );
-
- *searchList = getWindowsRegString( k, TQLatin1String("SearchList") );
- }
- RegCloseKey( k );
- return r == ERROR_SUCCESS;
-}
-
-void TQDns::doResInit()
-{
- char separator = 0;
-
- if ( theNs )
- delete theNs;
- theNs = new TQPtrList<TQHostAddress>;
- theNs->setAutoDelete( true );
- theDomains = new TQStrList( true );
- theDomains->setAutoDelete( true );
-
- TQString domainName, nameServer, searchList;
-
- bool gotNetworkParams = false;
- // try the API call GetNetworkParams() first and use registry lookup only
- // as a fallback
- HINSTANCE hinstLib = LoadLibrary( L"iphlpapi" );
- if ( hinstLib != 0 ) {
-#ifdef Q_OS_WINCE
- GNP getNetworkParams = (GNP) GetProcAddress( hinstLib, L"GetNetworkParams" );
-#else
- GNP getNetworkParams = (GNP) GetProcAddress( hinstLib, "GetNetworkParams" );
-#endif
- if ( getNetworkParams != 0 ) {
- ULONG l = 0;
- DWORD res;
- res = getNetworkParams( 0, &l );
- if ( res == ERROR_BUFFER_OVERFLOW ) {
- FIXED_INFO *finfo = (FIXED_INFO*)new char[l];
- res = getNetworkParams( finfo, &l );
- if ( res == ERROR_SUCCESS ) {
- domainName = TQLatin1String(finfo->DomainName);
- nameServer = TQLatin1String("");
- IP_ADDR_STRING *dnsServer = &finfo->DnsServerList;
- while ( dnsServer != 0 ) {
- nameServer += TQLatin1String(dnsServer->IpAddress.String);
- dnsServer = dnsServer->Next;
- if ( dnsServer != 0 )
- nameServer += QLatin1Char(' ');
- }
- searchList = TQLatin1String("");
- separator = ' ';
- gotNetworkParams = true;
- }
- delete[] finfo;
- }
- }
- FreeLibrary( hinstLib );
- }
- if ( !gotNetworkParams ) {
- if ( getDnsParamsFromRegistry(
- TQLatin1String("System\\CurrentControlSet\\Services\\Tcpip\\Parameters"),
- &domainName, &nameServer, &searchList )) {
- separator = ' ';
- } else {
- // Could not access the TCP/IP parameters
- domainName = TQLatin1String("");
- nameServer = TQLatin1String("127.0.0.1");
- searchList = TQLatin1String("");
- separator = ' ';
- }
- }
-
- nameServer = nameServer.simplifyWhiteSpace();
- int first, last;
- if ( !nameServer.isEmpty() ) {
- first = 0;
- do {
- last = nameServer.find( QLatin1Char(separator), first );
- if ( last < 0 )
- last = nameServer.length();
- TQDns tmp( nameServer.mid( first, last-first ), TQDns::A );
- TQValueList<TQHostAddress> address = tmp.addresses();
- Q_LONG i = address.count();
- while( i )
- theNs->append( new TQHostAddress(address[--i]) );
- first = last+1;
- } while( first < (int)nameServer.length() );
- }
-
- searchList += QLatin1Char(' ') + domainName;
- searchList = searchList.simplifyWhiteSpace().lower();
- first = 0;
- do {
- last = searchList.find( QLatin1Char(separator), first );
- if ( last < 0 )
- last = searchList.length();
- theDomains->append( qstrdup( searchList.mid( first, last-first ).latin1() ) );
- first = last+1;
- } while( first < (int)searchList.length() );
-}
-
-#elif defined(Q_OS_UNIX)
-
-#if defined(Q_DNS_SYNCHRONOUS)
-void TQDns::doSynchronousLookup()
-{
- if ( t!=None && !l.isEmpty() ) {
- TQValueListIterator<TQString> it = n.begin();
- TQValueListIterator<TQString> end = n.end();
- int type;
- switch( t ) {
- case TQDns::A:
- type = 1;
- break;
- case TQDns::Aaaa:
- type = 28;
- break;
- case TQDns::Mx:
- type = 15;
- break;
- case TQDns::Srv:
- type = 33;
- break;
- case TQDns::Cname:
- type = 5;
- break;
- case TQDns::Ptr:
- type = 12;
- break;
- case TQDns::Txt:
- type = 16;
- break;
- default:
- type = (char)255; // any
- break;
- }
- while( it != end ) {
- TQString s = *it;
- it++;
- TQByteArray ba( 512 );
- int len = res_search( s.latin1(), 1, type, (uchar*)ba.data(), ba.size() );
- if ( len > 0 ) {
- ba.resize( len );
-
- TQDnsQuery * query = new TQDnsQuery;
- query->started = now();
- query->id = ++theId;
- query->t = t;
- query->l = s;
- TQDnsAnswer a( ba, query );
- a.parse();
- } else if ( len == -1 ) {
- // res_search error
- }
- }
- emit resultsReady();
- }
-}
-#endif
-
-#if defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 3)))
-#define Q_MODERN_RES_API
-#endif
-
-void TQDns::doResInit()
-{
- if ( theNs )
- return;
- theNs = new TQPtrList<TQHostAddress>;
- theNs->setAutoDelete( true );
- theDomains = new TQStrList( true );
- theDomains->setAutoDelete( true );
-
- // read resolv.conf manually.
- QFile resolvConf(TQLatin1String("/etc/resolv.conf"));
- if (resolvConf.open(QIODevice::ReadOnly)) {
- QTextStream stream( &resolvConf );
- TQString line;
-
- while ( !stream.atEnd() ) {
- line = stream.readLine();
- TQStringList list = TQStringList::split( TQLatin1String(" "), line );
- if( line.startsWith( QLatin1Char('#') ) || list.size() < 2 )
- continue;
- const TQString type = list[0].lower();
-
- if ( type == TQLatin1String("nameserver") ) {
- TQHostAddress *address = new TQHostAddress();
- if ( address->setAddress( TQString(list[1]) ) ) {
- // only add ipv6 addresses from resolv.conf if
- // this host supports ipv6.
- if ( address->isIPv4Address() || ipv6support )
- theNs->append( address );
- else
- delete address;
- } else {
- delete address;
- }
- } else if ( type == TQLatin1String("search") ) {
- TQStringList srch = TQStringList::split( TQLatin1String(" "), list[1] );
- for ( TQStringList::Iterator i = srch.begin(); i != srch.end(); ++i )
- theDomains->append( (*i).lower().local8Bit() );
-
- } else if ( type == TQLatin1String("domain") ) {
- theDomains->append( list[1].lower().local8Bit() );
- }
- }
- }
-
- if (theNs->isEmpty()) {
-#if defined(Q_MODERN_RES_API)
- struct __res_state res;
- res_ninit( &res );
- int i;
- // find the name servers to use
- for( i=0; i < MAXNS && i < res.nscount; i++ )
- theNs->append( new TQHostAddress( ntohl( res.nsaddr_list[i].sin_addr.s_addr ) ) );
-# if defined(MAXDFLSRCH)
- for( i=0; i < MAXDFLSRCH; i++ ) {
- if ( res.dnsrch[i] && *(res.dnsrch[i]) )
- theDomains->append( TQT_TQSTRING(TQString::fromLatin1( res.dnsrch[i] )).lower().local8Bit() );
- else
- break;
- }
-# endif
- if ( *res.defdname )
- theDomains->append( TQT_TQSTRING(TQString::fromLatin1( res.defdname )).lower().local8Bit() );
-#else
- res_init();
- int i;
- // find the name servers to use
- for( i=0; i < MAXNS && i < _res.nscount; i++ )
- theNs->append( new TQHostAddress( ntohl( _res.nsaddr_list[i].sin_addr.s_addr ) ) );
-# if defined(MAXDFLSRCH)
- for( i=0; i < MAXDFLSRCH; i++ ) {
- if ( _res.dnsrch[i] && *(_res.dnsrch[i]) )
- theDomains->append( TQString::fromLatin1( _res.dnsrch[i] ).lower().local8Bit() );
- else
- break;
- }
-# endif
- if ( *_res.defdname )
- theDomains->append( TQString::fromLatin1( _res.defdname ).lower().local8Bit() );
-#endif
-
- // the code above adds "0.0.0.0" as a name server at the slightest
- // hint of trouble. so remove those again.
- theNs->first();
- while( theNs->current() ) {
- if ( theNs->current()->isNull() )
- delete theNs->take();
- else
- theNs->next();
- }
- }
-
- QFile hosts( TQString::fromLatin1( "/etc/hosts" ) );
- if ( hosts.open( QIODevice::ReadOnly ) ) {
- // read the /etc/hosts file, creating long-life A and PTR RRs
- // for the things we find.
- QTextStream i( &hosts );
- TQString line;
- while( !i.atEnd() ) {
- line = TQT_TQSTRING(i.readLine()).simplifyWhiteSpace().lower();
- uint n = 0;
- while( (int) n < line.length() && line[(int)n] != QLatin1Char('#') )
- n++;
- line.truncate( n );
- n = 0;
- while( (int) n < line.length() && !line[(int)n].isSpace() )
- n++;
- TQString ip = line.left( n );
- TQHostAddress a;
- a.setAddress( ip );
- if ( ( a.isIPv4Address() || a.isIPv6Address() ) && !a.isNull() ) {
- bool first = true;
- line = line.mid( n+1 );
- n = 0;
- while( (int) n < line.length() && !line[(int)n].isSpace() )
- n++;
- TQString hostname = line.left( n );
- // ### in case of bad syntax, hostname is invalid. do we care?
- if ( n ) {
- TQDnsRR * rr = new TQDnsRR( hostname );
- if ( a.isIPv4Address() )
- rr->t = TQDns::A;
- else
- rr->t = TQDns::Aaaa;
- rr->address = a;
- rr->deleteTime = UINT_MAX;
- rr->expireTime = UINT_MAX;
- rr->current = true;
- if ( first ) {
- first = false;
- TQDnsRR * ptr = new TQDnsRR( TQDns::toInAddrArpaDomain( a ) );
- ptr->t = TQDns::Ptr;
- ptr->target = hostname;
- ptr->deleteTime = UINT_MAX;
- ptr->expireTime = UINT_MAX;
- ptr->current = true;
- }
- }
- }
- }
- }
-}
-
-#endif
-
-QT_END_NAMESPACE
-
-#endif // QT_NO_DNS
-
-
-#else // USE_QT4
-
-/****************************************************************************
-**
-** Implementation of TQDns class.
-**
-** Created : 991122
-**
-** Copyright (C) 1999-2008 Trolltech ASA. All rights reserved.
-**
-** This file is part of the network module of the TQt GUI Toolkit.
-**
-** This file may be used under the terms of the GNU General
-** Public License versions 2.0 or 3.0 as published by the Free
-** Software Foundation and appearing in the files LICENSE.GPL2
-** and LICENSE.GPL3 included in the packaging of this file.
-** Alternatively you may (at your option) use any later version
-** of the GNU General Public License if such license has been
-** publicly approved by Trolltech ASA (or its successors, if any)
-** and the KDE Free TQt Foundation.
-**
-** Please review the following information to ensure GNU General
-** Public Licensing requirements will be met:
-** http://trolltech.com/products/qt/licenses/licensing/opensource/.
-** If you are unsure which license is appropriate for your use, please
-** review the following information:
-** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
-** or contact the sales department at sales@trolltech.com.
-**
-** This file may be used under the terms of the Q Public License as
-** defined by Trolltech ASA and appearing in the file LICENSE.TQPL
-** included in the packaging of this file. Licensees holding valid TQt
-** Commercial licenses may use this file in accordance with the TQt
-** Commercial License Agreement provided with the Software.
-**
-** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
-** herein.
-**
-**********************************************************************/
-
-#include "tqplatformdefs.h"
-
-// POSIX Large File Support redefines open -> open64
-#if defined(open)
-# undef open
-#endif
-
-// POSIX Large File Support redefines truncate -> truncate64
-#if defined(truncate)
-# undef truncate
-#endif
-
-// Solaris redefines connect -> __xnet_connect with _XOPEN_SOURCE_EXTENDED.
-#if defined(connect)
-# undef connect
-#endif
-
-// UnixWare 7 redefines socket -> _socket
-#if defined(socket)
-# undef socket
-#endif
-
-#include "tqdns.h"
-
-#ifndef TQT_NO_DNS
-
-#include "tqdatetime.h"
-#include "tqdict.h"
-#include "tqptrlist.h"
-#include "tqstring.h"
-#include "tqtimer.h"
-#include "tqapplication.h"
-#include "tqptrvector.h"
-#include "tqstrlist.h"
-#include "tqptrdict.h"
-#include "tqfile.h"
-#include "tqtextstream.h"
-#include "tqsocketdevice.h"
-#include "tqcleanuphandler.h"
-#include <limits.h>
-#ifdef TQ_OS_MAC
-#include "../3rdparty/dlcompat/dlfcn.h"
-#endif
-
-//#define TQDNS_DEBUG
-
-static TQ_UINT16 id; // ### seeded started by now()
-
-
-static TQDateTime * originOfTime = 0;
-
-static TQCleanupHandler<TQDateTime> qdns_cleanup_time;
-
-static TQ_UINT32 now()
-{
- if ( originOfTime )
- return originOfTime->secsTo( TQDateTime::tqcurrentDateTime() );
-
- originOfTime = new TQDateTime( TQDateTime::tqcurrentDateTime() );
- ::id = originOfTime->time().msec() * 60 + originOfTime->time().second();
- qdns_cleanup_time.add( &originOfTime );
- return 0;
-}
-
-
-static TQPtrList<TQHostAddress> * ns = 0;
-static TQStrList * domains = 0;
-static bool ipv6support = FALSE;
-
-static int qdns_res_init()
-{
-#ifdef TQ_OS_MAC
- typedef int (*PtrRes_init)();
- static PtrRes_init ptrRes_init = 0;
- if (!ptrRes_init)
- ptrRes_init = (PtrRes_init)DL_PREFIX(dlsym)(RTLD_NEXT, "res_init");
- if (ptrRes_init)
- return (*ptrRes_init)();
- else
- return -1;
-#elif defined(TQ_OS_UNIX)
- return res_init();
-#else
- return 0; // not called at all on Windows.
-#endif
-}
-
-
-class TQDnsPrivate {
-public:
- TQDnsPrivate() : queryTimer( 0 ), noNames(FALSE)
- {
-#if defined(TQ_DNS_SYNCHRONOUS)
-#if defined(TQ_OS_UNIX)
- noEventLoop = tqApp==0 || tqApp->loopLevel()==0;
-#else
- noEventLoop = FALSE;
-#endif
-#endif
- }
- ~TQDnsPrivate()
- {
- delete queryTimer;
- }
-private:
- TQTimer * queryTimer;
- bool noNames;
-#if defined(TQ_DNS_SYNCHRONOUS)
- bool noEventLoop;
-#endif
-
- friend class TQDns;
- friend class TQDnsAnswer;
-};
-
-
-class TQDnsRR;
-class TQDnsDomain;
-
-
-
-// TQDnsRR is the class used to store a single RR. TQDnsRR can store
-// all of the supported RR types. a TQDnsRR is always cached.
-
-// TQDnsRR is mostly constructed from the outside. a but hacky, but
-// permissible since the entire class is internal.
-
-class TQDnsRR {
-public:
- TQDnsRR( const TQString & label );
- ~TQDnsRR();
-
-public:
- TQDnsDomain * domain;
- TQDns::RecordType t;
- bool nxdomain;
- bool current;
- TQ_UINT32 expireTime;
- TQ_UINT32 deleteTime;
- // somewhat space-wasting per-type data
- // a / aaaa
- TQHostAddress address;
- // cname / mx / srv / ptr
- TQString target;
- // mx / srv
- TQ_UINT16 priority;
- // srv
- TQ_UINT16 weight;
- TQ_UINT16 port;
- // txt
- TQString text; // could be overloaded into target...
-private:
-
-};
-
-
-class TQDnsDomain {
-public:
- TQDnsDomain( const TQString & label );
- ~TQDnsDomain();
-
- static void add( const TQString & label, TQDnsRR * );
- static TQPtrList<TQDnsRR> * cached( const TQDns * );
-
- void take( TQDnsRR * );
-
- void sweep( TQ_UINT32 thisSweep );
-
- bool isEmpty() const { return rrs == 0 || rrs->isEmpty(); }
-
- TQString name() const { return l; }
-
-public:
- TQString l;
- TQPtrList<TQDnsRR> * rrs;
-};
-
-
-class TQDnsQuery: public TQTimer { // this inheritance is a very evil hack
-public:
- TQDnsQuery():
- id( 0 ), t( TQDns::None ), step(0), started(0),
- dns( new TQPtrDict<void>(17) ) {}
- ~TQDnsQuery() { delete dns; }
- TQ_UINT16 id;
- TQDns::RecordType t;
- TQString l;
-
- uint step;
- TQ_UINT32 started;
-
- TQPtrDict<void> * dns;
-};
-
-
-
-class TQDnsAnswer {
-public:
- TQDnsAnswer( TQDnsQuery * );
- TQDnsAnswer( const TQByteArray &, TQDnsQuery * );
- ~TQDnsAnswer();
-
- void parse();
- void notify();
-
- bool ok;
-
-private:
- TQDnsQuery * query;
-
- TQ_UINT8 * answer;
- int size;
- int pp;
-
- TQPtrList<TQDnsRR> * rrs;
-
- // convenience
- int next;
- int ttl;
- TQString label;
- TQDnsRR * rr;
-
- TQString readString(bool multipleLabels = TRUE);
- void parseA();
- void parseAaaa();
- void parseMx();
- void parseSrv();
- void parseCname();
- void parsePtr();
- void parseTxt();
- void parseNs();
-};
-
-
-TQDnsRR::TQDnsRR( const TQString & label )
- : domain( 0 ), t( TQDns::None ),
- nxdomain( FALSE ), current( FALSE ),
- expireTime( 0 ), deleteTime( 0 ),
- priority( 0 ), weight( 0 ), port( 0 )
-{
- TQDnsDomain::add( label, this );
-}
-
-
-// not supposed to be deleted except by TQDnsDomain
-TQDnsRR::~TQDnsRR()
-{
- // nothing is necessary
-}
-
-
-// this one just sticks in a NXDomain
-TQDnsAnswer::TQDnsAnswer( TQDnsQuery * query_ )
-{
- ok = TRUE;
-
- answer = 0;
- size = 0;
- query = query_;
- pp = 0;
- rrs = new TQPtrList<TQDnsRR>;
- rrs->setAutoDelete( FALSE );
- next = size;
- ttl = 0;
- label = TQString::null;
- rr = 0;
-
- TQDnsRR * newrr = new TQDnsRR( query->l );
- newrr->t = query->t;
- newrr->deleteTime = query->started + 10;
- newrr->expireTime = query->started + 10;
- newrr->nxdomain = TRUE;
- newrr->current = TRUE;
- rrs->append( newrr );
-}
-
-
-TQDnsAnswer::TQDnsAnswer( const TQByteArray& answer_,
- TQDnsQuery * query_ )
-{
- ok = TRUE;
-
- answer = (TQ_UINT8 *)(answer_.data());
- size = (int)answer_.size();
- query = query_;
- pp = 0;
- rrs = new TQPtrList<TQDnsRR>;
- rrs->setAutoDelete( FALSE );
- next = size;
- ttl = 0;
- label = TQString::null;
- rr = 0;
-}
-
-
-TQDnsAnswer::~TQDnsAnswer()
-{
- if ( !ok && rrs ) {
- TQPtrListIterator<TQDnsRR> it( *rrs );
- TQDnsRR * tmprr;
- while( (tmprr=it.current()) != 0 ) {
- ++it;
- tmprr->t = TQDns::None; // will be deleted soonish
- }
- }
- delete rrs;
-}
-
-
-TQString TQDnsAnswer::readString(bool multipleLabels)
-{
- int p = pp;
- TQString r = TQString::null;
- TQ_UINT8 b;
- for( ;; ) {
- b = 128;
- // Read one character
- if ( p >= 0 && p < size )
- b = answer[p];
-
- switch( b >> 6 ) {
- case 0:
- // b is less than 64
- p++;
-
- // Detect end of data
- if ( b == 0 ) {
- if ( p > pp )
- pp = p;
- return r.isNull() ? TQString( "." ) : r;
- }
-
- // Read a label of size 'b' characters
- if ( !r.isNull() )
- r += '.';
- while( b-- > 0 ) {
- r += TQChar( answer[p] );
- p++;
- }
-
- // Return immediately if we were only supposed to read one
- // label.
- if (!multipleLabels)
- return r;
-
- break;
- default:
- // Ignore unrecognized control character, or p was out of
- // range.
- goto not_ok;
- case 3:
- // Use the next character to determine the relative offset
- // to jump to before continuing the packet parsing.
- int q = ( (answer[p] & 0x3f) << 8 ) + answer[p+1];
-
- if ( q >= pp || q >= p )
- goto not_ok;
- if ( p >= pp )
- pp = p + 2;
- p = q;
- }
- }
-not_ok:
- ok = FALSE;
- return TQString::null;
-}
-
-
-
-void TQDnsAnswer::parseA()
-{
- if ( next != pp + 4 ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw %d bytes long IN A for %s",
- next - pp, label.ascii() );
-#endif
- return;
- }
-
- rr = new TQDnsRR( label );
- rr->t = TQDns::A;
- rr->address = TQHostAddress( ( answer[pp+0] << 24 ) +
- ( answer[pp+1] << 16 ) +
- ( answer[pp+2] << 8 ) +
- ( answer[pp+3] ) );
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw %s IN A %s (ttl %d)", label.ascii(),
- rr->address.toString().ascii(), ttl );
-#endif
-}
-
-
-void TQDnsAnswer::parseAaaa()
-{
- if ( next != pp + 16 ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw %d bytes long IN Aaaa for %s",
- next - pp, label.ascii() );
-#endif
- return;
- }
-
- rr = new TQDnsRR( label );
- rr->t = TQDns::Aaaa;
- rr->address = TQHostAddress( answer+pp );
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw %s IN Aaaa %s (ttl %d)", label.ascii(),
- rr->address.toString().ascii(), ttl );
-#endif
-}
-
-
-
-void TQDnsAnswer::parseMx()
-{
- if ( next < pp + 2 ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw %d bytes long IN MX for %s",
- next - pp, label.ascii() );
-#endif
- return;
- }
-
- rr = new TQDnsRR( label );
- rr->priority = (answer[pp] << 8) + answer[pp+1];
- pp += 2;
- rr->target = readString().lower();
- if ( !ok ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw bad string in MX for %s", label.ascii() );
-#endif
- return;
- }
- rr->t = TQDns::Mx;
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw %s IN MX %d %s (ttl %d)", label.ascii(),
- rr->priority, rr->target.ascii(), ttl );
-#endif
-}
-
-
-void TQDnsAnswer::parseSrv()
-{
- if ( next < pp + 6 ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw %d bytes long IN SRV for %s",
- next - pp, label.ascii() );
-#endif
- return;
- }
-
- rr = new TQDnsRR( label );
- rr->priority = (answer[pp] << 8) + answer[pp+1];
- rr->weight = (answer[pp+2] << 8) + answer[pp+3];
- rr->port = (answer[pp+4] << 8) + answer[pp+5];
- pp += 6;
- rr->target = readString().lower();
- if ( !ok ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw bad string in SRV for %s", label.ascii() );
-#endif
- return;
- }
- rr->t = TQDns::Srv;
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw %s IN SRV %d %d %d %s (ttl %d)", label.ascii(),
- rr->priority, rr->weight, rr->port, rr->target.ascii(), ttl );
-#endif
-}
-
-
-void TQDnsAnswer::parseCname()
-{
- TQString target = readString().lower();
- if ( !ok ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw bad cname for for %s", label.ascii() );
-#endif
- return;
- }
-
- rr = new TQDnsRR( label );
- rr->t = TQDns::Cname;
- rr->target = target;
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw %s IN CNAME %s (ttl %d)", label.ascii(),
- rr->target.ascii(), ttl );
-#endif
-}
-
-
-void TQDnsAnswer::parseNs()
-{
- TQString target = readString().lower();
- if ( !ok ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw bad cname for for %s", label.ascii() );
-#endif
- return;
- }
-
- // parse, but ignore
-
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw %s IN NS %s (ttl %d)", label.ascii(),
- target.ascii(), ttl );
-#endif
-}
-
-
-void TQDnsAnswer::parsePtr()
-{
- TQString target = readString().lower();
- if ( !ok ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw bad PTR for for %s", label.ascii() );
-#endif
- return;
- }
-
- rr = new TQDnsRR( label );
- rr->t = TQDns::Ptr;
- rr->target = target;
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw %s IN PTR %s (ttl %d)", label.ascii(),
- rr->target.ascii(), ttl );
-#endif
-}
-
-
-void TQDnsAnswer::parseTxt()
-{
- TQString text = readString(FALSE);
- if ( !ok ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw bad TXT for for %s", label.ascii() );
-#endif
- return;
- }
-
- rr = new TQDnsRR( label );
- rr->t = TQDns::Txt;
- rr->text = text;
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns: saw %s IN TXT \"%s\" (ttl %d)", label.ascii(),
- rr->text.ascii(), ttl );
-#endif
-}
-
-
-void TQDnsAnswer::parse()
-{
- // okay, do the work...
- if ( (answer[2] & 0x78) != 0 ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "DNS Manager: answer to wrong query type (%d)", answer[1] );
-#endif
- ok = FALSE;
- return;
- }
-
- // AA
- bool aa = (answer[2] & 4) != 0;
-
- // TC
- if ( (answer[2] & 2) != 0 ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "DNS Manager: truncated answer; pressing on" );
-#endif
- }
-
- // RD
- bool rd = (answer[2] & 1) != 0;
-
- // we don't test RA
- // we don't test the MBZ fields
-
- if ( (answer[3] & 0x0f) == 3 ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "DNS Manager: saw NXDomain for %s", query->l.ascii() );
-#endif
- // NXDomain. cache that for one minute.
- rr = new TQDnsRR( query->l );
- rr->t = query->t;
- rr->deleteTime = query->started + 60;
- rr->expireTime = query->started + 60;
- rr->nxdomain = TRUE;
- rr->current = TRUE;
- rrs->append( rr );
- return;
- }
-
- if ( (answer[3] & 0x0f) != 0 ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "DNS Manager: error code %d", answer[3] & 0x0f );
-#endif
- ok = FALSE;
- return;
- }
-
- int qdcount = ( answer[4] << 8 ) + answer[5];
- int ancount = ( answer[6] << 8 ) + answer[7];
- int nscount = ( answer[8] << 8 ) + answer[9];
- int adcount = (answer[10] << 8 ) +answer[11];
-
- pp = 12;
-
- // read query
- while( qdcount > 0 && pp < size ) {
- // should I compare the string against query->l?
- (void)readString();
- if ( !ok )
- return;
- pp += 4;
- qdcount--;
- }
-
- // answers and stuff
- int rrno = 0;
- // if we parse the answer completely, but there are no answers,
- // ignore the entire thing.
- int answers = 0;
- while( ( rrno < ancount ||
- ( ok && answers >0 && rrno < ancount + nscount + adcount ) ) &&
- pp < size ) {
- label = readString().lower();
- if ( !ok )
- return;
- int rdlength = 0;
- if ( pp + 10 <= size )
- rdlength = ( answer[pp+8] << 8 ) + answer[pp+9];
- if ( pp + 10 + rdlength > size ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "DNS Manager: ran out of stuff to parse (%d+%d>%d (%d)",
- pp, rdlength, size, rrno < ancount );
-#endif
- // if we're still in the AN section, we should go back and
- // at least down the TTLs. probably best to tqinvalidate
- // the results.
- // the rrs list is good for this
- ok = ( rrno < ancount );
- return;
- }
- uint type, clas;
- type = ( answer[pp+0] << 8 ) + answer[pp+1];
- clas = ( answer[pp+2] << 8 ) + answer[pp+3];
- ttl = ( answer[pp+4] << 24 ) + ( answer[pp+5] << 16 ) +
- ( answer[pp+6] << 8 ) + answer[pp+7];
- pp = pp + 10;
- if ( clas != 1 ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "DNS Manager: class %d (not internet) for %s",
- clas, label.isNull() ? "." : label.ascii() );
-#endif
- } else {
- next = pp + rdlength;
- rr = 0;
- switch( type ) {
- case 1:
- parseA();
- break;
- case 28:
- parseAaaa();
- break;
- case 15:
- parseMx();
- break;
- case 33:
- parseSrv();
- break;
- case 5:
- parseCname();
- break;
- case 12:
- parsePtr();
- break;
- case 16:
- parseTxt();
- break;
- case 2:
- parseNs();
- break;
- default:
- // something we don't know
-#if defined(TQDNS_DEBUG)
- qDebug( "DNS Manager: type %d for %s", type,
- label.isNull() ? "." : label.ascii() );
-#endif
- break;
- }
- if ( rr ) {
- rr->deleteTime = 0;
- if ( ttl > 0 )
- rr->expireTime = query->started + ttl;
- else
- rr->expireTime = query->started + 20;
- if ( rrno < ancount ) {
- answers++;
- rr->deleteTime = rr->expireTime;
- }
- rr->current = TRUE;
- rrs->append( rr );
- }
- }
- if ( !ok )
- return;
- pp = next;
- next = size;
- rrno++;
- }
- if ( answers == 0 ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "DNS Manager: answer contained no answers" );
-#endif
- ok = ( aa && rd );
- }
-
- // now go through the list and mark all the As that are referenced
- // by something we care about. we want to cache such As.
- rrs->first();
- TQDict<void> used( 17 );
- used.setAutoDelete( FALSE );
- while( (rr=rrs->current()) != 0 ) {
- rrs->next();
- if ( rr->target.length() && rr->deleteTime > 0 && rr->current )
- used.insert( rr->target, (void*)42 );
- if ( ( rr->t == TQDns::A || rr->t == TQDns::Aaaa ) &&
- used.find( rr->domain->name() ) != 0 )
- rr->deleteTime = rr->expireTime;
- }
-
- // next, for each RR, delete any older RRs that are equal to it
- rrs->first();
- while( (rr=rrs->current()) != 0 ) {
- rrs->next();
- if ( rr && rr->domain && rr->domain->rrs ) {
- TQPtrList<TQDnsRR> * drrs = rr->domain->rrs;
- drrs->first();
- TQDnsRR * older;
- while( (older=drrs->current()) != 0 ) {
- if ( older != rr &&
- older->t == rr->t &&
- older->nxdomain == rr->nxdomain &&
- older->address == rr->address &&
- older->target == rr->target &&
- older->priority == rr->priority &&
- older->weight == rr->weight &&
- older->port == rr->port &&
- older->text == rr->text ) {
- // well, it's equal, but it's not the same. so we kill it,
- // but use its expiry time.
-#if defined(TQDNS_DEBUG)
- qDebug( "killing off old %d for %s, expire was %d",
- older->t, older->domain->name().latin1(),
- rr->expireTime );
-#endif
- older->t = TQDns::None;
- rr->expireTime = TQMAX( older->expireTime, rr->expireTime );
- rr->deleteTime = TQMAX( older->deleteTime, rr->deleteTime );
- older->deleteTime = 0;
-#if defined(TQDNS_DEBUG)
- qDebug( " adjusted expire is %d", rr->expireTime );
-#endif
- }
- drrs->next();
- }
- }
- }
-
-#if defined(TQDNS_DEBUG)
- //qDebug( "DNS Manager: ()" );
-#endif
-}
-
-
-class TQDnsUgleHack: public TQDns {
-public:
- void ugle( bool emitAnyway=FALSE );
-};
-
-
-void TQDnsAnswer::notify()
-{
- if ( !rrs || !ok || !query || !query->dns )
- return;
-
- TQPtrDict<void> notified;
- notified.setAutoDelete( FALSE );
-
- TQPtrDictIterator<void> it( *query->dns );
- TQDns * dns;
- it.toFirst();
- while( (dns=(TQDns*)(it.current())) != 0 ) {
- ++it;
- if ( notified.find( (void*)dns ) == 0 ) {
- notified.insert( (void*)dns, (void*)42 );
- if ( rrs->count() == 0 ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "DNS Manager: found no answers!" );
-#endif
- dns->d->noNames = TRUE;
- ((TQDnsUgleHack*)dns)->ugle( TRUE );
- } else {
- TQStringList n = dns->qualifiedNames();
- if ( query && n.contains(query->l) )
- ((TQDnsUgleHack*)dns)->ugle();
-#if defined(TQDNS_DEBUG)
- else
- qDebug( "DNS Manager: DNS thing %s not notified for %s",
- dns->label().ascii(), query->l.ascii() );
-#endif
- }
- }
- }
-}
-
-
-//
-//
-// TQDnsManager
-//
-//
-
-
-class TQDnsManager: public TQDnsSocket {
-private:
-public: // just to silence the moronic g++.
- TQDnsManager();
- ~TQDnsManager();
-public:
- static TQDnsManager * manager();
-
- TQDnsDomain * domain( const TQString & );
-
- void transmitQuery( TQDnsQuery * );
- void transmitQuery( int );
-
- // reimplementation of the Q_SLOTS
- void cleanCache();
- void retransmit();
- void answer();
-
-public:
- TQPtrVector<TQDnsQuery> queries;
- TQDict<TQDnsDomain> cache;
- TQSocketDevice * ipv4Socket;
-#if !defined (TQT_NO_IPV6)
- TQSocketDevice * ipv6Socket;
-#endif
-};
-
-
-
-static TQDnsManager * globalManager = 0;
-
-static void cleanupDns()
-{
- delete globalManager;
- globalManager = 0;
-}
-
-TQDnsManager * TQDnsManager::manager()
-{
- if ( !globalManager ) {
- qAddPostRoutine(cleanupDns);
- new TQDnsManager();
- }
- return globalManager;
-}
-
-
-void TQDnsUgleHack::ugle( bool emitAnyway)
-{
- if ( emitAnyway || !isWorking() ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "DNS Manager: status change for %s (type %d)",
- label().ascii(), recordType() );
-#endif
- emit resultsReady();
- }
-}
-
-
-TQDnsManager::TQDnsManager()
- : TQDnsSocket( tqApp, "Internal DNS manager" ),
- queries( TQPtrVector<TQDnsQuery>( 0 ) ),
- cache( TQDict<TQDnsDomain>( 83, FALSE ) ),
- ipv4Socket( new TQSocketDevice( TQSocketDevice::Datagram, TQSocketDevice::IPv4, 0 ) )
-#if !defined (TQT_NO_IPV6)
- , ipv6Socket( new TQSocketDevice( TQSocketDevice::Datagram, TQSocketDevice::IPv6, 0 ) )
-#endif
-{
- cache.setAutoDelete( TRUE );
- globalManager = this;
-
- TQTimer * sweepTimer = new TQTimer( this );
- sweepTimer->start( 1000 * 60 * 3 );
- connect( sweepTimer, TQT_SIGNAL(timeout()),
- this, TQT_SLOT(cleanCache()) );
-
- TQSocketNotifier * rn4 = new TQSocketNotifier( ipv4Socket->socket(),
- TQSocketNotifier::Read,
- TQT_TQOBJECT(this), "dns IPv4 socket watcher" );
- ipv4Socket->setAddressReusable( FALSE );
- ipv4Socket->setBlocking( FALSE );
- connect( rn4, TQT_SIGNAL(activated(int)), TQT_SLOT(answer()) );
-
-#if !defined (TQT_NO_IPV6)
- // Don't connect the IPv6 socket notifier if the host does not
- // support IPv6.
- if ( ipv6Socket->socket() != -1 ) {
- TQSocketNotifier * rn6 = new TQSocketNotifier( ipv6Socket->socket(),
- TQSocketNotifier::Read,
- TQT_TQOBJECT(this), "dns IPv6 socket watcher" );
-
- ipv6support = TRUE;
- ipv6Socket->setAddressReusable( FALSE );
- ipv6Socket->setBlocking( FALSE );
- connect( rn6, TQT_SIGNAL(activated(int)), TQT_SLOT(answer()) );
- }
-#endif
-
- if ( !ns )
- TQDns::doResInit();
-
- // O(n*n) stuff here. but for 3 and 6, O(n*n) with a low k should
- // be perfect. the point is to eliminate any duplicates that
- // might be hidden in the lists.
- TQPtrList<TQHostAddress> * ns = new TQPtrList<TQHostAddress>;
-
- ::ns->first();
- TQHostAddress * h;
- while( (h=::ns->current()) != 0 ) {
- ns->first();
- while( ns->current() != 0 && !(*ns->current() == *h) )
- ns->next();
- if ( !ns->current() ) {
- ns->append( new TQHostAddress(*h) );
-#if defined(TQDNS_DEBUG)
- qDebug( "using name server %s", h->toString().latin1() );
- } else {
- qDebug( "skipping address %s", h->toString().latin1() );
-#endif
- }
- ::ns->next();
- }
-
- delete ::ns;
- ::ns = ns;
- ::ns->setAutoDelete( TRUE );
-
- TQStrList * domains = new TQStrList( TRUE );
-
- ::domains->first();
- const char * s;
- while( (s=::domains->current()) != 0 ) {
- domains->first();
- while( domains->current() != 0 && qstrcmp( domains->current(), s ) )
- domains->next();
- if ( !domains->current() ) {
- domains->append( s );
-#if defined(TQDNS_DEBUG)
- qDebug( "searching domain %s", s );
- } else {
- qDebug( "skipping domain %s", s );
-#endif
- }
- ::domains->next();
- }
-
- delete ::domains;
- ::domains = domains;
- ::domains->setAutoDelete( TRUE );
-}
-
-
-TQDnsManager::~TQDnsManager()
-{
- if ( globalManager )
- globalManager = 0;
- queries.setAutoDelete( TRUE );
- cache.setAutoDelete( TRUE );
- delete ipv4Socket;
-#if !defined (TQT_NO_IPV6)
- delete ipv6Socket;
-#endif
-}
-
-static TQ_UINT32 lastSweep = 0;
-
-void TQDnsManager::cleanCache()
-{
- bool again = FALSE;
- TQDictIterator<TQDnsDomain> it( cache );
- TQDnsDomain * d;
- TQ_UINT32 thisSweep = now();
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDnsManager::cleanCache(: Called, time is %u, last was %u",
- thisSweep, lastSweep );
-#endif
-
- while( (d=it.current()) != 0 ) {
- ++it;
- d->sweep( thisSweep ); // after this, d may be empty
- if ( !again )
- again = !d->isEmpty();
- }
- if ( !again )
- delete this;
- lastSweep = thisSweep;
-}
-
-
-void TQDnsManager::retransmit()
-{
- const TQObject * o = sender();
- if ( o == 0 || globalManager == 0 || this != globalManager )
- return;
- uint q = 0;
- while( q < queries.size() && queries[q] != o )
- q++;
- if ( q < queries.size() )
- transmitQuery( q );
-}
-
-
-void TQDnsManager::answer()
-{
- TQByteArray a( 16383 ); // large enough for anything, one suspects
-
- int r;
-#if defined (TQT_NO_IPV6)
- r = ipv4Socket->readBlock(a.data(), a.size());
-#else
- if (((TQSocketNotifier *)sender())->socket() == ipv4Socket->socket())
- r = ipv4Socket->readBlock(a.data(), a.size());
- else
- r = ipv6Socket->readBlock(a.data(), a.size());
-#endif
-#if defined(TQDNS_DEBUG)
-#if !defined (TQT_NO_IPV6)
- qDebug("DNS Manager: answer arrived: %d bytes from %s:%d", r,
- useIpv4Socket ? ipv4Socket->peerAddress().toString().ascii()
- : ipv6Socket->peerAddress().toString().ascii(),
- useIpv4Socket ? ipv4Socket->peerPort() : ipv6Socket->peerPort() );
-#else
- qDebug("DNS Manager: answer arrived: %d bytes from %s:%d", r,
- ipv4Socket->peerAddress().toString().ascii(), ipv4Socket->peerPort());;
-#endif
-#endif
- if ( r < 12 )
- return;
- // maybe we should check that the answer comes from port 53 on one
- // of our name servers...
- a.resize( r );
-
- TQ_UINT16 aid = (((TQ_UINT8)a[0]) << 8) + ((TQ_UINT8)a[1]);
- uint i = 0;
- while( i < queries.size() &&
- !( queries[i] && queries[i]->id == aid ) )
- i++;
- if ( i == queries.size() ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "DNS Manager: bad id (0x%04x) %d", aid, i );
-#endif
- return;
- }
-
- // at this point queries[i] is whatever we asked for.
-
- if ( ( (TQ_UINT8)(a[2]) & 0x80 ) == 0 ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "DNS Manager: received a query" );
-#endif
- return;
- }
-
- TQDnsQuery * q = queries[i];
- TQDnsAnswer answer( a, q );
- answer.parse();
- if ( answer.ok ) {
- queries.take( i );
- answer.notify();
- delete q;
- }
-}
-
-
-void TQDnsManager::transmitQuery( TQDnsQuery * query_ )
-{
- if ( !query_ )
- return;
-
- uint i = 0;
- while( i < queries.size() && queries[i] != 0 )
- i++;
- if ( i == queries.size() )
- queries.resize( i+1 );
- queries.insert( i, query_ );
- transmitQuery( i );
-}
-
-
-void TQDnsManager::transmitQuery( int i )
-{
- if ( i < 0 || i >= (int)queries.size() )
- return;
- TQDnsQuery * q = queries[i];
-
- if ( q && q->step > 8 ) {
- // okay, we've run out of retransmissions. we fake an NXDomain
- // with a very short life time...
- TQDnsAnswer answer( q );
- answer.notify();
-
- if (globalManager == 0)
- return;
-
- // and then get rid of the query
- queries.take( i );
-#if defined(TQDNS_DEBUG)
- qDebug( "DNS Manager: giving up on query 0x%04x", q->id );
-#endif
- delete q;
- TQTimer::singleShot( 0, TQDnsManager::manager(), TQT_SLOT(cleanCache()) );
- // and don't process anything more
- return;
- }
-
- if ( q && !q->dns || q->dns->isEmpty() )
- // noone currently wants the answer, so there's no point in
- // retransmitting the query. we keep it, though. an answer may
- // arrive for an earlier query transmission, and if it does we
- // may benefit from caching the result.
- return;
-
- TQByteArray p( 12 + q->l.length() + 2 + 4 );
- if ( p.size() > 500 )
- return; // way over the limit, so don't even try
-
- // header
- // id
- p[0] = (q->id & 0xff00) >> 8;
- p[1] = q->id & 0x00ff;
- p[2] = 1; // recursion desired, rest is 0
- p[3] = 0; // all is 0
- // one query
- p[4] = 0;
- p[5] = 1;
- // no answers, name servers or additional data
- p[6] = p[7] = p[8] = p[9] = p[10] = p[11] = 0;
-
- // the name is composed of several components. each needs to be
- // written by itself... so we write...
- // oh, and we assume that there's no funky characters in there.
- int pp = 12;
- uint lp = 0;
- while( lp < q->l.length() ) {
- int le = q->l.find( '.', lp );
- if ( le < 0 )
- le = q->l.length();
- TQString component = q->l.mid( lp, le-lp );
- p[pp++] = component.length();
- int cp;
- for( cp=0; cp < (int)component.length(); cp++ )
- p[pp++] = component[cp].latin1();
- lp = le + 1;
- }
- // final null
- p[pp++] = 0;
- // query type
- p[pp++] = 0;
- switch( q->t ) {
- case TQDns::A:
- p[pp++] = 1;
- break;
- case TQDns::Aaaa:
- p[pp++] = 28;
- break;
- case TQDns::Mx:
- p[pp++] = 15;
- break;
- case TQDns::Srv:
- p[pp++] = 33;
- break;
- case TQDns::Cname:
- p[pp++] = 5;
- break;
- case TQDns::Ptr:
- p[pp++] = 12;
- break;
- case TQDns::Txt:
- p[pp++] = 16;
- break;
- default:
- p[pp++] = (char)255; // any
- break;
- }
- // query class (always internet)
- p[pp++] = 0;
- p[pp++] = 1;
-
- // if we have no name servers, we should regenerate ns in case
- // name servers have recently been defined (like on windows,
- // plugging/unplugging the network cable will change the name
- // server entries)
- if ( !ns || ns->isEmpty() )
- TQDns::doResInit();
-
- if ( !ns || ns->isEmpty() ) {
- // we don't find any name servers. We fake an NXDomain
- // with a very short life time...
- TQDnsAnswer answer( q );
- answer.notify();
- // and then get rid of the query
- queries.take( i );
-#if defined(TQDNS_DEBUG)
- qDebug( "DNS Manager: no DNS server found on query 0x%04x", q->id );
-#endif
- delete q;
- TQTimer::singleShot( 1000*10, TQDnsManager::manager(), TQT_SLOT(cleanCache()) );
- // and don't process anything more
- return;
- }
-
- TQHostAddress receiver = *ns->at( q->step % ns->count() );
- if (receiver.isIPv4Address())
- ipv4Socket->writeBlock( p.data(), pp, receiver, 53 );
-#if !defined (TQT_NO_IPV6)
- else
- ipv6Socket->writeBlock( p.data(), pp, receiver, 53 );
-#endif
-#if defined(TQDNS_DEBUG)
- qDebug( "issuing query 0x%04x (%d) about %s type %d to %s",
- q->id, q->step, q->l.ascii(), q->t,
- ns->at( q->step % ns->count() )->toString().ascii() );
-#endif
- if ( ns->count() > 1 && q->step == 0 && queries.count() == 1 ) {
- // if it's the first time, and we don't have any other
- // outstanding queries, send nonrecursive queries to the other
- // name servers too.
- p[2] = 0;
- TQHostAddress * server;
- while( (server=ns->next()) != 0 ) {
- if (server->isIPv4Address())
- ipv4Socket->writeBlock( p.data(), pp, *server, 53 );
-#if !defined (TQT_NO_IPV6)
- else
- ipv6Socket->writeBlock( p.data(), pp, *server, 53 );
-#endif
-#if defined(TQDNS_DEBUG)
- qDebug( "copying query to %s", server->toString().ascii() );
-#endif
- }
- }
- q->step++;
- // some testing indicates that normal dns queries take up to 0.6
- // seconds. the graph becomes steep around that point, and the
- // number of errors rises... so it seems good to retry at that
- // point.
- q->start( q->step < ns->count() ? 800 : 1500, TRUE );
-}
-
-
-TQDnsDomain * TQDnsManager::domain( const TQString & label )
-{
- TQDnsDomain * d = cache.find( label );
- if ( !d ) {
- d = new TQDnsDomain( label );
- cache.insert( label, d );
- }
- return d;
-}
-
-
-//
-//
-// the TQDnsDomain class looks after and coordinates queries for TQDnsRRs for
-// each domain, and the cached TQDnsRRs. (A domain, in DNS terminology, is
-// a node in the DNS. "no", "trolltech.com" and "lupinella.troll.no" are
-// all domains.)
-//
-//
-
-
-// this is ONLY to be called by TQDnsManager::domain(). noone else.
-TQDnsDomain::TQDnsDomain( const TQString & label )
-{
- l = label;
- rrs = 0;
-}
-
-
-TQDnsDomain::~TQDnsDomain()
-{
- delete rrs;
- rrs = 0;
-}
-
-
-void TQDnsDomain::add( const TQString & label, TQDnsRR * rr )
-{
- TQDnsDomain * d = TQDnsManager::manager()->domain( label );
- if ( !d->rrs ) {
- d->rrs = new TQPtrList<TQDnsRR>;
- d->rrs->setAutoDelete( TRUE );
- }
- d->rrs->append( rr );
- rr->domain = d;
-}
-
-
-TQPtrList<TQDnsRR> * TQDnsDomain::cached( const TQDns * r )
-{
- TQPtrList<TQDnsRR> * l = new TQPtrList<TQDnsRR>;
-
- // test at first if you have to start a query at all
- if ( r->recordType() == TQDns::A ) {
- if ( r->label().lower() == "localhost" ) {
- // undocumented hack. ipv4-specific. also, may be a memory
- // leak? not sure. would be better to do this in doResInit(),
- // anyway.
- TQDnsRR *rrTmp = new TQDnsRR( r->label() );
- rrTmp->t = TQDns::A;
- rrTmp->address = TQHostAddress( 0x7f000001 );
- rrTmp->current = TRUE;
- l->append( rrTmp );
- return l;
- }
- TQHostAddress tmp;
- if ( tmp.setAddress( r->label() ) ) {
- TQDnsRR *rrTmp = new TQDnsRR( r->label() );
- if ( tmp.isIPv4Address() ) {
- rrTmp->t = TQDns::A;
- rrTmp->address = tmp;
- rrTmp->current = TRUE;
- l->append( rrTmp );
- } else {
- rrTmp->nxdomain = TRUE;
- }
- return l;
- }
- }
- if ( r->recordType() == TQDns::Aaaa ) {
- TQHostAddress tmp;
- if ( tmp.setAddress(r->label()) ) {
- TQDnsRR *rrTmp = new TQDnsRR( r->label() );
- if ( tmp.isIPv6Address() ) {
- rrTmp->t = TQDns::Aaaa;
- rrTmp->address = tmp;
- rrTmp->current = TRUE;
- l->append( rrTmp );
- } else {
- rrTmp->nxdomain = TRUE;
- }
- return l;
- }
- }
-
- // if you reach this point, you have to do the query
- TQDnsManager * m = TQDnsManager::manager();
- TQStringList n = r->qualifiedNames();
- TQValueListIterator<TQString> it = n.begin();
- TQValueListIterator<TQString> end = n.end();
- bool nxdomain;
- int cnamecount = 0;
- while( it != end ) {
- TQString s = *it++;
- nxdomain = FALSE;
-#if defined(TQDNS_DEBUG)
- qDebug( "looking at cache for %s (%s %d)",
- s.ascii(), r->label().ascii(), r->recordType() );
-#endif
- TQDnsDomain * d = m->domain( s );
-#if defined(TQDNS_DEBUG)
- qDebug( " - found %d RRs", d && d->rrs ? d->rrs->count() : 0 );
-#endif
- if ( d->rrs )
- d->rrs->first();
- TQDnsRR * rr;
- bool answer = FALSE;
- while( d->rrs && (rr=d->rrs->current()) != 0 ) {
- if ( rr->t == TQDns::Cname && r->recordType() != TQDns::Cname &&
- !rr->nxdomain && cnamecount < 16 ) {
- // cname. if the code is ugly, that may just
- // possibly be because the concept is.
-#if defined(TQDNS_DEBUG)
- qDebug( "found cname from %s to %s",
- r->label().ascii(), rr->target.ascii() );
-#endif
- s = rr->target;
- d = m->domain( s );
- if ( d->rrs )
- d->rrs->first();
- it = end;
- // we've elegantly moved over to whatever the cname
- // pointed to. well, not elegantly. let's remember
- // that we've done something, anyway, so we can't be
- // fooled into an infinte loop as well.
- cnamecount++;
- } else {
- if ( rr->t == r->recordType() ) {
- if ( rr->nxdomain )
- nxdomain = TRUE;
- else
- answer = TRUE;
- l->append( rr );
- if ( rr->deleteTime <= lastSweep ) {
- // we're returning something that'll be
- // deleted soon. we assume that if the client
- // wanted it twice, it'll want it again, so we
- // ask the name server again right now.
- TQDnsQuery * query = new TQDnsQuery;
- query->started = now();
- query->id = ++::id;
- query->t = rr->t;
- query->l = rr->domain->name();
- // note that here, we don't bother about
- // notification. but we do bother about
- // timeouts: we make sure to use high timeouts
- // and few tramsissions.
- query->step = ns->count();
- TQObject::connect( query, TQT_SIGNAL(timeout()),
- TQDnsManager::manager(),
- TQT_SLOT(retransmit()) );
- TQDnsManager::manager()->transmitQuery( query );
- }
- }
- d->rrs->next();
- }
- }
- // if we found a positive result, return quickly
- if ( answer && l->count() ) {
-#if defined(TQDNS_DEBUG)
- qDebug( "found %d records for %s",
- l->count(), r->label().ascii() );
- l->first();
- while( l->current() ) {
- qDebug( " type %d target %s address %s",
- l->current()->t,
- l->current()->target.latin1(),
- l->current()->address.toString().latin1() );
- l->next();
- }
-#endif
- l->first();
- return l;
- }
-
-#if defined(TQDNS_DEBUG)
- if ( nxdomain )
- qDebug( "found NXDomain %s", s.ascii() );
-#endif
-
- if ( !nxdomain ) {
- // if we didn't, and not a negative result either, perhaps
- // we need to transmit a query.
- uint q = 0;
- while ( q < m->queries.size() &&
- ( m->queries[q] == 0 ||
- m->queries[q]->t != r->recordType() ||
- m->queries[q]->l != s ) )
- q++;
- // we haven't done it before, so maybe we should. but
- // wait - if it's an unqualified name, only ask when all
- // the other alternatives are exhausted.
- if ( q == m->queries.size() && ( s.find( '.' ) >= 0 ||
- l->count() >= n.count()-1 ) ) {
- TQDnsQuery * query = new TQDnsQuery;
- query->started = now();
- query->id = ++::id;
- query->t = r->recordType();
- query->l = s;
- query->dns->replace( (void*)r, (void*)r );
- TQObject::connect( query, TQT_SIGNAL(timeout()),
- TQDnsManager::manager(), TQT_SLOT(retransmit()) );
- TQDnsManager::manager()->transmitQuery( query );
- } else if ( q < m->queries.size() ) {
- // if we've found an earlier query for the same
- // domain/type, subscribe to its answer
- m->queries[q]->dns->replace( (void*)r, (void*)r );
- }
- }
- }
- l->first();
- return l;
-}
-
-
-void TQDnsDomain::sweep( TQ_UINT32 thisSweep )
-{
- if ( !rrs )
- return;
-
- TQDnsRR * rr;
- rrs->first();
- while( (rr=rrs->current()) != 0 ) {
- if ( !rr->deleteTime )
- rr->deleteTime = thisSweep; // will hit next time around
-
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns::sweep: %s type %d expires %u %u - %s / %s",
- rr->domain->name().latin1(), rr->t,
- rr->expireTime, rr->deleteTime,
- rr->target.latin1(), rr->address.toString().latin1());
-#endif
- if ( rr->current == FALSE ||
- rr->t == TQDns::None ||
- rr->deleteTime <= thisSweep ||
- rr->expireTime <= thisSweep )
- rrs->remove();
- else
- rrs->next();
- }
-
- if ( rrs->isEmpty() ) {
- delete rrs;
- rrs = 0;
- }
-}
-
-
-
-
-// the itsy-bitsy little socket class I don't really need except for
-// so I can subclass and reimplement the Q_SLOTS.
-
-
-TQDnsSocket::TQDnsSocket( TQObject * parent, const char * name )
- : TQObject( parent, name )
-{
- // nothing
-}
-
-
-TQDnsSocket::~TQDnsSocket()
-{
- // nothing
-}
-
-
-void TQDnsSocket::cleanCache()
-{
- // nothing
-}
-
-
-void TQDnsSocket::retransmit()
-{
- // nothing
-}
-
-
-void TQDnsSocket::answer()
-{
- // nothing
-}
-
-
-/*!
- \class TQDns tqdns.h
- \brief The TQDns class provides asynchronous DNS lookups.
-\if defined(commercial)
- It is part of the <a href="commercialeditions.html">TQt Enterprise Edition</a>.
-\endif
-
- \module network
- \ingroup io
-
- Both Windows and Unix provide synchronous DNS lookups; Windows
- provides some asynchronous support too. At the time of writing
- neither operating system provides asynchronous support for
- anything other than hostname-to-address mapping.
-
- TQDns rectifies this shortcoming, by providing asynchronous caching
- lookups for the record types that we expect modern GUI
- applications to need in the near future.
-
- The class is \e not straightforward to use (although it is much
- simpler than the native APIs); TQSocket provides much easier to use
- TCP connection facilities. The aim of TQDns is to provide a correct
- and small API to the DNS and nothing more. (We use "correctness"
- to mean that the DNS information is correctly cached, and
- correctly timed out.)
-
- The API comprises a constructor, functions to set the DNS node
- (the domain in DNS terminology) and record type (setLabel() and
- setRecordType()), the corresponding get functions, an isWorking()
- function to determine whether TQDns is working or reading, a
- resultsReady() signal and query functions for the result.
-
- There is one query function for each RecordType, namely
- addresses(), mailServers(), servers(), hostNames() and texts().
- There are also two generic query functions: canonicalName()
- returns the name you'll presumably end up using (the exact meaning
- of this depends on the record type) and qualifiedNames() returns a
- list of the fully qualified names label() maps to.
-
- \sa TQSocket
-*/
-
-/*!
- Constructs a DNS query object with invalid settings for both the
- label and the search type.
-*/
-
-TQDns::TQDns()
-{
- d = new TQDnsPrivate;
- t = None;
-}
-
-
-
-
-/*!
- Constructs a DNS query object that will return record type \a rr
- information about \a label.
-
- The DNS lookup is started the next time the application enters the
- event loop. When the result is found the signal resultsReady() is
- emitted.
-
- \a rr defaults to \c A, IPv4 addresses.
-*/
-
-TQDns::TQDns( const TQString & label, RecordType rr )
-{
- d = new TQDnsPrivate;
- t = rr;
- setLabel( label );
- setStartQueryTimer(); // start query the next time we enter event loop
-}
-
-
-
-/*!
- Constructs a DNS query object that will return record type \a rr
- information about host address \a address. The label is set to the
- IN-ADDR.ARPA domain name. This is useful in combination with the
- \c Ptr record type (e.g. if you want to look up a hostname for a
- given address).
-
- The DNS lookup is started the next time the application enters the
- event loop. When the result is found the signal resultsReady() is
- emitted.
-
- \a rr defaults to \c Ptr, that maps addresses to hostnames.
-*/
-
-TQDns::TQDns( const TQHostAddress & address, RecordType rr )
-{
- d = new TQDnsPrivate;
- t = rr;
- setLabel( address );
- setStartQueryTimer(); // start query the next time we enter event loop
-}
-
-
-
-
-/*!
- Destroys the DNS query object and frees its allocated resources.
-*/
-
-TQDns::~TQDns()
-{
- if ( globalManager ) {
- uint q = 0;
- TQDnsManager * m = globalManager;
- while( q < m->queries.size() ) {
- TQDnsQuery * query=m->queries[q];
- if ( query && query->dns )
- (void)query->dns->take( (void*) this );
- q++;
- }
-
- }
-
- delete d;
- d = 0;
-}
-
-
-
-
-/*!
- Sets this DNS query object to query for information about \a
- label.
-
- This does not change the recordType(), but its isWorking() status
- will probably change as a result.
-
- The DNS lookup is started the next time the application enters the
- event loop. When the result is found the signal resultsReady() is
- emitted.
-*/
-
-void TQDns::setLabel( const TQString & label )
-{
- l = label;
- d->noNames = FALSE;
-
- // construct a list of qualified names
- n.clear();
- if ( l.length() > 1 && l[(int)l.length()-1] == '.' ) {
- n.append( l.left( l.length()-1 ).lower() );
- } else {
- int i = l.length();
- int dots = 0;
- const int maxDots = 2;
- while( i && dots < maxDots ) {
- if ( l[--i] == '.' )
- dots++;
- }
- if ( dots < maxDots ) {
- (void)TQDnsManager::manager(); // create a TQDnsManager, if it is not already there
- TQStrListIterator it( *domains );
- const char * dom;
- while( (dom=it.current()) != 0 ) {
- ++it;
- n.append( l.lower() + "." + dom );
- }
- }
- n.append( l.lower() );
- }
-
-#if defined(TQ_DNS_SYNCHRONOUS)
- if ( d->noEventLoop ) {
- doSynchronousLookup();
- } else {
- setStartQueryTimer(); // start query the next time we enter event loop
- }
-#else
- setStartQueryTimer(); // start query the next time we enter event loop
-#endif
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns::setLabel: %d address(es) for %s", n.count(), l.ascii() );
- int i = 0;
- for( i = 0; i < (int)n.count(); i++ )
- qDebug( "TQDns::setLabel: %d: %s", i, n[i].ascii() );
-#endif
-}
-
-
-/*!
- \overload
-
- Sets this DNS query object to query for information about the host
- address \a address. The label is set to the IN-ADDR.ARPA domain
- name. This is useful in combination with the \c Ptr record type
- (e.g. if you want to look up a hostname for a given address).
-*/
-
-void TQDns::setLabel( const TQHostAddress & address )
-{
- setLabel( toInAddrArpaDomain( address ) );
-}
-
-
-/*!
- \fn TQStringList TQDns::qualifiedNames() const
-
- Returns a list of the fully qualified names label() maps to.
-
- Note that if you want to iterate over the list, you should iterate
- over a copy, e.g.
- \code
- TQStringList list = myDns.qualifiedNames();
- TQStringList::Iterator it = list.begin();
- while( it != list.end() ) {
- myProcessing( *it );
- ++it;
- }
- \endcode
-
-*/
-
-
-/*!
- \fn TQString TQDns::label() const
-
- Returns the domain name for which this object returns information.
-
- \sa setLabel()
-*/
-
-/*!
- \enum TQDns::RecordType
-
- This enum type defines the record types TQDns can handle. The DNS
- provides many more; these are the ones we've judged to be in
- current use, useful for GUI programs and important enough to
- support right away:
-
- \value None No information. This exists only so that TQDns can
- have a default.
-
- \value A IPv4 addresses. By far the most common type.
-
- \value Aaaa IPv6 addresses. So far mostly unused.
-
- \value Mx Mail eXchanger names. Used for mail delivery.
-
- \value Srv SeRVer names. Generic record type for finding
- servers. So far mostly unused.
-
- \value Cname Canonical names. Maps from nicknames to the true
- name (the canonical name) for a host.
-
- \value Ptr name PoinTeRs. Maps from IPv4 or IPv6 addresses to hostnames.
-
- \value Txt arbitrary TeXT for domains.
-
- We expect that some support for the
- \link http://www.dns.net/dnsrd/rfc/rfc2535.html RFC-2535 \endlink
- extensions will be added in future versions.
-*/
-
-/*!
- Sets this object to query for record type \a rr records.
-
- The DNS lookup is started the next time the application enters the
- event loop. When the result is found the signal resultsReady() is
- emitted.
-
- \sa RecordType
-*/
-
-void TQDns::setRecordType( RecordType rr )
-{
- t = rr;
- d->noNames = FALSE;
- setStartQueryTimer(); // start query the next time we enter event loop
-}
-
-/*!
- \internal
-
- Private slot for starting the query.
-*/
-void TQDns::startQuery()
-{
- // isWorking() starts the query (if necessary)
- if ( !isWorking() )
- emit resultsReady();
-}
-
-/*!
- The three functions TQDns::TQDns(TQString, RecordType),
- TQDns::setLabel() and TQDns::setRecordType() may start a DNS lookup.
- This function handles setting up the single shot timer.
-*/
-void TQDns::setStartQueryTimer()
-{
-#if defined(TQ_DNS_SYNCHRONOUS)
- if ( !d->queryTimer && !d->noEventLoop )
-#else
- if ( !d->queryTimer )
-#endif
- {
- // start the query the next time we enter event loop
- d->queryTimer = new TQTimer( this );
- connect( d->queryTimer, TQT_SIGNAL(timeout()),
- this, TQT_SLOT(startQuery()) );
- d->queryTimer->start( 0, TRUE );
- }
-}
-
-/*
- Transforms the host address \a address to the IN-ADDR.ARPA domain
- name. Returns something indeterminate if you're sloppy or
- naughty. This function has an IPv4-specific name, but works for
- IPv6 too.
-*/
-TQString TQDns::toInAddrArpaDomain( const TQHostAddress &address )
-{
- TQString s;
- if ( address.isNull() ) {
- // if the address isn't valid, neither of the other two make
- // cases make sense. better to just return.
- } else if ( address.isIp4Addr() ) {
- TQ_UINT32 i = address.ip4Addr();
- s.sprintf( "%d.%d.%d.%d.IN-ADDR.ARPA",
- i & 0xff, (i >> 8) & 0xff, (i>>16) & 0xff, (i>>24) & 0xff );
- } else {
- // RFC 3152. (1886 is deprecated, and clients no longer need to
- // support it, in practice).
- TQ_IPV6ADDR i = address.toIPv6Address();
- s = "ip6.arpa";
- uint b = 0;
- while( b < 16 ) {
- s = TQString::number( i.c[b]%16, 16 ) + "." +
- TQString::number( i.c[b]/16, 16 ) + "." + s;
- b++;
- }
- }
- return s;
-}
-
-
-/*!
- \fn TQDns::RecordType TQDns::recordType() const
-
- Returns the record type of this DNS query object.
-
- \sa setRecordType() RecordType
-*/
-
-/*!
- \fn void TQDns::resultsReady()
-
- This signal is emitted when results are available for one of the
- qualifiedNames().
-*/
-
-/*!
- Returns TRUE if TQDns is doing a lookup for this object (i.e. if it
- does not already have the necessary information); otherwise
- returns FALSE.
-
- TQDns emits the resultsReady() signal when the status changes to FALSE.
-*/
-
-bool TQDns::isWorking() const
-{
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns::isWorking (%s, %d)", l.ascii(), t );
-#endif
- if ( t == None )
- return FALSE;
-
-#if defined(TQ_DNS_SYNCHRONOUS)
- if ( d->noEventLoop )
- return TRUE;
-#endif
-
- TQPtrList<TQDnsRR> * ll = TQDnsDomain::cached( this );
- TQ_LONG queries = n.count();
- while( ll->current() != 0 ) {
- if ( ll->current()->nxdomain ) {
- queries--;
- } else {
- delete ll;
- return FALSE;
- }
- ll->next();
- }
- delete ll;
-
- if ( queries <= 0 )
- return FALSE;
- if ( d->noNames )
- return FALSE;
- return TRUE;
-}
-
-
-/*!
- Returns a list of the addresses for this name if this TQDns object
- has a recordType() of \c TQDns::A or \c TQDns::Aaaa and the answer
- is available; otherwise returns an empty list.
-
- As a special case, if label() is a valid numeric IP address, this
- function returns that address.
-
- Note that if you want to iterate over the list, you should iterate
- over a copy, e.g.
- \code
- TQValueList<TQHostAddress> list = myDns.addresses();
- TQValueList<TQHostAddress>::Iterator it = list.begin();
- while( it != list.end() ) {
- myProcessing( *it );
- ++it;
- }
- \endcode
-
-*/
-
-TQValueList<TQHostAddress> TQDns::addresses() const
-{
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns::addresses (%s)", l.ascii() );
-#endif
- TQValueList<TQHostAddress> result;
- if ( t != A && t != Aaaa )
- return result;
-
- TQPtrList<TQDnsRR> * cached = TQDnsDomain::cached( this );
-
- TQDnsRR * rr;
- while( (rr=cached->current()) != 0 ) {
- if ( rr->current && !rr->nxdomain )
- result.append( rr->address );
- cached->next();
- }
- delete cached;
- return result;
-}
-
-
-/*!
- \class TQDns::MailServer
- \brief The TQDns::MailServer class is described in TQDns::mailServers().
-\if defined(commercial)
- It is part of the <a href="commercialeditions.html">TQt Enterprise Edition</a>.
-\endif
-
- \ingroup io
-
- \internal
-*/
-
-/*!
- Returns a list of mail servers if the record type is \c Mx. The
- class \c TQDns::MailServer contains the following public variables:
- \list
- \i TQString TQDns::MailServer::name
- \i TQ_UINT16 TQDns::MailServer::priority
- \endlist
-
- Note that if you want to iterate over the list, you should iterate
- over a copy, e.g.
- \code
- TQValueList<TQDns::MailServer> list = myDns.mailServers();
- TQValueList<TQDns::MailServer>::Iterator it = list.begin();
- while( it != list.end() ) {
- myProcessing( *it );
- ++it;
- }
- \endcode
-
-*/
-TQValueList<TQDns::MailServer> TQDns::mailServers() const
-{
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns::mailServers (%s)", l.ascii() );
-#endif
- TQValueList<TQDns::MailServer> result;
- if ( t != Mx )
- return result;
-
- TQPtrList<TQDnsRR> * cached = TQDnsDomain::cached( this );
-
- TQDnsRR * rr;
- while( (rr=cached->current()) != 0 ) {
- if ( rr->current && !rr->nxdomain ) {
- MailServer ms( rr->target, rr->priority );
- result.append( ms );
- }
- cached->next();
- }
- delete cached;
- return result;
-}
-
-
-/*!
- \class TQDns::Server
- \brief The TQDns::Server class is described in TQDns::servers().
-\if defined(commercial)
- It is part of the <a href="commercialeditions.html">TQt Enterprise Edition</a>.
-\endif
-
- \ingroup io
-
- \internal
-*/
-
-/*!
- Returns a list of servers if the record type is \c Srv. The class
- \c TQDns::Server contains the following public variables:
- \list
- \i TQString TQDns::Server::name
- \i TQ_UINT16 TQDns::Server::priority
- \i TQ_UINT16 TQDns::Server::weight
- \i TQ_UINT16 TQDns::Server::port
- \endlist
-
- Note that if you want to iterate over the list, you should iterate
- over a copy, e.g.
- \code
- TQValueList<TQDns::Server> list = myDns.servers();
- TQValueList<TQDns::Server>::Iterator it = list.begin();
- while( it != list.end() ) {
- myProcessing( *it );
- ++it;
- }
- \endcode
-*/
-TQValueList<TQDns::Server> TQDns::servers() const
-{
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns::servers (%s)", l.ascii() );
-#endif
- TQValueList<TQDns::Server> result;
- if ( t != Srv )
- return result;
-
- TQPtrList<TQDnsRR> * cached = TQDnsDomain::cached( this );
-
- TQDnsRR * rr;
- while( (rr=cached->current()) != 0 ) {
- if ( rr->current && !rr->nxdomain ) {
- Server s( rr->target, rr->priority, rr->weight, rr->port );
- result.append( s );
- }
- cached->next();
- }
- delete cached;
- return result;
-}
-
-
-/*!
- Returns a list of host names if the record type is \c Ptr.
-
- Note that if you want to iterate over the list, you should iterate
- over a copy, e.g.
- \code
- TQStringList list = myDns.hostNames();
- TQStringList::Iterator it = list.begin();
- while( it != list.end() ) {
- myProcessing( *it );
- ++it;
- }
- \endcode
-
-*/
-TQStringList TQDns::hostNames() const
-{
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns::hostNames (%s)", l.ascii() );
-#endif
- TQStringList result;
- if ( t != Ptr )
- return result;
-
- TQPtrList<TQDnsRR> * cached = TQDnsDomain::cached( this );
-
- TQDnsRR * rr;
- while( (rr=cached->current()) != 0 ) {
- if ( rr->current && !rr->nxdomain ) {
- TQString str( rr->target );
- result.append( str );
- }
- cached->next();
- }
- delete cached;
- return result;
-}
-
-
-/*!
- Returns a list of texts if the record type is \c Txt.
-
- Note that if you want to iterate over the list, you should iterate
- over a copy, e.g.
- \code
- TQStringList list = myDns.texts();
- TQStringList::Iterator it = list.begin();
- while( it != list.end() ) {
- myProcessing( *it );
- ++it;
- }
- \endcode
-*/
-TQStringList TQDns::texts() const
-{
-#if defined(TQDNS_DEBUG)
- qDebug( "TQDns::texts (%s)", l.ascii() );
-#endif
- TQStringList result;
- if ( t != Txt )
- return result;
-
- TQPtrList<TQDnsRR> * cached = TQDnsDomain::cached( this );
-
- TQDnsRR * rr;
- while( (rr=cached->current()) != 0 ) {
- if ( rr->current && !rr->nxdomain ) {
- TQString str( rr->text );
- result.append( str );
- }
- cached->next();
- }
- delete cached;
- return result;
-}
-
-
-/*!
- Returns the canonical name for this DNS node. (This works
- regardless of what recordType() is set to.)
-
- If the canonical name isn't known, this function returns a null
- string.
-
- The canonical name of a DNS node is its full name, or the full
- name of the target of its CNAME. For example, if l.trolltech.com
- is a CNAME to lillian.troll.no, and the search path for TQDns is
- "trolltech.com", then the canonical name for all of "lillian",
- "l", "lillian.troll.no." and "l.trolltech.com" is
- "lillian.troll.no.".
-*/
-
-TQString TQDns::canonicalName() const
-{
- // the cname should work regardless of the recordType(), so set the record
- // type temporarily to cname when you look at the cache
- TQDns *that = (TQDns*) this; // mutable function
- RecordType oldType = t;
- that->t = Cname;
- TQPtrList<TQDnsRR> * cached = TQDnsDomain::cached( that );
- that->t = oldType;
-
- TQDnsRR * rr;
- while( (rr=cached->current()) != 0 ) {
- if ( rr->current && !rr->nxdomain && rr->domain ) {
- delete cached;
- return rr->target;
- }
- cached->next();
- }
- delete cached;
- return TQString::null;
-}
-
-#if defined(TQ_DNS_SYNCHRONOUS)
-/*! \reimp
-*/
-void TQDns::connectNotify( const char *signal )
-{
- if ( d->noEventLoop && qstrcmp(signal,TQT_SIGNAL(resultsReady()) )==0 ) {
- doSynchronousLookup();
- }
-}
-#endif
-
-#if defined(TQ_OS_WIN32) || defined(TQ_OS_CYGWIN)
-
-#if defined(TQ_DNS_SYNCHRONOUS)
-void TQDns::doSynchronousLookup()
-{
- // ### not implemented yet
-}
-#endif
-
-// the following typedefs are needed for GetNetworkParams() API call
-#ifndef IP_TYPES_INCLUDED
-#define MAX_HOSTNAME_LEN 128
-#define MAX_DOMAIN_NAME_LEN 128
-#define MAX_SCOPE_ID_LEN 256
-typedef struct {
- char String[4 * 4];
-} IP_ADDRESS_STRING, *PIP_ADDRESS_STRING, IP_MASK_STRING, *PIP_MASK_STRING;
-typedef struct _IP_ADDR_STRING {
- struct _IP_ADDR_STRING* Next;
- IP_ADDRESS_STRING IpAddress;
- IP_MASK_STRING IpMask;
- DWORD Context;
-} IP_ADDR_STRING, *PIP_ADDR_STRING;
-typedef struct {
- char HostName[MAX_HOSTNAME_LEN + 4] ;
- char DomainName[MAX_DOMAIN_NAME_LEN + 4];
- PIP_ADDR_STRING CurrentDnsServer;
- IP_ADDR_STRING DnsServerList;
- UINT NodeType;
- char ScopeId[MAX_SCOPE_ID_LEN + 4];
- UINT EnableRouting;
- UINT EnableProxy;
- UINT EnableDns;
-} FIXED_INFO, *PFIXED_INFO;
-#endif
-typedef DWORD (WINAPI *GNP)( PFIXED_INFO, PULONG );
-
-// ### FIXME: this code is duplicated in qfiledialog.cpp
-static TQString getWindowsRegString( HKEY key, const TQString &subKey )
-{
- TQString s;
- TQT_WA( {
- char buf[1024];
- DWORD bsz = sizeof(buf);
- int r = RegQueryValueEx( key, (TCHAR*)subKey.ucs2(), 0, 0, (LPBYTE)buf, &bsz );
- if ( r == ERROR_SUCCESS ) {
- s = TQString::fromUcs2( (unsigned short *)buf );
- } else if ( r == ERROR_MORE_DATA ) {
- char *ptr = new char[bsz+1];
- r = RegQueryValueEx( key, (TCHAR*)subKey.ucs2(), 0, 0, (LPBYTE)ptr, &bsz );
- if ( r == ERROR_SUCCESS )
- s = ptr;
- delete [] ptr;
- }
- } , {
- char buf[512];
- DWORD bsz = sizeof(buf);
- int r = RegQueryValueExA( key, subKey.local8Bit(), 0, 0, (LPBYTE)buf, &bsz );
- if ( r == ERROR_SUCCESS ) {
- s = buf;
- } else if ( r == ERROR_MORE_DATA ) {
- char *ptr = new char[bsz+1];
- r = RegQueryValueExA( key, subKey.local8Bit(), 0, 0, (LPBYTE)ptr, &bsz );
- if ( r == ERROR_SUCCESS )
- s = ptr;
- delete [] ptr;
- }
- } );
- return s;
-}
-
-static bool getDnsParamsFromRegistry( const TQString &path,
- TQString *domainName, TQString *nameServer, TQString *searchList )
-{
- HKEY k;
- int r;
- TQT_WA( {
- r = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
- (TCHAR*)path.ucs2(),
- 0, KEY_READ, &k );
- } , {
- r = RegOpenKeyExA( HKEY_LOCAL_MACHINE,
- path,
- 0, KEY_READ, &k );
- } );
-
- if ( r == ERROR_SUCCESS ) {
- *domainName = getWindowsRegString( k, "DhcpDomain" );
- if ( domainName->isEmpty() )
- *domainName = getWindowsRegString( k, "Domain" );
-
- *nameServer = getWindowsRegString( k, "DhcpNameServer" );
- if ( nameServer->isEmpty() )
- *nameServer = getWindowsRegString( k, "NameServer" );
-
- *searchList = getWindowsRegString( k, "SearchList" );
- }
- RegCloseKey( k );
- return r == ERROR_SUCCESS;
-}
-
-void TQDns::doResInit()
-{
- char separator = 0;
-
- if ( ns )
- delete ns;
- ns = new TQPtrList<TQHostAddress>;
- ns->setAutoDelete( TRUE );
- domains = new TQStrList( TRUE );
- domains->setAutoDelete( TRUE );
-
- TQString domainName, nameServer, searchList;
-
- bool gotNetworkParams = FALSE;
- // try the API call GetNetworkParams() first and use registry lookup only
- // as a fallback
-#ifdef TQ_OS_TEMP
- HINSTANCE hinstLib = LoadLibraryW( L"iphlpapi" );
-#else
- HINSTANCE hinstLib = LoadLibraryA( "iphlpapi" );
-#endif
- if ( hinstLib != 0 ) {
-#ifdef TQ_OS_TEMP
- GNP getNetworkParams = (GNP) GetProcAddressW( hinstLib, L"GetNetworkParams" );
-#else
- GNP getNetworkParams = (GNP) GetProcAddress( hinstLib, "GetNetworkParams" );
-#endif
- if ( getNetworkParams != 0 ) {
- ULONG l = 0;
- DWORD res;
- res = getNetworkParams( 0, &l );
- if ( res == ERROR_BUFFER_OVERFLOW ) {
- FIXED_INFO *finfo = (FIXED_INFO*)new char[l];
- res = getNetworkParams( finfo, &l );
- if ( res == ERROR_SUCCESS ) {
- domainName = finfo->DomainName;
- nameServer = "";
- IP_ADDR_STRING *dnsServer = &finfo->DnsServerList;
- while ( dnsServer != 0 ) {
- nameServer += dnsServer->IpAddress.String;
- dnsServer = dnsServer->Next;
- if ( dnsServer != 0 )
- nameServer += " ";
- }
- searchList = "";
- separator = ' ';
- gotNetworkParams = TRUE;
- }
- delete[] finfo;
- }
- }
- FreeLibrary( hinstLib );
- }
- if ( !gotNetworkParams ) {
- if ( getDnsParamsFromRegistry(
- TQString( "System\\CurrentControlSet\\Services\\Tcpip\\Parameters" ),
- &domainName, &nameServer, &searchList )) {
- // for NT
- separator = ' ';
- } else if ( getDnsParamsFromRegistry(
- TQString( "System\\CurrentControlSet\\Services\\VxD\\MSTCP" ),
- &domainName, &nameServer, &searchList )) {
- // for 95/98
- separator = ',';
- } else {
- // Could not access the TCP/IP parameters
- domainName = "";
- nameServer = "127.0.0.1";
- searchList = "";
- separator = ' ';
- }
- }
-
- nameServer = nameServer.simplifyWhiteSpace();
- int first, last;
- if ( !nameServer.isEmpty() ) {
- first = 0;
- do {
- last = nameServer.find( separator, first );
- if ( last < 0 )
- last = nameServer.length();
- TQDns tmp( nameServer.mid( first, last-first ), TQDns::A );
- TQValueList<TQHostAddress> address = tmp.addresses();
- TQ_LONG i = address.count();
- while( i )
- ns->append( new TQHostAddress(address[--i]) );
- first = last+1;
- } while( first < (int)nameServer.length() );
- }
-
- searchList = searchList + " " + domainName;
- searchList = searchList.simplifyWhiteSpace().lower();
- first = 0;
- do {
- last = searchList.find( separator, first );
- if ( last < 0 )
- last = searchList.length();
- domains->append( qstrdup( searchList.mid( first, last-first ) ) );
- first = last+1;
- } while( first < (int)searchList.length() );
-}
-
-#elif defined(TQ_OS_UNIX)
-
-#if defined(TQ_DNS_SYNCHRONOUS)
-void TQDns::doSynchronousLookup()
-{
- if ( t!=None && !l.isEmpty() ) {
- TQValueListIterator<TQString> it = n.begin();
- TQValueListIterator<TQString> end = n.end();
- int type;
- switch( t ) {
- case TQDns::A:
- type = 1;
- break;
- case TQDns::Aaaa:
- type = 28;
- break;
- case TQDns::Mx:
- type = 15;
- break;
- case TQDns::Srv:
- type = 33;
- break;
- case TQDns::Cname:
- type = 5;
- break;
- case TQDns::Ptr:
- type = 12;
- break;
- case TQDns::Txt:
- type = 16;
- break;
- default:
- type = (char)255; // any
- break;
- }
- while( it != end ) {
- TQString s = *it;
- it++;
- TQByteArray ba( 512 );
- int len = res_search( s.latin1(), 1, type, (uchar*)ba.data(), ba.size() );
- if ( len > 0 ) {
- ba.resize( len );
-
- TQDnsQuery * query = new TQDnsQuery;
- query->started = now();
- query->id = ++::id;
- query->t = t;
- query->l = s;
- TQDnsAnswer a( ba, query );
- a.parse();
- } else if ( len == -1 ) {
- // res_search error
- }
- }
- emit resultsReady();
- }
-}
-#endif
-
-#if defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 3)))
-#define TQ_MODERN_RES_API
-#else
-#endif
-
-void TQDns::doResInit()
-{
- if ( ns )
- return;
- ns = new TQPtrList<TQHostAddress>;
- ns->setAutoDelete( TRUE );
- domains = new TQStrList( TRUE );
- domains->setAutoDelete( TRUE );
-
- // read resolv.conf manually.
- TQFile resolvConf("/etc/resolv.conf");
- if (resolvConf.open(IO_ReadOnly)) {
- TQTextStream stream( &resolvConf );
- TQString line;
-
- while ( !stream.atEnd() ) {
- line = stream.readLine();
- TQStringList list = TQStringList::split( " ", line );
- if ( line.startsWith( "#" ) || list.count() < 2 )
- continue;
- const TQString type = list[0].lower();
-
- if ( type == "nameserver" ) {
- TQHostAddress *address = new TQHostAddress();
- if ( address->setAddress( TQString(list[1]) ) ) {
- // only add ipv6 addresses from resolv.conf if
- // this host supports ipv6.
- if ( address->isIPv4Address() || ipv6support )
- ns->append( address );
- else
- delete address;
- } else {
- delete address;
- }
- } else if ( type == "search" ) {
- TQStringList srch = TQStringList::split( " ", list[1] );
- for ( TQStringList::Iterator i = srch.begin(); i != srch.end(); ++i )
- domains->append( (*i).lower() );
-
- } else if ( type == "domain" ) {
- domains->append( list[1].lower() );
- }
- }
- }
-
- if (ns->isEmpty()) {
-#if defined(TQ_MODERN_RES_API)
- struct __res_state res;
- res_ninit( &res );
- int i;
- // find the name servers to use
- for( i=0; i < MAXNS && i < res.nscount; i++ )
- ns->append( new TQHostAddress( ntohl( res.nsaddr_list[i].sin_addr.s_addr ) ) );
-# if defined(MAXDFLSRCH)
- for( i=0; i < MAXDFLSRCH; i++ ) {
- if ( res.dnsrch[i] && *(res.dnsrch[i]) )
- domains->append( TQString::tqfromLatin1( res.dnsrch[i] ).lower() );
- else
- break;
- }
-# endif
- if ( *res.defdname )
- domains->append( TQString::tqfromLatin1( res.defdname ).lower() );
-#else
- qdns_res_init();
- int i;
- // find the name servers to use
- for( i=0; i < MAXNS && i < _res.nscount; i++ )
- ns->append( new TQHostAddress( ntohl( _res.nsaddr_list[i].sin_addr.s_addr ) ) );
-# if defined(MAXDFLSRCH)
- for( i=0; i < MAXDFLSRCH; i++ ) {
- if ( _res.dnsrch[i] && *(_res.dnsrch[i]) )
- domains->append( TQString::tqfromLatin1( _res.dnsrch[i] ).lower() );
- else
- break;
- }
-# endif
- if ( *_res.defdname )
- domains->append( TQString::tqfromLatin1( _res.defdname ).lower() );
-#endif
-
- // the code above adds "0.0.0.0" as a name server at the slightest
- // hint of trouble. so remove those again.
- ns->first();
- while( ns->current() ) {
- if ( ns->current()->isNull() )
- delete ns->take();
- else
- ns->next();
- }
- }
-
- TQFile hosts( TQString::tqfromLatin1( "/etc/hosts" ) );
- if ( hosts.open( IO_ReadOnly ) ) {
- // read the /etc/hosts file, creating long-life A and PTR RRs
- // for the things we find.
- TQTextStream i( &hosts );
- TQString line;
- while( !i.atEnd() ) {
- line = i.readLine().simplifyWhiteSpace().lower();
- uint n = 0;
- while( n < line.length() && line[(int)n] != '#' )
- n++;
- line.truncate( n );
- n = 0;
- while( n < line.length() && !line[(int)n].isSpace() )
- n++;
- TQString ip = line.left( n );
- TQHostAddress a;
- a.setAddress( ip );
- if ( ( a.isIPv4Address() || a.isIPv6Address() ) && !a.isNull() ) {
- bool first = TRUE;
- line = line.mid( n+1 );
- n = 0;
- while( n < line.length() && !line[(int)n].isSpace() )
- n++;
- TQString hostname = line.left( n );
- // ### in case of bad syntax, hostname is invalid. do we care?
- if ( n ) {
- TQDnsRR * rr = new TQDnsRR( hostname );
- if ( a.isIPv4Address() )
- rr->t = TQDns::A;
- else
- rr->t = TQDns::Aaaa;
- rr->address = a;
- rr->deleteTime = UINT_MAX;
- rr->expireTime = UINT_MAX;
- rr->current = TRUE;
- if ( first ) {
- first = FALSE;
- TQDnsRR * ptr = new TQDnsRR( TQDns::toInAddrArpaDomain( a ) );
- ptr->t = TQDns::Ptr;
- ptr->target = hostname;
- ptr->deleteTime = UINT_MAX;
- ptr->expireTime = UINT_MAX;
- ptr->current = TRUE;
- }
- }
- }
- }
- }
-}
-
-#endif
-
-#endif // TQT_NO_DNS
-
-#endif // USE_QT4 \ No newline at end of file