📄 q3dns.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.**** This file is part of the Qt3Support module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.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 GNU** General Public Licensing requirements will be met:** http://trolltech.com/products/qt/licenses/licensing/opensource/**** If you are unsure which license is appropriate for your use, please** review the following information:** http://trolltech.com/products/qt/licenses/licensing/licensingoverview** or contact the sales department at sales@trolltech.com.**** In addition, as a special exception, Trolltech gives you certain** additional rights. These rights are described in the Trolltech GPL** Exception version 1.0, which can be found at** http://www.trolltech.com/products/qt/gplexception/ and in the file** GPL_EXCEPTION.txt in this package.**** In addition, as a special exception, Trolltech, as the sole copyright** holder for Qt Designer, grants users of the Qt/Eclipse Integration** plug-in the right for the Qt/Eclipse Integration to link to** functionality provided by Qt Designer and its related libraries.**** Trolltech reserves all rights not expressly granted herein.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include "qplatformdefs.h"#include "qbytearray.h"#ifdef Q_OS_WIN32# 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 "q3dns.h"#ifndef QT_NO_DNS#include "qdatetime.h"#include "q3dict.h"#include "q3ptrlist.h"#include "qstring.h"#include "qtimer.h"#include "qapplication.h"#include "q3ptrvector.h"#include "q3strlist.h"#include "q3ptrdict.h"#include "qfile.h"#include "qtextstream.h"#include "q3socketdevice.h"#include "q3cleanuphandler.h"#include <limits.h>//#define Q3DNS_DEBUGstatic Q_UINT16 id; // ### seeded started by now()static QDateTime * originOfTime = 0;static Q3CleanupHandler<QDateTime> q3dns_cleanup_time;static Q_UINT32 now(){ if ( originOfTime ) return originOfTime->secsTo( QDateTime::currentDateTime() ); originOfTime = new QDateTime( QDateTime::currentDateTime() ); ::id = originOfTime->time().msec() * 60 + originOfTime->time().second(); q3dns_cleanup_time.add( &originOfTime ); return 0;}static Q3PtrList<QHostAddress> * ns = 0;static Q3StrList * domains = 0;static bool ipv6support = false;class Q3DnsPrivate {public: Q3DnsPrivate() : 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 } ~Q3DnsPrivate() { delete queryTimer; }private: QTimer * queryTimer; bool noNames;#if defined(Q_DNS_SYNCHRONOUS) bool noEventLoop;#endif friend class Q3Dns; friend class Q3DnsAnswer;};class Q3DnsRR;class Q3DnsDomain;// Q3DnsRR is the class used to store a single RR. Q3DnsRR can store// all of the supported RR types. a Q3DnsRR is always cached.// Q3DnsRR is mostly constructed from the outside. a but hacky, but// permissible since the entire class is internal.class Q3DnsRR {public: Q3DnsRR( const QString & label ); ~Q3DnsRR();public: Q3DnsDomain * domain; Q3Dns::RecordType t; bool nxdomain; bool current; Q_UINT32 expireTime; Q_UINT32 deleteTime; // somewhat space-wasting per-type data // a / aaaa QHostAddress address; // cname / mx / srv / ptr QString target; // mx / srv Q_UINT16 priority; // srv Q_UINT16 weight; Q_UINT16 port; // txt QString text; // could be overloaded into target...private:};class Q3DnsDomain {public: Q3DnsDomain( const QString & label ); ~Q3DnsDomain(); static void add( const QString & label, Q3DnsRR * ); static Q3PtrList<Q3DnsRR> * cached( const Q3Dns * ); void take( Q3DnsRR * ); void sweep( Q_UINT32 thisSweep ); bool isEmpty() const { return rrs == 0 || rrs->isEmpty(); } QString name() const { return l; }public: QString l; Q3PtrList<Q3DnsRR> * rrs;};class Q3DnsQuery: public QTimer { // this inheritance is a very evil hackpublic: Q3DnsQuery(): id( 0 ), t( Q3Dns::None ), step(0), started(0), dns( new Q3PtrDict<void>(17) ) {} ~Q3DnsQuery() { delete dns; } Q_UINT16 id; Q3Dns::RecordType t; QString l; uint step; Q_UINT32 started; Q3PtrDict<void> * dns;};class Q3DnsAnswer {public: Q3DnsAnswer( Q3DnsQuery * ); Q3DnsAnswer( const QByteArray &, Q3DnsQuery * ); ~Q3DnsAnswer(); void parse(); void notify(); bool ok;private: Q3DnsQuery * query; Q_UINT8 * answer; int size; int pp; Q3PtrList<Q3DnsRR> * rrs; // convenience int next; int ttl; QString label; Q3DnsRR * rr; QString readString(bool multipleLabels = true); void parseA(); void parseAaaa(); void parseMx(); void parseSrv(); void parseCname(); void parsePtr(); void parseTxt(); void parseNs();};Q3DnsRR::Q3DnsRR( const QString & label ) : domain( 0 ), t( Q3Dns::None ), nxdomain( false ), current( false ), expireTime( 0 ), deleteTime( 0 ), priority( 0 ), weight( 0 ), port( 0 ){ Q3DnsDomain::add( label, this );}// not supposed to be deleted except by Q3DnsDomainQ3DnsRR::~Q3DnsRR(){ // nothing is necessary}// this one just sticks in a NXDomainQ3DnsAnswer::Q3DnsAnswer( Q3DnsQuery * query_ ){ ok = true; answer = 0; size = 0; query = query_; pp = 0; rrs = new Q3PtrList<Q3DnsRR>; rrs->setAutoDelete( false ); next = size; ttl = 0; label.clear(); rr = 0; Q3DnsRR * newrr = new Q3DnsRR( 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 );}Q3DnsAnswer::Q3DnsAnswer( const QByteArray& answer_, Q3DnsQuery * query_ ){ ok = true; answer = (Q_UINT8 *)(answer_.data()); size = (int)answer_.size(); query = query_; pp = 0; rrs = new Q3PtrList<Q3DnsRR>; rrs->setAutoDelete( false ); next = size; ttl = 0; label.clear(); rr = 0;}Q3DnsAnswer::~Q3DnsAnswer(){ if ( !ok && rrs ) { Q3PtrListIterator<Q3DnsRR> it( *rrs ); Q3DnsRR * tmprr; while( (tmprr=it.current()) != 0 ) { ++it; tmprr->t = Q3Dns::None; // will be deleted soonish } } delete rrs;}QString Q3DnsAnswer::readString(bool multipleLabels){ int p = pp; QString 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() ? QLatin1String( "." ) : 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 QString();}void Q3DnsAnswer::parseA(){ if ( next != pp + 4 ) {#if defined(Q3DNS_DEBUG) qDebug( "Q3Dns: saw %d bytes long IN A for %s", next - pp, label.ascii() );#endif return; } rr = new Q3DnsRR( label ); rr->t = Q3Dns::A; rr->address = QHostAddress( ( answer[pp+0] << 24 ) + ( answer[pp+1] << 16 ) + ( answer[pp+2] << 8 ) + ( answer[pp+3] ) );#if defined(Q3DNS_DEBUG) qDebug( "Q3Dns: saw %s IN A %s (ttl %d)", label.ascii(), rr->address.toString().ascii(), ttl );#endif}void Q3DnsAnswer::parseAaaa(){ if ( next != pp + 16 ) {#if defined(Q3DNS_DEBUG) qDebug( "Q3Dns: saw %d bytes long IN Aaaa for %s", next - pp, label.ascii() );#endif return; } rr = new Q3DnsRR( label ); rr->t = Q3Dns::Aaaa; rr->address = QHostAddress( answer+pp );#if defined(Q3DNS_DEBUG) qDebug( "Q3Dns: saw %s IN Aaaa %s (ttl %d)", label.ascii(), rr->address.toString().ascii(), ttl );#endif}void Q3DnsAnswer::parseMx(){ if ( next < pp + 2 ) {#if defined(Q3DNS_DEBUG) qDebug( "Q3Dns: saw %d bytes long IN MX for %s", next - pp, label.ascii() );#endif return; } rr = new Q3DnsRR( label ); rr->priority = (answer[pp] << 8) + answer[pp+1]; pp += 2; rr->target = readString().lower(); if ( !ok ) {#if defined(Q3DNS_DEBUG) qDebug( "Q3Dns: saw bad string in MX for %s", label.ascii() );#endif return; } rr->t = Q3Dns::Mx;#if defined(Q3DNS_DEBUG) qDebug( "Q3Dns: saw %s IN MX %d %s (ttl %d)", label.ascii(), rr->priority, rr->target.ascii(), ttl );#endif}void Q3DnsAnswer::parseSrv(){ if ( next < pp + 6 ) {#if defined(Q3DNS_DEBUG) qDebug( "Q3Dns: saw %d bytes long IN SRV for %s", next - pp, label.ascii() );#endif return; } rr = new Q3DnsRR( 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(Q3DNS_DEBUG) qDebug( "Q3Dns: saw bad string in SRV for %s", label.ascii() );#endif return; } rr->t = Q3Dns::Srv;#if defined(Q3DNS_DEBUG) qDebug( "Q3Dns: saw %s IN SRV %d %d %d %s (ttl %d)", label.ascii(), rr->priority, rr->weight, rr->port, rr->target.ascii(), ttl );#endif}void Q3DnsAnswer::parseCname(){ QString target = readString().lower(); if ( !ok ) {#if defined(Q3DNS_DEBUG) qDebug( "Q3Dns: saw bad cname for for %s", label.ascii() );#endif return; } rr = new Q3DnsRR( label ); rr->t = Q3Dns::Cname; rr->target = target;#if defined(Q3DNS_DEBUG) qDebug( "Q3Dns: saw %s IN CNAME %s (ttl %d)", label.ascii(), rr->target.ascii(), ttl );#endif}void Q3DnsAnswer::parseNs(){ QString target = readString().lower(); if ( !ok ) {#if defined(Q3DNS_DEBUG) qDebug( "Q3Dns: saw bad cname for for %s", label.ascii() );#endif return; } // parse, but ignore
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -