diff options
Diffstat (limited to 'src/network')
35 files changed, 2482 insertions, 1028 deletions
diff --git a/src/network/access/qftp.cpp b/src/network/access/qftp.cpp index ccc20e6..45fc11f 100644 --- a/src/network/access/qftp.cpp +++ b/src/network/access/qftp.cpp @@ -319,6 +319,10 @@ void QFtpDTP::connectToHost(const QString & host, quint16 port) socket = 0; } socket = new QTcpSocket(this); +#ifndef QT_NO_BEARERMANAGEMENT + //copy network session down to the socket + socket->setProperty("_q_networksession", property("_q_networksession")); +#endif socket->setObjectName(QLatin1String("QFtpDTP Passive state socket")); connect(socket, SIGNAL(connected()), SLOT(socketConnected())); connect(socket, SIGNAL(readyRead()), SLOT(socketReadyRead())); @@ -331,6 +335,10 @@ void QFtpDTP::connectToHost(const QString & host, quint16 port) int QFtpDTP::setupListener(const QHostAddress &address) { +#ifndef QT_NO_BEARERMANAGEMENT + //copy network session down to the socket + listener.setProperty("_q_networksession", property("_q_networksession")); +#endif if (!listener.isListening() && !listener.listen(address, 0)) return -1; return listener.serverPort(); @@ -808,6 +816,11 @@ QFtpPI::QFtpPI(QObject *parent) : void QFtpPI::connectToHost(const QString &host, quint16 port) { emit connectState(QFtp::HostLookup); +#ifndef QT_NO_BEARERMANAGEMENT + //copy network session down to the socket & DTP + commandSocket.setProperty("_q_networksession", property("_q_networksession")); + dtp.setProperty("_q_networksession", property("_q_networksession")); +#endif commandSocket.connectToHost(host, port); } @@ -2240,6 +2253,10 @@ void QFtpPrivate::_q_startNextCommand() c->rawCmds.clear(); _q_piFinished(QLatin1String("Proxy set to ") + proxyHost + QLatin1Char(':') + QString::number(proxyPort)); } else if (c->command == QFtp::ConnectToHost) { +#ifndef QT_NO_BEARERMANAGEMENT + //copy network session down to the PI + pi.setProperty("_q_networksession", q->property("_q_networksession")); +#endif if (!proxyHost.isEmpty()) { host = c->rawCmds[0]; port = c->rawCmds[1].toUInt(); diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index 35c3a67..727b014 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -117,9 +117,14 @@ QHttpNetworkConnectionPrivate::~QHttpNetworkConnectionPrivate() void QHttpNetworkConnectionPrivate::init() { + Q_Q(QHttpNetworkConnection); for (int i = 0; i < channelCount; i++) { channels[i].setConnection(this->q_func()); channels[i].ssl = encrypt; +#ifndef QT_NO_BEARERMANAGEMENT + //push session down to channels + channels[i].networkSession = networkSession; +#endif channels[i].init(); } } @@ -825,6 +830,23 @@ void QHttpNetworkConnectionPrivate::readMoreLater(QHttpNetworkReply *reply) } } +#ifndef QT_NO_BEARERMANAGEMENT +QHttpNetworkConnection::QHttpNetworkConnection(const QString &hostName, quint16 port, bool encrypt, QObject *parent, QSharedPointer<QNetworkSession> networkSession) + : QObject(*(new QHttpNetworkConnectionPrivate(hostName, port, encrypt)), parent) +{ + Q_D(QHttpNetworkConnection); + d->networkSession = networkSession; + d->init(); +} + +QHttpNetworkConnection::QHttpNetworkConnection(quint16 connectionCount, const QString &hostName, quint16 port, bool encrypt, QObject *parent, QSharedPointer<QNetworkSession> networkSession) + : QObject(*(new QHttpNetworkConnectionPrivate(connectionCount, hostName, port, encrypt)), parent) +{ + Q_D(QHttpNetworkConnection); + d->networkSession = networkSession; + d->init(); +} +#else QHttpNetworkConnection::QHttpNetworkConnection(const QString &hostName, quint16 port, bool encrypt, QObject *parent) : QObject(*(new QHttpNetworkConnectionPrivate(hostName, port, encrypt)), parent) { @@ -838,6 +860,7 @@ QHttpNetworkConnection::QHttpNetworkConnection(quint16 connectionCount, const QS Q_D(QHttpNetworkConnection); d->init(); } +#endif QHttpNetworkConnection::~QHttpNetworkConnection() { diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h index d4748c1..ad53dec 100644 --- a/src/network/access/qhttpnetworkconnection_p.h +++ b/src/network/access/qhttpnetworkconnection_p.h @@ -55,6 +55,7 @@ #include <QtNetwork/qnetworkrequest.h> #include <QtNetwork/qnetworkreply.h> #include <QtNetwork/qabstractsocket.h> +#include <QtNetwork/qnetworksession.h> #include <private/qobject_p.h> #include <qauthenticator.h> @@ -88,8 +89,13 @@ class Q_AUTOTEST_EXPORT QHttpNetworkConnection : public QObject Q_OBJECT public: +#ifndef QT_NO_BEARERMANAGEMENT + QHttpNetworkConnection(const QString &hostName, quint16 port = 80, bool encrypt = false, QObject *parent = 0, QSharedPointer<QNetworkSession> networkSession = QSharedPointer<QNetworkSession>()); + QHttpNetworkConnection(quint16 channelCount, const QString &hostName, quint16 port = 80, bool encrypt = false, QObject *parent = 0, QSharedPointer<QNetworkSession> networkSession = QSharedPointer<QNetworkSession>()); +#else QHttpNetworkConnection(const QString &hostName, quint16 port = 80, bool encrypt = false, QObject *parent = 0); QHttpNetworkConnection(quint16 channelCount, const QString &hostName, quint16 port = 80, bool encrypt = false, QObject *parent = 0); +#endif ~QHttpNetworkConnection(); //The hostname to which this is connected to. @@ -208,6 +214,10 @@ public: QList<HttpMessagePair> highPriorityQueue; QList<HttpMessagePair> lowPriorityQueue; +#ifndef QT_NO_BEARERMANAGEMENT + QSharedPointer<QNetworkSession> networkSession; +#endif + friend class QHttpNetworkConnectionChannel; }; diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index 60094b0..2292a7f 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -54,6 +54,10 @@ # include <QtNetwork/qsslconfiguration.h> #endif +#ifndef QT_NO_BEARERMANAGEMENT +#include "private/qnetworksession_p.h" +#endif + QT_BEGIN_NAMESPACE // TODO: Put channel specific stuff here so it does not polute qhttpnetworkconnection.cpp @@ -91,6 +95,11 @@ void QHttpNetworkConnectionChannel::init() #else socket = new QTcpSocket; #endif +#ifndef QT_NO_BEARERMANAGEMENT + //push session down to socket + if (networkSession) + socket->setProperty("_q_networksession", QVariant::fromValue(networkSession)); +#endif // Set by QNAM anyway, but let's be safe here socket->setProxy(QNetworkProxy::NoProxy); diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h index 893d75e..f27c6f5 100644 --- a/src/network/access/qhttpnetworkconnectionchannel_p.h +++ b/src/network/access/qhttpnetworkconnectionchannel_p.h @@ -117,6 +117,9 @@ public: bool ignoreAllSslErrors; QList<QSslError> ignoreSslErrorsList; #endif +#ifndef QT_NO_BEARERMANAGEMENT + QSharedPointer<QNetworkSession> networkSession; +#endif // HTTP pipelining -> http://en.wikipedia.org/wiki/Http_pipelining enum PipeliningSupport { diff --git a/src/network/access/qhttpnetworkrequest.cpp b/src/network/access/qhttpnetworkrequest.cpp index 8573364..2c67e87 100644 --- a/src/network/access/qhttpnetworkrequest.cpp +++ b/src/network/access/qhttpnetworkrequest.cpp @@ -158,8 +158,10 @@ QByteArray QHttpNetworkRequestPrivate::header(const QHttpNetworkRequest &request } if (request.d->operation == QHttpNetworkRequest::Post) { // add content type, if not set in the request - if (request.headerField("content-type").isEmpty()) - ba += "Content-Type: application/x-www-form-urlencoded\r\n"; + if (request.headerField("content-type").isEmpty()) { + qWarning("content-type missing in HTTP POST, defaulting to application/octet-stream"); + ba += "Content-Type: application/octet-stream\r\n"; + } if (!request.d->uploadByteDevice && request.d->url.hasQuery()) { QByteArray query = request.d->url.encodedQuery(); ba += "Content-Length: "; diff --git a/src/network/access/qnetworkaccessbackend.cpp b/src/network/access/qnetworkaccessbackend.cpp index 5aedac9..8f5a3da 100644 --- a/src/network/access/qnetworkaccessbackend.cpp +++ b/src/network/access/qnetworkaccessbackend.cpp @@ -46,7 +46,7 @@ #include "qnetworkreply_p.h" #include "QtCore/qhash.h" #include "QtCore/qmutex.h" -#include "QtNetwork/qnetworksession.h" +#include "QtNetwork/private/qnetworksession_p.h" #include "qnetworkaccesscachebackend_p.h" #include "qabstractnetworkcache.h" @@ -96,6 +96,11 @@ QNetworkAccessBackend *QNetworkAccessManagerPrivate::findBackend(QNetworkAccessM QNetworkAccessBackend *backend = (*it)->create(op, request); if (backend) { backend->manager = this; +#ifndef QT_NO_BEARERMANAGEMENT + //copy network session down to the backend + if (networkSession) + backend->setProperty("_q_networksession", QVariant::fromValue(networkSession)); +#endif return backend; // found a factory that handled our request } ++it; diff --git a/src/network/access/qnetworkaccessftpbackend.cpp b/src/network/access/qnetworkaccessftpbackend.cpp index e34e6bb..3ad1961 100644 --- a/src/network/access/qnetworkaccessftpbackend.cpp +++ b/src/network/access/qnetworkaccessftpbackend.cpp @@ -153,6 +153,10 @@ void QNetworkAccessFtpBackend::open() if (!objectCache->requestEntry(cacheKey, this, SLOT(ftpConnectionReady(QNetworkAccessCache::CacheableObject*)))) { ftp = new QNetworkAccessCachedFtpConnection; +#ifndef QT_NO_BEARERMANAGEMENT + //copy network session down to the QFtp + ftp->setProperty("_q_networksession", property("_q_networksession")); +#endif #ifndef QT_NO_NETWORKPROXY if (proxy.type() == QNetworkProxy::FtpCachingProxy) ftp->setProxy(proxy.hostName(), proxy.port()); diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 7e75045..7a4a894 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -1125,8 +1125,25 @@ void QNetworkAccessManagerPrivate::createSession(const QNetworkConfiguration &co initializeSession = false; - if (!config.isValid()) { - networkSession.clear(); + QSharedPointer<QNetworkSession> newSession; + if (config.isValid()) + newSession = QSharedNetworkSessionManager::getSession(config); + + if (networkSession) { + //do nothing if new and old session are the same + if (networkSession == newSession) + return; + //disconnect from old session + QObject::disconnect(networkSession.data(), SIGNAL(opened()), q, SIGNAL(networkSessionConnected())); + QObject::disconnect(networkSession.data(), SIGNAL(closed()), q, SLOT(_q_networkSessionClosed())); + QObject::disconnect(networkSession.data(), SIGNAL(stateChanged(QNetworkSession::State)), + q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State))); + } + + //switch to new session (null if config was invalid) + networkSession = newSession; + + if (!networkSession) { online = false; if (networkAccessible == QNetworkAccessManager::NotAccessible) @@ -1137,8 +1154,7 @@ void QNetworkAccessManagerPrivate::createSession(const QNetworkConfiguration &co return; } - networkSession = QSharedNetworkSessionManager::getSession(config); - + //connect to new session QObject::connect(networkSession.data(), SIGNAL(opened()), q, SIGNAL(networkSessionConnected()), Qt::QueuedConnection); //QueuedConnection is used to avoid deleting the networkSession inside its closed signal QObject::connect(networkSession.data(), SIGNAL(closed()), q, SLOT(_q_networkSessionClosed()), Qt::QueuedConnection); @@ -1150,9 +1166,15 @@ void QNetworkAccessManagerPrivate::createSession(const QNetworkConfiguration &co void QNetworkAccessManagerPrivate::_q_networkSessionClosed() { + Q_Q(QNetworkAccessManager); if (networkSession) { networkConfiguration = networkSession->configuration().identifier(); + //disconnect from old session + QObject::disconnect(networkSession.data(), SIGNAL(opened()), q, SIGNAL(networkSessionConnected())); + QObject::disconnect(networkSession.data(), SIGNAL(closed()), q, SLOT(_q_networkSessionClosed())); + QObject::disconnect(networkSession.data(), SIGNAL(stateChanged(QNetworkSession::State)), + q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State))); networkSession.clear(); } } @@ -1161,8 +1183,12 @@ void QNetworkAccessManagerPrivate::_q_networkSessionStateChanged(QNetworkSession { Q_Q(QNetworkAccessManager); - if (state == QNetworkSession::Connected) + //Do not emit the networkSessionConnected signal here, except for roaming -> connected + //transition, otherwise it is emitted twice in a row when opening a connection. + if (state == QNetworkSession::Connected && lastSessionState == QNetworkSession::Roaming) emit q->networkSessionConnected(); + lastSessionState = state; + if (online) { if (state != QNetworkSession::Connected && state != QNetworkSession::Roaming) { online = false; diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h index ee6ad70..e0817ca 100644 --- a/src/network/access/qnetworkaccessmanager_p.h +++ b/src/network/access/qnetworkaccessmanager_p.h @@ -79,6 +79,7 @@ public: #endif #ifndef QT_NO_BEARERMANAGEMENT networkSession(0), + lastSessionState(QNetworkSession::Invalid), networkAccessible(QNetworkAccessManager::Accessible), online(false), initializeSession(true), @@ -134,6 +135,7 @@ public: #ifndef QT_NO_BEARERMANAGEMENT QSharedPointer<QNetworkSession> networkSession; + QNetworkSession::State lastSessionState; QString networkConfiguration; QNetworkAccessManager::NetworkAccessibility networkAccessible; bool online; diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp index 485f449..f5d2772 100644 --- a/src/network/access/qnetworkreplyimpl.cpp +++ b/src/network/access/qnetworkreplyimpl.cpp @@ -74,7 +74,7 @@ inline QNetworkReplyImplPrivate::QNetworkReplyImplPrivate() void QNetworkReplyImplPrivate::_q_startOperation() { // ensure this function is only being called once - if (state == Working) { + if (state == Working || state == Finished) { qDebug("QNetworkReplyImpl::_q_startOperation was called more than once"); return; } diff --git a/src/network/bearer/qnetworksession.cpp b/src/network/bearer/qnetworksession.cpp index af60a43..6106550 100644 --- a/src/network/bearer/qnetworksession.cpp +++ b/src/network/bearer/qnetworksession.cpp @@ -705,6 +705,15 @@ void QNetworkSession::disconnectNotify(const char *signal) d->setALREnabled(false); } +#ifdef Q_OS_SYMBIAN +RConnection* QNetworkSessionPrivate::nativeSession(QNetworkSession &s) +{ + if (!s.d) + return 0; + return s.d->nativeSession(); +} +#endif + #include "moc_qnetworksession.cpp" QT_END_NAMESPACE diff --git a/src/network/bearer/qnetworksession.h b/src/network/bearer/qnetworksession.h index 688f37e..c08a9bf 100644 --- a/src/network/bearer/qnetworksession.h +++ b/src/network/bearer/qnetworksession.h @@ -140,6 +140,9 @@ private: QNetworkSessionPrivate *d; }; +Q_DECLARE_METATYPE(QNetworkSession::State); +Q_DECLARE_METATYPE(QNetworkSession::SessionError); + #ifndef QT_MOBILITY_BEARER QT_END_NAMESPACE Q_DECLARE_METATYPE(QNetworkSession::State) diff --git a/src/network/bearer/qnetworksession_p.h b/src/network/bearer/qnetworksession_p.h index 707ad37..e2fcfe6 100644 --- a/src/network/bearer/qnetworksession_p.h +++ b/src/network/bearer/qnetworksession_p.h @@ -55,9 +55,14 @@ #include "qnetworksession.h" #include "qnetworkconfiguration_p.h" +#include "QtCore/qsharedpointer.h" #ifndef QT_NO_BEARERMANAGEMENT +#ifdef Q_OS_SYMBIAN +class RConnection; +#endif + QT_BEGIN_NAMESPACE class Q_NETWORK_EXPORT QNetworkSessionPrivate : public QObject @@ -102,6 +107,10 @@ public: virtual quint64 bytesReceived() const = 0; virtual quint64 activeTime() const = 0; +#ifdef Q_OS_SYMBIAN + static RConnection* nativeSession(QNetworkSession&); + virtual RConnection* nativeSession() = 0; +#endif protected: inline QNetworkConfigurationPrivatePointer privateConfiguration(const QNetworkConfiguration &config) const { @@ -145,6 +154,8 @@ protected: QT_END_NAMESPACE +Q_DECLARE_METATYPE(QSharedPointer<QNetworkSession>) + #endif // QT_NO_BEARERMANAGEMENT #endif // QNETWORKSESSIONPRIVATE_H diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri index 66e87c9..107ac69 100644 --- a/src/network/kernel/kernel.pri +++ b/src/network/kernel/kernel.pri @@ -20,7 +20,7 @@ SOURCES += kernel/qauthenticator.cpp \ kernel/qnetworkproxy.cpp \ kernel/qnetworkinterface.cpp -symbian: SOURCES += kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_symbian.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 diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp new file mode 100644 index 0000000..9599274 --- /dev/null +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -0,0 +1,204 @@ +/**************************************************************************** +** +** 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 + +// Symbian Headers +#include <es_sock.h> +#include <in_sock.h> + +// Qt Headers +#include <QByteArray> +#include <QUrl> +#include <QList> + +#include "qplatformdefs.h" + +#include "qhostinfo_p.h" +#include <private/qcore_symbian_p.h> + +QT_BEGIN_NAMESPACE + + +QHostInfo QHostInfoAgent::fromName(const QString &hostName) +{ + QHostInfo results; + + // Connect to ESOCK + RSocketServ socketServ(qt_symbianGetSocketServer()); + RHostResolver hostResolver; + + // Will return both IPv4 and IPv6 + // TODO: Pass RHostResolver.Open() the global RConnection + int err = hostResolver.Open(socketServ, KAfInet, KProtocolInetUdp); + if (err) { + results.setError(QHostInfo::UnknownError); + results.setErrorString(tr("Symbian error code: %1").arg(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 + + TInetAddr IpAdd; + IpAdd.Input(qt_QString2TPtrC(hostName)); + + // Synchronous request. nameResult returns Host Name. + hostResolver.GetByAddress(IpAdd, nameResult); + if (err) { + // TODO - Could there be other errors? Symbian docs don't say. + if (err = KErrNotFound) { + results.setError(QHostInfo::HostNotFound); + results.setErrorString(tr("Host not found")); + } else { + results.setError(QHostInfo::UnknownError); + results.setErrorString(tr("Symbian error code: %1").arg(err)); + } + + return results; + } + + 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) { + // TODO - Could there be other errors? Symbian docs don't say. + if (err = KErrNotFound) { + results.setError(QHostInfo::HostNotFound); + results.setErrorString(tr("Host not found")); + } else { + results.setError(QHostInfo::UnknownError); + results.setErrorString(tr("Symbian error code: %1").arg(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); + + if (ipAddr.Length() > 0) { + if (nameResult().iAddr.Family() == KAfInet) { + // IPv4 - prepend + hostAddresses.prepend(QHostAddress(qt_TDesC2QString(ipAddr))); + } else { + // IPv6 - append + hostAddresses.append(QHostAddress(qt_TDesC2QString(ipAddr))); + } + } + } + + hostResolver.Close(); + + results.setAddresses(hostAddresses); + return results; +} + +QString QHostInfo::localHostName() +{ + // Connect to ESOCK + RSocketServ socketServ(qt_symbianGetSocketServer()); + RHostResolver hostResolver; + + // Will return both IPv4 and IPv6 + // TODO: Pass RHostResolver.Open() the global RConnection + 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() +{ + // TODO - fill with code. + return QString(); +} + +QT_END_NAMESPACE diff --git a/src/network/kernel/qhostinfo_unix.cpp b/src/network/kernel/qhostinfo_unix.cpp index 22f6e0d..8fc6bf6 100644 --- a/src/network/kernel/qhostinfo_unix.cpp +++ b/src/network/kernel/qhostinfo_unix.cpp @@ -147,7 +147,7 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) 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) && !defined (Q_OS_SYMBIAN) +#if !defined (QT_NO_GETADDRINFO) && !defined (Q_OS_DARWIN) sockaddr_in sa4; #ifndef QT_NO_IPV6 sockaddr_in6 sa6; @@ -208,23 +208,12 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) #ifdef Q_ADDRCONFIG hints.ai_flags = Q_ADDRCONFIG; #endif -#ifdef Q_OS_SYMBIAN -# ifdef QHOSTINFO_DEBUG - qDebug() << "Setting flags: 'hints.ai_flags &= AI_V4MAPPED | AI_ALL'"; -# endif -#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; -#ifdef Q_OS_SYMBIAN -# ifdef QHOSTINFO_DEBUG - qDebug() << "Setting flags: 'hints.ai_flags &= AI_V4MAPPED | AI_ALL'"; -# endif - hints.ai_flags &= AI_V4MAPPED | AI_ALL; -#endif result = getaddrinfo(aceHostname.constData(), 0, &hints, &res); } # endif diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index 2a942cc..020de42 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -375,6 +375,7 @@ #include <qpointer.h> #include <qtimer.h> #include <qelapsedtimer.h> +#include <qscopedvaluerollback.h> #ifndef QT_NO_OPENSSL #include <QtNetwork/qsslsocket.h> @@ -545,6 +546,10 @@ bool QAbstractSocketPrivate::initSocketLayer(QAbstractSocket::NetworkLayerProtoc resetSocketLayer(); socketEngine = QAbstractSocketEngine::createSocketEngine(q->socketType(), proxyInUse, q); +#ifndef QT_NO_BEARERMANAGEMENT + //copy network session down to the socket engine (if it has been set) + socketEngine->setProperty("_q_networksession", q->property("_q_networksession")); +#endif if (!socketEngine) { socketError = QAbstractSocket::UnsupportedSocketOperationError; q->setErrorString(QAbstractSocket::tr("Operation on socket is not supported")); @@ -592,6 +597,7 @@ bool QAbstractSocketPrivate::canReadNotification() socketEngine->setReadNotificationEnabled(false); } } + QScopedValueRollback<bool> rsncrollback(readSocketNotifierCalled); readSocketNotifierCalled = true; if (!isBuffered) @@ -605,7 +611,6 @@ bool QAbstractSocketPrivate::canReadNotification() #if defined (QABSTRACTSOCKET_DEBUG) qDebug("QAbstractSocketPrivate::canReadNotification() buffer is full"); #endif - readSocketNotifierCalled = false; return false; } @@ -617,7 +622,6 @@ bool QAbstractSocketPrivate::canReadNotification() qDebug("QAbstractSocketPrivate::canReadNotification() disconnecting socket"); #endif q->disconnectFromHost(); - readSocketNotifierCalled = false; return false; } newBytes = readBuffer.size() - newBytes; @@ -637,9 +641,9 @@ bool QAbstractSocketPrivate::canReadNotification() ; if (!emittedReadyRead && hasData) { + QScopedValueRollback<bool> r(emittedReadyRead); emittedReadyRead = true; emit q->readyRead(); - emittedReadyRead = false; } // If we were closed as a result of the readyRead() signal, @@ -648,7 +652,6 @@ bool QAbstractSocketPrivate::canReadNotification() #if defined (QABSTRACTSOCKET_DEBUG) qDebug("QAbstractSocketPrivate::canReadNotification() socket is closing - returning"); #endif - readSocketNotifierCalled = false; return true; } @@ -662,7 +665,6 @@ bool QAbstractSocketPrivate::canReadNotification() socketEngine->setReadNotificationEnabled(readSocketNotifierState); readSocketNotifierStateSet = false; } - readSocketNotifierCalled = false; return true; } @@ -768,9 +770,9 @@ bool QAbstractSocketPrivate::flush() if (written > 0) { // Don't emit bytesWritten() recursively. if (!emittedBytesWritten) { + QScopedValueRollback<bool> r(emittedBytesWritten); emittedBytesWritten = true; emit q->bytesWritten(written); - emittedBytesWritten = false; } } @@ -1602,6 +1604,10 @@ bool QAbstractSocket::setSocketDescriptor(int socketDescriptor, SocketState sock d->resetSocketLayer(); d->socketEngine = QAbstractSocketEngine::createSocketEngine(socketDescriptor, this); +#ifndef QT_NO_BEARERMANAGEMENT + //copy network session down to the socket engine (if it has been set) + d->socketEngine->setProperty("_q_networksession", property("_q_networksession")); +#endif if (!d->socketEngine) { d->socketError = UnsupportedSocketOperationError; setErrorString(tr("Operation on socket is not supported")); diff --git a/src/network/socket/qabstractsocket_p.h b/src/network/socket/qabstractsocket_p.h index 7e6343e..7662f47 100644 --- a/src/network/socket/qabstractsocket_p.h +++ b/src/network/socket/qabstractsocket_p.h @@ -59,7 +59,7 @@ #include "QtCore/qtimer.h" #include "private/qringbuffer_p.h" #include "private/qiodevice_p.h" -#include "private/qnativesocketengine_p.h" +#include "private/qabstractsocketengine_p.h" #include "qnetworkproxy.h" QT_BEGIN_NAMESPACE diff --git a/src/network/socket/qabstractsocketengine.cpp b/src/network/socket/qabstractsocketengine.cpp index 9fe6959..c29f936 100644 --- a/src/network/socket/qabstractsocketengine.cpp +++ b/src/network/socket/qabstractsocketengine.cpp @@ -40,7 +40,13 @@ ****************************************************************************/ #include "qabstractsocketengine_p.h" + +#ifdef Q_OS_SYMBIAN +#include "qsymbiansocketengine_p.h" +#else #include "qnativesocketengine_p.h" +#endif + #include "qmutex.h" #include "qnetworkproxy.h" @@ -113,7 +119,11 @@ QAbstractSocketEngine *QAbstractSocketEngine::createSocketEngine(QAbstractSocket return 0; #endif +#ifdef Q_OS_SYMBIAN + return new QSymbianSocketEngine(parent); +#else return new QNativeSocketEngine(parent); +#endif } QAbstractSocketEngine *QAbstractSocketEngine::createSocketEngine(int socketDescripter, QObject *parent) @@ -123,7 +133,11 @@ QAbstractSocketEngine *QAbstractSocketEngine::createSocketEngine(int socketDescr if (QAbstractSocketEngine *ret = socketHandlers()->at(i)->createSocketEngine(socketDescripter, parent)) return ret; } +#ifdef Q_OS_SYMBIAN + return new QSymbianSocketEngine(parent); +#else return new QNativeSocketEngine(parent); +#endif } QAbstractSocket::SocketError QAbstractSocketEngine::error() const diff --git a/src/network/socket/qlocalserver.cpp b/src/network/socket/qlocalserver.cpp index 019759c..46822d7b 100644 --- a/src/network/socket/qlocalserver.cpp +++ b/src/network/socket/qlocalserver.cpp @@ -274,11 +274,11 @@ QLocalSocket *QLocalServer::nextPendingConnection() if (d->pendingConnections.isEmpty()) return 0; QLocalSocket *nextSocket = d->pendingConnections.dequeue(); +#ifndef QT_LOCALSOCKET_TCP #ifdef Q_OS_SYMBIAN if(!d->socketNotifier) return nextSocket; #endif -#ifndef QT_LOCALSOCKET_TCP if (d->pendingConnections.size() <= d->maxPendingConnections) #ifndef Q_OS_WIN d->socketNotifier->setEnabled(true); diff --git a/src/network/socket/qlocalserver_p.h b/src/network/socket/qlocalserver_p.h index fe10959..8ec3ef0 100644 --- a/src/network/socket/qlocalserver_p.h +++ b/src/network/socket/qlocalserver_p.h @@ -65,7 +65,7 @@ # include <qt_windows.h> # include <private/qwineventnotifier_p.h> #else -# include <private/qnativesocketengine_p.h> +# include <qabstractsocketengine_p.h> # include <qsocketnotifier.h> #endif diff --git a/src/network/socket/qlocalsocket.cpp b/src/network/socket/qlocalsocket.cpp index 8fa4b92..6c91d86 100644 --- a/src/network/socket/qlocalsocket.cpp +++ b/src/network/socket/qlocalsocket.cpp @@ -346,7 +346,7 @@ QLocalSocket::QLocalSocket(QObject * parent) QLocalSocket::~QLocalSocket() { close(); -#ifndef Q_OS_WIN +#if !defined (Q_OS_WIN) && !defined (QT_LOCALSOCKET_TCP) Q_D(QLocalSocket); d->unixSocket.setParent(0); #endif diff --git a/src/network/socket/qlocalsocket_p.h b/src/network/socket/qlocalsocket_p.h index b042680..09e50f5 100644 --- a/src/network/socket/qlocalsocket_p.h +++ b/src/network/socket/qlocalsocket_p.h @@ -67,7 +67,7 @@ # include "private/qringbuffer_p.h" # include <private/qwineventnotifier_p.h> #else -# include "private/qnativesocketengine_p.h" +# include "private/qabstractsocketengine_p.h" # include <qtcpsocket.h> # include <qsocketnotifier.h> # include <errno.h> diff --git a/src/network/socket/qnativesocketengine.cpp b/src/network/socket/qnativesocketengine.cpp index 80c8d9a..efa4f6f 100644 --- a/src/network/socket/qnativesocketengine.cpp +++ b/src/network/socket/qnativesocketengine.cpp @@ -110,10 +110,6 @@ # include "qtcpserver.h" #endif -#ifdef Q_OS_SYMBIAN -# include <private/qcore_symbian_p.h> -#endif - QT_BEGIN_NAMESPACE //#define QNATIVESOCKETENGINE_DEBUG @@ -164,9 +160,6 @@ QT_BEGIN_NAMESPACE */ QNativeSocketEnginePrivate::QNativeSocketEnginePrivate() : socketDescriptor(-1), -#ifdef Q_OS_SYMBIAN - socketServer(qt_symbianGetSocketServer()), -#endif readNotifier(0), writeNotifier(0), exceptNotifier(0) @@ -394,7 +387,6 @@ bool QNativeSocketEngine::initialize(QAbstractSocket::SocketType socketType, QAb // Make sure we receive out-of-band data - // On Symbian OS this works only with native IP stack, not with WinSock if (socketType == QAbstractSocket::TcpSocket && !setOption(ReceiveOutOfBandData, 1)) { qWarning("QNativeSocketEngine::initialize unable to inline out-of-band data"); diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h index 643aa72..a186911 100644 --- a/src/network/socket/qnativesocketengine_p.h +++ b/src/network/socket/qnativesocketengine_p.h @@ -60,13 +60,6 @@ # include <winsock2.h> #endif -#ifdef Q_OS_SYMBIAN -#include <private/qeventdispatcher_symbian_p.h> -#include <unistd.h> -#include <es_sock.h> -#include <in_sock.h> -#endif - QT_BEGIN_NAMESPACE // Use our own defines and structs which we know are correct @@ -198,12 +191,6 @@ public: ~QNativeSocketEnginePrivate(); int socketDescriptor; -#ifdef Q_OS_SYMBIAN - mutable RSocket nativeSocket; - RSocketServ& socketServer; - RConnection connection; //TODO: shared ref - mutable RTimer selectTimer; -#endif QSocketNotifier *readNotifier, *writeNotifier, *exceptNotifier; @@ -241,11 +228,6 @@ public: UnknownSocketErrorString = -1 }; -#ifdef Q_OS_SYMBIAN - void getPortAndAddress(const TInetAddr& a, quint16 *port, QHostAddress *addr); - void setPortAndAddress(TInetAddr& nativeAddr, quint16 port, const QHostAddress &addr); - void setError(TInt symbianError); -#endif void setError(QAbstractSocket::SocketError error, ErrorString errorString) const; // native functions diff --git a/src/network/socket/qnativesocketengine_symbian.cpp b/src/network/socket/qnativesocketengine_symbian.cpp deleted file mode 100644 index d1a0819..0000000 --- a/src/network/socket/qnativesocketengine_symbian.cpp +++ /dev/null @@ -1,796 +0,0 @@ -/**************************************************************************** -** -** 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 QNATIVESOCKETENGINE_DEBUG -#include "qnativesocketengine_p.h" -#include "private/qnet_unix_p.h" -#include "qiodevice.h" -#include "qhostaddress.h" -#include "qelapsedtimer.h" -#include "qvarlengtharray.h" -#include "qnetworkinterface.h" -#include <es_sock.h> -#include <in_sock.h> -#include <QtCore/private/qcore_symbian_p.h> -#ifndef QT_NO_IPV6IFNAME -#include <net/if.h> -#endif - -#define QNATIVESOCKETENGINE_DEBUG - -#if defined QNATIVESOCKETENGINE_DEBUG -#include <qstring.h> -#include <ctype.h> -#endif - -QT_BEGIN_NAMESPACE - -#if defined QNATIVESOCKETENGINE_DEBUG - -/* - Returns a human readable representation of the first \a len - characters in \a data. -*/ -static QByteArray qt_prettyDebug(const char *data, int len, int maxSize) -{ - if (!data) return "(null)"; - QByteArray out; - for (int i = 0; i < len; ++i) { - char c = data[i]; - if (isprint(c)) { - out += c; - } else switch (c) { - case '\n': out += "\\n"; break; - case '\r': out += "\\r"; break; - case '\t': out += "\\t"; break; - default: - QString tmp; - tmp.sprintf("\\%o", c); - out += tmp.toLatin1(); - } - } - - if (len < maxSize) - out += "..."; - - return out; -} -#endif - -void QNativeSocketEnginePrivate::getPortAndAddress(const TInetAddr& a, quint16 *port, QHostAddress *addr) -{ -#if !defined(QT_NO_IPV6) - if (a.Family() == KAfInet6) { - Q_IPV6ADDR tmp; - memcpy(&tmp, a.Ip6Address().u.iAddr8, sizeof(tmp)); - if (addr) { - QHostAddress tmpAddress; - tmpAddress.setAddress(tmp); - *addr = tmpAddress; -#ifndef QT_NO_IPV6IFNAME - TPckgBuf<TSoInetIfQuery> query; - query().iSrcAddr = a; - TInt err = nativeSocket.GetOpt(KSoInetIfQueryBySrcAddr, KSolInetIfQuery, query); - if(!err) - addr->setScopeId(qt_TDesC2QString(query().iName)); - else -#endif - addr->setScopeId(QString::number(a.Scope())); - } - if (port) - *port = a.Port(); - return; - } -#endif - if (port) - *port = a.Port(); - if (addr) { - QHostAddress tmpAddress; - tmpAddress.setAddress(a.Address()); - *addr = tmpAddress; - } -} -/*! \internal - - Creates and returns a new socket descriptor of type \a socketType - and \a socketProtocol. Returns -1 on failure. -*/ -bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType, - QAbstractSocket::NetworkLayerProtocol socketProtocol) -{ -#ifndef QT_NO_IPV6 - TUint family = (socketProtocol == QAbstractSocket::IPv6Protocol) ? KAfInet6 : KAfInet; -#else - Q_UNUSED(socketProtocol); - TUint family = KAfInet; -#endif - TUint type = (socketType == QAbstractSocket::UdpSocket) ? KSockDatagram : KSockStream; - TUint protocol = (socketType == QAbstractSocket::UdpSocket) ? KProtocolInetUdp : KProtocolInetTcp; - TInt err = nativeSocket.Open(socketServer, family, type, protocol, connection); - - if (err != KErrNone) { - switch (err) { - case KErrNotSupported: - case KErrNotFound: - setError(QAbstractSocket::UnsupportedSocketOperationError, - ProtocolUnsupportedErrorString); - break; - case KErrNoMemory: - setError(QAbstractSocket::SocketResourceError, ResourceErrorString); - break; - case KErrPermissionDenied: - setError(QAbstractSocket::SocketAccessError, AccessErrorString); - break; - default: - break; - } - - return false; - } - - socketDescriptor = QSymbianSocketManager::instance().addSocket(nativeSocket); - return true; -} - -/* - Returns the value of the socket option \a opt. -*/ -int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) const -{ - Q_Q(const QNativeSocketEngine); - if (!q->isValid()) - return -1; - - TUint n; - TUint level = KSOLSocket; // default - - switch (opt) { - case QNativeSocketEngine::ReceiveBufferSocketOption: - n = KSORecvBuf; - break; - case QNativeSocketEngine::SendBufferSocketOption: - n = KSOSendBuf; - break; - case QNativeSocketEngine::NonBlockingSocketOption: - n = KSONonBlockingIO; - break; - case QNativeSocketEngine::BroadcastSocketOption: - return true; //symbian doesn't support or require this option - case QNativeSocketEngine::AddressReusable: - level = KSolInetIp; - n = KSoReuseAddr; - break; - case QNativeSocketEngine::BindExclusively: - return true; - case QNativeSocketEngine::ReceiveOutOfBandData: - level = KSolInetTcp; - n = KSoTcpOobInline; - break; - case QNativeSocketEngine::LowDelayOption: - level = KSolInetTcp; - n = KSoTcpNoDelay; - break; - case QNativeSocketEngine::KeepAliveOption: - level = KSolInetTcp; - n = KSoTcpKeepAlive; - break; - default: - return -1; - } - - int v = -1; - //GetOpt() is non const - TInt err = nativeSocket.GetOpt(n, level, v); - if (!err) - return v; - - return -1; -} - - -/* - Sets the socket option \a opt to \a v. -*/ -bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt, int v) -{ - Q_Q(QNativeSocketEngine); - if (!q->isValid()) - return false; - - int n = 0; - int level = SOL_SOCKET; // default - - switch (opt) { - case QNativeSocketEngine::ReceiveBufferSocketOption: - n = KSORecvBuf; - break; - case QNativeSocketEngine::SendBufferSocketOption: - n = KSOSendBuf; - break; - case QNativeSocketEngine::BroadcastSocketOption: - return true; - case QNativeSocketEngine::NonBlockingSocketOption: - n = KSONonBlockingIO; - break; - case QNativeSocketEngine::AddressReusable: - level = KSolInetIp; - n = KSoReuseAddr; - break; - case QNativeSocketEngine::BindExclusively: - return true; - case QNativeSocketEngine::ReceiveOutOfBandData: - level = KSolInetTcp; - n = KSoTcpOobInline; - break; - case QNativeSocketEngine::LowDelayOption: - level = KSolInetTcp; - n = KSoTcpNoDelay; - break; - case QNativeSocketEngine::KeepAliveOption: - level = KSolInetTcp; - n = KSoTcpKeepAlive; - break; - } - - return (KErrNone == nativeSocket.SetOpt(n, level, v)); -} - -void QNativeSocketEnginePrivate::setPortAndAddress(TInetAddr& nativeAddr, quint16 port, const QHostAddress &addr) -{ - nativeAddr.SetPort(port); -#if !defined(QT_NO_IPV6) - if (addr.protocol() == QAbstractSocket::IPv6Protocol) { -#ifndef QT_NO_IPV6IFNAME - TPckgBuf<TSoInetIfQuery> query; - query().iName = qt_QString2TPtrC(addr.scopeId()); - TInt err = nativeSocket.GetOpt(KSoInetIfQueryByName, KSolInetIfQuery, query); - if(!err) - nativeAddr.SetScope(query().iIndex); - else - nativeAddr.SetScope(0); -#else - nativeAddr.SetScope(addr.scopeId().toInt()); -#endif - Q_IPV6ADDR ip6 = addr.toIPv6Address(); - TIp6Addr v6addr; - memcpy(v6addr.u.iAddr8, ip6.c, 16); - nativeAddr.SetAddress(v6addr); - } else -#endif - if (addr.protocol() == QAbstractSocket::IPv4Protocol) { - nativeAddr.SetAddress(addr.toIPv4Address()); - } else { - qWarning("unsupported network protocol (%d)", addr.protocol()); - } -} - -bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 port) -{ -#ifdef QNATIVESOCKETENGINE_DEBUG - qDebug("QNativeSocketEnginePrivate::nativeConnect() : %d ", socketDescriptor); -#endif - - TInetAddr nativeAddr; - setPortAndAddress(nativeAddr, port, addr); - //TODO: async connect with active object - from here to end of function is a mess - TRequestStatus status; - nativeSocket.Connect(nativeAddr, status); - User::WaitForRequest(status); - TInt err = status.Int(); - if (err) { - switch (err) { - case KErrCouldNotConnect: - setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString); - socketState = QAbstractSocket::UnconnectedState; - break; - case KErrTimedOut: - setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString); - break; - case KErrHostUnreach: - setError(QAbstractSocket::NetworkError, HostUnreachableErrorString); - socketState = QAbstractSocket::UnconnectedState; - break; - case KErrNetUnreach: - setError(QAbstractSocket::NetworkError, NetworkUnreachableErrorString); - socketState = QAbstractSocket::UnconnectedState; - break; - case KErrInUse: - setError(QAbstractSocket::NetworkError, AddressInuseErrorString); - break; - case KErrPermissionDenied: - setError(QAbstractSocket::SocketAccessError, AccessErrorString); - socketState = QAbstractSocket::UnconnectedState; - break; - case KErrNotSupported: - case KErrBadDescriptor: - socketState = QAbstractSocket::UnconnectedState; - default: - break; - } - - if (socketState != QAbstractSocket::ConnectedState) { -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == false (%s)", - addr.toString().toLatin1().constData(), port, - socketState == QAbstractSocket::ConnectingState - ? "Connection in progress" : socketErrorString.toLatin1().constData()); -#endif - return false; - } - } - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == true", - addr.toString().toLatin1().constData(), port); -#endif - - socketState = QAbstractSocket::ConnectedState; - return true; -} - -bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16 port) -{ - TInetAddr nativeAddr; - setPortAndAddress(nativeAddr, port, address); - - TInt err = nativeSocket.Bind(nativeAddr); - - if (err) { - switch(errno) { - case KErrInUse: - setError(QAbstractSocket::AddressInUseError, AddressInuseErrorString); - break; - case KErrPermissionDenied: - setError(QAbstractSocket::SocketAccessError, AddressProtectedErrorString); - break; - case KErrNotSupported: - setError(QAbstractSocket::UnsupportedSocketOperationError, OperationUnsupportedErrorString); - break; - default: - break; - } - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == false (%s)", - address.toString().toLatin1().constData(), port, socketErrorString.toLatin1().constData()); -#endif - - return false; - } - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == true", - address.toString().toLatin1().constData(), port); -#endif - socketState = QAbstractSocket::BoundState; - return true; -} - -bool QNativeSocketEnginePrivate::nativeListen(int backlog) -{ - TInt err = nativeSocket.Listen(backlog); - if (err) { - switch (errno) { - case KErrInUse: - setError(QAbstractSocket::AddressInUseError, - PortInuseErrorString); - break; - default: - break; - } - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == false (%s)", - backlog, socketErrorString.toLatin1().constData()); -#endif - return false; - } - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == true", backlog); -#endif - - socketState = QAbstractSocket::ListeningState; - return true; -} - -int QNativeSocketEnginePrivate::nativeAccept() -{ - RSocket blankSocket; - //TODO: this is unbelievably broken, needs to be properly async - blankSocket.Open(socketServer); - TRequestStatus status; - nativeSocket.Accept(blankSocket, status); - User::WaitForRequest(status); - if(status.Int()) { - qWarning("QNativeSocketEnginePrivate::nativeAccept() - error %d", status.Int()); - return 0; - } - - return blankSocket.SubSessionHandle(); -} - -qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const -{ - int nbytes = 0; - qint64 available = 0; - TInt err = nativeSocket.GetOpt(KSOReadBytesPending, KSOLSocket, nbytes); - if(err) - return 0; - available = (qint64) nbytes; - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeBytesAvailable() == %lli", available); -#endif - return available; -} - -bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const -{ - int nbytes; - TInt err = nativeSocket.GetOpt(KSOReadBytesPending,KSOLSocket, nbytes); - return err == KErrNone && nbytes > 0; - //TODO: this is pretty horrible too... -} - -qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const -{ - int nbytes; - TInt err = nativeSocket.GetOpt(KSOReadBytesPending,KSOLSocket, nbytes); - return qint64(nbytes-28); //TODO: why -28 (open C version had this)? -} - -qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxSize, - QHostAddress *address, quint16 *port) -{ - TPtr8 buffer((TUint8*)data, (int)maxSize); - TInetAddr addr; - TRequestStatus status; //TODO: OMG sync receive! - nativeSocket.RecvFrom(buffer, addr, 0, status); - User::WaitForRequest(status); - - if (status.Int()) { - setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString); - } else if (port || address) { - getPortAndAddress(addr, port, address); - } - -#if defined (QNATIVESOCKETENGINE_DEBUG) - int len = buffer.Length(); - qDebug("QNativeSocketEnginePrivate::nativeReceiveDatagram(%p \"%s\", %lli, %s, %i) == %lli", - data, qt_prettyDebug(data, qMin(len, ssize_t(16)), len).data(), maxSize, - address ? address->toString().toLatin1().constData() : "(nil)", - port ? *port : 0, (qint64) len); -#endif - - if (status.Int()) - return -1; - return qint64(buffer.Length()); -} - -qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 len, - const QHostAddress &host, quint16 port) -{ - TPtrC8 buffer((TUint8*)data, (int)len); - TInetAddr addr; - setPortAndAddress(addr, port, host); - TSockXfrLength sentBytes; - TRequestStatus status; //TODO: OMG sync send! - nativeSocket.SendTo(buffer, addr, 0, status, sentBytes); - User::WaitForRequest(status); - TInt err = status.Int(); - - if (err) { - switch (err) { - case KErrTooBig: - setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString); - break; - default: - setError(QAbstractSocket::NetworkError, SendDatagramErrorString); - } - } - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEngine::sendDatagram(%p \"%s\", %lli, \"%s\", %i) == %lli", data, - qt_prettyDebug(data, qMin<int>(len, 16), len).data(), len, host.toString().toLatin1().constData(), - port, (qint64) sentBytes()); -#endif - - return qint64(sentBytes()); -} - -bool QNativeSocketEnginePrivate::fetchConnectionParameters() -{ - localPort = 0; - localAddress.clear(); - peerPort = 0; - peerAddress.clear(); - - if (socketDescriptor == -1) - return false; - - if (!nativeSocket.SubSessionHandle()) { - if (!QSymbianSocketManager::instance().lookupSocket(socketDescriptor, nativeSocket)) - return false; - } - - // Determine local address - TSockAddr addr; - nativeSocket.LocalName(addr); - getPortAndAddress(addr, &localPort, &localAddress); - - // Determine protocol family - switch (addr.Family()) { - case KAfInet: - socketProtocol = QAbstractSocket::IPv4Protocol; - break; -#if !defined (QT_NO_IPV6) - case KAfInet6: - socketProtocol = QAbstractSocket::IPv6Protocol; - break; -#endif - default: - socketProtocol = QAbstractSocket::UnknownNetworkLayerProtocol; - break; - } - - // Determine the remote address - nativeSocket.RemoteName(addr); - getPortAndAddress(addr, &peerPort, &peerAddress); - - // Determine the socket type (UDP/TCP) - TProtocolDesc protocol; - TInt err = nativeSocket.Info(protocol); - if (err) { - QAbstractSocket::UnknownSocketType; - } else { - switch (protocol.iProtocol) { - case KProtocolInetTcp: - socketType = QAbstractSocket::TcpSocket; - break; - case KProtocolInetUdp: - socketType = QAbstractSocket::UdpSocket; - break; - default: - socketType = QAbstractSocket::UnknownSocketType; - break; - } - } -#if defined (QNATIVESOCKETENGINE_DEBUG) - QString socketProtocolStr = "UnknownProtocol"; - if (socketProtocol == QAbstractSocket::IPv4Protocol) socketProtocolStr = "IPv4Protocol"; - else if (socketProtocol == QAbstractSocket::IPv6Protocol) socketProtocolStr = "IPv6Protocol"; - - QString socketTypeStr = "UnknownSocketType"; - if (socketType == QAbstractSocket::TcpSocket) socketTypeStr = "TcpSocket"; - else if (socketType == QAbstractSocket::UdpSocket) socketTypeStr = "UdpSocket"; - - qDebug("QNativeSocketEnginePrivate::fetchConnectionParameters() local == %s:%i," - " peer == %s:%i, socket == %s - %s", - localAddress.toString().toLatin1().constData(), localPort, - peerAddress.toString().toLatin1().constData(), peerPort,socketTypeStr.toLatin1().constData(), - socketProtocolStr.toLatin1().constData()); -#endif - return true; -} - -void QNativeSocketEnginePrivate::nativeClose() -{ -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEngine::nativeClose()"); -#endif - - //TODO: call nativeSocket.Shutdown(EImmediate) in some cases? - nativeSocket.Close(); - QSymbianSocketManager::instance().removeSocket(nativeSocket); -} - -qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len) -{ - Q_Q(QNativeSocketEngine); - TPtrC8 buffer((TUint8*)data, (int)len); - TSockXfrLength sentBytes; - TRequestStatus status; //TODO: OMG sync send! - nativeSocket.Send(buffer, 0, status, sentBytes); - User::WaitForRequest(status); - TInt err = status.Int(); - - if (err) { - switch (err) { - case KErrDisconnected: - sentBytes = -1; - setError(QAbstractSocket::RemoteHostClosedError, RemoteHostClosedErrorString); - q->close(); - break; - case KErrTooBig: - setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString); - break; - case KErrWouldBlock: - sentBytes = 0; - default: - setError(QAbstractSocket::NetworkError, SendDatagramErrorString); - } - } - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeWrite(%p \"%s\", %llu) == %i", - data, qt_prettyDebug(data, qMin((int) len, 16), - (int) len).data(), len, (int) sentBytes()); -#endif - - return qint64(sentBytes()); -} -/* -*/ -qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize) -{ - Q_Q(QNativeSocketEngine); - if (!q->isValid()) { - qWarning("QNativeSocketEngine::nativeRead: Invalid socket"); - return -1; - } - - TPtr8 buffer((TUint8*)data, (int)maxSize); - TSockXfrLength received = 0; - TRequestStatus status; //TODO: OMG sync receive! - nativeSocket.RecvOneOrMore(buffer, 0, status, received); - User::WaitForRequest(status); - TInt err = status.Int(); - int r = received(); - - if (err) { - switch(err) { - case KErrWouldBlock: - // No data was available for reading - r = -2; - break; - case KErrDisconnected: - r = 0; - break; - default: - r = -1; - //error string is now set in read(), not here in nativeRead() - break; - } - } - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeRead(%p \"%s\", %llu) == %i", - data, qt_prettyDebug(data, qMin(r, ssize_t(16)), r).data(), - maxSize, r); -#endif - - return qint64(r); -} - -int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const -{ - bool readyRead = false; - bool readyWrite = false; - if (selectForRead) - return nativeSelect(timeout, true, false, &readyRead, &readyWrite); - else - return nativeSelect(timeout, false, true, &readyRead, &readyWrite); -} - -/*! - \internal - \param timeout timeout in milliseconds - \param checkRead caller is interested if the socket is ready to read - \param checkWrite caller is interested if the socket is ready for write - \param selectForRead (out) should set to true if ready to read - \param selectForWrite (out) should set to true if ready to write - \return 0 on timeout, >0 on success, <0 on error - */ -int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite, - bool *selectForRead, bool *selectForWrite) const -{ - //TODO: implement - //as above, but checking both read and write status at the same time - if (!selectTimer.Handle()) - qt_symbian_throwIfError(selectTimer.CreateLocal()); - TRequestStatus timerStat; - selectTimer.HighRes(timerStat, timeout * 1000); - TRequestStatus* readStat = 0; - TRequestStatus* writeStat = 0; - TRequestStatus* array[3]; - array[0] = &timerStat; - int count = 1; - if (checkRead) { - //TODO: get from read AO - //readStat = ? - array[count++] = readStat; - } - if (checkWrite) { - //TODO: get from write AO - //writeStat = ? - array[count++] = writeStat; - } - - User::WaitForNRequest(array, count); - //IMPORTANT - WaitForNRequest only decrements the thread semaphore once, although more than one status may have completed. - if (timerStat.Int() != KRequestPending) { - //timed out - return 0; - } - selectTimer.Cancel(); - User::WaitForRequest(timerStat); - - if(readStat && readStat->Int() != KRequestPending) { - Q_ASSERT(checkRead && selectForRead); - //TODO: cancel the AO, but call its RunL anyway? looking for an UnsetActive() - *selectForRead = true; - } - if(writeStat && writeStat->Int() != KRequestPending) { - Q_ASSERT(checkWrite && selectForWrite); - //TODO: cancel the AO, but call its RunL anyway? looking for an UnsetActive() - *selectForWrite = true; - } - return 1; -} - -bool QNativeSocketEnginePrivate::nativeJoinMulticastGroup(const QHostAddress &groupAddress, - const QNetworkInterface &iface) -{ - //TODO - return false; -} - -bool QNativeSocketEnginePrivate::nativeLeaveMulticastGroup(const QHostAddress &groupAddress, - const QNetworkInterface &iface) -{ - //TODO - return false; -} - -QNetworkInterface QNativeSocketEnginePrivate::nativeMulticastInterface() const -{ - //TODO - return QNetworkInterface(); -} - -bool QNativeSocketEnginePrivate::nativeSetMulticastInterface(const QNetworkInterface &iface) -{ - //TODO - return false; -} - -QT_END_NAMESPACE diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp index c819659..3d850a1 100644 --- a/src/network/socket/qnativesocketengine_unix.cpp +++ b/src/network/socket/qnativesocketengine_unix.cpp @@ -65,12 +65,7 @@ #include <ctype.h> #endif -#ifdef Q_OS_SYMBIAN // ### TODO: Are these headers right? -#include <sys/socket.h> -#include <netinet/in.h> -#else #include <netinet/tcp.h> -#endif QT_BEGIN_NAMESPACE @@ -174,11 +169,8 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc int protocol = AF_INET; #endif int type = (socketType == QAbstractSocket::UdpSocket) ? SOCK_DGRAM : SOCK_STREAM; -#ifdef Q_OS_SYMBIAN - int socket = ::socket(protocol, type, 0); -#else + int socket = qt_safe_socket(protocol, type, 0); -#endif if (socket <= 0) { switch (errno) { @@ -320,11 +312,9 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt } #else // Q_OS_VXWORKS int onoff = 1; -#ifdef Q_OS_SYMBIAN - if (::ioctl(socketDescriptor, FIONBIO, &onoff) < 0) { -#else + if (qt_safe_ioctl(socketDescriptor, FIONBIO, &onoff) < 0) { -#endif + #ifdef QNATIVESOCKETENGINE_DEBUG perror("QNativeSocketEnginePrivate::setOption(): ioctl(FIONBIO, 1) failed"); #endif @@ -334,7 +324,7 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt return true; } case QNativeSocketEngine::AddressReusable: -#if defined(SO_REUSEPORT) && !defined(Q_OS_SYMBIAN) +#if defined(SO_REUSEPORT) n = SO_REUSEPORT; #else n = SO_REUSEADDR; @@ -427,11 +417,8 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 } else { // unreachable } -#ifdef Q_OS_SYMBIAN - int connectResult = ::connect(socketDescriptor, sockAddrPtr, sockAddrSize); -#else + int connectResult = qt_safe_connect(socketDescriptor, sockAddrPtr, sockAddrSize); -#endif if (connectResult == -1) { switch (errno) { case EISCONN: @@ -474,9 +461,6 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 case EBADF: case EFAULT: case ENOTSOCK: -#ifdef Q_OS_SYMBIAN - case EPIPE: -#endif socketState = QAbstractSocket::UnconnectedState; default: break; @@ -575,11 +559,7 @@ bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16 bool QNativeSocketEnginePrivate::nativeListen(int backlog) { -#ifdef Q_OS_SYMBIAN - if (::listen(socketDescriptor, backlog) < 0) { -#else if (qt_safe_listen(socketDescriptor, backlog) < 0) { -#endif switch (errno) { case EADDRINUSE: setError(QAbstractSocket::AddressInUseError, @@ -606,11 +586,7 @@ bool QNativeSocketEnginePrivate::nativeListen(int backlog) int QNativeSocketEnginePrivate::nativeAccept() { -#ifdef Q_OS_SYMBIAN - int acceptedDescriptor = ::accept(socketDescriptor, 0, 0); -#else int acceptedDescriptor = qt_safe_accept(socketDescriptor, 0, 0); -#endif return acceptedDescriptor; } @@ -785,11 +761,7 @@ qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const int nbytes = 0; // gives shorter than true amounts on Unix domain sockets. qint64 available = 0; -#ifdef Q_OS_SYMBIAN - if (::ioctl(socketDescriptor, FIONREAD, (char *) &nbytes) >= 0) -#else if (qt_safe_ioctl(socketDescriptor, FIONREAD, (char *) &nbytes) >= 0) -#endif available = (qint64) nbytes; #if defined (QNATIVESOCKETENGINE_DEBUG) @@ -808,15 +780,10 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const // Peek 0 bytes into the next message. The size of the message may // well be 0, so we can't check recvfrom's return value. ssize_t readBytes; -#ifdef Q_OS_SYMBIAN - char c; - readBytes = ::recvfrom(socketDescriptor, &c, 1, MSG_PEEK, &storage.a, &storageSize); -#else do { char c; readBytes = ::recvfrom(socketDescriptor, &c, 1, MSG_PEEK, &storage.a, &storageSize); } while (readBytes == -1 && errno == EINTR); -#endif // If there's no error, or if our buffer was too small, there must be a // pending datagram. @@ -829,14 +796,6 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const return result; } -#ifdef Q_OS_SYMBIAN -qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const -{ - size_t nbytes = 0; - ::ioctl(socketDescriptor, E32IONREAD, (char *) &nbytes); - return qint64(nbytes-28); -} -#else qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const { QVarLengthArray<char, 8192> udpMessagePeekBuffer(8192); @@ -863,7 +822,7 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const return qint64(recvResult); } -#endif + qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxSize, QHostAddress *address, quint16 *port) { @@ -873,17 +832,11 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS sz = sizeof(aa); ssize_t recvFromResult = 0; -#ifdef Q_OS_SYMBIAN - char c; - recvFromResult = ::recvfrom(socketDescriptor, maxSize ? data : &c, maxSize ? maxSize : 1, - 0, &aa.a, &sz); -#else do { char c; recvFromResult = ::recvfrom(socketDescriptor, maxSize ? data : &c, maxSize ? maxSize : 1, 0, &aa.a, &sz); } while (recvFromResult == -1 && errno == EINTR); -#endif if (recvFromResult == -1) { setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString); @@ -932,13 +885,8 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l // ignore the SIGPIPE signal qt_ignore_sigpipe(); -#ifdef Q_OS_SYMBIAN - ssize_t sentBytes = ::sendto(socketDescriptor, data, len, - 0, sockAddrPtr, sockAddrSize); -#else ssize_t sentBytes = qt_safe_sendto(socketDescriptor, data, len, 0, sockAddrPtr, sockAddrSize); -#endif if (sentBytes < 0) { switch (errno) { @@ -1036,11 +984,7 @@ void QNativeSocketEnginePrivate::nativeClose() qDebug("QNativeSocketEngine::nativeClose()"); #endif -#ifdef Q_OS_SYMBIAN - ::close(socketDescriptor); -#else - qt_safe_close(socketDescriptor); -#endif + qt_safe_close(socketDescriptor); } qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len) @@ -1051,12 +995,7 @@ qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len) qt_ignore_sigpipe(); ssize_t writtenBytes; -#ifdef Q_OS_SYMBIAN - // Symbian does not support signals natively and Open C returns EINTR when moving to offline - writtenBytes = ::write(socketDescriptor, data, len); -#else writtenBytes = qt_safe_write(socketDescriptor, data, len); -#endif if (writtenBytes < 0) { switch (errno) { @@ -1096,11 +1035,7 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize) } ssize_t r = 0; -#ifdef Q_OS_SYMBIAN - r = ::read(socketDescriptor, data, maxSize); -#else r = qt_safe_read(socketDescriptor, data, maxSize); -#endif if (r < 0) { r = -1; @@ -1117,9 +1052,6 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize) case EIO: //error string is now set in read(), not here in nativeRead() break; -#ifdef Q_OS_SYMBIAN - case EPIPE: -#endif case ECONNRESET: #if defined(Q_OS_VXWORKS) case ESHUTDOWN: @@ -1150,40 +1082,11 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) co tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; -#ifdef Q_OS_SYMBIAN - fd_set fdexception; - FD_ZERO(&fdexception); - FD_SET(socketDescriptor, &fdexception); -#endif - int retval; if (selectForRead) -#ifdef Q_OS_SYMBIAN - retval = ::select(socketDescriptor + 1, &fds, 0, &fdexception, timeout < 0 ? 0 : &tv); -#else retval = qt_safe_select(socketDescriptor + 1, &fds, 0, 0, timeout < 0 ? 0 : &tv); -#endif else -#ifdef Q_OS_SYMBIAN - retval = ::select(socketDescriptor + 1, 0, &fds, &fdexception, timeout < 0 ? 0 : &tv); -#else retval = qt_safe_select(socketDescriptor + 1, 0, &fds, 0, timeout < 0 ? 0 : &tv); -#endif - - -#ifdef Q_OS_SYMBIAN - bool selectForExec = false; - if(retval != 0) { - if(retval < 0) { - qWarning("nativeSelect(....) returned < 0 for socket %d", socketDescriptor); - } - selectForExec = FD_ISSET(socketDescriptor, &fdexception); - } - if(selectForExec) { - qWarning("nativeSelect (selectForRead %d, retVal %d, errno %d) Unexpected exception for fd %d", - selectForRead, retval, errno, socketDescriptor); - } -#endif return retval; } @@ -1201,65 +1104,12 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c if (checkWrite) FD_SET(socketDescriptor, &fdwrite); -#ifdef Q_OS_SYMBIAN - fd_set fdexception; - FD_ZERO(&fdexception); - FD_SET(socketDescriptor, &fdexception); -#endif - struct timeval tv; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; int ret; -#ifndef Q_OS_SYMBIAN ret = qt_safe_select(socketDescriptor + 1, &fdread, &fdwrite, 0, timeout < 0 ? 0 : &tv); -#else - QElapsedTimer timer; - timer.start(); - - do { - ret = ::select(socketDescriptor + 1, &fdread, &fdwrite, &fdexception, timeout < 0 ? 0 : &tv); - bool selectForExec = false; - if(ret != 0) { - if(ret < 0) { - qWarning("nativeSelect(....) returned < 0 for socket %d", socketDescriptor); - } - selectForExec = FD_ISSET(socketDescriptor, &fdexception); - } - if(selectForExec) { - qWarning("nativeSelect (checkRead %d, checkWrite %d, ret %d, errno %d): Unexpected expectfds ready in fd %d", - checkRead, checkWrite, ret, errno, socketDescriptor); - if (checkWrite){ - FD_CLR(socketDescriptor, &fdread); - FD_SET(socketDescriptor, &fdwrite); - } else if (checkRead) - FD_SET(socketDescriptor, &fdread); - - - if ((ret == -1) && ( errno == ECONNREFUSED || errno == EPIPE )) - ret = 1; - - } - - if (ret != -1 || errno != EINTR) { - break; - } - - if (timeout > 0) { - // recalculate the timeout - int t = timeout - timer.elapsed(); - if (t < 0) { - // oops, timeout turned negative? - ret = -1; - break; - } - - tv.tv_sec = t / 1000; - tv.tv_usec = (t % 1000) * 1000; - } - } while (true); -#endif if (ret <= 0) return ret; diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp index ab3d260..91dfdf3 100644 --- a/src/network/socket/qsocks5socketengine.cpp +++ b/src/network/socket/qsocks5socketengine.cpp @@ -556,6 +556,7 @@ void QSocks5SocketEnginePrivate::initialize(Socks5Mode socks5Mode) udpData = new QSocks5UdpAssociateData; data = udpData; udpData->udpSocket = new QUdpSocket(q); + udpData->udpSocket->setProperty("_q_networksession", q->property("_q_networksession")); udpData->udpSocket->setProxy(QNetworkProxy::NoProxy); QObject::connect(udpData->udpSocket, SIGNAL(readyRead()), q, SLOT(_q_udpSocketReadNotification()), @@ -567,6 +568,7 @@ void QSocks5SocketEnginePrivate::initialize(Socks5Mode socks5Mode) } data->controlSocket = new QTcpSocket(q); + data->controlSocket->setProperty("_q_networksession", q->property("_q_networksession")); data->controlSocket->setProxy(QNetworkProxy::NoProxy); QObject::connect(data->controlSocket, SIGNAL(connected()), q, SLOT(_q_controlSocketConnected()), Qt::DirectConnection); @@ -1376,6 +1378,7 @@ bool QSocks5SocketEngine::bind(const QHostAddress &address, quint16 port) d->udpData->associatePort = d->localPort; d->localPort = 0; QUdpSocket dummy; + dummy.setProperty("_q_networksession", property("_q_networksession")); dummy.setProxy(QNetworkProxy::NoProxy); if (!dummy.bind() || writeDatagram(0,0, d->data->controlSocket->localAddress(), dummy.localPort()) != 0 diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp new file mode 100644 index 0000000..dac50d4 --- /dev/null +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -0,0 +1,1810 @@ +/**************************************************************************** +** +** 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 QNATIVESOCKETENGINE_DEBUG +#include "qsymbiansocketengine_p.h" + +#include "qiodevice.h" +#include "qhostaddress.h" +#include "qelapsedtimer.h" +#include "qvarlengtharray.h" +#include "qnetworkinterface.h" +#include "qnetworksession_p.h" +#include <es_sock.h> +#include <in_sock.h> +#include <net/if.h> + +#include <private/qcore_symbian_p.h> + +#if !defined(QT_NO_NETWORKPROXY) +# include "qnetworkproxy.h" +# include "qabstractsocket.h" +# include "qtcpserver.h" +#endif + +#include <QCoreApplication> + +#include <qabstracteventdispatcher.h> +#include <qsocketnotifier.h> +#include <qnetworkinterface.h> + +#include <private/qthread_p.h> +#include <private/qobject_p.h> +#include <private/qsystemerror_p.h> + +#define QNATIVESOCKETENGINE_DEBUG + +#if defined QNATIVESOCKETENGINE_DEBUG +#include <qstring.h> +#include <ctype.h> +#endif + +QT_BEGIN_NAMESPACE + +#define Q_VOID +// Common constructs +#define Q_CHECK_VALID_SOCKETLAYER(function, returnValue) do { \ + if (!isValid()) { \ + qWarning(""#function" was called on an uninitialized socket device"); \ + return returnValue; \ + } } while (0) +#define Q_CHECK_INVALID_SOCKETLAYER(function, returnValue) do { \ + if (isValid()) { \ + qWarning(""#function" was called on an already initialized socket device"); \ + return returnValue; \ + } } while (0) +#define Q_CHECK_STATE(function, checkState, returnValue) do { \ + if (d->socketState != (checkState)) { \ + qWarning(""#function" was not called in "#checkState); \ + return (returnValue); \ + } } while (0) +#define Q_CHECK_NOT_STATE(function, checkState, returnValue) do { \ + if (d->socketState == (checkState)) { \ + qWarning(""#function" was called in "#checkState); \ + return (returnValue); \ + } } while (0) +#define Q_CHECK_STATES(function, state1, state2, returnValue) do { \ + if (d->socketState != (state1) && d->socketState != (state2)) { \ + qWarning(""#function" was called" \ + " not in "#state1" or "#state2); \ + return (returnValue); \ + } } while (0) +#define Q_CHECK_TYPE(function, type, returnValue) do { \ + if (d->socketType != (type)) { \ + qWarning(#function" was called by a" \ + " socket other than "#type""); \ + return (returnValue); \ + } } while (0) + +#if defined QNATIVESOCKETENGINE_DEBUG + +/* + Returns a human readable representation of the first \a len + characters in \a data. +*/ +static QByteArray qt_prettyDebug(const char *data, int len, int maxSize) +{ + if (!data) return "(null)"; + QByteArray out; + for (int i = 0; i < len; ++i) { + char c = data[i]; + if (isprint(c)) { + out += c; + } else switch (c) { + case '\n': out += "\\n"; break; + case '\r': out += "\\r"; break; + case '\t': out += "\\t"; break; + default: + QString tmp; + tmp.sprintf("\\%o", c); + out += tmp.toLatin1(); + } + } + + if (len < maxSize) + out += "..."; + + return out; +} +#endif + +void QSymbianSocketEnginePrivate::getPortAndAddress(const TInetAddr& a, quint16 *port, QHostAddress *addr) +{ + if (a.Family() == KAfInet6) { + Q_IPV6ADDR tmp; + memcpy(&tmp, a.Ip6Address().u.iAddr8, sizeof(tmp)); + if (addr) { + QHostAddress tmpAddress; + tmpAddress.setAddress(tmp); + *addr = tmpAddress; + TPckgBuf<TSoInetIfQuery> query; + query().iSrcAddr = a; + TInt err = nativeSocket.GetOpt(KSoInetIfQueryBySrcAddr, KSolInetIfQuery, query); + if (!err) + addr->setScopeId(qt_TDesC2QString(query().iName)); + else + addr->setScopeId(QString::number(a.Scope())); + } + if (port) + *port = a.Port(); + return; + } + if (port) + *port = a.Port(); + if (addr) { + QHostAddress tmpAddress; + tmpAddress.setAddress(a.Address()); + *addr = tmpAddress; + } +} +/*! \internal + + Creates and returns a new socket descriptor of type \a socketType + and \a socketProtocol. Returns -1 on failure. +*/ +bool QSymbianSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType, + QAbstractSocket::NetworkLayerProtocol socketProtocol) +{ + Q_Q(QSymbianSocketEngine); + TUint family = KAfInet; // KAfInet6 is only used as an address family, not as a protocol family + TUint type = (socketType == QAbstractSocket::UdpSocket) ? KSockDatagram : KSockStream; + TUint protocol = (socketType == QAbstractSocket::UdpSocket) ? KProtocolInetUdp : KProtocolInetTcp; + + //Check if there is a user specified session + RConnection *connection = 0; + QVariant v(q->property("_q_networksession")); + if (v.isValid()) { + QSharedPointer<QNetworkSession> s = qvariant_cast<QSharedPointer<QNetworkSession> >(v); + connection = QNetworkSessionPrivate::nativeSession(*s); +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << "QSymbianSocketEnginePrivate::createNewSocket - _q_networksession was set" << connection; +#endif + } + TInt err; + if (connection) { + if (connection->SubSessionHandle()) + err = nativeSocket.Open(socketServer, family, type, protocol, *connection); + else { + setError(QAbstractSocket::NetworkError, SessionNotOpenErrorString); + return false; + } + } else + err = nativeSocket.Open(socketServer, family, type, protocol); //TODO: FIXME - deprecated API, make sure we always have a connection instead + + if (err != KErrNone) { + switch (err) { + case KErrNotSupported: + case KErrNotFound: + setError(QAbstractSocket::UnsupportedSocketOperationError, + ProtocolUnsupportedErrorString); + break; + default: + setError(err); + break; + } + + return false; + } +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << "QSymbianSocketEnginePrivate::createNewSocket - created" << nativeSocket.SubSessionHandle(); +#endif + socketDescriptor = QSymbianSocketManager::instance().addSocket(nativeSocket); +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << " - allocated socket descriptor" << socketDescriptor; +#endif + return true; +} + +void QSymbianSocketEnginePrivate::setPortAndAddress(TInetAddr& nativeAddr, quint16 port, const QHostAddress &addr) +{ + nativeAddr.SetPort(port); + if (addr == QHostAddress::Any) { + //Should allow both IPv4 and IPv6 + //Listening on "0.0.0.0" accepts ONLY ipv4 connections + //Listening on "::" accepts ONLY ipv6 connections + nativeAddr.SetFamily(KAFUnspec); + } else if (addr.protocol() == QAbstractSocket::IPv6Protocol) { + TPckgBuf<TSoInetIfQuery> query; + query().iName = qt_QString2TPtrC(addr.scopeId()); + TInt err = nativeSocket.GetOpt(KSoInetIfQueryByName, KSolInetIfQuery, query); + if (!err) + nativeAddr.SetScope(query().iIndex); + else + nativeAddr.SetScope(0); + Q_IPV6ADDR ip6 = addr.toIPv6Address(); + TIp6Addr v6addr; + memcpy(v6addr.u.iAddr8, ip6.c, 16); + nativeAddr.SetAddress(v6addr); + } else if (addr.protocol() == QAbstractSocket::IPv4Protocol) { + nativeAddr.SetAddress(addr.toIPv4Address()); + } else { + qWarning("unsupported network protocol (%d)", addr.protocol()); + } +} + +QSymbianSocketEnginePrivate::QSymbianSocketEnginePrivate() : + socketDescriptor(-1), + socketServer(QSymbianSocketManager::instance().getSocketServer()), + readNotifier(0), + writeNotifier(0), + exceptNotifier(0), + asyncSelect(0) +{ +} + +QSymbianSocketEnginePrivate::~QSymbianSocketEnginePrivate() +{ +} + + +QSymbianSocketEngine::QSymbianSocketEngine(QObject *parent) + : QAbstractSocketEngine(*new QSymbianSocketEnginePrivate(), parent) +{ +} + + +QSymbianSocketEngine::~QSymbianSocketEngine() +{ + close(); + // FIXME what else do we need to free? +} + +/*! + Initializes a QSymbianSocketEngine by creating a new socket of type \a + socketType and network layer protocol \a protocol. Returns true on + success; otherwise returns false. + + If the socket was already initialized, this function closes the + socket before reeinitializing it. + + The new socket is non-blocking, and for UDP sockets it's also + broadcast enabled. +*/ +bool QSymbianSocketEngine::initialize(QAbstractSocket::SocketType socketType, QAbstractSocket::NetworkLayerProtocol protocol) +{ + Q_D(QSymbianSocketEngine); + if (isValid()) + close(); + + // Create the socket + if (!d->createNewSocket(socketType, protocol)) { +#if defined (QNATIVESOCKETENGINE_DEBUG) + QString typeStr = QLatin1String("UnknownSocketType"); + if (socketType == QAbstractSocket::TcpSocket) typeStr = QLatin1String("TcpSocket"); + else if (socketType == QAbstractSocket::UdpSocket) typeStr = QLatin1String("UdpSocket"); + QString protocolStr = QLatin1String("UnknownProtocol"); + if (protocol == QAbstractSocket::IPv4Protocol) protocolStr = QLatin1String("IPv4Protocol"); + else if (protocol == QAbstractSocket::IPv6Protocol) protocolStr = QLatin1String("IPv6Protocol"); + qDebug("QSymbianSocketEngine::initialize(type == %s, protocol == %s) failed: %s", + typeStr.toLatin1().constData(), protocolStr.toLatin1().constData(), d->socketErrorString.toLatin1().constData()); +#endif + return false; + } + + // Make the socket nonblocking. + if (!setOption(NonBlockingSocketOption, 1)) { + d->setError(QAbstractSocket::UnsupportedSocketOperationError, + d->NonBlockingInitFailedErrorString); + close(); + return false; + } + + // Set the broadcasting flag if it's a UDP socket. + if (socketType == QAbstractSocket::UdpSocket + && !setOption(BroadcastSocketOption, 1)) { + d->setError(QAbstractSocket::UnsupportedSocketOperationError, + d->BroadcastingInitFailedErrorString); + close(); + return false; + } + + + // Make sure we receive out-of-band data + if (socketType == QAbstractSocket::TcpSocket + && !setOption(ReceiveOutOfBandData, 1)) { + qWarning("QSymbianSocketEngine::initialize unable to inline out-of-band data"); + } + + + d->socketType = socketType; + d->socketProtocol = protocol; + return true; +} + +/*! \overload + + Initializes the socket using \a socketDescriptor instead of + creating a new one. The socket type and network layer protocol are + determined automatically. The socket's state is set to \a + socketState. + + If the socket type is either TCP or UDP, it is made non-blocking. + UDP sockets are also broadcast enabled. + */ +bool QSymbianSocketEngine::initialize(int socketDescriptor, QAbstractSocket::SocketState socketState) +{ + Q_D(QSymbianSocketEngine); + + if (isValid()) + close(); + + if (!QSymbianSocketManager::instance().lookupSocket(socketDescriptor, d->nativeSocket)) { + qWarning("QSymbianSocketEngine::initialize - socket descriptor not found"); + d->setError(QAbstractSocket::UnsupportedSocketOperationError, + QSymbianSocketEnginePrivate::InvalidSocketErrorString); + return false; + } +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << "QSymbianSocketEngine::initialize - attached to" << d->nativeSocket.SubSessionHandle() << socketDescriptor; +#endif + Q_ASSERT(d->socketDescriptor == socketDescriptor || d->socketDescriptor == -1); + d->socketDescriptor = socketDescriptor; + + // determine socket type and protocol + if (!d->fetchConnectionParameters()) { +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QSymbianSocketEngine::initialize(socketDescriptor == %i) failed: %s", + socketDescriptor, d->socketErrorString.toLatin1().constData()); +#endif + d->socketDescriptor = -1; + return false; + } + + if (d->socketType != QAbstractSocket::UnknownSocketType) { + // Make the socket nonblocking. + if (!setOption(NonBlockingSocketOption, 1)) { + d->setError(QAbstractSocket::UnsupportedSocketOperationError, + d->NonBlockingInitFailedErrorString); + close(); + return false; + } + + // Set the broadcasting flag if it's a UDP socket. + if (d->socketType == QAbstractSocket::UdpSocket + && !setOption(BroadcastSocketOption, 1)) { + d->setError(QAbstractSocket::UnsupportedSocketOperationError, + d->BroadcastingInitFailedErrorString); + close(); + return false; + } + + // Make sure we receive out-of-band data + if (d->socketType == QAbstractSocket::TcpSocket + && !setOption(ReceiveOutOfBandData, 1)) { + qWarning("QSymbianSocketEngine::initialize unable to inline out-of-band data"); + } + } + + d->socketState = socketState; + return true; +} + +/*! + Returns true if the socket is valid; otherwise returns false. A + socket is valid if it has not been successfully initialized, or if + it has been closed. +*/ +bool QSymbianSocketEngine::isValid() const +{ + Q_D(const QSymbianSocketEngine); + return d->socketDescriptor != -1; +} + + +/*! + Returns the native socket descriptor. Any use of this descriptor + stands the risk of being non-portable. +*/ +int QSymbianSocketEngine::socketDescriptor() const +{ + Q_D(const QSymbianSocketEngine); + return d->socketDescriptor; +} + +/* + Sets the socket option \a opt to \a v. +*/ +bool QSymbianSocketEngine::setOption(QAbstractSocketEngine::SocketOption opt, int v) +{ + Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setOption(), false); + + TUint n = 0; + TUint level = KSOLSocket; // default + + if (!QSymbianSocketEnginePrivate::translateSocketOption(opt, n, level)) + return false; + + if (!level && !n) + return true; + + return (KErrNone == d->nativeSocket.SetOpt(n, level, v)); +} + +/* + Returns the value of the socket option \a opt. +*/ +int QSymbianSocketEngine::option(QAbstractSocketEngine::SocketOption opt) const +{ + Q_D(const QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::option(), -1); + + TUint n; + TUint level = KSOLSocket; // default + + if (!QSymbianSocketEnginePrivate::translateSocketOption(opt, n, level)) + return false; + + if (!level && !n) + return 1; + + int v = -1; + //GetOpt() is non const + TInt err = d->nativeSocket.GetOpt(n, level, v); + if (!err) + return v; + + return -1; +} + +bool QSymbianSocketEnginePrivate::translateSocketOption(QAbstractSocketEngine::SocketOption opt, TUint &n, TUint &level) +{ + + switch (opt) { + case QAbstractSocketEngine::ReceiveBufferSocketOption: + n = KSORecvBuf; + break; + case QAbstractSocketEngine::SendBufferSocketOption: + n = KSOSendBuf; + break; + case QAbstractSocketEngine::NonBlockingSocketOption: + n = KSONonBlockingIO; + break; + case QAbstractSocketEngine::AddressReusable: + level = KSolInetIp; + n = KSoReuseAddr; + break; + case QAbstractSocketEngine::BroadcastSocketOption: + case QAbstractSocketEngine::BindExclusively: + level = 0; + n = 0; + return true; + case QAbstractSocketEngine::ReceiveOutOfBandData: + level = KSolInetTcp; + n = KSoTcpOobInline; + break; + case QAbstractSocketEngine::LowDelayOption: + level = KSolInetTcp; + n = KSoTcpNoDelay; + break; + case QAbstractSocketEngine::KeepAliveOption: + level = KSolInetTcp; + n = KSoTcpKeepAlive; + break; + case QAbstractSocketEngine::MulticastLoopbackOption: + level = KSolInetIp; + n = KSoIp6MulticastLoop; + break; + case QAbstractSocketEngine::MulticastTtlOption: + level = KSolInetIp; + n = KSoIp6MulticastHops; + break; + default: + return false; + } + return true; +} + +qint64 QSymbianSocketEngine::receiveBufferSize() const +{ + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::receiveBufferSize(), -1); + return option(ReceiveBufferSocketOption); +} + +void QSymbianSocketEngine::setReceiveBufferSize(qint64 size) +{ + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setReceiveBufferSize(), Q_VOID); + setOption(ReceiveBufferSocketOption, size); +} + +qint64 QSymbianSocketEngine::sendBufferSize() const +{ + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setSendBufferSize(), -1); + return option(SendBufferSocketOption); +} + +void QSymbianSocketEngine::setSendBufferSize(qint64 size) +{ + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setSendBufferSize(), Q_VOID); + setOption(SendBufferSocketOption, size); +} + +/*! + Connects to the remote host name given by \a name on port \a + port. When this function is called, the upper-level will not + perform a hostname lookup. + + The native socket engine does not support this operation, + but some other socket engines (notably proxy-based ones) do. +*/ +bool QSymbianSocketEngine::connectToHostByName(const QString &name, quint16 port) +{ + Q_UNUSED(name); + Q_UNUSED(port); + Q_D(QSymbianSocketEngine); + d->setError(QAbstractSocket::UnsupportedSocketOperationError, + QSymbianSocketEnginePrivate::OperationUnsupportedErrorString); + return false; +} + +/*! + If there's a connection activity on the socket, process it. Then + notify our parent if there really was activity. +*/ +void QSymbianSocketEngine::connectionNotification() +{ + // FIXME check if we really need to do it like that in Symbian + Q_D(QSymbianSocketEngine); + Q_ASSERT(state() == QAbstractSocket::ConnectingState); + + connectToHost(d->peerAddress, d->peerPort); + if (state() != QAbstractSocket::ConnectingState) { + // we changed states + QAbstractSocketEngine::connectionNotification(); + } +} + + +bool QSymbianSocketEngine::connectToHost(const QHostAddress &addr, quint16 port) +{ + Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::connectToHost(), false); + +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug("QSymbianSocketEngine::connectToHost() : %d ", d->socketDescriptor); +#endif + + if (!d->checkProxy(addr)) + return false; + + d->peerAddress = addr; + d->peerPort = port; + + TInetAddr nativeAddr; + d->setPortAndAddress(nativeAddr, port, addr); + TRequestStatus status; + d->nativeSocket.Connect(nativeAddr, status); + User::WaitForRequest(status); + TInt err = status.Int(); + //For non blocking connect, KErrAlreadyExists is returned from the second Connect() to indicate + //the connection is up. So treat this the same as KErrNone which would be returned from the first + //call if it wouldn't block. (e.g. winsock wrapper in the emulator ignores the nonblocking flag) + if (err && err != KErrAlreadyExists) { + switch (err) { + case KErrWouldBlock: + d->socketState = QAbstractSocket::ConnectingState; + break; + default: + d->setError(err); + d->socketState = QAbstractSocket::UnconnectedState; + break; + } + + if (d->socketState != QAbstractSocket::ConnectedState) { +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QSymbianSocketEngine::connectToHost(%s, %i) == false (%s)", + addr.toString().toLatin1().constData(), port, + d->socketState == QAbstractSocket::ConnectingState + ? "Connection in progress" : d->socketErrorString.toLatin1().constData()); +#endif + return false; + } + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QSymbianSocketEngine::Connect(%s, %i) == true", + addr.toString().toLatin1().constData(), port); +#endif + + d->socketState = QAbstractSocket::ConnectedState; + d->fetchConnectionParameters(); + return true; +} + +bool QSymbianSocketEngine::bind(const QHostAddress &address, quint16 port) +{ + Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::bind(), false); + + if (!d->checkProxy(address)) + return false; + + Q_CHECK_STATE(QSymbianSocketEngine::bind(), QAbstractSocket::UnconnectedState, false); + + TInetAddr nativeAddr; + d->setPortAndAddress(nativeAddr, port, address); + + TInt err = d->nativeSocket.Bind(nativeAddr); +#ifdef __WINS__ + if (err == KErrArgument) // winsock prt returns wrong error code + err = KErrInUse; +#endif + + if (err) { + d->setError(err); + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QSymbianSocketEngine::bind(%s, %i) == false (%s)", + address.toString().toLatin1().constData(), port, d->socketErrorString.toLatin1().constData()); +#endif + + return false; + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QSymbianSocketEngine::bind(%s, %i) == true", + address.toString().toLatin1().constData(), port); +#endif + d->socketState = QAbstractSocket::BoundState; + + d->fetchConnectionParameters(); + return true; +} + +bool QSymbianSocketEngine::listen() +{ + Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::listen(), false); + Q_CHECK_STATE(QSymbianSocketEngine::listen(), QAbstractSocket::BoundState, false); + Q_CHECK_TYPE(QSymbianSocketEngine::listen(), QAbstractSocket::TcpSocket, false); + // TODO the value 50 is from the QNativeSocketEngine. Maybe it's a bit too much + // for a mobile platform + TInt err = d->nativeSocket.Listen(50); + if (err) { + d->setError(err); + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QSymbianSocketEngine::listen() == false (%s)", + d->socketErrorString.toLatin1().constData()); +#endif + return false; + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QSymbianSocketEngine::listen() == true"); +#endif + + d->socketState = QAbstractSocket::ListeningState; + return true; +} + +int QSymbianSocketEngine::accept() +{ + Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::accept(), -1); + Q_CHECK_STATE(QSymbianSocketEngine::accept(), QAbstractSocket::ListeningState, false); + Q_CHECK_TYPE(QSymbianSocketEngine::accept(), QAbstractSocket::TcpSocket, false); + RSocket blankSocket; + blankSocket.Open(d->socketServer); + TRequestStatus status; + d->nativeSocket.Accept(blankSocket, status); + User::WaitForRequest(status); + if (status.Int()) { + blankSocket.Close(); + if (status != KErrWouldBlock) + qWarning("QSymbianSocketEngine::accept() - error %d", status.Int()); + return -1; + } + +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << "QSymbianSocketEnginePrivate::accept - created" << blankSocket.SubSessionHandle(); +#endif + int fd = QSymbianSocketManager::instance().addSocket(blankSocket); +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << " - allocated socket descriptor" << fd; +#endif + return fd; +} + +qint64 QSymbianSocketEngine::bytesAvailable() const +{ + Q_D(const QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::bytesAvailable(), -1); + Q_CHECK_NOT_STATE(QSymbianSocketEngine::bytesAvailable(), QAbstractSocket::UnconnectedState, false); + int nbytes = 0; + qint64 available = 0; + TInt err = d->nativeSocket.GetOpt(KSOReadBytesPending, KSOLSocket, nbytes); + if (err) + return 0; + available = (qint64) nbytes; + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QSymbianSocketEngine::bytesAvailable() == %lli", available); +#endif + return available; +} + +bool QSymbianSocketEngine::hasPendingDatagrams() const +{ + Q_D(const QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::hasPendingDatagrams(), false); + Q_CHECK_NOT_STATE(QSymbianSocketEngine::hasPendingDatagrams(), QAbstractSocket::UnconnectedState, false); + Q_CHECK_TYPE(QSymbianSocketEngine::hasPendingDatagrams(), QAbstractSocket::UdpSocket, false); + int nbytes; + TInt err = d->nativeSocket.GetOpt(KSOReadBytesPending,KSOLSocket, nbytes); + return err == KErrNone && nbytes > 0; +} + +qint64 QSymbianSocketEngine::pendingDatagramSize() const +{ + Q_D(const QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::pendingDatagramSize(), false); + Q_CHECK_TYPE(QSymbianSocketEngine::hasPendingDatagrams(), QAbstractSocket::UdpSocket, false); + int nbytes; + TInt err = d->nativeSocket.GetOpt(KSOReadBytesPending,KSOLSocket, nbytes); + if (nbytes > 0) { + //nbytes includes IP header, which is of variable length (IPv4 with or without options, IPv6...) + QByteArray next(nbytes,0); + TPtr8 buffer((TUint8*)next.data(), next.size()); + TInetAddr addr; + TRequestStatus status; + //TODO: rather than peek, should we save this for next call to readDatagram? + //what if calls don't match though? + d->nativeSocket.RecvFrom(buffer, addr, KSockReadPeek, status); + User::WaitForRequest(status); + if (status.Int()) + return 0; + return buffer.Length(); + } + return qint64(nbytes); +} + + +qint64 QSymbianSocketEngine::readDatagram(char *data, qint64 maxSize, + QHostAddress *address, quint16 *port) +{ + Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::readDatagram(), -1); + Q_CHECK_TYPE(QSymbianSocketEngine::readDatagram(), QAbstractSocket::UdpSocket, false); + TPtr8 buffer((TUint8*)data, (int)maxSize); + TInetAddr addr; + TRequestStatus status; + d->nativeSocket.RecvFrom(buffer, addr, 0, status); + User::WaitForRequest(status); //Non blocking receive + + if (status.Int()) { + d->setError(QAbstractSocket::NetworkError, d->ReceiveDatagramErrorString); + } else if (port || address) { + d->getPortAndAddress(addr, port, address); + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + int len = buffer.Length(); + qDebug("QSymbianSocketEngine::receiveDatagram(%p \"%s\", %lli, %s, %i) == %lli", + data, qt_prettyDebug(data, qMin(len, ssize_t(16)), len).data(), maxSize, + address ? address->toString().toLatin1().constData() : "(nil)", + port ? *port : 0, (qint64) len); +#endif + + if (status.Int()) + return -1; + return qint64(buffer.Length()); +} + + +qint64 QSymbianSocketEngine::writeDatagram(const char *data, qint64 len, + const QHostAddress &host, quint16 port) +{ + Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::writeDatagram(), -1); + Q_CHECK_TYPE(QSymbianSocketEngine::writeDatagram(), QAbstractSocket::UdpSocket, -1); + TPtrC8 buffer((TUint8*)data, (int)len); + TInetAddr addr; + d->setPortAndAddress(addr, port, host); + TSockXfrLength sentBytes; + TRequestStatus status; + d->nativeSocket.SendTo(buffer, addr, 0, status, sentBytes); + User::WaitForRequest(status); //Non blocking send + TInt err = status.Int(); + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QSymbianSocketEngine::writeDatagram(%p \"%s\", %lli, \"%s\", %i) == %lli (err=%d)", data, + qt_prettyDebug(data, qMin<int>(len, 16), len).data(), len, host.toString().toLatin1().constData(), + port, (qint64) sentBytes(), err); +#endif + + if (err) { + switch (err) { + case KErrWouldBlock: + // do not error the socket. (otherwise socket layer is reset) + // On symbian^1 and earlier, KErrWouldBlock is returned when interface is not up yet + // On symbian^3, KErrNone is returned but sentBytes = 0 + return 0; + case KErrTooBig: + d->setError(QAbstractSocket::DatagramTooLargeError, d->DatagramTooLargeErrorString); + break; + default: + d->setError(QAbstractSocket::NetworkError, d->SendDatagramErrorString); + } + return -1; + } + + if (QSysInfo::s60Version() <= QSysInfo::SV_S60_5_0) { + // This is evil hack, but for some reason native RSocket::SendTo returns 0, + // for large datagrams (such as 600 bytes). Based on comments from Open C team + // this should happen only in platforms <= S60 5.0. + return len; + } + return sentBytes(); +} + +// FIXME check where the native socket engine called that.. +bool QSymbianSocketEnginePrivate::fetchConnectionParameters() +{ + localPort = 0; + localAddress.clear(); + peerPort = 0; + peerAddress.clear(); + + if (socketDescriptor == -1) + return false; + + if (!nativeSocket.SubSessionHandle()) { + if (!QSymbianSocketManager::instance().lookupSocket(socketDescriptor, nativeSocket)) { + setError(QAbstractSocket::UnsupportedSocketOperationError, InvalidSocketErrorString); + return false; + } + } + + // Determine local address + TSockAddr addr; + nativeSocket.LocalName(addr); + getPortAndAddress(addr, &localPort, &localAddress); + + // Determine protocol family + switch (addr.Family()) { + case KAfInet: + socketProtocol = QAbstractSocket::IPv4Protocol; + break; + case KAfInet6: + socketProtocol = QAbstractSocket::IPv6Protocol; + break; + default: + socketProtocol = QAbstractSocket::UnknownNetworkLayerProtocol; + break; + } + + // Determine the remote address + nativeSocket.RemoteName(addr); + getPortAndAddress(addr, &peerPort, &peerAddress); + + // Determine the socket type (UDP/TCP) + TProtocolDesc protocol; + TInt err = nativeSocket.Info(protocol); + if (err) { + setError(err); + return false; + } else { + switch (protocol.iProtocol) { + case KProtocolInetTcp: + socketType = QAbstractSocket::TcpSocket; + break; + case KProtocolInetUdp: + socketType = QAbstractSocket::UdpSocket; + break; + default: + socketType = QAbstractSocket::UnknownSocketType; + break; + } + } +#if defined (QNATIVESOCKETENGINE_DEBUG) + QString socketProtocolStr = QLatin1String("UnknownProtocol"); + if (socketProtocol == QAbstractSocket::IPv4Protocol) socketProtocolStr = QLatin1String("IPv4Protocol"); + else if (socketProtocol == QAbstractSocket::IPv6Protocol) socketProtocolStr = QLatin1String("IPv6Protocol"); + + QString socketTypeStr = QLatin1String("UnknownSocketType"); + if (socketType == QAbstractSocket::TcpSocket) socketTypeStr = QLatin1String("TcpSocket"); + else if (socketType == QAbstractSocket::UdpSocket) socketTypeStr = QLatin1String("UdpSocket"); + + qDebug("QSymbianSocketEnginePrivate::fetchConnectionParameters() local == %s:%i," + " peer == %s:%i, socket == %s - %s", + localAddress.toString().toLatin1().constData(), localPort, + peerAddress.toString().toLatin1().constData(), peerPort,socketTypeStr.toLatin1().constData(), + socketProtocolStr.toLatin1().constData()); +#endif + return true; +} + +void QSymbianSocketEngine::close() +{ + if (!isValid()) + return; + Q_D(QSymbianSocketEngine); +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QSymbianSocketEngine::close()"); +#endif + + if (d->readNotifier) + d->readNotifier->setEnabled(false); + if (d->writeNotifier) + d->writeNotifier->setEnabled(false); + if (d->exceptNotifier) + d->exceptNotifier->setEnabled(false); + if (d->asyncSelect) { + d->asyncSelect->deleteLater(); + d->asyncSelect = 0; + } + + //TODO: call nativeSocket.Shutdown(EImmediate) in some cases? + if (d->socketType == QAbstractSocket::UdpSocket) { + //TODO: Close hangs without this, but only for UDP - why? + TRequestStatus stat; + d->nativeSocket.Shutdown(RSocket::EImmediate, stat); + User::WaitForRequest(stat); + } +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << "QSymbianSocketEngine::close - closing socket" << d->nativeSocket.SubSessionHandle() << d->socketDescriptor; +#endif + //remove must come before close to avoid a race where another thread gets the old subsession handle + //reused & asserts when calling QSymbianSocketManager::instance->addSocket + QSymbianSocketManager::instance().removeSocket(d->nativeSocket); + d->nativeSocket.Close(); + d->socketDescriptor = -1; + + d->socketState = QAbstractSocket::UnconnectedState; + d->hasSetSocketError = false; + d->localPort = 0; + d->localAddress.clear(); + d->peerPort = 0; + d->peerAddress.clear(); + if (d->readNotifier) { + qDeleteInEventHandler(d->readNotifier); + d->readNotifier = 0; + } + if (d->writeNotifier) { + qDeleteInEventHandler(d->writeNotifier); + d->writeNotifier = 0; + } + if (d->exceptNotifier) { + qDeleteInEventHandler(d->exceptNotifier); + d->exceptNotifier = 0; + } +} + +qint64 QSymbianSocketEngine::write(const char *data, qint64 len) +{ + Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::write(), -1); + Q_CHECK_STATE(QSymbianSocketEngine::write(), QAbstractSocket::ConnectedState, -1); + TPtrC8 buffer((TUint8*)data, (int)len); + TSockXfrLength sentBytes = 0; + TRequestStatus status; + d->nativeSocket.Send(buffer, 0, status, sentBytes); + User::WaitForRequest(status); //TODO: on emulator this blocks for write >16kB (non blocking IO not implemented properly?) + TInt err = status.Int(); + + if (err) { + switch (err) { + case KErrDisconnected: + case KErrEof: + sentBytes = -1; + d->setError(QAbstractSocket::RemoteHostClosedError, d->RemoteHostClosedErrorString); + close(); + break; + case KErrTooBig: + d->setError(QAbstractSocket::DatagramTooLargeError, d->DatagramTooLargeErrorString); + break; + case KErrWouldBlock: + break; + default: + sentBytes = -1; + d->setError(err); + close(); + break; + } + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QSymbianSocketEngine::write(%p \"%s\", %llu) == %i", + data, qt_prettyDebug(data, qMin((int) len, 16), + (int) len).data(), len, (int) sentBytes()); +#endif + + return qint64(sentBytes()); +} +/* +*/ +qint64 QSymbianSocketEngine::read(char *data, qint64 maxSize) +{ + Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::read(), -1); + Q_CHECK_STATES(QSymbianSocketEngine::read(), QAbstractSocket::ConnectedState, QAbstractSocket::BoundState, -1); + + TPtr8 buffer((TUint8*)data, (int)maxSize); + TSockXfrLength received = 0; + TRequestStatus status; + TSockAddr dummy; + if (d->socketType == QAbstractSocket::UdpSocket) { + //RecvOneOrMore() can only be used with stream-interfaced connected sockets; datagram interface sockets will return KErrNotSupported. + d->nativeSocket.RecvFrom(buffer, dummy, 0, status); + } else { + d->nativeSocket.RecvOneOrMore(buffer, 0, status, received); + } + User::WaitForRequest(status); //Non blocking receive + TInt err = status.Int(); + int r = buffer.Length(); + + if (err == KErrWouldBlock) { + // No data was available for reading + r = -2; + } else if (err != KErrNone) { + d->setError(err); + close(); + r = -1; + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QSymbianSocketEngine::read(%p \"%s\", %llu) == %i (err = %d)", + data, qt_prettyDebug(data, qMin(r, ssize_t(16)), r).data(), + maxSize, r, err); +#endif + + return qint64(r); +} + +int QSymbianSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const +{ + bool readyRead = false; + bool readyWrite = false; + if (selectForRead) + return nativeSelect(timeout, true, false, &readyRead, &readyWrite); + else + return nativeSelect(timeout, false, true, &readyRead, &readyWrite); +} + +/*! + \internal + \param timeout timeout in milliseconds + \param checkRead caller is interested if the socket is ready to read + \param checkWrite caller is interested if the socket is ready for write + \param selectForRead (out) should set to true if ready to read + \param selectForWrite (out) should set to true if ready to write + \return 0 on timeout, >0 on success, <0 on error + */ +int QSymbianSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite, + bool *selectForRead, bool *selectForWrite) const +{ + //cancel asynchronous notifier (only one IOCTL allowed at a time) + if (asyncSelect) + asyncSelect->Cancel(); + + TPckgBuf<TUint> selectFlags; + selectFlags() = KSockSelectExcept; + if (checkRead) + selectFlags() |= KSockSelectRead; + if (checkWrite) + selectFlags() |= KSockSelectWrite; + TRequestStatus selectStat; + nativeSocket.Ioctl(KIOctlSelect, selectStat, &selectFlags, KSOLSocket); + + if (timeout < 0) + User::WaitForRequest(selectStat); //negative means no timeout + else { + if (!selectTimer.Handle()) + qt_symbian_throwIfError(selectTimer.CreateLocal()); + TRequestStatus timerStat; + selectTimer.HighRes(timerStat, timeout * 1000); + User::WaitForRequest(timerStat, selectStat); + if (selectStat == KRequestPending) { + nativeSocket.CancelIoctl(); + //CancelIoctl completes the request (most likely with KErrCancel) + //We need to wait for this to keep the thread semaphore balanced (or active scheduler will panic) + User::WaitForRequest(selectStat); + //restart asynchronous notifier (only one IOCTL allowed at a time) + if (asyncSelect) + asyncSelect->IssueRequest(); + return 0; //timeout + } else { + selectTimer.Cancel(); + User::WaitForRequest(timerStat); + } + } + + if (selectStat != KErrNone) + return selectStat.Int(); + if (selectFlags() & KSockSelectExcept) { + TInt err; + nativeSocket.GetOpt(KSOSelectLastError, KSOLSocket, err); + //restart asynchronous notifier (only one IOCTL allowed at a time) + if (asyncSelect) + asyncSelect->IssueRequest(); //TODO: in error case should we restart or not? + return err; + } + if (checkRead && (selectFlags() & KSockSelectRead)) { + Q_ASSERT(selectForRead); + *selectForRead = true; + } + if (checkWrite && (selectFlags() & KSockSelectWrite)) { + Q_ASSERT(selectForWrite); + *selectForWrite = true; + } + //restart asynchronous notifier (only one IOCTL allowed at a time) + if (asyncSelect) + asyncSelect->IssueRequest(); + return 1; +} + +bool QSymbianSocketEngine::joinMulticastGroup(const QHostAddress &groupAddress, + const QNetworkInterface &iface) +{ + Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::joinMulticastGroup(), false); + Q_CHECK_STATE(QSymbianSocketEngine::joinMulticastGroup(), QAbstractSocket::BoundState, false); + Q_CHECK_TYPE(QSymbianSocketEngine::joinMulticastGroup(), QAbstractSocket::UdpSocket, false); + return d->multicastGroupMembershipHelper(groupAddress, iface, KSoIp6JoinGroup); +} + +bool QSymbianSocketEngine::leaveMulticastGroup(const QHostAddress &groupAddress, + const QNetworkInterface &iface) +{ + Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::leaveMulticastGroup(), false); + Q_CHECK_STATE(QSymbianSocketEngine::leaveMulticastGroup(), QAbstractSocket::BoundState, false); + Q_CHECK_TYPE(QSymbianSocketEngine::leaveMulticastGroup(), QAbstractSocket::UdpSocket, false); + return d->multicastGroupMembershipHelper(groupAddress, iface, KSoIp6LeaveGroup); +} + +bool QSymbianSocketEnginePrivate::multicastGroupMembershipHelper(const QHostAddress &groupAddress, + const QNetworkInterface &iface, + TUint operation) +{ + //TODO - untested + //translate address + TPckgBuf<TIp6Mreq> option; + Q_IPV6ADDR ip6 = groupAddress.toIPv6Address(); + memcpy(option().iAddr.u.iAddr8, ip6.c, 16); + //translate interface + //TODO - can we just use iface.index() ? + TPckgBuf<TSoInetIfQuery> query; + query().iName = qt_QString2TPtrC(iface.name()); + TInt err = nativeSocket.GetOpt(KSoInetIfQueryByName, KSolInetIfQuery, query); + if (err == KErrNone) + option().iInterface = query().iIndex; + else + option().iInterface = 0; + //join or leave group + return (KErrNone == nativeSocket.SetOpt(operation, KSolInetIp, option)); +} + +QNetworkInterface QSymbianSocketEngine::multicastInterface() const +{ + //TODO + const Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::multicastInterface(), QNetworkInterface()); + Q_CHECK_TYPE(QSymbianSocketEngine::multicastInterface(), QAbstractSocket::UdpSocket, QNetworkInterface()); + return QNetworkInterface(); +} + +bool QSymbianSocketEngine::setMulticastInterface(const QNetworkInterface &iface) +{ + //TODO - this is possibly a unix'ism as the RConnection on which the socket was created is probably controlling this + Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setMulticastInterface(), false); + Q_CHECK_TYPE(QSymbianSocketEngine::setMulticastInterface(), QAbstractSocket::UdpSocket, false); + return false; +} + +bool QSymbianSocketEnginePrivate::checkProxy(const QHostAddress &address) +{ + if (address == QHostAddress::LocalHost || address == QHostAddress::LocalHostIPv6) + return true; + +#if !defined(QT_NO_NETWORKPROXY) + QObject *parent = q_func()->parent(); + QNetworkProxy proxy; + if (QAbstractSocket *socket = qobject_cast<QAbstractSocket *>(parent)) { + proxy = socket->proxy(); + } else if (QTcpServer *server = qobject_cast<QTcpServer *>(parent)) { + proxy = server->proxy(); + } else { + // no parent -> no proxy + return true; + } + + if (proxy.type() == QNetworkProxy::DefaultProxy) + proxy = QNetworkProxy::applicationProxy(); + + if (proxy.type() != QNetworkProxy::DefaultProxy && + proxy.type() != QNetworkProxy::NoProxy) { + // QSymbianSocketEngine doesn't do proxies + setError(QAbstractSocket::UnsupportedSocketOperationError, + InvalidProxyTypeString); + return false; + } +#endif + + return true; +} + +// FIXME this is also in QNativeSocketEngine, unify it +/*! \internal + + Sets the error and error string if not set already. The only + interesting error is the first one that occurred, and not the last + one. +*/ +void QSymbianSocketEnginePrivate::setError(QAbstractSocket::SocketError error, ErrorString errorString) const +{ + if (hasSetSocketError) { + // Only set socket errors once for one engine; expect the + // socket to recreate its engine after an error. Note: There's + // one exception: SocketError(11) bypasses this as it's purely + // a temporary internal error condition. + // Another exception is the way the waitFor*() functions set + // an error when a timeout occurs. After the call to setError() + // they reset the hasSetSocketError to false + return; + } + if (error != QAbstractSocket::SocketError(11)) + hasSetSocketError = true; + + socketError = error; + + switch (errorString) { + case NonBlockingInitFailedErrorString: + socketErrorString = QSymbianSocketEngine::tr("Unable to initialize non-blocking socket"); + break; + case BroadcastingInitFailedErrorString: + socketErrorString = QSymbianSocketEngine::tr("Unable to initialize broadcast socket"); + break; + case NoIpV6ErrorString: + socketErrorString = QSymbianSocketEngine::tr("Attempt to use IPv6 socket on a platform with no IPv6 support"); + break; + case RemoteHostClosedErrorString: + socketErrorString = QSymbianSocketEngine::tr("The remote host closed the connection"); + break; + case TimeOutErrorString: + socketErrorString = QSymbianSocketEngine::tr("Network operation timed out"); + break; + case ResourceErrorString: + socketErrorString = QSymbianSocketEngine::tr("Out of resources"); + break; + case OperationUnsupportedErrorString: + socketErrorString = QSymbianSocketEngine::tr("Unsupported socket operation"); + break; + case ProtocolUnsupportedErrorString: + socketErrorString = QSymbianSocketEngine::tr("Protocol type not supported"); + break; + case InvalidSocketErrorString: + socketErrorString = QSymbianSocketEngine::tr("Invalid socket descriptor"); + break; + case HostUnreachableErrorString: + socketErrorString = QSymbianSocketEngine::tr("Host unreachable"); + break; + case NetworkUnreachableErrorString: + socketErrorString = QSymbianSocketEngine::tr("Network unreachable"); + break; + case AccessErrorString: + socketErrorString = QSymbianSocketEngine::tr("Permission denied"); + break; + case ConnectionTimeOutErrorString: + socketErrorString = QSymbianSocketEngine::tr("Connection timed out"); + break; + case ConnectionRefusedErrorString: + socketErrorString = QSymbianSocketEngine::tr("Connection refused"); + break; + case AddressInuseErrorString: + socketErrorString = QSymbianSocketEngine::tr("The bound address is already in use"); + break; + case AddressNotAvailableErrorString: + socketErrorString = QSymbianSocketEngine::tr("The address is not available"); + break; + case AddressProtectedErrorString: + socketErrorString = QSymbianSocketEngine::tr("The address is protected"); + break; + case DatagramTooLargeErrorString: + socketErrorString = QSymbianSocketEngine::tr("Datagram was too large to send"); + break; + case SendDatagramErrorString: + socketErrorString = QSymbianSocketEngine::tr("Unable to send a message"); + break; + case ReceiveDatagramErrorString: + socketErrorString = QSymbianSocketEngine::tr("Unable to receive a message"); + break; + case WriteErrorString: + socketErrorString = QSymbianSocketEngine::tr("Unable to write"); + break; + case ReadErrorString: + socketErrorString = QSymbianSocketEngine::tr("Network error"); + break; + case PortInuseErrorString: + socketErrorString = QSymbianSocketEngine::tr("Another socket is already listening on the same port"); + break; + case NotSocketErrorString: + socketErrorString = QSymbianSocketEngine::tr("Operation on non-socket"); + break; + case InvalidProxyTypeString: + socketErrorString = QSymbianSocketEngine::tr("The proxy type is invalid for this operation"); + break; + case InvalidAddressErrorString: + socketErrorString = QSymbianSocketEngine::tr("The address is invalid for this operation"); + break; + case SessionNotOpenErrorString: + socketErrorString = QSymbianSocketEngine::tr("The specified network session is not opened"); + break; + case UnknownSocketErrorString: + socketErrorString = QSymbianSocketEngine::tr("Unknown error"); + break; + } +} + +void QSymbianSocketEnginePrivate::setError(TInt symbianError) +{ + switch (symbianError) { + case KErrDisconnected: + case KErrEof: + setError(QAbstractSocket::RemoteHostClosedError, + QSymbianSocketEnginePrivate::RemoteHostClosedErrorString); + break; + case KErrNetUnreach: + setError(QAbstractSocket::NetworkError, + QSymbianSocketEnginePrivate::NetworkUnreachableErrorString); + break; + case KErrHostUnreach: + setError(QAbstractSocket::NetworkError, + QSymbianSocketEnginePrivate::HostUnreachableErrorString); + break; + case KErrNoProtocolOpt: + setError(QAbstractSocket::NetworkError, + QSymbianSocketEnginePrivate::ProtocolUnsupportedErrorString); + break; + case KErrInUse: + setError(QAbstractSocket::AddressInUseError, AddressInuseErrorString); + break; + case KErrPermissionDenied: + setError(QAbstractSocket::SocketAccessError, AccessErrorString); + break; + case KErrNotSupported: + setError(QAbstractSocket::UnsupportedSocketOperationError, OperationUnsupportedErrorString); + break; + case KErrNoMemory: + setError(QAbstractSocket::SocketResourceError, ResourceErrorString); + break; + case KErrCouldNotConnect: + setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString); + break; + case KErrTimedOut: + setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString); + break; + case KErrBadName: + setError(QAbstractSocket::NetworkError, InvalidAddressErrorString); + break; + default: + socketError = QAbstractSocket::NetworkError; + socketErrorString = QSystemError(symbianError, QSystemError::NativeError).toString(); + break; + } + hasSetSocketError = true; +} + +class QReadNotifier : public QSocketNotifier +{ + friend class QAsyncSelect; +public: + QReadNotifier(int fd, QSymbianSocketEngine *parent) + : QSocketNotifier(fd, QSocketNotifier::Read, parent) + { engine = parent; } +protected: + bool event(QEvent *); + + QSymbianSocketEngine *engine; +}; + +bool QReadNotifier::event(QEvent *e) +{ + if (e->type() == QEvent::SockAct) { + engine->readNotification(); + return true; + } + return QSocketNotifier::event(e); +} + +bool QSymbianSocketEngine::isReadNotificationEnabled() const +{ + Q_D(const QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::isReadNotificationEnabled(), false); + return d->readNotifier && d->readNotifier->isEnabled(); +} + +void QSymbianSocketEngine::setReadNotificationEnabled(bool enable) +{ + Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setReadNotificationEnabled(), Q_VOID); + if (d->readNotifier) { + d->readNotifier->setEnabled(enable); + } else if (enable && d->threadData->eventDispatcher) { + QReadNotifier *rn = new QReadNotifier(d->socketDescriptor, this); + d->readNotifier = rn; + if (!d->asyncSelect) + d->asyncSelect = q_check_ptr(new QAsyncSelect(0, d->nativeSocket, this)); + d->asyncSelect->setReadNotifier(rn); + d->readNotifier->setEnabled(true); + } + // TODO: what do we do if event dispatcher doesn't exist yet? + if (d->asyncSelect) + d->asyncSelect->IssueRequest(); +} + + +class QWriteNotifier : public QSocketNotifier +{ + friend class QAsyncSelect; +public: + QWriteNotifier(int fd, QSymbianSocketEngine *parent) + : QSocketNotifier(fd, QSocketNotifier::Write, parent) + { engine = parent; } +protected: + bool event(QEvent *); + + QSymbianSocketEngine *engine; +}; + +bool QWriteNotifier::event(QEvent *e) +{ + if (e->type() == QEvent::SockAct) { + if (engine->state() == QAbstractSocket::ConnectingState) + engine->connectionNotification(); + else + engine->writeNotification(); + return true; + } + return QSocketNotifier::event(e); +} + +bool QSymbianSocketEngine::isWriteNotificationEnabled() const +{ + Q_D(const QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::isWriteNotificationEnabled(), false); + return d->writeNotifier && d->writeNotifier->isEnabled(); +} + +void QSymbianSocketEngine::setWriteNotificationEnabled(bool enable) +{ + Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setWriteNotificationEnabled(), Q_VOID); + if (d->writeNotifier) { + d->writeNotifier->setEnabled(enable); + } else if (enable && d->threadData->eventDispatcher) { + QWriteNotifier *wn = new QWriteNotifier(d->socketDescriptor, this); + d->writeNotifier = wn; + if (!(d->asyncSelect)) + d->asyncSelect = q_check_ptr(new QAsyncSelect(d->threadData->eventDispatcher, d->nativeSocket, this)); + d->asyncSelect->setWriteNotifier(wn); + d->writeNotifier->setEnabled(true); + } + // TODO: what do we do if event dispatcher doesn't exist yet? + if (d->asyncSelect) + d->asyncSelect->IssueRequest(); +} + +class QExceptionNotifier : public QSocketNotifier +{ + friend class QAsyncSelect; +public: + QExceptionNotifier(int fd, QSymbianSocketEngine *parent) + : QSocketNotifier(fd, QSocketNotifier::Exception, parent) { engine = parent; } + +protected: + bool event(QEvent *); + + QSymbianSocketEngine *engine; +}; + +bool QExceptionNotifier::event(QEvent *e) +{ + if (e->type() == QEvent::SockAct) { + if (engine->state() == QAbstractSocket::ConnectingState) + engine->connectionNotification(); + else + engine->exceptionNotification(); + return true; + } + return QSocketNotifier::event(e); +} + +bool QSymbianSocketEngine::isExceptionNotificationEnabled() const +{ + Q_D(const QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::isExceptionNotificationEnabled(), false); + return d->exceptNotifier && d->exceptNotifier->isEnabled(); + return false; +} + +// FIXME do we really need this for symbian? +void QSymbianSocketEngine::setExceptionNotificationEnabled(bool enable) +{ + Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setExceptionNotificationEnabled(), Q_VOID); + if (d->exceptNotifier) { + d->exceptNotifier->setEnabled(enable); + } else if (enable && d->threadData->eventDispatcher) { + QExceptionNotifier *en = new QExceptionNotifier(d->socketDescriptor, this); + d->exceptNotifier = en; + if (!(d->asyncSelect)) + d->asyncSelect = q_check_ptr(new QAsyncSelect(d->threadData->eventDispatcher, d->nativeSocket, this)); + d->asyncSelect->setExceptionNotifier(en); + d->writeNotifier->setEnabled(true); + } + if (d->asyncSelect) + d->asyncSelect->IssueRequest(); +} + +bool QSymbianSocketEngine::waitForRead(int msecs, bool *timedOut) +{ + Q_D(const QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::waitForRead(), false); + Q_CHECK_NOT_STATE(QSymbianSocketEngine::waitForRead(), + QAbstractSocket::UnconnectedState, false); + + if (timedOut) + *timedOut = false; + + int ret = d->nativeSelect(msecs, true); + if (ret == 0) { + if (timedOut) + *timedOut = true; + d->setError(QAbstractSocket::SocketTimeoutError, + d->TimeOutErrorString); + d->hasSetSocketError = false; // A timeout error is temporary in waitFor functions + return false; + } else if (state() == QAbstractSocket::ConnectingState) { + connectToHost(d->peerAddress, d->peerPort); + } + + return ret > 0; +} + +bool QSymbianSocketEngine::waitForWrite(int msecs, bool *timedOut) +{ + Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::waitForWrite(), false); + Q_CHECK_NOT_STATE(QSymbianSocketEngine::waitForWrite(), + QAbstractSocket::UnconnectedState, false); + + if (timedOut) + *timedOut = false; + + int ret = d->nativeSelect(msecs, false); + + if (ret == 0) { + if (timedOut) + *timedOut = true; + d->setError(QAbstractSocket::SocketTimeoutError, + d->TimeOutErrorString); + d->hasSetSocketError = false; // A timeout error is temporary in waitFor functions + return false; + } else if (state() == QAbstractSocket::ConnectingState) { + connectToHost(d->peerAddress, d->peerPort); + } + + return ret > 0; +} + +bool QSymbianSocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite, + bool checkRead, bool checkWrite, + int msecs, bool *timedOut) +{ + Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::waitForWrite(), false); + Q_CHECK_NOT_STATE(QSymbianSocketEngine::waitForReadOrWrite(), + QAbstractSocket::UnconnectedState, false); + + int ret = d->nativeSelect(msecs, checkRead, checkWrite, readyToRead, readyToWrite); + + if (ret == 0) { + if (timedOut) + *timedOut = true; + d->setError(QAbstractSocket::SocketTimeoutError, + d->TimeOutErrorString); + d->hasSetSocketError = false; // A timeout error is temporary in waitFor functions + return false; + } else if (state() == QAbstractSocket::ConnectingState) { + connectToHost(d->peerAddress, d->peerPort); + } + + return ret > 0; +} + +qint64 QSymbianSocketEngine::bytesToWrite() const +{ + // This is what the QNativeSocketEngine does + return 0; +} + +//TODO: is defining PostThreadChangeEvent as QEvent::User + 1 safe? +//TODO: would QMetaObject::invokeMethod(obj, "postThreadChangeSlot", Qt::QueuedConnection) be better? +//TODO: if QTBUG-16787 is implemented, use that instead +bool QSymbianSocketEngine::event(QEvent* ev) +{ + Q_D(QSymbianSocketEngine); + switch (ev->type()) { + case QEvent::ThreadChange: + if (d->asyncSelect) { + delete d->asyncSelect; + d->asyncSelect = 0; + QEvent *postThreadChangeEvent = new QEvent(PostThreadChangeEvent); + QCoreApplication::postEvent(this, postThreadChangeEvent); + } + return true; + case PostThreadChangeEvent: + // recreate select in new thread + d->asyncSelect = q_check_ptr(new QAsyncSelect(0, d->nativeSocket, this)); + if (d->readNotifier) { + d->asyncSelect->setReadNotifier(static_cast<QReadNotifier*>(d->readNotifier)); + setReadNotificationEnabled(d->readNotifier->isEnabled()); + } + if (d->writeNotifier) { + d->asyncSelect->setWriteNotifier(static_cast<QWriteNotifier*>(d->writeNotifier)); + setReadNotificationEnabled(d->writeNotifier->isEnabled()); + } + if (d->exceptNotifier) { + d->asyncSelect->setExceptionNotifier(static_cast<QExceptionNotifier*>(d->exceptNotifier)); + setReadNotificationEnabled(d->exceptNotifier->isEnabled()); + } + return true; + } + return QAbstractSocketEngine::event(ev); +} + +QAsyncSelect::QAsyncSelect(QAbstractEventDispatcher *dispatcher, RSocket& sock, QSymbianSocketEngine *parent) + : CActive(CActive::EPriorityStandard), + m_inSocketEvent(false), + m_deleteLater(false), + m_socket(sock), + m_selectFlags(0), + engine(parent) +{ + CActiveScheduler::Add(this); +} + +QAsyncSelect::~QAsyncSelect() +{ + Cancel(); +} + +void QAsyncSelect::DoCancel() +{ + m_socket.CancelIoctl(); +} + +void QAsyncSelect::RunL() +{ + QT_TRYCATCH_LEAVING(run()); +} + +//RunError is called by the active scheduler if RunL leaves. +//Typically this will happen if a std::bad_alloc propagates down from the application +TInt QAsyncSelect::RunError(TInt aError) +{ + if (engine) { + QT_TRY { + engine->d_func()->setError(aError); + QEvent e(QEvent::SockAct); + if (iExcN) + iExcN->event(&e); + if (iReadN) + iReadN->event(&e); + } + QT_CATCH(...) {} + } +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << "QAsyncSelect::RunError" << aError; +#endif + return KErrNone; +} + +void QAsyncSelect::run() +{ + //TODO: block when event loop demands it + //if (maybeQueueForLater()) + // return; + m_inSocketEvent = true; + m_selectBuf() &= m_selectFlags; //the select ioctl reports everything, so mask to only what we requested + //KSockSelectReadContinuation is for reading datagrams in a mode that doesn't discard when the + //datagram is larger than the read buffer - Qt doesn't need to use this. + if (iReadN && ((m_selectBuf() & KSockSelectRead) || iStatus != KErrNone)) { + QEvent e(QEvent::SockAct); + iReadN->event(&e); + } + if (iWriteN && ((m_selectBuf() & KSockSelectWrite) || iStatus != KErrNone)) { + QEvent e(QEvent::SockAct); + iWriteN->event(&e); + } + if (iExcN && ((m_selectBuf() & KSockSelectExcept) || iStatus != KErrNone)) { + QEvent e(QEvent::SockAct); + iExcN->event(&e); + } + m_inSocketEvent = false; + if (m_deleteLater) { + delete this; + return; + } + // select again (unless disabled by one of the callbacks) + IssueRequest(); +} + +void QAsyncSelect::deleteLater() +{ + if (m_inSocketEvent) { + iExcN = 0; + iReadN = 0; + iWriteN = 0; + engine = 0; + m_deleteLater = true; + } else { + delete this; + } +} + +void QAsyncSelect::IssueRequest() +{ + if (m_inSocketEvent) + return; //prevent thrashing during a callback - socket engine enables/disables multiple notifiers + TUint selectFlags = 0; + if (iReadN && iReadN->isEnabled()) + selectFlags |= KSockSelectRead; + if (iWriteN && iWriteN->isEnabled()) + selectFlags |= KSockSelectWrite; + if (iExcN && iExcN->isEnabled()) + selectFlags |= KSockSelectExcept; + if (selectFlags != m_selectFlags) { + Cancel(); + m_selectFlags = selectFlags; + } + if (m_selectFlags && !IsActive()) { + //always request errors (write notification does not complete on connect errors) + m_selectBuf() = m_selectFlags | KSockSelectExcept; + m_socket.Ioctl(KIOctlSelect, iStatus, &m_selectBuf, KSOLSocket); + SetActive(); + } +} + +QT_END_NAMESPACE diff --git a/src/network/socket/qsymbiansocketengine_p.h b/src/network/socket/qsymbiansocketengine_p.h new file mode 100644 index 0000000..bc39450 --- /dev/null +++ b/src/network/socket/qsymbiansocketengine_p.h @@ -0,0 +1,261 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QSYMBIANSOCKETENGINE_P_H +#define QSYMBIANSOCKETENGINE_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 "QtNetwork/qhostaddress.h" +#include "private/qabstractsocketengine_p.h" +#include "qplatformdefs.h" + +#include <private/qeventdispatcher_symbian_p.h> +#include <unistd.h> +#include <es_sock.h> +#include <in_sock.h> + +QT_BEGIN_NAMESPACE + + +class QSymbianSocketEnginePrivate; +class QNetworkInterface; + +class Q_AUTOTEST_EXPORT QSymbianSocketEngine : public QAbstractSocketEngine +{ + Q_OBJECT + friend class QAsyncSelect; +public: + QSymbianSocketEngine(QObject *parent = 0); + ~QSymbianSocketEngine(); + + bool initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::IPv4Protocol); + bool initialize(int socketDescriptor, QAbstractSocket::SocketState socketState = QAbstractSocket::ConnectedState); + + int socketDescriptor() const; + + bool isValid() const; + + bool connectToHost(const QHostAddress &address, quint16 port); + bool connectToHostByName(const QString &name, quint16 port); + bool bind(const QHostAddress &address, quint16 port); + bool listen(); + int accept(); + void close(); + + bool joinMulticastGroup(const QHostAddress &groupAddress, + const QNetworkInterface &iface); + bool leaveMulticastGroup(const QHostAddress &groupAddress, + const QNetworkInterface &iface); + QNetworkInterface multicastInterface() const; + bool setMulticastInterface(const QNetworkInterface &iface); + + qint64 bytesAvailable() const; + + qint64 read(char *data, qint64 maxlen); + qint64 write(const char *data, qint64 len); + + qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *addr = 0, + quint16 *port = 0); + qint64 writeDatagram(const char *data, qint64 len, const QHostAddress &addr, + quint16 port); + bool hasPendingDatagrams() const; + qint64 pendingDatagramSize() const; + + qint64 bytesToWrite() const; + + qint64 receiveBufferSize() const; + void setReceiveBufferSize(qint64 bufferSize); + + qint64 sendBufferSize() const; + void setSendBufferSize(qint64 bufferSize); + + int option(SocketOption option) const; + bool setOption(SocketOption option, int value); + + bool waitForRead(int msecs = 30000, bool *timedOut = 0); + bool waitForWrite(int msecs = 30000, bool *timedOut = 0); + bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite, + bool checkRead, bool checkWrite, + int msecs = 30000, bool *timedOut = 0); + + bool isReadNotificationEnabled() const; + void setReadNotificationEnabled(bool enable); + bool isWriteNotificationEnabled() const; + void setWriteNotificationEnabled(bool enable); + bool isExceptionNotificationEnabled() const; + void setExceptionNotificationEnabled(bool enable); + + bool event(QEvent* ev); + + static const QEvent::Type PostThreadChangeEvent = (QEvent::Type)(QEvent::User + 1); + +public Q_SLOTS: + // TODO: Why do we do this? This is private Qt implementation stuff anyway, no need for it + // non-virtual override; + void connectionNotification(); + +private: + Q_DECLARE_PRIVATE(QSymbianSocketEngine) + Q_DISABLE_COPY(QSymbianSocketEngine) +}; + +class QSocketNotifier; + +class QReadNotifier; +class QWriteNotifier; +class QExceptionNotifier; +class QAsyncSelect : public CActive +{ +public: + QAsyncSelect(QAbstractEventDispatcher *dispatcher, RSocket& sock, QSymbianSocketEngine *parent); + ~QAsyncSelect(); + + void deleteLater(); + void IssueRequest(); + + void refresh(); + + void setReadNotifier(QReadNotifier *rn) { iReadN = rn; } + void setWriteNotifier(QWriteNotifier *wn) { iWriteN = wn; } + void setExceptionNotifier(QExceptionNotifier *en) { iExcN = en; } + +protected: + void DoCancel(); + void RunL(); + void run(); + TInt RunError(TInt aError); + +private: + QReadNotifier* iReadN; + QWriteNotifier* iWriteN; + QExceptionNotifier* iExcN; + bool m_inSocketEvent; + bool m_deleteLater; + RSocket &m_socket; + + TUint m_selectFlags; + TPckgBuf<TUint> m_selectBuf; //in & out IPC buffer + QSymbianSocketEngine *engine; +}; + +class QSymbianSocketEnginePrivate : public QAbstractSocketEnginePrivate +{ + Q_DECLARE_PUBLIC(QSymbianSocketEngine) +public: + QSymbianSocketEnginePrivate(); + ~QSymbianSocketEnginePrivate(); + + int socketDescriptor; + mutable RSocket nativeSocket; + // From QtCore: + RSocketServ& socketServer; + mutable RTimer selectTimer; + + QSocketNotifier *readNotifier, *writeNotifier, *exceptNotifier; + QAsyncSelect* asyncSelect; + + // FIXME this is duplicated from qnativesocketengine_p.h + enum ErrorString { + NonBlockingInitFailedErrorString, + BroadcastingInitFailedErrorString, + NoIpV6ErrorString, + RemoteHostClosedErrorString, + TimeOutErrorString, + ResourceErrorString, + OperationUnsupportedErrorString, + ProtocolUnsupportedErrorString, + InvalidSocketErrorString, + HostUnreachableErrorString, + NetworkUnreachableErrorString, + AccessErrorString, + ConnectionTimeOutErrorString, + ConnectionRefusedErrorString, + AddressInuseErrorString, + AddressNotAvailableErrorString, + AddressProtectedErrorString, + DatagramTooLargeErrorString, + SendDatagramErrorString, + ReceiveDatagramErrorString, + WriteErrorString, + ReadErrorString, + PortInuseErrorString, + NotSocketErrorString, + InvalidProxyTypeString, + //symbian specific + InvalidAddressErrorString, + SessionNotOpenErrorString, + + UnknownSocketErrorString = -1 + }; + void setError(QAbstractSocket::SocketError error, ErrorString errorString) const; + + void getPortAndAddress(const TInetAddr& a, quint16 *port, QHostAddress *addr); + void setPortAndAddress(TInetAddr& nativeAddr, quint16 port, const QHostAddress &addr); + void setError(TInt symbianError); + + int nativeSelect(int timeout, bool selectForRead) const; + int nativeSelect(int timeout, bool checkRead, bool checkWrite, + bool *selectForRead, bool *selectForWrite) const; + + bool createNewSocket(QAbstractSocket::SocketType socketType, + QAbstractSocket::NetworkLayerProtocol socketProtocol); + + bool checkProxy(const QHostAddress &address); + bool fetchConnectionParameters(); + + bool multicastGroupMembershipHelper(const QHostAddress &groupAddress, + const QNetworkInterface &iface, + TUint operation); + static bool translateSocketOption(QAbstractSocketEngine::SocketOption opt, TUint &n, TUint &level); +}; + +QT_END_NAMESPACE + +#endif // QSYMBIANSOCKETENGINE_P_H diff --git a/src/network/socket/qtcpserver.cpp b/src/network/socket/qtcpserver.cpp index 98c05dd..6b012db 100644 --- a/src/network/socket/qtcpserver.cpp +++ b/src/network/socket/qtcpserver.cpp @@ -105,7 +105,7 @@ #include "qhostaddress.h" #include "qlist.h" #include "qpointer.h" -#include "qnativesocketengine_p.h" +#include "qabstractsocketengine_p.h" #include "qtcpserver.h" #include "qtcpsocket.h" #include "qnetworkproxy.h" @@ -287,6 +287,10 @@ bool QTcpServer::listen(const QHostAddress &address, quint16 port) delete d->socketEngine; d->socketEngine = QAbstractSocketEngine::createSocketEngine(QAbstractSocket::TcpSocket, proxy, this); +#ifndef QT_NO_BEARERMANAGEMENT + //copy network session down to the socket engine (if it has been set) + d->socketEngine->setProperty("_q_networksession", property("_q_networksession")); +#endif if (!d->socketEngine) { d->serverSocketError = QAbstractSocket::UnsupportedSocketOperationError; d->serverSocketErrorString = tr("Operation on socket is not supported"); @@ -412,6 +416,10 @@ bool QTcpServer::setSocketDescriptor(int socketDescriptor) if (d->socketEngine) delete d->socketEngine; d->socketEngine = QAbstractSocketEngine::createSocketEngine(socketDescriptor, this); +#ifndef QT_NO_BEARERMANAGEMENT + //copy network session down to the socket engine (if it has been set) + d->socketEngine->setProperty("_q_networksession", property("_q_networksession")); +#endif if (!d->socketEngine->initialize(socketDescriptor, QAbstractSocket::ListeningState)) { d->serverSocketError = d->socketEngine->error(); d->serverSocketErrorString = d->socketEngine->errorString(); diff --git a/src/network/socket/qudpsocket.cpp b/src/network/socket/qudpsocket.cpp index 6a62b12..4334f68 100644 --- a/src/network/socket/qudpsocket.cpp +++ b/src/network/socket/qudpsocket.cpp @@ -504,16 +504,6 @@ qint64 QUdpSocket::writeDatagram(const char *data, qint64 size, const QHostAddre return -1; qint64 sent = d->socketEngine->writeDatagram(data, size, address, port); -#ifdef Q_OS_SYMBIAN - if( QSysInfo::s60Version() <= QSysInfo::SV_S60_5_0 ) { - // This is evil hack, but for some reason native RSocket::SendTo returns 0, - // for large datagrams (such as 600 bytes). Based on comments from Open C team - // this should happen only in platforms <= S60 5.0. - // As an workaround, we just set sent = size - if( sent == 0 ) - sent = size; - } -#endif d->cachedSocketDescriptor = d->socketEngine->socketDescriptor(); if (sent >= 0) { diff --git a/src/network/socket/socket.pri b/src/network/socket/socket.pri index f2262fe..32be429 100644 --- a/src/network/socket/socket.pri +++ b/src/network/socket/socket.pri @@ -1,7 +1,6 @@ # Qt network socket HEADERS += socket/qabstractsocketengine_p.h \ - socket/qnativesocketengine_p.h \ socket/qhttpsocketengine_p.h \ socket/qsocks5socketengine_p.h \ socket/qabstractsocket.h \ @@ -15,7 +14,6 @@ HEADERS += socket/qabstractsocketengine_p.h \ socket/qlocalsocket_p.h SOURCES += socket/qabstractsocketengine.cpp \ - socket/qnativesocketengine.cpp \ socket/qhttpsocketengine.cpp \ socket/qsocks5socketengine.cpp \ socket/qabstractsocket.cpp \ @@ -25,11 +23,26 @@ SOURCES += socket/qabstractsocketengine.cpp \ socket/qlocalsocket.cpp \ socket/qlocalserver.cpp -unix:!symbian:SOURCES += socket/qnativesocketengine_unix.cpp -symbian:SOURCES += socket/qnativesocketengine_symbian.cpp -unix:SOURCES += \ +# On Symbian we use QSymbianSocketEngine +symbian:SOURCES += socket/qsymbiansocketengine.cpp +symbian:HEADERS += socket/qsymbiansocketengine_p.h +# On others we use QNativeSocketEngine +!symbian:SOURCES += socket/qnativesocketengine.cpp +!symbian:HEADERS += socket/qnativesocketengine_p.h + +unix:!symbian: { + SOURCES += socket/qnativesocketengine_unix.cpp \ socket/qlocalsocket_unix.cpp \ socket/qlocalserver_unix.cpp +} + +symbian: { + SOURCES += socket/qlocalsocket_tcp.cpp \ + socket/qlocalserver_tcp.cpp + + DEFINES += QT_LOCALSOCKET_TCP +} + unix:HEADERS += \ socket/qnet_unix_p.h diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index 224ed67..827f0bb 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -2048,6 +2048,10 @@ void QSslSocketPrivate::createPlainSocket(QIODevice::OpenMode openMode) q->setPeerName(QString()); plainSocket = new QTcpSocket(q); +#ifndef QT_NO_BEARERMANAGEMENT + //copy network session down to the plain socket (if it has been set) + plainSocket->setProperty("_q_networksession", q->property("_q_networksession")); +#endif q->connect(plainSocket, SIGNAL(connected()), q, SLOT(_q_connectedSlot()), Qt::DirectConnection); |