summaryrefslogtreecommitdiffstats
path: root/src/network/kernel
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commit38be0d13830efd2d98281c645c3a60afe05ffece (patch)
tree6ea73f3ec77f7d153333779883e8120f82820abe /src/network/kernel
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'src/network/kernel')
-rw-r--r--src/network/kernel/kernel.pri34
-rw-r--r--src/network/kernel/qauthenticator.cpp1428
-rw-r--r--src/network/kernel/qauthenticator.h92
-rw-r--r--src/network/kernel/qauthenticator_p.h115
-rw-r--r--src/network/kernel/qhostaddress.cpp1170
-rw-r--r--src/network/kernel/qhostaddress.h155
-rw-r--r--src/network/kernel/qhostaddress_p.h76
-rw-r--r--src/network/kernel/qhostinfo.cpp808
-rw-r--r--src/network/kernel/qhostinfo.h102
-rw-r--r--src/network/kernel/qhostinfo_p.h319
-rw-r--r--src/network/kernel/qhostinfo_symbian.cpp600
-rw-r--r--src/network/kernel/qhostinfo_unix.cpp396
-rw-r--r--src/network/kernel/qhostinfo_win.cpp274
-rw-r--r--src/network/kernel/qnetworkinterface.cpp619
-rw-r--r--src/network/kernel/qnetworkinterface.h136
-rw-r--r--src/network/kernel/qnetworkinterface_p.h123
-rw-r--r--src/network/kernel/qnetworkinterface_symbian.cpp266
-rw-r--r--src/network/kernel/qnetworkinterface_unix.cpp449
-rw-r--r--src/network/kernel/qnetworkinterface_win.cpp328
-rw-r--r--src/network/kernel/qnetworkinterface_win_p.h266
-rw-r--r--src/network/kernel/qnetworkproxy.cpp1310
-rw-r--r--src/network/kernel/qnetworkproxy.h186
-rw-r--r--src/network/kernel/qnetworkproxy_generic.cpp59
-rw-r--r--src/network/kernel/qnetworkproxy_mac.cpp242
-rw-r--r--src/network/kernel/qnetworkproxy_p.h85
-rw-r--r--src/network/kernel/qnetworkproxy_symbian.cpp267
-rw-r--r--src/network/kernel/qnetworkproxy_win.cpp443
-rw-r--r--src/network/kernel/qurlinfo.cpp731
-rw-r--r--src/network/kernel/qurlinfo.h131
29 files changed, 11210 insertions, 0 deletions
diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri
new file mode 100644
index 0000000000..bb98305173
--- /dev/null
+++ b/src/network/kernel/kernel.pri
@@ -0,0 +1,34 @@
+# 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
+
+symbian: SOURCES += kernel/qhostinfo_symbian.cpp kernel/qnetworkinterface_symbian.cpp
+unix:!symbian:SOURCES += kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_unix.cpp
+win32:SOURCES += kernel/qhostinfo_win.cpp kernel/qnetworkinterface_win.cpp
+integrity:SOURCES += kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_unix.cpp
+
+mac:LIBS_PRIVATE += -framework SystemConfiguration -framework CoreFoundation
+mac:SOURCES += kernel/qnetworkproxy_mac.cpp
+else:win32:SOURCES += kernel/qnetworkproxy_win.cpp
+else:symbian:SOURCES += kernel/qnetworkproxy_symbian.cpp
+else:SOURCES += kernel/qnetworkproxy_generic.cpp
+
+symbian: LIBS += -lcommsdat
diff --git a/src/network/kernel/qauthenticator.cpp b/src/network/kernel/qauthenticator.cpp
new file mode 100644
index 0000000000..d61d3b7fa9
--- /dev/null
+++ b/src/network/kernel/qauthenticator.cpp
@@ -0,0 +1,1428 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@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 <qiodevice.h>
+#include <qdatastream.h>
+#include <qendian.h>
+#include <qstring.h>
+#include <qdatetime.h>
+
+//#define NTLMV1_CLIENT
+
+QT_BEGIN_NAMESPACE
+
+#ifdef NTLMV1_CLIENT
+#include "../../3rdparty/des/des.cpp"
+#endif
+
+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 network
+ \inmodule QtNetwork
+
+ The QAuthenticator class is usually used in the
+ \l{QNetworkAccessManager::}{authenticationRequired()} and
+ \l{QNetworkAccessManager::}{proxyAuthenticationRequired()} signals of QNetworkAccessManager and
+ QAbstractSocket. The class provides a way to pass back the required
+ authentication information to the socket when accessing services that
+ require authentication.
+
+ QAuthenticator supports the following authentication methods:
+ \list
+ \o Basic
+ \o NTLM version 1
+ \o Digest-MD5
+ \endlist
+
+ Note that, in particular, NTLM version 2 is not supported.
+
+ \section1 Options
+
+ In addition to the username and password required for authentication, a
+ QAuthenticator object can also contain additional options. The
+ options() function can be used to query incoming options sent by
+ the server; the setOption() function can
+ be used to set outgoing options, to be processed by the authenticator
+ calculation. The options accepted and provided depend on the authentication
+ type (see method()).
+
+ The following tables list known incoming options as well as accepted
+ outgoing options. The list of incoming options is not exhaustive, since
+ servers may include additional information at any time. The list of
+ outgoing options is exhaustive, however, and no unknown options will be
+ treated or sent back to the server.
+
+ \section2 Basic
+
+ \table
+ \header \o Option \o Direction \o Description
+ \row \o \tt{realm} \o Incoming \o Contains the realm of the authentication, the same as realm()
+ \endtable
+
+ The Basic authentication mechanism supports no outgoing options.
+
+ \section2 NTLM version 1
+
+ The NTLM authentication mechanism currently supports no incoming or outgoing options.
+
+ \section2 Digest-MD5
+
+ \table
+ \header \o Option \o Direction \o Description
+ \row \o \tt{realm} \o Incoming \o Contains the realm of the authentication, the same as realm()
+ \endtable
+
+ The Digest-MD5 authentication mechanism supports no outgoing options.
+
+ \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;
+
+ if (d && !d->ref.deref())
+ delete d;
+
+ d = other.d;
+ if (d)
+ d->ref.ref();
+ 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
+ && d->options == other.d->options;
+}
+
+/*!
+ \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();
+ int separatorPosn = 0;
+
+ switch(d->method) {
+ case QAuthenticatorPrivate::Ntlm:
+ if((separatorPosn = user.indexOf(QLatin1String("\\"))) != -1) {
+ //domain name is present
+ d->realm.clear();
+ d->userDomain = user.left(separatorPosn);
+ d->extractedUser = user.mid(separatorPosn + 1);
+ d->user = user;
+ } else if((separatorPosn = user.indexOf(QLatin1String("@"))) != -1) {
+ //domain name is present
+ d->realm.clear();
+ d->userDomain = user.left(separatorPosn);
+ d->extractedUser = user.left(separatorPosn);
+ d->user = user;
+ } else {
+ d->extractedUser = user;
+ d->user = user;
+ d->realm.clear();
+ d->userDomain.clear();
+ }
+ break;
+ default:
+ d->user = user;
+ d->userDomain.clear();
+ break;
+ }
+}
+
+/*!
+ 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();
+}
+
+/*!
+ \since 4.7
+ Returns the value related to option \a opt if it was set by the server.
+ See \l{QAuthenticator#Options} for more information on incoming options.
+ If option \a opt isn't found, an invalid QVariant will be returned.
+
+ \sa options(), QAuthenticator#Options
+*/
+QVariant QAuthenticator::option(const QString &opt) const
+{
+ return d ? d->options.value(opt) : QVariant();
+}
+
+/*!
+ \since 4.7
+ Returns all incoming options set in this QAuthenticator object by parsing
+ the server reply. See \l{QAuthenticator#Options} for more information
+ on incoming options.
+
+ \sa option(), QAuthenticator#Options
+*/
+QVariantHash QAuthenticator::options() const
+{
+ return d ? d->options : QVariantHash();
+}
+
+/*!
+ \since 4.7
+
+ Sets the outgoing option \a opt to value \a value.
+ See \l{QAuthenticator#Options} for more information on outgoing options.
+
+ \sa options(), option(), QAuthenticator#Options
+*/
+void QAuthenticator::setOption(const QString &opt, const QVariant &value)
+{
+ detach();
+ d->options.insert(opt, value);
+}
+
+
+/*!
+ 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)
+{
+ const QList<QPair<QString, QString> > values = header.values();
+ QList<QPair<QByteArray, QByteArray> > rawValues;
+
+ QList<QPair<QString, QString> >::const_iterator it, end;
+ for (it = values.constBegin(), end = values.constEnd(); it != end; ++it)
+ rawValues.append(qMakePair(it->first.toLatin1(), it->second.toUtf8()));
+
+ // continue in byte array form
+ parseHttpResponse(rawValues, isProxy);
+}
+#endif
+
+void QAuthenticatorPrivate::parseHttpResponse(const QList<QPair<QByteArray, QByteArray> > &values, bool isProxy)
+{
+ 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.
+ */
+
+ QByteArray headerVal;
+ for (int i = 0; i < values.size(); ++i) {
+ const QPair<QByteArray, QByteArray> &current = values.at(i);
+ if (current.first.toLower() != search)
+ continue;
+ QByteArray str = current.second.toLower();
+ if (method < Basic && str.startsWith("basic")) {
+ method = Basic;
+ headerVal = current.second.mid(6);
+ } else if (method < Ntlm && str.startsWith("ntlm")) {
+ method = Ntlm;
+ headerVal = current.second.mid(5);
+ } else if (method < DigestMd5 && str.startsWith("digest")) {
+ method = DigestMd5;
+ headerVal = current.second.mid(7);
+ }
+ }
+
+ challenge = headerVal.trimmed();
+ QHash<QByteArray, QByteArray> options = parseDigestAuthenticationChallenge(challenge);
+
+ switch(method) {
+ case Basic:
+ if(realm.isEmpty())
+ this->options[QLatin1String("realm")] = realm = QString::fromLatin1(options.value("realm"));
+ if (user.isEmpty())
+ phase = Done;
+ break;
+ case Ntlm:
+ // #### extract from header
+ break;
+ case DigestMd5: {
+ if(realm.isEmpty())
+ this->options[QLatin1String("realm")] = realm = QString::fromLatin1(options.value("realm"));
+ if (options.value("stale").toLower() == "true")
+ phase = Start;
+ if (user.isEmpty())
+ phase = Done;
+ break;
+ }
+ default:
+ realm.clear();
+ challenge = QByteArray();
+ phase = Invalid;
+ }
+}
+
+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
+
+/*
+ * AvId values
+ */
+#define AVTIMESTAMP 7
+
+//#define NTLMV1_CLIENT
+
+
+//************************Global variables***************************
+
+const int blockSize = 64; //As per RFC2104 Block-size is 512 bits
+const int nDigestLen = 16; //Trunctaion Length of the Hmac-Md5 digest
+const quint8 respversion = 1;
+const quint8 hirespversion = 1;
+
+/* 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;
+ QByteArray targetInfoBuff;
+};
+
+
+
+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;
+ QByteArray v2Hash;
+};
+
+
+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);
+}
+
+#ifdef NTLMV1_CLIENT
+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;
+}
+#endif
+
+/*********************************************************************
+* Function Name: qEncodeHmacMd5
+* Params:
+* key: Type - QByteArray
+* - It is the Authentication key
+* message: Type - QByteArray
+* - This is the actual message which will be encoded
+* using HMacMd5 hash algorithm
+*
+* Return Value:
+* hmacDigest: Type - QByteArray
+*
+* Description:
+* This function will be used to encode the input message using
+* HMacMd5 hash algorithm.
+*
+* As per the RFC2104 the HMacMd5 algorithm can be specified
+* ---------------------------------------
+* MD5(K XOR opad, MD5(K XOR ipad, text))
+* ---------------------------------------
+*
+*********************************************************************/
+QByteArray qEncodeHmacMd5(QByteArray &key, const QByteArray &message)
+{
+ Q_ASSERT_X(!(message.isEmpty()),"qEncodeHmacMd5", "Empty message check");
+ Q_ASSERT_X(!(key.isEmpty()),"qEncodeHmacMd5", "Empty key check");
+
+ QCryptographicHash hash(QCryptographicHash::Md5);
+ QByteArray hMsg;
+
+ QByteArray iKeyPad(blockSize, 0x36);
+ QByteArray oKeyPad(blockSize, 0x5c);
+
+ hash.reset();
+ // Adjust the key length to blockSize
+
+ if(blockSize < key.length()) {
+ hash.addData(key);
+ key = hash.result(); //MD5 will always return 16 bytes length output
+ }
+
+ //Key will be <= 16 or 20 bytes as hash function (MD5 or SHA hash algorithms)
+ //key size can be max of Block size only
+ key = key.leftJustified(blockSize,0,true);
+
+ //iKeyPad, oKeyPad and key are all of same size "blockSize"
+
+ //xor of iKeyPad with Key and store the result into iKeyPad
+ for(int i = 0; i<key.size();i++) {
+ iKeyPad[i] = key[i]^iKeyPad[i];
+ }
+
+ //xor of oKeyPad with Key and store the result into oKeyPad
+ for(int i = 0; i<key.size();i++) {
+ oKeyPad[i] = key[i]^oKeyPad[i];
+ }
+
+ iKeyPad.append(message); // (K0 xor ipad) || text
+
+ hash.reset();
+ hash.addData(iKeyPad);
+ hMsg = hash.result();
+ //Digest gen after pass-1: H((K0 xor ipad)||text)
+
+ QByteArray hmacDigest;
+ oKeyPad.append(hMsg);
+ hash.reset();
+ hash.addData(oKeyPad);
+ hmacDigest = hash.result();
+ // H((K0 xor opad )|| H((K0 xor ipad) || text))
+
+ /*hmacDigest should not be less than half the length of the HMAC output
+ (to match the birthday attack bound) and not less than 80 bits
+ (a suitable lower bound on the number of bits that need to be
+ predicted by an attacker).
+ Refer RFC 2104 for more details on truncation part */
+
+ /*MD5 hash always returns 16 byte digest only and HMAC-MD5 spec
+ (RFC 2104) also says digest length should be 16 bytes*/
+ return hmacDigest;
+}
+
+static QByteArray qCreatev2Hash(const QAuthenticatorPrivate *ctx,
+ QNtlmPhase3Block *phase3)
+{
+ Q_ASSERT(phase3 != 0);
+ // since v2 Hash is need for both NTLMv2 and LMv2 it is calculated
+ // only once and stored and reused
+ if(phase3->v2Hash.size() == 0) {
+ QCryptographicHash md4(QCryptographicHash::Md4);
+ QByteArray passUnicode = qStringAsUcs2Le(ctx->password);
+ md4.addData(passUnicode.data(), passUnicode.size());
+
+ QByteArray hashKey = md4.result();
+ Q_ASSERT(hashKey.size() == 16);
+ // Assuming the user and domain is always unicode in challenge
+ QByteArray message =
+ qStringAsUcs2Le(ctx->extractedUser.toUpper()) +
+ qStringAsUcs2Le(phase3->domainStr);
+
+ phase3->v2Hash = qEncodeHmacMd5(hashKey, message);
+ }
+ return phase3->v2Hash;
+}
+
+static QByteArray clientChallenge(const QAuthenticatorPrivate *ctx)
+{
+ Q_ASSERT(ctx->cnonce.size() >= 8);
+ QByteArray clientCh = ctx->cnonce.right(8);
+ return clientCh;
+}
+
+// caller has to ensure a valid targetInfoBuff
+static QByteArray qExtractServerTime(const QByteArray& targetInfoBuff)
+{
+ QByteArray timeArray;
+ QDataStream ds(targetInfoBuff);
+ ds.setByteOrder(QDataStream::LittleEndian);
+
+ quint16 avId;
+ quint16 avLen;
+
+ ds >> avId;
+ ds >> avLen;
+ while(avId != 0) {
+ if(avId == AVTIMESTAMP) {
+ timeArray.resize(avLen);
+ //avLen size of QByteArray is allocated
+ ds.readRawData(timeArray.data(), avLen);
+ break;
+ }
+ ds.skipRawData(avLen);
+ ds >> avId;
+ ds >> avLen;
+ }
+ return timeArray;
+}
+
+static QByteArray qEncodeNtlmv2Response(const QAuthenticatorPrivate *ctx,
+ const QNtlmPhase2Block& ch,
+ QNtlmPhase3Block *phase3)
+{
+ Q_ASSERT(phase3 != 0);
+ // return value stored in phase3
+ qCreatev2Hash(ctx, phase3);
+
+ QByteArray temp;
+ QDataStream ds(&temp, QIODevice::WriteOnly);
+ ds.setByteOrder(QDataStream::LittleEndian);
+
+ ds << respversion;
+ ds << hirespversion;
+
+ //Reserved
+ QByteArray reserved1(6, 0);
+ ds.writeRawData(reserved1.constData(), reserved1.size());
+
+ quint64 time = 0;
+ QByteArray timeArray;
+
+ if(ch.targetInfo.len)
+ {
+ timeArray = qExtractServerTime(ch.targetInfoBuff);
+ }
+
+ //if server sends time, use it instead of current time
+ if(timeArray.size()) {
+ ds.writeRawData(timeArray.constData(), timeArray.size());
+ } else {
+ QDateTime currentTime(QDate::currentDate(),
+ QTime::currentTime(), Qt::UTC);
+
+ // number of seconds between 1601 and epoc(1970)
+ // 369 years, 89 leap years
+ // ((369 * 365) + 89) * 24 * 3600 = 11644473600
+
+ time = Q_UINT64_C(currentTime.toTime_t() + 11644473600);
+
+ // represented as 100 nano seconds
+ time = Q_UINT64_C(time * 10000000);
+ ds << time;
+ }
+
+ //8 byte client challenge
+ QByteArray clientCh = clientChallenge(ctx);
+ ds.writeRawData(clientCh.constData(), clientCh.size());
+
+ //Reserved
+ QByteArray reserved2(4, 0);
+ ds.writeRawData(reserved2.constData(), reserved2.size());
+
+ if (ch.targetInfo.len > 0) {
+ ds.writeRawData(ch.targetInfoBuff.constData(),
+ ch.targetInfoBuff.size());
+ }
+
+ //Reserved
+ QByteArray reserved3(4, 0);
+ ds.writeRawData(reserved3.constData(), reserved3.size());
+
+ QByteArray message((const char*)ch.challenge, sizeof(ch.challenge));
+ message.append(temp);
+
+ QByteArray ntChallengeResp = qEncodeHmacMd5(phase3->v2Hash, message);
+ ntChallengeResp.append(temp);
+
+ return ntChallengeResp;
+}
+
+static QByteArray qEncodeLmv2Response(const QAuthenticatorPrivate *ctx,
+ const QNtlmPhase2Block& ch,
+ QNtlmPhase3Block *phase3)
+{
+ Q_ASSERT(phase3 != 0);
+ // return value stored in phase3
+ qCreatev2Hash(ctx, phase3);
+
+ QByteArray message((const char*)ch.challenge, sizeof(ch.challenge));
+ QByteArray clientCh = clientChallenge(ctx);
+
+ message.append(clientCh);
+
+ QByteArray lmChallengeResp = qEncodeHmacMd5(phase3->v2Hash, message);
+ lmChallengeResp.append(clientCh);
+
+ return lmChallengeResp;
+}
+
+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) {
+ if (ch.targetInfo.len + ch.targetInfo.offset > (unsigned)data.size())
+ return false;
+
+ ch.targetInfoBuff = data.mid(ch.targetInfo.offset, ch.targetInfo.len);
+ }
+
+ 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;
+
+ 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));
+
+ if(ctx->userDomain.isEmpty()) {
+ offset = qEncodeNtlmString(pb.domain, offset, ch.targetNameStr, unicode);
+ pb.domainStr = ch.targetNameStr;
+ } else {
+ offset = qEncodeNtlmString(pb.domain, offset, ctx->userDomain, unicode);
+ pb.domainStr = ctx->userDomain;
+ }
+
+ offset = qEncodeNtlmString(pb.user, offset, ctx->extractedUser, unicode);
+ pb.userStr = ctx->extractedUser;
+
+ offset = qEncodeNtlmString(pb.workstation, offset, ctx->workstation, unicode);
+ pb.workstationStr = ctx->workstation;
+
+ // Get LM response
+#ifdef NTLMV1_CLIENT
+ pb.lmResponseBuf = qEncodeLmResponse(ctx, ch);
+#else
+ if (ch.targetInfo.len > 0) {
+ pb.lmResponseBuf = QByteArray();
+ } else {
+ pb.lmResponseBuf = qEncodeLmv2Response(ctx, ch, &pb);
+ }
+#endif
+ offset = qEncodeNtlmBuffer(pb.lmResponse, offset, pb.lmResponseBuf);
+
+ // Get NTLM response
+#ifdef NTLMV1_CLIENT
+ pb.ntlmResponseBuf = qEncodeNtlmResponse(ctx, ch);
+#else
+ pb.ntlmResponseBuf = qEncodeNtlmv2Response(ctx, ch, &pb);
+#endif
+ 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 0000000000..b97802ad3e
--- /dev/null
+++ b/src/network/kernel/qauthenticator.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QAUTHENTICATOR_H
+#define QAUTHENTICATOR_H
+
+#include <QtCore/qstring.h>
+#include <QtCore/qvariant.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;
+
+ QVariant option(const QString &opt) const;
+ QVariantHash options() const;
+ void setOption(const QString &opt, const QVariant &value);
+
+ 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 0000000000..7db2dedc7e
--- /dev/null
+++ b/src/network/kernel/qauthenticator_p.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@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>
+#include <qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+class QHttpResponseHeader;
+
+class Q_AUTOTEST_EXPORT QAuthenticatorPrivate
+{
+public:
+ enum Method { None, Basic, Plain, Login, Ntlm, CramMd5, DigestMd5 };
+ QAuthenticatorPrivate();
+
+ QAtomicInt ref;
+ QString user;
+ QString extractedUser;
+ QString password;
+ QVariantHash 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;
+ QString userDomain;
+
+ 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
+ void parseHttpResponse(const QList<QPair<QByteArray, QByteArray> >&, bool isProxy);
+
+};
+
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/network/kernel/qhostaddress.cpp b/src/network/kernel/qhostaddress.cpp
new file mode 100644
index 0000000000..ae7d7a1486
--- /dev/null
+++ b/src/network/kernel/qhostaddress.cpp
@@ -0,0 +1,1170 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@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 network
+ \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(), and retrieved with
+ toIPv4Address(), toIPv6Address(), or toString(). You can check the
+ type with protocol().
+
+ \note Please note that QHostAddress does not do DNS lookups.
+ QHostInfo is needed for that.
+
+ The class also supports common predefined addresses: \l Null, \l
+ LocalHost, \l LocalHostIPv6, \l Broadcast, and \l Any.
+
+ \sa QHostInfo, 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.data()))
+{
+}
+
+/*!
+ 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()
+{
+}
+
+/*!
+ Assigns another host \a address to this object, and returns a reference
+ to this object.
+*/
+QHostAddress &QHostAddress::operator=(const QHostAddress &address)
+{
+ *d.data() = *address.d.data();
+ 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 the Protocol() is
+ \l{QAbstractSocket::}{IPv4Protocol}.
+
+ \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 the protocol() is
+ \l{QAbstractSocket::}{IPv6Protocol}.
+
+ \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 {Serializing Qt Data Types}
+*/
+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 {Serializing Qt Data Types}
+*/
+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 0000000000..e626e9fefc
--- /dev/null
+++ b/src/network/kernel/qhostaddress.h
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QHOSTADDRESS_H
+#define QHOSTADDRESS_H
+
+#include <QtCore/qpair.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qscopedpointer.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:
+ QScopedPointer<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 0000000000..a23b84ec69
--- /dev/null
+++ b/src/network/kernel/qhostaddress_p.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@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 0000000000..a16d4ca451
--- /dev/null
+++ b/src/network/kernel/qhostinfo.cpp
@@ -0,0 +1,808 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qhostinfo.h"
+#include "qhostinfo_p.h"
+
+#include "QtCore/qscopedpointer.h"
+#include <qabstracteventdispatcher.h>
+#include <qcoreapplication.h>
+#include <qmetaobject.h>
+#include <qstringlist.h>
+#include <qthread.h>
+#include <qurl.h>
+#include <private/qnetworksession_p.h>
+
+#ifdef Q_OS_UNIX
+# include <unistd.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+//#define QHOSTINFO_DEBUG
+
+#ifndef Q_OS_SYMBIAN
+Q_GLOBAL_STATIC(QHostInfoLookupManager, theHostInfoLookupManager)
+#else
+Q_GLOBAL_STATIC(QSymbianHostInfoLookupManager, theHostInfoLookupManager)
+#endif
+
+/*!
+ \class QHostInfo
+ \brief The QHostInfo class provides static functions for host name lookups.
+
+ \reentrant
+ \inmodule QtNetwork
+ \ingroup network
+
+ 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. 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.
+
+ \note Since Qt 4.6.1 QHostInfo is using multiple threads for DNS lookup
+ instead of one dedicated DNS thread. This improves performance,
+ but also changes the order of signal emissions when using lookupHost()
+ compared to previous versions of Qt.
+ \note Since Qt 4.6.3 QHostInfo is using a small internal 60 second DNS cache
+ for performance improvements.
+
+ \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
+
+ \note There is no guarantee on the order the signals will be emitted
+ if you start multiple requests with lookupHost().
+
+ \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");
+
+ int id = theIdCounter.fetchAndAddRelaxed(1); // generate unique ID
+
+ if (name.isEmpty()) {
+ QHostInfo hostInfo(id);
+ hostInfo.setError(QHostInfo::HostNotFound);
+ hostInfo.setErrorString(QCoreApplication::translate("QHostInfo", "No host name given"));
+ QScopedPointer<QHostInfoResult> result(new QHostInfoResult);
+ QObject::connect(result.data(), SIGNAL(resultsReady(QHostInfo)),
+ receiver, member, Qt::QueuedConnection);
+ result.data()->emitResultsReady(hostInfo);
+ return id;
+ }
+
+#ifndef Q_OS_SYMBIAN
+ QHostInfoLookupManager *manager = theHostInfoLookupManager();
+
+ if (manager) {
+ // the application is still alive
+ if (manager->cache.isEnabled()) {
+ // check cache first
+ bool valid = false;
+ QHostInfo info = manager->cache.get(name, &valid);
+ if (valid) {
+ info.setLookupId(id);
+ QHostInfoResult result;
+ QObject::connect(&result, SIGNAL(resultsReady(QHostInfo)), receiver, member, Qt::QueuedConnection);
+ result.emitResultsReady(info);
+ return id;
+ }
+ }
+
+ // cache is not enabled or it was not in the cache, do normal lookup
+ QHostInfoRunnable* runnable = new QHostInfoRunnable(name, id);
+ QObject::connect(&runnable->resultEmitter, SIGNAL(resultsReady(QHostInfo)), receiver, member, Qt::QueuedConnection);
+ manager->scheduleLookup(runnable);
+ }
+#else
+ QSymbianHostInfoLookupManager *manager = theHostInfoLookupManager();
+
+ if (manager) {
+ // the application is still alive
+ if (manager->cache.isEnabled()) {
+ // check cache first
+ bool valid = false;
+ QHostInfo info = manager->cache.get(name, &valid);
+ if (valid) {
+ info.setLookupId(id);
+ QHostInfoResult result;
+ QObject::connect(&result, SIGNAL(resultsReady(QHostInfo)), receiver, member, Qt::QueuedConnection);
+ result.emitResultsReady(info);
+ return id;
+ }
+ }
+
+ // cache is not enabled or it was not in the cache, do normal lookup
+#ifndef QT_NO_BEARERMANAGEMENT
+ QSharedPointer<QNetworkSession> networkSession;
+ QVariant v(receiver->property("_q_networksession"));
+ if (v.isValid())
+ networkSession = qvariant_cast< QSharedPointer<QNetworkSession> >(v);
+#endif
+
+ QSymbianHostResolver *symbianResolver = 0;
+ QT_TRAP_THROWING(symbianResolver = new QSymbianHostResolver(name, id, networkSession));
+ QObject::connect(&symbianResolver->resultEmitter, SIGNAL(resultsReady(QHostInfo)), receiver, member, Qt::QueuedConnection);
+ manager->scheduleLookup(symbianResolver);
+ }
+#endif
+
+ return id;
+}
+
+/*!
+ Aborts the host lookup with the ID \a id, as returned by lookupHost().
+
+ \sa lookupHost(), lookupId()
+*/
+void QHostInfo::abortHostLookup(int id)
+{
+ theHostInfoLookupManager()->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
+
+ QHostInfo hostInfo = QHostInfoAgent::fromName(name);
+ QAbstractHostInfoLookupManager* manager = theHostInfoLookupManager();
+ manager->cache.put(name, hostInfo);
+ return hostInfo;
+}
+
+#ifndef QT_NO_BEARERMANAGEMENT
+QHostInfo QHostInfoPrivate::fromName(const QString &name, QSharedPointer<QNetworkSession> session)
+{
+#if defined QHOSTINFO_DEBUG
+ qDebug("QHostInfoPrivate::fromName(\"%s\") with session %p",name.toLatin1().constData(), session.data());
+#endif
+
+ QHostInfo hostInfo = QHostInfoAgent::fromName(name, session);
+ QAbstractHostInfoLookupManager* manager = theHostInfoLookupManager();
+ manager->cache.put(name, hostInfo);
+ return hostInfo;
+}
+#endif
+
+#ifndef Q_OS_SYMBIAN
+// This function has a special implementation for symbian right now in qhostinfo_symbian.cpp but not on other OS.
+QHostInfo QHostInfoAgent::fromName(const QString &hostName, QSharedPointer<QNetworkSession> networkSession)
+{
+ return QHostInfoAgent::fromName(hostName);
+}
+#endif
+
+
+/*!
+ \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.data()))
+{
+}
+
+/*!
+ 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.data() = *other.d.data();
+ return *this;
+}
+
+/*!
+ Destroys the host info object.
+*/
+QHostInfo::~QHostInfo()
+{
+}
+
+/*!
+ 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()
+*/
+
+#ifndef Q_OS_SYMBIAN
+QHostInfoRunnable::QHostInfoRunnable(QString hn, int i) : toBeLookedUp(hn), id(i)
+{
+ setAutoDelete(true);
+}
+
+// the QHostInfoLookupManager will at some point call this via a QThreadPool
+void QHostInfoRunnable::run()
+{
+ QHostInfoLookupManager *manager = theHostInfoLookupManager();
+ // check aborted
+ if (manager->wasAborted(id)) {
+ manager->lookupFinished(this);
+ return;
+ }
+
+ QHostInfo hostInfo;
+
+ // QHostInfo::lookupHost already checks the cache. However we need to check
+ // it here too because it might have been cache saved by another QHostInfoRunnable
+ // in the meanwhile while this QHostInfoRunnable was scheduled but not running
+ if (manager->cache.isEnabled()) {
+ // check the cache first
+ bool valid = false;
+ hostInfo = manager->cache.get(toBeLookedUp, &valid);
+ if (!valid) {
+ // not in cache, we need to do the lookup and store the result in the cache
+ hostInfo = QHostInfoAgent::fromName(toBeLookedUp);
+ manager->cache.put(toBeLookedUp, hostInfo);
+ }
+ } else {
+ // cache is not enabled, just do the lookup and continue
+ hostInfo = QHostInfoAgent::fromName(toBeLookedUp);
+ }
+
+ // check aborted again
+ if (manager->wasAborted(id)) {
+ manager->lookupFinished(this);
+ return;
+ }
+
+ // signal emission
+ hostInfo.setLookupId(id);
+ resultEmitter.emitResultsReady(hostInfo);
+
+ // now also iterate through the postponed ones
+ {
+ QMutexLocker locker(&manager->mutex);
+ QMutableListIterator<QHostInfoRunnable*> iterator(manager->postponedLookups);
+ while (iterator.hasNext()) {
+ QHostInfoRunnable* postponed = iterator.next();
+ if (toBeLookedUp == postponed->toBeLookedUp) {
+ // we can now emit
+ iterator.remove();
+ hostInfo.setLookupId(postponed->id);
+ postponed->resultEmitter.emitResultsReady(hostInfo);
+ }
+ }
+ }
+
+ manager->lookupFinished(this);
+
+ // thread goes back to QThreadPool
+}
+
+QHostInfoLookupManager::QHostInfoLookupManager() : mutex(QMutex::Recursive), wasDeleted(false)
+{
+ moveToThread(QCoreApplicationPrivate::mainThread());
+ connect(QCoreApplication::instance(), SIGNAL(destroyed()), SLOT(waitForThreadPoolDone()), Qt::DirectConnection);
+ threadPool.setMaxThreadCount(5); // do 5 DNS lookups in parallel
+}
+
+QHostInfoLookupManager::~QHostInfoLookupManager()
+{
+ wasDeleted = true;
+
+ // don't qDeleteAll currentLookups, the QThreadPool has ownership
+ clear();
+}
+
+void QHostInfoLookupManager::clear()
+{
+ {
+ QMutexLocker locker(&mutex);
+ qDeleteAll(postponedLookups);
+ qDeleteAll(scheduledLookups);
+ qDeleteAll(finishedLookups);
+ postponedLookups.clear();
+ scheduledLookups.clear();
+ finishedLookups.clear();
+ }
+
+ threadPool.waitForDone();
+ cache.clear();
+}
+
+void QHostInfoLookupManager::work()
+{
+ if (wasDeleted)
+ return;
+
+ // goals of this function:
+ // - launch new lookups via the thread pool
+ // - make sure only one lookup per host/IP is in progress
+
+ QMutexLocker locker(&mutex);
+
+ if (!finishedLookups.isEmpty()) {
+ // remove ID from aborted if it is in there
+ for (int i = 0; i < finishedLookups.length(); i++) {
+ abortedLookups.removeAll(finishedLookups.at(i)->id);
+ }
+
+ finishedLookups.clear();
+ }
+
+ if (!postponedLookups.isEmpty()) {
+ // try to start the postponed ones
+
+ QMutableListIterator<QHostInfoRunnable*> iterator(postponedLookups);
+ while (iterator.hasNext()) {
+ QHostInfoRunnable* postponed = iterator.next();
+
+ // check if none of the postponed hostnames is currently running
+ bool alreadyRunning = false;
+ for (int i = 0; i < currentLookups.length(); i++) {
+ if (currentLookups.at(i)->toBeLookedUp == postponed->toBeLookedUp) {
+ alreadyRunning = true;
+ break;
+ }
+ }
+ if (!alreadyRunning) {
+ iterator.remove();
+ scheduledLookups.prepend(postponed); // prepend! we want to finish it ASAP
+ }
+ }
+ }
+
+ if (!scheduledLookups.isEmpty()) {
+ // try to start the new ones
+ QMutableListIterator<QHostInfoRunnable*> iterator(scheduledLookups);
+ while (iterator.hasNext()) {
+ QHostInfoRunnable *scheduled = iterator.next();
+
+ // check if a lookup for this host is already running, then postpone
+ for (int i = 0; i < currentLookups.size(); i++) {
+ if (currentLookups.at(i)->toBeLookedUp == scheduled->toBeLookedUp) {
+ iterator.remove();
+ postponedLookups.append(scheduled);
+ scheduled = 0;
+ break;
+ }
+ }
+
+ if (scheduled && currentLookups.size() < threadPool.maxThreadCount()) {
+ // runnable now running in new thread, track this in currentLookups
+ threadPool.start(scheduled);
+ iterator.remove();
+ currentLookups.append(scheduled);
+ } else {
+ // was postponed, continue iterating
+ continue;
+ }
+ };
+ }
+}
+
+// called by QHostInfo
+void QHostInfoLookupManager::scheduleLookup(QHostInfoRunnable *r)
+{
+ if (wasDeleted)
+ return;
+
+ QMutexLocker locker(&this->mutex);
+ scheduledLookups.enqueue(r);
+ work();
+}
+
+// called by QHostInfo
+void QHostInfoLookupManager::abortLookup(int id)
+{
+ if (wasDeleted)
+ return;
+
+ QMutexLocker locker(&this->mutex);
+
+ // is postponed? delete and return
+ for (int i = 0; i < postponedLookups.length(); i++) {
+ if (postponedLookups.at(i)->id == id) {
+ delete postponedLookups.takeAt(i);
+ return;
+ }
+ }
+
+ // is scheduled? delete and return
+ for (int i = 0; i < scheduledLookups.length(); i++) {
+ if (scheduledLookups.at(i)->id == id) {
+ delete scheduledLookups.takeAt(i);
+ return;
+ }
+ }
+
+ if (!abortedLookups.contains(id))
+ abortedLookups.append(id);
+}
+
+// called from QHostInfoRunnable
+bool QHostInfoLookupManager::wasAborted(int id)
+{
+ if (wasDeleted)
+ return true;
+
+ QMutexLocker locker(&this->mutex);
+ return abortedLookups.contains(id);
+}
+
+// called from QHostInfoRunnable
+void QHostInfoLookupManager::lookupFinished(QHostInfoRunnable *r)
+{
+ if (wasDeleted)
+ return;
+
+ QMutexLocker locker(&this->mutex);
+ currentLookups.removeOne(r);
+ finishedLookups.append(r);
+ work();
+}
+#endif
+
+// This function returns immediately when we had a result in the cache, else it will later emit a signal
+QHostInfo qt_qhostinfo_lookup(const QString &name, QObject *receiver, const char *member, bool *valid, int *id)
+{
+ *valid = false;
+ *id = -1;
+
+ // check cache
+ QAbstractHostInfoLookupManager* manager = theHostInfoLookupManager();
+ if (manager && manager->cache.isEnabled()) {
+ QHostInfo info = manager->cache.get(name, valid);
+ if (*valid) {
+ return info;
+ }
+ }
+
+ // was not in cache, trigger lookup
+ *id = QHostInfo::lookupHost(name, receiver, member);
+
+ // return empty response, valid==false
+ return QHostInfo();
+}
+
+void qt_qhostinfo_clear_cache()
+{
+ QAbstractHostInfoLookupManager* manager = theHostInfoLookupManager();
+ if (manager) {
+ manager->clear();
+ }
+}
+
+void Q_AUTOTEST_EXPORT qt_qhostinfo_enable_cache(bool e)
+{
+ QAbstractHostInfoLookupManager* manager = theHostInfoLookupManager();
+ if (manager) {
+ manager->cache.setEnabled(e);
+ }
+}
+
+// cache for 60 seconds
+// cache 64 items
+QHostInfoCache::QHostInfoCache() : max_age(60), enabled(true), cache(64)
+{
+#ifdef QT_QHOSTINFO_CACHE_DISABLED_BY_DEFAULT
+ enabled = false;
+#endif
+}
+
+bool QHostInfoCache::isEnabled()
+{
+ return enabled;
+}
+
+// this function is currently only used for the auto tests
+// and not usable by public API
+void QHostInfoCache::setEnabled(bool e)
+{
+ enabled = e;
+}
+
+
+QHostInfo QHostInfoCache::get(const QString &name, bool *valid)
+{
+ QMutexLocker locker(&this->mutex);
+
+ *valid = false;
+ if (cache.contains(name)) {
+ QHostInfoCacheElement *element = cache.object(name);
+ if (element->age.elapsed() < max_age*1000)
+ *valid = true;
+ return element->info;
+
+ // FIXME idea:
+ // if too old but not expired, trigger a new lookup
+ // to freshen our cache
+ }
+
+ return QHostInfo();
+}
+
+void QHostInfoCache::put(const QString &name, const QHostInfo &info)
+{
+ // if the lookup failed, don't cache
+ if (info.error() != QHostInfo::NoError)
+ return;
+
+ QHostInfoCacheElement* element = new QHostInfoCacheElement();
+ element->info = info;
+ element->age = QElapsedTimer();
+ element->age.start();
+
+ QMutexLocker locker(&this->mutex);
+ cache.insert(name, element); // cache will take ownership
+}
+
+void QHostInfoCache::clear()
+{
+ QMutexLocker locker(&this->mutex);
+ cache.clear();
+}
+
+QAbstractHostInfoLookupManager* QAbstractHostInfoLookupManager::globalInstance()
+{
+ return theHostInfoLookupManager();
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/kernel/qhostinfo.h b/src/network/kernel/qhostinfo.h
new file mode 100644
index 0000000000..33453e76ce
--- /dev/null
+++ b/src/network/kernel/qhostinfo.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QHOSTINFO_H
+#define QHOSTINFO_H
+
+#include <QtCore/qlist.h>
+#include <QtCore/qscopedpointer.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:
+ QScopedPointer<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 0000000000..8da069262a
--- /dev/null
+++ b/src/network/kernel/qhostinfo_p.h
@@ -0,0 +1,319 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@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 QHostInfo 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"
+#include "QtCore/qthread.h"
+#include "QtCore/qthreadpool.h"
+#include "QtCore/qmutex.h"
+#include "QtCore/qrunnable.h"
+#include "QtCore/qlist.h"
+#include "QtCore/qqueue.h"
+#include <QElapsedTimer>
+#include <QCache>
+
+#include <QNetworkSession>
+#include <QSharedPointer>
+
+#ifdef Q_OS_SYMBIAN
+// Symbian Headers
+#include <es_sock.h>
+#include <in_sock.h>
+#endif
+
+
+QT_BEGIN_NAMESPACE
+
+
+class QHostInfoResult : public QObject
+{
+ Q_OBJECT
+public Q_SLOTS:
+ inline void emitResultsReady(const QHostInfo &info)
+ {
+ emit resultsReady(info);
+ }
+
+Q_SIGNALS:
+ void resultsReady(const QHostInfo &info);
+};
+
+// needs to be QObject because fromName calls tr()
+class QHostInfoAgent : public QObject
+{
+ Q_OBJECT
+public:
+ static QHostInfo fromName(const QString &hostName);
+ static QHostInfo fromName(const QString &hostName, QSharedPointer<QNetworkSession> networkSession);
+
+#ifdef Q_OS_SYMBIAN
+ static int lookupHost(const QString &name, QObject *receiver, const char *member);
+ static void abortHostLookup(int lookupId);
+#endif
+};
+
+class QHostInfoPrivate
+{
+public:
+ inline QHostInfoPrivate()
+ : err(QHostInfo::NoError),
+ errorStr(QLatin1String(QT_TRANSLATE_NOOP("QHostInfo", "Unknown error"))),
+ lookupId(0)
+ {
+ }
+#ifndef QT_NO_BEARERMANAGEMENT
+ //not a public API yet
+ static QHostInfo fromName(const QString &hostName, QSharedPointer<QNetworkSession> networkSession);
+#endif
+
+ QHostInfo::HostInfoError err;
+ QString errorStr;
+ QList<QHostAddress> addrs;
+ QString hostName;
+ int lookupId;
+};
+
+// These functions are outside of the QHostInfo class and strictly internal.
+// Do NOT use them outside of QAbstractSocket.
+QHostInfo Q_NETWORK_EXPORT qt_qhostinfo_lookup(const QString &name, QObject *receiver, const char *member, bool *valid, int *id);
+void Q_AUTOTEST_EXPORT qt_qhostinfo_clear_cache();
+void Q_AUTOTEST_EXPORT qt_qhostinfo_enable_cache(bool e);
+
+class QHostInfoCache
+{
+public:
+ QHostInfoCache();
+ const int max_age; // seconds
+
+ QHostInfo get(const QString &name, bool *valid);
+ void put(const QString &name, const QHostInfo &info);
+ void clear();
+
+ bool isEnabled();
+ void setEnabled(bool e);
+private:
+ bool enabled;
+ struct QHostInfoCacheElement {
+ QHostInfo info;
+ QElapsedTimer age;
+ };
+ QCache<QString,QHostInfoCacheElement> cache;
+ QMutex mutex;
+};
+
+// the following classes are used for the (normal) case: We use multiple threads to lookup DNS
+
+class QHostInfoRunnable : public QRunnable
+{
+public:
+ QHostInfoRunnable (QString hn, int i);
+ void run();
+
+ QString toBeLookedUp;
+ int id;
+ QHostInfoResult resultEmitter;
+};
+
+
+class QAbstractHostInfoLookupManager : public QObject
+{
+ Q_OBJECT
+
+public:
+ ~QAbstractHostInfoLookupManager() {}
+ virtual void clear() = 0;
+
+ QHostInfoCache cache;
+
+protected:
+ QAbstractHostInfoLookupManager() {}
+ static QAbstractHostInfoLookupManager* globalInstance();
+
+};
+
+#ifndef Q_OS_SYMBIAN
+class QHostInfoLookupManager : public QAbstractHostInfoLookupManager
+{
+ Q_OBJECT
+public:
+ QHostInfoLookupManager();
+ ~QHostInfoLookupManager();
+
+ void clear();
+ void work();
+
+ // called from QHostInfo
+ void scheduleLookup(QHostInfoRunnable *r);
+ void abortLookup(int id);
+
+ // called from QHostInfoRunnable
+ void lookupFinished(QHostInfoRunnable *r);
+ bool wasAborted(int id);
+
+ friend class QHostInfoRunnable;
+protected:
+ QList<QHostInfoRunnable*> currentLookups; // in progress
+ QList<QHostInfoRunnable*> postponedLookups; // postponed because in progress for same host
+ QQueue<QHostInfoRunnable*> scheduledLookups; // not yet started
+ QList<QHostInfoRunnable*> finishedLookups; // recently finished
+ QList<int> abortedLookups; // ids of aborted lookups
+
+ QThreadPool threadPool;
+
+ QMutex mutex;
+
+ bool wasDeleted;
+
+private slots:
+ void waitForThreadPoolDone() { threadPool.waitForDone(); }
+};
+
+#else
+
+class QSymbianHostResolver : public CActive
+{
+public:
+ QSymbianHostResolver(const QString &hostName, int id, QSharedPointer<QNetworkSession> networkSession);
+ ~QSymbianHostResolver();
+
+ void requestHostLookup();
+ void abortHostLookup();
+ int id();
+
+ void returnResults();
+
+ QHostInfoResult resultEmitter;
+
+private:
+ void DoCancel();
+ void RunL();
+ void run();
+ TInt RunError(TInt aError);
+
+ void processNameResult();
+ void nextNameResult();
+ void processAddressResult();
+
+private:
+ int iId;
+
+ const QString iHostName;
+ QString iEncodedHostName;
+ TPtrC iHostNamePtr;
+
+ RSocketServ& iSocketServ;
+ RHostResolver iHostResolver;
+ QSharedPointer<QNetworkSession> iNetworkSession;
+
+ TNameEntry iNameResult;
+ TInetAddr IpAdd;
+
+ QHostAddress iAddress;
+
+ QHostInfo iResults;
+
+ QList<QHostAddress> iHostAddresses;
+
+ enum {
+ EIdle,
+ EGetByName,
+ EGetByAddress,
+ ECompleteFromCache,
+ EError
+ } iState;
+};
+
+class QSymbianHostInfoLookupManager : public QAbstractHostInfoLookupManager
+{
+ Q_OBJECT
+public:
+ QSymbianHostInfoLookupManager();
+ ~QSymbianHostInfoLookupManager();
+
+ static QSymbianHostInfoLookupManager* globalInstance();
+
+ int id();
+ void clear();
+
+ // called from QHostInfo
+ void scheduleLookup(QSymbianHostResolver *r);
+ void abortLookup(int id);
+
+ // called from QSymbianHostResolver
+ void lookupFinished(QSymbianHostResolver *r);
+
+private:
+ void runNextLookup();
+
+ // this is true for single threaded use, with multiple threads the max is ((number of threads) + KMaxConcurrentLookups - 1)
+ static const int KMaxConcurrentLookups = 5;
+
+ QList<QSymbianHostResolver*> iCurrentLookups;
+ QList<QSymbianHostResolver*> iScheduledLookups;
+
+ QMutex mutex;
+};
+#endif
+
+
+
+QT_END_NAMESPACE
+
+#endif // QHOSTINFO_P_H
diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp
new file mode 100644
index 0000000000..2a8de1d2de
--- /dev/null
+++ b/src/network/kernel/qhostinfo_symbian.cpp
@@ -0,0 +1,600 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QHOSTINFO_DEBUG
+
+// Qt Headers
+#include <QByteArray>
+#include <QUrl>
+#include <QList>
+
+#include "qplatformdefs.h"
+
+#include "qhostinfo_p.h"
+#include <private/qcore_symbian_p.h>
+#include <private/qsystemerror_p.h>
+#include <private/qnetworksession_p.h>
+
+// Header does not exist in the S60 5.0 SDK
+//#include <networking/dnd_err.h>
+const TInt KErrDndNameNotFound = -5120; // Returned when no data found for GetByName
+const TInt KErrDndAddrNotFound = -5121; // Returned when no data found for GetByAddr
+
+QT_BEGIN_NAMESPACE
+
+static void setError_helper(QHostInfo &info, TInt symbianError)
+{
+ switch (symbianError) {
+ case KErrDndNameNotFound:
+ case KErrDndAddrNotFound:
+ case KErrNotFound:
+ case KErrEof:
+ // various "no more results" error codes
+ info.setError(QHostInfo::HostNotFound);
+ info.setErrorString(QObject::tr("Host not found"));
+ break;
+ default:
+ // Unknown error
+ info.setError(QHostInfo::UnknownError);
+ info.setErrorString(QSystemError(symbianError, QSystemError::NativeError).toString());
+ break;
+ }
+}
+
+QHostInfo QHostInfoAgent::fromName(const QString &hostName, QSharedPointer<QNetworkSession> networkSession)
+{
+ QHostInfo results;
+
+ // Connect to ESOCK
+ RSocketServ socketServ(qt_symbianGetSocketServer());
+ RHostResolver hostResolver;
+
+
+ int err;
+ if (networkSession)
+ err = QNetworkSessionPrivate::nativeOpenHostResolver(*networkSession, hostResolver, KAfInet, KProtocolInetUdp);
+ else
+ err = hostResolver.Open(socketServ, KAfInet, KProtocolInetUdp);
+ if (err) {
+ setError_helper(results, err);
+ return results;
+ }
+
+ TNameEntry nameResult;
+
+#if defined(QHOSTINFO_DEBUG)
+ qDebug("QHostInfoAgent::fromName(%s) looking up...",
+ hostName.toLatin1().constData());
+#endif
+
+ QHostAddress address;
+ if (address.setAddress(hostName)) {
+ // Reverse lookup
+#if defined(QHOSTINFO_DEBUG)
+ qDebug("(reverse lookup)");
+#endif
+ TInetAddr IpAdd;
+ IpAdd.Input(qt_QString2TPtrC(hostName));
+
+ // Synchronous request. nameResult returns Host Name.
+ err = hostResolver.GetByAddress(IpAdd, nameResult);
+ if (err) {
+ //for behavioural compatibility with Qt 4.7 and unix/windows
+ //backends: don't report error, return ip address as host name
+ results.setHostName(address.toString());
+ } else {
+ results.setHostName(qt_TDesC2QString(nameResult().iName));
+ }
+ results.setAddresses(QList<QHostAddress>() << address);
+ return results;
+ }
+
+ // IDN support
+ QByteArray aceHostname = QUrl::toAce(hostName);
+ results.setHostName(hostName);
+ if (aceHostname.isEmpty()) {
+ results.setError(QHostInfo::HostNotFound);
+ results.setErrorString(hostName.isEmpty() ?
+ QCoreApplication::translate("QHostInfoAgent", "No host name given") :
+ QCoreApplication::translate("QHostInfoAgent", "Invalid hostname"));
+ return results;
+ }
+
+
+ // Call RHostResolver::GetByAddress, and place all IPv4 addresses at the start and
+ // the IPv6 addresses at the end of the address list in results.
+
+ // Synchronous request.
+ err = hostResolver.GetByName(qt_QString2TPtrC(QString::fromLatin1(aceHostname)), nameResult);
+ if (err) {
+ setError_helper(results, err);
+ return results;
+ }
+
+ QList<QHostAddress> hostAddresses;
+
+ TInetAddr hostAdd = nameResult().iAddr;
+ // 39 is the maximum length of an IPv6 address.
+ TBuf<39> ipAddr;
+
+ // Fill ipAddr with the IP address from hostAdd
+ hostAdd.Output(ipAddr);
+ if (ipAddr.Length() > 0)
+ hostAddresses.append(QHostAddress(qt_TDesC2QString(ipAddr)));
+
+ // Check if there's more than one IP address linkd to this name
+ while (hostResolver.Next(nameResult) == KErrNone) {
+ hostAdd = nameResult().iAddr;
+ hostAdd.Output(ipAddr);
+
+ // Ensure that record is valid (not an alias and with length greater than 0)
+ if (!(nameResult().iFlags & TNameRecord::EAlias) && !(hostAdd.IsUnspecified())) {
+ hostAddresses.append(QHostAddress(qt_TDesC2QString(ipAddr)));
+ }
+ }
+
+ hostResolver.Close();
+
+ results.setAddresses(hostAddresses);
+ return results;
+}
+
+QHostInfo QHostInfoAgent::fromName(const QString &hostName)
+{
+ // null shared pointer
+ QSharedPointer<QNetworkSession> networkSession;
+ return fromName(hostName, networkSession);
+}
+
+QString QHostInfo::localHostName()
+{
+ // Connect to ESOCK
+ RSocketServ socketServ(qt_symbianGetSocketServer());
+ RHostResolver hostResolver;
+
+ // RConnection not required to get the host name
+ int err = hostResolver.Open(socketServ, KAfInet, KProtocolInetUdp);
+ if (err)
+ return QString();
+
+ THostName hostName;
+ err = hostResolver.GetHostName(hostName);
+ if (err)
+ return QString();
+
+ hostResolver.Close();
+
+ return qt_TDesC2QString(hostName);
+}
+
+QString QHostInfo::localDomainName()
+{
+ // This concept does not exist on Symbian OS because the device can be on
+ // multiple networks with multiple "local domain" names.
+ // For now, return a null string.
+ return QString();
+}
+
+
+QSymbianHostResolver::QSymbianHostResolver(const QString &hostName, int identifier, QSharedPointer<QNetworkSession> networkSession)
+ : CActive(CActive::EPriorityStandard), iHostName(hostName),
+ iSocketServ(qt_symbianGetSocketServer()), iNetworkSession(networkSession), iResults(identifier)
+{
+ CActiveScheduler::Add(this);
+}
+
+QSymbianHostResolver::~QSymbianHostResolver()
+{
+#if defined(QHOSTINFO_DEBUG)
+ qDebug() << "QSymbianHostInfoLookupManager::~QSymbianHostResolver" << id();
+#endif
+ Cancel();
+ iHostResolver.Close();
+}
+
+// Async equivalent to QHostInfoAgent::fromName()
+void QSymbianHostResolver::requestHostLookup()
+{
+
+#if defined(QHOSTINFO_DEBUG)
+ qDebug("QSymbianHostResolver::requestHostLookup(%s) looking up... (id = %d)",
+ iHostName.toLatin1().constData(), id());
+#endif
+
+ QSymbianHostInfoLookupManager *manager = QSymbianHostInfoLookupManager::globalInstance();
+ if (manager->cache.isEnabled()) {
+ //check if name has been put in the cache while this request was queued
+ bool valid;
+ QHostInfo cachedResult = manager->cache.get(iHostName, &valid);
+ if (valid) {
+#if defined(QHOSTINFO_DEBUG)
+ qDebug("...found in cache");
+#endif
+ iResults = cachedResult;
+ iState = ECompleteFromCache;
+ SetActive();
+ TRequestStatus* stat = &iStatus;
+ User::RequestComplete(stat, KErrNone);
+ return;
+ }
+ }
+
+ int err;
+ if (iNetworkSession) {
+ err = QNetworkSessionPrivate::nativeOpenHostResolver(*iNetworkSession, iHostResolver, KAfInet, KProtocolInetUdp);
+#if defined(QHOSTINFO_DEBUG)
+ qDebug("using resolver from session (err = %d)", err);
+#endif
+ } else {
+ err = iHostResolver.Open(iSocketServ, KAfInet, KProtocolInetUdp);
+#if defined(QHOSTINFO_DEBUG)
+ qDebug("using default resolver (err = %d)", err);
+#endif
+ }
+ if (err) {
+ setError_helper(iResults, err);
+ } else {
+
+ if (iAddress.setAddress(iHostName)) {
+ // Reverse lookup
+ IpAdd.Input(qt_QString2TPtrC(iHostName));
+
+ // Asynchronous request.
+ iHostResolver.GetByAddress(IpAdd, iNameResult, iStatus); // <---- ASYNC
+ iState = EGetByAddress;
+
+ } else {
+
+ // IDN support
+ QByteArray aceHostname = QUrl::toAce(iHostName);
+ iResults.setHostName(iHostName);
+ if (aceHostname.isEmpty()) {
+ iResults.setError(QHostInfo::HostNotFound);
+ iResults.setErrorString(iHostName.isEmpty() ?
+ QCoreApplication::translate("QHostInfoAgent", "No host name given") :
+ QCoreApplication::translate("QHostInfoAgent", "Invalid hostname"));
+
+ err = KErrArgument;
+ } else {
+ iEncodedHostName = QString::fromLatin1(aceHostname);
+ iHostNamePtr.Set(qt_QString2TPtrC(iEncodedHostName));
+
+ // Asynchronous request.
+ iHostResolver.GetByName(iHostNamePtr, iNameResult, iStatus);
+ iState = EGetByName;
+ }
+ }
+ }
+ SetActive();
+ if (err) {
+ iHostResolver.Close();
+
+ //self complete so that RunL can inform manager without causing recursion
+ iState = EError;
+ TRequestStatus* stat = &iStatus;
+ User::RequestComplete(stat, err);
+ }
+}
+
+void QSymbianHostResolver::abortHostLookup()
+{
+ if (resultEmitter.thread() == QThread::currentThread()) {
+#ifdef QHOSTINFO_DEBUG
+ qDebug("QSymbianHostResolver::abortHostLookup - deleting %d", id());
+#endif
+ //normal case, abort from same thread it was started
+ delete this; //will cancel outstanding request
+ } else {
+#ifdef QHOSTINFO_DEBUG
+ qDebug("QSymbianHostResolver::abortHostLookup - detaching %d", id());
+#endif
+ //abort from different thread, carry on but don't report the results
+ resultEmitter.disconnect();
+ }
+}
+
+void QSymbianHostResolver::DoCancel()
+{
+#if defined(QHOSTINFO_DEBUG)
+ qDebug() << "QSymbianHostResolver::DoCancel" << QThread::currentThreadId() << id() << (int)iState << this;
+#endif
+ if (iState == EGetByAddress || iState == EGetByName) {
+ //these states have made an async request to host resolver
+ iHostResolver.Cancel();
+ } else {
+ //for the self completing states there is nothing to cancel
+ Q_ASSERT(iState == EError || iState == ECompleteFromCache);
+ }
+}
+
+void QSymbianHostResolver::RunL()
+{
+ QT_TRYCATCH_LEAVING(run());
+}
+
+void QSymbianHostResolver::run()
+{
+ switch (iState) {
+ case EGetByName:
+ processNameResult();
+ break;
+ case EGetByAddress:
+ processAddressResult();
+ break;
+ case ECompleteFromCache:
+ case EError:
+ returnResults();
+ break;
+ default:
+ qWarning("QSymbianHostResolver internal error, bad state in run()");
+ iResults.setError(QHostInfo::UnknownError);
+ iResults.setErrorString(QSystemError(KErrCorrupt,QSystemError::NativeError).toString());
+ returnResults();
+ }
+}
+
+void QSymbianHostResolver::returnResults()
+{
+#if defined(QHOSTINFO_DEBUG)
+ qDebug() << "QSymbianHostResolver::returnResults" << iResults.error() << iResults.errorString();
+ foreach (QHostAddress addr, iResults.addresses())
+ qDebug() << addr;
+#endif
+ iState = EIdle;
+
+ QSymbianHostInfoLookupManager *manager = QSymbianHostInfoLookupManager::globalInstance();
+ if (manager->cache.isEnabled()) {
+ manager->cache.put(iHostName, iResults);
+ }
+ manager->lookupFinished(this);
+
+ resultEmitter.emitResultsReady(iResults);
+
+ delete this;
+}
+
+TInt QSymbianHostResolver::RunError(TInt aError)
+{
+ QT_TRY {
+ iState = EIdle;
+
+ QSymbianHostInfoLookupManager *manager = QSymbianHostInfoLookupManager::globalInstance();
+ manager->lookupFinished(this);
+
+ setError_helper(iResults, aError);
+
+ resultEmitter.emitResultsReady(iResults);
+ }
+ QT_CATCH(...) {}
+
+ delete this;
+
+ return KErrNone;
+}
+
+void QSymbianHostResolver::processNameResult()
+{
+ if (iStatus.Int() == KErrNone) {
+ TInetAddr hostAdd = iNameResult().iAddr;
+ // 39 is the maximum length of an IPv6 address.
+ TBuf<39> ipAddr;
+
+ hostAdd.Output(ipAddr);
+
+ // Ensure that record is valid (not an alias and with length greater than 0)
+ if (!(iNameResult().iFlags & TNameRecord::EAlias) && !(hostAdd.IsUnspecified())) {
+ iHostAddresses.append(QHostAddress(qt_TDesC2QString(ipAddr)));
+ }
+
+ iState = EGetByName;
+ iHostResolver.Next(iNameResult, iStatus);
+ SetActive();
+ }
+ else {
+ // No more addresses, so return the results (or an error if there aren't any).
+#if defined(QHOSTINFO_DEBUG)
+ qDebug() << "QSymbianHostResolver::processNameResult with err=" << iStatus.Int() << "count=" << iHostAddresses.count();
+#endif
+ if (iHostAddresses.count() > 0) {
+ iResults.setAddresses(iHostAddresses);
+ } else {
+ iState = EError;
+ setError_helper(iResults, iStatus.Int());
+ }
+ returnResults();
+ }
+}
+
+void QSymbianHostResolver::processAddressResult()
+{
+ TInt err = iStatus.Int();
+
+ if (err < 0) {
+ //For behavioural compatibility with Qt 4.7, don't report errors on reverse lookup,
+ //return the address as a string (same as unix/windows backends)
+ iResults.setHostName(iAddress.toString());
+ } else {
+ iResults.setHostName(qt_TDesC2QString(iNameResult().iName));
+ }
+ iResults.setAddresses(QList<QHostAddress>() << iAddress);
+ returnResults();
+}
+
+
+int QSymbianHostResolver::id()
+{
+ return iResults.lookupId();
+}
+
+QSymbianHostInfoLookupManager::QSymbianHostInfoLookupManager()
+{
+}
+
+QSymbianHostInfoLookupManager::~QSymbianHostInfoLookupManager()
+{
+}
+
+void QSymbianHostInfoLookupManager::clear()
+{
+ QMutexLocker locker(&mutex);
+#if defined(QHOSTINFO_DEBUG)
+ qDebug() << "QSymbianHostInfoLookupManager::clear" << QThread::currentThreadId();
+#endif
+ foreach (QSymbianHostResolver *hr, iCurrentLookups)
+ hr->abortHostLookup();
+ iCurrentLookups.clear();
+ qDeleteAll(iScheduledLookups);
+ cache.clear();
+}
+
+void QSymbianHostInfoLookupManager::lookupFinished(QSymbianHostResolver *r)
+{
+ QMutexLocker locker(&mutex);
+
+#if defined(QHOSTINFO_DEBUG)
+ qDebug() << "QSymbianHostInfoLookupManager::lookupFinished" << QThread::currentThreadId() << r->id() << "current" << iCurrentLookups.count() << "queued" << iScheduledLookups.count();
+#endif
+ // remove finished lookup from array and destroy
+ TInt count = iCurrentLookups.count();
+ for (TInt i = 0; i < count; i++) {
+ if (iCurrentLookups[i]->id() == r->id()) {
+ iCurrentLookups.removeAt(i);
+ break;
+ }
+ }
+
+ runNextLookup();
+}
+
+void QSymbianHostInfoLookupManager::runNextLookup()
+{
+#if defined(QHOSTINFO_DEBUG)
+ qDebug() << "QSymbianHostInfoLookupManager::runNextLookup" << QThread::currentThreadId() << "current" << iCurrentLookups.count() << "queued" << iScheduledLookups.count();
+#endif
+ // check to see if there are any scheduled lookups
+ for (int i=0; i<iScheduledLookups.count(); i++) {
+ QSymbianHostResolver* hostResolver = iScheduledLookups.at(i);
+ if (hostResolver->resultEmitter.thread() == QThread::currentThread()) {
+ // if so, move one to the current lookups and run it
+ iCurrentLookups.append(hostResolver);
+ iScheduledLookups.removeAt(i);
+ hostResolver->requestHostLookup();
+ // if spare capacity, try to start another one
+ if (iCurrentLookups.count() >= KMaxConcurrentLookups)
+ break;
+ i--; //compensate for removeAt
+ }
+ }
+}
+
+// called from QHostInfo
+void QSymbianHostInfoLookupManager::scheduleLookup(QSymbianHostResolver* r)
+{
+ QMutexLocker locker(&mutex);
+
+#if defined(QHOSTINFO_DEBUG)
+ qDebug() << "QSymbianHostInfoLookupManager::scheduleLookup" << QThread::currentThreadId() << r->id() << "current" << iCurrentLookups.count() << "queued" << iScheduledLookups.count();
+#endif
+ // Check to see if we have space on the current lookups pool.
+ bool defer = false;
+ if (iCurrentLookups.count() >= KMaxConcurrentLookups) {
+ // busy, defer unless there are no request in this thread
+ // at least one active request per thread with queued requests is needed
+ for (int i=0; i < iCurrentLookups.count();i++) {
+ if (iCurrentLookups.at(i)->resultEmitter.thread() == QThread::currentThread()) {
+ defer = true;
+ break;
+ }
+ }
+ }
+ if (defer) {
+ // If no, schedule for later.
+ iScheduledLookups.append(r);
+#if defined(QHOSTINFO_DEBUG)
+ qDebug(" - scheduled");
+#endif
+ return;
+ } else {
+ // If yes, add it to the current lookups.
+ iCurrentLookups.append(r);
+
+ // ... and trigger the async call.
+ r->requestHostLookup();
+ }
+}
+
+void QSymbianHostInfoLookupManager::abortLookup(int id)
+{
+ QMutexLocker locker(&mutex);
+
+#if defined(QHOSTINFO_DEBUG)
+ qDebug() << "QSymbianHostInfoLookupManager::abortLookup" << QThread::currentThreadId() << id << "current" << iCurrentLookups.count() << "queued" << iScheduledLookups.count();
+#endif
+ int i = 0;
+ // Find the aborted lookup by ID.
+ // First in the current lookups.
+ for (i = 0; i < iCurrentLookups.count(); i++) {
+ if (id == iCurrentLookups[i]->id()) {
+ QSymbianHostResolver* r = iCurrentLookups.at(i);
+ iCurrentLookups.removeAt(i);
+ r->abortHostLookup();
+ runNextLookup();
+ return;
+ }
+ }
+ // Then in the scheduled lookups.
+ for (i = 0; i < iScheduledLookups.count(); i++) {
+ if (id == iScheduledLookups[i]->id()) {
+ QSymbianHostResolver* r = iScheduledLookups.at(i);
+ iScheduledLookups.removeAt(i);
+ delete r;
+ return;
+ }
+ }
+}
+
+QSymbianHostInfoLookupManager* QSymbianHostInfoLookupManager::globalInstance()
+{
+ return static_cast<QSymbianHostInfoLookupManager*>
+ (QAbstractHostInfoLookupManager::globalInstance());
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/kernel/qhostinfo_unix.cpp b/src/network/kernel/qhostinfo_unix.cpp
new file mode 100644
index 0000000000..8fc6bf6504
--- /dev/null
+++ b/src/network/kernel/qhostinfo_unix.cpp
@@ -0,0 +1,396 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QHOSTINFO_DEBUG
+
+#include "qplatformdefs.h"
+
+#include "qhostinfo_p.h"
+#include "private/qnativesocketengine_p.h"
+#include "qiodevice.h"
+#include <qbytearray.h>
+#include <qlibrary.h>
+#include <qurl.h>
+#include <qfile.h>
+#include <private/qmutexpool_p.h>
+#include <private/qnet_unix_p.h>
+
+#include <sys/types.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#if defined(Q_OS_VXWORKS)
+# include <hostLib.h>
+#else
+# include <resolv.h>
+#endif
+
+#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;
+
+#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) {
+ QMutexLocker locker(QMutexPool::globalInstanceGet(&local_res_init));
+ 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.setHostName(QString::fromLatin1(hbuf));
+#else
+ in_addr_t inetaddr = qt_safe_inet_addr(hostName.toLatin1().constData());
+ struct hostent *ent = gethostbyaddr((const char *)&inetaddr, sizeof(inetaddr), AF_INET);
+ if (ent)
+ results.setHostName(QString::fromLatin1(ent->h_name));
+#endif
+
+ if (results.hostName().isEmpty())
+ results.setHostName(address.toString());
+ results.setAddresses(QList<QHostAddress>() << address);
+ return results;
+ }
+
+ // IDN support
+ QByteArray aceHostname = QUrl::toAce(hostName);
+ results.setHostName(hostName);
+ if (aceHostname.isEmpty()) {
+ results.setError(QHostInfo::HostNotFound);
+ results.setErrorString(hostName.isEmpty() ?
+ QCoreApplication::translate("QHostInfoAgent", "No host name given") :
+ QCoreApplication::translate("QHostInfoAgent", "Invalid hostname"));
+ return results;
+ }
+
+#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(aceHostname.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(aceHostname.constData(), 0, &hints, &res);
+ }
+# endif
+
+ if (result == 0) {
+ addrinfo *node = res;
+ QList<QHostAddress> addresses;
+ while (node) {
+#ifdef QHOSTINFO_DEBUG
+ qDebug() << "getaddrinfo node: flags:" << node->ai_flags << "family:" << node->ai_family << "ai_socktype:" << node->ai_socktype << "ai_protocol:" << node->ai_protocol << "ai_addrlen:" << node->ai_addrlen;
+#endif
+ 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;
+ sockaddr_in6 *sa6 = (sockaddr_in6 *) node->ai_addr;
+ addr.setAddress(sa6->sin6_addr.s6_addr);
+ if (sa6->sin6_scope_id)
+ addr.setScopeId(QString::number(sa6->sin6_scope_id));
+ 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(aceHostname.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"));
+ }
+#if !defined(Q_OS_VXWORKS)
+ } 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"));
+#endif
+ } 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()
+{
+#if !defined(Q_OS_VXWORKS)
+ resolveLibrary();
+ if (local_res_ninit) {
+ // using thread-safe version
+ res_state_ptr state = res_state_ptr(qMalloc(sizeof(*state)));
+ Q_CHECK_PTR(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;
+ }
+#endif
+ // 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 0000000000..58f309b80b
--- /dev/null
+++ b/src/network/kernel/qhostinfo_win.cpp
@@ -0,0 +1,274 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <winsock2.h>
+
+#include "qhostinfo_p.h"
+#include "private/qnativesocketengine_p.h"
+#include <ws2tcpip.h>
+#include <private/qsystemlibrary_p.h>
+#include <qmutex.h>
+#include <qurl.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;
+};
+
+//###
+#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) QSystemLibrary::resolve(QLatin1String("ws2_32"), "getaddrinfo");
+ local_freeaddrinfo = (freeaddrinfoProto) QSystemLibrary::resolve(QLatin1String("ws2_32"), "freeaddrinfo");
+ local_getnameinfo = (getnameinfoProto) QSystemLibrary::resolve(QLatin1String("ws2_32"), "getnameinfo");
+#else
+ local_getaddrinfo = (getaddrinfoProto) QSystemLibrary::resolve(QLatin1String("ws2"), "getaddrinfo");
+ local_freeaddrinfo = (freeaddrinfoProto) QSystemLibrary::resolve(QLatin1String("ws2"), "freeaddrinfo");
+ local_getnameinfo = (getnameinfoProto) QSystemLibrary::resolve(QLatin1String("ws2"), "getnameinfo");
+#endif
+}
+
+#if defined(Q_OS_WINCE)
+#include <qmutex.h>
+QMutex qPrivCEMutex;
+#endif
+
+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) {
+ QMutexLocker locker(QMutexPool::globalInstanceGet(&local_getaddrinfo));
+ if (!triedResolve) {
+ resolveLibrary();
+ triedResolve = true;
+ }
+ }
+
+ QHostInfo results;
+
+#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.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.setHostName(QString::fromLatin1(ent->h_name));
+ }
+
+ if (results.hostName().isEmpty())
+ results.setHostName(address.toString());
+ results.setAddresses(QList<QHostAddress>() << address);
+ return results;
+ }
+
+ // IDN support
+ QByteArray aceHostname = QUrl::toAce(hostName);
+ results.setHostName(hostName);
+ if (aceHostname.isEmpty()) {
+ results.setError(QHostInfo::HostNotFound);
+ results.setErrorString(hostName.isEmpty() ? tr("No host name given") : tr("Invalid hostname"));
+ return results;
+ }
+
+ 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(aceHostname.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(aceHostname.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 0000000000..e72bc65c2b
--- /dev/null
+++ b/src/network/kernel/qnetworkinterface.cpp
@@ -0,0 +1,619 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@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 network
+
+ 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.data()))
+{
+}
+
+/*!
+ Makes a copy of the QNetworkAddressEntry object \a other.
+*/
+QNetworkAddressEntry &QNetworkAddressEntry::operator=(const QNetworkAddressEntry &other)
+{
+ *d.data() = *other.d.data();
+ return *this;
+}
+
+/*!
+ Destroys this QNetworkAddressEntry object.
+*/
+QNetworkAddressEntry::~QNetworkAddressEntry()
+{
+}
+
+/*!
+ 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 network
+
+ 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 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 (const 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());
+#if defined(Q_CC_RVCT)
+ // RVCT gets confused with << networkInterface.addressEntries(), reason unknown.
+ debug.nospace() << ")\n";
+#else
+ debug.nospace() << ", entries = " << networkInterface.addressEntries()
+ << ")\n";
+#endif
+ 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 0000000000..d65a6d70a5
--- /dev/null
+++ b/src/network/kernel/qnetworkinterface.h
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QNETWORKINTERFACE_H
+#define QNETWORKINTERFACE_H
+
+#include <QtCore/qshareddata.h>
+#include <QtCore/qscopedpointer.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:
+ QScopedPointer<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 0000000000..0136593b8a
--- /dev/null
+++ b/src/network/kernel/qnetworkinterface_p.h
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@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_symbian.cpp b/src/network/kernel/qnetworkinterface_symbian.cpp
new file mode 100644
index 0000000000..7767f54085
--- /dev/null
+++ b/src/network/kernel/qnetworkinterface_symbian.cpp
@@ -0,0 +1,266 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QNETWORKINTERFACE_DEBUG
+
+#include "qnetworkinterface.h"
+#include "qnetworkinterface_p.h"
+#include <private/qcore_symbian_p.h>
+
+#ifndef QT_NO_NETWORKINTERFACE
+
+#include <in_sock.h>
+#include <in_iface.h>
+#include <es_sock.h>
+
+QT_BEGIN_NAMESPACE
+
+
+static QNetworkInterface::InterfaceFlags convertFlags(const TSoInetInterfaceInfo& aInfo)
+{
+ QNetworkInterface::InterfaceFlags flags = 0;
+ flags |= (aInfo.iState == EIfUp) ? QNetworkInterface::IsUp : QNetworkInterface::InterfaceFlag(0);
+ // We do not have separate flag for running in Symbian OS
+ flags |= (aInfo.iState == EIfUp) ? QNetworkInterface::IsRunning : QNetworkInterface::InterfaceFlag(0);
+ flags |= (aInfo.iFeatures & KIfCanBroadcast) ? QNetworkInterface::CanBroadcast : QNetworkInterface::InterfaceFlag(0);
+ flags |= (aInfo.iFeatures & KIfIsLoopback) ? QNetworkInterface::IsLoopBack : QNetworkInterface::InterfaceFlag(0);
+ flags |= (aInfo.iFeatures & KIfIsPointToPoint) ? QNetworkInterface::IsPointToPoint : QNetworkInterface::InterfaceFlag(0);
+ flags |= (aInfo.iFeatures & KIfCanMulticast) ? QNetworkInterface::CanMulticast : QNetworkInterface::InterfaceFlag(0);
+ return flags;
+}
+
+//TODO: share this, at least QHostInfo needs to do the same thing
+static QHostAddress qt_QHostAddressFromTInetAddr(const TInetAddr& addr)
+{
+ //TODO: do we want to call v4 mapped addresses v4 or v6 outside of this file?
+ if (addr.IsV4Mapped() || addr.Family() == KAfInet) {
+ //convert v4 host address
+ return QHostAddress(addr.Address());
+ } else {
+ //convert v6 host address
+ return QHostAddress((quint8 *)(addr.Ip6Address().u.iAddr8));
+ }
+}
+
+static QList<QNetworkInterfacePrivate *> interfaceListing()
+{
+ TInt err(KErrNone);
+ QList<QNetworkInterfacePrivate *> interfaces;
+ QList<QHostAddress> addressesWithEstimatedNetmasks;
+
+ // Open dummy socket for interface queries
+ RSocket socket;
+ err = socket.Open(qt_symbianGetSocketServer(), _L("udp"));
+ if (err) {
+ return interfaces;
+ }
+
+ // Ask socket to start enumerating interfaces
+ err = socket.SetOpt(KSoInetEnumInterfaces, KSolInetIfCtrl);
+ if (err) {
+ socket.Close();
+ return interfaces;
+ }
+
+ int ifindex = 0;
+ TPckgBuf<TSoInetInterfaceInfo> infoPckg;
+ TSoInetInterfaceInfo &info = infoPckg();
+ while (socket.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, infoPckg) == KErrNone) {
+ if (info.iName != KNullDesC) {
+ TName address;
+ QNetworkAddressEntry entry;
+ QNetworkInterfacePrivate *iface = 0;
+
+ iface = new QNetworkInterfacePrivate;
+ iface->index = ifindex++;
+ interfaces << iface;
+ iface->name = qt_TDesC2QString(info.iName);
+ iface->flags = convertFlags(info);
+
+ if (/*info.iFeatures&KIfHasHardwareAddr &&*/ info.iHwAddr.Family() != KAFUnspec) {
+ for (TInt i = sizeof(SSockAddr); i < sizeof(SSockAddr) + info.iHwAddr.GetUserLen(); i++) {
+ address.AppendNumFixedWidth(info.iHwAddr[i], EHex, 2);
+ if ((i + 1) < sizeof(SSockAddr) + info.iHwAddr.GetUserLen())
+ address.Append(_L(":"));
+ }
+ address.UpperCase();
+ iface->hardwareAddress = qt_TDesC2QString(address);
+ }
+
+ // Get the address of the interface
+ entry.setIp(qt_QHostAddressFromTInetAddr(info.iAddress));
+
+#if defined(QNETWORKINTERFACE_DEBUG)
+ qDebug() << "address is" << info.iAddress.Family() << entry.ip();
+ qDebug() << "netmask is" << info.iNetMask.Family() << qt_QHostAddressFromTInetAddr( info.iNetMask );
+#endif
+
+ // Get the interface netmask
+ if (info.iNetMask.IsUnspecified()) {
+ // For some reason netmask is always 0.0.0.0 for IPv4 interfaces
+ // and loopback interfaces (which we statically know)
+ if (info.iAddress.IsV4Mapped()) {
+ if (info.iFeatures & KIfIsLoopback) {
+ entry.setPrefixLength(32);
+ } else {
+ // Workaround: Let Symbian determine netmask based on IP address class (IPv4 only API)
+ TInetAddr netmask;
+ netmask.NetMask(info.iAddress);
+ entry.setNetmask(QHostAddress(netmask.Address())); //binary convert v4 address
+ addressesWithEstimatedNetmasks << entry.ip();
+#if defined(QNETWORKINTERFACE_DEBUG)
+ qDebug() << "address class determined netmask" << entry.netmask();
+#endif
+ }
+ } else {
+ // For IPv6 interfaces
+ if (info.iFeatures & KIfIsLoopback) {
+ entry.setPrefixLength(128);
+ } else if (info.iNetMask.IsUnspecified()) {
+ //Don't see this error for IPv6, but try to handle it if it happens
+ entry.setPrefixLength(64); //most common
+#if defined(QNETWORKINTERFACE_DEBUG)
+ qDebug() << "total guess netmask" << entry.netmask();
+#endif
+ addressesWithEstimatedNetmasks << entry.ip();
+ }
+ }
+ } else {
+ //Expected code path for IPv6 non loopback interfaces (IPv4 could come here if symbian is fixed)
+ entry.setNetmask(qt_QHostAddressFromTInetAddr(info.iNetMask));
+#if defined(QNETWORKINTERFACE_DEBUG)
+ qDebug() << "reported netmask" << entry.netmask();
+#endif
+ }
+
+ // broadcast address is determined from the netmask in postProcess()
+
+ // Add new entry to interface address entries
+ iface->addressEntries << entry;
+
+#if defined(QNETWORKINTERFACE_DEBUG)
+ qDebug("\n Found network interface %s, interface flags:\n\
+ IsUp = %d, IsRunning = %d, CanBroadcast = %d,\n\
+ IsLoopBack = %d, IsPointToPoint = %d, CanMulticast = %d, \n\
+ ip = %s, netmask = %s, broadcast = %s,\n\
+ hwaddress = %s",
+ iface->name.toLatin1().constData(),
+ iface->flags & QNetworkInterface::IsUp, iface->flags & QNetworkInterface::IsRunning, iface->flags & QNetworkInterface::CanBroadcast,
+ iface->flags & QNetworkInterface::IsLoopBack, iface->flags & QNetworkInterface::IsPointToPoint, iface->flags & QNetworkInterface::CanMulticast,
+ entry.ip().toString().toLatin1().constData(), entry.netmask().toString().toLatin1().constData(), entry.broadcast().toString().toLatin1().constData(),
+ iface->hardwareAddress.toLatin1().constData());
+#endif
+ }
+ }
+
+ // if we didn't have to guess any netmasks, then we're done.
+ if (addressesWithEstimatedNetmasks.isEmpty()) {
+ socket.Close();
+ return interfaces;
+ }
+
+ // we will try to use routing info to detect more precisely
+ // estimated netmasks and then ::postProcess() should calculate
+ // broadcast addresses
+
+ // use dummy socket to start enumerating routes
+ err = socket.SetOpt(KSoInetEnumRoutes, KSolInetRtCtrl);
+ if (err) {
+ socket.Close();
+ // return what we have
+ // up to this moment
+ return interfaces;
+ }
+
+ TSoInetRouteInfo routeInfo;
+ TPckg<TSoInetRouteInfo> routeInfoPkg(routeInfo);
+ while (socket.GetOpt(KSoInetNextRoute, KSolInetRtCtrl, routeInfoPkg) == KErrNone) {
+ // get interface address
+ QHostAddress ifAddr(qt_QHostAddressFromTInetAddr(routeInfo.iIfAddr));
+ if (ifAddr.isNull())
+ continue;
+ if (!addressesWithEstimatedNetmasks.contains(ifAddr)) {
+#if defined(QNETWORKINTERFACE_DEBUG)
+ qDebug() << "skipping route from" << ifAddr << "because it wasn't an estimated netmask";
+#endif
+ continue;
+ }
+
+ QHostAddress destination(qt_QHostAddressFromTInetAddr(routeInfo.iDstAddr));
+#if defined(QNETWORKINTERFACE_DEBUG)
+ qDebug() << "route from" << ifAddr << "to" << destination;
+#endif
+ if (destination.isNull() || destination != ifAddr)
+ continue;
+
+ // search interfaces
+ for (int ifindex = 0; ifindex < interfaces.size(); ++ifindex) {
+ QNetworkInterfacePrivate *iface = interfaces.at(ifindex);
+ for (int eindex = 0; eindex < iface->addressEntries.size(); ++eindex) {
+ QNetworkAddressEntry entry = iface->addressEntries.at(eindex);
+ if (entry.ip() != ifAddr) {
+ continue;
+ } else if (!routeInfo.iNetMask.IsUnspecified()) {
+ //the route may also return 0.0.0.0 netmask, in which case don't use it.
+ QHostAddress netmask(qt_QHostAddressFromTInetAddr(routeInfo.iNetMask));
+ entry.setNetmask(netmask);
+#if defined(QNETWORKINTERFACE_DEBUG)
+ qDebug() << " - route netmask" << routeInfo.iNetMask.Family() << netmask << " (using route determined netmask)";
+#endif
+ iface->addressEntries.replace(eindex, entry);
+ }
+ }
+ }
+ }
+
+ socket.Close();
+
+ return interfaces;
+}
+
+QList<QNetworkInterfacePrivate *> QNetworkInterfaceManager::scan()
+{
+ return interfaceListing();
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_NETWORKINTERFACE
diff --git a/src/network/kernel/qnetworkinterface_unix.cpp b/src/network/kernel/qnetworkinterface_unix.cpp
new file mode 100644
index 0000000000..6098bdeee0
--- /dev/null
+++ b/src/network/kernel/qnetworkinterface_unix.cpp
@@ -0,0 +1,449 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qset.h"
+#include "qnetworkinterface.h"
+#include "qnetworkinterface_p.h"
+#include "qalgorithms.h"
+#include "private/qnet_unix_p.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 (qt_safe_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 (qt_safe_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 (qt_safe_ioctl(socket, SIOCGIFFLAGS, &req) >= 0) {
+ iface->flags = convertFlags(req.ifr_flags);
+ }
+
+#ifdef SIOCGIFHWADDR
+ // Get the HW address
+ if (qt_safe_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 = qt_safe_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 (qt_safe_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 (qt_safe_ioctl(socket, SIOCGIFNETMASK, &req) >= 0) {
+ sockaddr *sa = &req.ifr_addr;
+ entry.setNetmask(addressFromSockaddr(sa));
+ }
+
+ // Get the address of the interface
+ if (qt_safe_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 = qt_safe_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 0000000000..e83324c81f
--- /dev/null
+++ b/src/network/kernel/qnetworkinterface_win.cpp
@@ -0,0 +1,328 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@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>
+#include <private/qsystemlibrary_p.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 = QSystemLibrary::load(L"iphlpapi");
+ if (iphlpapiHnd == NULL)
+ return;
+
+#if defined(Q_OS_WINCE)
+ ptrGetAdaptersInfo = (PtrGetAdaptersInfo)GetProcAddress(iphlpapiHnd, L"GetAdaptersInfo");
+ ptrGetAdaptersAddresses = (PtrGetAdaptersAddresses)GetProcAddress(iphlpapiHnd, L"GetAdaptersAddresses");
+ ptrGetNetworkParams = (PtrGetNetworkParams)GetProcAddress(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);
+ if (!pAdapter)
+ return ipv4netmasks;
+ // 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);
+ if (!pAdapter)
+ return interfaces;
+ // 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) && ptr->Ipv6IfIndex != 0)
+ 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);
+ if (!pAdapter)
+ return interfaces;
+ // 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);
+ if (!pinfo)
+ return QString();
+ // 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 0000000000..ca15406012
--- /dev/null
+++ b/src/network/kernel/qnetworkinterface_win_p.h
@@ -0,0 +1,266 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@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 <qt_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 0000000000..68ff95543a
--- /dev/null
+++ b/src/network/kernel/qnetworkproxy.cpp
@@ -0,0 +1,1310 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+/*!
+ \class QNetworkProxy
+
+ \since 4.1
+
+ \brief The QNetworkProxy class provides a network layer proxy.
+
+ \reentrant
+ \ingroup network
+ \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,
+ QNetworkAccessManager 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. Domain names are resolved through the SOCKS5 server if
+ the QNetworkProxy::HostNameLookupCapability is enabled, otherwise
+ they are resolved locally and the IP address is sent to the
+ server. 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 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/qnetworkproxy_p.h"
+#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)),
+ };
+
+ if (int(type) < 0 || int(type) > int(QNetworkProxy::FtpCachingProxy))
+ type = QNetworkProxy::DefaultProxy;
+ 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;
+ bool capabilitiesSet;
+
+ 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),
+ capabilitiesSet(false)
+ { }
+
+ 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)
+{
+ if (QGlobalNetworkProxy *globalProxy = globalNetworkProxy())
+ globalProxy->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))
+{
+ if (QGlobalNetworkProxy *globalProxy = globalNetworkProxy())
+ globalProxy->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 if any
+ capabilities have been set with setCapabilities().
+
+ \sa type(), setCapabilities()
+*/
+void QNetworkProxy::setType(QNetworkProxy::ProxyType type)
+{
+ d->type = type;
+ if (!d->capabilitiesSet)
+ d->capabilities = defaultCapabilitiesForType(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;
+ d->capabilitiesSet = true;
+}
+
+/*!
+ \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 network
+ \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.
+
+ \section1 System Proxies
+
+ You can configure a factory to use the system proxy's settings.
+ Call the setUseSystemConfiguration() function with true to enable
+ this behavior, or false to disable it.
+
+ Similarly, you can use a factory to make queries directly to the
+ system proxy by calling its systemProxyForQuery() function.
+
+ \warning Depending on the configuration of the user's system, the
+ use of system proxy features on certain platforms may be subject
+ to limitations. The systemProxyForQuery() documentation contains a
+ list of these limitations for those platforms that are affected.
+*/
+
+/*!
+ 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()
+{
+}
+
+
+/*!
+ \since 4.6
+
+ Enables the use of the platform-specific proxy settings, and only those.
+ See systemProxyForQuery() for more information.
+
+ Internally, this method (when called with \a enable set to true)
+ sets an application-wide proxy factory. For this reason, this method
+ is mutually exclusive with setApplicationProxyFactory(): calling
+ setApplicationProxyFactory() overrides the use of the system-wide proxy,
+ and calling setUseSystemConfiguration() overrides any
+ application proxy or proxy factory that was previously set.
+
+ \note See the systemProxyForQuery() documentation for a list of
+ limitations related to the use of system proxies.
+*/
+void QNetworkProxyFactory::setUseSystemConfiguration(bool enable)
+{
+ if (enable) {
+ setApplicationProxyFactory(new QSystemConfigurationProxyFactory);
+ } else {
+ setApplicationProxyFactory(0);
+ }
+}
+
+/*!
+ 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.
+
+ \list
+ \o On MacOS X, this function will ignore the Proxy Auto Configuration
+ settings, since it cannot execute the associated ECMAScript code.
+
+ \o On Windows platforms, this function may take several seconds to
+ execute depending on the configuration of the user's system.
+ \endlist
+*/
+
+/*!
+ 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);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_NETWORKPROXY
diff --git a/src/network/kernel/qnetworkproxy.h b/src/network/kernel/qnetworkproxy.h
new file mode 100644
index 0000000000..26562d533f
--- /dev/null
+++ b/src/network/kernel/qnetworkproxy.h
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@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 setUseSystemConfiguration(bool enable);
+ 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 0000000000..1591d855c6
--- /dev/null
+++ b/src/network/kernel/qnetworkproxy_generic.cpp
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@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 0000000000..6fe35ae9f0
--- /dev/null
+++ b/src/network/kernel/qnetworkproxy_mac.cpp
@@ -0,0 +1,242 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@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())) {
+ CFRelease(dict);
+ 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);
+
+ // ### TODO: Use PAC somehow
+ }
+ }
+
+ // 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;
+ }
+
+ CFRelease(dict);
+ 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_p.h b/src/network/kernel/qnetworkproxy_p.h
new file mode 100644
index 0000000000..21d2cb0ed5
--- /dev/null
+++ b/src/network/kernel/qnetworkproxy_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 David Faure <dfaure@kdab.net>
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QNETWORKPROXY_P_H
+#define QNETWORKPROXY_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.
+//
+
+#ifndef QT_NO_NETWORKPROXY
+
+QT_BEGIN_NAMESPACE
+
+class QSystemConfigurationProxyFactory : public QNetworkProxyFactory
+{
+public:
+ QSystemConfigurationProxyFactory() : QNetworkProxyFactory() {}
+
+ virtual QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery& query)
+ {
+ QList<QNetworkProxy> proxies = QNetworkProxyFactory::systemProxyForQuery(query);
+
+ // Make sure NoProxy is in the list, so that QTcpServer can work:
+ // it searches for the first proxy that can has the ListeningCapability capability
+ // if none have (as is the case with HTTP proxies), it fails to bind.
+ // NoProxy allows it to fallback to the 'no proxy' case and bind.
+ proxies.append(QNetworkProxy::NoProxy);
+
+ return proxies;
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_NETWORKINTERFACE
+
+#endif
+
diff --git a/src/network/kernel/qnetworkproxy_symbian.cpp b/src/network/kernel/qnetworkproxy_symbian.cpp
new file mode 100644
index 0000000000..79dfb27396
--- /dev/null
+++ b/src/network/kernel/qnetworkproxy_symbian.cpp
@@ -0,0 +1,267 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the FOO 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/**
+ * Some notes about the code:
+ *
+ * ** It is assumed that the system proxies are for url based requests
+ * ie. HTTP/HTTPS based.
+ * ** It is assumed that proxies don't use authentication.
+ * ** It is assumed that there is no exceptions to proxy use (Symbian side
+ * does have the field for it but it is not user modifiable by default).
+ * ** There is no checking for protocol name.
+ */
+
+#include <QtNetwork/qnetworkproxy.h>
+
+#ifndef QT_NO_NETWORKPROXY
+
+#include <metadatabase.h> // CMDBSession
+#include <commsdattypeinfov1_1.h> // CCDIAPRecord, CCDProxiesRecord
+#include <commsdattypesv1_1.h> // KCDTIdIAPRecord, KCDTIdProxiesRecord
+#include <QtNetwork/QNetworkConfigurationManager>
+#include <QFlags>
+
+using namespace CommsDat;
+
+QT_BEGIN_NAMESPACE
+
+class SymbianIapId
+{
+public:
+ enum State{
+ NotValid,
+ Valid
+ };
+ Q_DECLARE_FLAGS(States, State)
+ SymbianIapId() {}
+ ~SymbianIapId() {}
+ void setIapId(TUint32 iapId) { iapState |= Valid; id = iapId; }
+ bool isValid() { return iapState == Valid; }
+ TUint32 iapId() { return id; }
+private:
+ QFlags<States> iapState;
+ TUint32 id;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(SymbianIapId::States)
+
+class SymbianProxyQuery
+{
+public:
+ static QNetworkConfiguration findCurrentConfiguration(QNetworkConfigurationManager& configurationManager);
+ static SymbianIapId getIapId(QNetworkConfigurationManager& configurationManager);
+ static CCDIAPRecord *getIapRecordLC(TUint32 aIAPId, CMDBSession &aDb);
+ static CMDBRecordSet<CCDProxiesRecord> *prepareQueryLC(TUint32 serviceId, TDesC& serviceType);
+ static QList<QNetworkProxy> proxyQueryL(TUint32 aIAPId, const QNetworkProxyQuery &query);
+};
+
+QNetworkConfiguration SymbianProxyQuery::findCurrentConfiguration(QNetworkConfigurationManager& configurationManager)
+{
+ QList<QNetworkConfiguration> activeConfigurations = configurationManager.allConfigurations(
+ QNetworkConfiguration::Active);
+ QNetworkConfiguration currentConfig;
+ if (activeConfigurations.count() > 0) {
+ currentConfig = activeConfigurations.at(0);
+ } else {
+ // No active configurations, try default one
+ QNetworkConfiguration defaultConfiguration = configurationManager.defaultConfiguration();
+ if (defaultConfiguration.isValid()) {
+ switch (defaultConfiguration.type()) {
+ case QNetworkConfiguration::InternetAccessPoint:
+ currentConfig = defaultConfiguration;
+ break;
+ case QNetworkConfiguration::ServiceNetwork:
+ {
+ // Note: This code assumes that the only unambigious way to
+ // find current proxy config is if there is only one access point
+ // or if the found access point is immediately usable.
+ QList<QNetworkConfiguration> childConfigurations = defaultConfiguration.children();
+ if (childConfigurations.count() == 1) {
+ currentConfig = childConfigurations.at(0);
+ } else {
+ for (int index = 0; index < childConfigurations.count(); index++) {
+ QNetworkConfiguration childConfig = childConfigurations.at(index);
+ if (childConfig.isValid() && childConfig.state() == QNetworkConfiguration::Discovered) {
+ currentConfig = childConfig;
+ break;
+ }
+ }
+ }
+ }
+ break;
+ case QNetworkConfiguration::UserChoice:
+ // User choice is not a valid configuration for proxy discovery
+ break;
+ }
+ }
+ }
+ return currentConfig;
+}
+
+SymbianIapId SymbianProxyQuery::getIapId(QNetworkConfigurationManager& configurationManager)
+{
+ SymbianIapId iapId;
+
+ QNetworkConfiguration currentConfig = findCurrentConfiguration(configurationManager);
+ if (currentConfig.isValid()) {
+ // Note: the following code assumes that the identifier is in format
+ // I_xxxx where xxxx is the identifier of IAP. This is meant as a
+ // temporary solution until there is a support for returning
+ // implementation specific identifier.
+ const int generalPartLength = 2;
+ const int identifierNumberLength = currentConfig.identifier().length() - generalPartLength;
+ QString idString(currentConfig.identifier().right(identifierNumberLength));
+ bool success;
+ uint id = idString.toUInt(&success);
+ if (success)
+ iapId.setIapId(id);
+ else
+ qWarning() << "Failed to convert identifier to access point identifier: "
+ << currentConfig.identifier();
+ }
+
+ return iapId;
+}
+
+CCDIAPRecord *SymbianProxyQuery::getIapRecordLC(TUint32 aIAPId, CMDBSession &aDb)
+{
+ CCDIAPRecord *iap = static_cast<CCDIAPRecord*> (CCDRecordBase::RecordFactoryL(KCDTIdIAPRecord));
+ CleanupStack::PushL(iap);
+ iap->SetRecordId(aIAPId);
+ iap->LoadL(aDb);
+ return iap;
+}
+
+CMDBRecordSet<CCDProxiesRecord> *SymbianProxyQuery::prepareQueryLC(TUint32 serviceId, TDesC& serviceType)
+{
+ // Create a recordset of type CCDProxiesRecord
+ // for priming search.
+ // This will ultimately contain record(s)
+ // matching the priming record attributes
+ CMDBRecordSet<CCDProxiesRecord> *proxyRecords = new (ELeave) CMDBRecordSet<CCDProxiesRecord> (
+ KCDTIdProxiesRecord);
+ CleanupStack::PushL(proxyRecords);
+
+ CCDProxiesRecord *primingProxyRecord =
+ static_cast<CCDProxiesRecord *> (CCDRecordBase::RecordFactoryL(KCDTIdProxiesRecord));
+ CleanupStack::PushL(primingProxyRecord);
+
+ primingProxyRecord->iServiceType.SetMaxLengthL(serviceType.Length());
+ primingProxyRecord->iServiceType = serviceType;
+ primingProxyRecord->iService = serviceId;
+ primingProxyRecord->iUseProxyServer = ETrue;
+
+ proxyRecords->iRecords.AppendL(primingProxyRecord);
+ // Ownership of primingProxyRecord is transferred to
+ // proxyRecords, just remove it from the CleanupStack
+ CleanupStack::Pop(primingProxyRecord);
+ return proxyRecords;
+}
+
+QList<QNetworkProxy> SymbianProxyQuery::proxyQueryL(TUint32 aIAPId, const QNetworkProxyQuery &query)
+{
+ QList<QNetworkProxy> foundProxies;
+ if (query.queryType() != QNetworkProxyQuery::UrlRequest) {
+ return foundProxies;
+ }
+
+ CMDBSession *iDb = CMDBSession::NewLC(KCDVersion1_1);
+ CCDIAPRecord *iap = getIapRecordLC(aIAPId, *iDb);
+
+ // Read service table id and service type
+ // from the IAP record found
+ TUint32 serviceId = iap->iService;
+ RBuf serviceType;
+ serviceType.CreateL(iap->iServiceType);
+ CleanupStack::PopAndDestroy(iap);
+ CleanupClosePushL(serviceType);
+
+ CMDBRecordSet<CCDProxiesRecord> *proxyRecords = prepareQueryLC(serviceId, serviceType);
+
+ // Now to find a proxy table matching our criteria
+ if (proxyRecords->FindL(*iDb)) {
+ TInt count = proxyRecords->iRecords.Count();
+ for(TInt index = 0; index < count; index++) {
+ CCDProxiesRecord *proxyRecord = static_cast<CCDProxiesRecord *> (proxyRecords->iRecords[index]);
+ RBuf serverName;
+ serverName.CreateL(proxyRecord->iServerName);
+ CleanupClosePushL(serverName);
+ if (serverName.Length() == 0)
+ User::Leave(KErrNotFound);
+ QString serverNameQt((const QChar*)serverName.Ptr(), serverName.Length());
+ CleanupStack::Pop(); // serverName
+ TUint32 port = proxyRecord->iPortNumber;
+
+ QNetworkProxy proxy(QNetworkProxy::HttpProxy, serverNameQt, port);
+ foundProxies.append(proxy);
+ }
+ }
+
+ CleanupStack::PopAndDestroy(proxyRecords);
+ CleanupStack::Pop(); // serviceType
+ CleanupStack::PopAndDestroy(iDb);
+
+ return foundProxies;
+}
+
+QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkProxyQuery &query)
+{
+ QList<QNetworkProxy> proxies;
+ SymbianIapId iapId;
+ TInt error;
+ QNetworkConfigurationManager manager;
+ iapId = SymbianProxyQuery::getIapId(manager);
+ if (iapId.isValid()) {
+ TRAP(error, proxies = SymbianProxyQuery::proxyQueryL(iapId.iapId(), query))
+ if (error != KErrNone) {
+ qWarning() << "Error while retrieving proxies: '" << error << '"';
+ proxies.clear();
+ }
+ }
+ proxies << QNetworkProxy::NoProxy;
+
+ return proxies;
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/network/kernel/qnetworkproxy_win.cpp b/src/network/kernel/qnetworkproxy_win.cpp
new file mode 100644
index 0000000000..3e374037db
--- /dev/null
+++ b/src/network/kernel/qnetworkproxy_win.cpp
@@ -0,0 +1,443 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qnetworkproxy.h"
+
+#ifndef QT_NO_NETWORKPROXY
+
+#include <qmutex.h>
+#include <qstringlist.h>
+#include <qregexp.h>
+#include <qurl.h>
+
+#include <string.h>
+#include <qt_windows.h>
+#include <wininet.h>
+#include <private/qsystemlibrary_p.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
+
+#define WINHTTP_ERROR_BASE 12000
+#define ERROR_WINHTTP_LOGIN_FAILURE (WINHTTP_ERROR_BASE + 15)
+#define ERROR_WINHTTP_AUTODETECTION_FAILED (WINHTTP_ERROR_BASE + 180)
+
+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;
+
+#ifdef Q_OS_WINCE
+ // Windows CE does not have any of the following API
+ return;
+#else
+ // load the winhttp.dll library
+ QSystemLibrary lib(L"winhttp");
+ if (!lib.load())
+ return; // failed to load
+
+ ptrWinHttpOpen = (PtrWinHttpOpen)lib.resolve("WinHttpOpen");
+ ptrWinHttpCloseHandle = (PtrWinHttpCloseHandle)lib.resolve("WinHttpCloseHandle");
+ ptrWinHttpGetProxyForUrl = (PtrWinHttpGetProxyForUrl)lib.resolve("WinHttpGetProxyForUrl");
+ ptrWinHttpGetDefaultProxyConfiguration = (PtrWinHttpGetDefaultProxyConfiguration)lib.resolve("WinHttpGetDefaultProxyConfiguration");
+ ptrWinHttpGetIEProxyConfigForCurrentUser = (PtrWinHttpGetIEProxyConfigForCurrentUser)lib.resolve("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) {
+ // http://msdn.microsoft.com/en-us/library/aa384250%28VS.85%29.aspx speaks only about a "proxy URL",
+ // not multiple URLs. However we tested this and it can return multiple URLs. So we use splitSpaceSemicolon
+ // on it.
+ proxyServerList = splitSpaceSemicolon(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 = false;
+ 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
+ QUrl url = query.url();
+ // url could be empty, e.g. from QNetworkProxy::applicationProxy(), that's fine,
+ // we'll still ask for the proxy.
+ // But for a file url, we know we don't need one.
+ if (url.scheme() == QLatin1String("file") || url.scheme() == QLatin1String("qrc"))
+ return sp->defaultResult;
+ if (query.queryType() != QNetworkProxyQuery::UrlRequest) {
+ // change the scheme to https, maybe it'll work
+ url.setScheme(QLatin1String("https"));
+ }
+
+ bool getProxySucceeded = ptrWinHttpGetProxyForUrl(sp->hHttpSession,
+ (LPCWSTR)url.toString().utf16(),
+ &sp->autoProxyOptions,
+ &proxyInfo);
+ DWORD getProxyError = GetLastError();
+
+ if (!getProxySucceeded
+ && (ERROR_WINHTTP_LOGIN_FAILURE == getProxyError)) {
+ // We first tried without AutoLogon, because this might prevent caching the result.
+ // But now we've to enable it (http://msdn.microsoft.com/en-us/library/aa383153%28v=VS.85%29.aspx)
+ sp->autoProxyOptions.fAutoLogonIfChallenged = TRUE;
+ getProxySucceeded = ptrWinHttpGetProxyForUrl(sp->hHttpSession,
+ (LPCWSTR)url.toString().utf16(),
+ &sp->autoProxyOptions,
+ &proxyInfo);
+ getProxyError = GetLastError();
+ }
+
+ if (getProxySucceeded) {
+ // 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
+
+ if (ERROR_WINHTTP_AUTODETECTION_FAILED == getProxyError) {
+ //No config file could be retrieved on the network.
+ //Don't search for it next time again.
+ sp->isAutoConfig = false;
+ }
+
+ return sp->defaultResult;
+ }
+
+ // static configuration
+ if (isBypassed(query.peerHostName(), sp->proxyBypass))
+ return sp->defaultResult;
+
+ QList<QNetworkProxy> result = parseServerList(query, sp->proxyServerList);
+ // In some cases, this was empty. See SF task 00062670
+ if (result.isEmpty())
+ return sp->defaultResult;
+
+ return result;
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/network/kernel/qurlinfo.cpp b/src/network/kernel/qurlinfo.cpp
new file mode 100644
index 0000000000..cff4912904
--- /dev/null
+++ b/src/network/kernel/qurlinfo.cpp
@@ -0,0 +1,731 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@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 network
+
+ 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://qt.nokia.com/doc/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;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_URLINFO
diff --git a/src/network/kernel/qurlinfo.h b/src/network/kernel/qurlinfo.h
new file mode 100644
index 0000000000..d40bf0c44d
--- /dev/null
+++ b/src/network/kernel/qurlinfo.h
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@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