~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/network/qhostinfo.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
 
4
**
 
5
** This file is part of the network module of the Qt Toolkit.
 
6
**
 
7
** This file may be distributed under the terms of the Q Public License
 
8
** as defined by Trolltech AS of Norway and appearing in the file
 
9
** LICENSE.QPL included in the packaging of this file.
 
10
**
 
11
** This file may be distributed and/or modified under the terms of the
 
12
** GNU General Public License version 2 as published by the Free Software
 
13
** Foundation and appearing in the file LICENSE.GPL included in the
 
14
** packaging of this file.
 
15
**
 
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
 
17
**   information about Qt Commercial License Agreements.
 
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
 
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
 
20
**
 
21
** Contact info@trolltech.com if any conditions of this licensing are
 
22
** not clear to you.
 
23
**
 
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
26
**
 
27
****************************************************************************/
 
28
 
 
29
#include "qhostinfo.h"
 
30
#include "qhostinfo_p.h"
 
31
 
 
32
#include <qabstracteventdispatcher.h>
 
33
#include <private/qunicodetables_p.h>
 
34
#include <qcoreapplication.h>
 
35
#include <qmetaobject.h>
 
36
#include <qregexp.h>
 
37
#include <private/qsocketlayer_p.h>
 
38
#include <qstringlist.h>
 
39
#include <qthread.h>
 
40
#include <qtimer.h>
 
41
#include <qurl.h>
 
42
 
 
43
#ifdef Q_OS_UNIX
 
44
#  include <unistd.h>
 
45
#endif
 
46
 
 
47
Q_GLOBAL_STATIC(QHostInfoAgent, agent)
 
48
   
 
49
//#define QHOSTINFO_DEBUG
 
50
 
 
51
/*!         
 
52
    \class QHostInfo
 
53
    \brief The QHostInfo class provides static functions for host name lookups.
 
54
 
 
55
    \reentrant
 
56
    \module network
 
57
    \ingroup io
 
58
 
 
59
    QHostInfo uses the lookup mechanisms provided by the operating
 
60
    system to find the IP address(es) associated with a host name.
 
61
    The class provides two static convenience functions: one that
 
62
    works asynchronously and emits a signal once the host is found,
 
63
    and one that blocks and returns a QHostInfo object.
 
64
 
 
65
    To look up a host's IP addresses asynchronously, call lookupHost(),
 
66
    which takes the host name, a receiver object, and a slot
 
67
    signature as arguments and returns an ID. You can abort the
 
68
    lookup by calling abortHostLookup() with the lookup ID.
 
69
 
 
70
    Example:
 
71
 
 
72
    \code
 
73
        QHostInfo::lookupHost("www.trolltech.com",
 
74
                              this, SLOT(printResults(QHostInfo)));
 
75
    \endcode
 
76
 
 
77
 
 
78
    The slot is invoked when the results are ready. (If you use
 
79
    Qt/Embedded and disabled multithread support by defining \c
 
80
    QT_NO_THREAD, lookupHost() will block until the lookup has
 
81
    finished.) The results are stored in a QHostInfo object. Call
 
82
    addresses() to get the list of IP addresses for the host, and
 
83
    hostName() to get the host name that was looked up.
 
84
 
 
85
    If the lookup failed, error() returns the type of error that
 
86
    occurred. errorString() gives a human-readable description of the
 
87
    lookup error.
 
88
 
 
89
    If you want a blocking lookup, use the QHostInfo::fromName() function:
 
90
 
 
91
    \code
 
92
        QHostInfo info = QHostInfo::fromName("www.trolltech.com");
 
93
    \endcode
 
94
 
 
95
    QHostInfo supports Internationalized Domain Names (IDNs) through the
 
96
    IDNA and Punycode standards.
 
97
 
 
98
    To retrieve the name of the local host, use the static
 
99
    QHostInfo::localHostName() function.
 
100
 
 
101
    \sa QAbstractSocket, {http://ietf.org/rfc/rfc3492}{RFC 3492}
 
102
*/
 
103
 
 
104
static QBasicAtomic idCounter = Q_ATOMIC_INIT(1);
 
105
static int qt_qhostinfo_newid()
 
106
{
 
107
    register int id;
 
108
    for (;;) {
 
109
        id = idCounter;
 
110
        if (idCounter.testAndSet(id, id + 1))
 
111
            break;
 
112
    }
 
113
    return id;
 
114
}
 
