diff options
Diffstat (limited to 'tqtinterface/qt4/src/network/tqdns.cpp')
-rw-r--r-- | tqtinterface/qt4/src/network/tqdns.cpp | 5294 |
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 ([email protected]) -** -** 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 [email protected]. -** $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 [email protected]. -** -** 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 |