1
//=============================================================================
4
// Creation date : Sat Jul 21 2000 17:19:31 by Szymon Stefanek
6
// This file is part of the KVirc irc client distribution
7
// Copyright (C) 2000-2008 Szymon Stefanek (pragma at kvirc dot net)
9
// This program is FREE software. You can redistribute it and/or
10
// modify it under the terms of the GNU General Public License
11
// as published by the Free Software Foundation; either version 2
12
// of the License, or (at your opinion) any later version.
14
// This program is distributed in the HOPE that it will be USEFUL,
15
// but WITHOUT ANY WARRANTY; without even the implied warranty of
16
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
// See the GNU General Public License for more details.
19
// You should have received a copy of the GNU General Public License
20
// along with this program. If not, write to the Free Software Foundation,
21
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23
//=============================================================================
26
#include "kvi_error.h"
27
#include "kvi_netutils.h"
31
#if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
34
#ifdef COMPILE_IPV6_SUPPORT
43
#include <sys/types.h>
44
#include <sys/socket.h>
48
// this is for FreeBSD
49
#ifndef EAI_ADDRFAMILY
50
#define EAI_ADDRFAMILY EAI_FAMILY
59
KviDnsResult::KviDnsResult()
61
m_iError = KviError_success;
62
m_pHostnameList = new KviPointerList<QString>;
63
m_pHostnameList->setAutoDelete(true);
64
m_pIpAddressList = new KviPointerList<QString>;
65
m_pIpAddressList->setAutoDelete(true);
69
KviDnsResult::~KviDnsResult()
71
delete m_pHostnameList;
72
delete m_pIpAddressList;
75
void KviDnsResult::appendHostname(const QString &host)
77
m_pHostnameList->append(new QString(host));
81
void KviDnsResult::appendAddress(const QString &addr)
83
m_pIpAddressList->append(new QString(addr));
88
KviDnsThread::KviDnsThread(KviDns * pDns)
93
KviDnsThread::~KviDnsThread()
97
int KviDnsThread::translateDnsError(int iErr)
99
#if defined(COMPILE_IPV6_SUPPORT) || (!defined(COMPILE_ON_WINDOWS) && !defined(COMPILE_ON_MINGW))
103
case EAI_FAMILY: return KviError_unsupportedAddressFamily; break;
104
#if (!defined(COMPILE_ON_WINDOWS) && !defined(COMPILE_ON_MINGW)) && defined(EAI_ADDRFAMILY) && (EAI_ADDRFAMILY != EAI_FAMILY)
105
case EAI_ADDRFAMILY: return KviError_unsupportedAddressFamily; break;
107
// NOT FreeBSD ARE WE?
108
#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
110
case EAI_NODATA: return KviError_validNameButNoIpAddress; break;
112
case EAI_FAIL: return KviError_unrecoverableNameserverError; break;
113
case EAI_AGAIN: return KviError_dnsTemporaneousFault; break;
114
// this should never happen
115
case EAI_BADFLAGS: return KviError_dnsInternalErrorBadFlags; break;
116
case EAI_MEMORY: return KviError_dnsInternalErrorOutOfMemory; break;
117
// got this when experimenting with protocols
118
case EAI_SERVICE: return KviError_dnsInternalErrorServiceNotSupported; break;
119
#if !defined(COMPILE_ON_WINDOWS) && !defined(COMPILE_ON_MINGW)
120
case EAI_NONAME: return KviError_dnsNoName; break;
122
// got this when experimenting with protocols
123
case EAI_SOCKTYPE: return KviError_dnsInternalErrorUnsupportedSocketType; break;
124
#if !defined(COMPILE_ON_WINDOWS) && !defined(COMPILE_ON_MINGW)
125
case EAI_SYSTEM: return -errno;
130
return KviError_dnsQueryFailed;
133
void KviDnsThread::postDnsError(KviDnsResult * dns,int iErr)
136
KviThreadDataEvent<KviDnsResult> * e = new KviThreadDataEvent<KviDnsResult>(KVI_DNS_THREAD_EVENT_DATA);
138
postEvent(m_pParentDns,e);
141
void KviDnsThread::run()
143
KviDnsResult * dns = new KviDnsResult();
145
dns->setQuery(m_szQuery);
147
if(m_szQuery.isEmpty())
149
postDnsError(dns,KviError_noHostToResolve);
153
#ifndef COMPILE_IPV6_SUPPORT
154
if(m_queryType != KviDns::IPv4)
156
if(m_queryType == KviDns::IPv6)
158
postDnsError(dns,KviError_noIPv6Support);
161
m_queryType = KviDns::IPv4;
165
#if (defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)) && !defined(COMPILE_IPV6_SUPPORT)
167
if(m_queryType == KviDns::IPv6)
169
postDnsError(dns,KviError_noIPv6Support);
173
// gethostbyaddr and gethostbyname are thread-safe on Windoze
174
struct in_addr inAddr;
175
struct hostent *pHostEntry = 0;
178
// DIE DIE!....I hope that this stuff will disappear sooner or later :)
180
if(KviNetUtils::stringIpToBinaryIp(m_szQuery,&inAddr))
182
pHostEntry = gethostbyaddr((const char *)&inAddr,sizeof(inAddr),AF_INET);
184
pHostEntry = gethostbyname(m_szQuery.toUtf8().data());
191
case HOST_NOT_FOUND: dns->setError(KviError_hostNotFound); break;
192
case NO_ADDRESS: dns->setError(KviError_validNameButNoIpAddress); break;
193
case NO_RECOVERY: dns->setError(KviError_unrecoverableNameserverError); break;
194
case TRY_AGAIN: dns->setError(KviError_dnsTemporaneousFault); break;
195
default: dns->setError(KviError_dnsQueryFailed); break;
198
dns->appendHostname(pHostEntry->h_name);
200
KviNetUtils::binaryIpToStringIp(* ((struct in_addr*)(pHostEntry->h_addr)),szIp);
201
dns->appendAddress(szIp);
204
while(pHostEntry->h_addr_list[idx])
207
KviNetUtils::binaryIpToStringIp(* ((struct in_addr*)(pHostEntry->h_addr_list[idx])),tmp);
208
if(!tmp.isEmpty())dns->appendAddress(tmp);
211
if(pHostEntry->h_aliases[0])
213
dns->appendHostname(QString::fromUtf8(pHostEntry->h_aliases[0]));
214
if(pHostEntry->h_aliases[1])dns->appendHostname(QString::fromUtf8(pHostEntry->h_aliases[1]));
224
//#ifdef HAVE_GETNAMEINFO
225
struct sockaddr_in ipv4Addr;
227
#ifdef COMPILE_IPV6_SUPPORT
228
struct sockaddr_in6 ipv6Addr;
229
bool bIsIPv6Ip = false;
232
bool bIsIPv4Ip = KviNetUtils::stringIpToBinaryIp(m_szQuery,(struct in_addr *)&(ipv4Addr.sin_addr));
234
#ifdef COMPILE_IPV6_SUPPORT
235
if(!bIsIPv4Ip)bIsIPv6Ip = KviNetUtils::stringIpToBinaryIp_V6(m_szQuery,(struct in6_addr *)&(ipv6Addr.sin6_addr));
238
//#ifdef HAVE_GETNAMEINFO
240
#ifdef COMPILE_IPV6_SUPPORT
241
if(bIsIPv4Ip || bIsIPv6Ip)
247
// use getnameinfo...
248
char retname[1025]; // should be enough....
250
#ifdef COMPILE_IPV6_SUPPORT
254
ipv4Addr.sin_family = AF_INET;
255
ipv4Addr.sin_port = 0;
256
// NI_NAMEREQD as last param ?
257
retVal = getnameinfo((struct sockaddr *)&ipv4Addr,sizeof(ipv4Addr),retname,1025,0,0,NI_NAMEREQD);
258
#ifdef COMPILE_IPV6_SUPPORT
260
ipv6Addr.sin6_family = AF_INET6;
261
ipv6Addr.sin6_port = 0;
262
retVal = getnameinfo((struct sockaddr *)&ipv6Addr,sizeof(ipv6Addr),retname,1025,0,0,NI_NAMEREQD);
266
if(retVal != 0)dns->setError(translateDnsError(retVal));
268
dns->appendHostname(retname);
269
dns->appendAddress(m_szQuery);
273
//#endif //HAVE_GETNAMEINFO
276
//#ifdef COMPILE_IPV6_SUPPORT
277
// struct in6_addr in6Addr;
279
struct addrinfo * pRet = 0;
280
struct addrinfo * pNext;
281
struct addrinfo hints;
282
hints.ai_flags = 0; //AI_CANONNAME; <-- for IPV6 it makes cannoname to point to the IP address!
283
#ifdef COMPILE_IPV6_SUPPORT
284
hints.ai_family = (m_queryType == KviDns::IPv6) ? PF_INET6 : ((m_queryType == KviDns::IPv4) ? PF_INET : PF_UNSPEC);
286
hints.ai_family = PF_INET;
288
hints.ai_socktype = SOCK_STREAM;
289
hints.ai_protocol = 0;
290
hints.ai_addrlen = 0;
291
hints.ai_canonname = 0;
295
retVal = getaddrinfo(KviQString::toUtf8(m_szQuery).data(),0,&hints,&pRet);
297
if(retVal != 0)dns->setError(translateDnsError(retVal));
299
dns->appendHostname(pRet->ai_canonname ? QString::fromUtf8(pRet->ai_canonname) : m_szQuery);
301
#ifdef COMPILE_IPV6_SUPPORT
302
if(pRet->ai_family == PF_INET6)KviNetUtils::binaryIpToStringIp_V6(((sockaddr_in6 *)(pRet->ai_addr))->sin6_addr,szIp);
305
KviNetUtils::binaryIpToStringIp(((sockaddr_in *)(pRet->ai_addr))->sin_addr,szIp);
306
#ifdef COMPILE_IPV6_SUPPORT
309
dns->appendAddress(szIp);
311
pNext = pRet->ai_next;
315
#ifdef COMPILE_IPV6_SUPPORT
316
if(pNext->ai_family == PF_INET6)KviNetUtils::binaryIpToStringIp_V6(((sockaddr_in6 *)(pNext->ai_addr))->sin6_addr,tmp);
319
KviNetUtils::binaryIpToStringIp(((sockaddr_in *)(pNext->ai_addr))->sin_addr,tmp);
320
#ifdef COMPILE_IPV6_SUPPORT
323
if(!tmp.isEmpty())dns->appendAddress(tmp);
325
if(pNext->ai_canonname)
327
// FIXME: only of not equal to other names ?
328
dns->appendHostname(QString::fromUtf8(pNext->ai_canonname));
331
pNext = pNext->ai_next;
335
if(pRet)freeaddrinfo(pRet);
336
//#ifdef HAVE_GETNAMEINFO
338
//#endif //HAVE_GETNAMEINFO
340
#endif // !COMPILE_ON_WINDOWS
343
KviThreadDataEvent<KviDnsResult> * e = new KviThreadDataEvent<KviDnsResult>(KVI_DNS_THREAD_EVENT_DATA);
345
postEvent(m_pParentDns,e);
352
m_pSlaveThread = new KviDnsThread(this);
353
m_pDnsResult = new KviDnsResult();
360
if(m_pSlaveThread)delete m_pSlaveThread; // will eventually terminate it (but it will also block us!!!)
361
KviThreadManager::killPendingEvents(this);
362
if(m_pDnsResult)delete m_pDnsResult;
363
if(m_pAuxData)debug("You're leaking memory man! m_pAuxData is non 0!");
366
bool KviDns::isRunning() const
368
return (m_state == Busy);
371
bool KviDns::lookup(const QString &query,QueryType type)
373
if(m_state == Busy)return false;
374
m_pSlaveThread->setQuery(KviQString::trimmed(query),type);
375
bool bStarted = m_pSlaveThread->start();
376
m_state = bStarted ? Busy : Failure;
382
if(!m_pDnsResult)return KviError_dnsQueryFailed;
383
return m_pDnsResult->error();
386
KviDnsResult * KviDns::result()
388
if(!m_pDnsResult)m_pDnsResult = new KviDnsResult();
392
KviPointerList<QString> * KviDns::hostnameList()
394
return result()->hostnameList();
397
KviPointerList<QString> * KviDns::ipAddressList()
399
return result()->ipAddressList();
402
int KviDns::hostnameCount()
404
return result()->hostnameList()->count();
407
int KviDns::ipAddressCount()
409
return result()->ipAddressList()->count();
412
const QString & KviDns::firstHostname()
414
QString * pStr = result()->hostnameList()->first();
415
if(pStr)return *pStr;
416
return KviQString::Empty;
419
const QString & KviDns::firstIpAddress()
421
QString * pStr = result()->ipAddressList()->first();
422
if(pStr)return *pStr;
423
return KviQString::Empty;
426
const QString & KviDns::query()
428
return result()->query();
431
bool KviDns::event(QEvent *e)
433
if(e->type() == KVI_THREAD_EVENT)
435
if(((KviThreadEvent *)e)->id() == KVI_DNS_THREAD_EVENT_DATA)
437
if(m_pDnsResult)delete m_pDnsResult;
438
m_pDnsResult = ((KviThreadDataEvent<KviDnsResult> *)e)->getData();
439
m_state = (m_pDnsResult->error() == KviError_success) ? Success : Failure;
440
emit lookupDone(this);
442
} // else ops... unknown thread event ?
444
return QObject::event(e);