~ubuntu-branches/ubuntu/trusty/kvirc/trusty

« back to all changes in this revision

Viewing changes to src/kvilib/net/kvi_dns.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Kai Wasserbäch, Kai Wasserbäch, Raúl Sánchez Siles
  • Date: 2011-02-12 10:40:21 UTC
  • mfrom: (14.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20110212104021-5mh4f75jlku20mnt
The combined "Twisted Experiment" and "Nocturnal Raid" release.

[ Kai Wasserbäch ]
* Synced to upstream's SVN revision 5467.
* debian/rules:
  - Added .PHONY line.
  - Resurrect -DMANUAL_REVISION, got lost somewhere and we build SVN
    revisions again.
  - Replace "-DWITH_NO_EMBEDDED_CODE=YES" with "-DWANT_CRYPTOPP=YES".
  - Change the remaining -DWITH/-DWITHOUT to the new -DWANT syntax.
* debian/control:
  - Removed DMUA, I'm a DD now.
  - Changed my e-mail address.
  - Removed unneeded relationships (no upgrades over two releases are
    supported).
  - Fix Suggests for kvirc-dbg.
  - kvirc-data: Make the "Suggests: kvirc" a Recommends, doesn't make much
    sense to install the -data package without the program.
* debian/source/local-options: Added with "unapply-patches".
* debian/kvirc.lintian-overrides: Updated to work for 4.1.1.
* debian/patches/21_make_shared-mime-info_B-D_superfluous.patch: Updated.
* debian/kvirc-data.install: Added .notifyrc.

[ Raúl Sánchez Siles ]
* Stating the right version where kvirc-data break and replace should happen.
* Fixing link to license file.
* Added French and Portuguese man pages.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
//=============================================================================
2
 
//
3
 
//   File : kvi_dns.cpp
4
 
//   Creation date : Sat Jul 21 2000 17:19:31 by Szymon Stefanek
5
 
//
6
 
//   This file is part of the KVirc irc client distribution
7
 
//   Copyright (C) 2000-2008 Szymon Stefanek (pragma at kvirc dot net)
8
 
//
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.
13
 
//
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.
18
 
//
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.
22
 
//
23
 
//=============================================================================
24
 
 
25
 
#include "kvi_dns.h"
26
 
#include "kvi_error.h"
27
 
#include "kvi_netutils.h"
28
 
 
29
 
#include <errno.h>
30
 
 
31
 
#if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
32
 
        #include <winsock2.h>
33
 
 
34
 
        #ifdef COMPILE_IPV6_SUPPORT
35
 
                #ifdef WIN2K
36
 
                        #include <ws2ip6.h>
37
 
                #else
38
 
                        #include <ws2tcpip.h>
39
 
                        //#include <tpipv6.h>
40
 
                #endif
41
 
        #endif
42
 
#else
43
 
        #include <sys/types.h>
44
 
        #include <sys/socket.h>
45
 
        #include <netdb.h>
46
 
#endif
47
 
 
48
 
// this is for FreeBSD
49
 
#ifndef EAI_ADDRFAMILY
50
 
        #define EAI_ADDRFAMILY EAI_FAMILY
51
 
#endif
52
 
 
53
 
#ifndef EAI_NODATA
54
 
        #define EAI_NODATA 0
55
 
#endif
56
 
 
57
 
 
58
 
 
59
 
KviDnsResult::KviDnsResult()
60
 
{
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);
66
 
 
67
 
}
68
 
 
69
 
KviDnsResult::~KviDnsResult()
70
 
{
71
 
        delete m_pHostnameList;
72
 
        delete m_pIpAddressList;
73
 
}
74
 
 
75
 
void KviDnsResult::appendHostname(const QString &host)
76
 
{
77
 
        m_pHostnameList->append(new QString(host));
78
 
}
79
 
 
80
 
 
81
 
void KviDnsResult::appendAddress(const QString &addr)
82
 
{
83
 
        m_pIpAddressList->append(new QString(addr));
84
 
}
85
 
 
86
 
 
87
 
 
88
 
KviDnsThread::KviDnsThread(KviDns * pDns)
89
 
{
90
 
        m_pParentDns = pDns;
91
 
}
92
 
 
93
 
KviDnsThread::~KviDnsThread()
94
 
{
95
 
}
96
 
 
97
 
int KviDnsThread::translateDnsError(int iErr)
98
 
{
99
 
#if defined(COMPILE_IPV6_SUPPORT) || (!defined(COMPILE_ON_WINDOWS) && !defined(COMPILE_ON_MINGW))
100
 
 
101
 
        switch(iErr)
102
 
        {
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;
106
 
#endif
107
 
// NOT FreeBSD ARE WE?
108
 
#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
109
 
// YARR
110
 
                case EAI_NODATA:     return KviError_validNameButNoIpAddress; break;
111
 
#endif
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;
121
 
#endif
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;
126
 
#endif
127
 
        }
128
 
 
129
 
#endif
130
 
        return KviError_dnsQueryFailed;
131
 
}
132
 
 
133
 
void KviDnsThread::postDnsError(KviDnsResult * dns,int iErr)
134
 
{
135
 
        dns->setError(iErr);
136
 
        KviThreadDataEvent<KviDnsResult> * e = new KviThreadDataEvent<KviDnsResult>(KVI_DNS_THREAD_EVENT_DATA);
137
 
        e->setData(dns);
138
 
        postEvent(m_pParentDns,e);
139
 
}
140
 
 
141
 
void KviDnsThread::run()
142
 
