📄 q3dns.cpp
字号:
/*! \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 list of the fully qualified names label() maps to. \sa Q3Socket*//*! Constructs a DNS query object with invalid settings for both the label and the search type.*/Q3Dns::Q3Dns(){ d = new Q3DnsPrivate; 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.*/Q3Dns::Q3Dns( const QString & label, RecordType rr ){ d = new Q3DnsPrivate; 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.*/Q3Dns::Q3Dns( const QHostAddress & address, RecordType rr ){ d = new Q3DnsPrivate; t = rr; setLabel( address ); setStartQueryTimer(); // start query the next time we enter event loop}/*! Destroys the DNS query object and frees its allocated resources.*/Q3Dns::~Q3Dns(){ if ( globalManager ) { uint q = 0; Q3DnsManager * m = globalManager; while( q < m->queries.size() ) { Q3DnsQuery * 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 Q3Dns::setLabel( const QString & 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( 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)Q3DnsManager::manager(); // create a Q3DnsManager, if it is not already there Q3StrListIterator it( *domains ); const char * dom; while( (dom=it.current()) != 0 ) { ++it; n.append( l.lower() + QLatin1String(".") + QLatin1String(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(Q3DNS_DEBUG) qDebug( "Q3Dns::setLabel: %d address(es) for %s", n.count(), l.ascii() ); int i = 0; for( i = 0; i < (int)n.count(); i++ ) qDebug( "Q3Dns::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 Q3Dns::setLabel( const QHostAddress & address ){ setLabel( toInAddrArpaDomain( address ) );}/*! \fn QStringList Q3Dns::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 QStringList list = myDns.qualifiedNames(); QStringList::Iterator it = list.begin(); while( it != list.end() ) { myProcessing( *it ); ++it; } \endcode*//*! \fn QString Q3Dns::label() const Returns the domain name for which this object returns information. \sa setLabel()*//*! \enum Q3Dns::RecordType This enum type defines the record types Q3Dns 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 Q3Dns 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 Q3Dns::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 Q3Dns::startQuery(){ // isWorking() starts the query (if necessary) if ( !isWorking() ) emit resultsReady();}/*! The three functions Q3Dns::Q3Dns(QString, RecordType), Q3Dns::setLabel() and Q3Dns::setRecordType() may start a DNS lookup. This function handles setting up the single shot timer.*/void Q3Dns::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 QTimer( this ); connect( d->queryTimer, SIGNAL(timeout()), this, 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.*/QString Q3Dns::toInAddrArpaDomain( const QHostAddress &address ){ QString 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 = QLatin1String("ip6.arpa"); uint b = 0; while( b < 16 ) { s = QString::number( i.c[b]%16, 16 ) + QLatin1String(".") + QString::number( i.c[b]/16, 16 ) + QLatin1String(".") + s; b++; } } return s;}/*! \fn Q3Dns::RecordType Q3Dns::recordType() const Returns the record type of this DNS query object. \sa setRecordType() RecordType*//*! \fn void Q3Dns::resultsReady() This signal is emitted when results are available for one of the qualifiedNames().*//*! Returns true if Q3Dns is doing a lookup for this object (i.e. if it does not already have the necessary information); otherwise returns false. Q3Dns emits the resultsReady() signal when the status changes to false.*/bool Q3Dns::isWorking() const{#if defined(Q3DNS_DEBUG) qDebug( "Q3Dns::isWorking (%s, %d)", l.ascii(), t );#endif if ( t == None ) return false;#if defined(Q_DNS_SYNCHRONOUS) if ( d->noEventLoop ) return true;#endif Q3PtrList<Q3DnsRR> * ll = Q3DnsDomain::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 Q3Dns object has a recordType() of Q3Dns::A or Q3Dns::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 Q3ValueList<QHostAddress> list = myDns.addresses(); Q3ValueList<QHostAddress>::Iterator it = list.begin(); while( it != list.end() ) { myProcessing( *it ); ++it; } \endcode*/Q3ValueList<QHostAddress> Q3Dns::addresses() const{#if defined(Q3DNS_DEBUG) qDebug( "Q3Dns::addresses (%s)", l.ascii() );#endif Q3ValueList<QHostAddress> result; if ( t != A && t != Aaaa ) return result; Q3PtrList<Q3DnsRR> * cached = Q3DnsDomain::cached( this ); Q3DnsRR * rr; while( (rr=cached->current()) != 0 ) { if ( rr->current && !rr->nxdomain ) result.append( rr->address ); cached->next(); } delete cached; return result;}/*! \class Q3Dns::MailServer \brief The Q3Dns::MailServer class is described in Q3Dns::mailServers(). \internal*//*! Returns a list of mail servers if the record type is \c Mx. The class Q3Dns::MailServer contains the following public variables: \list \i QString Q3Dns::MailServer::name \i Q_UINT16 Q3Dns::MailServer::priority \endlist Note that if you want to iterate over the list, you should iterate over a copy, e.g. \code Q3ValueList<Q3Dns::MailServer> list = myDns.mailServers(); Q3ValueList<Q3Dns::MailServer>::Iterator it = list.begin(); while( it != list.end() ) { myProcessing( *it ); ++it; } \endcode*/Q3ValueList<Q3Dns::MailServer> Q3Dns::mailServers() const{#if defined(Q3DNS_DEBUG) qDebug( "Q3Dns::mailServers (%s)", l.ascii() );#endif Q3ValueList<Q3Dns::MailServer> result; if ( t != Mx ) return result; Q3PtrList<Q3DnsRR> * cached = Q3DnsDomain::cached( this ); Q3DnsRR * 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 Q3Dns::Server \brief The Q3Dns::Server class is described in Q3Dns::servers(). \internal*//*! Returns a list of servers if the record type is \c Srv. The class Q3Dns::Server contains the following public variables: \list \i QString Q3Dns::Server::name \i Q_UINT16 Q3Dns::Server::priority \i Q_UINT16 Q3Dns::Server::weight \i Q_UINT16 Q3Dns::Server::port \endlist Note that if you want to iterate over the list, you should iterate over a copy, e.g. \code Q3ValueList<Q3Dns::Server> list = myDns.servers(); Q3ValueList<Q3Dns::Server>::Iterator it = list.begin(); while( it != list.end() ) { myProcessing( *it ); ++it; } \endcode*/Q3ValueList<Q3Dns::Server> Q3Dns::servers() const{#if defined(Q3DNS_DEBUG) qDebug( "Q3Dns::servers (%s)", l.ascii() );#endif Q3ValueList<Q3Dns::Server> result; if ( t != Srv ) return result;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -