⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 q3dns.cpp

📁 qt-x11-opensource-src-4.1.4.tar.gz源码
💻 CPP
📖 第 1 页 / 共 5 页
字号:
    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(Q3DNS_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(Q3DNS_DEBUG)	qDebug( "DNS Manager: received a query" );#endif	return;    }    Q3DnsQuery * q = queries[i];    Q3DnsAnswer answer( a, q );    answer.parse();    if ( answer.ok ) {	queries.take( i );	answer.notify();	delete q;    }}void Q3DnsManager::transmitQuery( Q3DnsQuery * 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 Q3DnsManager::transmitQuery( int i ){    if ( i < 0 || i >= (int)queries.size() )	return;    Q3DnsQuery * 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...	Q3DnsAnswer answer( q );	answer.notify();	// and then get rid of the query	queries.take( i );#if defined(Q3DNS_DEBUG)	qDebug( "DNS Manager: giving up on query 0x%04x", q->id );#endif	delete q;	QTimer::singleShot( 0, Q3DnsManager::manager(), 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;    QByteArray 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( '.', lp );	if ( le < 0 )	    le = q->l.length();	QString 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 Q3Dns::A:	p[pp++] = 1;	break;    case Q3Dns::Aaaa:	p[pp++] = 28;	break;    case Q3Dns::Mx:	p[pp++] = 15;	break;    case Q3Dns::Srv:	p[pp++] = 33;	break;    case Q3Dns::Cname:	p[pp++] = 5;	break;    case Q3Dns::Ptr:	p[pp++] = 12;	break;    case Q3Dns::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() )        Q3Dns::doResInit();    if ( !ns || ns->isEmpty() ) {	// we don't find any name servers. We fake an NXDomain	// with a very short life time...	Q3DnsAnswer answer( q );	answer.notify();	// and then get rid of the query	queries.take( i );#if defined(Q3DNS_DEBUG)	qDebug( "DNS Manager: no DNS server found on query 0x%04x", q->id );#endif	delete q;	QTimer::singleShot( 1000*10, Q3DnsManager::manager(), SLOT(cleanCache()) );	// and don't process anything more	return;    }    QHostAddress receiver = *ns->at( q->step % ns->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(Q3DNS_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;	QHostAddress * server;	while( (server=ns->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(Q3DNS_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 );}Q3DnsDomain * Q3DnsManager::domain( const QString & label ){    Q3DnsDomain * d = cache.find( label );    if ( !d ) {	d = new Q3DnsDomain( label );	cache.insert( label, d );    }    return d;}////// the Q3DnsDomain class looks after and coordinates queries for Q3DnsRRs for// each domain, and the cached Q3DnsRRs.  (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 Q3DnsManager::domain().  noone else.Q3DnsDomain::Q3DnsDomain( const QString & label ){    l = label;    rrs = 0;}Q3DnsDomain::~Q3DnsDomain(){    delete rrs;    rrs = 0;}void Q3DnsDomain::add( const QString & label, Q3DnsRR * rr ){    Q3DnsDomain * d = Q3DnsManager::manager()->domain( label );    if ( !d->rrs ) {	d->rrs = new Q3PtrList<Q3DnsRR>;	d->rrs->setAutoDelete( true );    }    d->rrs->append( rr );    rr->domain = d;}Q3PtrList<Q3DnsRR> * Q3DnsDomain::cached( const Q3Dns * r ){    Q3PtrList<Q3DnsRR> * l = new Q3PtrList<Q3DnsRR>;    // test at first if you have to start a query at all    if ( r->recordType() == Q3Dns::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.	    Q3DnsRR *rrTmp = new Q3DnsRR( r->label() );	    rrTmp->t = Q3Dns::A;	    rrTmp->address = QHostAddress( 0x7f000001 );	    rrTmp->current = true;	    l->append( rrTmp );	    return l;	}	QHostAddress tmp;	if ( tmp.setAddress( r->label() ) ) {	    Q3DnsRR *rrTmp = new Q3DnsRR( r->label() );	    if ( tmp.isIPv4Address() ) {		rrTmp->t = Q3Dns::A;                rrTmp->address = tmp;                rrTmp->current = true;                l->append( rrTmp );            } else {                rrTmp->nxdomain = true;            }	    return l;	}    }    if ( r->recordType() == Q3Dns::Aaaa ) {	QHostAddress tmp;	if ( tmp.setAddress(r->label()) ) {	    Q3DnsRR *rrTmp = new Q3DnsRR( r->label() );	    if ( tmp.isIPv6Address() ) {		rrTmp->t = Q3Dns::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    Q3DnsManager * m = Q3DnsManager::manager();    QStringList n = r->qualifiedNames();    bool nxdomain;    int cnamecount = 0;    int it = 0;    while( it < n.count() ) {	QString s = n.at(it++);	nxdomain = false;#if defined(Q3DNS_DEBUG)	qDebug( "looking at cache for %s (%s %d)",		s.ascii(), r->label().ascii(), r->recordType() );#endif	Q3DnsDomain * d = m->domain( s );#if defined(Q3DNS_DEBUG)	qDebug( " - found %d RRs", d && d->rrs ? d->rrs->count() : 0 );#endif	if ( d->rrs )	    d->rrs->first();	Q3DnsRR * rr;	bool answer = false;	while( d->rrs && (rr=d->rrs->current()) != 0 ) {	    if ( rr->t == Q3Dns::Cname && r->recordType() != Q3Dns::Cname &&		 !rr->nxdomain && cnamecount < 16 ) {		// cname.  if the code is ugly, that may just		// possibly be because the concept is.#if defined(Q3DNS_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.			Q3DnsQuery * query = new Q3DnsQuery;			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();			QObject::connect( query, SIGNAL(timeout()),					  Q3DnsManager::manager(),					  SLOT(retransmit()) );			Q3DnsManager::manager()->transmitQuery( query );		    }		}		d->rrs->next();	    }	}	// if we found a positive result, return quickly	if ( answer && l->count() ) {#if defined(Q3DNS_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(Q3DNS_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 ||					     int(l->count()) >= n.count()-1 ) ) {		Q3DnsQuery * query = new Q3DnsQuery;		query->started = now();		query->id = ++::id;		query->t = r->recordType();		query->l = s;		query->dns->replace( (void*)r, (void*)r );		QObject::connect( query, SIGNAL(timeout()),				  Q3DnsManager::manager(), SLOT(retransmit()) );		Q3DnsManager::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 Q3DnsDomain::sweep( Q_UINT32 thisSweep ){    if ( !rrs )	return;    Q3DnsRR * rr;    rrs->first();    while( (rr=rrs->current()) != 0 ) {	if ( !rr->deleteTime )	    rr->deleteTime = thisSweep; // will hit next time around#if defined(Q3DNS_DEBUG)	qDebug( "Q3Dns::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 == Q3Dns::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.Q3DnsSocket::Q3DnsSocket( QObject * parent, const char * name )    : QObject( parent, name ){    // nothing}Q3DnsSocket::~Q3DnsSocket(){    // nothing}void Q3DnsSocket::cleanCache(){    // nothing}void Q3DnsSocket::retransmit(){    // nothing}void Q3DnsSocket::answer(){    // nothing}/*!    \class Q3Dns q3dns.h    \brief The Q3Dns 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.    Q3Dns 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); Q3Socket provides much easier to use    TCP connection facilities. The aim of Q3Dns 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 Q3Dns 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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -