diff options
| author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-24 02:13:59 +0000 | 
|---|---|---|
| committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-24 02:13:59 +0000 | 
| commit | a6d58bb6052ac8cb01805a48c4ad2f129126116f (patch) | |
| tree | dd867a099fcbb263a8009a9fb22695b87855dad6 /src/kvilib/net/kvi_dns.cpp | |
| download | kvirc-a6d58bb6052ac8cb01805a48c4ad2f129126116f.tar.gz kvirc-a6d58bb6052ac8cb01805a48c4ad2f129126116f.zip | |
Added KDE3 version of kvirc
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/kvirc@1095341 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/kvilib/net/kvi_dns.cpp')
| -rw-r--r-- | src/kvilib/net/kvi_dns.cpp | 450 | 
1 files changed, 450 insertions, 0 deletions
| diff --git a/src/kvilib/net/kvi_dns.cpp b/src/kvilib/net/kvi_dns.cpp new file mode 100644 index 0000000..faa2e12 --- /dev/null +++ b/src/kvilib/net/kvi_dns.cpp @@ -0,0 +1,450 @@ +//============================================================================= +// +//   File : kvi_dns.cpp +//   Creation date : Sat Jul 21 2000 17:19:31 by Szymon Stefanek +// +//   This file is part of the KVirc irc client distribution +//   Copyright (C) 2000-2007 Szymon Stefanek (pragma at kvirc dot net) +// +//   This program is FREE software. You can redistribute it and/or +//   modify it under the terms of the GNU General Public License +//   as published by the Free Software Foundation; either version 2 +//   of the License, or (at your opinion) any later version. +// +//   This program is distributed in the HOPE that it will be USEFUL, +//   but WITHOUT ANY WARRANTY; without even the implied warranty of +//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +//   See the GNU General Public License for more details. +// +//   You should have received a copy of the GNU General Public License +//   along with this program. If not, write to the Free Software Foundation, +//   Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= +#define __KVILIB__ + +#include "kvi_dns.h" +#include "kvi_error.h" +#include "kvi_netutils.h" + +#include <errno.h> + +#ifdef COMPILE_ON_WINDOWS +	#include <winsock2.h> + +	#ifdef COMPILE_IPV6_SUPPORT +		#ifdef WIN2K +			#include <ws2ip6.h> +		#else +			#include <ws2tcpip.h> +			//#include <tpipv6.h> +		#endif +	#endif +#else +	#include <sys/types.h> +	#include <sys/socket.h> +	#include <netdb.h> +#endif + +// this is for FreeBSD +#ifndef EAI_ADDRFAMILY +	#define EAI_ADDRFAMILY EAI_FAMILY +#endif + +#ifndef EAI_NODATA +	#define EAI_NODATA 0 +#endif + + + +KviDnsResult::KviDnsResult() +{ +	m_iError = KviError_success; +	m_pHostnameList = new KviPointerList<QString>; +	m_pHostnameList->setAutoDelete(true); +	m_pIpAddressList = new KviPointerList<QString>; +	m_pIpAddressList->setAutoDelete(true); + +} + +KviDnsResult::~KviDnsResult() +{ +	delete m_pHostnameList; +	delete m_pIpAddressList; +} + +void KviDnsResult::appendHostname(const QString &host) +{ +	m_pHostnameList->append(new QString(host)); +} + + +void KviDnsResult::appendAddress(const QString &addr) +{ +	m_pIpAddressList->append(new QString(addr)); +} + + + +KviDnsThread::KviDnsThread(KviDns * pDns) +{ +	m_pParentDns = pDns; +} + +KviDnsThread::~KviDnsThread() +{ +} + +int KviDnsThread::translateDnsError(int iErr) +{ +#if defined(COMPILE_IPV6_SUPPORT) || !defined(COMPILE_ON_WINDOWS) + +	switch(iErr) +	{ +		case EAI_FAMILY:     return KviError_unsupportedAddressFamily; break;  +#if !defined(COMPILE_ON_WINDOWS) && defined(EAI_ADDRFAMILY) && (EAI_ADDRFAMILY != EAI_FAMILY) +		case EAI_ADDRFAMILY: return KviError_unsupportedAddressFamily; break; +#endif +// NOT FreeBSD ARE WE? +#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) +// YARR +		case EAI_NODATA:     return KviError_validNameButNoIpAddress; break; +#endif +		case EAI_FAIL:       return KviError_unrecoverableNameserverError; break; +		case EAI_AGAIN:      return KviError_dnsTemporaneousFault; break; +		// this should never happen +		case EAI_BADFLAGS:   return KviError_dnsInternalErrorBadFlags; break; +		case EAI_MEMORY:     return KviError_dnsInternalErrorOutOfMemory; break; +		// got this when experimenting with protocols +		case EAI_SERVICE:    return KviError_dnsInternalErrorServiceNotSupported; break; +#ifndef COMPILE_ON_WINDOWS +		case EAI_NONAME:     return KviError_dnsNoName; break; +#endif +		// got this when experimenting with protocols +		case EAI_SOCKTYPE:   return KviError_dnsInternalErrorUnsupportedSocketType; break; +#ifndef COMPILE_ON_WINDOWS +		case EAI_SYSTEM:     return -errno; +#endif +	} + +#endif +	return KviError_dnsQueryFailed; +} + +void KviDnsThread::postDnsError(KviDnsResult * dns,int iErr) +{ +	dns->setError(iErr); +	KviThreadDataEvent<KviDnsResult> * e = new KviThreadDataEvent<KviDnsResult>(KVI_DNS_THREAD_EVENT_DATA); +	e->setData(dns); +	postEvent(m_pParentDns,e); +} + +void KviDnsThread::run() +{ +	KviDnsResult * dns = new KviDnsResult(); + +	dns->setQuery(m_szQuery); + +	if(m_szQuery.isEmpty()) +	{ +		postDnsError(dns,KviError_noHostToResolve); +		return; +	} + +#ifndef COMPILE_IPV6_SUPPORT +	if(m_queryType != KviDns::IpV4) +	{ +		if(m_queryType == KviDns::IpV6) +		{ +			postDnsError(dns,KviError_noIpV6Support); +			return; +		} +		m_queryType = KviDns::IpV4; +	} +#endif + +#if defined(COMPILE_ON_WINDOWS) && !defined(COMPILE_IPV6_SUPPORT) + +	if(m_queryType == KviDns::IpV6) +	{ +		postDnsError(dns,KviError_noIpV6Support); +		return; +	} + +	// gethostbyaddr and gethostbyname are thread-safe on Windoze +	struct in_addr inAddr; +	struct hostent *pHostEntry = 0; + + +	// DIE DIE!....I hope that this stuff will disappear sooner or later :) + +	if(KviNetUtils::stringIpToBinaryIp(m_szQuery,&inAddr)) +	{ +		pHostEntry = gethostbyaddr((const char *)&inAddr,sizeof(inAddr),AF_INET); +	} else { +		pHostEntry = gethostbyname(m_szQuery); +	} + +	if(!pHostEntry) +	{ +		switch(h_errno) +		{ +			case HOST_NOT_FOUND: dns->setError(KviError_hostNotFound); break; +			case NO_ADDRESS:     dns->setError(KviError_validNameButNoIpAddress); break; +			case NO_RECOVERY:    dns->setError(KviError_unrecoverableNameserverError); break; +			case TRY_AGAIN:      dns->setError(KviError_dnsTemporaneousFault); break; +			default:             dns->setError(KviError_dnsQueryFailed); break; +		} +	} else { +		dns->appendHostname(pHostEntry->h_name); +		QString szIp; +		KviNetUtils::binaryIpToStringIp(* ((struct in_addr*)(pHostEntry->h_addr)),szIp); +		dns->appendAddress(szIp); + +		int idx = 1; +		while(pHostEntry->h_addr_list[idx]) +		{ +			QString tmp; +			KviNetUtils::binaryIpToStringIp(* ((struct in_addr*)(pHostEntry->h_addr_list[idx])),tmp); +			if(tmp.hasData())dns->appendAddress(tmp); +			++idx; +		} +		if(pHostEntry->h_aliases[0]) +		{ +			dns->appendHostname(QString::fromUtf8(pHostEntry->h_aliases[0])); +			if(pHostEntry->h_aliases[1])dns->appendHostname(QString::fromUtf8(pHostEntry->h_aliases[1])); +		} +	} + + +#else //!COMPILE_ON_WINDOWS || COMPILE_IPV6_SUPPORT + +	int retVal; + + +//#ifdef HAVE_GETNAMEINFO +	struct sockaddr_in ipv4Addr; + +#ifdef COMPILE_IPV6_SUPPORT +	struct sockaddr_in6 ipv6Addr; +	bool bIsIpV6Ip = false; +#endif + +	bool bIsIpV4Ip = KviNetUtils::stringIpToBinaryIp(m_szQuery,(struct in_addr *)&(ipv4Addr.sin_addr)); + +#ifdef COMPILE_IPV6_SUPPORT +	if(!bIsIpV4Ip)bIsIpV6Ip = KviNetUtils::stringIpToBinaryIp_V6(m_szQuery,(struct in6_addr *)&(ipv6Addr.sin6_addr)); +#endif + +//#ifdef HAVE_GETNAMEINFO + +#ifdef COMPILE_IPV6_SUPPORT +	if(bIsIpV4Ip || bIsIpV6Ip) +	{ +#else +	if(bIsIpV4Ip) +	{ +#endif +		// use getnameinfo... +		char retname[1025]; // should be enough.... + +#ifdef COMPILE_IPV6_SUPPORT +		if(bIsIpV4Ip) +		{ +#endif +			ipv4Addr.sin_family = AF_INET; +			ipv4Addr.sin_port = 0; +			// NI_NAMEREQD as last param ? +			retVal = getnameinfo((struct sockaddr *)&ipv4Addr,sizeof(ipv4Addr),retname,1025,0,0,NI_NAMEREQD); +#ifdef COMPILE_IPV6_SUPPORT +		} else { +			ipv6Addr.sin6_family = AF_INET6; +			ipv6Addr.sin6_port = 0; +			retVal = getnameinfo((struct sockaddr *)&ipv6Addr,sizeof(ipv6Addr),retname,1025,0,0,NI_NAMEREQD); +		} +#endif + +		if(retVal != 0)dns->setError(translateDnsError(retVal)); +		else { +			dns->appendHostname(retname); +			dns->appendAddress(m_szQuery); +		} +			 +	} else { +//#endif //HAVE_GETNAMEINFO + + +//#ifdef COMPILE_IPV6_SUPPORT +//		struct in6_addr in6Addr; +//#endif +		struct addrinfo * pRet = 0; +		struct addrinfo * pNext; +		struct addrinfo hints; +		hints.ai_flags     = 0; //AI_CANONNAME; <-- for IPV6 it makes cannoname to point to the IP address! +#ifdef COMPILE_IPV6_SUPPORT +		hints.ai_family    = (m_queryType == KviDns::IpV6) ? PF_INET6 : ((m_queryType == KviDns::IpV4) ? PF_INET : PF_UNSPEC); +#else +		hints.ai_family    = PF_INET; +#endif +		hints.ai_socktype  = SOCK_STREAM; +		hints.ai_protocol  = 0; +		hints.ai_addrlen   = 0; +		hints.ai_canonname = 0; +		hints.ai_addr      = 0; +		hints.ai_next      = 0; + +		retVal = getaddrinfo(KviQString::toUtf8(m_szQuery).data(),0,&hints,&pRet); + +		if(retVal != 0)dns->setError(translateDnsError(retVal)); +		else { +			dns->appendHostname(pRet->ai_canonname ? QString::fromUtf8(pRet->ai_canonname) : m_szQuery); +			QString szIp; +#ifdef COMPILE_IPV6_SUPPORT +			if(pRet->ai_family == PF_INET6)KviNetUtils::binaryIpToStringIp_V6(((sockaddr_in6 *)(pRet->ai_addr))->sin6_addr,szIp); +			else { +#endif +				KviNetUtils::binaryIpToStringIp(((sockaddr_in *)(pRet->ai_addr))->sin_addr,szIp); +#ifdef COMPILE_IPV6_SUPPORT +			} +#endif +			dns->appendAddress(szIp); + +			pNext = pRet->ai_next; +			while(pNext) +			{ +				QString tmp; +#ifdef COMPILE_IPV6_SUPPORT +				if(pNext->ai_family == PF_INET6)KviNetUtils::binaryIpToStringIp_V6(((sockaddr_in6 *)(pNext->ai_addr))->sin6_addr,tmp); +				else { +#endif +					KviNetUtils::binaryIpToStringIp(((sockaddr_in *)(pNext->ai_addr))->sin_addr,tmp); +#ifdef COMPILE_IPV6_SUPPORT +				} +#endif +				if(!tmp.isEmpty())dns->appendAddress(tmp); + +				if(pNext->ai_canonname) +				{ +					// FIXME: only of not equal to other names ? +					dns->appendHostname(QString::fromUtf8(pNext->ai_canonname)); +				} + +				pNext = pNext->ai_next; + +			} +		} +		if(pRet)freeaddrinfo(pRet); +//#ifdef HAVE_GETNAMEINFO +	} +//#endif //HAVE_GETNAMEINFO + +#endif // !COMPILE_ON_WINDOWS + + +	KviThreadDataEvent<KviDnsResult> * e = new KviThreadDataEvent<KviDnsResult>(KVI_DNS_THREAD_EVENT_DATA); +	e->setData(dns); +	postEvent(m_pParentDns,e); +} + + + + +KviDns::KviDns() +: QObject() +{ +	m_pSlaveThread = new KviDnsThread(this); +	m_pDnsResult = new KviDnsResult(); +	m_pAuxData = 0; +	m_state = Idle; +} + +KviDns::~KviDns() +{ +	if(m_pSlaveThread)delete m_pSlaveThread; // will eventually terminate it (but it will also block us!!!) +	KviThreadManager::killPendingEvents(this); +	if(m_pDnsResult)delete m_pDnsResult; +	if(m_pAuxData)debug("You're leaking memory man! m_pAuxData is non 0!"); +} + + +bool KviDns::isRunning() const +{ +	return (m_state == Busy); +}; + +bool KviDns::lookup(const QString &query,QueryType type) +{ +	if(m_state == Busy)return false; +	m_pSlaveThread->setQuery(KviQString::trimmed(query),type); +	bool bStarted = m_pSlaveThread->start(); +	m_state = bStarted ? Busy : Failure; +	return bStarted; +} + +int KviDns::error() +{ +	if(!m_pDnsResult)return KviError_dnsQueryFailed; +	return m_pDnsResult->error(); +} + +KviDnsResult * KviDns::result() +{ +	if(!m_pDnsResult)m_pDnsResult = new KviDnsResult(); +	return m_pDnsResult; +} + +KviPointerList<QString> * KviDns::hostnameList() +{ +	return result()->hostnameList(); +} + +KviPointerList<QString> * KviDns::ipAddressList() +{ +	return result()->ipAddressList(); +} + +int KviDns::hostnameCount() +{ +	return result()->hostnameList()->count(); +} + +int KviDns::ipAddressCount() +{ +	return result()->ipAddressList()->count(); +} + +const QString & KviDns::firstHostname() +{ +	QString * pStr = result()->hostnameList()->first(); +	if(pStr)return *pStr; +	return KviQString::empty; +} + +const QString & KviDns::firstIpAddress() +{ +	QString * pStr = result()->ipAddressList()->first(); +	if(pStr)return *pStr; +	return KviQString::empty; +} + +const QString & KviDns::query() +{ +	return result()->query(); +} + +bool KviDns::event(QEvent *e) +{ +	if(e->type() == KVI_THREAD_EVENT) +	{ +		if(((KviThreadEvent *)e)->id() == KVI_DNS_THREAD_EVENT_DATA) +		{ +			if(m_pDnsResult)delete m_pDnsResult; +			m_pDnsResult = ((KviThreadDataEvent<KviDnsResult> *)e)->getData(); +			m_state = (m_pDnsResult->error() == KviError_success) ? Success : Failure; +			emit lookupDone(this); +			return true; +		} // else ops... unknown thread event ? +	} +	return QObject::event(e); +} + | 
