diff options
Diffstat (limited to 'src/network/socket/qsymbiansocketengine.cpp')
-rw-r--r-- | src/network/socket/qsymbiansocketengine.cpp | 1770 |
1 files changed, 0 insertions, 1770 deletions
diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp deleted file mode 100644 index f8831d3b45..0000000000 --- a/src/network/socket/qsymbiansocketengine.cpp +++ /dev/null @@ -1,1770 +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$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $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 <private/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 <private/qeventdispatcher_symbian_p.h> -#include <qsocketnotifier.h> -#include <qnetworkinterface.h> - -#include <private/qthread_p.h> -#include <private/qobject_p.h> -#include <private/qsystemerror_p.h> - -#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 && !a.IsV4Compat() && !a.IsV4Mapped()) { - 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 - QVariant v(q->property("_q_networksession")); - TInt err; - if (v.isValid()) { - QSharedPointer<QNetworkSession> s = qvariant_cast<QSharedPointer<QNetworkSession> >(v); - err = QNetworkSessionPrivate::nativeOpenSocket(*s, nativeSocket, family, type, protocol); -#ifdef QNATIVESOCKETENGINE_DEBUG - qDebug() << "QSymbianSocketEnginePrivate::createNewSocket - _q_networksession was set" << err; -#endif - } 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.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()), - readNotificationsEnabled(false), - writeNotificationsEnabled(false), - exceptNotificationsEnabled(false), - asyncSelect(0), - hasReceivedBufferedDatagram(false) -{ -} - -QSymbianSocketEnginePrivate::~QSymbianSocketEnginePrivate() -{ -} - - -QSymbianSocketEngine::QSymbianSocketEngine(QObject *parent) - : QAbstractSocketEngine(*new QSymbianSocketEnginePrivate(), parent) -{ -} - - -QSymbianSocketEngine::~QSymbianSocketEngine() -{ - close(); -} - -/*! - 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; - if (address == QHostAddress::Any || address == QHostAddress::AnyIPv6) { - //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); - nativeAddr.SetPort(port); - } else { - 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) { - switch (err) { - case KErrNotFound: - // the specified interface was not found - use the error code expected - d->setError(QAbstractSocket::SocketAddressNotAvailableError, QSymbianSocketEnginePrivate::AddressNotAvailableErrorString); - break; - default: - d->setError(err); - break; - } - -#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(); - - // When we bind to unspecified address (to get a dual mode socket), report back the - // same type of address that was requested. This is required for SOCKS proxy to work. - if (nativeAddr.Family() == KAFUnspec) - d->localAddress = address; - 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); - 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); - //can only buffer one datagram at a time - if (d->hasReceivedBufferedDatagram) - return d->receivedDataBuffer.size(); - int nbytes = 0; - 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...) - //therefore read the datagram into a buffer to find its true size - d->receivedDataBuffer.resize(nbytes); - TPtr8 buffer((TUint8*)d->receivedDataBuffer.data(), nbytes); - //nbytes = size including IP header, buffer is a pointer descriptor backed by the receivedDataBuffer - TInetAddr addr; - TRequestStatus status; - //RecvFrom copies only the payload (we don't want the header so don't specify the option to retrieve it) - d->nativeSocket.RecvFrom(buffer, addr, 0, status); - User::WaitForRequest(status); - if (status != KErrNone) { - d->receivedDataBuffer.clear(); - return 0; - } - nbytes = buffer.Length(); - //nbytes = size of payload, resize the receivedDataBuffer to the final size - d->receivedDataBuffer.resize(nbytes); - d->hasReceivedBufferedDatagram = true; - //now receivedDataBuffer contains one datagram, which has been removed from the socket's internal buffer -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug() << "QSymbianSocketEngine::pendingDatagramSize buffering" << nbytes << "bytes"; -#endif - } - 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); - - // if a datagram was buffered in pendingDatagramSize(), return it now - if (d->hasReceivedBufferedDatagram) { - qint64 size = qMin(maxSize, (qint64)d->receivedDataBuffer.size()); - memcpy(data, d->receivedDataBuffer.constData(), size); - d->receivedDataBuffer.clear(); - d->hasReceivedBufferedDatagram = false; -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug() << "QSymbianSocketEngine::readDatagram returning" << size << "bytes from buffer"; -#endif - return size; - } - - 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 - socketProtocol = localAddress.protocol(); - - // 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 - - d->readNotificationsEnabled = false; - d->writeNotificationsEnabled = false; - d->exceptNotificationsEnabled = 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(); - - d->hasReceivedBufferedDatagram = false; - d->receivedDataBuffer.clear(); -} - -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); - - // if a datagram was buffered in pendingDatagramSize(), return it now - if (d->hasReceivedBufferedDatagram) { - qint64 size = qMin(maxSize, (qint64)d->receivedDataBuffer.size()); - memcpy(data, d->receivedDataBuffer.constData(), size); - d->receivedDataBuffer.clear(); - d->hasReceivedBufferedDatagram = false; -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug() << "QSymbianSocketEngine::read returning" << size << "bytes from buffer"; -#endif - return size; - } - - 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; - TInt err; - if (timeout == 0) { - //if timeout is zero, poll - err = nativeSocket.GetOpt(KSOSelectPoll, KSOLSocket, selectFlags); - } else { - 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(); - #ifdef QNATIVESOCKETENGINE_DEBUG - qDebug() << "QSymbianSocketEnginePrivate::nativeSelect: select timeout"; - #endif - return 0; //timeout - } else { - selectTimer.Cancel(); - User::WaitForRequest(timerStat); - } - } - - #ifdef QNATIVESOCKETENGINE_DEBUG - qDebug() << "QSymbianSocketEnginePrivate::nativeSelect: select status" << selectStat.Int() << (int)selectFlags(); - #endif - err = selectStat.Int(); - } - - if (!err && (selectFlags() & KSockSelectExcept)) { - nativeSocket.GetOpt(KSOSelectLastError, KSOLSocket, err); -#ifdef QNATIVESOCKETENGINE_DEBUG - qDebug() << "QSymbianSocketEnginePrivate::nativeSelect: select last error" << err; -#endif - } - if (err) { - //TODO: avoidable cast? - //set the error here, because read won't always return the same error again as select. - const_cast<QSymbianSocketEnginePrivate*>(this)->setError(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) -{ -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug() << "QSymbianSocketEnginePrivate::multicastGroupMembershipHelper" << groupAddress << iface << operation; -#endif - //translate address - TPckgBuf<TIp6Mreq> option; - if (groupAddress.protocol() == QAbstractSocket::IPv6Protocol) { - Q_IPV6ADDR ip6 = groupAddress.toIPv6Address(); - memcpy(option().iAddr.u.iAddr8, ip6.c, 16); - } else { - TInetAddr wrapped; - wrapped.SetAddress(groupAddress.toIPv4Address()); - wrapped.ConvertToV4Mapped(); - option().iAddr = wrapped.Ip6Address(); - } - option().iInterface = iface.index(); - //join or leave group - TInt err = nativeSocket.SetOpt(operation, KSolInetIp, option); -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug() << "address" << qt_prettyDebug((const char *)(option().iAddr.u.iAddr8), 16, 16); - qDebug() << "interface" << option().iInterface; - qDebug() << "error" << err; -#endif - if (err) { - setError(err); - } - return (KErrNone == err); -} - -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.isLoopback()) - 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: - case KErrConnectionTerminated: //interface stopped externally - RConnection::Stop(EStopAuthoritative) - 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; -} - -void QSymbianSocketEngine::startNotifications() -{ - Q_D(QSymbianSocketEngine); -#ifdef QNATIVESOCKETENGINE_DEBUG - qDebug() << "QSymbianSocketEngine::startNotifications" << d->readNotificationsEnabled << d->writeNotificationsEnabled << d->exceptNotificationsEnabled; -#endif - if (!d->asyncSelect && (d->readNotificationsEnabled || d->writeNotificationsEnabled || d->exceptNotificationsEnabled)) { - Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::startNotifications(), Q_VOID); - if (d->threadData->eventDispatcher) { - d->asyncSelect = q_check_ptr(new QAsyncSelect( - static_cast<QEventDispatcherSymbian*> (d->threadData->eventDispatcher), d->nativeSocket, - this)); - } else { - // call again when event dispatcher has been created - QMetaObject::invokeMethod(this, "startNotifications", Qt::QueuedConnection); - } - } - if (d->asyncSelect) - d->asyncSelect->IssueRequest(); -} - -bool QSymbianSocketEngine::isReadNotificationEnabled() const -{ - Q_D(const QSymbianSocketEngine); - return d->readNotificationsEnabled; -} - -void QSymbianSocketEngine::setReadNotificationEnabled(bool enable) -{ - Q_D(QSymbianSocketEngine); -#ifdef QNATIVESOCKETENGINE_DEBUG - qDebug() << "QSymbianSocketEngine::setReadNotificationEnabled" << enable << "socket" << d->socketDescriptor; -#endif - d->readNotificationsEnabled = enable; - startNotifications(); -} - -bool QSymbianSocketEngine::isWriteNotificationEnabled() const -{ - Q_D(const QSymbianSocketEngine); - return d->writeNotificationsEnabled; -} - -void QSymbianSocketEngine::setWriteNotificationEnabled(bool enable) -{ - Q_D(QSymbianSocketEngine); -#ifdef QNATIVESOCKETENGINE_DEBUG - qDebug() << "QSymbianSocketEngine::setWriteNotificationEnabled" << enable << "socket" << d->socketDescriptor; -#endif - d->writeNotificationsEnabled = enable; - startNotifications(); -} - -bool QSymbianSocketEngine::isExceptionNotificationEnabled() const -{ - Q_D(const QSymbianSocketEngine); - return d->exceptNotificationsEnabled; - return false; -} - -void QSymbianSocketEngine::setExceptionNotificationEnabled(bool enable) -{ - Q_D(QSymbianSocketEngine); -#ifdef QNATIVESOCKETENGINE_DEBUG - qDebug() << "QSymbianSocketEngine::setExceptionNotificationEnabled" << enable << "socket" << d->socketDescriptor; -#endif - d->exceptNotificationsEnabled = enable; - startNotifications(); -} - -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; -} - -bool QSymbianSocketEngine::event(QEvent* ev) -{ - Q_D(QSymbianSocketEngine); - if (ev->type() == QEvent::ThreadChange) { -#ifdef QNATIVESOCKETENGINE_DEBUG - qDebug() << "QSymbianSocketEngine::event - ThreadChange" << d->readNotificationsEnabled << d->writeNotificationsEnabled << d->exceptNotificationsEnabled; -#endif - if (d->asyncSelect) { - delete d->asyncSelect; - d->asyncSelect = 0; - // recreate select in new thread (because it is queued, the method is called in the new thread context) - QMetaObject::invokeMethod(this, "startNotifications", Qt::QueuedConnection); - } - d->selectTimer.Close(); - return true; - } - return QAbstractSocketEngine::event(ev); -} - -QAsyncSelect::QAsyncSelect(QEventDispatcherSymbian *dispatcher, RSocket& sock, QSymbianSocketEngine *parent) - : QActiveObject(CActive::EPriorityStandard, dispatcher), - 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); - if (engine->isExceptionNotificationEnabled()) - engine->exceptionNotification(); - if (engine->isReadNotificationEnabled()) - engine->readNotification(); - } - QT_CATCH(...) {} - } -#ifdef QNATIVESOCKETENGINE_DEBUG - qDebug() << "QAsyncSelect::RunError" << aError; -#endif - return KErrNone; -} - -void QAsyncSelect::run() -{ - //when event loop disabled socket events, defer until later - if (maybeDeferSocketEvent()) - return; -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug() << "QAsyncSelect::run" << m_selectBuf() << m_selectFlags; -#endif - 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 (engine && engine->isReadNotificationEnabled() - && ((m_selectBuf() & KSockSelectRead) || iStatus != KErrNone)) { - engine->readNotification(); - } - if (engine && engine->isWriteNotificationEnabled() - && ((m_selectBuf() & KSockSelectWrite) || iStatus != KErrNone)) { - if (engine->state() == QAbstractSocket::ConnectingState) - engine->connectionNotification(); - else - engine->writeNotification(); - } - if (engine && engine->isExceptionNotificationEnabled() - && ((m_selectBuf() & KSockSelectExcept) || iStatus != KErrNone)) { - engine->exceptionNotification(); - } - 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) { - 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 (engine->isReadNotificationEnabled()) - selectFlags |= KSockSelectRead; - if (engine->isWriteNotificationEnabled()) - selectFlags |= KSockSelectWrite; - if (engine->isExceptionNotificationEnabled()) - selectFlags |= KSockSelectExcept; - if (selectFlags != m_selectFlags) { -#ifdef QNATIVESOCKETENGINE_DEBUG - qDebug() << "QAsyncSelect::IssueRequest() - select flags" << m_selectFlags << "->" << selectFlags; -#endif - 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(); - } -#ifdef QNATIVESOCKETENGINE_DEBUG - qDebug() << "QAsyncSelect::IssueRequest() - IsActive" << IsActive(); -#endif -} - -QT_END_NAMESPACE |