115
 
 
116
/*!
 
117
    Looks up the IP address(es) associated with host name \a name, and
 
118
    returns an ID for the lookup. When the result of the lookup is
 
119
    ready, the slot or signal \a member in \a receiver is called with
 
120
    a QHostInfo argument. The QHostInfo object can then be inspected
 
121
    to get the results of the lookup.
 
122
 
 
123
    The lookup is performed by a single function call, for example:
 
124
 
 
125
    \code
 
126
        QHostInfo::lookupHost("www.kde.org",
 
127
                              this, SLOT(lookedUp(QHostInfo)));
 
128
    \endcode
 
129
 
 
130
    The implementation of the slot prints basic information about the
 
131
    addresses returned by the lookup, or reports an error if it failed:
 
132
 
 
133
    \code
 
134
        void MyWidget::lookedUp(const QHostInfo &host)
 
135
        {
 
136
            if (host.error() != QHostInfo::NoError) {
 
137
                qDebug() << "Lookup failed:" << host.errorString();
 
138
                return;
 
139
            }
 
140
 
 
141
            foreach (QHostAddress address, host.addresses())
 
142
                qDebug() << "Found address:" << address.toString();
 
143
        }
 
144
    \endcode
 
145
 
 
146
    \sa abortHostLookup(), addresses(), error(), fromName()
 
147
*/
 
148
int QHostInfo::lookupHost(const QString &name, QObject *receiver,
 
149
                          const char *member)
 
150
{
 
151
#if defined QHOSTINFO_DEBUG
 
152
    qDebug("QHostInfo::lookupHost(\"%s\", %p, %s)",
 
153
           name.toLatin1().constData(), receiver, member ? member + 1 : 0);
 
154
#endif
 
155
    if (!QAbstractEventDispatcher::instance(QThread::currentThread())) {
 
156
        qWarning("QHostInfo::lookupHost() called with no event dispatcher");
 
157
        return -1;
 
158
    }
 
159
 
 
160
    qRegisterMetaType<QHostInfo>("QHostInfo");
 
161
 
 
162
    // Don't start a thread if we don't have to do any lookup.
 
163
    QHostAddress addr;
 
164
    if (addr.setAddress(name)) {
 
165
        if (!member || !member[0]) {
 
166
            qWarning("QHostInfo::lookupHost() called with invalid slot [%s]", member);
 
167
            return -1;
 
168
        }
 
169
 
 
170
        QByteArray arr(member + 1);
 
171
        if (!arr.contains('(')) {
 
172
            qWarning("QHostInfo::lookupHost() called with invalid slot [%s]", member);
 
173
            return -1;
 
174
        }
 
175
 
 
176
        QHostInfo info(::qt_qhostinfo_newid());
 
177
        info.setAddresses(QList<QHostAddress>() << addr);
 
178
        arr.resize(arr.indexOf('('));
 
179
 
 
180
        // To mimic the same behavior that the lookup would have if it was not
 
181
        // an IP, we need to choose a Qt::QueuedConnection if there is thread support;
 
182
        // otherwise Qt::DirectConnection.
 
183
        if (!QMetaObject::invokeMethod(receiver, arr,
 
184
#if !defined QT_NO_THREAD
 
185
                         Qt::QueuedConnection,
 
186
#else
 
187
                         Qt::DirectConnection,
 
188
#endif
 
189
                         QGenericArgument("QHostInfo", &info))) {
 
190
            qWarning("QHostInfo::lookupHost() called with invalid slot (QMetaObject::invokeMethod failed)");
 
191
        }
 
192
        return info.lookupId();
 
193
    }
 
194
 
 
195
#if defined Q_OS_WIN32
 
196
    QSocketLayer bust; // makes sure WSAStartup was callled
 
197
#endif
 
198
 
 
199
    // Support for IDNA by first splitting the name into labels, then
 
200
    // running the punycode decoder on each part, then merging
 
201
    // together before passing the name to the lookup agent.
 
202
    QString lookup;
 
203
    const unsigned short delimiters[] = {0x2e, 0x3002, 0xff0e, 0xff61, 0};
 
204
    QStringList labels = name.split(QRegExp("[" + QString::fromUtf16(delimiters) + "]"));
 
205
    for (int i = 0; i < labels.count(); ++i) {
 
206
        if (i != 0) lookup += '.';
 
207
        QString label = QUnicodeTables::normalize(labels.at(i), QString::NormalizationForm_KC, QChar::Unicode_3_1);
 
208
        lookup += QString::fromAscii(QUrl::toPunycode(label));
 
209
    }
 
210
 
 
211
    QHostInfoAgent *agent = ::agent();
 
212
 
 
213
    QHostInfoResult *result = new QHostInfoResult;
 
214
    QObject::connect(result, SIGNAL(resultsReady(QHostInfo)),
 
215
                     receiver, member);
 
216
    QObject::connect(result, SIGNAL(resultsReady(QHostInfo)),
 
217
                     result, SLOT(deleteLater()));
 
218
    result->lookupId = ::qt_qhostinfo_newid();
 
219
    agent->addHostName(lookup, result);
 
220
 
 
221
#if !defined QT_NO_THREAD
 
222
    if (!agent->isRunning())
 
223
        agent->start();
 
224
#else
 
225
    if (!agent->isRunning())
 
226
        agent->run();
 
227
    else
 
228
        agent->wakeOne();
 
229
#endif
 
230
    return result->lookupId;
 
231
}
 