{
143
 
        KviDnsResult * dns = new KviDnsResult();
144
 
 
145
 
        dns->setQuery(m_szQuery);
146
 
 
147
 
        if(m_szQuery.isEmpty())
148
 
        {
149
 
                postDnsError(dns,KviError_noHostToResolve);
150
 
                return;
151
 
        }
152
 
 
153
 
#ifndef COMPILE_IPV6_SUPPORT
154
 
        if(m_queryType != KviDns::IPv4)
155
 
        {
156
 
                if(m_queryType == KviDns::IPv6)
157
 
                {
158
 
                        postDnsError(dns,KviError_noIPv6Support);
159
 
                        return;
160
 
                }
161
 
                m_queryType = KviDns::IPv4;
162
 
        }
163
 
#endif
164
 
 
165
 
#if (defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)) && !defined(COMPILE_IPV6_SUPPORT)
166
 
 
167
 
        if(m_queryType == KviDns::IPv6)
168
 
        {
169
 
                postDnsError(dns,KviError_noIPv6Support);
170
 
                return;
171
 
        }
172
 
 
173
 
        // gethostbyaddr and gethostbyname are thread-safe on Windoze
174
 
        struct in_addr inAddr;
175
 
        struct hostent *pHostEntry = 0;
176
 
 
177
 
 
178
 
        // DIE DIE!....I hope that this stuff will disappear sooner or later :)
179
 
 
180
 
        if(KviNetUtils::stringIpToBinaryIp(m_szQuery,&inAddr))
181
 
        {
182
 
                pHostEntry = gethostbyaddr((const char *)&inAddr,sizeof(inAddr),AF_INET);
183
 
        } else {
184
 
                pHostEntry = gethostbyname(m_szQuery.toUtf8().data());
185
 
        }
186
 
 
187
 
        if(!pHostEntry)
188
 
        {
189
 
                switch(h_errno)
190
 
                {
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;
196
 
                }
197
 
        } else {
198
 
                dns->appendHostname(pHostEntry->h_name);
199
 
                QString szIp;
200
 
                KviNetUtils::binaryIpToStringIp(* ((struct in_addr*)(pHostEntry->h_addr)),szIp);
201
 
                dns->appendAddress(szIp);
202
 
 
203
 
                int idx = 1;
204
 
                while(pHostEntry->h_addr_list[idx])
205
 
                {
206
 
                        QString tmp;
207
 
                        KviNetUtils::binaryIpToStringIp(* ((struct in_addr*)(pHostEntry->h_addr_list[idx])),tmp);
208
 
                        if(!tmp.isEmpty())dns->appendAddress(tmp);
209
 
                        ++idx;
210
 
                }
211
 
                if(pHostEntry->h_aliases[0])
212
 
                {
213
 
                        dns->appendHostname(QString::fromUtf8(pHostEntry->h_aliases[0]));
214
 
                        if(pHostEntry->h_aliases[1])dns->appendHostname(QString::fromUtf8(pHostEntry->h_aliases[1]));
215
 
                }
216
 
        }
217
 
 
218
 
 
219
 
#else
220
 
 
221
 
        int retVal;
222
 
 
223
 
 
224
 
//#ifdef HAVE_GETNAMEINFO
225
 
        struct sockaddr_in ipv4Addr;
226
 
 
227
 
#ifdef COMPILE_IPV6_SUPPORT
228
 
        struct sockaddr_in6 ipv6Addr;
229
 
        bool bIsIPv6Ip = false;
230
 
#endif
231
 
 
232
 
        bool bIsIPv4Ip = KviNetUtils::stringIpToBinaryIp(m_szQuery,(struct in_addr *)&(ipv4Addr.sin_addr));
233
 
 
234
 
#ifdef COMPILE_IPV6_SUPPORT
235
 
        if(!bIsIPv4Ip)bIsIPv6Ip = KviNetUtils::stringIpToBinaryIp_V6(m_szQuery,(struct in6_addr *)&(ipv6Addr.sin6_addr));
236
 
#endif
237
 
 
238
 
//#ifdef HAVE_GETNAMEINFO
239
 
 
240
 
#ifdef COMPILE_IPV6_SUPPORT
241
 
        if(bIsIPv4Ip || bIsIPv6Ip)
242
 
        {
243
 
#else
244
 
        if(bIsIPv4Ip)
245
 
        {
246
 
#endif
247
 
                // use getnameinfo...
248
 
                char retname[1025]; // should be enough....
249
 
 
250
 
#ifdef COMPILE_IPV6_SUPPORT
251
 
                if(bIsIPv4Ip)
252
 
                {
253
 
#endif
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
259
 
                } else {
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);
263
 
                }
264
 
#endif
265
 
 
266
 
                if(retVal != 0)dns->setError(translateDnsError(retVal));
267
 
                else {
268
 
                        dns->appendHostname(retname);
269
 
                        dns->appendAddress(m_szQuery);
270
 
                }
271
 
 
272
 
        } else {
273
 
//#endif //HAVE_GETNAMEINFO
274
 
 
275
 
 
276
 
//#ifdef COMPILE_IPV6_SUPPORT
277
 
//              struct in6_addr in6Addr;
278
 
//#endif
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);
285
 
#else
286
 
                hints.ai_family    = PF_INET;
287
 
#endif
288
 
                hints.ai_socktype  = SOCK_STREAM;
289
 
                hints.ai_protocol  = 0;
290
 
                hints.ai_addrlen   = 0;
291
 
                hints.ai_canonname = 0;
292
 
                hints.ai_addr      = 0;
293
 
                hints.ai_next      = 0;
294
 
 
295
 
                retVal = getaddrinfo(KviQString::toUtf8(m_szQuery).data(),0,&hints,&pRet);
296
 
 
297
 
                if(retVal != 0)dns->setError(translateDnsError(retVal));
298
 
                else {
299
 
                        dns->appendHostname(pRet->ai_canonname ? QString::fromUtf8(pRet->ai_canonname) : m_szQuery);
300
 
                        QString szIp;
301
 
#ifdef COMPILE_IPV6_SUPPORT
302
 
                        if(pRet->ai_family == PF_INET6)KviNetUtils::binaryIpToStringIp_V6(((sockaddr_in6 *)(pRet->ai_addr))->sin6_addr,szIp);
303
 
                        else {
304
 
#endif
305
 
                                KviNetUtils::binaryIpToStringIp(((sockaddr_in *)(pRet->ai_addr))->sin_addr,szIp);
306
 
#ifdef COMPILE_IPV6_SUPPORT
307
 
                        }
308
 
#endif
309
 
                        dns->appendAddress(szIp);
310
 
 
311
 
                        pNext = pRet->ai_next;
312
 
                        while(pNext)
313
 
                        {
314
 
                                QString tmp;
315
 
#ifdef COMPILE_IPV6_SUPPORT
316
 
                                if(pNext->ai_family == PF_INET6)KviNetUtils::binaryIpToStringIp_V6(((sockaddr_in6 *)(pNext->ai_addr))->sin6_addr,tmp);
317
 
                                else {
318
 
#endif
319
 
                                        KviNetUtils::binaryIpToStringIp(((sockaddr_in *)(pNext->ai_addr))->sin_addr,tmp);
320
 
#ifdef COMPILE_IPV6_SUPPORT
321
 
                                }
322
 
#endif
323
 
                                if(!tmp.isEmpty())dns->appendAddress(tmp);
324
 
 
325
 
                                if(pNext->ai_canonname)
326
 
                                {
327
 
                                        // FIXME: only of not equal to other names ?
328
 
                                        dns->appendHostname(QString::fromUtf8(pNext->ai_canonname));
329
 
                                }
330
 
 
331
 
                                pNext = pNext->ai_next;
332
 
 
333
 
                        }
334
 
                }
335
 
                if(pRet)freeaddrinfo(pRet);
336
 
//#ifdef HAVE_GETNAMEINFO
337
 
        }
338
 
//#endif //HAVE_GETNAMEINFO
339
 
 
340
 
#endif // !COMPILE_ON_WINDOWS
341
 
 
342
 
 
343
 
        KviThreadDataEvent<KviDnsResult> * e = new KviThreadDataEvent<KviDnsResult>(KVI_DNS_THREAD_EVENT_DATA);
344
 
        e->setData(dns);
345
 
        postEvent(m_pParentDns,e);
346
 
}
347
 
 
348
 
 
349
 
KviDns::KviDns()
350
 
: QObject()
351
 
{
352
 
        m_pSlaveThread = new KviDnsThread(this);
353
 
        m_pDnsResult = new KviDnsResult();
354
 
        m_pAuxData = 0;
355
 
        m_state = Idle;
356
 
}
357
 
 
358
 
KviDns::~KviDns()
359
 
{
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!");
364
 
}
365
 
 
366
 
bool KviDns::isRunning() const
367
 
{
368
 
        return (m_state == Busy);
369
 
}
370
 
 
371
 
bool KviDns::lookup(const QString &query,QueryType type)
372
 
{
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;
377
 
        return bStarted;
378
 
}
379
 
 
380
 
int KviDns::error()
381
 
{
382
 
        if(!m_pDnsResult)return KviError_dnsQueryFailed;
383
 
        return m_pDnsResult->error();
384
 
}
385
 
 
386
 
KviDnsResult * KviDns::result()
387
 
{
388
 
        if(!m_pDnsResult)m_pDnsResult = new KviDnsResult();
389
 
        return m_pDnsResult;
390
 
}
391
 
 
392
 
KviPointerList<QString> * KviDns::hostnameList()
393
 
{
394
 
        return result()->hostnameList();
395
 
}
396
 
 
397
 
KviPointerList<QString> * KviDns::ipAddressList()
398
 
{
399
 
        return result()->ipAddressList();
400
 
}
401
 
 
402
 
int KviDns::hostnameCount()
403
 
{
404
 
        return result()->hostnameList()->count();
405
 
}
406
 
 
407
 
int KviDns::ipAddressCount()
408
 
{
409
 
        return result()->ipAddressList()->count();
410
 
}
411
 
 
412
 
const QString & KviDns::firstHostname()
413
 
{
414
 
        QString * pStr = result()->hostnameList()->first();
415
 
        if(pStr)return *pStr;
416
 
        return KviQString::Empty;
417
 
}
418
 
 
419
 
const QString & KviDns::firstIpAddress()
420
 
{
421
 
        QString * pStr = result()->ipAddressList()->first();
422
 
        if(pStr)return *pStr;
423
 
        return KviQString::Empty;
424
 
}
425
 
 
426
 
const QString & KviDns::query()
427
 
{
428
 
        return result()->query();
429
 
}
430
 
 
431
 
bool KviDns::event(QEvent *e)
432
 
{
433
 
        if(e->type() == KVI_THREAD_EVENT)
434
 
        {
435
 
                if(((KviThreadEvent *)e)->id() == KVI_DNS_THREAD_EVENT_DATA)
436
 
                {
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);
441
 
                        return true;
442
 
                } // else ops... unknown thread event ?
443
 
        }
444
 
        return QObject::event(e);
445
 
}