summaryrefslogtreecommitdiffstats
path: root/src/network/kernel
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@nokia.com>2009-03-23 09:18:55 (GMT)
committerSimon Hausmann <simon.hausmann@nokia.com>2009-03-23 09:18:55 (GMT)
commite5fcad302d86d316390c6b0f62759a067313e8a9 (patch)
treec2afbf6f1066b6ce261f14341cf6d310e5595bc1 /src/network/kernel
downloadQt-e5fcad302d86d316390c6b0f62759a067313e8a9.zip
Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.gz
Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.bz2
Long live Qt 4.5!
Diffstat (limited to 'src/network/kernel')
-rw-r--r--src/network/kernel/kernel.pri30
-rw-r--r--src/network/kernel/qauthenticator.cpp1026
-rw-r--r--src/network/kernel/qauthenticator.h87
-rw-r--r--src/network/kernel/qauthenticator_p.h111
-rw-r--r--src/network/kernel/qhostaddress.cpp1166
-rw-r--r--src/network/kernel/qhostaddress.h154
-rw-r--r--src/network/kernel/qhostaddress_p.h76
-rw-r--r--src/network/kernel/qhostinfo.cpp479
-rw-r--r--src/network/kernel/qhostinfo.h101
-rw-r--r--src/network/kernel/qhostinfo_p.h196
-rw-r--r--src/network/kernel/qhostinfo_unix.cpp379
-rw-r--r--src/network/kernel/qhostinfo_win.cpp295
-rw-r--r--src/network/kernel/qnetworkinterface.cpp615
-rw-r--r--src/network/kernel/qnetworkinterface.h135
-rw-r--r--src/network/kernel/qnetworkinterface_p.h123
-rw-r--r--src/network/kernel/qnetworkinterface_unix.cpp448
-rw-r--r--src/network/kernel/qnetworkinterface_win.cpp327
-rw-r--r--src/network/kernel/qnetworkinterface_win_p.h266
-rw-r--r--src/network/kernel/qnetworkproxy.cpp1255
-rw-r--r--src/network/kernel/qnetworkproxy.h185
-rw-r--r--src/network/kernel/qnetworkproxy_generic.cpp59
-rw-r--r--src/network/kernel/qnetworkproxy_mac.cpp240
-rw-r--r--src/network/kernel/qnetworkproxy_win.cpp415
-rw-r--r--src/network/kernel/qurlinfo.cpp731
-rw-r--r--src/network/kernel/qurlinfo.h131
25 files changed, 9030 insertions, 0 deletions
diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri
new file mode 100644
index 0000000..8aa6ff4
--- /dev/null
+++ b/src/network/kernel/kernel.pri
@@ -0,0 +1,30 @@
+# Qt network kernel module
+
+PRECOMPILED_HEADER = ../corelib/global/qt_pch.h
+INCLUDEPATH += $$PWD
+
+HEADERS += kernel/qauthenticator.h \
+ kernel/qauthenticator_p.h \
+ kernel/qhostaddress.h \
+ kernel/qhostinfo.h \
+ kernel/qhostinfo_p.h \
+ kernel/qurlinfo.h \
+ kernel/qnetworkproxy.h \
+ kernel/qnetworkinterface.h \
+ kernel/qnetworkinterface_p.h
+
+SOURCES += kernel/qauthenticator.cpp \
+ kernel/qhostaddress.cpp \
+ kernel/qhostinfo.cpp \
+ kernel/qurlinfo.cpp \
+ kernel/qnetworkproxy.cpp \
+ kernel/qnetworkinterface.cpp
+
+unix:SOURCES += kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_unix.cpp
+win32:SOURCES += kernel/qhostinfo_win.cpp kernel/qnetworkinterface_win.cpp
+
+mac:LIBS+= -framework SystemConfiguration
+mac:SOURCES += kernel/qnetworkproxy_mac.cpp
+else:win32:SOURCES += kernel/qnetworkproxy_win.cpp
+else:SOURCES += kernel/qnetworkproxy_generic.cpp
+
diff --git a/src/network/kernel/qauthenticator.cpp b/src/network/kernel/qauthenticator.cpp
new file mode 100644
index 0000000..4f477bd
--- /dev/null
+++ b/src/network/kernel/qauthenticator.cpp
@@ -0,0 +1,1026 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qauthenticator.h>
+#include <qauthenticator_p.h>
+#include <qdebug.h>
+#include <qhash.h>
+#include <qbytearray.h>
+#include <qcryptographichash.h>
+#include <qhttp.h>
+#include <qdatastream.h>
+#include <qendian.h>
+#include <qstring.h>
+
+QT_BEGIN_NAMESPACE
+
+#include <../3rdparty/des/des.cpp>
+
+static QByteArray qNtlmPhase1();
+static QByteArray qNtlmPhase3(QAuthenticatorPrivate *ctx, const QByteArray& phase2data);
+
+/*!
+ \class QAuthenticator
+ \brief The QAuthenticator class provides an authentication object.
+ \since 4.3
+
+ \reentrant
+ \ingroup io
+ \inmodule QtNetwork
+
+ The QAuthenticator class is usually used in the
+ \l{QHttp::}{authenticationRequired()} and
+ \l{QHttp::}{proxyAuthenticationRequired()} signals of QHttp and
+ QAbstractSocket. The class provides a way to pass back the required
+ authentication information to the socket when accessing services that
+ require authentication.
+
+ \sa QSslSocket
+*/
+
+
+/*!
+ Constructs an empty authentication object
+*/
+QAuthenticator::QAuthenticator()
+ : d(0)
+{
+}
+
+/*!
+ Destructs the object
+*/
+QAuthenticator::~QAuthenticator()
+{
+ if (d && !d->ref.deref())
+ delete d;
+}
+
+/*!
+ Constructs a copy of \a other.
+*/
+QAuthenticator::QAuthenticator(const QAuthenticator &other)
+ : d(other.d)
+{
+ if (d)
+ d->ref.ref();
+}
+
+/*!
+ Assigns the contents of \a other to this authenticator.
+*/
+QAuthenticator &QAuthenticator::operator=(const QAuthenticator &other)
+{
+ if (d == other.d)
+ return *this;
+ detach();
+ d->user = other.d->user;
+ d->password = other.d->password;
+ return *this;
+}
+
+/*!
+ Returns true if this authenticator is identical to \a other; otherwise
+ returns false.
+*/
+bool QAuthenticator::operator==(const QAuthenticator &other) const
+{
+ if (d == other.d)
+ return true;
+ return d->user == other.d->user
+ && d->password == other.d->password
+ && d->realm == other.d->realm
+ && d->method == other.d->method;
+}
+
+/*!
+ \fn bool QAuthenticator::operator!=(const QAuthenticator &other) const
+
+ Returns true if this authenticator is different from \a other; otherwise
+ returns false.
+*/
+
+/*!
+ returns the user used for authentication.
+*/
+QString QAuthenticator::user() const
+{
+ return d ? d->user : QString();
+}
+
+/*!
+ Sets the \a user used for authentication.
+*/
+void QAuthenticator::setUser(const QString &user)
+{
+ detach();
+ d->user = user;
+}
+
+/*!
+ returns the password used for authentication.
+*/
+QString QAuthenticator::password() const
+{
+ return d ? d->password : QString();
+}
+
+/*!
+ Sets the \a password used for authentication.
+*/
+void QAuthenticator::setPassword(const QString &password)
+{
+ detach();
+ d->password = password;
+}
+
+/*!
+ \internal
+*/
+void QAuthenticator::detach()
+{
+ if (!d) {
+ d = new QAuthenticatorPrivate;
+ d->ref = 1;
+ return;
+ }
+
+ qAtomicDetach(d);
+ d->phase = QAuthenticatorPrivate::Start;
+}
+
+/*!
+ returns the realm requiring authentication.
+*/
+QString QAuthenticator::realm() const
+{
+ return d ? d->realm : QString();
+}
+
+
+/*!
+ returns true if the authenticator is null.
+*/
+bool QAuthenticator::isNull() const
+{
+ return !d;
+}
+
+QAuthenticatorPrivate::QAuthenticatorPrivate()
+ : ref(0)
+ , method(None)
+ , phase(Start)
+ , nonceCount(0)
+{
+ cnonce = QCryptographicHash::hash(QByteArray::number(qrand(), 16) + QByteArray::number(qrand(), 16),
+ QCryptographicHash::Md5).toHex();
+ nonceCount = 0;
+}
+
+#ifndef QT_NO_HTTP
+void QAuthenticatorPrivate::parseHttpResponse(const QHttpResponseHeader &header, bool isProxy)
+{
+ QList<QPair<QString, QString> > values = header.values();
+ const char *search = isProxy ? "proxy-authenticate" : "www-authenticate";
+
+ method = None;
+ /*
+ Fun from the HTTP 1.1 specs, that we currently ignore:
+
+ User agents are advised to take special care in parsing the WWW-
+ Authenticate field value as it might contain more than one challenge,
+ or if more than one WWW-Authenticate header field is provided, the
+ contents of a challenge itself can contain a comma-separated list of
+ authentication parameters.
+ */
+
+ QString headerVal;
+ for (int i = 0; i < values.size(); ++i) {
+ const QPair<QString, QString> &current = values.at(i);
+ if (current.first.toLower() != QLatin1String(search))
+ continue;
+ QString str = current.second;
+ if (method < Basic && str.startsWith(QLatin1String("Basic"), Qt::CaseInsensitive)) {
+ method = Basic; headerVal = str.mid(6);
+ } else if (method < Ntlm && str.startsWith(QLatin1String("NTLM"), Qt::CaseInsensitive)) {
+ method = Ntlm;
+ headerVal = str.mid(5);
+ } else if (method < DigestMd5 && str.startsWith(QLatin1String("Digest"), Qt::CaseInsensitive)) {
+ method = DigestMd5;
+ headerVal = str.mid(7);
+ }
+ }
+
+ challenge = headerVal.trimmed().toLatin1();
+ QHash<QByteArray, QByteArray> options = parseDigestAuthenticationChallenge(challenge);
+
+ switch(method) {
+ case Basic:
+ realm = QString::fromLatin1(options.value("realm"));
+ if (user.isEmpty())
+ phase = Done;
+ break;
+ case Ntlm:
+ // #### extract from header
+ realm = QString();
+ break;
+ case DigestMd5: {
+ realm = QString::fromLatin1(options.value("realm"));
+ if (options.value("stale").toLower() == "true")
+ phase = Start;
+ if (user.isEmpty())
+ phase = Done;
+ break;
+ }
+ default:
+ realm = QString();
+ challenge = QByteArray();
+ phase = Invalid;
+ }
+}
+#endif
+
+QByteArray QAuthenticatorPrivate::calculateResponse(const QByteArray &requestMethod, const QByteArray &path)
+{
+ QByteArray response;
+ const char *methodString = 0;
+ switch(method) {
+ case QAuthenticatorPrivate::None:
+ methodString = "";
+ phase = Done;
+ break;
+ case QAuthenticatorPrivate::Plain:
+ response = '\0' + user.toUtf8() + '\0' + password.toUtf8();
+ phase = Done;
+ break;
+ case QAuthenticatorPrivate::Basic:
+ methodString = "Basic ";
+ response = user.toLatin1() + ':' + password.toLatin1();
+ response = response.toBase64();
+ phase = Done;
+ break;
+ case QAuthenticatorPrivate::Login:
+ if (challenge.contains("VXNlciBOYW1lAA==")) {
+ response = user.toUtf8().toBase64();
+ phase = Phase2;
+ } else if (challenge.contains("UGFzc3dvcmQA")) {
+ response = password.toUtf8().toBase64();
+ phase = Done;
+ }
+ break;
+ case QAuthenticatorPrivate::CramMd5:
+ break;
+ case QAuthenticatorPrivate::DigestMd5:
+ methodString = "Digest ";
+ response = digestMd5Response(challenge, requestMethod, path);
+ phase = Done;
+ break;
+ case QAuthenticatorPrivate::Ntlm:
+ methodString = "NTLM ";
+ if (challenge.isEmpty()) {
+ response = qNtlmPhase1().toBase64();
+ if (user.isEmpty())
+ phase = Done;
+ else
+ phase = Phase2;
+ } else {
+ response = qNtlmPhase3(this, QByteArray::fromBase64(challenge)).toBase64();
+ phase = Done;
+ }
+
+ break;
+ }
+ return QByteArray(methodString) + response;
+}
+
+
+// ---------------------------- Digest Md5 code ----------------------------------------
+
+QHash<QByteArray, QByteArray> QAuthenticatorPrivate::parseDigestAuthenticationChallenge(const QByteArray &challenge)
+{
+ QHash<QByteArray, QByteArray> options;
+ // parse the challenge
+ const char *d = challenge.constData();
+ const char *end = d + challenge.length();
+ while (d < end) {
+ while (d < end && (*d == ' ' || *d == '\n' || *d == '\r'))
+ ++d;
+ const char *start = d;
+ while (d < end && *d != '=')
+ ++d;
+ QByteArray key = QByteArray(start, d - start);
+ ++d;
+ if (d >= end)
+ break;
+ bool quote = (*d == '"');
+ if (quote)
+ ++d;
+ if (d >= end)
+ break;
+ start = d;
+ QByteArray value;
+ while (d < end) {
+ bool backslash = false;
+ if (*d == '\\' && d < end - 1) {
+ ++d;
+ backslash = true;
+ }
+ if (!backslash) {
+ if (quote) {
+ if (*d == '"')
+ break;
+ } else {
+ if (*d == ',')
+ break;
+ }
+ }
+ value += *d;
+ ++d;
+ }
+ while (d < end && *d != ',')
+ ++d;
+ ++d;
+ options[key] = value;
+ }
+
+ QByteArray qop = options.value("qop");
+ if (!qop.isEmpty()) {
+ QList<QByteArray> qopoptions = qop.split(',');
+ if (!qopoptions.contains("auth"))
+ return QHash<QByteArray, QByteArray>();
+ // #### can't do auth-int currently
+// if (qop.contains("auth-int"))
+// qop = "auth-int";
+// else if (qop.contains("auth"))
+// qop = "auth";
+// else
+// qop = QByteArray();
+ options["qop"] = "auth";
+ }
+
+ return options;
+}
+
+/*
+ Digest MD5 implementation
+
+ Code taken from RFC 2617
+
+ Currently we don't support the full SASL authentication mechanism (which includes cyphers)
+*/
+
+
+/* calculate request-digest/response-digest as per HTTP Digest spec */
+static QByteArray digestMd5ResponseHelper(
+ const QByteArray &alg,
+ const QByteArray &userName,
+ const QByteArray &realm,
+ const QByteArray &password,
+ const QByteArray &nonce, /* nonce from server */
+ const QByteArray &nonceCount, /* 8 hex digits */
+ const QByteArray &cNonce, /* client nonce */
+ const QByteArray &qop, /* qop-value: "", "auth", "auth-int" */
+ const QByteArray &method, /* method from the request */
+ const QByteArray &digestUri, /* requested URL */
+ const QByteArray &hEntity /* H(entity body) if qop="auth-int" */
+ )
+{
+ QCryptographicHash hash(QCryptographicHash::Md5);
+ hash.addData(userName);
+ hash.addData(":", 1);
+ hash.addData(realm);
+ hash.addData(":", 1);
+ hash.addData(password);
+ QByteArray ha1 = hash.result();
+ if (alg.toLower() == "md5-sess") {
+ hash.reset();
+ // RFC 2617 contains an error, it was:
+ // hash.addData(ha1);
+ // but according to the errata page at http://www.rfc-editor.org/errata_list.php, ID 1649, it
+ // must be the following line:
+ hash.addData(ha1.toHex());
+ hash.addData(":", 1);
+ hash.addData(nonce);
+ hash.addData(":", 1);
+ hash.addData(cNonce);
+ ha1 = hash.result();
+ };
+ ha1 = ha1.toHex();
+
+ // calculate H(A2)
+ hash.reset();
+ hash.addData(method);
+ hash.addData(":", 1);
+ hash.addData(digestUri);
+ if (qop.toLower() == "auth-int") {
+ hash.addData(":", 1);
+ hash.addData(hEntity);
+ }
+ QByteArray ha2hex = hash.result().toHex();
+
+ // calculate response
+ hash.reset();
+ hash.addData(ha1);
+ hash.addData(":", 1);
+ hash.addData(nonce);
+ hash.addData(":", 1);
+ if (!qop.isNull()) {
+ hash.addData(nonceCount);
+ hash.addData(":", 1);
+ hash.addData(cNonce);
+ hash.addData(":", 1);
+ hash.addData(qop);
+ hash.addData(":", 1);
+ }
+ hash.addData(ha2hex);
+ return hash.result().toHex();
+}
+
+QByteArray QAuthenticatorPrivate::digestMd5Response(const QByteArray &challenge, const QByteArray &method, const QByteArray &path)
+{
+ QHash<QByteArray,QByteArray> options = parseDigestAuthenticationChallenge(challenge);
+
+ ++nonceCount;
+ QByteArray nonceCountString = QByteArray::number(nonceCount, 16);
+ while (nonceCountString.length() < 8)
+ nonceCountString.prepend('0');
+
+ QByteArray nonce = options.value("nonce");
+ QByteArray opaque = options.value("opaque");
+ QByteArray qop = options.value("qop");
+
+// qDebug() << "calculating digest: method=" << method << "path=" << path;
+ QByteArray response = digestMd5ResponseHelper(options.value("algorithm"), user.toLatin1(),
+ realm.toLatin1(), password.toLatin1(),
+ nonce, nonceCountString,
+ cnonce, qop, method,
+ path, QByteArray());
+
+
+ QByteArray credentials;
+ credentials += "username=\"" + user.toLatin1() + "\", ";
+ credentials += "realm=\"" + realm.toLatin1() + "\", ";
+ credentials += "nonce=\"" + nonce + "\", ";
+ credentials += "uri=\"" + path + "\", ";
+ if (!opaque.isEmpty())
+ credentials += "opaque=\"" + opaque + "\", ";
+ credentials += "response=\"" + response + "\"";
+ if (!options.value("algorithm").isEmpty())
+ credentials += ", algorithm=" + options.value("algorithm");
+ if (!options.value("qop").isEmpty()) {
+ credentials += ", qop=" + qop + ", ";
+ credentials += "nc=" + nonceCountString + ", ";
+ credentials += "cnonce=\"" + cnonce + "\"";
+ }
+
+ return credentials;
+}
+
+// ---------------------------- Digest Md5 code ----------------------------------------
+
+
+
+/*
+ * NTLM message flags.
+ *
+ * Copyright (c) 2004 Andrey Panin <pazke@donpac.ru>
+ *
+ * This software is released under the MIT license.
+ */
+
+/*
+ * Indicates that Unicode strings are supported for use in security
+ * buffer data.
+ */
+#define NTLMSSP_NEGOTIATE_UNICODE 0x00000001
+
+/*
+ * Indicates that OEM strings are supported for use in security buffer data.
+ */
+#define NTLMSSP_NEGOTIATE_OEM 0x00000002
+
+/*
+ * Requests that the server's authentication realm be included in the
+ * Type 2 message.
+ */
+#define NTLMSSP_REQUEST_TARGET 0x00000004
+
+/*
+ * Specifies that authenticated communication between the client and server
+ * should carry a digital signature (message integrity).
+ */
+#define NTLMSSP_NEGOTIATE_SIGN 0x00000010
+
+/*
+ * Specifies that authenticated communication between the client and server
+ * should be encrypted (message confidentiality).
+ */
+#define NTLMSSP_NEGOTIATE_SEAL 0x00000020
+
+/*
+ * Indicates that datagram authentication is being used.
+ */
+#define NTLMSSP_NEGOTIATE_DATAGRAM 0x00000040
+
+/*
+ * Indicates that the LAN Manager session key should be
+ * used for signing and sealing authenticated communications.
+ */
+#define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080
+
+/*
+ * Indicates that NTLM authentication is being used.
+ */
+#define NTLMSSP_NEGOTIATE_NTLM 0x00000200
+
+/*
+ * Sent by the client in the Type 1 message to indicate that the name of the
+ * domain in which the client workstation has membership is included in the
+ * message. This is used by the server to determine whether the client is
+ * eligible for local authentication.
+ */
+#define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x00001000
+
+/*
+ * Sent by the client in the Type 1 message to indicate that the client
+ * workstation's name is included in the message. This is used by the server
+ * to determine whether the client is eligible for local authentication.
+ */
+#define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x00002000
+
+/*
+ * Sent by the server to indicate that the server and client are on the same
+ * machine. Implies that the client may use the established local credentials
+ * for authentication instead of calculating a response to the challenge.
+ */
+#define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x00004000
+
+/*
+ * Indicates that authenticated communication between the client and server
+ * should be signed with a "dummy" signature.
+ */
+#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000
+
+/*
+ * Sent by the server in the Type 2 message to indicate that the target
+ * authentication realm is a domain.
+ */
+#define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000
+
+/*
+ * Sent by the server in the Type 2 message to indicate that the target
+ * authentication realm is a server.
+ */
+#define NTLMSSP_TARGET_TYPE_SERVER 0x00020000
+
+/*
+ * Sent by the server in the Type 2 message to indicate that the target
+ * authentication realm is a share. Presumably, this is for share-level
+ * authentication. Usage is unclear.
+ */
+#define NTLMSSP_TARGET_TYPE_SHARE 0x00040000
+
+/*
+ * Indicates that the NTLM2 signing and sealing scheme should be used for
+ * protecting authenticated communications. Note that this refers to a
+ * particular session security scheme, and is not related to the use of
+ * NTLMv2 authentication.
+ */
+#define NTLMSSP_NEGOTIATE_NTLM2 0x00080000
+
+/*
+ * Sent by the server in the Type 2 message to indicate that it is including
+ * a Target Information block in the message. The Target Information block
+ * is used in the calculation of the NTLMv2 response.
+ */
+#define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000
+
+/*
+ * Indicates that 128-bit encryption is supported.
+ */
+#define NTLMSSP_NEGOTIATE_128 0x20000000
+
+/*
+ * Indicates that the client will provide an encrypted master session key in
+ * the "Session Key" field of the Type 3 message. This is used in signing and
+ * sealing, and is RC4-encrypted using the previous session key as the
+ * encryption key.
+ */
+#define NTLMSSP_NEGOTIATE_KEY_EXCHANGE 0x40000000
+
+/*
+ * Indicates that 56-bit encryption is supported.
+ */
+#define NTLMSSP_NEGOTIATE_56 0x80000000
+
+
+/* usage:
+ // fill up ctx with what we know.
+ QByteArray response = qNtlmPhase1(ctx);
+ // send response (b64 encoded??)
+ // get response from server (b64 decode?)
+ Phase2Block pb;
+ qNtlmDecodePhase2(response, pb);
+ response = qNtlmPhase3(ctx, pb);
+ // send response (b64 encoded??)
+*/
+
+/*
+ TODO:
+ - Fix unicode handling
+ - add v2 handling
+*/
+
+class QNtlmBuffer {
+public:
+ QNtlmBuffer() : len(0), maxLen(0), offset(0) {}
+ quint16 len;
+ quint16 maxLen;
+ quint32 offset;
+ enum { Size = 8 };
+};
+
+class QNtlmPhase1BlockBase
+{
+public:
+ char magic[8];
+ quint32 type;
+ quint32 flags;
+ QNtlmBuffer domain;
+ QNtlmBuffer workstation;
+ enum { Size = 32 };
+};
+
+// ################# check paddings
+class QNtlmPhase2BlockBase
+{
+public:
+ char magic[8];
+ quint32 type;
+ QNtlmBuffer targetName;
+ quint32 flags;
+ unsigned char challenge[8];
+ quint32 context[2];
+ QNtlmBuffer targetInfo;
+ enum { Size = 48 };
+};
+
+class QNtlmPhase3BlockBase {
+public:
+ char magic[8];
+ quint32 type;
+ QNtlmBuffer lmResponse;
+ QNtlmBuffer ntlmResponse;
+ QNtlmBuffer domain;
+ QNtlmBuffer user;
+ QNtlmBuffer workstation;
+ QNtlmBuffer sessionKey;
+ quint32 flags;
+ enum { Size = 64 };
+};
+
+static void qStreamNtlmBuffer(QDataStream& ds, const QByteArray& s)
+{
+ ds.writeRawData(s.constData(), s.size());
+}
+
+
+static void qStreamNtlmString(QDataStream& ds, const QString& s, bool unicode)
+{
+ if (!unicode) {
+ qStreamNtlmBuffer(ds, s.toLatin1());
+ return;
+ }
+ const ushort *d = s.utf16();
+ for (int i = 0; i < s.length(); ++i)
+ ds << d[i];
+}
+
+
+
+static int qEncodeNtlmBuffer(QNtlmBuffer& buf, int offset, const QByteArray& s)
+{
+ buf.len = s.size();
+ buf.maxLen = buf.len;
+ buf.offset = (offset + 1) & ~1;
+ return buf.offset + buf.len;
+}
+
+
+static int qEncodeNtlmString(QNtlmBuffer& buf, int offset, const QString& s, bool unicode)
+{
+ if (!unicode)
+ return qEncodeNtlmBuffer(buf, offset, s.toLatin1());
+ buf.len = 2 * s.length();
+ buf.maxLen = buf.len;
+ buf.offset = (offset + 1) & ~1;
+ return buf.offset + buf.len;
+}
+
+
+static QDataStream& operator<<(QDataStream& s, const QNtlmBuffer& b)
+{
+ s << b.len << b.maxLen << b.offset;
+ return s;
+}
+
+static QDataStream& operator>>(QDataStream& s, QNtlmBuffer& b)
+{
+ s >> b.len >> b.maxLen >> b.offset;
+ return s;
+}
+
+
+class QNtlmPhase1Block : public QNtlmPhase1BlockBase
+{ // request
+public:
+ QNtlmPhase1Block() {
+ qstrncpy(magic, "NTLMSSP", 8);
+ type = 1;
+ flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_REQUEST_TARGET;
+ }
+
+ // extracted
+ QString domainStr, workstationStr;
+};
+
+
+class QNtlmPhase2Block : public QNtlmPhase2BlockBase
+{ // challenge
+public:
+ QNtlmPhase2Block() {
+ magic[0] = 0;
+ type = 0xffffffff;
+ }
+
+ // extracted
+ QString targetNameStr, targetInfoStr;
+};
+
+
+
+class QNtlmPhase3Block : public QNtlmPhase3BlockBase { // response
+public:
+ QNtlmPhase3Block() {
+ qstrncpy(magic, "NTLMSSP", 8);
+ type = 3;
+ flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO;
+ }
+
+ // extracted
+ QByteArray lmResponseBuf, ntlmResponseBuf;
+ QString domainStr, userStr, workstationStr, sessionKeyStr;
+};
+
+
+static QDataStream& operator<<(QDataStream& s, const QNtlmPhase1Block& b) {
+ bool unicode = (b.flags & NTLMSSP_NEGOTIATE_UNICODE);
+
+ s.writeRawData(b.magic, sizeof(b.magic));
+ s << b.type;
+ s << b.flags;
+ s << b.domain;
+ s << b.workstation;
+ if (!b.domainStr.isEmpty())
+ qStreamNtlmString(s, b.domainStr, unicode);
+ if (!b.workstationStr.isEmpty())
+ qStreamNtlmString(s, b.workstationStr, unicode);
+ return s;
+}
+
+
+static QDataStream& operator<<(QDataStream& s, const QNtlmPhase3Block& b) {
+ bool unicode = (b.flags & NTLMSSP_NEGOTIATE_UNICODE);
+ s.writeRawData(b.magic, sizeof(b.magic));
+ s << b.type;
+ s << b.lmResponse;
+ s << b.ntlmResponse;
+ s << b.domain;
+ s << b.user;
+ s << b.workstation;
+ s << b.sessionKey;
+ s << b.flags;
+
+ if (!b.domainStr.isEmpty())
+ qStreamNtlmString(s, b.domainStr, unicode);
+
+ qStreamNtlmString(s, b.userStr, unicode);
+
+ if (!b.workstationStr.isEmpty())
+ qStreamNtlmString(s, b.workstationStr, unicode);
+
+ // Send auth info
+ qStreamNtlmBuffer(s, b.lmResponseBuf);
+ qStreamNtlmBuffer(s, b.ntlmResponseBuf);
+
+
+ return s;
+}
+
+
+static QByteArray qNtlmPhase1()
+{
+ QByteArray rc;
+ QDataStream ds(&rc, QIODevice::WriteOnly);
+ ds.setByteOrder(QDataStream::LittleEndian);
+ QNtlmPhase1Block pb;
+ ds << pb;
+ return rc;
+}
+
+
+static QByteArray qStringAsUcs2Le(const QString& src)
+{
+ QByteArray rc(2*src.length(), 0);
+ const unsigned short *s = src.utf16();
+ unsigned short *d = (unsigned short*)rc.data();
+ for (int i = 0; i < src.length(); ++i) {
+ d[i] = qToLittleEndian(s[i]);
+ }
+ return rc;
+}
+
+
+static QString qStringFromUcs2Le(const QByteArray& src)
+{
+ Q_ASSERT(src.size() % 2 == 0);
+ unsigned short *d = (unsigned short*)src.data();
+ for (int i = 0; i < src.length() / 2; ++i) {
+ d[i] = qFromLittleEndian(d[i]);
+ }
+ return QString((const QChar *)src.data(), src.size()/2);
+}
+
+
+static QByteArray qEncodeNtlmResponse(const QAuthenticatorPrivate *ctx, const QNtlmPhase2Block& ch)
+{
+ QCryptographicHash md4(QCryptographicHash::Md4);
+ QByteArray asUcs2Le = qStringAsUcs2Le(ctx->password);
+ md4.addData(asUcs2Le.data(), asUcs2Le.size());
+
+ unsigned char md4hash[22];
+ memset(md4hash, 0, sizeof(md4hash));
+ QByteArray hash = md4.result();
+ Q_ASSERT(hash.size() == 16);
+ memcpy(md4hash, hash.constData(), 16);
+
+ QByteArray rc(24, 0);
+ deshash((unsigned char *)rc.data(), md4hash, (unsigned char *)ch.challenge);
+ deshash((unsigned char *)rc.data() + 8, md4hash + 7, (unsigned char *)ch.challenge);
+ deshash((unsigned char *)rc.data() + 16, md4hash + 14, (unsigned char *)ch.challenge);
+
+ hash.fill(0);
+ return rc;
+}
+
+
+static QByteArray qEncodeLmResponse(const QAuthenticatorPrivate *ctx, const QNtlmPhase2Block& ch)
+{
+ QByteArray hash(21, 0);
+ QByteArray key(14, 0);
+ qstrncpy(key.data(), ctx->password.toUpper().toLatin1(), 14);
+ const char *block = "KGS!@#$%";
+
+ deshash((unsigned char *)hash.data(), (unsigned char *)key.data(), (unsigned char *)block);
+ deshash((unsigned char *)hash.data() + 8, (unsigned char *)key.data() + 7, (unsigned char *)block);
+ key.fill(0);
+
+ QByteArray rc(24, 0);
+ deshash((unsigned char *)rc.data(), (unsigned char *)hash.data(), ch.challenge);
+ deshash((unsigned char *)rc.data() + 8, (unsigned char *)hash.data() + 7, ch.challenge);
+ deshash((unsigned char *)rc.data() + 16, (unsigned char *)hash.data() + 14, ch.challenge);
+
+ hash.fill(0);
+ return rc;
+}
+
+
+static bool qNtlmDecodePhase2(const QByteArray& data, QNtlmPhase2Block& ch)
+{
+ Q_ASSERT(QNtlmPhase2BlockBase::Size == sizeof(QNtlmPhase2BlockBase));
+ if (data.size() < QNtlmPhase2BlockBase::Size)
+ return false;
+
+
+ QDataStream ds(data);
+ ds.setByteOrder(QDataStream::LittleEndian);
+ if (ds.readRawData(ch.magic, 8) < 8)
+ return false;
+ if (strncmp(ch.magic, "NTLMSSP", 8) != 0)
+ return false;
+
+ ds >> ch.type;
+ if (ch.type != 2)
+ return false;
+
+ ds >> ch.targetName;
+ ds >> ch.flags;
+ if (ds.readRawData((char *)ch.challenge, 8) < 8)
+ return false;
+ ds >> ch.context[0] >> ch.context[1];
+ ds >> ch.targetInfo;
+
+ if (ch.targetName.len > 0) {
+ if (ch.targetName.len + ch.targetName.offset >= (unsigned)data.size())
+ return false;
+
+ ch.targetNameStr = qStringFromUcs2Le(data.mid(ch.targetName.offset, ch.targetName.len));
+ }
+
+ if (ch.targetInfo.len > 0) {
+ // UNUSED right now
+ }
+
+ return true;
+}
+
+
+static QByteArray qNtlmPhase3(QAuthenticatorPrivate *ctx, const QByteArray& phase2data)
+{
+ QNtlmPhase2Block ch;
+ if (!qNtlmDecodePhase2(phase2data, ch))
+ return QByteArray();
+
+ QByteArray rc;
+ QDataStream ds(&rc, QIODevice::WriteOnly);
+ ds.setByteOrder(QDataStream::LittleEndian);
+ QNtlmPhase3Block pb;
+
+ bool unicode = ch.flags & NTLMSSP_NEGOTIATE_UNICODE;
+
+ ctx->realm = ch.targetNameStr;
+
+ pb.flags = NTLMSSP_NEGOTIATE_NTLM;
+ if (unicode)
+ pb.flags |= NTLMSSP_NEGOTIATE_UNICODE;
+ else
+ pb.flags |= NTLMSSP_NEGOTIATE_OEM;
+
+
+ int offset = QNtlmPhase3BlockBase::Size;
+ Q_ASSERT(QNtlmPhase3BlockBase::Size == sizeof(QNtlmPhase3BlockBase));
+
+ offset = qEncodeNtlmString(pb.domain, offset, ctx->realm, unicode);
+ pb.domainStr = ctx->realm;
+ offset = qEncodeNtlmString(pb.user, offset, ctx->user, unicode);
+ pb.userStr = ctx->user;
+
+ offset = qEncodeNtlmString(pb.workstation, offset, ctx->workstation, unicode);
+ pb.workstationStr = ctx->workstation;
+
+ // Get LM response
+ pb.lmResponseBuf = qEncodeLmResponse(ctx, ch);
+ offset = qEncodeNtlmBuffer(pb.lmResponse, offset, pb.lmResponseBuf);
+
+ // Get NTLM response
+ pb.ntlmResponseBuf = qEncodeNtlmResponse(ctx, ch);
+ offset = qEncodeNtlmBuffer(pb.ntlmResponse, offset, pb.ntlmResponseBuf);
+
+
+ // Encode and send
+ ds << pb;
+
+ return rc;
+}
+
+
+
+QT_END_NAMESPACE
diff --git a/src/network/kernel/qauthenticator.h b/src/network/kernel/qauthenticator.h
new file mode 100644
index 0000000..aa78a56
--- /dev/null
+++ b/src/network/kernel/qauthenticator.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QAUTHENTICATOR_H
+#define QAUTHENTICATOR_H
+
+#include <QtCore/qstring.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Network)
+
+class QAuthenticatorPrivate;
+class QUrl;
+
+class Q_NETWORK_EXPORT QAuthenticator
+{
+public:
+ QAuthenticator();
+ ~QAuthenticator();
+
+ QAuthenticator(const QAuthenticator &other);
+ QAuthenticator &operator=(const QAuthenticator &other);
+
+ bool operator==(const QAuthenticator &other) const;
+ inline bool operator!=(const QAuthenticator &other) const { return !operator==(other); }
+
+ QString user() const;
+ void setUser(const QString &user);
+
+ QString password() const;
+ void setPassword(const QString &password);
+
+ QString realm() const;
+
+ bool isNull() const;
+ void detach();
+private:
+ friend class QAuthenticatorPrivate;
+ QAuthenticatorPrivate *d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/network/kernel/qauthenticator_p.h b/src/network/kernel/qauthenticator_p.h
new file mode 100644
index 0000000..42583cf
--- /dev/null
+++ b/src/network/kernel/qauthenticator_p.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QAUTHENTICATOR_P_H
+#define QAUTHENTICATOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <qhash.h>
+#include <qbytearray.h>
+#include <qstring.h>
+#include <qauthenticator.h>
+
+QT_BEGIN_NAMESPACE
+
+class QHttpResponseHeader;
+
+class QAuthenticatorPrivate
+{
+public:
+ enum Method { None, Basic, Plain, Login, Ntlm, CramMd5, DigestMd5 };
+ QAuthenticatorPrivate();
+
+ QAtomicInt ref;
+ QString user;
+ QString password;
+ QHash<QByteArray, QByteArray> options;
+ Method method;
+ QString realm;
+ QByteArray challenge;
+
+ enum Phase {
+ Start,
+ Phase2,
+ Done,
+ Invalid
+ };
+ Phase phase;
+
+ // digest specific
+ QByteArray cnonce;
+ int nonceCount;
+
+ // ntlm specific
+ QString workstation;
+
+ QByteArray calculateResponse(const QByteArray &method, const QByteArray &path);
+
+ inline static QAuthenticatorPrivate *getPrivate(QAuthenticator &auth) { return auth.d; }
+ inline static const QAuthenticatorPrivate *getPrivate(const QAuthenticator &auth) { return auth.d; }
+
+ QByteArray digestMd5Response(const QByteArray &challenge, const QByteArray &method, const QByteArray &path);
+ static QHash<QByteArray, QByteArray> parseDigestAuthenticationChallenge(const QByteArray &challenge);
+
+#ifndef QT_NO_HTTP
+ void parseHttpResponse(const QHttpResponseHeader &, bool isProxy);
+#endif
+
+};
+
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/network/kernel/qhostaddress.cpp b/src/network/kernel/qhostaddress.cpp
new file mode 100644
index 0000000..fc43369
--- /dev/null
+++ b/src/network/kernel/qhostaddress.cpp
@@ -0,0 +1,1166 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qhostaddress.h"
+#include "qhostaddress_p.h"
+#include "qdebug.h"
+#include "qplatformdefs.h"
+#include "qstringlist.h"
+#include "qendian.h"
+#ifndef QT_NO_DATASTREAM
+#include <qdatastream.h>
+#endif
+#if defined(Q_OS_WINCE)
+#include <winsock.h>
+#endif
+
+#ifdef QT_LINUXBASE
+# include <arpa/inet.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#define QT_ENSURE_PARSED(a) \
+ do { \
+ if (!(a)->d->isParsed) \
+ (a)->d->parse(); \
+ } while (0)
+
+#ifdef Q_OS_WIN
+# if !defined (QT_NO_IPV6)
+// sockaddr_in6 size changed between old and new SDK
+// Only the new version is the correct one, so always
+// use this structure.
+#if defined(Q_OS_WINCE)
+# if !defined(u_char)
+# define u_char unsigned char
+# endif
+# if !defined(u_short)
+# define u_short unsigned short
+# endif
+# if !defined(u_long)
+# define u_long unsigned long
+# endif
+#endif
+struct qt_in6_addr {
+ u_char qt_s6_addr[16];
+};
+typedef struct {
+ short sin6_family; /* AF_INET6 */
+ u_short sin6_port; /* Transport level port number */
+ u_long sin6_flowinfo; /* IPv6 flow information */
+ struct qt_in6_addr sin6_addr; /* IPv6 address */
+ u_long sin6_scope_id; /* set of interfaces for a scope */
+} qt_sockaddr_in6;
+# else
+typedef void * qt_sockaddr_in6 ;
+# endif
+# ifndef AF_INET6
+# define AF_INET6 23 /* Internetwork Version 6 */
+# endif
+#else
+#define qt_sockaddr_in6 sockaddr_in6
+#define qt_s6_addr s6_addr
+#endif
+
+
+class QHostAddressPrivate
+{
+public:
+ QHostAddressPrivate();
+
+ void setAddress(quint32 a_ = 0);
+ void setAddress(const quint8 *a_);
+ void setAddress(const Q_IPV6ADDR &a_);
+
+ bool parse();
+ void clear();
+
+ quint32 a; // IPv4 address
+ Q_IPV6ADDR a6; // IPv6 address
+ QAbstractSocket::NetworkLayerProtocol protocol;
+
+ QString ipString;
+ bool isParsed;
+ QString scopeId;
+
+ friend class QHostAddress;
+};
+
+QHostAddressPrivate::QHostAddressPrivate()
+ : a(0), protocol(QAbstractSocket::UnknownNetworkLayerProtocol), isParsed(true)
+{
+ memset(&a6, 0, sizeof(a6));
+}
+
+void QHostAddressPrivate::setAddress(quint32 a_)
+{
+ a = a_;
+ protocol = QAbstractSocket::IPv4Protocol;
+ isParsed = true;
+}
+
+void QHostAddressPrivate::setAddress(const quint8 *a_)
+{
+ for (int i = 0; i < 16; i++)
+ a6[i] = a_[i];
+ protocol = QAbstractSocket::IPv6Protocol;
+ isParsed = true;
+}
+
+void QHostAddressPrivate::setAddress(const Q_IPV6ADDR &a_)
+{
+ a6 = a_;
+ a = 0;
+ protocol = QAbstractSocket::IPv6Protocol;
+ isParsed = true;
+}
+
+static bool parseIp4(const QString& address, quint32 *addr)
+{
+ QStringList ipv4 = address.split(QLatin1String("."));
+ if (ipv4.count() != 4)
+ return false;
+
+ quint32 ipv4Address = 0;
+ for (int i = 0; i < 4; ++i) {
+ bool ok = false;
+ uint byteValue = ipv4.at(i).toUInt(&ok);
+ if (!ok || byteValue > 255)
+ return false;
+
+ ipv4Address <<= 8;
+ ipv4Address += byteValue;
+ }
+
+ *addr = ipv4Address;
+ return true;
+}
+
+static bool parseIp6(const QString &address, quint8 *addr, QString *scopeId)
+{
+ QString tmp = address;
+ int scopeIdPos = tmp.lastIndexOf(QLatin1Char('%'));
+ if (scopeIdPos != -1) {
+ *scopeId = tmp.mid(scopeIdPos + 1);
+ tmp.chop(tmp.size() - scopeIdPos);
+ } else {
+ scopeId->clear();
+ }
+
+ QStringList ipv6 = tmp.split(QLatin1String(":"));
+ int count = ipv6.count();
+ if (count < 3 || count > 8)
+ return false;
+
+ int colonColon = tmp.count(QLatin1String("::"));
+ if(count == 8 && colonColon > 1)
+ return false;
+
+ // address can be compressed with a "::", but that
+ // may only appear once (see RFC 1884)
+ // the statement below means:
+ // if(shortened notation is not used AND
+ // ((pure IPv6 notation AND less than 8 parts) OR
+ // ((mixed IPv4/6 notation AND less than 7 parts)))
+ if(colonColon != 1 && count < (tmp.contains(QLatin1Char('.')) ? 7 : 8))
+ return false;
+
+ int mc = 16;
+ int fillCount = 9 - count; // number of 0 words to fill in the middle
+ for (int i = count - 1; i >= 0; --i) {
+ if (mc <= 0)
+ return false;
+
+ if (ipv6.at(i).isEmpty()) {
+ if (i == count - 1) {
+ // special case: ":" is last character
+ if (!ipv6.at(i - 1).isEmpty())
+ return false;
+ addr[--mc] = 0;
+ addr[--mc] = 0;
+ } else if (i == 0) {
+ // special case: ":" is first character
+ if (!ipv6.at(i + 1).isEmpty())
+ return false;
+ addr[--mc] = 0;
+ addr[--mc] = 0;
+ } else {
+ for (int j = 0; j < fillCount; ++j) {
+ if (mc <= 0)
+ return false;
+ addr[--mc] = 0;
+ addr[--mc] = 0;
+ }
+ }
+ } else {
+ bool ok = false;
+ uint byteValue = ipv6.at(i).toUInt(&ok, 16);
+ if (ok && byteValue <= 0xffff) {
+ addr[--mc] = byteValue & 0xff;
+ addr[--mc] = (byteValue >> 8) & 0xff;
+ } else {
+ if (i != count - 1)
+ return false;
+
+ // parse the ipv4 part of a mixed type
+ quint32 maybeIp4;
+ if (!parseIp4(ipv6.at(i), &maybeIp4))
+ return false;
+
+ addr[--mc] = maybeIp4 & 0xff;
+ addr[--mc] = (maybeIp4 >> 8) & 0xff;
+ addr[--mc] = (maybeIp4 >> 16) & 0xff;
+ addr[--mc] = (maybeIp4 >> 24) & 0xff;
+ --fillCount;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool QHostAddressPrivate::parse()
+{
+ isParsed = true;
+ protocol = QAbstractSocket::UnknownNetworkLayerProtocol;
+ QString a = ipString.simplified();
+
+ // All IPv6 addresses contain a ':', and may contain a '.'.
+ if (a.contains(QLatin1Char(':'))) {
+ quint8 maybeIp6[16];
+ if (parseIp6(a, maybeIp6, &scopeId)) {
+ setAddress(maybeIp6);
+ protocol = QAbstractSocket::IPv6Protocol;
+ return true;
+ }
+ }
+
+ // All IPv4 addresses contain a '.'.
+ if (a.contains(QLatin1Char('.'))) {
+ quint32 maybeIp4 = 0;
+ if (parseIp4(a, &maybeIp4)) {
+ setAddress(maybeIp4);
+ protocol = QAbstractSocket::IPv4Protocol;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void QHostAddressPrivate::clear()
+{
+ a = 0;
+ protocol = QAbstractSocket::UnknownNetworkLayerProtocol;
+ isParsed = true;
+ memset(&a6, 0, sizeof(a6));
+}
+
+
+bool QNetmaskAddress::setAddress(const QString &address)
+{
+ length = -1;
+ QHostAddress other;
+ return other.setAddress(address) && setAddress(other);
+}
+
+bool QNetmaskAddress::setAddress(const QHostAddress &address)
+{
+ static const quint8 zeroes[16] = { 0 };
+ union {
+ quint32 v4;
+ quint8 v6[16];
+ } ip;
+
+ int netmask = 0;
+ quint8 *ptr = ip.v6;
+ quint8 *end;
+ length = -1;
+
+ QHostAddress::operator=(address);
+
+ if (d->protocol == QAbstractSocket::IPv4Protocol) {
+ ip.v4 = qToBigEndian(d->a);
+ end = ptr + 4;
+ } else if (d->protocol == QAbstractSocket::IPv6Protocol) {
+ memcpy(ip.v6, d->a6.c, 16);
+ end = ptr + 16;
+ } else {
+ d->clear();
+ return false;
+ }
+
+ while (ptr < end) {
+ switch (*ptr) {
+ case 255:
+ netmask += 8;
+ ++ptr;
+ continue;
+
+ default:
+ d->clear();
+ return false; // invalid IP-style netmask
+
+ // the rest always falls through
+ case 254:
+ ++netmask;
+ case 252:
+ ++netmask;
+ case 248:
+ ++netmask;
+ case 240:
+ ++netmask;
+ case 224:
+ ++netmask;
+ case 192:
+ ++netmask;
+ case 128:
+ ++netmask;
+ case 0:
+ break;
+ }
+ break;
+ }
+
+ // confirm that the rest is only zeroes
+ if (ptr < end && memcmp(ptr + 1, zeroes, end - ptr - 1) != 0) {
+ d->clear();
+ return false;
+ }
+
+ length = netmask;
+ return true;
+}
+
+static void clearBits(quint8 *where, int start, int end)
+{
+ Q_ASSERT(end == 32 || end == 128);
+ if (start == end)
+ return;
+
+ // for the byte where 'start' is, clear the lower bits only
+ quint8 bytemask = 256 - (1 << (8 - (start & 7)));
+ where[start / 8] &= bytemask;
+
+ // for the tail part, clear everything
+ memset(where + (start + 7) / 8, 0, end / 8 - (start + 7) / 8);
+}
+
+int QNetmaskAddress::prefixLength() const
+{
+ return length;
+}
+
+void QNetmaskAddress::setPrefixLength(QAbstractSocket::NetworkLayerProtocol proto, int newLength)
+{
+ length = newLength;
+ if (length < 0 || length > (proto == QAbstractSocket::IPv4Protocol ? 32 :
+ proto == QAbstractSocket::IPv6Protocol ? 128 : -1)) {
+ // invalid information, reject
+ d->protocol = QAbstractSocket::UnknownNetworkLayerProtocol;
+ length = -1;
+ return;
+ }
+
+ d->protocol = proto;
+ if (d->protocol == QAbstractSocket::IPv4Protocol) {
+ if (length == 0) {
+ d->a = 0;
+ } else if (length == 32) {
+ d->a = quint32(0xffffffff);
+ } else {
+ d->a = quint32(0xffffffff) >> (32 - length) << (32 - length);
+ }
+ } else {
+ memset(d->a6.c, 0xFF, sizeof(d->a6));
+ clearBits(d->a6.c, length, 128);
+ }
+}
+
+/*!
+ \class QHostAddress
+ \brief The QHostAddress class provides an IP address.
+ \ingroup io
+ \inmodule QtNetwork
+
+ This class holds an IPv4 or IPv6 address in a platform- and
+ protocol-independent manner.
+
+ QHostAddress is normally used with the QTcpSocket, QTcpServer,
+ and QUdpSocket to connect to a host or to set up a server.
+
+ A host address is set with setAddress(), checked for its type
+ using isIPv4Address() or isIPv6Address(), and retrieved with
+ toIPv4Address(), toIPv6Address(), or toString().
+
+ The class also supports common predefined addresses: \l Null, \l
+ LocalHost, \l LocalHostIPv6, \l Broadcast, and \l Any.
+
+ \sa QTcpSocket, QTcpServer, QUdpSocket
+*/
+
+/*! \enum QHostAddress::SpecialAddress
+
+ \value Null The null address object. Equivalent to QHostAddress().
+ \value LocalHost The IPv4 localhost address. Equivalent to QHostAddress("127.0.0.1").
+ \value LocalHostIPv6 The IPv6 localhost address. Equivalent to QHostAddress("::1").
+ \value Broadcast The IPv4 broadcast address. Equivalent to QHostAddress("255.255.255.255").
+ \value Any The IPv4 any-address. Equivalent to QHostAddress("0.0.0.0").
+ \value AnyIPv6 The IPv6 any-address. Equivalent to QHostAddress("::").
+*/
+
+/*! Constructs a host address object with the IP address 0.0.0.0.
+
+ \sa clear()
+*/
+QHostAddress::QHostAddress()
+ : d(new QHostAddressPrivate)
+{
+}
+
+/*!
+ Constructs a host address object with the IPv4 address \a ip4Addr.
+*/
+QHostAddress::QHostAddress(quint32 ip4Addr)
+ : d(new QHostAddressPrivate)
+{
+ setAddress(ip4Addr);
+}
+
+/*!
+ Constructs a host address object with the IPv6 address \a ip6Addr.
+
+ \a ip6Addr must be a 16-byte array in network byte order (big
+ endian).
+*/
+QHostAddress::QHostAddress(quint8 *ip6Addr)
+ : d(new QHostAddressPrivate)
+{
+ setAddress(ip6Addr);
+}
+
+/*!
+ Constructs a host address object with the IPv6 address \a ip6Addr.
+*/
+QHostAddress::QHostAddress(const Q_IPV6ADDR &ip6Addr)
+ : d(new QHostAddressPrivate)
+{
+ setAddress(ip6Addr);
+}
+
+/*!
+ Constructs an IPv4 or IPv6 address based on the string \a address
+ (e.g., "127.0.0.1").
+
+ \sa setAddress()
+*/
+QHostAddress::QHostAddress(const QString &address)
+ : d(new QHostAddressPrivate)
+{
+ d->ipString = address;
+ d->isParsed = false;
+}
+
+/*!
+ \fn QHostAddress::QHostAddress(const sockaddr *sockaddr)
+
+ Constructs an IPv4 or IPv6 address using the address specified by
+ the native structure \a sockaddr.
+
+ \sa setAddress()
+*/
+QHostAddress::QHostAddress(const struct sockaddr *sockaddr)
+ : d(new QHostAddressPrivate)
+{
+ if (sockaddr->sa_family == AF_INET)
+ setAddress(htonl(((sockaddr_in *)sockaddr)->sin_addr.s_addr));
+#ifndef QT_NO_IPV6
+ else if (sockaddr->sa_family == AF_INET6)
+ setAddress(((qt_sockaddr_in6 *)sockaddr)->sin6_addr.qt_s6_addr);
+#endif
+}
+
+/*!
+ Constructs a copy of the given \a address.
+*/
+QHostAddress::QHostAddress(const QHostAddress &address)
+ : d(new QHostAddressPrivate(*address.d))
+{
+}
+
+/*!
+ Constructs a QHostAddress object for \a address.
+*/
+QHostAddress::QHostAddress(SpecialAddress address)
+ : d(new QHostAddressPrivate)
+{
+ switch (address) {
+ case Null:
+ break;
+ case Broadcast:
+ setAddress(QLatin1String("255.255.255.255"));
+ break;
+ case LocalHost:
+ setAddress(QLatin1String("127.0.0.1"));
+ break;
+ case LocalHostIPv6:
+ setAddress(QLatin1String("::1"));
+ break;
+ case Any:
+ setAddress(QLatin1String("0.0.0.0"));
+ break;
+ case AnyIPv6:
+ setAddress(QLatin1String("::"));
+ break;
+ }
+}
+
+/*!
+ Destroys the host address object.
+*/
+QHostAddress::~QHostAddress()
+{
+ delete d;
+}
+
+/*!
+ Assigns another host \a address to this object, and returns a reference
+ to this object.
+*/
+QHostAddress &QHostAddress::operator=(const QHostAddress &address)
+{
+ *d = *address.d;
+ return *this;
+}
+
+/*!
+ Assigns the host address \a address to this object, and returns a
+ reference to this object.
+
+ \sa setAddress()
+*/
+QHostAddress &QHostAddress::operator=(const QString &address)
+{
+ setAddress(address);
+ return *this;
+}
+
+/*!
+ \fn bool QHostAddress::operator!=(const QHostAddress &other) const
+ \since 4.2
+
+ Returns true if this host address is not the same as the \a other
+ address given; otherwise returns false.
+*/
+
+/*!
+ \fn bool QHostAddress::operator!=(SpecialAddress other) const
+
+ Returns true if this host address is not the same as the \a other
+ address given; otherwise returns false.
+*/
+
+/*!
+ Sets the host address to 0.0.0.0.
+*/
+void QHostAddress::clear()
+{
+ d->clear();
+}
+
+/*!
+ Set the IPv4 address specified by \a ip4Addr.
+*/
+void QHostAddress::setAddress(quint32 ip4Addr)
+{
+ d->setAddress(ip4Addr);
+}
+
+/*!
+ \overload
+
+ Set the IPv6 address specified by \a ip6Addr.
+
+ \a ip6Addr must be an array of 16 bytes in network byte order
+ (high-order byte first).
+*/
+void QHostAddress::setAddress(quint8 *ip6Addr)
+{
+ d->setAddress(ip6Addr);
+}
+
+/*!
+ \overload
+
+ Set the IPv6 address specified by \a ip6Addr.
+*/
+void QHostAddress::setAddress(const Q_IPV6ADDR &ip6Addr)
+{
+ d->setAddress(ip6Addr);
+}
+
+/*!
+ \overload
+
+ Sets the IPv4 or IPv6 address specified by the string
+ representation specified by \a address (e.g. "127.0.0.1").
+ Returns true and sets the address if the address was successfully
+ parsed; otherwise returns false.
+*/
+bool QHostAddress::setAddress(const QString &address)
+{
+ d->ipString = address;
+ return d->parse();
+}
+
+/*!
+ \fn void QHostAddress::setAddress(const sockaddr *sockaddr)
+ \overload
+
+ Sets the IPv4 or IPv6 address specified by the native structure \a
+ sockaddr. Returns true and sets the address if the address was
+ successfully parsed; otherwise returns false.
+*/
+void QHostAddress::setAddress(const struct sockaddr *sockaddr)
+{
+ clear();
+ if (sockaddr->sa_family == AF_INET)
+ setAddress(htonl(((sockaddr_in *)sockaddr)->sin_addr.s_addr));
+#ifndef QT_NO_IPV6
+ else if (sockaddr->sa_family == AF_INET6)
+ setAddress(((qt_sockaddr_in6 *)sockaddr)->sin6_addr.qt_s6_addr);
+#endif
+}
+
+/*!
+ Returns the IPv4 address as a number.
+
+ For example, if the address is 127.0.0.1, the returned value is
+ 2130706433 (i.e. 0x7f000001).
+
+ This value is only valid if isIp4Addr() returns true.
+
+ \sa toString()
+*/
+quint32 QHostAddress::toIPv4Address() const
+{
+ QT_ENSURE_PARSED(this);
+ return d->a;
+}
+
+/*!
+ Returns the network layer protocol of the host address.
+*/
+QAbstractSocket::NetworkLayerProtocol QHostAddress::protocol() const
+{
+ QT_ENSURE_PARSED(this);
+ return d->protocol;
+}
+
+/*!
+ Returns the IPv6 address as a Q_IPV6ADDR structure. The structure
+ consists of 16 unsigned characters.
+
+ \snippet doc/src/snippets/code/src_network_kernel_qhostaddress.cpp 0
+
+ This value is only valid if isIPv6Address() returns true.
+
+ \sa toString()
+*/
+Q_IPV6ADDR QHostAddress::toIPv6Address() const
+{
+ QT_ENSURE_PARSED(this);
+ return d->a6;
+}
+
+/*!
+ Returns the address as a string.
+
+ For example, if the address is the IPv4 address 127.0.0.1, the
+ returned string is "127.0.0.1".
+
+ \sa toIPv4Address()
+*/
+QString QHostAddress::toString() const
+{
+ QT_ENSURE_PARSED(this);
+ if (d->protocol == QAbstractSocket::IPv4Protocol) {
+ quint32 i = toIPv4Address();
+ QString s;
+ s.sprintf("%d.%d.%d.%d", (i>>24) & 0xff, (i>>16) & 0xff,
+ (i >> 8) & 0xff, i & 0xff);
+ return s;
+ }
+
+ if (d->protocol == QAbstractSocket::IPv6Protocol) {
+ quint16 ugle[8];
+ for (int i = 0; i < 8; i++) {
+ ugle[i] = (quint16(d->a6[2*i]) << 8) | quint16(d->a6[2*i+1]);
+ }
+ QString s;
+ s.sprintf("%X:%X:%X:%X:%X:%X:%X:%X",
+ ugle[0], ugle[1], ugle[2], ugle[3], ugle[4], ugle[5], ugle[6], ugle[7]);
+ if (!d->scopeId.isEmpty())
+ s.append(QLatin1Char('%') + d->scopeId);
+ return s;
+ }
+
+ return QString();
+}
+
+/*!
+ \since 4.1
+
+ Returns the scope ID of an IPv6 address. For IPv4 addresses, or if the
+ address does not contain a scope ID, an empty QString is returned.
+
+ The IPv6 scope ID specifies the scope of \e reachability for non-global
+ IPv6 addresses, limiting the area in which the address can be used. All
+ IPv6 addresses are associated with such a reachability scope. The scope ID
+ is used to disambiguate addresses that are not guaranteed to be globally
+ unique.
+
+ IPv6 specifies the following four levels of reachability:
+
+ \list
+
+ \o Node-local: Addresses that are only used for communicating with
+ services on the same interface (e.g., the loopback interface "::1").
+
+ \o Link-local: Addresses that are local to the network interface
+ (\e{link}). There is always one link-local address for each IPv6 interface
+ on your host. Link-local addresses ("fe80...") are generated from the MAC
+ address of the local network adaptor, and are not guaranteed to be unique.
+
+ \o Site-local: Addresses that are local to the site / private network
+ (e.g., the company intranet). Site-local addresses ("fec0...") are
+ usually distributed by the site router, and are not guaranteed to be
+ unique outside of the local site.
+
+ \o Global: For globally routable addresses, such as public servers on the
+ Internet.
+
+ \endlist
+
+ When using a link-local or site-local address for IPv6 connections, you
+ must specify the scope ID. The scope ID for a link-local address is
+ usually the same as the interface name (e.g., "eth0", "en1") or number
+ (e.g., "1", "2").
+
+ \sa setScopeId()
+*/
+QString QHostAddress::scopeId() const
+{
+ QT_ENSURE_PARSED(this);
+ return (d->protocol == QAbstractSocket::IPv6Protocol) ? d->scopeId : QString();
+}
+
+/*!
+ \since 4.1
+
+ Sets the IPv6 scope ID of the address to \a id. If the address
+ protocol is not IPv6, this function does nothing.
+*/
+void QHostAddress::setScopeId(const QString &id)
+{
+ QT_ENSURE_PARSED(this);
+ if (d->protocol == QAbstractSocket::IPv6Protocol)
+ d->scopeId = id;
+}
+
+/*!
+ Returns true if this host address is the same as the \a other address
+ given; otherwise returns false.
+*/
+bool QHostAddress::operator==(const QHostAddress &other) const
+{
+ QT_ENSURE_PARSED(this);
+ QT_ENSURE_PARSED(&other);
+
+ if (d->protocol == QAbstractSocket::IPv4Protocol)
+ return other.d->protocol == QAbstractSocket::IPv4Protocol && d->a == other.d->a;
+ if (d->protocol == QAbstractSocket::IPv6Protocol) {
+ return other.d->protocol == QAbstractSocket::IPv6Protocol
+ && memcmp(&d->a6, &other.d->a6, sizeof(Q_IPV6ADDR)) == 0;
+ }
+ return d->protocol == other.d->protocol;
+}
+
+/*!
+ Returns true if this host address is the same as the \a other
+ address given; otherwise returns false.
+*/
+bool QHostAddress::operator ==(SpecialAddress other) const
+{
+ QT_ENSURE_PARSED(this);
+ QHostAddress otherAddress(other);
+ QT_ENSURE_PARSED(&otherAddress);
+
+ if (d->protocol == QAbstractSocket::IPv4Protocol)
+ return otherAddress.d->protocol == QAbstractSocket::IPv4Protocol && d->a == otherAddress.d->a;
+ if (d->protocol == QAbstractSocket::IPv6Protocol) {
+ return otherAddress.d->protocol == QAbstractSocket::IPv6Protocol
+ && memcmp(&d->a6, &otherAddress.d->a6, sizeof(Q_IPV6ADDR)) == 0;
+ }
+ return int(other) == int(Null);
+}
+
+/*!
+ Returns true if this host address is null (INADDR_ANY or in6addr_any).
+ The default constructor creates a null address, and that address is
+ not valid for any host or interface.
+*/
+bool QHostAddress::isNull() const
+{
+ QT_ENSURE_PARSED(this);
+ return d->protocol == QAbstractSocket::UnknownNetworkLayerProtocol;
+}
+
+/*!
+ \fn quint32 QHostAddress::ip4Addr() const
+
+ Use toIPv4Address() instead.
+*/
+
+/*!
+ \fn bool QHostAddress::isIp4Addr() const
+
+ Use protocol() instead.
+*/
+
+/*!
+ \fn bool QHostAddress::isIPv4Address() const
+
+ Use protocol() instead.
+*/
+
+/*!
+ \fn bool QHostAddress::isIPv6Address() const
+
+ Use protocol() instead.
+*/
+
+/*!
+ \since 4.5
+
+ Returns true if this IP is in the subnet described by the network
+ prefix \a subnet and netmask \a netmask.
+
+ An IP is considered to belong to a subnet if it is contained
+ between the lowest and the highest address in that subnet. In the
+ case of IP version 4, the lowest address is the network address,
+ while the highest address is the broadcast address.
+
+ The \a subnet argument does not have to be the actual network
+ address (the lowest address in the subnet). It can be any valid IP
+ belonging to that subnet. In particular, if it is equal to the IP
+ address held by this object, this function will always return true
+ (provided the netmask is a valid value).
+
+ \sa parseSubnet()
+*/
+bool QHostAddress::isInSubnet(const QHostAddress &subnet, int netmask) const
+{
+ QT_ENSURE_PARSED(this);
+ if (subnet.protocol() != d->protocol || netmask < 0)
+ return false;
+
+ union {
+ quint32 ip;
+ quint8 data[4];
+ } ip4, net4;
+ const quint8 *ip;
+ const quint8 *net;
+ if (d->protocol == QAbstractSocket::IPv4Protocol) {
+ if (netmask > 32)
+ netmask = 32;
+ ip4.ip = qToBigEndian(d->a);
+ net4.ip = qToBigEndian(subnet.d->a);
+ ip = ip4.data;
+ net = net4.data;
+ } else if (d->protocol == QAbstractSocket::IPv6Protocol) {
+ if (netmask > 128)
+ netmask = 128;
+ ip = d->a6.c;
+ net = subnet.d->a6.c;
+ } else {
+ return false;
+ }
+
+ if (netmask >= 8 && memcmp(ip, net, netmask / 8) != 0)
+ return false;
+ if ((netmask & 7) == 0)
+ return true;
+
+ // compare the last octet now
+ quint8 bytemask = 256 - (1 << (8 - (netmask & 7)));
+ quint8 ipbyte = ip[netmask / 8];
+ quint8 netbyte = net[netmask / 8];
+ return (ipbyte & bytemask) == (netbyte & bytemask);
+}
+
+/*!
+ \since 4.5
+ \overload
+
+ Returns true if this IP is in the subnet described by \a
+ subnet. The QHostAddress member of \a subnet contains the network
+ prefix and the int (second) member contains the netmask (prefix
+ length).
+*/
+bool QHostAddress::isInSubnet(const QPair<QHostAddress, int> &subnet) const
+{
+ return isInSubnet(subnet.first, subnet.second);
+}
+
+
+/*!
+ \since 4.5
+
+ Parses the IP and subnet information contained in \a subnet and
+ returns the network prefix for that network and its prefix length.
+
+ The IP address and the netmask must be separated by a slash
+ (/).
+
+ This function supports arguments in the form:
+ \list
+ \o 123.123.123.123/n where n is any value between 0 and 32
+ \o 123.123.123.123/255.255.255.255
+ \o <ipv6-address>/n where n is any value between 0 and 128
+ \endlist
+
+ For IP version 4, this function accepts as well missing trailing
+ components (i.e., less than 4 octets, like "192.168.1"), followed
+ or not by a dot. If the netmask is also missing in that case, it
+ is set to the number of octets actually passed (in the example
+ above, it would be 24, for 3 octets).
+
+ \sa isInSubnet()
+*/
+QPair<QHostAddress, int> QHostAddress::parseSubnet(const QString &subnet)
+{
+ // We support subnets in the form:
+ // ddd.ddd.ddd.ddd/nn
+ // ddd.ddd.ddd/nn
+ // ddd.ddd/nn
+ // ddd/nn
+ // ddd.ddd.ddd.
+ // ddd.ddd.ddd
+ // ddd.ddd.
+ // ddd.ddd
+ // ddd.
+ // ddd
+ // <ipv6-address>/nn
+ //
+ // where nn can be an IPv4-style netmask for the IPv4 forms
+
+ const QPair<QHostAddress, int> invalid = qMakePair(QHostAddress(), -1);
+ if (subnet.isEmpty())
+ return invalid;
+
+ int slash = subnet.indexOf(QLatin1Char('/'));
+ QString netStr = subnet;
+ if (slash != -1)
+ netStr.truncate(slash);
+
+ int netmask = -1;
+ bool isIpv6 = netStr.contains(QLatin1Char(':'));
+
+ if (slash != -1) {
+ // is the netmask given in IP-form or in bit-count form?
+ if (!isIpv6 && subnet.indexOf(QLatin1Char('.'), slash + 1) != -1) {
+ // IP-style, convert it to bit-count form
+ QNetmaskAddress parser;
+ if (!parser.setAddress(subnet.mid(slash + 1)))
+ return invalid;
+ netmask = parser.prefixLength();
+ } else {
+ bool ok;
+ netmask = subnet.mid(slash + 1).toUInt(&ok);
+ if (!ok)
+ return invalid; // failed to parse the subnet
+ }
+ }
+
+ if (isIpv6) {
+ // looks like it's an IPv6 address
+ if (netmask > 128)
+ return invalid; // invalid netmask
+ if (netmask < 0)
+ netmask = 128;
+
+ QHostAddress net;
+ if (!net.setAddress(netStr))
+ return invalid; // failed to parse the IP
+
+ clearBits(net.d->a6.c, netmask, 128);
+ return qMakePair(net, netmask);
+ }
+
+ if (netmask > 32)
+ return invalid; // invalid netmask
+
+ // parse the address manually
+ QStringList parts = netStr.split(QLatin1Char('.'));
+ if (parts.isEmpty() || parts.count() > 4)
+ return invalid; // invalid IPv4 address
+
+ if (parts.last().isEmpty())
+ parts.removeLast();
+
+ quint32 addr = 0;
+ for (int i = 0; i < parts.count(); ++i) {
+ bool ok;
+ uint byteValue = parts.at(i).toUInt(&ok);
+ if (!ok || byteValue > 255)
+ return invalid; // invalid IPv4 address
+
+ addr <<= 8;
+ addr += byteValue;
+ }
+ addr <<= 8 * (4 - parts.count());
+ if (netmask == -1) {
+ netmask = 8 * parts.count();
+ } else if (netmask == 0) {
+ // special case here
+ // x86's instructions "shr" and "shl" do not operate when
+ // their argument is 32, so the code below doesn't work as expected
+ addr = 0;
+ } else if (netmask != 32) {
+ // clear remaining bits
+ quint32 mask = quint32(0xffffffff) >> (32 - netmask) << (32 - netmask);
+ addr &= mask;
+ }
+
+ return qMakePair(QHostAddress(addr), netmask);
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const QHostAddress &address)
+{
+ d.maybeSpace() << "QHostAddress(" << address.toString() << ")";
+ return d.space();
+}
+#endif
+
+uint qHash(const QHostAddress &key)
+{
+ return qHash(key.toString());
+}
+
+#ifndef QT_NO_DATASTREAM
+
+/*! \relates QHostAddress
+
+ Writes host address \a address to the stream \a out and returns a reference
+ to the stream.
+
+ \sa {Format of the QDataStream operators}
+*/
+QDataStream &operator<<(QDataStream &out, const QHostAddress &address)
+{
+ qint8 prot;
+ prot = qint8(address.protocol());
+ out << prot;
+ switch (address.protocol()) {
+ case QAbstractSocket::UnknownNetworkLayerProtocol:
+ break;
+ case QAbstractSocket::IPv4Protocol:
+ out << address.toIPv4Address();
+ break;
+ case QAbstractSocket::IPv6Protocol:
+ {
+ Q_IPV6ADDR ipv6 = address.toIPv6Address();
+ for (int i = 0; i < 16; ++i)
+ out << ipv6[i];
+ out << address.scopeId();
+ }
+ break;
+ }
+ return out;
+}
+
+/*! \relates QHostAddress
+
+ Reads a host address into \a address from the stream \a in and returns a
+ reference to the stream.
+
+ \sa {Format of the QDataStream operators}
+*/
+QDataStream &operator>>(QDataStream &in, QHostAddress &address)
+{
+ qint8 prot;
+ in >> prot;
+ switch (QAbstractSocket::NetworkLayerProtocol(prot)) {
+ case QAbstractSocket::UnknownNetworkLayerProtocol:
+ address.clear();
+ break;
+ case QAbstractSocket::IPv4Protocol:
+ {
+ quint32 ipv4;
+ in >> ipv4;
+ address.setAddress(ipv4);
+ }
+ break;
+ case QAbstractSocket::IPv6Protocol:
+ {
+ Q_IPV6ADDR ipv6;
+ for (int i = 0; i < 16; ++i)
+ in >> ipv6[i];
+ address.setAddress(ipv6);
+
+ QString scope;
+ in >> scope;
+ address.setScopeId(scope);
+ }
+ break;
+ default:
+ address.clear();
+ in.setStatus(QDataStream::ReadCorruptData);
+ }
+ return in;
+}
+
+#endif //QT_NO_DATASTREAM
+
+QT_END_NAMESPACE
diff --git a/src/network/kernel/qhostaddress.h b/src/network/kernel/qhostaddress.h
new file mode 100644
index 0000000..02a6f97
--- /dev/null
+++ b/src/network/kernel/qhostaddress.h
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QHOSTADDRESS_H
+#define QHOSTADDRESS_H
+
+#include <QtCore/qpair.h>
+#include <QtCore/qstring.h>
+#include <QtNetwork/qabstractsocket.h>
+
+struct sockaddr;
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Network)
+
+class QHostAddressPrivate;
+
+class Q_NETWORK_EXPORT QIPv6Address
+{
+public:
+ inline quint8 &operator [](int index) { return c[index]; }
+ inline quint8 operator [](int index) const { return c[index]; }
+ quint8 c[16];
+};
+
+typedef QIPv6Address Q_IPV6ADDR;
+
+class Q_NETWORK_EXPORT QHostAddress
+{
+public:
+ enum SpecialAddress {
+ Null,
+ Broadcast,
+ LocalHost,
+ LocalHostIPv6,
+ Any,
+ AnyIPv6
+ };
+
+ QHostAddress();
+ explicit QHostAddress(quint32 ip4Addr);
+ explicit QHostAddress(quint8 *ip6Addr);
+ explicit QHostAddress(const Q_IPV6ADDR &ip6Addr);
+ explicit QHostAddress(const sockaddr *sockaddr);
+ explicit QHostAddress(const QString &address);
+ QHostAddress(const QHostAddress &copy);
+ QHostAddress(SpecialAddress address);
+ ~QHostAddress();
+
+ QHostAddress &operator=(const QHostAddress &other);
+ QHostAddress &operator=(const QString &address);
+
+ void setAddress(quint32 ip4Addr);
+ void setAddress(quint8 *ip6Addr);
+ void setAddress(const Q_IPV6ADDR &ip6Addr);
+ void setAddress(const sockaddr *sockaddr);
+ bool setAddress(const QString &address);
+
+ QAbstractSocket::NetworkLayerProtocol protocol() const;
+ quint32 toIPv4Address() const;
+ Q_IPV6ADDR toIPv6Address() const;
+
+ QString toString() const;
+
+ QString scopeId() const;
+ void setScopeId(const QString &id);
+
+ bool operator ==(const QHostAddress &address) const;
+ bool operator ==(SpecialAddress address) const;
+ inline bool operator !=(const QHostAddress &address) const
+ { return !operator==(address); }
+ inline bool operator !=(SpecialAddress address) const
+ { return !operator==(address); }
+ bool isNull() const;
+ void clear();
+
+#ifdef QT3_SUPPORT
+ inline QT3_SUPPORT quint32 ip4Addr() const { return toIPv4Address(); }
+ inline QT3_SUPPORT bool isIPv4Address() const { return protocol() == QAbstractSocket::IPv4Protocol
+ || protocol() == QAbstractSocket::UnknownNetworkLayerProtocol; }
+ inline QT3_SUPPORT bool isIp4Addr() const { return protocol() == QAbstractSocket::IPv4Protocol
+ || protocol() == QAbstractSocket::UnknownNetworkLayerProtocol; }
+ inline QT3_SUPPORT bool isIPv6Address() const { return protocol() == QAbstractSocket::IPv6Protocol; }
+#endif
+
+ bool isInSubnet(const QHostAddress &subnet, int netmask) const;
+ bool isInSubnet(const QPair<QHostAddress, int> &subnet) const;
+
+ static QPair<QHostAddress, int> parseSubnet(const QString &subnet);
+
+protected:
+ QHostAddressPrivate *d;
+};
+
+inline bool operator ==(QHostAddress::SpecialAddress address1, const QHostAddress &address2)
+{ return address2 == address1; }
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_NETWORK_EXPORT QDebug operator<<(QDebug, const QHostAddress &);
+#endif
+
+
+Q_NETWORK_EXPORT uint qHash(const QHostAddress &key);
+
+#ifndef QT_NO_DATASTREAM
+Q_NETWORK_EXPORT QDataStream &operator<<(QDataStream &, const QHostAddress &);
+Q_NETWORK_EXPORT QDataStream &operator>>(QDataStream &, QHostAddress &);
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+#endif // QHOSTADDRESS_H
diff --git a/src/network/kernel/qhostaddress_p.h b/src/network/kernel/qhostaddress_p.h
new file mode 100644
index 0000000..e6634b7
--- /dev/null
+++ b/src/network/kernel/qhostaddress_p.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QHOSTADDRESSPRIVATE_H
+#define QHOSTADDRESSPRIVATE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QHostAddress and QNetworkInterface classes. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+#include "qhostaddress.h"
+#include "qabstractsocket.h"
+
+class QNetmaskAddress: public QHostAddress
+{
+ int length;
+public:
+ QNetmaskAddress() : QHostAddress(), length(-1) { }
+
+ bool setAddress(const QString &address);
+ bool setAddress(const QHostAddress &address);
+
+ int prefixLength() const;
+ void setPrefixLength(QAbstractSocket::NetworkLayerProtocol proto, int len);
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/network/kernel/qhostinfo.cpp b/src/network/kernel/qhostinfo.cpp
new file mode 100644
index 0000000..ca4124d
--- /dev/null
+++ b/src/network/kernel/qhostinfo.cpp
@@ -0,0 +1,479 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qhostinfo.h"
+#include "qhostinfo_p.h"
+
+#include <qabstracteventdispatcher.h>
+#include <private/qunicodetables_p.h>
+#include <qcoreapplication.h>
+#include <qmetaobject.h>
+#include <qregexp.h>
+#include <private/qnativesocketengine_p.h>
+#include <qstringlist.h>
+#include <qthread.h>
+#include <qtimer.h>
+#include <qurl.h>
+
+#ifdef Q_OS_UNIX
+# include <unistd.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(QHostInfoAgent, theAgent)
+void QHostInfoAgent::staticCleanup()
+{
+ theAgent()->cleanup();
+}
+
+//#define QHOSTINFO_DEBUG
+
+/*!
+ \class QHostInfo
+ \brief The QHostInfo class provides static functions for host name lookups.
+
+ \reentrant
+ \inmodule QtNetwork
+ \ingroup io
+
+ QHostInfo uses the lookup mechanisms provided by the operating
+ system to find the IP address(es) associated with a host name,
+ or the host name associated with an IP address.
+ The class provides two static convenience functions: one that
+ works asynchronously and emits a signal once the host is found,
+ and one that blocks and returns a QHostInfo object.
+
+ To look up a host's IP addresses asynchronously, call lookupHost(),
+ which takes the host name or IP address, a receiver object, and a slot
+ signature as arguments and returns an ID. You can abort the
+ lookup by calling abortHostLookup() with the lookup ID.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_network_kernel_qhostinfo.cpp 0
+
+
+ The slot is invoked when the results are ready. (If you use
+ Qt for Embedded Linux and disabled multithreading support by defining
+ \c QT_NO_THREAD, lookupHost() will block until the lookup has
+ finished.) The results are stored in a QHostInfo object. Call
+ addresses() to get the list of IP addresses for the host, and
+ hostName() to get the host name that was looked up.
+
+ If the lookup failed, error() returns the type of error that
+ occurred. errorString() gives a human-readable description of the
+ lookup error.
+
+ If you want a blocking lookup, use the QHostInfo::fromName() function:
+
+ \snippet doc/src/snippets/code/src_network_kernel_qhostinfo.cpp 1
+
+ QHostInfo supports Internationalized Domain Names (IDNs) through the
+ IDNA and Punycode standards.
+
+ To retrieve the name of the local host, use the static
+ QHostInfo::localHostName() function.
+
+ \sa QAbstractSocket, {http://www.rfc-editor.org/rfc/rfc3492.txt}{RFC 3492}
+*/
+
+static QBasicAtomicInt theIdCounter = Q_BASIC_ATOMIC_INITIALIZER(1);
+
+/*!
+ Looks up the IP address(es) associated with host name \a name, and
+ returns an ID for the lookup. When the result of the lookup is
+ ready, the slot or signal \a member in \a receiver is called with
+ a QHostInfo argument. The QHostInfo object can then be inspected
+ to get the results of the lookup.
+
+ The lookup is performed by a single function call, for example:
+
+ \snippet doc/src/snippets/code/src_network_kernel_qhostinfo.cpp 2
+
+ The implementation of the slot prints basic information about the
+ addresses returned by the lookup, or reports an error if it failed:
+
+ \snippet doc/src/snippets/code/src_network_kernel_qhostinfo.cpp 3
+
+ If you pass a literal IP address to \a name instead of a host name,
+ QHostInfo will search for the domain name for the IP (i.e., QHostInfo will
+ perform a \e reverse lookup). On success, the resulting QHostInfo will
+ contain both the resolved domain name and IP addresses for the host
+ name. Example:
+
+ \snippet doc/src/snippets/code/src_network_kernel_qhostinfo.cpp 4
+
+ \sa abortHostLookup(), addresses(), error(), fromName()
+*/
+int QHostInfo::lookupHost(const QString &name, QObject *receiver,
+ const char *member)
+{
+#if defined QHOSTINFO_DEBUG
+ qDebug("QHostInfo::lookupHost(\"%s\", %p, %s)",
+ name.toLatin1().constData(), receiver, member ? member + 1 : 0);
+#endif
+ if (!QAbstractEventDispatcher::instance(QThread::currentThread())) {
+ qWarning("QHostInfo::lookupHost() called with no event dispatcher");
+ return -1;
+ }
+
+ qRegisterMetaType<QHostInfo>("QHostInfo");
+
+#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
+ QWindowsSockInit bust; // makes sure WSAStartup was callled
+#endif
+
+ // Support for IDNA
+ QString lookup = QString::fromLatin1(QUrl::toAce(name));
+
+ QHostInfoResult *result = new QHostInfoResult;
+ result->autoDelete = false;
+ QObject::connect(result, SIGNAL(resultsReady(QHostInfo)),
+ receiver, member);
+ int id = result->lookupId = theIdCounter.fetchAndAddRelaxed(1);
+
+ if (lookup.isEmpty()) {
+ QHostInfo info(id);
+ info.setError(QHostInfo::HostNotFound);
+ info.setErrorString(QObject::tr("No host name given"));
+ QMetaObject::invokeMethod(result, "emitResultsReady", Qt::QueuedConnection,
+ Q_ARG(QHostInfo, info));
+ result->autoDelete = true;
+ return id;
+ }
+
+ QHostInfoAgent *agent = theAgent();
+ agent->addHostName(lookup, result);
+
+#if !defined QT_NO_THREAD
+ if (!agent->isRunning())
+ agent->start();
+#else
+// if (!agent->isRunning())
+ agent->run();
+// else
+// agent->wakeOne();
+#endif
+ return id;
+}
+
+/*!
+ Aborts the host lookup with the ID \a id, as returned by lookupHost().
+
+ \sa lookupHost(), lookupId()
+*/
+void QHostInfo::abortHostLookup(int id)
+{
+ QHostInfoAgent *agent = theAgent();
+ agent->abortLookup(id);
+}
+
+/*!
+ Looks up the IP address(es) for the given host \a name. The
+ function blocks during the lookup which means that execution of
+ the program is suspended until the results of the lookup are
+ ready. Returns the result of the lookup in a QHostInfo object.
+
+ If you pass a literal IP address to \a name instead of a host name,
+ QHostInfo will search for the domain name for the IP (i.e., QHostInfo will
+ perform a \e reverse lookup). On success, the returned QHostInfo will
+ contain both the resolved domain name and IP addresses for the host name.
+
+ \sa lookupHost()
+*/
+QHostInfo QHostInfo::fromName(const QString &name)
+{
+#if defined QHOSTINFO_DEBUG
+ qDebug("QHostInfo::fromName(\"%s\")",name.toLatin1().constData());
+#endif
+
+ if (!name.isEmpty())
+ return QHostInfoAgent::fromName(QLatin1String(QUrl::toAce(name)));
+
+ QHostInfo retval;
+ retval.d->err = HostNotFound;
+ retval.d->errorStr = QObject::tr("No host name given");
+ return retval;
+}
+
+/*!
+ \internal
+ Pops a query off the queries list, performs a blocking call to
+ QHostInfoAgent::lookupHost(), and emits the resultsReady()
+ signal. This process repeats until the queries list is empty.
+*/
+void QHostInfoAgent::run()
+{
+#ifndef QT_NO_THREAD
+ // Dont' allow thread termination during event delivery, but allow it
+ // during the actual blocking host lookup stage.
+ setTerminationEnabled(false);
+ forever
+#endif
+ {
+ QHostInfoQuery *query;
+ {
+#ifndef QT_NO_THREAD
+ // the queries list is shared between threads. lock all
+ // access to it.
+ QMutexLocker locker(&mutex);
+ if (!quit && queries.isEmpty())
+ cond.wait(&mutex);
+ if (quit) {
+ // Reset the quit variable in case QCoreApplication is
+ // destroyed and recreated.
+ quit = false;
+ break;
+ }
+ if (queries.isEmpty())
+ continue;
+#else
+ if (queries.isEmpty())
+ return;
+#endif
+ query = queries.takeFirst();
+ pendingQueryId = query->object->lookupId;
+ }
+
+#if defined(QHOSTINFO_DEBUG)
+ qDebug("QHostInfoAgent::run(%p): looking up \"%s\"", this,
+ query->hostName.toLatin1().constData());
+#endif
+
+#ifndef QT_NO_THREAD
+ // Start query - allow termination at this point, but not outside. We
+ // don't want to all termination during event delivery, but we don't
+ // want the lookup to prevent the app from quitting (the agent
+ // destructor terminates the thread).
+ setTerminationEnabled(true);
+#endif
+ QHostInfo info = fromName(query->hostName);
+#ifndef QT_NO_THREAD
+ setTerminationEnabled(false);
+#endif
+
+ int id = query->object->lookupId;
+ info.setLookupId(id);
+ if (pendingQueryId == id)
+ query->object->emitResultsReady(info);
+ delete query;
+ }
+}
+
+/*!
+ \enum QHostInfo::HostInfoError
+
+ This enum describes the various errors that can occur when trying
+ to resolve a host name.
+
+ \value NoError The lookup was successful.
+ \value HostNotFound No IP addresses were found for the host.
+ \value UnknownError An unknown error occurred.
+
+ \sa error(), setError()
+*/
+
+/*!
+ Constructs an empty host info object with lookup ID \a id.
+
+ \sa lookupId()
+*/
+QHostInfo::QHostInfo(int id)
+ : d(new QHostInfoPrivate)
+{
+ d->lookupId = id;
+}
+
+/*!
+ Constructs a copy of \a other.
+*/
+QHostInfo::QHostInfo(const QHostInfo &other)
+ : d(new QHostInfoPrivate(*other.d))
+{
+}
+
+/*!
+ Assigns the data of the \a other object to this host info object,
+ and returns a reference to it.
+*/
+QHostInfo &QHostInfo::operator=(const QHostInfo &other)
+{
+ *d = *other.d;
+ return *this;
+}
+
+/*!
+ Destroys the host info object.
+*/
+QHostInfo::~QHostInfo()
+{
+ delete d;
+}
+
+/*!
+ Returns the list of IP addresses associated with hostName(). This
+ list may be empty.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_network_kernel_qhostinfo.cpp 5
+
+ \sa hostName(), error()
+*/
+QList<QHostAddress> QHostInfo::addresses() const
+{
+ return d->addrs;
+}
+
+/*!
+ Sets the list of addresses in this QHostInfo to \a addresses.
+
+ \sa addresses()
+*/
+void QHostInfo::setAddresses(const QList<QHostAddress> &addresses)
+{
+ d->addrs = addresses;
+}
+
+/*!
+ Returns the name of the host whose IP addresses were looked up.
+
+ \sa localHostName()
+*/
+QString QHostInfo::hostName() const
+{
+ return d->hostName;
+}
+
+/*!
+ Sets the host name of this QHostInfo to \a hostName.
+
+ \sa hostName()
+*/
+void QHostInfo::setHostName(const QString &hostName)
+{
+ d->hostName = hostName;
+}
+
+/*!
+ Returns the type of error that occurred if the host name lookup
+ failed; otherwise returns NoError.
+
+ \sa setError(), errorString()
+*/
+QHostInfo::HostInfoError QHostInfo::error() const
+{
+ return d->err;
+}
+
+/*!
+ Sets the error type of this QHostInfo to \a error.
+
+ \sa error(), errorString()
+*/
+void QHostInfo::setError(HostInfoError error)
+{
+ d->err = error;
+}
+
+/*!
+ Returns the ID of this lookup.
+
+ \sa setLookupId(), abortHostLookup(), hostName()
+*/
+int QHostInfo::lookupId() const
+{
+ return d->lookupId;
+}
+
+/*!
+ Sets the ID of this lookup to \a id.
+
+ \sa lookupId(), lookupHost()
+*/
+void QHostInfo::setLookupId(int id)
+{
+ d->lookupId = id;
+}
+
+/*!
+ If the lookup failed, this function returns a human readable
+ description of the error; otherwise "Unknown error" is returned.
+
+ \sa setErrorString(), error()
+*/
+QString QHostInfo::errorString() const
+{
+ return d->errorStr;
+}
+
+/*!
+ Sets the human readable description of the error that occurred to \a str
+ if the lookup failed.
+
+ \sa errorString(), setError()
+*/
+void QHostInfo::setErrorString(const QString &str)
+{
+ d->errorStr = str;
+}
+
+/*!
+ \fn QString QHostInfo::localHostName()
+
+ Returns the host name of this machine.
+
+ \sa hostName()
+*/
+
+/*!
+ \fn QString QHostInfo::localDomainName()
+
+ Returns the DNS domain of this machine.
+
+ Note: DNS domains are not related to domain names found in
+ Windows networks.
+
+ \sa hostName()
+*/
+
+QT_END_NAMESPACE
diff --git a/src/network/kernel/qhostinfo.h b/src/network/kernel/qhostinfo.h
new file mode 100644
index 0000000..084ec89
--- /dev/null
+++ b/src/network/kernel/qhostinfo.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QHOSTINFO_H
+#define QHOSTINFO_H
+
+#include <QtCore/qlist.h>
+#include <QtNetwork/qhostaddress.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Network)
+
+class QObject;
+class QHostInfoPrivate;
+
+class Q_NETWORK_EXPORT QHostInfo
+{
+public:
+ enum HostInfoError {
+ NoError,
+ HostNotFound,
+ UnknownError
+ };
+
+ QHostInfo(int lookupId = -1);
+ QHostInfo(const QHostInfo &d);
+ QHostInfo &operator=(const QHostInfo &d);
+ ~QHostInfo();
+
+ QString hostName() const;
+ void setHostName(const QString &name);
+
+ QList<QHostAddress> addresses() const;
+ void setAddresses(const QList<QHostAddress> &addresses);
+
+ HostInfoError error() const;
+ void setError(HostInfoError error);
+
+ QString errorString() const;
+ void setErrorString(const QString &errorString);
+
+ void setLookupId(int id);
+ int lookupId() const;
+
+ static int lookupHost(const QString &name, QObject *receiver, const char *member);
+ static void abortHostLookup(int lookupId);
+
+ static QHostInfo fromName(const QString &name);
+ static QString localHostName();
+ static QString localDomainName();
+
+private:
+ QHostInfoPrivate *d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QHOSTINFO_H
diff --git a/src/network/kernel/qhostinfo_p.h b/src/network/kernel/qhostinfo_p.h
new file mode 100644
index 0000000..1db00d3
--- /dev/null
+++ b/src/network/kernel/qhostinfo_p.h
@@ -0,0 +1,196 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QHOSTINFO_P_H
+#define QHOSTINFO_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "QtCore/qcoreapplication.h"
+#include "private/qcoreapplication_p.h"
+#include "QtNetwork/qhostinfo.h"
+#include "QtCore/qmutex.h"
+#include "QtCore/qwaitcondition.h"
+#include "QtCore/qobject.h"
+#include "QtCore/qpointer.h"
+
+#if !defined QT_NO_THREAD
+#include "QtCore/qthread.h"
+# define QHostInfoAgentBase QThread
+#else
+# define QHostInfoAgentBase QObject
+#endif
+
+QT_BEGIN_NAMESPACE
+
+static const int QHOSTINFO_THREAD_WAIT = 250; // ms
+
+class QHostInfoResult : public QObject
+{
+ Q_OBJECT
+public Q_SLOTS:
+ inline void emitResultsReady(const QHostInfo &info)
+ {
+ emit resultsReady(info);
+ if (autoDelete)
+ delete this;
+ }
+
+Q_SIGNALS:
+ void resultsReady(const QHostInfo &info);
+
+public:
+ int lookupId;
+ bool autoDelete;
+};
+
+struct QHostInfoQuery
+{
+ inline QHostInfoQuery() : object(0) {}
+ inline ~QHostInfoQuery() { delete object; }
+ inline QHostInfoQuery(const QString &name, QHostInfoResult *result)
+ : hostName(name), object(result) {}
+
+ QString hostName;
+ QHostInfoResult *object;
+};
+
+class QHostInfoAgent : public QHostInfoAgentBase
+{
+ Q_OBJECT
+public:
+ inline QHostInfoAgent()
+ {
+ // There is a chance that there will be two instances of
+ // QHostInfoAgent if two threads try to get Q_GLOBAL_STATIC
+ // object at the same time. The second object will be deleted
+ // immediately before anyone uses it, but we need to be
+ // careful about what we do in the constructor.
+ static QBasicAtomicInt done = Q_BASIC_ATOMIC_INITIALIZER(0);
+ if (done.testAndSetRelaxed(0, 1))
+ qAddPostRoutine(staticCleanup);
+ moveToThread(QCoreApplicationPrivate::mainThread());
+ quit = false;
+ pendingQueryId = -1;
+ }
+ inline ~QHostInfoAgent()
+ { cleanup(); }
+
+ void run();
+ static QHostInfo fromName(const QString &hostName);
+
+ inline void addHostName(const QString &name, QHostInfoResult *result)
+ {
+ QMutexLocker locker(&mutex);
+ queries << new QHostInfoQuery(name, result);
+ cond.wakeOne();
+ }
+
+ inline void abortLookup(int id)
+ {
+ QMutexLocker locker(&mutex);
+ for (int i = 0; i < queries.size(); ++i) {
+ QHostInfoResult *result = queries.at(i)->object;
+ if (result->lookupId == id) {
+ result->disconnect();
+ delete queries.takeAt(i);
+ return;
+ }
+ }
+ if (pendingQueryId == id)
+ pendingQueryId = -1;
+ }
+
+ static void staticCleanup();
+
+public Q_SLOTS:
+ inline void cleanup()
+ {
+ {
+ QMutexLocker locker(&mutex);
+ qDeleteAll(queries);
+ queries.clear();
+ quit = true;
+ cond.wakeOne();
+ }
+#ifndef QT_NO_THREAD
+ if (!wait(QHOSTINFO_THREAD_WAIT))
+ terminate();
+ wait();
+#endif
+ }
+
+private:
+ QList<QHostInfoQuery *> queries;
+ QMutex mutex;
+ QWaitCondition cond;
+ volatile bool quit;
+ int pendingQueryId;
+};
+
+class QHostInfoPrivate
+{
+public:
+ inline QHostInfoPrivate()
+ : err(QHostInfo::NoError),
+ errorStr(QLatin1String(QT_TRANSLATE_NOOP("QHostInfo", "Unknown error")))
+ {
+ }
+
+ QHostInfo::HostInfoError err;
+ QString errorStr;
+ QList<QHostAddress> addrs;
+ QString hostName;
+ int lookupId;
+};
+
+QT_END_NAMESPACE
+
+#endif // QHOSTINFO_P_H
diff --git a/src/network/kernel/qhostinfo_unix.cpp b/src/network/kernel/qhostinfo_unix.cpp
new file mode 100644
index 0000000..f987520
--- /dev/null
+++ b/src/network/kernel/qhostinfo_unix.cpp
@@ -0,0 +1,379 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QHOSTINFO_DEBUG
+
+static const int RESOLVER_TIMEOUT = 2000;
+
+#include "qplatformdefs.h"
+
+#include "qhostinfo_p.h"
+#include "qiodevice.h"
+#include <qbytearray.h>
+#include <qlibrary.h>
+#include <qurl.h>
+#include <qfile.h>
+#include <private/qmutexpool_p.h>
+
+extern "C" {
+#include <sys/types.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+}
+
+#if defined (QT_NO_GETADDRINFO)
+#include <qmutex.h>
+QT_BEGIN_NAMESPACE
+Q_GLOBAL_STATIC(QMutex, getHostByNameMutex)
+QT_END_NAMESPACE
+#endif
+
+QT_BEGIN_NAMESPACE
+
+// Almost always the same. If not, specify in qplatformdefs.h.
+#if !defined(QT_SOCKOPTLEN_T)
+# define QT_SOCKOPTLEN_T QT_SOCKLEN_T
+#endif
+
+// HP-UXi has a bug in getaddrinfo(3) that makes it thread-unsafe
+// with this flag. So disable it in that platform.
+#if defined(AI_ADDRCONFIG) && !defined(Q_OS_HPUX)
+# define Q_ADDRCONFIG AI_ADDRCONFIG
+#endif
+
+typedef struct __res_state *res_state_ptr;
+
+typedef int (*res_init_proto)(void);
+static res_init_proto local_res_init = 0;
+typedef int (*res_ninit_proto)(res_state_ptr);
+static res_ninit_proto local_res_ninit = 0;
+typedef void (*res_nclose_proto)(res_state_ptr);
+static res_nclose_proto local_res_nclose = 0;
+static res_state_ptr local_res = 0;
+
+static void resolveLibrary()
+{
+#ifndef QT_NO_LIBRARY
+ QLibrary lib(QLatin1String("resolv"));
+ if (!lib.load())
+ return;
+
+ local_res_init = res_init_proto(lib.resolve("__res_init"));
+ if (!local_res_init)
+ local_res_init = res_init_proto(lib.resolve("res_init"));
+
+ local_res_ninit = res_ninit_proto(lib.resolve("__res_ninit"));
+ if (!local_res_ninit)
+ local_res_ninit = res_ninit_proto(lib.resolve("res_ninit"));
+
+ if (!local_res_ninit) {
+ // if we can't get a thread-safe context, we have to use the global _res state
+ local_res = res_state_ptr(lib.resolve("_res"));
+ } else {
+ local_res_nclose = res_nclose_proto(lib.resolve("res_nclose"));
+ if (!local_res_nclose)
+ local_res_nclose = res_nclose_proto(lib.resolve("__res_nclose"));
+ if (!local_res_nclose)
+ local_res_ninit = 0;
+ }
+#endif
+}
+
+QHostInfo QHostInfoAgent::fromName(const QString &hostName)
+{
+ QHostInfo results;
+ results.setHostName(hostName);
+
+#if defined(QHOSTINFO_DEBUG)
+ qDebug("QHostInfoAgent::fromName(%s) looking up...",
+ hostName.toLatin1().constData());
+#endif
+
+ // Load res_init on demand.
+ static volatile bool triedResolve = false;
+ if (!triedResolve) {
+#ifndef QT_NO_THREAD
+ QMutexLocker locker(QMutexPool::globalInstanceGet(&local_res_init));
+#endif
+ if (!triedResolve) {
+ resolveLibrary();
+ triedResolve = true;
+ }
+ }
+
+ // If res_init is available, poll it.
+ if (local_res_init)
+ local_res_init();
+
+ QHostAddress address;
+ if (address.setAddress(hostName)) {
+ // Reverse lookup
+// Reverse lookups using getnameinfo are broken on darwin, use gethostbyaddr instead.
+#if !defined (QT_NO_GETADDRINFO) && !defined (Q_OS_DARWIN)
+ sockaddr_in sa4;
+#ifndef QT_NO_IPV6
+ sockaddr_in6 sa6;
+#endif
+ sockaddr *sa = 0;
+ QT_SOCKLEN_T saSize = 0;
+ if (address.protocol() == QAbstractSocket::IPv4Protocol) {
+ sa = (sockaddr *)&sa4;
+ saSize = sizeof(sa4);
+ memset(&sa4, 0, sizeof(sa4));
+ sa4.sin_family = AF_INET;
+ sa4.sin_addr.s_addr = htonl(address.toIPv4Address());
+ }
+#ifndef QT_NO_IPV6
+ else {
+ sa = (sockaddr *)&sa6;
+ saSize = sizeof(sa6);
+ memset(&sa6, 0, sizeof(sa6));
+ sa6.sin6_family = AF_INET6;
+ memcpy(sa6.sin6_addr.s6_addr, address.toIPv6Address().c, sizeof(sa6.sin6_addr.s6_addr));
+ }
+#endif
+
+ char hbuf[NI_MAXHOST];
+ if (!sa || getnameinfo(sa, saSize, hbuf, sizeof(hbuf), 0, 0, 0) != 0) {
+ results.setError(QHostInfo::HostNotFound);
+ results.setErrorString(tr("Host not found"));
+ return results;
+ }
+ results.setHostName(QString::fromLatin1(hbuf));
+#else
+ in_addr_t inetaddr = inet_addr(hostName.toLatin1().constData());
+ struct hostent *ent = gethostbyaddr((const char *)&inetaddr, sizeof(inetaddr), AF_INET);
+ if (!ent) {
+ results.setError(QHostInfo::HostNotFound);
+ results.setErrorString(tr("Host not found"));
+ return results;
+ }
+ results.setHostName(QString::fromLatin1(ent->h_name));
+#endif
+ }
+
+#if !defined (QT_NO_GETADDRINFO)
+ // Call getaddrinfo, and place all IPv4 addresses at the start and
+ // the IPv6 addresses at the end of the address list in results.
+ addrinfo *res = 0;
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+#ifdef Q_ADDRCONFIG
+ hints.ai_flags = Q_ADDRCONFIG;
+#endif
+
+ int result = getaddrinfo(hostName.toLatin1().constData(), 0, &hints, &res);
+# ifdef Q_ADDRCONFIG
+ if (result == EAI_BADFLAGS) {
+ // if the lookup failed with AI_ADDRCONFIG set, try again without it
+ hints.ai_flags = 0;
+ result = getaddrinfo(hostName.toLatin1().constData(), 0, &hints, &res);
+ }
+# endif
+
+ if (result == 0) {
+ addrinfo *node = res;
+ QList<QHostAddress> addresses;
+ while (node) {
+ if (node->ai_family == AF_INET) {
+ QHostAddress addr;
+ addr.setAddress(ntohl(((sockaddr_in *) node->ai_addr)->sin_addr.s_addr));
+ if (!addresses.contains(addr))
+ addresses.append(addr);
+ }
+#ifndef QT_NO_IPV6
+ else if (node->ai_family == AF_INET6) {
+ QHostAddress addr;
+ addr.setAddress(((sockaddr_in6 *) node->ai_addr)->sin6_addr.s6_addr);
+ if (!addresses.contains(addr))
+ addresses.append(addr);
+ }
+#endif
+ node = node->ai_next;
+ }
+ if (addresses.isEmpty() && node == 0) {
+ // Reached the end of the list, but no addresses were found; this
+ // means the list contains one or more unknown address types.
+ results.setError(QHostInfo::UnknownError);
+ results.setErrorString(tr("Unknown address type"));
+ }
+
+ results.setAddresses(addresses);
+ freeaddrinfo(res);
+ } else if (result == EAI_NONAME
+ || result == EAI_FAIL
+#ifdef EAI_NODATA
+ // EAI_NODATA is deprecated in RFC 3493
+ || result == EAI_NODATA
+#endif
+ ) {
+ results.setError(QHostInfo::HostNotFound);
+ results.setErrorString(tr("Host not found"));
+ } else {
+ results.setError(QHostInfo::UnknownError);
+ results.setErrorString(QString::fromLocal8Bit(gai_strerror(result)));
+ }
+
+#else
+ // Fall back to gethostbyname for platforms that don't define
+ // getaddrinfo. gethostbyname does not support IPv6, and it's not
+ // reentrant on all platforms. For now this is okay since we only
+ // use one QHostInfoAgent, but if more agents are introduced, locking
+ // must be provided.
+ QMutexLocker locker(::getHostByNameMutex());
+ hostent *result = gethostbyname(hostName.toLatin1().constData());
+ if (result) {
+ if (result->h_addrtype == AF_INET) {
+ QList<QHostAddress> addresses;
+ for (char **p = result->h_addr_list; *p != 0; p++) {
+ QHostAddress addr;
+ addr.setAddress(ntohl(*((quint32 *)*p)));
+ if (!addresses.contains(addr))
+ addresses.prepend(addr);
+ }
+ results.setAddresses(addresses);
+ } else {
+ results.setError(QHostInfo::UnknownError);
+ results.setErrorString(tr("Unknown address type"));
+ }
+ } else if (h_errno == HOST_NOT_FOUND || h_errno == NO_DATA
+ || h_errno == NO_ADDRESS) {
+ results.setError(QHostInfo::HostNotFound);
+ results.setErrorString(tr("Host not found"));
+ } else {
+ results.setError(QHostInfo::UnknownError);
+ results.setErrorString(tr("Unknown error"));
+ }
+#endif // !defined (QT_NO_GETADDRINFO)
+
+#if defined(QHOSTINFO_DEBUG)
+ if (results.error() != QHostInfo::NoError) {
+ qDebug("QHostInfoAgent::fromName(): error #%d %s",
+ h_errno, results.errorString().toLatin1().constData());
+ } else {
+ QString tmp;
+ QList<QHostAddress> addresses = results.addresses();
+ for (int i = 0; i < addresses.count(); ++i) {
+ if (i != 0) tmp += ", ";
+ tmp += addresses.at(i).toString();
+ }
+ qDebug("QHostInfoAgent::fromName(): found %i entries for \"%s\": {%s}",
+ addresses.count(), hostName.toLatin1().constData(),
+ tmp.toLatin1().constData());
+ }
+#endif
+ return results;
+}
+
+QString QHostInfo::localHostName()
+{
+ char hostName[512];
+ if (gethostname(hostName, sizeof(hostName)) == -1)
+ return QString();
+ hostName[sizeof(hostName) - 1] = '\0';
+ return QString::fromLocal8Bit(hostName);
+}
+
+QString QHostInfo::localDomainName()
+{
+ resolveLibrary();
+ if (local_res_ninit) {
+ // using thread-safe version
+ res_state_ptr state = res_state_ptr(qMalloc(sizeof(*state)));
+ memset(state, 0, sizeof(*state));
+ local_res_ninit(state);
+ QString domainName = QUrl::fromAce(state->defdname);
+ if (domainName.isEmpty())
+ domainName = QUrl::fromAce(state->dnsrch[0]);
+ local_res_nclose(state);
+ qFree(state);
+
+ return domainName;
+ }
+
+ if (local_res_init && local_res) {
+ // using thread-unsafe version
+
+#if defined(QT_NO_GETADDRINFO)
+ // We have to call res_init to be sure that _res was initialized
+ // So, for systems without getaddrinfo (which is thread-safe), we lock the mutex too
+ QMutexLocker locker(::getHostByNameMutex());
+#endif
+ local_res_init();
+ QString domainName = QUrl::fromAce(local_res->defdname);
+ if (domainName.isEmpty())
+ domainName = QUrl::fromAce(local_res->dnsrch[0]);
+ return domainName;
+ }
+
+ // nothing worked, try doing it by ourselves:
+ QFile resolvconf;
+#if defined(_PATH_RESCONF)
+ resolvconf.setFileName(QFile::decodeName(_PATH_RESCONF));
+#else
+ resolvconf.setFileName(QLatin1String("/etc/resolv.conf"));
+#endif
+ if (!resolvconf.open(QIODevice::ReadOnly))
+ return QString(); // failure
+
+ QString domainName;
+ while (!resolvconf.atEnd()) {
+ QByteArray line = resolvconf.readLine().trimmed();
+ if (line.startsWith("domain "))
+ return QUrl::fromAce(line.mid(sizeof "domain " - 1).trimmed());
+
+ // in case there's no "domain" line, fall back to the first "search" entry
+ if (domainName.isEmpty() && line.startsWith("search ")) {
+ QByteArray searchDomain = line.mid(sizeof "search " - 1).trimmed();
+ int pos = searchDomain.indexOf(' ');
+ if (pos != -1)
+ searchDomain.truncate(pos);
+ domainName = QUrl::fromAce(searchDomain);
+ }
+ }
+
+ // return the fallen-back-to searched domain
+ return domainName;
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/kernel/qhostinfo_win.cpp b/src/network/kernel/qhostinfo_win.cpp
new file mode 100644
index 0000000..0a34e2b
--- /dev/null
+++ b/src/network/kernel/qhostinfo_win.cpp
@@ -0,0 +1,295 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#if defined Q_CC_MSVC && _MSC_VER <=1300
+//VC.net 2002 support for templates doesn't match some PSDK requirements
+#define _WSPIAPI_COUNTOF(_Array) (sizeof(_Array) / sizeof(_Array[0]))
+#endif
+
+#include <winsock2.h>
+
+#include "qhostinfo_p.h"
+#include "private/qnativesocketengine_p.h"
+#include <ws2tcpip.h>
+#include <qlibrary.h>
+#include <qtimer.h>
+#include <qmutex.h>
+#include <private/qmutexpool_p.h>
+
+QT_BEGIN_NAMESPACE
+
+//#define QHOSTINFO_DEBUG
+
+// Older SDKs do not include the addrinfo struct declaration, so we
+// include a copy of it here.
+struct qt_addrinfo
+{
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ size_t ai_addrlen;
+ char *ai_canonname;
+ sockaddr *ai_addr;
+ qt_addrinfo *ai_next;
+};
+
+// sockaddr_in6 size changed between old and new SDK
+// Only the new version is the correct one, so always
+// use this structure.
+struct qt_in6_addr {
+ uchar qt_s6_addr[16];
+};
+
+struct qt_sockaddr_in6 {
+ short sin6_family; /* AF_INET6 */
+ u_short sin6_port; /* Transport level port number */
+ u_long sin6_flowinfo; /* IPv6 flow information */
+ struct qt_in6_addr sin6_addr; /* IPv6 address */
+ u_long sin6_scope_id; /* set of interfaces for a scope */
+};
+
+//###
+#define QT_SOCKLEN_T int
+#ifndef NI_MAXHOST // already defined to 1025 in ws2tcpip.h?
+#define NI_MAXHOST 1024
+#endif
+
+typedef int (__stdcall *getnameinfoProto)(const sockaddr *, QT_SOCKLEN_T, const char *, DWORD, const char *, DWORD, int);
+typedef int (__stdcall *getaddrinfoProto)(const char *, const char *, const qt_addrinfo *, qt_addrinfo **);
+typedef int (__stdcall *freeaddrinfoProto)(qt_addrinfo *);
+static getnameinfoProto local_getnameinfo = 0;
+static getaddrinfoProto local_getaddrinfo = 0;
+static freeaddrinfoProto local_freeaddrinfo = 0;
+
+static void resolveLibrary()
+{
+ // Attempt to resolve getaddrinfo(); without it we'll have to fall
+ // back to gethostbyname(), which has no IPv6 support.
+#if !defined(Q_OS_WINCE)
+ local_getaddrinfo = (getaddrinfoProto) QLibrary::resolve(QLatin1String("ws2_32.dll"), "getaddrinfo");
+ local_freeaddrinfo = (freeaddrinfoProto) QLibrary::resolve(QLatin1String("ws2_32.dll"), "freeaddrinfo");
+ local_getnameinfo = (getnameinfoProto) QLibrary::resolve(QLatin1String("ws2_32.dll"), "getnameinfo");
+#else
+ local_getaddrinfo = (getaddrinfoProto) QLibrary::resolve(QLatin1String("ws2.dll"), "getaddrinfo");
+ local_freeaddrinfo = (freeaddrinfoProto) QLibrary::resolve(QLatin1String("ws2.dll"), "freeaddrinfo");
+ local_getnameinfo = (getnameinfoProto) QLibrary::resolve(QLatin1String("ws2.dll"), "getnameinfo");
+#endif
+}
+
+#if defined(Q_OS_WINCE)
+#include <qmutex.h>
+QMutex qPrivCEMutex;
+#endif
+/*
+ Performs a blocking call to gethostbyname or getaddrinfo, stores
+ the results in a QHostInfo structure and emits the
+ resultsReady() signal.
+*/
+QHostInfo QHostInfoAgent::fromName(const QString &hostName)
+{
+#if defined(Q_OS_WINCE)
+ QMutexLocker locker(&qPrivCEMutex);
+#endif
+ QWindowsSockInit winSock;
+
+ // Load res_init on demand.
+ static volatile bool triedResolve = false;
+ if (!triedResolve) {
+#ifndef QT_NO_THREAD
+ QMutexLocker locker(QMutexPool::globalInstanceGet(&local_getaddrinfo));
+#endif
+ if (!triedResolve) {
+ resolveLibrary();
+ triedResolve = true;
+ }
+ }
+
+ QHostInfo results;
+ results.setHostName(hostName);
+
+#if defined(QHOSTINFO_DEBUG)
+ qDebug("QHostInfoAgent::fromName(%p): looking up \"%s\" (IPv6 support is %s)",
+ this, hostName.toLatin1().constData(),
+ (local_getaddrinfo && local_freeaddrinfo) ? "enabled" : "disabled");
+#endif
+
+ QHostAddress address;
+ if (address.setAddress(hostName)) {
+ // Reverse lookup
+ if (local_getnameinfo) {
+ sockaddr_in sa4;
+ qt_sockaddr_in6 sa6;
+ sockaddr *sa;
+ QT_SOCKLEN_T saSize;
+ if (address.protocol() == QAbstractSocket::IPv4Protocol) {
+ sa = (sockaddr *)&sa4;
+ saSize = sizeof(sa4);
+ memset(&sa4, 0, sizeof(sa4));
+ sa4.sin_family = AF_INET;
+ sa4.sin_addr.s_addr = htonl(address.toIPv4Address());
+ } else {
+ sa = (sockaddr *)&sa6;
+ saSize = sizeof(sa6);
+ memset(&sa6, 0, sizeof(sa6));
+ sa6.sin6_family = AF_INET6;
+ memcpy(sa6.sin6_addr.qt_s6_addr, address.toIPv6Address().c, sizeof(sa6.sin6_addr.qt_s6_addr));
+ }
+
+ char hbuf[NI_MAXHOST];
+ if (local_getnameinfo(sa, saSize, hbuf, sizeof(hbuf), 0, 0, 0) != 0) {
+ results.setError(QHostInfo::HostNotFound);
+ results.setErrorString(tr("Host not found"));
+ return results;
+ }
+ results.setHostName(QString::fromLatin1(hbuf));
+ } else {
+ unsigned long addr = inet_addr(hostName.toLatin1().constData());
+ struct hostent *ent = gethostbyaddr((const char*)&addr, sizeof(addr), AF_INET);
+ if (!ent) {
+ results.setError(QHostInfo::HostNotFound);
+ results.setErrorString(tr("Host not found"));
+ return results;
+ }
+ results.setHostName(QString::fromLatin1(ent->h_name));
+ }
+ }
+
+ if (local_getaddrinfo && local_freeaddrinfo) {
+ // Call getaddrinfo, and place all IPv4 addresses at the start
+ // and the IPv6 addresses at the end of the address list in
+ // results.
+ qt_addrinfo *res;
+ int err = local_getaddrinfo(hostName.toLatin1().constData(), 0, 0, &res);
+ if (err == 0) {
+ QList<QHostAddress> addresses;
+ for (qt_addrinfo *p = res; p != 0; p = p->ai_next) {
+ switch (p->ai_family) {
+ case AF_INET: {
+ QHostAddress addr;
+ addr.setAddress(ntohl(((sockaddr_in *) p->ai_addr)->sin_addr.s_addr));
+ if (!addresses.contains(addr))
+ addresses.append(addr);
+ }
+ break;
+ case AF_INET6: {
+ QHostAddress addr;
+ addr.setAddress(((qt_sockaddr_in6 *) p->ai_addr)->sin6_addr.qt_s6_addr);
+ if (!addresses.contains(addr))
+ addresses.append(addr);
+ }
+ break;
+ default:
+ results.setError(QHostInfo::UnknownError);
+ results.setErrorString(tr("Unknown address type"));
+ }
+ }
+ results.setAddresses(addresses);
+ local_freeaddrinfo(res);
+ } else if (WSAGetLastError() == WSAHOST_NOT_FOUND || WSAGetLastError() == WSANO_DATA) {
+ results.setError(QHostInfo::HostNotFound);
+ results.setErrorString(tr("Host not found"));
+ } else {
+ results.setError(QHostInfo::UnknownError);
+ results.setErrorString(tr("Unknown error"));
+ }
+ } else {
+ // Fall back to gethostbyname, which only supports IPv4.
+ hostent *ent = gethostbyname(hostName.toLatin1().constData());
+ if (ent) {
+ char **p;
+ QList<QHostAddress> addresses;
+ switch (ent->h_addrtype) {
+ case AF_INET:
+ for (p = ent->h_addr_list; *p != 0; p++) {
+ long *ip4Addr = (long *) *p;
+ QHostAddress temp;
+ temp.setAddress(ntohl(*ip4Addr));
+ addresses << temp;
+ }
+ break;
+ default:
+ results.setError(QHostInfo::UnknownError);
+ results.setErrorString(tr("Unknown address type"));
+ break;
+ }
+ results.setAddresses(addresses);
+ } else if (WSAGetLastError() == 11001) {
+ results.setErrorString(tr("Host not found"));
+ results.setError(QHostInfo::HostNotFound);
+ } else {
+ results.setErrorString(tr("Unknown error"));
+ results.setError(QHostInfo::UnknownError);
+ }
+ }
+
+#if defined(QHOSTINFO_DEBUG)
+ if (results.error() != QHostInfo::NoError) {
+ qDebug("QHostInfoAgent::run(%p): error (%s)",
+ this, results.errorString().toLatin1().constData());
+ } else {
+ QString tmp;
+ QList<QHostAddress> addresses = results.addresses();
+ for (int i = 0; i < addresses.count(); ++i) {
+ if (i != 0) tmp += ", ";
+ tmp += addresses.at(i).toString();
+ }
+ qDebug("QHostInfoAgent::run(%p): found %i entries: {%s}",
+ this, addresses.count(), tmp.toLatin1().constData());
+ }
+#endif
+ return results;
+}
+
+QString QHostInfo::localHostName()
+{
+ QWindowsSockInit winSock;
+
+ char hostName[512];
+ if (gethostname(hostName, sizeof(hostName)) == -1)
+ return QString();
+ hostName[sizeof(hostName) - 1] = '\0';
+ return QString::fromLocal8Bit(hostName);
+}
+
+// QString QHostInfo::localDomainName() defined in qnetworkinterface_win.cpp
+
+QT_END_NAMESPACE
diff --git a/src/network/kernel/qnetworkinterface.cpp b/src/network/kernel/qnetworkinterface.cpp
new file mode 100644
index 0000000..670745b
--- /dev/null
+++ b/src/network/kernel/qnetworkinterface.cpp
@@ -0,0 +1,615 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qnetworkinterface.h"
+#include "qnetworkinterface_p.h"
+
+#include "qdebug.h"
+#include "qendian.h"
+
+#ifndef QT_NO_NETWORKINTERFACE
+
+QT_BEGIN_NAMESPACE
+
+static QList<QNetworkInterfacePrivate *> postProcess(QList<QNetworkInterfacePrivate *> list)
+{
+ // Some platforms report a netmask but don't report a broadcast address
+ // Go through all available addresses and calculate the broadcast address
+ // from the IP and the netmask
+ //
+ // This is an IPv4-only thing -- IPv6 has no concept of broadcasts
+ // The math is:
+ // broadcast = IP | ~netmask
+
+ QList<QNetworkInterfacePrivate *>::Iterator it = list.begin();
+ const QList<QNetworkInterfacePrivate *>::Iterator end = list.end();
+ for ( ; it != end; ++it) {
+ QList<QNetworkAddressEntry>::Iterator addr_it = (*it)->addressEntries.begin();
+ const QList<QNetworkAddressEntry>::Iterator addr_end = (*it)->addressEntries.end();
+ for ( ; addr_it != addr_end; ++addr_it) {
+ if (addr_it->ip().protocol() != QAbstractSocket::IPv4Protocol)
+ continue;
+
+ if (!addr_it->netmask().isNull() && addr_it->broadcast().isNull()) {
+ QHostAddress bcast = addr_it->ip();
+ bcast = QHostAddress(bcast.toIPv4Address() | ~addr_it->netmask().toIPv4Address());
+ addr_it->setBroadcast(bcast);
+ }
+ }
+ }
+
+ return list;
+}
+
+Q_GLOBAL_STATIC(QNetworkInterfaceManager, manager)
+
+QNetworkInterfaceManager::QNetworkInterfaceManager()
+{
+}
+
+QNetworkInterfaceManager::~QNetworkInterfaceManager()
+{
+}
+
+QSharedDataPointer<QNetworkInterfacePrivate> QNetworkInterfaceManager::interfaceFromName(const QString &name)
+{
+ QList<QSharedDataPointer<QNetworkInterfacePrivate> > interfaceList = allInterfaces();
+ QList<QSharedDataPointer<QNetworkInterfacePrivate> >::ConstIterator it = interfaceList.constBegin();
+ for ( ; it != interfaceList.constEnd(); ++it)
+ if ((*it)->name == name)
+ return *it;
+
+ return empty;
+}
+
+QSharedDataPointer<QNetworkInterfacePrivate> QNetworkInterfaceManager::interfaceFromIndex(int index)
+{
+ QList<QSharedDataPointer<QNetworkInterfacePrivate> > interfaceList = allInterfaces();
+ QList<QSharedDataPointer<QNetworkInterfacePrivate> >::ConstIterator it = interfaceList.constBegin();
+ for ( ; it != interfaceList.constEnd(); ++it)
+ if ((*it)->index == index)
+ return *it;
+
+ return empty;
+}
+
+QList<QSharedDataPointer<QNetworkInterfacePrivate> > QNetworkInterfaceManager::allInterfaces()
+{
+ QList<QNetworkInterfacePrivate *> list = postProcess(scan());
+ QList<QSharedDataPointer<QNetworkInterfacePrivate> > result;
+
+ foreach (QNetworkInterfacePrivate *ptr, list)
+ result << QSharedDataPointer<QNetworkInterfacePrivate>(ptr);
+
+ return result;
+}
+
+QString QNetworkInterfacePrivate::makeHwAddress(int len, uchar *data)
+{
+ QString result;
+ for (int i = 0; i < len; ++i) {
+ if (i)
+ result += QLatin1Char(':');
+
+ char buf[3];
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && defined(_MSC_VER) && _MSC_VER >= 1400
+ sprintf_s(buf, 3, "%02hX", ushort(data[i]));
+#else
+ sprintf(buf, "%02hX", ushort(data[i]));
+#endif
+ result += QLatin1String(buf);
+ }
+ return result;
+}
+
+/*!
+ \class QNetworkAddressEntry
+ \brief The QNetworkAddressEntry class stores one IP address
+ supported by a network interface, along with its associated
+ netmask and broadcast address.
+
+ \since 4.2
+ \reentrant
+ \ingroup io
+
+ Each network interface can contain zero or more IP addresses, which
+ in turn can be associated with a netmask and/or a broadcast
+ address (depending on support from the operating system).
+
+ This class represents one such group.
+*/
+
+/*!
+ Constructs an empty QNetworkAddressEntry object.
+*/
+QNetworkAddressEntry::QNetworkAddressEntry()
+ : d(new QNetworkAddressEntryPrivate)
+{
+}
+
+/*!
+ Constructs a QNetworkAddressEntry object that is a copy of the
+ object \a other.
+*/
+QNetworkAddressEntry::QNetworkAddressEntry(const QNetworkAddressEntry &other)
+ : d(new QNetworkAddressEntryPrivate(*other.d))
+{
+}
+
+/*!
+ Makes a copy of the QNetworkAddressEntry object \a other.
+*/
+QNetworkAddressEntry &QNetworkAddressEntry::operator=(const QNetworkAddressEntry &other)
+{
+ *d = *other.d;
+ return *this;
+}
+
+/*!
+ Destroys this QNetworkAddressEntry object.
+*/
+QNetworkAddressEntry::~QNetworkAddressEntry()
+{
+ delete d;
+}
+
+/*!
+ Returns true if this network address entry is the same as \a
+ other.
+*/
+bool QNetworkAddressEntry::operator==(const QNetworkAddressEntry &other) const
+{
+ if (d == other.d) return true;
+ if (!d || !other.d) return false;
+ return d->address == other.d->address &&
+ d->netmask == other.d->netmask &&
+ d->broadcast == other.d->broadcast;
+}
+
+/*!
+ \fn bool QNetworkAddressEntry::operator!=(const QNetworkAddressEntry &other) const
+
+ Returns true if this network address entry is different from \a
+ other.
+*/
+
+/*!
+ This function returns one IPv4 or IPv6 address found, that was
+ found in a network interface.
+*/
+QHostAddress QNetworkAddressEntry::ip() const
+{
+ return d->address;
+}
+
+/*!
+ Sets the IP address the QNetworkAddressEntry object contains to \a
+ newIp.
+*/
+void QNetworkAddressEntry::setIp(const QHostAddress &newIp)
+{
+ d->address = newIp;
+}
+
+/*!
+ Returns the netmask associated with the IP address. The
+ netmask is expressed in the form of an IP address, such as
+ 255.255.0.0.
+
+ For IPv6 addresses, the prefix length is converted to an address
+ where the number of bits set to 1 is equal to the prefix
+ length. For a prefix length of 64 bits (the most common value),
+ the netmask will be expressed as a QHostAddress holding the
+ address FFFF:FFFF:FFFF:FFFF::
+
+ \sa prefixLength()
+*/
+QHostAddress QNetworkAddressEntry::netmask() const
+{
+ return d->netmask;
+}
+
+/*!
+ Sets the netmask that this QNetworkAddressEntry object contains to
+ \a newNetmask. Setting the netmask also sets the prefix length to
+ match the new netmask.
+
+ \sa setPrefixLength()
+*/
+void QNetworkAddressEntry::setNetmask(const QHostAddress &newNetmask)
+{
+ if (newNetmask.protocol() != ip().protocol()) {
+ d->netmask = QNetmaskAddress();
+ return;
+ }
+
+ d->netmask.setAddress(newNetmask);
+}
+
+/*!
+ \since 4.5
+ Returns the prefix length of this IP address. The prefix length
+ matches the number of bits set to 1 in the netmask (see
+ netmask()). For IPv4 addresses, the value is between 0 and 32. For
+ IPv6 addresses, it's contained between 0 and 128 and is the
+ preferred form of representing addresses.
+
+ This function returns -1 if the prefix length could not be
+ determined (i.e., netmask() returns a null QHostAddress()).
+
+ \sa netmask()
+*/
+int QNetworkAddressEntry::prefixLength() const
+{
+ return d->netmask.prefixLength();
+}
+
+/*!
+ \since 4.5
+ Sets the prefix length of this IP address to \a length. The value
+ of \a length must be valid for this type of IP address: between 0
+ and 32 for IPv4 addresses, between 0 and 128 for IPv6
+ addresses. Setting to any invalid value is equivalent to setting
+ to -1, which means "no prefix length".
+
+ Setting the prefix length also sets the netmask (see netmask()).
+
+ \sa setNetmask()
+*/
+void QNetworkAddressEntry::setPrefixLength(int length)
+{
+ d->netmask.setPrefixLength(d->address.protocol(), length);
+}
+
+/*!
+ Returns the broadcast address associated with the IPv4
+ address and netmask. It can usually be derived from those two by
+ setting to 1 the bits of the IP address where the netmask contains
+ a 0. (In other words, by bitwise-OR'ing the IP address with the
+ inverse of the netmask)
+
+ This member is always empty for IPv6 addresses, since the concept
+ of broadcast has been abandoned in that system in favor of
+ multicast. In particular, the group of hosts corresponding to all
+ the nodes in the local network can be reached by the "all-nodes"
+ special multicast group (address FF02::1).
+*/
+QHostAddress QNetworkAddressEntry::broadcast() const
+{
+ return d->broadcast;
+}
+
+/*!
+ Sets the broadcast IP address of this QNetworkAddressEntry object
+ to \a newBroadcast.
+*/
+void QNetworkAddressEntry::setBroadcast(const QHostAddress &newBroadcast)
+{
+ d->broadcast = newBroadcast;
+}
+
+/*!
+ \class QNetworkInterface
+ \brief The QNetworkInterface class provides a listing of the host's IP
+ addresses and network interfaces.
+
+ \since 4.2
+ \reentrant
+ \ingroup io
+
+ QNetworkInterface represents one network interface attached to the
+ host where the program is being run. Each network interface may
+ contain zero or more IP addresses, each of which is optionally
+ associated with a netmask and/or a broadcast address. The list of
+ such trios can be obtained with addressEntries(). Alternatively,
+ when the netmask or the broadcast addresses aren't necessary, use
+ the allAddresses() convenience function to obtain just the IP
+ addresses.
+
+ QNetworkInterface also reports the interface's hardware address with
+ hardwareAddress().
+
+ Not all operating systems support reporting all features. Only the
+ IPv4 addresses are guaranteed to be listed by this class in all
+ platforms. In particular, IPv6 address listing is only supported
+ on Windows XP and more recent versions, Linux, MacOS X and the
+ BSDs.
+
+ \sa QNetworkAddressEntry
+*/
+
+/*!
+ \enum QNetworkInterface::InterfaceFlag
+ Specifies the flags associated with this network interface. The
+ possible values are:
+
+ \value IsUp the network interface is active
+ \value IsRunning the network interface has resources
+ allocated
+ \value CanBroadcast the network interface works in
+ broadcast mode
+ \value IsLoopBack the network interface is a loopback
+ interface: that is, it's a virtual
+ interface whose destination is the
+ host computer itself
+ \value IsPointToPoint the network interface is a
+ point-to-point interface: that is,
+ there is one, single other address
+ that can be directly reached by it.
+ \value CanMulticast the network interface supports
+ multicasting
+
+ Note that one network interface cannot be both broadcast-based and
+ point-to-point.
+*/
+
+/*!
+ Constructs an empty network interface object.
+*/
+QNetworkInterface::QNetworkInterface()
+ : d(0)
+{
+}
+
+/*!
+ Frees the resources associated with the QNetworkInterface object.
+*/
+QNetworkInterface::~QNetworkInterface()
+{
+}
+
+/*!
+ Creates a copy of the the QNetworkInterface object contained in \a
+ other.
+*/
+QNetworkInterface::QNetworkInterface(const QNetworkInterface &other)
+ : d(other.d)
+{
+}
+
+/*!
+ Copies the contents of the QNetworkInterface object contained in \a
+ other into this one.
+*/
+QNetworkInterface &QNetworkInterface::operator=(const QNetworkInterface &other)
+{
+ d = other.d;
+ return *this;
+}
+
+/*!
+ Returns true if this QNetworkInterface object contains valid
+ information about a network interface.
+*/
+bool QNetworkInterface::isValid() const
+{
+ return !name().isEmpty();
+}
+
+/*!
+ \since 4.5
+ Returns the interface system index, if known. This is an integer
+ assigned by the operating system to identify this interface and it
+ generally doesn't change. It matches the scope ID field in IPv6
+ addresses.
+
+ If the index isn't known, this function returns 0.
+*/
+int QNetworkInterface::index() const
+{
+ return d ? d->index : 0;
+}
+
+/*!
+ Returns the name of this network interface. On Unix systems, this
+ is a string containing the type of the interface and optionally a
+ sequence number, such as "eth0", "lo" or "pcn0". On Windows, it's
+ an internal ID that cannot be changed by the user.
+*/
+QString QNetworkInterface::name() const
+{
+ return d ? d->name : QString();
+}
+
+/*!
+ \since 4.5
+
+ Returns the human-readable name of this network interface on
+ Windows, such as "Local Area Connection", if the name could be
+ determined. If it couldn't, this function returns the same as
+ name(). The human-readable name is a name that the user can modify
+ in the Windows Control Panel, so it may change during the
+ execution of the program.
+
+ On Unix, this function currently always returns the same as
+ name(), since Unix systems don't store a configuration for
+ human-readable names.
+*/
+QString QNetworkInterface::humanReadableName() const
+{
+ return d ? !d->friendlyName.isEmpty() ? d->friendlyName : name() : QString();
+}
+
+/*!
+ Returns the flags associated with this network interface.
+*/
+QNetworkInterface::InterfaceFlags QNetworkInterface::flags() const
+{
+ return d ? d->flags : InterfaceFlags(0);
+}
+
+/*!
+ Returns the low-level hardware address for this interface. On
+ Ethernet interfaces, this will be a MAC address in string
+ representation, separated by colons.
+
+ Other interface types may have other types of hardware
+ addresses. Implementations should not depend on this function
+ returning a valid MAC address.
+*/
+QString QNetworkInterface::hardwareAddress() const
+{
+ return d ? d->hardwareAddress : QString();
+}
+
+/*!
+ Returns the list of IP addresses that this interface possesses
+ along with their associated netmasks and broadcast addresses.
+
+ If the netmask or broadcast address information is not necessary,
+ you can call the allAddresses() function to obtain just the IP
+ addresses.
+*/
+QList<QNetworkAddressEntry> QNetworkInterface::addressEntries() const
+{
+ return d ? d->addressEntries : QList<QNetworkAddressEntry>();
+}
+
+/*!
+ Returns a QNetworkInterface object for the interface named \a
+ name. If no such interface exists, this function returns an
+ invalid QNetworkInterface object.
+
+ \sa name(), isValid()
+*/
+QNetworkInterface QNetworkInterface::interfaceFromName(const QString &name)
+{
+ QNetworkInterface result;
+ result.d = manager()->interfaceFromName(name);
+ return result;
+}
+
+/*!
+ Returns a QNetworkInterface object for the interface whose internal
+ ID is \a index. Network interfaces have a unique identifier called
+ the "interface index" to distinguish it from other interfaces on
+ the system. Often, this value is assigned progressively and
+ interfaces being removed and then added again get a different
+ value every time.
+
+ This index is also found in the IPv6 address' scope ID field.
+*/
+QNetworkInterface QNetworkInterface::interfaceFromIndex(int index)
+{
+ QNetworkInterface result;
+ result.d = manager()->interfaceFromIndex(index);
+ return result;
+}
+
+/*!
+ Returns a listing of all the network interfaces found on the host
+ machine.
+*/
+QList<QNetworkInterface> QNetworkInterface::allInterfaces()
+{
+ QList<QSharedDataPointer<QNetworkInterfacePrivate> > privs = manager()->allInterfaces();
+ QList<QNetworkInterface> result;
+ foreach (QSharedDataPointer<QNetworkInterfacePrivate> p, privs) {
+ QNetworkInterface item;
+ item.d = p;
+ result << item;
+ }
+
+ return result;
+}
+
+/*!
+ This convenience function returns all IP addresses found on the
+ host machine. It is equivalent to calling addressEntries() on all the
+ objects returned by allInterfaces() to obtain lists of QHostAddress
+ objects then calling QHostAddress::ip() on each of these.
+*/
+QList<QHostAddress> QNetworkInterface::allAddresses()
+{
+ QList<QSharedDataPointer<QNetworkInterfacePrivate> > privs = manager()->allInterfaces();
+ QList<QHostAddress> result;
+ foreach (const QSharedDataPointer<QNetworkInterfacePrivate> p, privs) {
+ foreach (const QNetworkAddressEntry &entry, p->addressEntries)
+ result += entry.ip();
+ }
+
+ return result;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+static inline QDebug flagsDebug(QDebug debug, QNetworkInterface::InterfaceFlags flags)
+{
+ if (flags & QNetworkInterface::IsUp)
+ debug.nospace() << "IsUp ";
+ if (flags & QNetworkInterface::IsRunning)
+ debug.nospace() << "IsRunning ";
+ if (flags & QNetworkInterface::CanBroadcast)
+ debug.nospace() << "CanBroadcast ";
+ if (flags & QNetworkInterface::IsLoopBack)
+ debug.nospace() << "IsLoopBack ";
+ if (flags & QNetworkInterface::IsPointToPoint)
+ debug.nospace() << "IsPointToPoint ";
+ if (flags & QNetworkInterface::CanMulticast)
+ debug.nospace() << "CanMulticast ";
+ return debug.nospace();
+}
+
+static inline QDebug operator<<(QDebug debug, const QNetworkAddressEntry &entry)
+{
+ debug.nospace() << "(address = " << entry.ip();
+ if (!entry.netmask().isNull())
+ debug.nospace() << ", netmask = " << entry.netmask();
+ if (!entry.broadcast().isNull())
+ debug.nospace() << ", broadcast = " << entry.broadcast();
+ debug.nospace() << ")";
+ return debug.space();
+}
+
+QDebug operator<<(QDebug debug, const QNetworkInterface &networkInterface)
+{
+ debug.nospace() << "QNetworkInterface(name = " << networkInterface.name()
+ << ", hardware address = " << networkInterface.hardwareAddress()
+ << ", flags = ";
+ flagsDebug(debug, networkInterface.flags());
+ debug.nospace() << ", entries = " << networkInterface.addressEntries()
+ << ")\n";
+ return debug.space();
+}
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_NETWORKINTERFACE
diff --git a/src/network/kernel/qnetworkinterface.h b/src/network/kernel/qnetworkinterface.h
new file mode 100644
index 0000000..09fbd0f
--- /dev/null
+++ b/src/network/kernel/qnetworkinterface.h
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QNETWORKINTERFACE_H
+#define QNETWORKINTERFACE_H
+
+#include <QtCore/qshareddata.h>
+#include <QtNetwork/qhostaddress.h>
+
+#ifndef QT_NO_NETWORKINTERFACE
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Network)
+
+template<typename T> class QList;
+
+class QNetworkAddressEntryPrivate;
+class Q_NETWORK_EXPORT QNetworkAddressEntry
+{
+public:
+ QNetworkAddressEntry();
+ QNetworkAddressEntry(const QNetworkAddressEntry &other);
+ QNetworkAddressEntry &operator=(const QNetworkAddressEntry &other);
+ ~QNetworkAddressEntry();
+ bool operator==(const QNetworkAddressEntry &other) const;
+ inline bool operator!=(const QNetworkAddressEntry &other) const
+ { return !(*this == other); }
+
+ QHostAddress ip() const;
+ void setIp(const QHostAddress &newIp);
+
+ QHostAddress netmask() const;
+ void setNetmask(const QHostAddress &newNetmask);
+ int prefixLength() const;
+ void setPrefixLength(int length);
+
+ QHostAddress broadcast() const;
+ void setBroadcast(const QHostAddress &newBroadcast);
+
+private:
+ QNetworkAddressEntryPrivate *d;
+};
+
+class QNetworkInterfacePrivate;
+class Q_NETWORK_EXPORT QNetworkInterface
+{
+public:
+ enum InterfaceFlag {
+ IsUp = 0x1,
+ IsRunning = 0x2,
+ CanBroadcast = 0x4,
+ IsLoopBack = 0x8,
+ IsPointToPoint = 0x10,
+ CanMulticast = 0x20
+ };
+ Q_DECLARE_FLAGS(InterfaceFlags, InterfaceFlag)
+
+ QNetworkInterface();
+ QNetworkInterface(const QNetworkInterface &other);
+ QNetworkInterface &operator=(const QNetworkInterface &other);
+ ~QNetworkInterface();
+
+ bool isValid() const;
+
+ int index() const;
+ QString name() const;
+ QString humanReadableName() const;
+ InterfaceFlags flags() const;
+ QString hardwareAddress() const;
+ QList<QNetworkAddressEntry> addressEntries() const;
+
+ static QNetworkInterface interfaceFromName(const QString &name);
+ static QNetworkInterface interfaceFromIndex(int index);
+ static QList<QNetworkInterface> allInterfaces();
+ static QList<QHostAddress> allAddresses();
+
+private:
+ friend class QNetworkInterfacePrivate;
+ QSharedDataPointer<QNetworkInterfacePrivate> d;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QNetworkInterface::InterfaceFlags)
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QNetworkInterface &networkInterface);
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_NETWORKINTERFACE
+
+#endif
diff --git a/src/network/kernel/qnetworkinterface_p.h b/src/network/kernel/qnetworkinterface_p.h
new file mode 100644
index 0000000..c07e23c
--- /dev/null
+++ b/src/network/kernel/qnetworkinterface_p.h
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QNETWORKINTERFACEPRIVATE_H
+#define QNETWORKINTERFACEPRIVATE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qatomic.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qreadwritelock.h>
+#include <QtCore/qstring.h>
+#include <QtNetwork/qhostaddress.h>
+#include <QtNetwork/qabstractsocket.h>
+#include <private/qhostaddress_p.h>
+
+#ifndef QT_NO_NETWORKINTERFACE
+
+QT_BEGIN_NAMESPACE
+
+class QNetworkAddressEntryPrivate
+{
+public:
+ QHostAddress address;
+ QNetmaskAddress netmask;
+ QHostAddress broadcast;
+};
+
+class QNetworkInterfacePrivate: public QSharedData
+{
+public:
+ QNetworkInterfacePrivate() : index(0), flags(0)
+ { }
+ ~QNetworkInterfacePrivate()
+ { }
+
+ int index; // interface index, if know
+ QNetworkInterface::InterfaceFlags flags;
+
+ QString name;
+ QString friendlyName;
+ QString hardwareAddress;
+
+ QList<QNetworkAddressEntry> addressEntries;
+
+ static QString makeHwAddress(int len, uchar *data);
+
+private:
+ // disallow copying -- avoid detaching
+ QNetworkInterfacePrivate &operator=(const QNetworkInterfacePrivate &other);
+ QNetworkInterfacePrivate(const QNetworkInterfacePrivate &other);
+};
+
+class QNetworkInterfaceManager
+{
+public:
+ QNetworkInterfaceManager();
+ ~QNetworkInterfaceManager();
+
+ QSharedDataPointer<QNetworkInterfacePrivate> interfaceFromName(const QString &name);
+ QSharedDataPointer<QNetworkInterfacePrivate> interfaceFromIndex(int index);
+ QList<QSharedDataPointer<QNetworkInterfacePrivate> > allInterfaces();
+
+ // convenience:
+ QSharedDataPointer<QNetworkInterfacePrivate> empty;
+
+private:
+ QList<QNetworkInterfacePrivate *> scan();
+};
+
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_NETWORKINTERFACE
+
+#endif
diff --git a/src/network/kernel/qnetworkinterface_unix.cpp b/src/network/kernel/qnetworkinterface_unix.cpp
new file mode 100644
index 0000000..34a44ac
--- /dev/null
+++ b/src/network/kernel/qnetworkinterface_unix.cpp
@@ -0,0 +1,448 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qset.h"
+#include "qnetworkinterface.h"
+#include "qnetworkinterface_p.h"
+#include "qalgorithms.h"
+
+#ifndef QT_NO_NETWORKINTERFACE
+
+#define IP_MULTICAST // make AIX happy and define IFF_MULTICAST
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#ifdef Q_OS_SOLARIS
+# include <sys/sockio.h>
+#endif
+#include <net/if.h>
+
+#ifndef QT_NO_GETIFADDRS
+# include <ifaddrs.h>
+#endif
+
+#ifdef QT_LINUXBASE
+# include <arpa/inet.h>
+# ifndef SIOCGIFBRDADDR
+# define SIOCGIFBRDADDR 0x8919
+# endif
+#endif // QT_LINUXBASE
+
+#include <qplatformdefs.h>
+
+QT_BEGIN_NAMESPACE
+
+static QHostAddress addressFromSockaddr(sockaddr *sa)
+{
+ QHostAddress address;
+ if (!sa)
+ return address;
+
+ if (sa->sa_family == AF_INET)
+ address.setAddress(htonl(((sockaddr_in *)sa)->sin_addr.s_addr));
+#ifndef QT_NO_IPV6
+ else if (sa->sa_family == AF_INET6)
+ address.setAddress(((sockaddr_in6 *)sa)->sin6_addr.s6_addr);
+#endif
+ return address;
+
+}
+
+static QNetworkInterface::InterfaceFlags convertFlags(uint rawFlags)
+{
+ QNetworkInterface::InterfaceFlags flags = 0;
+ flags |= (rawFlags & IFF_UP) ? QNetworkInterface::IsUp : QNetworkInterface::InterfaceFlag(0);
+ flags |= (rawFlags & IFF_RUNNING) ? QNetworkInterface::IsRunning : QNetworkInterface::InterfaceFlag(0);
+ flags |= (rawFlags & IFF_BROADCAST) ? QNetworkInterface::CanBroadcast : QNetworkInterface::InterfaceFlag(0);
+ flags |= (rawFlags & IFF_LOOPBACK) ? QNetworkInterface::IsLoopBack : QNetworkInterface::InterfaceFlag(0);
+#ifdef IFF_POINTOPOINT //cygwin doesn't define IFF_POINTOPOINT
+ flags |= (rawFlags & IFF_POINTOPOINT) ? QNetworkInterface::IsPointToPoint : QNetworkInterface::InterfaceFlag(0);
+#endif
+
+#ifdef IFF_MULTICAST
+ flags |= (rawFlags & IFF_MULTICAST) ? QNetworkInterface::CanMulticast : QNetworkInterface::InterfaceFlag(0);
+#endif
+ return flags;
+}
+
+#ifdef QT_NO_GETIFADDRS
+// getifaddrs not available
+
+static const int STORAGEBUFFER_GROWTH = 256;
+
+static QSet<QByteArray> interfaceNames(int socket)
+{
+ QSet<QByteArray> result;
+#ifdef QT_NO_IPV6IFNAME
+ QByteArray storageBuffer;
+ struct ifconf interfaceList;
+
+ forever {
+ // grow the storage buffer
+ storageBuffer.resize(storageBuffer.size() + STORAGEBUFFER_GROWTH);
+ interfaceList.ifc_buf = storageBuffer.data();
+ interfaceList.ifc_len = storageBuffer.size();
+
+ // get the interface list
+ if (::ioctl(socket, SIOCGIFCONF, &interfaceList) >= 0) {
+ if (int(interfaceList.ifc_len + sizeof(ifreq) + 64) < storageBuffer.size()) {
+ // if the buffer was big enough, break
+ storageBuffer.resize(interfaceList.ifc_len);
+ break;
+ }
+ } else {
+ // internal error
+ return result;
+ }
+ if (storageBuffer.size() > 100000) {
+ // out of space
+ return result;
+ }
+ }
+
+ int interfaceCount = interfaceList.ifc_len / sizeof(ifreq);
+ for (int i = 0; i < interfaceCount; ++i) {
+ QByteArray name = QByteArray(interfaceList.ifc_req[i].ifr_name);
+ if (!name.isEmpty())
+ result << name;
+ }
+
+ return result;
+#else
+ Q_UNUSED(socket);
+
+ // use if_nameindex
+ struct if_nameindex *interfaceList = ::if_nameindex();
+ for (struct if_nameindex *ptr = interfaceList; ptr && ptr->if_name; ++ptr)
+ result << ptr->if_name;
+
+ if_freenameindex(interfaceList);
+ return result;
+#endif
+}
+
+static QNetworkInterfacePrivate *findInterface(int socket, QList<QNetworkInterfacePrivate *> &interfaces,
+ struct ifreq &req)
+{
+ QNetworkInterfacePrivate *iface = 0;
+ int ifindex = 0;
+
+#ifndef QT_NO_IPV6IFNAME
+ // Get the interface index
+ ifindex = if_nametoindex(req.ifr_name);
+
+ // find the interface data
+ QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
+ for ( ; if_it != interfaces.end(); ++if_it)
+ if ((*if_it)->index == ifindex) {
+ // existing interface
+ iface = *if_it;
+ break;
+ }
+#else
+ // Search by name
+ QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
+ for ( ; if_it != interfaces.end(); ++if_it)
+ if ((*if_it)->name == QLatin1String(req.ifr_name)) {
+ // existing interface
+ iface = *if_it;
+ break;
+ }
+#endif
+
+ if (!iface) {
+ // new interface, create data:
+ iface = new QNetworkInterfacePrivate;
+ iface->index = ifindex;
+ interfaces << iface;
+
+#ifdef SIOCGIFNAME
+ // Get the canonical name
+ QByteArray oldName = req.ifr_name;
+ if (::ioctl(socket, SIOCGIFNAME, &req) >= 0) {
+ iface->name = QString::fromLatin1(req.ifr_name);
+
+ // reset the name:
+ memcpy(req.ifr_name, oldName, qMin<int>(oldName.length() + 1, sizeof(req.ifr_name) - 1));
+ } else
+#endif
+ {
+ // use this name anyways
+ iface->name = QString::fromLatin1(req.ifr_name);
+ }
+
+ // Get interface flags
+ if (::ioctl(socket, SIOCGIFFLAGS, &req) >= 0) {
+ iface->flags = convertFlags(req.ifr_flags);
+ }
+
+#ifdef SIOCGIFHWADDR
+ // Get the HW address
+ if (::ioctl(socket, SIOCGIFHWADDR, &req) >= 0) {
+ uchar *addr = (uchar *)&req.ifr_addr;
+ iface->hardwareAddress = iface->makeHwAddress(6, addr);
+ }
+#endif
+ }
+
+ return iface;
+}
+
+static QList<QNetworkInterfacePrivate *> interfaceListing()
+{
+ QList<QNetworkInterfacePrivate *> interfaces;
+
+ int socket;
+ if ((socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) == -1)
+ return interfaces; // error
+
+ QSet<QByteArray> names = interfaceNames(socket);
+ QSet<QByteArray>::ConstIterator it = names.constBegin();
+ for ( ; it != names.constEnd(); ++it) {
+ ifreq req;
+ memset(&req, 0, sizeof(ifreq));
+ memcpy(req.ifr_name, *it, qMin<int>(it->length() + 1, sizeof(req.ifr_name) - 1));
+
+ QNetworkInterfacePrivate *iface = findInterface(socket, interfaces, req);
+
+ // Get the interface broadcast address
+ QNetworkAddressEntry entry;
+ if (iface->flags & QNetworkInterface::CanBroadcast) {
+ if (::ioctl(socket, SIOCGIFBRDADDR, &req) >= 0) {
+ sockaddr *sa = &req.ifr_addr;
+ if (sa->sa_family == AF_INET)
+ entry.setBroadcast(addressFromSockaddr(sa));
+ }
+ }
+
+ // Get the interface netmask
+ if (::ioctl(socket, SIOCGIFNETMASK, &req) >= 0) {
+ sockaddr *sa = &req.ifr_addr;
+ entry.setNetmask(addressFromSockaddr(sa));
+ }
+
+ // Get the address of the interface
+ if (::ioctl(socket, SIOCGIFADDR, &req) >= 0) {
+ sockaddr *sa = &req.ifr_addr;
+ entry.setIp(addressFromSockaddr(sa));
+ }
+
+ iface->addressEntries << entry;
+ }
+
+ ::close(socket);
+ return interfaces;
+}
+
+#else
+// use getifaddrs
+
+// platform-specific defs:
+# ifdef Q_OS_LINUX
+QT_BEGIN_INCLUDE_NAMESPACE
+# include <features.h>
+QT_END_INCLUDE_NAMESPACE
+# endif
+
+# if defined(Q_OS_LINUX) && __GLIBC__ - 0 >= 2 && __GLIBC_MINOR__ - 0 >= 1
+# include <netpacket/packet.h>
+
+static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList)
+{
+ QList<QNetworkInterfacePrivate *> interfaces;
+
+ for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next) {
+ if ( !ptr->ifa_addr )
+ continue;
+
+ // Get the interface index
+ int ifindex = if_nametoindex(ptr->ifa_name);
+
+ // on Linux we use AF_PACKET and sockaddr_ll to obtain hHwAddress
+ QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
+ for ( ; if_it != interfaces.end(); ++if_it)
+ if ((*if_it)->index == ifindex) {
+ // this one has been added already
+ if ( ptr->ifa_addr->sa_family == AF_PACKET
+ && (*if_it)->hardwareAddress.isEmpty()) {
+ sockaddr_ll *sll = (sockaddr_ll *)ptr->ifa_addr;
+ (*if_it)->hardwareAddress = (*if_it)->makeHwAddress(sll->sll_halen, (uchar*)sll->sll_addr);
+ }
+ break;
+ }
+ if ( if_it != interfaces.end() )
+ continue;
+
+ QNetworkInterfacePrivate *iface = new QNetworkInterfacePrivate;
+ interfaces << iface;
+ iface->index = ifindex;
+ iface->name = QString::fromLatin1(ptr->ifa_name);
+ iface->flags = convertFlags(ptr->ifa_flags);
+
+ if ( ptr->ifa_addr->sa_family == AF_PACKET ) {
+ sockaddr_ll *sll = (sockaddr_ll *)ptr->ifa_addr;
+ iface->hardwareAddress = iface->makeHwAddress(sll->sll_halen, (uchar*)sll->sll_addr);
+ }
+ }
+
+ return interfaces;
+}
+
+# elif defined(Q_OS_BSD4)
+QT_BEGIN_INCLUDE_NAMESPACE
+# include <net/if_dl.h>
+QT_END_INCLUDE_NAMESPACE
+
+static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList)
+{
+ QList<QNetworkInterfacePrivate *> interfaces;
+
+ // on NetBSD we use AF_LINK and sockaddr_dl
+ // scan the list for that family
+ for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next)
+ if (ptr->ifa_addr && ptr->ifa_addr->sa_family == AF_LINK) {
+ QNetworkInterfacePrivate *iface = new QNetworkInterfacePrivate;
+ interfaces << iface;
+
+ sockaddr_dl *sdl = (sockaddr_dl *)ptr->ifa_addr;
+ iface->index = sdl->sdl_index;
+ iface->name = QString::fromLatin1(ptr->ifa_name);
+ iface->flags = convertFlags(ptr->ifa_flags);
+ iface->hardwareAddress = iface->makeHwAddress(sdl->sdl_alen, (uchar*)LLADDR(sdl));
+ }
+
+ return interfaces;
+}
+
+# else // Generic version
+
+static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList)
+{
+ QList<QNetworkInterfacePrivate *> interfaces;
+
+ // make sure there's one entry for each interface
+ for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next) {
+ // Get the interface index
+ int ifindex = if_nametoindex(ptr->ifa_name);
+
+ QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
+ for ( ; if_it != interfaces.end(); ++if_it)
+ if ((*if_it)->index == ifindex)
+ // this one has been added already
+ break;
+
+ if (if_it == interfaces.end()) {
+ // none found, create
+ QNetworkInterfacePrivate *iface = new QNetworkInterfacePrivate;
+ interfaces << iface;
+
+ iface->index = ifindex;
+ iface->name = QString::fromLatin1(ptr->ifa_name);
+ iface->flags = convertFlags(ptr->ifa_flags);
+ }
+ }
+
+ return interfaces;
+}
+
+# endif
+
+
+static QList<QNetworkInterfacePrivate *> interfaceListing()
+{
+ QList<QNetworkInterfacePrivate *> interfaces;
+
+ int socket;
+ if ((socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) == -1)
+ return interfaces; // error
+
+ ifaddrs *interfaceListing;
+ if (getifaddrs(&interfaceListing) == -1) {
+ // error
+ ::close(socket);
+ return interfaces;
+ }
+
+ interfaces = createInterfaces(interfaceListing);
+ for (ifaddrs *ptr = interfaceListing; ptr; ptr = ptr->ifa_next) {
+ // Get the interface index
+ int ifindex = if_nametoindex(ptr->ifa_name);
+ QNetworkInterfacePrivate *iface = 0;
+ QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
+ for ( ; if_it != interfaces.end(); ++if_it)
+ if ((*if_it)->index == ifindex) {
+ // found this interface already
+ iface = *if_it;
+ break;
+ }
+ if (!iface) {
+ // skip all non-IP interfaces
+ continue;
+ }
+
+ QNetworkAddressEntry entry;
+ entry.setIp(addressFromSockaddr(ptr->ifa_addr));
+ if (entry.ip().isNull())
+ // could not parse the address
+ continue;
+
+ entry.setNetmask(addressFromSockaddr(ptr->ifa_netmask));
+ if (iface->flags & QNetworkInterface::CanBroadcast)
+ entry.setBroadcast(addressFromSockaddr(ptr->ifa_broadaddr));
+
+ iface->addressEntries << entry;
+ }
+
+ freeifaddrs(interfaceListing);
+ ::close(socket);
+ return interfaces;
+}
+#endif
+
+QList<QNetworkInterfacePrivate *> QNetworkInterfaceManager::scan()
+{
+ return interfaceListing();
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_NETWORKINTERFACE
diff --git a/src/network/kernel/qnetworkinterface_win.cpp b/src/network/kernel/qnetworkinterface_win.cpp
new file mode 100644
index 0000000..9540c18
--- /dev/null
+++ b/src/network/kernel/qnetworkinterface_win.cpp
@@ -0,0 +1,327 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qnetworkinterface.h"
+#include "qnetworkinterface_p.h"
+
+#ifndef QT_NO_NETWORKINTERFACE
+
+#include "qnetworkinterface_win_p.h"
+#include <qhostinfo.h>
+#include <qhash.h>
+#include <qurl.h>
+
+QT_BEGIN_NAMESPACE
+
+typedef DWORD (WINAPI *PtrGetAdaptersInfo)(PIP_ADAPTER_INFO, PULONG);
+static PtrGetAdaptersInfo ptrGetAdaptersInfo = 0;
+typedef ULONG (WINAPI *PtrGetAdaptersAddresses)(ULONG, ULONG, PVOID, PIP_ADAPTER_ADDRESSES, PULONG);
+static PtrGetAdaptersAddresses ptrGetAdaptersAddresses = 0;
+typedef DWORD (WINAPI *PtrGetNetworkParams)(PFIXED_INFO, PULONG);
+static PtrGetNetworkParams ptrGetNetworkParams = 0;
+
+static void resolveLibs()
+{
+ // try to find the functions we need from Iphlpapi.dll
+ static bool done = false;
+
+ if (!done) {
+ done = true;
+
+ HINSTANCE iphlpapiHnd;
+ QT_WA({
+ iphlpapiHnd = LoadLibraryW(L"iphlpapi");
+ }, {
+ iphlpapiHnd = LoadLibraryA("iphlpapi");
+ });
+ if (iphlpapiHnd == NULL)
+ return; // failed to load, probably Windows 95
+
+#if defined(Q_OS_WINCE)
+ ptrGetAdaptersInfo = (PtrGetAdaptersInfo)GetProcAddressW(iphlpapiHnd, L"GetAdaptersInfo");
+ ptrGetAdaptersAddresses = (PtrGetAdaptersAddresses)GetProcAddressW(iphlpapiHnd, L"GetAdaptersAddresses");
+ ptrGetNetworkParams = (PtrGetNetworkParams)GetProcAddressW(iphlpapiHnd, L"GetNetworkParams");
+#else
+ ptrGetAdaptersInfo = (PtrGetAdaptersInfo)GetProcAddress(iphlpapiHnd, "GetAdaptersInfo");
+ ptrGetAdaptersAddresses = (PtrGetAdaptersAddresses)GetProcAddress(iphlpapiHnd, "GetAdaptersAddresses");
+ ptrGetNetworkParams = (PtrGetNetworkParams)GetProcAddress(iphlpapiHnd, "GetNetworkParams");
+#endif
+ }
+}
+
+static QHostAddress addressFromSockaddr(sockaddr *sa)
+{
+ QHostAddress address;
+ if (!sa)
+ return address;
+
+ if (sa->sa_family == AF_INET)
+ address.setAddress(htonl(((sockaddr_in *)sa)->sin_addr.s_addr));
+ else if (sa->sa_family == AF_INET6)
+ address.setAddress(((qt_sockaddr_in6 *)sa)->sin6_addr.qt_s6_addr);
+ else
+ qWarning("Got unknown socket family %d", sa->sa_family);
+ return address;
+
+}
+
+static QHash<QHostAddress, QHostAddress> ipv4Netmasks()
+{
+ //Retrieve all the IPV4 addresses & netmasks
+ IP_ADAPTER_INFO staticBuf[2]; // 2 is arbitrary
+ PIP_ADAPTER_INFO pAdapter = staticBuf;
+ ULONG bufSize = sizeof staticBuf;
+ QHash<QHostAddress, QHostAddress> ipv4netmasks;
+
+ DWORD retval = ptrGetAdaptersInfo(pAdapter, &bufSize);
+ if (retval == ERROR_BUFFER_OVERFLOW) {
+ // need more memory
+ pAdapter = (IP_ADAPTER_INFO *)qMalloc(bufSize);
+ // try again
+ if (ptrGetAdaptersInfo(pAdapter, &bufSize) != ERROR_SUCCESS) {
+ qFree(pAdapter);
+ return ipv4netmasks;
+ }
+ } else if (retval != ERROR_SUCCESS) {
+ // error
+ return ipv4netmasks;
+ }
+
+ // iterate over the list and add the entries to our listing
+ for (PIP_ADAPTER_INFO ptr = pAdapter; ptr; ptr = ptr->Next) {
+ for (PIP_ADDR_STRING addr = &ptr->IpAddressList; addr; addr = addr->Next) {
+ QHostAddress address(QLatin1String(addr->IpAddress.String));
+ QHostAddress mask(QLatin1String(addr->IpMask.String));
+ ipv4netmasks[address] = mask;
+ }
+ }
+ if (pAdapter != staticBuf)
+ qFree(pAdapter);
+
+ return ipv4netmasks;
+
+}
+
+static QList<QNetworkInterfacePrivate *> interfaceListingWinXP()
+{
+ QList<QNetworkInterfacePrivate *> interfaces;
+ IP_ADAPTER_ADDRESSES staticBuf[2]; // 2 is arbitrary
+ PIP_ADAPTER_ADDRESSES pAdapter = staticBuf;
+ ULONG bufSize = sizeof staticBuf;
+
+ const QHash<QHostAddress, QHostAddress> &ipv4netmasks = ipv4Netmasks();
+ ULONG flags = GAA_FLAG_INCLUDE_ALL_INTERFACES |
+ GAA_FLAG_INCLUDE_PREFIX |
+ GAA_FLAG_SKIP_DNS_SERVER |
+ GAA_FLAG_SKIP_MULTICAST;
+ ULONG retval = ptrGetAdaptersAddresses(AF_UNSPEC, flags, NULL, pAdapter, &bufSize);
+ if (retval == ERROR_BUFFER_OVERFLOW) {
+ // need more memory
+ pAdapter = (IP_ADAPTER_ADDRESSES *)qMalloc(bufSize);
+
+ // try again
+ if (ptrGetAdaptersAddresses(AF_UNSPEC, flags, NULL, pAdapter, &bufSize) != ERROR_SUCCESS) {
+ qFree(pAdapter);
+ return interfaces;
+ }
+ } else if (retval != ERROR_SUCCESS) {
+ // error
+ return interfaces;
+ }
+
+ // iterate over the list and add the entries to our listing
+ for (PIP_ADAPTER_ADDRESSES ptr = pAdapter; ptr; ptr = ptr->Next) {
+ QNetworkInterfacePrivate *iface = new QNetworkInterfacePrivate;
+ interfaces << iface;
+
+ iface->index = 0;
+ if (ptr->Length >= offsetof(IP_ADAPTER_ADDRESSES, Ipv6IfIndex))
+ iface->index = ptr->Ipv6IfIndex;
+ else if (ptr->IfIndex != 0)
+ iface->index = ptr->IfIndex;
+
+ iface->flags = QNetworkInterface::CanBroadcast;
+ if (ptr->OperStatus == IfOperStatusUp)
+ iface->flags |= QNetworkInterface::IsUp | QNetworkInterface::IsRunning;
+ if ((ptr->Flags & IP_ADAPTER_NO_MULTICAST) == 0)
+ iface->flags |= QNetworkInterface::CanMulticast;
+
+ iface->name = QString::fromLocal8Bit(ptr->AdapterName);
+ iface->friendlyName = QString::fromWCharArray(ptr->FriendlyName);
+ if (ptr->PhysicalAddressLength)
+ iface->hardwareAddress = iface->makeHwAddress(ptr->PhysicalAddressLength,
+ ptr->PhysicalAddress);
+ else
+ // loopback if it has no address
+ iface->flags |= QNetworkInterface::IsLoopBack;
+
+ // The GetAdaptersAddresses call has an interesting semantic:
+ // It can return a number N of addresses and a number M of prefixes.
+ // But if you have IPv6 addresses, generally N > M.
+ // I cannot find a way to relate the Address to the Prefix, aside from stopping
+ // the iteration at the last Prefix entry and assume that it applies to all addresses
+ // from that point on.
+ PIP_ADAPTER_PREFIX pprefix = 0;
+ if (ptr->Length >= offsetof(IP_ADAPTER_ADDRESSES, FirstPrefix))
+ pprefix = ptr->FirstPrefix;
+ for (PIP_ADAPTER_UNICAST_ADDRESS addr = ptr->FirstUnicastAddress; addr; addr = addr->Next) {
+ QNetworkAddressEntry entry;
+ entry.setIp(addressFromSockaddr(addr->Address.lpSockaddr));
+ if (pprefix) {
+ if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol) {
+ entry.setNetmask(ipv4netmasks[entry.ip()]);
+
+ // broadcast address is set on postProcess()
+ } else { //IPV6
+ entry.setPrefixLength(pprefix->PrefixLength);
+ }
+ pprefix = pprefix->Next ? pprefix->Next : pprefix;
+ }
+ iface->addressEntries << entry;
+ }
+ }
+
+ if (pAdapter != staticBuf)
+ qFree(pAdapter);
+
+ return interfaces;
+}
+
+static QList<QNetworkInterfacePrivate *> interfaceListingWin2k()
+{
+ QList<QNetworkInterfacePrivate *> interfaces;
+ IP_ADAPTER_INFO staticBuf[2]; // 2 is arbitrary
+ PIP_ADAPTER_INFO pAdapter = staticBuf;
+ ULONG bufSize = sizeof staticBuf;
+
+ DWORD retval = ptrGetAdaptersInfo(pAdapter, &bufSize);
+ if (retval == ERROR_BUFFER_OVERFLOW) {
+ // need more memory
+ pAdapter = (IP_ADAPTER_INFO *)qMalloc(bufSize);
+
+ // try again
+ if (ptrGetAdaptersInfo(pAdapter, &bufSize) != ERROR_SUCCESS) {
+ qFree(pAdapter);
+ return interfaces;
+ }
+ } else if (retval != ERROR_SUCCESS) {
+ // error
+ return interfaces;
+ }
+
+ // iterate over the list and add the entries to our listing
+ for (PIP_ADAPTER_INFO ptr = pAdapter; ptr; ptr = ptr->Next) {
+ QNetworkInterfacePrivate *iface = new QNetworkInterfacePrivate;
+ interfaces << iface;
+
+ iface->index = ptr->Index;
+ iface->flags = QNetworkInterface::IsUp | QNetworkInterface::IsRunning;
+ if (ptr->Type == MIB_IF_TYPE_PPP)
+ iface->flags |= QNetworkInterface::IsPointToPoint;
+ else
+ iface->flags |= QNetworkInterface::CanBroadcast;
+ iface->name = QString::fromLocal8Bit(ptr->AdapterName);
+ iface->hardwareAddress = QNetworkInterfacePrivate::makeHwAddress(ptr->AddressLength,
+ ptr->Address);
+
+ for (PIP_ADDR_STRING addr = &ptr->IpAddressList; addr; addr = addr->Next) {
+ QNetworkAddressEntry entry;
+ entry.setIp(QHostAddress(QLatin1String(addr->IpAddress.String)));
+ entry.setNetmask(QHostAddress(QLatin1String(addr->IpMask.String)));
+ // broadcast address is set on postProcess()
+
+ iface->addressEntries << entry;
+ }
+ }
+
+ if (pAdapter != staticBuf)
+ qFree(pAdapter);
+
+ return interfaces;
+}
+
+static QList<QNetworkInterfacePrivate *> interfaceListing()
+{
+ resolveLibs();
+ if (ptrGetAdaptersAddresses != NULL)
+ return interfaceListingWinXP();
+ else if (ptrGetAdaptersInfo != NULL)
+ return interfaceListingWin2k();
+
+ // failed
+ return QList<QNetworkInterfacePrivate *>();
+}
+
+QList<QNetworkInterfacePrivate *> QNetworkInterfaceManager::scan()
+{
+ return interfaceListing();
+}
+
+QString QHostInfo::localDomainName()
+{
+ resolveLibs();
+ if (ptrGetNetworkParams == NULL)
+ return QString(); // couldn't resolve
+
+ FIXED_INFO info, *pinfo;
+ ULONG bufSize = sizeof info;
+ pinfo = &info;
+ if (ptrGetNetworkParams(pinfo, &bufSize) == ERROR_BUFFER_OVERFLOW) {
+ pinfo = (FIXED_INFO *)qMalloc(bufSize);
+
+ // try again
+ if (ptrGetNetworkParams(pinfo, &bufSize) != ERROR_SUCCESS) {
+ qFree(pinfo);
+ return QString(); // error
+ }
+ }
+
+ QString domainName = QUrl::fromAce(pinfo->DomainName);
+
+ if (pinfo != &info)
+ qFree(pinfo);
+
+ return domainName;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_NETWORKINTERFACE
diff --git a/src/network/kernel/qnetworkinterface_win_p.h b/src/network/kernel/qnetworkinterface_win_p.h
new file mode 100644
index 0000000..07425d0
--- /dev/null
+++ b/src/network/kernel/qnetworkinterface_win_p.h
@@ -0,0 +1,266 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QNETWORKINTERFACE_WIN_P_H
+#define QNETWORKINTERFACE_WIN_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <winsock2.h>
+#include <windows.h>
+#include <time.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef GAA_FLAG_INCLUDE_ALL_INTERFACES
+# define GAA_FLAG_INCLUDE_ALL_INTERFACES 0x0100
+#endif
+#ifndef MAX_ADAPTER_ADDRESS_LENGTH
+// definitions from iptypes.h
+# define MAX_ADAPTER_DESCRIPTION_LENGTH 128 // arb.
+# define MAX_ADAPTER_NAME_LENGTH 256 // arb.
+# define MAX_ADAPTER_ADDRESS_LENGTH 8 // arb.
+# define DEFAULT_MINIMUM_ENTITIES 32 // arb.
+# define MAX_HOSTNAME_LEN 128 // arb.
+# define MAX_DOMAIN_NAME_LEN 128 // arb.
+# define MAX_SCOPE_ID_LEN 256 // arb.
+
+# define GAA_FLAG_SKIP_UNICAST 0x0001
+# define GAA_FLAG_SKIP_ANYCAST 0x0002
+# define GAA_FLAG_SKIP_MULTICAST 0x0004
+# define GAA_FLAG_SKIP_DNS_SERVER 0x0008
+# define GAA_FLAG_INCLUDE_PREFIX 0x0010
+# define GAA_FLAG_SKIP_FRIENDLY_NAME 0x0020
+
+# define IP_ADAPTER_DDNS_ENABLED 0x01
+# define IP_ADAPTER_REGISTER_ADAPTER_SUFFIX 0x02
+# define IP_ADAPTER_DHCP_ENABLED 0x04
+# define IP_ADAPTER_RECEIVE_ONLY 0x08
+# define IP_ADAPTER_NO_MULTICAST 0x10
+# define IP_ADAPTER_IPV6_OTHER_STATEFUL_CONFIG 0x20
+
+# define MIB_IF_TYPE_OTHER 1
+# define MIB_IF_TYPE_ETHERNET 6
+# define MIB_IF_TYPE_TOKENRING 9
+# define MIB_IF_TYPE_FDDI 15
+# define MIB_IF_TYPE_PPP 23
+# define MIB_IF_TYPE_LOOPBACK 24
+# define MIB_IF_TYPE_SLIP 28
+
+#endif
+// copied from qnativesocketengine_win.cpp
+struct qt_in6_addr {
+ u_char qt_s6_addr[16];
+};
+typedef struct {
+ short sin6_family; /* AF_INET6 */
+ u_short sin6_port; /* Transport level port number */
+ u_long sin6_flowinfo; /* IPv6 flow information */
+ struct qt_in6_addr sin6_addr; /* IPv6 address */
+ u_long sin6_scope_id; /* set of interfaces for a scope */
+} qt_sockaddr_in6;
+
+// copied from MSDN online help
+typedef enum {
+ IpPrefixOriginOther = 0,
+ IpPrefixOriginManual,
+ IpPrefixOriginWellKnown,
+ IpPrefixOriginDhcp,
+ IpPrefixOriginRouterAdvertisement
+} IP_PREFIX_ORIGIN;
+
+typedef enum {
+ IpSuffixOriginOther = 0,
+ IpSuffixOriginManual,
+ IpSuffixOriginWellKnown,
+ IpSuffixOriginDhcp,
+ IpSuffixOriginLinkLayerAddress,
+ IpSuffixOriginRandom
+} IP_SUFFIX_ORIGIN;
+
+typedef enum {
+ IpDadStateInvalid = 0,
+ IpDadStateTentative,
+ IpDadStateDuplicate,
+ IpDadStateDeprecated,
+ IpDadStatePreferred,
+} IP_DAD_STATE;
+
+typedef enum {
+ IfOperStatusUp = 1,
+ IfOperStatusDown,
+ IfOperStatusTesting,
+ IfOperStatusUnknown,
+ IfOperStatusDormant,
+ IfOperStatusNotPresent,
+ IfOperStatusLowerLayerDown
+} IF_OPER_STATUS;
+
+typedef struct _IP_ADAPTER_UNICAST_ADDRESS {
+ union {
+ ULONGLONG Alignment;
+ struct {
+ ULONG Length;
+ DWORD Flags;
+ };
+ };
+ struct _IP_ADAPTER_UNICAST_ADDRESS* Next;
+ SOCKET_ADDRESS Address;
+ IP_PREFIX_ORIGIN PrefixOrigin;
+ IP_SUFFIX_ORIGIN SuffixOrigin;
+ IP_DAD_STATE DadState;
+ ULONG ValidLifetime;
+ ULONG PreferredLifetime;
+ ULONG LeaseLifetime;
+} IP_ADAPTER_UNICAST_ADDRESS, *PIP_ADAPTER_UNICAST_ADDRESS;
+
+typedef struct _IP_ADAPTER_ANYCAST_ADDRESS
+ IP_ADAPTER_ANYCAST_ADDRESS, *PIP_ADAPTER_ANYCAST_ADDRESS;
+
+typedef struct _IP_ADAPTER_MULTICAST_ADDRESS
+ IP_ADAPTER_MULTICAST_ADDRESS,
+ *PIP_ADAPTER_MULTICAST_ADDRESS;
+
+typedef struct _IP_ADAPTER_DNS_SERVER_ADDRESS
+ IP_ADAPTER_DNS_SERVER_ADDRESS,
+ *PIP_ADAPTER_DNS_SERVER_ADDRESS;
+
+typedef struct _IP_ADAPTER_PREFIX {
+ union {
+ ULONGLONG Alignment;
+ struct {
+ ULONG Length;
+ DWORD Flags;
+ };
+ };
+ struct _IP_ADAPTER_PREFIX* Next;
+ SOCKET_ADDRESS Address;
+ ULONG PrefixLength;
+} IP_ADAPTER_PREFIX,
+ *PIP_ADAPTER_PREFIX;
+
+typedef struct _IP_ADAPTER_ADDRESSES {
+ union {
+ ULONGLONG Alignment;
+ struct {
+ ULONG Length;
+ DWORD IfIndex;
+ };
+ };
+ struct _IP_ADAPTER_ADDRESSES* Next;
+ PCHAR AdapterName;
+ PIP_ADAPTER_UNICAST_ADDRESS FirstUnicastAddress;
+ PIP_ADAPTER_ANYCAST_ADDRESS FirstAnycastAddress;
+ PIP_ADAPTER_MULTICAST_ADDRESS FirstMulticastAddress;
+ PIP_ADAPTER_DNS_SERVER_ADDRESS FirstDnsServerAddress;
+ PWCHAR DnsSuffix;
+ PWCHAR Description;
+ PWCHAR FriendlyName;
+ BYTE PhysicalAddress[MAX_ADAPTER_ADDRESS_LENGTH];
+ DWORD PhysicalAddressLength;
+ DWORD Flags;
+ DWORD Mtu;
+ DWORD IfType;
+ IF_OPER_STATUS OperStatus;
+ DWORD Ipv6IfIndex;
+ DWORD ZoneIndices[16];
+ PIP_ADAPTER_PREFIX FirstPrefix;
+} IP_ADAPTER_ADDRESSES,
+ *PIP_ADAPTER_ADDRESSES;
+
+typedef struct {
+ char String[4 * 4];
+} IP_ADDRESS_STRING, *PIP_ADDRESS_STRING, IP_MASK_STRING, *PIP_MASK_STRING;
+
+typedef struct _IP_ADDR_STRING {
+ struct _IP_ADDR_STRING* Next;
+ IP_ADDRESS_STRING IpAddress;
+ IP_MASK_STRING IpMask;
+ DWORD Context;
+} IP_ADDR_STRING,
+ *PIP_ADDR_STRING;
+
+typedef struct _IP_ADAPTER_INFO {
+ struct _IP_ADAPTER_INFO* Next;
+ DWORD ComboIndex;
+ char AdapterName[MAX_ADAPTER_NAME_LENGTH + 4];
+ char Description[MAX_ADAPTER_DESCRIPTION_LENGTH + 4];
+ UINT AddressLength;
+ BYTE Address[MAX_ADAPTER_ADDRESS_LENGTH];
+ DWORD Index;
+ UINT Type;
+ UINT DhcpEnabled;
+ PIP_ADDR_STRING CurrentIpAddress;
+ IP_ADDR_STRING IpAddressList;
+ IP_ADDR_STRING GatewayList;
+ IP_ADDR_STRING DhcpServer;
+ BOOL HaveWins;
+ IP_ADDR_STRING PrimaryWinsServer;
+ IP_ADDR_STRING SecondaryWinsServer;
+ time_t LeaseObtained;
+ time_t LeaseExpires;
+} IP_ADAPTER_INFO,
+ *PIP_ADAPTER_INFO;
+
+typedef struct {
+ char HostName[MAX_HOSTNAME_LEN + 4];
+ char DomainName[MAX_DOMAIN_NAME_LEN + 4];
+ PIP_ADDR_STRING CurrentDnsServer;
+ IP_ADDR_STRING DnsServerList;
+ UINT NodeType;
+ char ScopeId[MAX_SCOPE_ID_LEN + 4];
+ UINT EnableRouting;
+ UINT EnableProxy;
+ UINT EnableDns;
+} FIXED_INFO, *PFIXED_INFO;
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/network/kernel/qnetworkproxy.cpp b/src/network/kernel/qnetworkproxy.cpp
new file mode 100644
index 0000000..f4ece97
--- /dev/null
+++ b/src/network/kernel/qnetworkproxy.cpp
@@ -0,0 +1,1255 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+/*!
+ \class QNetworkProxy
+
+ \since 4.1
+
+ \brief The QNetworkProxy class provides a network layer proxy.
+
+ \reentrant
+ \ingroup io
+ \inmodule QtNetwork
+
+ QNetworkProxy provides the method for configuring network layer
+ proxy support to the Qt network classes. The currently supported
+ classes are QAbstractSocket, QTcpSocket, QUdpSocket, QTcpServer,
+ QHttp and QFtp. The proxy support is designed to be as transparent
+ as possible. This means that existing network-enabled applications
+ that you have written should automatically support network proxy
+ using the following code.
+
+ \snippet doc/src/snippets/code/src_network_kernel_qnetworkproxy.cpp 0
+
+ An alternative to setting an application wide proxy is to specify
+ the proxy for individual sockets using QAbstractSocket::setProxy()
+ and QTcpServer::setProxy(). In this way, it is possible to disable
+ the use of a proxy for specific sockets using the following code:
+
+ \snippet doc/src/snippets/code/src_network_kernel_qnetworkproxy.cpp 1
+
+ Network proxy is not used if the address used in \l
+ {QAbstractSocket::connectToHost()}{connectToHost()}, \l
+ {QUdpSocket::bind()}{bind()} or \l
+ {QTcpServer::listen()}{listen()} is equivalent to
+ QHostAddress::LocalHost or QHostAddress::LocalHostIPv6.
+
+ Each type of proxy support has certain restrictions associated with it.
+ You should read the \l{ProxyType} documentation carefully before
+ selecting a proxy type to use.
+
+ \note Changes made to currently connected sockets do not take effect.
+ If you need to change a connected socket, you should reconnect it.
+
+ \section1 SOCKS5
+
+ The SOCKS5 support in Qt 4 is based on \l{RFC 1928} and \l{RFC 1929}.
+ The supported authentication methods are no authentication and
+ username/password authentication. Both IPv4 and IPv6 are
+ supported, but domain name resolution via the SOCKS server is not
+ supported; i.e. all domain names are resolved locally. There are
+ several things to remember when using SOCKS5 with QUdpSocket and
+ QTcpServer:
+
+ With QUdpSocket, a call to \l {QUdpSocket::bind()}{bind()} may fail
+ with a timeout error. If a port number other than 0 is passed to
+ \l {QUdpSocket::bind()}{bind()}, it is not guaranteed that it is the
+ specified port that will be used.
+ Use \l{QUdpSocket::localPort()}{localPort()} and
+ \l{QUdpSocket::localAddress()}{localAddress()} to get the actual
+ address and port number in use. Because proxied UDP goes through
+ two UDP connections, it is more likely that packets will be dropped.
+
+ With QTcpServer a call to \l{QTcpServer::listen()}{listen()} may
+ fail with a timeout error. If a port number other than 0 is passed
+ to \l{QTcpServer::listen()}{listen()}, then it is not guaranteed
+ that it is the specified port that will be used.
+ Use \l{QTcpServer::serverPort()}{serverPort()} and
+ \l{QTcpServer::serverAddress()}{serverAddress()} to get the actual
+ address and port used to listen for connections. SOCKS5 only supports
+ one accepted connection per call to \l{QTcpServer::listen()}{listen()},
+ and each call is likely to result in a different
+ \l{QTcpServer::serverPort()}{serverPort()} being used.
+
+ \sa QAbstractSocket, QTcpServer
+*/
+
+/*!
+ \enum QNetworkProxy::ProxyType
+
+ This enum describes the types of network proxying provided in Qt.
+
+ There are two types of proxies that Qt understands:
+ transparent proxies and caching proxies. The first group consists
+ of proxies that can handle any arbitrary data transfer, while the
+ second can only handle specific requests. The caching proxies only
+ make sense for the specific classes where they can be used.
+
+ \value NoProxy No proxying is used
+ \value DefaultProxy Proxy is determined based on the application proxy set using setApplicationProxy()
+ \value Socks5Proxy \l Socks5 proxying is used
+ \value HttpProxy HTTP transparent proxying is used
+ \value HttpCachingProxy Proxying for HTTP requests only
+ \value FtpCachingProxy Proxying for FTP requests only
+
+ The table below lists different proxy types and their
+ capabilities. Since each proxy type has different capabilities, it
+ is important to understand them before choosing a proxy type.
+
+ \table
+ \header
+ \o Proxy type
+ \o Description
+ \o Default capabilities
+
+ \row
+ \o SOCKS 5
+ \o Generic proxy for any kind of connection. Supports TCP,
+ UDP, binding to a port (incoming connections) and
+ authentication.
+ \o TunnelingCapability, ListeningCapability,
+ UdpTunnelingCapability, HostNameLookupCapability
+
+ \row
+ \o HTTP
+ \o Implemented using the "CONNECT" command, supports only
+ outgoing TCP connections; supports authentication.
+ \o TunnelingCapability, CachingCapability, HostNameLookupCapability
+
+ \row
+ \o Caching-only HTTP
+ \o Implemented using normal HTTP commands, it is useful only
+ in the context of HTTP requests (see QHttp,
+ QNetworkAccessManager)
+ \o CachingCapability, HostNameLookupCapability
+
+ \row
+ \o Caching FTP
+ \o Implemented using an FTP proxy, it is useful only in the
+ context of FTP requests (see QFtp,
+ QNetworkAccessManager)
+ \o CachingCapability, HostNameLookupCapability
+
+ \endtable
+
+ Also note that you shouldn't set the application default proxy
+ (setApplicationProxy()) to a proxy that doesn't have the
+ TunnelingCapability capability. If you do, QTcpSocket will not
+ know how to open connections.
+
+ \sa setType(), type(), capabilities(), setCapabilities()
+*/
+
+/*!
+ \enum QNetworkProxy::Capability
+ \since 4.5
+
+ These flags indicate the capabilities that a given proxy server
+ supports.
+
+ QNetworkProxy sets different capabilities by default when the
+ object is created (see QNetworkProxy::ProxyType for a list of the
+ defaults). However, it is possible to change the capabitilies
+ after the object has been created with setCapabilities().
+
+ The capabilities that QNetworkProxy supports are:
+
+ \value TunnelingCapability Ability to open transparent, tunneled
+ TCP connections to a remote host. The proxy server relays the
+ transmission verbatim from one side to the other and does no
+ caching.
+
+ \value ListeningCapability Ability to create a listening socket
+ and wait for an incoming TCP connection from a remote host.
+
+ \value UdpTunnelingCapability Ability to relay UDP datagrams via
+ the proxy server to and from a remote host.
+
+ \value CachingCapability Ability to cache the contents of the
+ transfer. This capability is specific to each protocol and proxy
+ type. For example, HTTP proxies can cache the contents of web data
+ transferred with "GET" commands.
+
+ \value HostNameLookupCapability Ability to connect to perform the
+ lookup on a remote host name and connect to it, as opposed to
+ requiring the application to perform the name lookup and request
+ connection to IP addresses only.
+*/
+
+#include "qnetworkproxy.h"
+
+#ifndef QT_NO_NETWORKPROXY
+
+#include "private/qsocks5socketengine_p.h"
+#include "private/qhttpsocketengine_p.h"
+#include "qauthenticator.h"
+#include "qhash.h"
+#include "qmutex.h"
+#include "qurl.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSocks5SocketEngineHandler;
+class QHttpSocketEngineHandler;
+
+class QGlobalNetworkProxy
+{
+public:
+ QGlobalNetworkProxy()
+ : mutex(QMutex::Recursive)
+ , applicationLevelProxy(0)
+ , applicationLevelProxyFactory(0)
+ , socks5SocketEngineHandler(0)
+ , httpSocketEngineHandler(0)
+ {
+ }
+
+ ~QGlobalNetworkProxy()
+ {
+ delete applicationLevelProxy;
+ delete applicationLevelProxyFactory;
+ delete socks5SocketEngineHandler;
+ delete httpSocketEngineHandler;
+ }
+
+ void init()
+ {
+ QMutexLocker lock(&mutex);
+#ifndef QT_NO_SOCKS5
+ if (!socks5SocketEngineHandler)
+ socks5SocketEngineHandler = new QSocks5SocketEngineHandler();
+#endif
+#ifndef QT_NO_HTTP
+ if (!httpSocketEngineHandler)
+ httpSocketEngineHandler = new QHttpSocketEngineHandler();
+#endif
+ }
+
+ void setApplicationProxy(const QNetworkProxy &proxy)
+ {
+ QMutexLocker lock(&mutex);
+ if (!applicationLevelProxy)
+ applicationLevelProxy = new QNetworkProxy;
+ *applicationLevelProxy = proxy;
+ delete applicationLevelProxyFactory;
+ applicationLevelProxyFactory = 0;
+ }
+
+ void setApplicationProxyFactory(QNetworkProxyFactory *factory)
+ {
+ QMutexLocker lock(&mutex);
+ if (applicationLevelProxy)
+ *applicationLevelProxy = QNetworkProxy();
+ delete applicationLevelProxyFactory;
+ applicationLevelProxyFactory = factory;
+ }
+
+ QNetworkProxy applicationProxy()
+ {
+ return proxyForQuery(QNetworkProxyQuery()).first();
+ }
+
+ QList<QNetworkProxy> proxyForQuery(const QNetworkProxyQuery &query);
+
+private:
+ QMutex mutex;
+ QNetworkProxy *applicationLevelProxy;
+ QNetworkProxyFactory *applicationLevelProxyFactory;
+ QSocks5SocketEngineHandler *socks5SocketEngineHandler;
+ QHttpSocketEngineHandler *httpSocketEngineHandler;
+};
+
+QList<QNetworkProxy> QGlobalNetworkProxy::proxyForQuery(const QNetworkProxyQuery &query)
+{
+ QMutexLocker locker(&mutex);
+
+ QList<QNetworkProxy> result;
+ if (!applicationLevelProxyFactory) {
+ if (applicationLevelProxy
+ && applicationLevelProxy->type() != QNetworkProxy::DefaultProxy)
+ result << *applicationLevelProxy;
+ else
+ result << QNetworkProxy(QNetworkProxy::NoProxy);
+ return result;
+ }
+
+ // we have a factory
+ result = applicationLevelProxyFactory->queryProxy(query);
+ if (result.isEmpty()) {
+ qWarning("QNetworkProxyFactory: factory %p has returned an empty result set",
+ applicationLevelProxyFactory);
+ result << QNetworkProxy(QNetworkProxy::NoProxy);
+ }
+ return result;
+}
+
+Q_GLOBAL_STATIC(QGlobalNetworkProxy, globalNetworkProxy);
+
+namespace {
+ template<bool> struct StaticAssertTest;
+ template<> struct StaticAssertTest<true> { enum { Value = 1 }; };
+}
+
+static inline void qt_noop_with_arg(int) {}
+#define q_static_assert(expr) qt_noop_with_arg(sizeof(StaticAssertTest< expr >::Value))
+
+static QNetworkProxy::Capabilities defaultCapabilitiesForType(QNetworkProxy::ProxyType type)
+{
+ q_static_assert(int(QNetworkProxy::DefaultProxy) == 0);
+ q_static_assert(int(QNetworkProxy::FtpCachingProxy) == 5);
+ static const int defaults[] =
+ {
+ /* [QNetworkProxy::DefaultProxy] = */
+ (int(QNetworkProxy::ListeningCapability) |
+ int(QNetworkProxy::TunnelingCapability) |
+ int(QNetworkProxy::UdpTunnelingCapability)),
+ /* [QNetworkProxy::Socks5Proxy] = */
+ (int(QNetworkProxy::TunnelingCapability) |
+ int(QNetworkProxy::ListeningCapability) |
+ int(QNetworkProxy::UdpTunnelingCapability) |
+ int(QNetworkProxy::HostNameLookupCapability)),
+ // it's weird to talk about the proxy capabilities of a "not proxy"...
+ /* [QNetworkProxy::NoProxy] = */
+ (int(QNetworkProxy::ListeningCapability) |
+ int(QNetworkProxy::TunnelingCapability) |
+ int(QNetworkProxy::UdpTunnelingCapability)),
+ /* [QNetworkProxy::HttpProxy] = */
+ (int(QNetworkProxy::TunnelingCapability) |
+ int(QNetworkProxy::CachingCapability) |
+ int(QNetworkProxy::HostNameLookupCapability)),
+ /* [QNetworkProxy::HttpCachingProxy] = */
+ (int(QNetworkProxy::CachingCapability) |
+ int(QNetworkProxy::HostNameLookupCapability)),
+ /* [QNetworkProxy::FtpCachingProxy] = */
+ (int(QNetworkProxy::CachingCapability) |
+ int(QNetworkProxy::HostNameLookupCapability)),
+ };
+
+ Q_ASSERT(int(type) >= 0 && int(type) <= int(QNetworkProxy::FtpCachingProxy));
+ return QNetworkProxy::Capabilities(defaults[int(type)]);
+}
+
+class QNetworkProxyPrivate: public QSharedData
+{
+public:
+ QString hostName;
+ QString user;
+ QString password;
+ QNetworkProxy::Capabilities capabilities;
+ quint16 port;
+ QNetworkProxy::ProxyType type;
+
+ inline QNetworkProxyPrivate(QNetworkProxy::ProxyType t = QNetworkProxy::DefaultProxy,
+ const QString &h = QString(), quint16 p = 0,
+ const QString &u = QString(), const QString &pw = QString())
+ : hostName(h),
+ user(u),
+ password(pw),
+ capabilities(defaultCapabilitiesForType(t)),
+ port(p),
+ type(t)
+ { }
+
+ inline bool operator==(const QNetworkProxyPrivate &other) const
+ {
+ return type == other.type &&
+ port == other.port &&
+ hostName == other.hostName &&
+ user == other.user &&
+ password == other.password &&
+ capabilities == other.capabilities;
+ }
+};
+
+template<> void QSharedDataPointer<QNetworkProxyPrivate>::detach()
+{
+ if (d && d->ref == 1)
+ return;
+ QNetworkProxyPrivate *x = (d ? new QNetworkProxyPrivate(*d)
+ : new QNetworkProxyPrivate);
+ x->ref.ref();
+ if (d && !d->ref.deref())
+ delete d;
+ d = x;
+}
+
+/*!
+ Constructs a QNetworkProxy with DefaultProxy type; the proxy type is
+ determined by applicationProxy(), which defaults to NoProxy.
+
+ \sa setType(), setApplicationProxy()
+*/
+QNetworkProxy::QNetworkProxy()
+ : d(0)
+{
+ globalNetworkProxy()->init();
+}
+
+/*!
+ Constructs a QNetworkProxy with \a type, \a hostName, \a port,
+ \a user and \a password.
+
+ The default capabilities for proxy type \a type are set automatically.
+
+ \sa capabilities()
+*/
+QNetworkProxy::QNetworkProxy(ProxyType type, const QString &hostName, quint16 port,
+ const QString &user, const QString &password)
+ : d(new QNetworkProxyPrivate(type, hostName, port, user, password))
+{
+ globalNetworkProxy()->init();
+}
+
+/*!
+ Constructs a copy of \a other.
+*/
+QNetworkProxy::QNetworkProxy(const QNetworkProxy &other)
+ : d(other.d)
+{
+}
+
+/*!
+ Destroys the QNetworkProxy object.
+*/
+QNetworkProxy::~QNetworkProxy()
+{
+ // QSharedDataPointer takes care of deleting for us
+}
+
+/*!
+ \since 4.4
+
+ Compares the value of this network proxy to \a other and returns true
+ if they are equal (same proxy type, server as well as username and password)
+*/
+bool QNetworkProxy::operator==(const QNetworkProxy &other) const
+{
+ return d == other.d || (d && other.d && *d == *other.d);
+}
+
+/*!
+ \fn bool QNetworkProxy::operator!=(const QNetworkProxy &other) const
+ \since 4.4
+
+ Compares the value of this network proxy to \a other and returns true
+ if they differ.
+\*/
+
+/*!
+ \since 4.2
+
+ Assigns the value of the network proxy \a other to this network proxy.
+*/
+QNetworkProxy &QNetworkProxy::operator=(const QNetworkProxy &other)
+{
+ d = other.d;
+ return *this;
+}
+
+/*!
+ Sets the proxy type for this instance to be \a type.
+
+ Note that changing the type of a proxy does not change
+ the set of capabilities this QNetworkProxy object holds.
+
+ \sa type(), setCapabilities()
+*/
+void QNetworkProxy::setType(QNetworkProxy::ProxyType type)
+{
+ d->type = type;
+}
+
+/*!
+ Returns the proxy type for this instance.
+
+ \sa setType()
+*/
+QNetworkProxy::ProxyType QNetworkProxy::type() const
+{
+ return d ? d->type : DefaultProxy;
+}
+
+/*!
+ \since 4.5
+
+ Sets the capabilities of this proxy to \a capabilities.
+
+ \sa setType(), capabilities()
+*/
+void QNetworkProxy::setCapabilities(Capabilities capabilities)
+{
+ d->capabilities = capabilities;
+}
+
+/*!
+ \since 4.5
+
+ Returns the capabilities of this proxy server.
+
+ \sa setCapabilities(), type()
+*/
+QNetworkProxy::Capabilities QNetworkProxy::capabilities() const
+{
+ return d ? d->capabilities : defaultCapabilitiesForType(DefaultProxy);
+}
+
+/*!
+ \since 4.4
+
+ Returns true if this proxy supports the
+ QNetworkProxy::CachingCapability capability.
+
+ In Qt 4.4, the capability was tied to the proxy type, but since Qt
+ 4.5 it is possible to remove the capability of caching from a
+ proxy by calling setCapabilities().
+
+ \sa capabilities(), type(), isTransparentProxy()
+*/
+bool QNetworkProxy::isCachingProxy() const
+{
+ return capabilities() & CachingCapability;
+}
+
+/*!
+ \since 4.4
+
+ Returns true if this proxy supports transparent tunneling of TCP
+ connections. This matches the QNetworkProxy::TunnelingCapability
+ capability.
+
+ In Qt 4.4, the capability was tied to the proxy type, but since Qt
+ 4.5 it is possible to remove the capability of caching from a
+ proxy by calling setCapabilities().
+
+ \sa capabilities(), type(), isCachingProxy()
+*/
+bool QNetworkProxy::isTransparentProxy() const
+{
+ return capabilities() & TunnelingCapability;
+}
+
+/*!
+ Sets the user name for proxy authentication to be \a user.
+
+ \sa user(), setPassword(), password()
+*/
+void QNetworkProxy::setUser(const QString &user)
+{
+ d->user = user;
+}
+
+/*!
+ Returns the user name used for authentication.
+
+ \sa setUser(), setPassword(), password()
+*/
+QString QNetworkProxy::user() const
+{
+ return d ? d->user : QString();
+}
+
+/*!
+ Sets the password for proxy authentication to be \a password.
+
+ \sa user(), setUser(), password()
+*/
+void QNetworkProxy::setPassword(const QString &password)
+{
+ d->password = password;
+}
+
+/*!
+ Returns the password used for authentication.
+
+ \sa user(), setPassword(), setUser()
+*/
+QString QNetworkProxy::password() const
+{
+ return d ? d->password : QString();
+}
+
+/*!
+ Sets the host name of the proxy host to be \a hostName.
+
+ \sa hostName(), setPort(), port()
+*/
+void QNetworkProxy::setHostName(const QString &hostName)
+{
+ d->hostName = hostName;
+}
+
+/*!
+ Returns the host name of the proxy host.
+
+ \sa setHostName(), setPort(), port()
+*/
+QString QNetworkProxy::hostName() const
+{
+ return d ? d->hostName : QString();
+}
+
+/*!
+ Sets the port of the proxy host to be \a port.
+
+ \sa hostName(), setHostName(), port()
+*/
+void QNetworkProxy::setPort(quint16 port)
+{
+ d->port = port;
+}
+
+/*!
+ Returns the port of the proxy host.
+
+ \sa setHostName(), setPort(), hostName()
+*/
+quint16 QNetworkProxy::port() const
+{
+ return d ? d->port : 0;
+}
+
+/*!
+ Sets the application level network proxying to be \a networkProxy.
+
+ If a QAbstractSocket or QTcpSocket has the
+ QNetworkProxy::DefaultProxy type, then the QNetworkProxy set with
+ this function is used. If you want more flexibility in determining
+ which the proxy, use the QNetworkProxyFactory class.
+
+ Setting a default proxy value with this function will override the
+ application proxy factory set with
+ QNetworkProxyFactory::setApplicationProxyFactory.
+
+ \sa QNetworkProxyFactory, applicationProxy(), QAbstractSocket::setProxy(), QTcpServer::setProxy()
+*/
+void QNetworkProxy::setApplicationProxy(const QNetworkProxy &networkProxy)
+{
+ if (globalNetworkProxy()) {
+ // don't accept setting the proxy to DefaultProxy
+ if (networkProxy.type() == DefaultProxy)
+ globalNetworkProxy()->setApplicationProxy(QNetworkProxy::NoProxy);
+ else
+ globalNetworkProxy()->setApplicationProxy(networkProxy);
+ }
+}
+
+/*!
+ Returns the application level network proxying.
+
+ If a QAbstractSocket or QTcpSocket has the
+ QNetworkProxy::DefaultProxy type, then the QNetworkProxy returned
+ by this function is used.
+
+ \sa QNetworkProxyFactory, setApplicationProxy(), QAbstractSocket::proxy(), QTcpServer::proxy()
+*/
+QNetworkProxy QNetworkProxy::applicationProxy()
+{
+ if (globalNetworkProxy())
+ return globalNetworkProxy()->applicationProxy();
+ return QNetworkProxy();
+}
+
+class QNetworkProxyQueryPrivate: public QSharedData
+{
+public:
+ inline QNetworkProxyQueryPrivate()
+ : localPort(-1), type(QNetworkProxyQuery::TcpSocket)
+ { }
+
+ bool operator==(const QNetworkProxyQueryPrivate &other) const
+ {
+ return type == other.type &&
+ localPort == other.localPort &&
+ remote == other.remote;
+ }
+
+ QUrl remote;
+ int localPort;
+ QNetworkProxyQuery::QueryType type;
+};
+
+template<> void QSharedDataPointer<QNetworkProxyQueryPrivate>::detach()
+{
+ if (d && d->ref == 1)
+ return;
+ QNetworkProxyQueryPrivate *x = (d ? new QNetworkProxyQueryPrivate(*d)
+ : new QNetworkProxyQueryPrivate);
+ x->ref.ref();
+ if (d && !d->ref.deref())
+ delete d;
+ d = x;
+}
+
+/*!
+ \class QNetworkProxyQuery
+ \since 4.5
+ \inmodule QtNetwork
+ \brief The QNetworkProxyQuery class is used to query the proxy
+ settings for a socket
+
+ QNetworkProxyQuery holds the details of a socket being created or
+ request being made. It is used by QNetworkProxy and
+ QNetworkProxyFactory to allow applications to have a more
+ fine-grained control over which proxy servers are used, depending
+ on the details of the query. This allows an application to apply
+ different settings, according to the protocol or destination
+ hostname, for instance.
+
+ QNetworkProxyQuery supports the following criteria for selecting
+ the proxy:
+
+ \list
+ \o the type of query
+ \o the local port number to use
+ \o the destination host name
+ \o the destination port number
+ \o the protocol name, such as "http" or "ftp"
+ \o the URL being requested
+ \endlist
+
+ The destination host name is the host in the connection in the
+ case of outgoing connection sockets. It is the \c hostName
+ parameter passed to QTcpSocket::connectToHost() or the host
+ component of a URL requested with QNetworkRequest.
+
+ The destination port number is the requested port to connect to in
+ the case of outgoing sockets, while the local port number is the
+ port the socket wishes to use locally before attempting the
+ external connection. In most cases, the local port number is used
+ by listening sockets only (QTcpSocket) or by datagram sockets
+ (QUdpSocket).
+
+ The protocol name is an arbitrary string that indicates the type
+ of connection being attempted. For example, it can match the
+ scheme of a URL, like "http", "https" and "ftp". In most cases,
+ the proxy selection will not change depending on the protocol, but
+ this information is provided in case a better choice can be made,
+ like choosing an caching HTTP proxy for HTTP-based connections,
+ but a more powerful SOCKSv5 proxy for all others.
+
+ Some of the criteria may not make sense in all of the types of
+ query. The following table lists the criteria that are most
+ commonly used, according to the type of query.
+
+ \table
+ \header
+ \o Query type
+ \o Description
+
+ \row
+ \o TcpSocket
+ \o Normal sockets requesting a connection to a remote server,
+ like QTcpSocket. The peer hostname and peer port match the
+ values passed to QTcpSocket::connectToHost(). The local port
+ is usually -1, indicating the socket has no preference in
+ which port should be used. The URL component is not used.
+
+ \row
+ \o UdpSocket
+ \o Datagram-based sockets, which can both send and
+ receive. The local port, remote host or remote port fields
+ can all be used or be left unused, depending on the
+ characteristics of the socket. The URL component is not used.
+
+ \row
+ \o TcpServer
+ \o Passive server sockets that listen on a port and await
+ incoming connections from the network. Normally, only the
+ local port is used, but the remote address could be used in
+ specific circumstances, for example to indicate which remote
+ host a connection is expected from. The URL component is not used.
+
+ \row
+ \o UrlRequest
+ \o A more high-level request, such as those coming from
+ QNetworkAccessManager. These requests will inevitably use an
+ outgoing TCP socket, but the this query type is provided to
+ indicate that more detailed information is present in the URL
+ component. For ease of implementation, the URL's host and
+ port are set as the destination address.
+ \endtable
+
+ It should be noted that any of the criteria may be missing or
+ unknown (an empty QString for the hostname or protocol name, -1
+ for the port numbers). If that happens, the functions executing
+ the query should make their best guess or apply some
+ implementation-defined default values.
+
+ \sa QNetworkProxy, QNetworkProxyFactory, QNetworkAccessManager,
+ QAbstractSocket::setProxy()
+*/
+
+/*!
+ \enum QNetworkProxyQuery::QueryType
+
+ Describes the type of one QNetworkProxyQuery query.
+
+ \value TcpSocket a normal, outgoing TCP socket
+ \value UdpSocket a datagram-based UDP socket, which could send
+ to multiple destinations
+ \value TcpServer a TCP server that listens for incoming
+ connections from the network
+ \value UrlRequest a more complex request which involves loading
+ of a URL
+
+ \sa queryType(), setQueryType()
+*/
+
+/*!
+ Constructs a default QNetworkProxyQuery object. By default, the
+ query type will be QNetworkProxyQuery::TcpSocket.
+*/
+QNetworkProxyQuery::QNetworkProxyQuery()
+{
+}
+
+/*!
+ Constructs a QNetworkProxyQuery with the URL \a requestUrl and
+ sets the query type to \a queryType.
+
+ \sa protocolTag(), peerHostName(), peerPort()
+*/
+QNetworkProxyQuery::QNetworkProxyQuery(const QUrl &requestUrl, QueryType queryType)
+{
+ d->remote = requestUrl;
+ d->type = queryType;
+}
+
+/*!
+ Constructs a QNetworkProxyQuery of type \a queryType and sets the
+ protocol tag to be \a protocolTag. This constructor is suitable
+ for QNetworkProxyQuery::TcpSocket queries, because it sets the
+ peer hostname to \a hostname and the peer's port number to \a
+ port.
+*/
+QNetworkProxyQuery::QNetworkProxyQuery(const QString &hostname, int port,
+ const QString &protocolTag,
+ QueryType queryType)
+{
+ d->remote.setScheme(protocolTag);
+ d->remote.setHost(hostname);
+ d->remote.setPort(port);
+ d->type = queryType;
+}
+
+/*!
+ Constructs a QNetworkProxyQuery of type \a queryType and sets the
+ protocol tag to be \a protocolTag. This constructor is suitable
+ for QNetworkProxyQuery::TcpSocket queries because it sets the
+ local port number to \a bindPort.
+
+ Note that \a bindPort is of type quint16 to indicate the exact
+ port number that is requested. The value of -1 (unknown) is not
+ allowed in this context.
+
+ \sa localPort()
+*/
+QNetworkProxyQuery::QNetworkProxyQuery(quint16 bindPort, const QString &protocolTag,
+ QueryType queryType)
+{
+ d->remote.setScheme(protocolTag);
+ d->localPort = bindPort;
+ d->type = queryType;
+}
+
+/*!
+ Constructs a QNetworkProxyQuery object that is a copy of \a other.
+*/
+QNetworkProxyQuery::QNetworkProxyQuery(const QNetworkProxyQuery &other)
+ : d(other.d)
+{
+}
+
+/*!
+ Destroys this QNetworkProxyQuery object.
+*/
+QNetworkProxyQuery::~QNetworkProxyQuery()
+{
+ // QSharedDataPointer automatically deletes
+}
+
+/*!
+ Copies the contents of \a other.
+*/
+QNetworkProxyQuery &QNetworkProxyQuery::operator=(const QNetworkProxyQuery &other)
+{
+ d = other.d;
+ return *this;
+}
+
+/*!
+ Returns true if this QNetworkProxyQuery object contains the same
+ data as \a other.
+*/
+bool QNetworkProxyQuery::operator==(const QNetworkProxyQuery &other) const
+{
+ return d == other.d || (d && other.d && *d == *other.d);
+}
+
+/*!
+ \fn bool QNetworkProxyQuery::operator!=(const QNetworkProxyQuery &other) const
+
+ Returns true if this QNetworkProxyQuery object does not contain
+ the same data as \a other.
+*/
+
+/*!
+ Returns the query type.
+*/
+QNetworkProxyQuery::QueryType QNetworkProxyQuery::queryType() const
+{
+ return d ? d->type : TcpSocket;
+}
+
+/*!
+ Sets the query type of this object to be \a type.
+*/
+void QNetworkProxyQuery::setQueryType(QueryType type)
+{
+ d->type = type;
+}
+
+/*!
+ Returns the port number for the outgoing request or -1 if the port
+ number is not known.
+
+ If the query type is QNetworkProxyQuery::UrlRequest, this function
+ returns the port number of the URL being requested. In general,
+ frameworks will fill in the port number from their default values.
+
+ \sa peerHostName(), localPort(), setPeerPort()
+*/
+int QNetworkProxyQuery::peerPort() const
+{
+ return d ? d->remote.port() : -1;
+}
+
+/*!
+ Sets the requested port number for the outgoing connection to be
+ \a port. Valid values are 1 to 65535, or -1 to indicate that the
+ remote port number is unknown.
+
+ The peer port number can also be used to indicate the expected
+ port number of an incoming connection in the case of
+ QNetworkProxyQuery::UdpSocket or QNetworkProxyQuery::TcpServer
+ query types.
+
+ \sa peerPort(), setPeerHostName(), setLocalPort()
+*/
+void QNetworkProxyQuery::setPeerPort(int port)
+{
+ d->remote.setPort(port);
+}
+
+/*!
+ Returns the host name or IP address being of the outgoing
+ connection being requested, or an empty string if the remote
+ hostname is not known.
+
+ If the query type is QNetworkProxyQuery::UrlRequest, this function
+ returns the host component of the URL being requested.
+
+ \sa peerPort(), localPort(), setPeerHostName()
+*/
+QString QNetworkProxyQuery::peerHostName() const
+{
+ return d ? d->remote.host() : QString();
+}
+
+/*!
+ Sets the hostname of the outgoing connection being requested to \a
+ hostname. An empty hostname can be used to indicate that the
+ remote host is unknown.
+
+ The peer host name can also be used to indicate the expected
+ source address of an incoming connection in the case of
+ QNetworkProxyQuery::UdpSocket or QNetworkProxyQuery::TcpServer
+ query types.
+
+ \sa peerHostName(), setPeerPort(), setLocalPort()
+*/
+void QNetworkProxyQuery::setPeerHostName(const QString &hostname)
+{
+ d->remote.setHost(hostname);
+}
+
+/*!
+ Returns the port number of the socket that will accept incoming
+ packets from remote servers or -1 if the port is not known.
+
+ \sa peerPort(), peerHostName(), setLocalPort()
+*/
+int QNetworkProxyQuery::localPort() const
+{
+ return d ? d->localPort : -1;
+}
+
+/*!
+ Sets the port number that the socket wishes to use locally to
+ accept incoming packets from remote servers to \a port. The local
+ port is most often used with the QNetworkProxyQuery::TcpServer
+ and QNetworkProxyQuery::UdpSocket query types.
+
+ Valid values are 0 to 65535 (with 0 indicating that any port
+ number will be acceptable) or -1, which means the local port
+ number is unknown or not applicable.
+
+ In some circumstances, for special protocols, it's the local port
+ number can also be used with a query of type
+ QNetworkProxyQuery::TcpSocket. When that happens, the socket is
+ indicating it wishes to use the port number \a port when
+ connecting to a remote host.
+
+ \sa localPort(), setPeerPort(), setPeerHostName()
+*/
+void QNetworkProxyQuery::setLocalPort(int port)
+{
+ d->localPort = port;
+}
+
+/*!
+ Returns the protocol tag for this QNetworkProxyQuery object, or an
+ empty QString in case the protocol tag is unknown.
+
+ In the case of queries of type QNetworkProxyQuery::UrlRequest,
+ this function returns the value of the scheme component of the
+ URL.
+
+ \sa setProtocolTag(), url()
+*/
+QString QNetworkProxyQuery::protocolTag() const
+{
+ return d ? d->remote.scheme() : QString();
+}
+
+/*!
+ Sets the protocol tag for this QNetworkProxyQuery object to be \a
+ protocolTag.
+
+ The protocol tag is an arbitrary string that indicates which
+ protocol is being talked over the socket, such as "http", "xmpp",
+ "telnet", etc. The protocol tag is used by the backend to
+ return a request that is more specific to the protocol in
+ question: for example, a HTTP connection could be use a caching
+ HTTP proxy server, while all other connections use a more powerful
+ SOCKSv5 proxy server.
+
+ \sa protocolTag()
+*/
+void QNetworkProxyQuery::setProtocolTag(const QString &protocolTag)
+{
+ d->remote.setScheme(protocolTag);
+}
+
+/*!
+ Returns the URL component of this QNetworkProxyQuery object in
+ case of a query of type QNetworkProxyQuery::UrlRequest.
+
+ \sa setUrl()
+*/
+QUrl QNetworkProxyQuery::url() const
+{
+ return d ? d->remote : QUrl();
+}
+
+/*!
+ Sets the URL component of this QNetworkProxyQuery object to be \a
+ url. Setting the URL will also set the protocol tag, the remote
+ host name and port number. This is done so as to facilitate the
+ implementation of the code that determines the proxy server to be
+ used.
+
+ \sa url(), peerHostName(), peerPort()
+*/
+void QNetworkProxyQuery::setUrl(const QUrl &url)
+{
+ d->remote = url;
+}
+
+/*!
+ \class QNetworkProxyFactory
+ \brief The QNetworkProxyFactory class provides fine-grained proxy selection.
+ \since 4.5
+
+ \ingroup io
+ \inmodule QtNetwork
+
+ QNetworkProxyFactory is an extension to QNetworkProxy, allowing
+ applications to have a more fine-grained control over which proxy
+ servers are used, depending on the socket requesting the
+ proxy. This allows an application to apply different settings,
+ according to the protocol or destination hostname, for instance.
+
+ QNetworkProxyFactory can be set globally for an application, in
+ which case it will override any global proxies set with
+ QNetworkProxy::setApplicationProxy(). If set globally, any sockets
+ created with Qt will query the factory to determine the proxy to
+ be used.
+
+ A factory can also be set in certain frameworks that support
+ multiple connections, such as QNetworkAccessManager. When set on
+ such object, the factory will be queried for sockets created by
+ that framework only.
+*/
+
+/*!
+ Creates a QNetworkProxyFactory object.
+
+ Since QNetworkProxyFactory is an abstract class, you cannot create
+ objects of type QNetworkProxyFactory directly.
+*/
+QNetworkProxyFactory::QNetworkProxyFactory()
+{
+}
+
+/*!
+ Destroys the QNetworkProxyFactory object.
+*/
+QNetworkProxyFactory::~QNetworkProxyFactory()
+{
+}
+
+/*!
+ Sets the application-wide proxy factory to be \a factory. This
+ function will take ownership of that object and will delete it
+ when necessary.
+
+ The application-wide proxy is used as a last-resort when all other
+ proxy selection requests returned QNetworkProxy::DefaultProxy. For
+ example, QTcpSocket objects can have a proxy set with
+ QTcpSocket::setProxy, but if none is set, the proxy factory class
+ set with this function will be queried.
+
+ If you set a proxy factory with this function, any application
+ level proxies set with QNetworkProxy::setApplicationProxy will be
+ overridden.
+
+ \sa QNetworkProxy::setApplicationProxy(),
+ QAbstractSocket::proxy(), QAbstractSocket::setProxy()
+*/
+void QNetworkProxyFactory::setApplicationProxyFactory(QNetworkProxyFactory *factory)
+{
+ if (globalNetworkProxy())
+ globalNetworkProxy()->setApplicationProxyFactory(factory);
+}
+
+/*!
+ \fn QList<QNetworkProxy> QNetworkProxyFactory::queryProxy(const QNetworkProxyQuery &query)
+
+ This function examines takes the query request, \a query,
+ examines the details of the type of socket or request and returns
+ a list of QNetworkProxy objects that indicate the proxy servers to
+ be used, in order of preference.
+
+ When reimplementing this class, take care to return at least one
+ element.
+
+ If you cannot determine a better proxy alternative, use
+ QNetworkProxy::DefaultProxy, which tells the code querying for a
+ proxy to use a higher alternative. For example, if this factory is
+ set to a QNetworkAccessManager object, DefaultProxy will tell it
+ to query the application-level proxy settings.
+
+ If this factory is set as the application proxy factory,
+ DefaultProxy and NoProxy will have the same meaning.
+*/
+
+/*!
+ \fn QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkProxyQuery &query)
+
+ This function examines takes the query request, \a query,
+ examines the details of the type of socket or request and returns
+ a list of QNetworkProxy objects that indicate the proxy servers to
+ be used, in order of preference.
+
+ This function can be used to determine the platform-specific proxy
+ settings. This function will use the libraries provided by the
+ operating system to determine the proxy for a given connection, if
+ such libraries exist. If they don't, this function will just return a
+ QNetworkProxy of type QNetworkProxy::NoProxy.
+
+ On Windows, this function will use the WinHTTP DLL functions. Despite
+ its name, Microsoft suggests using it for all applications that
+ require network connections, not just HTTP. This will respect the
+ proxy settings set on the registry with the proxycfg.exe tool. If
+ those settings are not found, this function will attempt to obtain
+ Internet Explorer's settings and use them.
+
+ On MacOS X, this function will obtain the proxy settings using the
+ SystemConfiguration framework from Apple. It will apply the FTP,
+ HTTP and HTTPS proxy configurations for queries that contain the
+ protocol tag "ftp", "http" and "https", respectively. If the SOCKS
+ proxy is enabled in that configuration, this function will use the
+ SOCKS server for all queries. If SOCKS isn't enabled, it will use
+ the HTTPS proxy for all TcpSocket and UrlRequest queries.
+
+ On other systems, there is no standardised method of obtaining the
+ system proxy configuration. This function may be improved in
+ future versions to support those systems.
+
+ \section1 Limitations
+
+ These are the limitations for the current version of this
+ function. Future versions of Qt may lift some of the limitations
+ listed here.
+
+ On MacOS X, this function will ignore the Proxy Auto Configuration
+ settings, since it cannot execute the associated ECMAScript code.
+*/
+
+/*!
+ This function examines takes the query request, \a query,
+ examines the details of the type of socket or request and returns
+ a list of QNetworkProxy objects that indicate the proxy servers to
+ be used, in order of preference.
+*/
+QList<QNetworkProxy> QNetworkProxyFactory::proxyForQuery(const QNetworkProxyQuery &query)
+{
+ if (!globalNetworkProxy())
+ return QList<QNetworkProxy>() << QNetworkProxy(QNetworkProxy::NoProxy);
+ return globalNetworkProxy()->proxyForQuery(query);
+}
+
+#endif // QT_NO_NETWORKPROXY
+
+QT_END_NAMESPACE
diff --git a/src/network/kernel/qnetworkproxy.h b/src/network/kernel/qnetworkproxy.h
new file mode 100644
index 0000000..abe4213
--- /dev/null
+++ b/src/network/kernel/qnetworkproxy.h
@@ -0,0 +1,185 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QNETWORKPROXY_H
+#define QNETWORKPROXY_H
+
+#include <QtNetwork/qhostaddress.h>
+#include <QtCore/qshareddata.h>
+
+#ifndef QT_NO_NETWORKPROXY
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Network)
+
+class QUrl;
+
+class QNetworkProxyQueryPrivate;
+class Q_NETWORK_EXPORT QNetworkProxyQuery
+{
+public:
+ enum QueryType {
+ TcpSocket,
+ UdpSocket,
+ TcpServer = 100,
+ UrlRequest
+ };
+
+ QNetworkProxyQuery();
+ QNetworkProxyQuery(const QUrl &requestUrl, QueryType queryType = UrlRequest);
+ QNetworkProxyQuery(const QString &hostname, int port, const QString &protocolTag = QString(),
+ QueryType queryType = TcpSocket);
+ QNetworkProxyQuery(quint16 bindPort, const QString &protocolTag = QString(),
+ QueryType queryType = TcpServer);
+ QNetworkProxyQuery(const QNetworkProxyQuery &other);
+ ~QNetworkProxyQuery();
+ QNetworkProxyQuery &operator=(const QNetworkProxyQuery &other);
+ bool operator==(const QNetworkProxyQuery &other) const;
+ inline bool operator!=(const QNetworkProxyQuery &other) const
+ { return !(*this == other); }
+
+ QueryType queryType() const;
+ void setQueryType(QueryType type);
+
+ int peerPort() const;
+ void setPeerPort(int port);
+
+ QString peerHostName() const;
+ void setPeerHostName(const QString &hostname);
+
+ int localPort() const;
+ void setLocalPort(int port);
+
+ QString protocolTag() const;
+ void setProtocolTag(const QString &protocolTag);
+
+ QUrl url() const;
+ void setUrl(const QUrl &url);
+
+private:
+ QSharedDataPointer<QNetworkProxyQueryPrivate> d;
+};
+Q_DECLARE_TYPEINFO(QNetworkProxyQuery, Q_MOVABLE_TYPE);
+
+class QNetworkProxyPrivate;
+
+class Q_NETWORK_EXPORT QNetworkProxy
+{
+public:
+ enum ProxyType {
+ DefaultProxy,
+ Socks5Proxy,
+ NoProxy,
+ HttpProxy,
+ HttpCachingProxy,
+ FtpCachingProxy
+ };
+
+ enum Capability {
+ TunnelingCapability = 0x0001,
+ ListeningCapability = 0x0002,
+ UdpTunnelingCapability = 0x0004,
+ CachingCapability = 0x0008,
+ HostNameLookupCapability = 0x0010
+ };
+ Q_DECLARE_FLAGS(Capabilities, Capability)
+
+ QNetworkProxy();
+ QNetworkProxy(ProxyType type, const QString &hostName = QString(), quint16 port = 0,
+ const QString &user = QString(), const QString &password = QString());
+ QNetworkProxy(const QNetworkProxy &other);
+ QNetworkProxy &operator=(const QNetworkProxy &other);
+ ~QNetworkProxy();
+ bool operator==(const QNetworkProxy &other) const;
+ inline bool operator!=(const QNetworkProxy &other) const
+ { return !(*this == other); }
+
+ void setType(QNetworkProxy::ProxyType type);
+ QNetworkProxy::ProxyType type() const;
+
+ void setCapabilities(Capabilities capab);
+ Capabilities capabilities() const;
+ bool isCachingProxy() const;
+ bool isTransparentProxy() const;
+
+ void setUser(const QString &userName);
+ QString user() const;
+
+ void setPassword(const QString &password);
+ QString password() const;
+
+ void setHostName(const QString &hostName);
+ QString hostName() const;
+
+ void setPort(quint16 port);
+ quint16 port() const;
+
+ static void setApplicationProxy(const QNetworkProxy &proxy);
+ static QNetworkProxy applicationProxy();
+
+private:
+ QSharedDataPointer<QNetworkProxyPrivate> d;
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QNetworkProxy::Capabilities)
+
+class Q_NETWORK_EXPORT QNetworkProxyFactory
+{
+public:
+ QNetworkProxyFactory();
+ virtual ~QNetworkProxyFactory();
+
+ virtual QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query = QNetworkProxyQuery()) = 0;
+
+ static void setApplicationProxyFactory(QNetworkProxyFactory *factory);
+ static QList<QNetworkProxy> proxyForQuery(const QNetworkProxyQuery &query);
+ static QList<QNetworkProxy> systemProxyForQuery(const QNetworkProxyQuery &query = QNetworkProxyQuery());
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_NETWORKPROXY
+
+#endif // QHOSTINFO_H
diff --git a/src/network/kernel/qnetworkproxy_generic.cpp b/src/network/kernel/qnetworkproxy_generic.cpp
new file mode 100644
index 0000000..866d63d
--- /dev/null
+++ b/src/network/kernel/qnetworkproxy_generic.cpp
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qnetworkproxy.h"
+
+#ifndef QT_NO_NETWORKPROXY
+
+/*
+ * No system proxy. Just return a list with NoProxy.
+ */
+
+QT_BEGIN_NAMESPACE
+
+QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkProxyQuery &)
+{
+ return QList<QNetworkProxy>() << QNetworkProxy::NoProxy;
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/network/kernel/qnetworkproxy_mac.cpp b/src/network/kernel/qnetworkproxy_mac.cpp
new file mode 100644
index 0000000..5e6e3e8
--- /dev/null
+++ b/src/network/kernel/qnetworkproxy_mac.cpp
@@ -0,0 +1,240 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qnetworkproxy.h"
+
+#ifndef QT_NO_NETWORKPROXY
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <SystemConfiguration/SystemConfiguration.h>
+
+#include <QtCore/QRegExp>
+#include <QtCore/QStringList>
+#include <QtCore/qendian.h>
+#include <QtCore/qstringlist.h>
+#include "private/qcore_mac_p.h"
+
+/*
+ * MacOS X has a proxy configuration module in System Preferences (on
+ * MacOS X 10.5, it's in Network, Advanced), where one can set the
+ * proxy settings for:
+ *
+ * \list
+ * \o FTP proxy
+ * \o Web Proxy (HTTP)
+ * \o Secure Web Proxy (HTTPS)
+ * \o Streaming Proxy (RTSP)
+ * \o SOCKS Proxy
+ * \o Gopher Proxy
+ * \o URL for Automatic Proxy Configuration (PAC scripts)
+ * \o Bypass list (by default: *.local, 169.254/16)
+ * \endlist
+ *
+ * The matching configuration can be obtained by calling SCDynamicStoreCopyProxies
+ * (from <SystemConfiguration/SCDynamicStoreCopySpecific.h>). See
+ * Apple's documentation:
+ *
+ * http://developer.apple.com/DOCUMENTATION/Networking/Reference/SysConfig/SCDynamicStoreCopySpecific/CompositePage.html#//apple_ref/c/func/SCDynamicStoreCopyProxies
+ *
+ */
+
+QT_BEGIN_NAMESPACE
+
+static bool isHostExcluded(CFDictionaryRef dict, const QString &host)
+{
+ if (host.isEmpty())
+ return true;
+
+ bool isSimple = !host.contains(QLatin1Char('.')) && !host.contains(QLatin1Char(':'));
+ CFNumberRef excludeSimples;
+ if (isSimple &&
+ (excludeSimples = (CFNumberRef)CFDictionaryGetValue(dict, kSCPropNetProxiesExcludeSimpleHostnames))) {
+ int enabled;
+ if (CFNumberGetValue(excludeSimples, kCFNumberIntType, &enabled) && enabled)
+ return true;
+ }
+
+ QHostAddress ipAddress;
+ bool isIpAddress = ipAddress.setAddress(host);
+
+ // not a simple host name
+ // does it match the list of exclusions?
+ CFArrayRef exclusionList = (CFArrayRef)CFDictionaryGetValue(dict, kSCPropNetProxiesExceptionsList);
+ if (!exclusionList)
+ return false;
+
+ CFIndex size = CFArrayGetCount(exclusionList);
+ for (CFIndex i = 0; i < size; ++i) {
+ CFStringRef cfentry = (CFStringRef)CFArrayGetValueAtIndex(exclusionList, i);
+ QString entry = QCFString::toQString(cfentry);
+
+ if (isIpAddress && ipAddress.isInSubnet(QHostAddress::parseSubnet(entry))) {
+ return true; // excluded
+ } else {
+ // do wildcard matching
+ QRegExp rx(entry, Qt::CaseInsensitive, QRegExp::Wildcard);
+ if (rx.exactMatch(host))
+ return true;
+ }
+ }
+
+ // host was not excluded
+ return false;
+}
+
+static QNetworkProxy proxyFromDictionary(CFDictionaryRef dict, QNetworkProxy::ProxyType type,
+ CFStringRef enableKey, CFStringRef hostKey,
+ CFStringRef portKey)
+{
+ CFNumberRef protoEnabled;
+ CFNumberRef protoPort;
+ CFStringRef protoHost;
+ if (enableKey
+ && (protoEnabled = (CFNumberRef)CFDictionaryGetValue(dict, enableKey))
+ && (protoHost = (CFStringRef)CFDictionaryGetValue(dict, hostKey))
+ && (protoPort = (CFNumberRef)CFDictionaryGetValue(dict, portKey))) {
+ int enabled;
+ if (CFNumberGetValue(protoEnabled, kCFNumberIntType, &enabled) && enabled) {
+ QString host = QCFString::toQString(protoHost);
+
+ int port;
+ CFNumberGetValue(protoPort, kCFNumberIntType, &port);
+
+ return QNetworkProxy(type, host, port);
+ }
+ }
+
+ // proxy not enabled
+ return QNetworkProxy();
+}
+
+QList<QNetworkProxy> macQueryInternal(const QNetworkProxyQuery &query)
+{
+ QList<QNetworkProxy> result;
+
+ // obtain a dictionary to the proxy settings:
+ CFDictionaryRef dict = SCDynamicStoreCopyProxies(NULL);
+ if (!dict) {
+ qWarning("QNetworkProxyFactory::systemProxyForQuery: SCDynamicStoreCopyProxies returned NULL");
+ return result; // failed
+ }
+
+ if (isHostExcluded(dict, query.peerHostName()))
+ return result; // no proxy for this host
+
+ // is there a PAC enabled? If so, use it first.
+ CFNumberRef pacEnabled;
+ if ((pacEnabled = (CFNumberRef)CFDictionaryGetValue(dict, kSCPropNetProxiesProxyAutoConfigEnable))) {
+ int enabled;
+ if (CFNumberGetValue(pacEnabled, kCFNumberIntType, &enabled) && enabled) {
+ // PAC is enabled
+ CFStringRef pacUrl =
+ (CFStringRef)CFDictionaryGetValue(dict, kSCPropNetProxiesProxyAutoConfigURLString);
+ QString url = QCFString::toQString(pacUrl);
+
+ // ### Use PAC somehow
+ qDebug("Mac system proxy: found PAC script at \"%s\"", qPrintable(url));
+ }
+ }
+
+ // no PAC, decide which proxy we're looking for based on the query
+ bool isHttps = false;
+ QString protocol = query.protocolTag().toLower();
+
+ // try the protocol-specific proxy
+ QNetworkProxy protocolSpecificProxy;
+ if (protocol == QLatin1String("ftp")) {
+ protocolSpecificProxy =
+ proxyFromDictionary(dict, QNetworkProxy::FtpCachingProxy,
+ kSCPropNetProxiesFTPEnable,
+ kSCPropNetProxiesFTPProxy,
+ kSCPropNetProxiesFTPPort);
+ } else if (protocol == QLatin1String("http")) {
+ protocolSpecificProxy =
+ proxyFromDictionary(dict, QNetworkProxy::HttpProxy,
+ kSCPropNetProxiesHTTPEnable,
+ kSCPropNetProxiesHTTPProxy,
+ kSCPropNetProxiesHTTPPort);
+ } else if (protocol == QLatin1String("https")) {
+ isHttps = true;
+ protocolSpecificProxy =
+ proxyFromDictionary(dict, QNetworkProxy::HttpProxy,
+ kSCPropNetProxiesHTTPSEnable,
+ kSCPropNetProxiesHTTPSProxy,
+ kSCPropNetProxiesHTTPSPort);
+ }
+ if (protocolSpecificProxy.type() != QNetworkProxy::DefaultProxy)
+ result << protocolSpecificProxy;
+
+ // let's add SOCKSv5 if present too
+ QNetworkProxy socks5 = proxyFromDictionary(dict, QNetworkProxy::Socks5Proxy,
+ kSCPropNetProxiesSOCKSEnable,
+ kSCPropNetProxiesSOCKSProxy,
+ kSCPropNetProxiesSOCKSPort);
+ if (socks5.type() != QNetworkProxy::DefaultProxy)
+ result << socks5;
+
+ // let's add the HTTPS proxy if present (and if we haven't added
+ // yet)
+ if (!isHttps) {
+ QNetworkProxy https = proxyFromDictionary(dict, QNetworkProxy::HttpProxy,
+ kSCPropNetProxiesHTTPSEnable,
+ kSCPropNetProxiesHTTPSProxy,
+ kSCPropNetProxiesHTTPSPort);
+ if (https.type() != QNetworkProxy::DefaultProxy && https != protocolSpecificProxy)
+ result << https;
+ }
+
+ return result;
+}
+
+QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkProxyQuery &query)
+{
+ QList<QNetworkProxy> result = macQueryInternal(query);
+ if (result.isEmpty())
+ result << QNetworkProxy::NoProxy;
+
+ return result;
+}
+
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/network/kernel/qnetworkproxy_win.cpp b/src/network/kernel/qnetworkproxy_win.cpp
new file mode 100644
index 0000000..16d18cf
--- /dev/null
+++ b/src/network/kernel/qnetworkproxy_win.cpp
@@ -0,0 +1,415 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qnetworkproxy.h"
+
+#ifndef QT_NO_NETWORKPROXY
+
+#if defined(UNICODE)
+
+#include <qmutex.h>
+#include <qstringlist.h>
+#include <qregexp.h>
+#include <qurl.h>
+
+#include <string.h>
+#include <windows.h>
+#include <wininet.h>
+
+/*
+ * Information on the WinHTTP DLL:
+ * http://msdn.microsoft.com/en-us/library/aa384122(VS.85).aspx example for WPAD
+ *
+ * http://msdn.microsoft.com/en-us/library/aa384097(VS.85).aspx WinHttpGetProxyForUrl
+ * http://msdn.microsoft.com/en-us/library/aa384096(VS.85).aspx WinHttpGetIEProxyConfigForCurrentUs
+ * http://msdn.microsoft.com/en-us/library/aa384095(VS.85).aspx WinHttpGetDefaultProxyConfiguration
+ */
+
+// We don't want to include winhttp.h because that's not
+// present in some Windows SDKs (I don't know why)
+// So, instead, copy the definitions here
+
+typedef struct {
+ DWORD dwFlags;
+ DWORD dwAutoDetectFlags;
+ LPCWSTR lpszAutoConfigUrl;
+ LPVOID lpvReserved;
+ DWORD dwReserved;
+ BOOL fAutoLogonIfChallenged;
+} WINHTTP_AUTOPROXY_OPTIONS;
+
+typedef struct {
+ DWORD dwAccessType;
+ LPWSTR lpszProxy;
+ LPWSTR lpszProxyBypass;
+} WINHTTP_PROXY_INFO;
+
+typedef struct {
+ BOOL fAutoDetect;
+ LPWSTR lpszAutoConfigUrl;
+ LPWSTR lpszProxy;
+ LPWSTR lpszProxyBypass;
+} WINHTTP_CURRENT_USER_IE_PROXY_CONFIG;
+
+#define WINHTTP_AUTOPROXY_AUTO_DETECT 0x00000001
+#define WINHTTP_AUTOPROXY_CONFIG_URL 0x00000002
+
+#define WINHTTP_AUTO_DETECT_TYPE_DHCP 0x00000001
+#define WINHTTP_AUTO_DETECT_TYPE_DNS_A 0x00000002
+
+#define WINHTTP_ACCESS_TYPE_DEFAULT_PROXY 0
+#define WINHTTP_ACCESS_TYPE_NO_PROXY 1
+#define WINHTTP_ACCESS_TYPE_NAMED_PROXY 3
+
+#define WINHTTP_NO_PROXY_NAME NULL
+#define WINHTTP_NO_PROXY_BYPASS NULL
+
+QT_BEGIN_NAMESPACE
+
+typedef BOOL (WINAPI * PtrWinHttpGetProxyForUrl)(HINTERNET, LPCWSTR, WINHTTP_AUTOPROXY_OPTIONS*, WINHTTP_PROXY_INFO*);
+typedef HINTERNET (WINAPI * PtrWinHttpOpen)(LPCWSTR, DWORD, LPCWSTR, LPCWSTR,DWORD);
+typedef BOOL (WINAPI * PtrWinHttpGetDefaultProxyConfiguration)(WINHTTP_PROXY_INFO*);
+typedef BOOL (WINAPI * PtrWinHttpGetIEProxyConfigForCurrentUser)(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG*);
+typedef BOOL (WINAPI * PtrWinHttpCloseHandle)(HINTERNET);
+static PtrWinHttpGetProxyForUrl ptrWinHttpGetProxyForUrl = 0;
+static PtrWinHttpOpen ptrWinHttpOpen = 0;
+static PtrWinHttpGetDefaultProxyConfiguration ptrWinHttpGetDefaultProxyConfiguration = 0;
+static PtrWinHttpGetIEProxyConfigForCurrentUser ptrWinHttpGetIEProxyConfigForCurrentUser = 0;
+static PtrWinHttpCloseHandle ptrWinHttpCloseHandle = 0;
+
+
+static QStringList splitSpaceSemicolon(const QString &source)
+{
+ QStringList list;
+ int start = 0;
+ int end;
+ while (true) {
+ int space = source.indexOf(QLatin1Char(' '), start);
+ int semicolon = source.indexOf(QLatin1Char(';'), start);
+ end = space;
+ if (semicolon != -1 && (end == -1 || semicolon < end))
+ end = semicolon;
+
+ if (end == -1) {
+ if (start != source.length())
+ list.append(source.mid(start));
+ return list;
+ }
+ if (start != end)
+ list.append(source.mid(start, end - start));
+ start = end + 1;
+ }
+ return list;
+}
+
+static bool isBypassed(const QString &host, const QStringList &bypassList)
+{
+ if (host.isEmpty())
+ return true;
+
+ bool isSimple = !host.contains(QLatin1Char('.')) && !host.contains(QLatin1Char(':'));
+
+ QHostAddress ipAddress;
+ bool isIpAddress = ipAddress.setAddress(host);
+
+ // does it match the list of exclusions?
+ foreach (const QString &entry, bypassList) {
+ if (isSimple && entry == QLatin1String("<local>"))
+ return true;
+ if (isIpAddress && ipAddress.isInSubnet(QHostAddress::parseSubnet(entry))) {
+ return true; // excluded
+ } else {
+ // do wildcard matching
+ QRegExp rx(entry, Qt::CaseInsensitive, QRegExp::Wildcard);
+ if (rx.exactMatch(host))
+ return true;
+ }
+ }
+
+ // host was not excluded
+ return false;
+}
+
+static QList<QNetworkProxy> parseServerList(const QNetworkProxyQuery &query, const QStringList &proxyList)
+{
+ // Reference documentation from Microsoft:
+ // http://msdn.microsoft.com/en-us/library/aa383912(VS.85).aspx
+ //
+ // According to the website, the proxy server list is
+ // one or more of the space- or semicolon-separated strings in the format:
+ // ([<scheme>=][<scheme>"://"]<server>[":"<port>])
+
+ QList<QNetworkProxy> result;
+ foreach (const QString &entry, proxyList) {
+ int server = 0;
+
+ int pos = entry.indexOf(QLatin1Char('='));
+ if (pos != -1) {
+ QStringRef scheme = entry.leftRef(pos);
+ if (scheme != query.protocolTag())
+ continue;
+
+ server = pos + 1;
+ }
+
+ QNetworkProxy::ProxyType proxyType = QNetworkProxy::HttpProxy;
+ quint16 port = 8080;
+
+ pos = entry.indexOf(QLatin1String("://"), server);
+ if (pos != -1) {
+ QStringRef scheme = entry.midRef(server, pos - server);
+ if (scheme == QLatin1String("http") || scheme == QLatin1String("https")) {
+ // no-op
+ // defaults are above
+ } else if (scheme == QLatin1String("socks") || scheme == QLatin1String("socks5")) {
+ proxyType = QNetworkProxy::Socks5Proxy;
+ port = 1080;
+ } else {
+ // unknown proxy type
+ continue;
+ }
+
+ server = pos + 3;
+ }
+
+ pos = entry.indexOf(QLatin1Char(':'), server);
+ if (pos != -1) {
+ bool ok;
+ uint value = entry.mid(pos + 1).toUInt(&ok);
+ if (!ok || value > 65535)
+ continue; // invalid port number
+
+ port = value;
+ } else {
+ pos = entry.length();
+ }
+
+ result << QNetworkProxy(proxyType, entry.mid(server, pos - server), port);
+ }
+
+ return result;
+}
+
+class QWindowsSystemProxy
+{
+public:
+ QWindowsSystemProxy();
+ ~QWindowsSystemProxy();
+ void init();
+
+ QMutex mutex;
+
+ HINTERNET hHttpSession;
+ WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions;
+
+ QString autoConfigUrl;
+ QStringList proxyServerList;
+ QStringList proxyBypass;
+ QList<QNetworkProxy> defaultResult;
+
+ bool initialized;
+ bool functional;
+ bool isAutoConfig;
+};
+
+Q_GLOBAL_STATIC(QWindowsSystemProxy, systemProxy)
+
+QWindowsSystemProxy::QWindowsSystemProxy()
+ : initialized(false), functional(false), isAutoConfig(false)
+{
+ defaultResult << QNetworkProxy::NoProxy;
+}
+
+QWindowsSystemProxy::~QWindowsSystemProxy()
+{
+ if (hHttpSession)
+ ptrWinHttpCloseHandle(hHttpSession);
+}
+
+void QWindowsSystemProxy::init()
+{
+ if (initialized)
+ return;
+ initialized = true;
+ if (QSysInfo::windowsVersion() & QSysInfo::WV_DOS_based)
+ return; // no point, this library is only available on 2k, XP and up
+
+#ifdef Q_OS_WINCE
+ // Windows CE does not have any of the following API
+ return;
+#else
+ // load the winhttp.dll library
+ HINSTANCE winhttpHnd = LoadLibraryW(L"winhttp");
+ if (!winhttpHnd)
+ return; // failed to load
+
+ ptrWinHttpOpen = (PtrWinHttpOpen)GetProcAddress(winhttpHnd, "WinHttpOpen");
+ ptrWinHttpCloseHandle = (PtrWinHttpCloseHandle)GetProcAddress(winhttpHnd, "WinHttpCloseHandle");
+ ptrWinHttpGetProxyForUrl = (PtrWinHttpGetProxyForUrl)GetProcAddress(winhttpHnd, "WinHttpGetProxyForUrl");
+ ptrWinHttpGetDefaultProxyConfiguration = (PtrWinHttpGetDefaultProxyConfiguration)GetProcAddress(winhttpHnd, "WinHttpGetDefaultProxyConfiguration");
+ ptrWinHttpGetIEProxyConfigForCurrentUser = (PtrWinHttpGetIEProxyConfigForCurrentUser)GetProcAddress(winhttpHnd, "WinHttpGetIEProxyConfigForCurrentUser");
+
+ // Try to obtain the Internet Explorer configuration.
+ WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ieProxyConfig;
+ if (ptrWinHttpGetIEProxyConfigForCurrentUser(&ieProxyConfig)) {
+ if (ieProxyConfig.lpszAutoConfigUrl) {
+ autoConfigUrl = QString::fromWCharArray(ieProxyConfig.lpszAutoConfigUrl);
+ GlobalFree(ieProxyConfig.lpszAutoConfigUrl);
+ }
+ if (ieProxyConfig.lpszProxy) {
+ proxyServerList << QString::fromWCharArray(ieProxyConfig.lpszProxy);
+ GlobalFree(ieProxyConfig.lpszProxy);
+ }
+ if (ieProxyConfig.lpszProxyBypass) {
+ proxyBypass = splitSpaceSemicolon(QString::fromWCharArray(ieProxyConfig.lpszProxyBypass));
+ GlobalFree(ieProxyConfig.lpszProxyBypass);
+ }
+ }
+
+ hHttpSession = NULL;
+ if (ieProxyConfig.fAutoDetect || !autoConfigUrl.isEmpty()) {
+ // using proxy autoconfiguration
+ proxyServerList.clear();
+ proxyBypass.clear();
+
+ // open the handle and obtain the options
+ hHttpSession = ptrWinHttpOpen(L"Qt System Proxy access/1.0",
+ WINHTTP_ACCESS_TYPE_NO_PROXY,
+ WINHTTP_NO_PROXY_NAME,
+ WINHTTP_NO_PROXY_BYPASS,
+ 0);
+ if (!hHttpSession)
+ return;
+
+ isAutoConfig = true;
+ memset(&autoProxyOptions, 0, sizeof autoProxyOptions);
+ autoProxyOptions.fAutoLogonIfChallenged = true;
+ if (ieProxyConfig.fAutoDetect) {
+ autoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
+ autoProxyOptions.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP |
+ WINHTTP_AUTO_DETECT_TYPE_DNS_A;
+ } else {
+ autoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL;
+ autoProxyOptions.lpszAutoConfigUrl = (LPCWSTR)autoConfigUrl.utf16();
+ }
+ } else {
+ // not auto-detected
+ // attempt to get the static configuration instead
+ WINHTTP_PROXY_INFO proxyInfo;
+ if (ptrWinHttpGetDefaultProxyConfiguration(&proxyInfo) &&
+ proxyInfo.dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY) {
+ // we got information from the registry
+ // overwrite the IE configuration, if any
+
+ proxyBypass = splitSpaceSemicolon(QString::fromWCharArray(proxyInfo.lpszProxyBypass));
+ proxyServerList = splitSpaceSemicolon(QString::fromWCharArray(proxyInfo.lpszProxy));
+ }
+
+ if (proxyInfo.lpszProxy)
+ GlobalFree(proxyInfo.lpszProxy);
+ if (proxyInfo.lpszProxyBypass)
+ GlobalFree(proxyInfo.lpszProxyBypass);
+ }
+
+ functional = isAutoConfig || !proxyServerList.isEmpty();
+#endif
+}
+
+QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkProxyQuery &query)
+{
+ QWindowsSystemProxy *sp = systemProxy();
+ if (!sp)
+ return QList<QNetworkProxy>() << QNetworkProxy();
+
+ QMutexLocker locker(&sp->mutex);
+ sp->init();
+ if (!sp->functional)
+ return sp->defaultResult;
+
+ if (sp->isAutoConfig) {
+ WINHTTP_PROXY_INFO proxyInfo;
+
+ // try to get the proxy config for the URL, if we have a URL
+ QUrl url = query.url();
+ if (query.queryType() != QNetworkProxyQuery::UrlRequest) {
+ // change the scheme to https, maybe it'll work
+ url.setScheme(QLatin1String("https"));
+ }
+ if (ptrWinHttpGetProxyForUrl(sp->hHttpSession,
+ (LPCWSTR)url.toString().utf16(),
+ &sp->autoProxyOptions,
+ &proxyInfo)) {
+ // yes, we got a config for this URL
+ QString proxyBypass = QString::fromWCharArray(proxyInfo.lpszProxyBypass);
+ QStringList proxyServerList = splitSpaceSemicolon(QString::fromWCharArray(proxyInfo.lpszProxy));
+ if (proxyInfo.lpszProxy)
+ GlobalFree(proxyInfo.lpszProxy);
+ if (proxyInfo.lpszProxyBypass)
+ GlobalFree(proxyInfo.lpszProxyBypass);
+
+ if (isBypassed(query.peerHostName(), splitSpaceSemicolon(proxyBypass)))
+ return sp->defaultResult;
+ return parseServerList(query, proxyServerList);
+ }
+
+ // GetProxyForUrl failed
+ return sp->defaultResult;
+ }
+
+ // static configuration
+ if (isBypassed(query.peerHostName(), sp->proxyBypass))
+ return sp->defaultResult;
+
+ return parseServerList(query, sp->proxyServerList);
+}
+
+#else // !UNICODE
+
+QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkProxyQuery &)
+{
+ return QList<QNetworkProxy>() << QNetworkProxy::NoProxy;
+}
+
+#endif
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/network/kernel/qurlinfo.cpp b/src/network/kernel/qurlinfo.cpp
new file mode 100644
index 0000000..255c9ea
--- /dev/null
+++ b/src/network/kernel/qurlinfo.cpp
@@ -0,0 +1,731 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qurlinfo.h"
+
+#ifndef QT_NO_URLINFO
+
+#include "qurl.h"
+#include "qdir.h"
+#include <limits.h>
+
+QT_BEGIN_NAMESPACE
+
+class QUrlInfoPrivate
+{
+public:
+ QUrlInfoPrivate() :
+ permissions(0),
+ size(0),
+ isDir(false),
+ isFile(true),
+ isSymLink(false),
+ isWritable(true),
+ isReadable(true),
+ isExecutable(false)
+ {}
+
+ QString name;
+ int permissions;
+ QString owner;
+ QString group;
+ qint64 size;
+
+ QDateTime lastModified;
+ QDateTime lastRead;
+ bool isDir;
+ bool isFile;
+ bool isSymLink;
+ bool isWritable;
+ bool isReadable;
+ bool isExecutable;
+};
+
+
+/*!
+ \class QUrlInfo
+ \brief The QUrlInfo class stores information about URLs.
+
+ \ingroup io
+ \ingroup misc
+
+ The information about a URL that can be retrieved includes name(),
+ permissions(), owner(), group(), size(), lastModified(),
+ lastRead(), isDir(), isFile(), isSymLink(), isWritable(),
+ isReadable() and isExecutable().
+
+ You can create your own QUrlInfo objects passing in all the
+ relevant information in the constructor, and you can modify a
+ QUrlInfo; for each getter mentioned above there is an equivalent
+ setter. Note that setting values does not affect the underlying
+ resource that the QUrlInfo provides information about; for example
+ if you call setWritable(true) on a read-only resource the only
+ thing changed is the QUrlInfo object, not the resource.
+
+ \sa QUrl, {FTP Example}
+*/
+
+/*!
+ \enum QUrlInfo::PermissionSpec
+
+ This enum is used by the permissions() function to report the
+ permissions of a file.
+
+ \value ReadOwner The file is readable by the owner of the file.
+ \value WriteOwner The file is writable by the owner of the file.
+ \value ExeOwner The file is executable by the owner of the file.
+ \value ReadGroup The file is readable by the group.
+ \value WriteGroup The file is writable by the group.
+ \value ExeGroup The file is executable by the group.
+ \value ReadOther The file is readable by anyone.
+ \value WriteOther The file is writable by anyone.
+ \value ExeOther The file is executable by anyone.
+*/
+
+/*!
+ Constructs an invalid QUrlInfo object with default values.
+
+ \sa isValid()
+*/
+
+QUrlInfo::QUrlInfo()
+{
+ d = 0;
+}
+
+/*!
+ Copy constructor, copies \a ui to this URL info object.
+*/
+
+QUrlInfo::QUrlInfo(const QUrlInfo &ui)
+{
+ if (ui.d) {
+ d = new QUrlInfoPrivate;
+ *d = *ui.d;
+ } else {
+ d = 0;
+ }
+}
+
+/*!
+ Constructs a QUrlInfo object by specifying all the URL's
+ information.
+
+ The information that is passed is the \a name, file \a
+ permissions, \a owner and \a group and the file's \a size. Also
+ passed is the \a lastModified date/time and the \a lastRead
+ date/time. Flags are also passed, specifically, \a isDir, \a
+ isFile, \a isSymLink, \a isWritable, \a isReadable and \a
+ isExecutable.
+*/
+
+QUrlInfo::QUrlInfo(const QString &name, int permissions, const QString &owner,
+ const QString &group, qint64 size, const QDateTime &lastModified,
+ const QDateTime &lastRead, bool isDir, bool isFile, bool isSymLink,
+ bool isWritable, bool isReadable, bool isExecutable)
+{
+ d = new QUrlInfoPrivate;
+ d->name = name;
+ d->permissions = permissions;
+ d->owner = owner;
+ d->group = group;
+ d->size = size;
+ d->lastModified = lastModified;
+ d->lastRead = lastRead;
+ d->isDir = isDir;
+ d->isFile = isFile;
+ d->isSymLink = isSymLink;
+ d->isWritable = isWritable;
+ d->isReadable = isReadable;
+ d->isExecutable = isExecutable;
+}
+
+
+/*!
+ Constructs a QUrlInfo object by specifying all the URL's
+ information.
+
+ The information that is passed is the \a url, file \a
+ permissions, \a owner and \a group and the file's \a size. Also
+ passed is the \a lastModified date/time and the \a lastRead
+ date/time. Flags are also passed, specifically, \a isDir, \a
+ isFile, \a isSymLink, \a isWritable, \a isReadable and \a
+ isExecutable.
+*/
+
+QUrlInfo::QUrlInfo(const QUrl &url, int permissions, const QString &owner,
+ const QString &group, qint64 size, const QDateTime &lastModified,
+ const QDateTime &lastRead, bool isDir, bool isFile, bool isSymLink,
+ bool isWritable, bool isReadable, bool isExecutable)
+{
+ d = new QUrlInfoPrivate;
+ d->name = QFileInfo(url.path()).fileName();
+ d->permissions = permissions;
+ d->owner = owner;
+ d->group = group;
+ d->size = size;
+ d->lastModified = lastModified;
+ d->lastRead = lastRead;
+ d->isDir = isDir;
+ d->isFile = isFile;
+ d->isSymLink = isSymLink;
+ d->isWritable = isWritable;
+ d->isReadable = isReadable;
+ d->isExecutable = isExecutable;
+}
+
+
+/*!
+ Sets the name of the URL to \a name. The name is the full text,
+ for example, "http://doc.trolltech.com/qurlinfo.html".
+
+ If you call this function for an invalid URL info, this function
+ turns it into a valid one.
+
+ \sa isValid()
+*/
+
+void QUrlInfo::setName(const QString &name)
+{
+ if (!d)
+ d = new QUrlInfoPrivate;
+ d->name = name;
+}
+
+
+/*!
+ If \a b is true then the URL is set to be a directory; if \a b is
+ false then the URL is set not to be a directory (which normally
+ means it is a file). (Note that a URL can refer to both a file and
+ a directory even though most file systems do not support this.)
+
+ If you call this function for an invalid URL info, this function
+ turns it into a valid one.
+
+ \sa isValid()
+*/
+
+void QUrlInfo::setDir(bool b)
+{
+ if (!d)
+ d = new QUrlInfoPrivate;
+ d->isDir = b;
+}
+
+
+/*!
+ If \a b is true then the URL is set to be a file; if \b is false
+ then the URL is set not to be a file (which normally means it is a
+ directory). (Note that a URL can refer to both a file and a
+ directory even though most file systems do not support this.)
+
+ If you call this function for an invalid URL info, this function
+ turns it into a valid one.
+
+ \sa isValid()
+*/
+
+void QUrlInfo::setFile(bool b)
+{
+ if (!d)
+ d = new QUrlInfoPrivate;
+ d->isFile = b;
+}
+
+
+/*!
+ Specifies that the URL refers to a symbolic link if \a b is true
+ and that it does not if \a b is false.
+
+ If you call this function for an invalid URL info, this function
+ turns it into a valid one.
+
+ \sa isValid()
+*/
+
+void QUrlInfo::setSymLink(bool b)
+{
+ if (!d)
+ d = new QUrlInfoPrivate;
+ d->isSymLink = b;
+}
+
+
+/*!
+ Specifies that the URL is writable if \a b is true and not
+ writable if \a b is false.
+
+ If you call this function for an invalid URL info, this function
+ turns it into a valid one.
+
+ \sa isValid()
+*/
+
+void QUrlInfo::setWritable(bool b)
+{
+ if (!d)
+ d = new QUrlInfoPrivate;
+ d->isWritable = b;
+}
+
+
+/*!
+ Specifies that the URL is readable if \a b is true and not
+ readable if \a b is false.
+
+ If you call this function for an invalid URL info, this function
+ turns it into a valid one.
+
+ \sa isValid()
+*/
+
+void QUrlInfo::setReadable(bool b)
+{
+ if (!d)
+ d = new QUrlInfoPrivate;
+ d->isReadable = b;
+}
+
+/*!
+ Specifies that the owner of the URL is called \a s.
+
+ If you call this function for an invalid URL info, this function
+ turns it into a valid one.
+
+ \sa isValid()
+*/
+
+void QUrlInfo::setOwner(const QString &s)
+{
+ if (!d)
+ d = new QUrlInfoPrivate;
+ d->owner = s;
+}
+
+/*!
+ Specifies that the owning group of the URL is called \a s.
+
+ If you call this function for an invalid URL info, this function
+ turns it into a valid one.
+
+ \sa isValid()
+*/
+
+void QUrlInfo::setGroup(const QString &s)
+{
+ if (!d)
+ d = new QUrlInfoPrivate;
+ d->group = s;
+}
+
+/*!
+ Specifies the \a size of the URL.
+
+ If you call this function for an invalid URL info, this function
+ turns it into a valid one.
+
+ \sa isValid()
+*/
+
+void QUrlInfo::setSize(qint64 size)
+{
+ if (!d)
+ d = new QUrlInfoPrivate;
+ d->size = size;
+}
+
+/*!
+ Specifies that the URL has access permissions \a p.
+
+ If you call this function for an invalid URL info, this function
+ turns it into a valid one.
+
+ \sa isValid()
+*/
+
+void QUrlInfo::setPermissions(int p)
+{
+ if (!d)
+ d = new QUrlInfoPrivate;
+ d->permissions = p;
+}
+
+/*!
+ Specifies that the object the URL refers to was last modified at
+ \a dt.
+
+ If you call this function for an invalid URL info, this function
+ turns it into a valid one.
+
+ \sa isValid()
+*/
+
+void QUrlInfo::setLastModified(const QDateTime &dt)
+{
+ if (!d)
+ d = new QUrlInfoPrivate;
+ d->lastModified = dt;
+}
+
+/*!
+ \since 4.4
+
+ Specifies that the object the URL refers to was last read at
+ \a dt.
+
+ If you call this function for an invalid URL info, this function
+ turns it into a valid one.
+
+ \sa isValid()
+*/
+
+void QUrlInfo::setLastRead(const QDateTime &dt)
+{
+ if (!d)
+ d = new QUrlInfoPrivate;
+ d->lastRead = dt;
+}
+
+/*!
+ Destroys the URL info object.
+*/
+
+QUrlInfo::~QUrlInfo()
+{
+ delete d;
+}
+
+/*!
+ Assigns the values of \a ui to this QUrlInfo object.
+*/
+
+QUrlInfo &QUrlInfo::operator=(const QUrlInfo &ui)
+{
+ if (ui.d) {
+ if (!d)
+ d= new QUrlInfoPrivate;
+ *d = *ui.d;
+ } else {
+ delete d;
+ d = 0;
+ }
+ return *this;
+}
+
+/*!
+ Returns the file name of the URL.
+
+ \sa isValid()
+*/
+
+QString QUrlInfo::name() const
+{
+ if (!d)
+ return QString();
+ return d->name;
+}
+
+/*!
+ Returns the permissions of the URL. You can use the \c PermissionSpec flags
+ to test for certain permissions.
+
+ \sa isValid()
+*/
+
+int QUrlInfo::permissions() const
+{
+ if (!d)
+ return 0;
+ return d->permissions;
+}
+
+/*!
+ Returns the owner of the URL.
+
+ \sa isValid()
+*/
+
+QString QUrlInfo::owner() const
+{
+ if (!d)
+ return QString();
+ return d->owner;
+}
+
+/*!
+ Returns the group of the URL.
+
+ \sa isValid()
+*/
+
+QString QUrlInfo::group() const
+{
+ if (!d)
+ return QString();
+ return d->group;
+}
+
+/*!
+ Returns the size of the URL.
+
+ \sa isValid()
+*/
+
+qint64 QUrlInfo::size() const
+{
+ if (!d)
+ return 0;
+ return d->size;
+}
+
+/*!
+ Returns the last modification date of the URL.
+
+ \sa isValid()
+*/
+
+QDateTime QUrlInfo::lastModified() const
+{
+ if (!d)
+ return QDateTime();
+ return d->lastModified;
+}
+
+/*!
+ Returns the date when the URL was last read.
+
+ \sa isValid()
+*/
+
+QDateTime QUrlInfo::lastRead() const
+{
+ if (!d)
+ return QDateTime();
+ return d->lastRead;
+}
+
+/*!
+ Returns true if the URL is a directory; otherwise returns false.
+
+ \sa isValid()
+*/
+
+bool QUrlInfo::isDir() const
+{
+ if (!d)
+ return false;
+ return d->isDir;
+}
+
+/*!
+ Returns true if the URL is a file; otherwise returns false.
+
+ \sa isValid()
+*/
+
+bool QUrlInfo::isFile() const
+{
+ if (!d)
+ return false;
+ return d->isFile;
+}
+
+/*!
+ Returns true if the URL is a symbolic link; otherwise returns false.
+
+ \sa isValid()
+*/
+
+bool QUrlInfo::isSymLink() const
+{
+ if (!d)
+ return false;
+ return d->isSymLink;
+}
+
+/*!
+ Returns true if the URL is writable; otherwise returns false.
+
+ \sa isValid()
+*/
+
+bool QUrlInfo::isWritable() const
+{
+ if (!d)
+ return false;
+ return d->isWritable;
+}
+
+/*!
+ Returns true if the URL is readable; otherwise returns false.
+
+ \sa isValid()
+*/
+
+bool QUrlInfo::isReadable() const
+{
+ if (!d)
+ return false;
+ return d->isReadable;
+}
+
+/*!
+ Returns true if the URL is executable; otherwise returns false.
+
+ \sa isValid()
+*/
+
+bool QUrlInfo::isExecutable() const
+{
+ if (!d)
+ return false;
+ return d->isExecutable;
+}
+
+/*!
+ Returns true if \a i1 is greater than \a i2; otherwise returns
+ false. The objects are compared by the value, which is specified
+ by \a sortBy. This must be one of QDir::Name, QDir::Time or
+ QDir::Size.
+*/
+
+bool QUrlInfo::greaterThan(const QUrlInfo &i1, const QUrlInfo &i2,
+ int sortBy)
+{
+ switch (sortBy) {
+ case QDir::Name:
+ return i1.name() > i2.name();
+ case QDir::Time:
+ return i1.lastModified() > i2.lastModified();
+ case QDir::Size:
+ return i1.size() > i2.size();
+ default:
+ return false;
+ }
+}
+
+/*!
+ Returns true if \a i1 is less than \a i2; otherwise returns false.
+ The objects are compared by the value, which is specified by \a
+ sortBy. This must be one of QDir::Name, QDir::Time or QDir::Size.
+*/
+
+bool QUrlInfo::lessThan(const QUrlInfo &i1, const QUrlInfo &i2,
+ int sortBy)
+{
+ return !greaterThan(i1, i2, sortBy);
+}
+
+/*!
+ Returns true if \a i1 equals to \a i2; otherwise returns false.
+ The objects are compared by the value, which is specified by \a
+ sortBy. This must be one of QDir::Name, QDir::Time or QDir::Size.
+*/
+
+bool QUrlInfo::equal(const QUrlInfo &i1, const QUrlInfo &i2,
+ int sortBy)
+{
+ switch (sortBy) {
+ case QDir::Name:
+ return i1.name() == i2.name();
+ case QDir::Time:
+ return i1.lastModified() == i2.lastModified();
+ case QDir::Size:
+ return i1.size() == i2.size();
+ default:
+ return false;
+ }
+}
+
+/*!
+ Returns true if this QUrlInfo is equal to \a other; otherwise
+ returns false.
+
+ \sa lessThan(), equal()
+*/
+
+bool QUrlInfo::operator==(const QUrlInfo &other) const
+{
+ if (!d)
+ return other.d == 0;
+ if (!other.d)
+ return false;
+
+ return (d->name == other.d->name &&
+ d->permissions == other.d->permissions &&
+ d->owner == other.d->owner &&
+ d->group == other.d->group &&
+ d->size == other.d->size &&
+ d->lastModified == other.d->lastModified &&
+ d->lastRead == other.d->lastRead &&
+ d->isDir == other.d->isDir &&
+ d->isFile == other.d->isFile &&
+ d->isSymLink == other.d->isSymLink &&
+ d->isWritable == other.d->isWritable &&
+ d->isReadable == other.d->isReadable &&
+ d->isExecutable == other.d->isExecutable);
+}
+
+/*!
+ \fn bool QUrlInfo::operator!=(const QUrlInfo &other) const
+ \since 4.2
+
+ Returns true if this QUrlInfo is not equal to \a other; otherwise
+ returns false.
+
+ \sa lessThan(), equal()
+*/
+
+/*!
+ Returns true if the URL info is valid; otherwise returns false.
+ Valid means that the QUrlInfo contains real information.
+
+ You should always check if the URL info is valid before relying on
+ the values.
+*/
+bool QUrlInfo::isValid() const
+{
+ return d != 0;
+}
+
+#endif // QT_NO_URLINFO
+
+QT_END_NAMESPACE
diff --git a/src/network/kernel/qurlinfo.h b/src/network/kernel/qurlinfo.h
new file mode 100644
index 0000000..502fd34
--- /dev/null
+++ b/src/network/kernel/qurlinfo.h
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QURLINFO_H
+#define QURLINFO_H
+
+#include <QtCore/qdatetime.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qiodevice.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Network)
+
+#ifndef QT_NO_URLINFO
+
+class QUrl;
+class QUrlInfoPrivate;
+
+class Q_NETWORK_EXPORT QUrlInfo
+{
+public:
+ enum PermissionSpec {
+ ReadOwner = 00400, WriteOwner = 00200, ExeOwner = 00100,
+ ReadGroup = 00040, WriteGroup = 00020, ExeGroup = 00010,
+ ReadOther = 00004, WriteOther = 00002, ExeOther = 00001 };
+
+ QUrlInfo();
+ QUrlInfo(const QUrlInfo &ui);
+ QUrlInfo(const QString &name, int permissions, const QString &owner,
+ const QString &group, qint64 size, const QDateTime &lastModified,
+ const QDateTime &lastRead, bool isDir, bool isFile, bool isSymLink,
+ bool isWritable, bool isReadable, bool isExecutable);
+ QUrlInfo(const QUrl &url, int permissions, const QString &owner,
+ const QString &group, qint64 size, const QDateTime &lastModified,
+ const QDateTime &lastRead, bool isDir, bool isFile, bool isSymLink,
+ bool isWritable, bool isReadable, bool isExecutable);
+ QUrlInfo &operator=(const QUrlInfo &ui);
+ virtual ~QUrlInfo();
+
+ virtual void setName(const QString &name);
+ virtual void setDir(bool b);
+ virtual void setFile(bool b);
+ virtual void setSymLink(bool b);
+ virtual void setOwner(const QString &s);
+ virtual void setGroup(const QString &s);
+ virtual void setSize(qint64 size);
+ virtual void setWritable(bool b);
+ virtual void setReadable(bool b);
+ virtual void setPermissions(int p);
+ virtual void setLastModified(const QDateTime &dt);
+ void setLastRead(const QDateTime &dt);
+
+ bool isValid() const;
+
+ QString name() const;
+ int permissions() const;
+ QString owner() const;
+ QString group() const;
+ qint64 size() const;
+ QDateTime lastModified() const;
+ QDateTime lastRead() const;
+ bool isDir() const;
+ bool isFile() const;
+ bool isSymLink() const;
+ bool isWritable() const;
+ bool isReadable() const;
+ bool isExecutable() const;
+
+ static bool greaterThan(const QUrlInfo &i1, const QUrlInfo &i2,
+ int sortBy);
+ static bool lessThan(const QUrlInfo &i1, const QUrlInfo &i2,
+ int sortBy);
+ static bool equal(const QUrlInfo &i1, const QUrlInfo &i2,
+ int sortBy);
+
+ bool operator==(const QUrlInfo &i) const;
+ inline bool operator!=(const QUrlInfo &i) const
+ { return !operator==(i); }
+
+private:
+ QUrlInfoPrivate *d;
+};
+
+#endif // QT_NO_URLINFO
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QURLINFO_H