232
 
 
233
/*!
 
234
    Aborts the host lookup with the ID \a id, as returned by lookupHost().
 
235
 
 
236
    \sa lookupHost(), lookupId()
 
237
*/
 
238
void QHostInfo::abortHostLookup(int id)
 
239
{
 
240
    QHostInfoAgent *agent = ::agent();
 
241
    agent->abortLookup(id);
 
242
}
 
243
 
 
244
/*!
 
245
    Looks up the IP address(es) for the given host \a name. The
 
246
    function blocks during the lookup which means that execution of
 
247
    the program is suspended until the results of the lookup are
 
248
    ready. Returns the result of the lookup in a QHostInfo object.
 
249
 
 
250
    \sa lookupHost()
 
251
*/
 
252
QHostInfo QHostInfo::fromName(const QString &name)
 
253
{
 
254
#if defined QHOSTINFO_DEBUG
 
255
    qDebug("QHostInfo::fromName(\"%s\")",name.toLatin1().constData());
 
256
#endif
 
257
 
 
258
    // If the address string is an IP address, don't do a lookup.
 
259
    QHostAddress addr;
 
260
    if (addr.setAddress(name)) {
 
261
        QHostInfo info;
 
262
        info.setAddresses(QList<QHostAddress>() << addr);
 
263
        return info;
 
264
    }
 
265
 
 
266
    // Support for IDNA by first splitting the name into labels, then
 
267
    // running the punycode decoder on each part, then merging
 
268
    // together before passing the name to the lookup agent.
 
269
    QString lookup;
 
270
    const unsigned short delimiters[] = {0x2e, 0x3002, 0xff0e, 0xff61, 0};
 
271
    QStringList labels = name.split(QRegExp("[" + QString::fromUtf16(delimiters) + "]"));
 
272
    for (int i = 0; i < labels.count(); ++i) {
 
273
        if (i != 0) lookup += '.';
 
274
        QString label = QUnicodeTables::normalize(labels.at(i), QString::NormalizationForm_KC, QChar::Unicode_3_1);
 
275
        lookup += QString::fromAscii(QUrl::toPunycode(label));
 
276
    }
 
277
 
 
278
    return QHostInfoAgent::fromName(lookup);
 
279
}
 
280
 
 
281
/*!
 
282
    \internal
 
283
    Pops a query off the queries list, performs a blocking call to
 
284
    QHostInfoAgent::lookupHost(), and emits the resultsReady()
 
285
    signal. This process repeats until the queries list is empty.
 
286
*/
 
287
void QHostInfoAgent::run()
 
288
{
 
289
    forever {
 
290
        QHostInfoQuery *query;
 
291
        {
 
292
            // the queries list is shared between threads. lock all
 
293
            // access to it.
 
294
            QMutexLocker locker(&mutex);
 
295
            if (!quit && queries.isEmpty())
 
296
                cond.wait(&mutex);
 
297
            if (quit)
 
298
                break;
 
299
            if (queries.isEmpty())
 
300
                continue;
 
301
            query = queries.takeFirst();
 
302
        }
 
303
 
 
304
#if defined(QHOSTINFO_DEBUG)
 
305
        qDebug("QHostInfoAgent::run(%p): looking up \"%s\"", this,
 
306
               query->hostName.toLatin1().constData());
 
307
#endif
 
308
 
 
309
        QHostInfo info = fromName(query->hostName);
 
310
        info.setLookupId(query->object->lookupId);
 
311
        query->object->emitResultsReady(info);
 
312
        query->object = 0;
 
313
        delete query;
 
314
    }
 
315
}
 
316
 
 
317
/*!
 
318
    \enum QHostInfo::HostInfoError
 
319
 
 
320
    This enum describes the various errors that can occur when trying
 
321
    to resolve a host name.
 
322
 
 
323
    \value NoError The lookup was successful.
 
324
    \value HostNotFound No IP addresses were found for the host.
 
325
    \value UnknownError An unknown error occurred.
 
326
 
 
327
    \sa error(), setError()
 
328
*/
 
329
 
 
330
/*!
 
331
    Constructs an empty host info object with lookup ID \a id.
 
332
 
 
333
    \sa lookupId()
 
334
*/
 
335
QHostInfo::QHostInfo(int id)
 
336
    : d(new QHostInfoPrivate)
 
337
{
 
338
    d->lookupId = id;
 
339
}
 
340
 
 
341
/*!
 
342
    Constructs a copy of \a other.
 
343
*/
 
344
QHostInfo::QHostInfo(const QHostInfo &other)
 
345
    : d(new QHostInfoPrivate(*other.d))
 
346
{
 
347
}
 
348
 
 
349
/*!
 
350
    Assigns the data of the \a other object to this host info object,
 
351
    and returns a reference to it.
 
352
*/
 
353
QHostInfo &QHostInfo::operator=(const QHostInfo &other)
 
354
{
 
355
    *d = *other.d;
 
356
    return *this;
 
357
}
 
358
 
 
359
/*!
 
360
    Destroys the host info object.
 
361
*/
 
362
QHostInfo::~QHostInfo()
 
363
{
 
364
    delete d;
 
365
}
 
366
 
 
367
/*!
 
368
    Returns the list of IP addresses associated with hostName(). This
 
369
    list may be empty.
 
370
 
 
371
    Example:
 
372
 
 
373
    \code
 
374
        QHostInfo info;
 
375
        ...
 
376
        if (!info.addresses.isEmpty()) {
 
377
            QHostAddress address = info.addresses().first();
 
378
            // use the first IP address
 
379
        }
 
380
    \endcode
 
381
 
 
382
    \sa hostName(), error()
 
383
*/
 
384
QList<QHostAddress> QHostInfo::addresses() const
 
385
{
 
386
    return d->addrs;
 
387
}
 
388
 
 
389
/*!
 
390
    Sets the list of addresses in this QHostInfo to \a addresses.
 
391
 
 
392
    \sa addresses()
 
393
*/
 
394
void QHostInfo::setAddresses(const QList<QHostAddress> &addresses)
 
395
{
 
396
    d->addrs = addresses;
 
397
}
 
398
 
 
399
/*!
 
400
    Returns the name of the host whose IP addresses were looked up.
 
401
 
 
402
    \sa localHostName()
 
403
*/
 
404
QString QHostInfo::hostName() const
 
405
{
 
406
    return d->hostName;
 
407
}
 
408
 
 
409
/*!
 
410
    Sets the host name of this QHostInfo to \a hostName.
 
411
 
 
412
    \sa hostName()
 
413
*/
 
414
void QHostInfo::setHostName(const QString &hostName)
 
415
{
 
416
    d->hostName = hostName;
 
417
}
 
418
 
 
419
/*!
 
420
    Returns the type of error that occurred if the host name lookup
 
421
    failed; otherwise returns NoError.
 
422
 
 
423
    \sa setError(), errorString()
 
424
*/
 
425
QHostInfo::HostInfoError QHostInfo::error() const
 
426
{
 
427
    return d->err;
 
428
}
 
429
 
 
430
/*!
 
431
    Sets the error type of this QHostInfo to \a error.
 
432
 
 
433
    \sa error(), errorString()
 
434
*/
 
435
void QHostInfo::setError(HostInfoError error)
 
436
{
 
437
    d->err = error;
 
438
}
 
439
 
 
440
/*!
 
441
    Returns the ID of this lookup.
 
442
 
 
443
    \sa setLookupId(), abortHostLookup(), hostName()
 
444
*/
 
445
int QHostInfo::lookupId() const
 
446
{
 
447
    return d->lookupId;
 
448
}
 
449
 
 
450
/*!
 
451
    Sets the ID of this lookup to \a id.
 
452
 
 
453
    \sa lookupId(), lookupHost()
 
454
*/
 
455
void QHostInfo::setLookupId(int id)
 
456
{
 
457
    d->lookupId = id;
 
458
}
 
459
 
 
460
/*!
 
461
    If the lookup failed, this function returns a human readable
 
462
    description of the error; otherwise "Unknown error" is returned.
 
463
 
 
464
    \sa setErrorString(), error()
 
465
*/
 
466
QString QHostInfo::errorString() const
 
467
{
 
468
    return d->errorStr;
 
469
}
 
470
 
 
471
/*!
 
472
    Sets the human readable description of the error that occurred to \a str
 
473
    if the lookup failed.
 
474
 
 
475
    \sa errorString(), setError()
 
476
*/
 
477
void QHostInfo::setErrorString(const QString &str)
 
478
{
 
479
    d->errorStr = str;
 
480
}
 
481
 
 
482
/*!
 
483
    \fn QString QHostInfo::localHostName()
 
484
 
 
485
    Returns the host name of this machine.
 
486
 
 
487
    \sa hostName()
 
488
*/