summaryrefslogtreecommitdiffstats
path: root/Source/CPack
ModeNameSize
-rw-r--r--OSXLauncherScript.scpt3102logstatsplain
-rw-r--r--OSXScriptLauncher.cxx4082logstatsplain
-rw-r--r--bills-comments.txt2424logstatsplain
-rw-r--r--cmCPackArchiveGenerator.cxx11793logstatsplain
-rw-r--r--cmCPackArchiveGenerator.h2370logstatsplain
-rw-r--r--cmCPackBundleGenerator.cxx4929logstatsplain
-rw-r--r--cmCPackBundleGenerator.h1123logstatsplain
-rw-r--r--cmCPackComponentGroup.cxx1464logstatsplain
-rw-r--r--cmCPackComponentGroup.h4197logstatsplain
-rw-r--r--cmCPackConfigure.h.in571logstatsplain
-rw-r--r--cmCPackCygwinBinaryGenerator.cxx3145logstatsplain
-rw-r--r--cmCPackCygwinBinaryGenerator.h1171logstatsplain
-rw-r--r--cmCPackCygwinSourceGenerator.cxx6333logstatsplain
-rw-r--r--cmCPackCygwinSourceGenerator.h1248logstatsplain
-rw-r--r--cmCPackDebGenerator.cxx29840logstatsplain
-rw-r--r--cmCPackDebGenerator.h1661logstatsplain
-rw-r--r--cmCPackDragNDropGenerator.cxx14606logstatsplain
-rw-r--r--cmCPackDragNDropGenerator.h1257logstatsplain
-rw-r--r--cmCPackGenerator.cxx54516logstatsplain
-rw-r--r--cmCPackGenerator.h8202logstatsplain
-rw-r--r--cmCPackGeneratorFactory.cxx4692logstatsplain
-rw-r--r--cmCPackGeneratorFactory.h1767logstatsplain
-rw-r--r--cmCPackLog.cxx5289logstatsplain
-rw-r--r--cmCPackLog.h4124logstatsplain
-rw-r--r--cmCPackNSISGenerator.cxx34253logstatsplain
-rw-r--r--cmCPackNSISGenerator.h2777logstatsplain
-rw-r--r--cmCPackOSXX11Generator.cxx10087logstatsplain
-rw-r--r--cmCPackOSXX11Generator.h1391logstatsplain
-rw-r--r--cmCPackPackageMakerGenerator.cxx32605logstatsplain
-rw-r--r--cmCPackPackageMakerGenerator.h4724logstatsplain
-rw-r--r--cmCPackRPMGenerator.cxx10454logstatsplain
-rw-r--r--cmCPackRPMGenerator.h1796logstatsplain
-rw-r--r--cmCPackSTGZGenerator.cxx3734logstatsplain
-rw-r--r--cmCPackSTGZGenerator.h1143logstatsplain
-rw-r--r--cmCPackTGZGenerator.cxx958logstatsplain
-rw-r--r--cmCPackTGZGenerator.h1034logstatsplain
-rw-r--r--cmCPackTarBZip2Generator.cxx982logstatsplain
-rw-r--r--cmCPackTarBZip2Generator.h1072logstatsplain
-rw-r--r--cmCPackTarCompressGenerator.cxx1003logstatsplain
-rw-r--r--cmCPackTarCompressGenerator.h1091logstatsplain
-rw-r--r--cmCPackZIPGenerator.cxx958logstatsplain
-rw-r--r--cmCPackZIPGenerator.h1030logstatsplain
-rw-r--r--cpack.cxx16291logstatsplain
-rw-r--r--cygwin.readme1460logstatsplain
native socket engine Reviewed-By: Markus Goetz --- src/network/socket/qnativesocketengine_p.h | 4 + src/network/socket/qnativesocketengine_symbian.cpp | 187 +++++++++++---------- 2 files changed, 105 insertions(+), 86 deletions(-) diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h index 72ebd9f..ceecfeb 100644 --- a/src/network/socket/qnativesocketengine_p.h +++ b/src/network/socket/qnativesocketengine_p.h @@ -64,6 +64,7 @@ #include #include #include +#include #endif QT_BEGIN_NAMESPACE @@ -201,6 +202,7 @@ public: mutable RSocket nativeSocket; RSocketServ socketServer; //TODO: shared ref RConnection connection; //TODO: shared ref + mutable RTimer selectTimer; #endif QSocketNotifier *readNotifier, *writeNotifier, *exceptNotifier; @@ -240,6 +242,8 @@ public: }; #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; diff --git a/src/network/socket/qnativesocketengine_symbian.cpp b/src/network/socket/qnativesocketengine_symbian.cpp index f2aeee9..788e58a 100644 --- a/src/network/socket/qnativesocketengine_symbian.cpp +++ b/src/network/socket/qnativesocketengine_symbian.cpp @@ -48,6 +48,7 @@ #include "qvarlengtharray.h" #include #include +#include #ifndef QT_NO_IPV6IFNAME #include #endif @@ -93,60 +94,7 @@ static QByteArray qt_prettyDebug(const char *data, int len, int maxSize) } #endif -static void qt_ignore_sigpipe() -{ -#ifndef Q_NO_POSIX_SIGNALS - // Set to ignore SIGPIPE once only. - static QBasicAtomicInt atom = Q_BASIC_ATOMIC_INITIALIZER(0); - if (atom.testAndSetRelaxed(0, 1)) { - struct sigaction noaction; - memset(&noaction, 0, sizeof(noaction)); - noaction.sa_handler = SIG_IGN; - ::sigaction(SIGPIPE, &noaction, 0); - } -#else - // Posix signals are not supported by the underlying platform - // so we don't need to ignore sigpipe signal explicitly -#endif -} - -/* - Extracts the port and address from a sockaddr, and stores them in - \a port and \a addr if they are non-null. -*/ -static inline void qt_socket_getPortAndAddress(const qt_sockaddr *s, quint16 *port, QHostAddress *addr) -{ -#if !defined(QT_NO_IPV6) - if (s->a.sa_family == AF_INET6) { - Q_IPV6ADDR tmp; - memcpy(&tmp, &s->a6.sin6_addr, sizeof(tmp)); - if (addr) { - QHostAddress tmpAddress; - tmpAddress.setAddress(tmp); - *addr = tmpAddress; -#ifndef QT_NO_IPV6IFNAME - char scopeid[IFNAMSIZ]; - if (::if_indextoname(s->a6.sin6_scope_id, scopeid)) { - addr->setScopeId(QLatin1String(scopeid)); - } else -#endif - addr->setScopeId(QString::number(s->a6.sin6_scope_id)); - } - if (port) - *port = ntohs(s->a6.sin6_port); - return; - } -#endif - if (port) - *port = ntohs(s->a4.sin_port); - if (addr) { - QHostAddress tmpAddress; - tmpAddress.setAddress(ntohl(s->a4.sin_addr.s_addr)); - *addr = tmpAddress; - } -} - -static inline void qt_socket_getPortAndAddress(const TInetAddr& a, quint16 *port, QHostAddress *addr) +void QNativeSocketEnginePrivate::getPortAndAddress(const TInetAddr& a, quint16 *port, QHostAddress *addr) { #if !defined(QT_NO_IPV6) if (a.Family() == KAfInet6) { @@ -157,13 +105,12 @@ static inline void qt_socket_getPortAndAddress(const TInetAddr& a, quint16 *port tmpAddress.setAddress(tmp); *addr = tmpAddress; #ifndef QT_NO_IPV6IFNAME - char scopeid[IFNAMSIZ]; - //TODO: rather than using posix api, the symbian way is - //to use GetOpt with TSoInetIfQuery and KSoInetIfQueryByIndex - //which means this should be in a member function to have access to the nativeSocket - if (::if_indextoname(a.Scope(), scopeid)) { - addr->setScopeId(QLatin1String(scopeid)); - } else + TPckgBuf 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())); } @@ -176,7 +123,7 @@ static inline void qt_socket_getPortAndAddress(const TInetAddr& a, quint16 *port *port = a.Port(); if (addr) { QHostAddress tmpAddress; - tmpAddress.setAddress(a.Address()); //TODO: byte order ok? + tmpAddress.setAddress(a.Address()); *addr = tmpAddress; } } @@ -218,7 +165,7 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc return false; } - socketDescriptor = nativeSocket.SubSessionHandle(); //TODO + socketDescriptor = QSymbianSocketManager::instance().addSocket(&nativeSocket); return true; } @@ -245,15 +192,16 @@ int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) co n = KSONonBlockingIO; break; case QNativeSocketEngine::BroadcastSocketOption: - n = SO_BROADCAST; //TODO - break; + return true; //symbian doesn't support or require this option case QNativeSocketEngine::AddressReusable: - n = SO_REUSEADDR; //TODO + level = KSolInetIp; + n = KSoReuseAddr; break; case QNativeSocketEngine::BindExclusively: return true; case QNativeSocketEngine::ReceiveOutOfBandData: - n = SO_OOBINLINE; //TODO + level = KSolInetTcp; + n = KSoTcpOobInline; break; case QNativeSocketEngine::LowDelayOption: level = KSolInetTcp; @@ -297,18 +245,19 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt n = KSOSendBuf; break; case QNativeSocketEngine::BroadcastSocketOption: - n = SO_BROADCAST; //TODO - break; + return true; case QNativeSocketEngine::NonBlockingSocketOption: n = KSONonBlockingIO; break; case QNativeSocketEngine::AddressReusable: - n = SO_REUSEADDR; //TODO + level = KSolInetIp; + n = KSoReuseAddr; break; case QNativeSocketEngine::BindExclusively: return true; case QNativeSocketEngine::ReceiveOutOfBandData: - n = SO_OOBINLINE; //TODO + level = KSolInetTcp; + n = KSoTcpOobInline; break; case QNativeSocketEngine::LowDelayOption: level = KSolInetTcp; @@ -323,13 +272,19 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt return (KErrNone == nativeSocket.SetOpt(n, level, v)); } -static TInetAddr qt_QHostAddressToTInetAddr(const QHostAddress &addr) +void QNativeSocketEnginePrivate::setPortAndAddress(TInetAddr& nativeAddr, quint16 port, const QHostAddress &addr) { - TInetAddr nativeAddr; + nativeAddr.SetPort(port); #if !defined(QT_NO_IPV6) if (addr.protocol() == QAbstractSocket::IPv6Protocol) { #ifndef QT_NO_IPV6IFNAME - nativeAddr.SetScope(::if_nametoindex(addr.scopeId().toLatin1().data())); //TODO - if_nametoindex + TPckgBuf 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 @@ -344,7 +299,6 @@ static TInetAddr qt_QHostAddressToTInetAddr(const QHostAddress &addr) } else { qWarning("unsupported network protocol (%d)", addr.protocol()); } - return nativeAddr; } bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 port) @@ -353,8 +307,8 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 qDebug("QNativeSocketEnginePrivate::nativeConnect() : %d ", socketDescriptor); #endif - TInetAddr nativeAddr = qt_QHostAddressToTInetAddr(addr); - nativeAddr.SetPort(port); + 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); @@ -413,8 +367,8 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16 port) { - TInetAddr nativeAddr = qt_QHostAddressToTInetAddr(address); - nativeAddr.SetPort(port); + TInetAddr nativeAddr; + setPortAndAddress(nativeAddr, port, address); TInt err = nativeSocket.Bind(nativeAddr); @@ -535,7 +489,7 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS if (status.Int()) { setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString); } else if (port || address) { - qt_socket_getPortAndAddress(addr, port, address); + getPortAndAddress(addr, port, address); } #if defined (QNATIVESOCKETENGINE_DEBUG) @@ -555,9 +509,9 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l const QHostAddress &host, quint16 port) { TPtrC8 buffer((TUint8*)data, (int)len); - TInetAddr addr = qt_QHostAddressToTInetAddr(host); + TInetAddr addr; + setPortAndAddress(addr, port, host); TSockXfrLength sentBytes; - addr.SetPort(port); TRequestStatus status; //TODO: OMG sync send! nativeSocket.SendTo(buffer, addr, 0, status, sentBytes); User::WaitForRequest(status); @@ -592,12 +546,17 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters() if (socketDescriptor == -1) return false; - //TODO: work out how to initialise nativeSocket from socketDescriptor + if (!nativeSocket.SubSessionHandle()) { + RSocket *s = QSymbianSocketManager::instance().lookupSocket(socketDescriptor); + if (!s) + return false; + nativeSocket = *s; //TODO: badwrongfun (address is different, so this is broken) + } // Determine local address TSockAddr addr; nativeSocket.LocalName(addr); - qt_socket_getPortAndAddress(addr, &localPort, &localAddress); + getPortAndAddress(addr, &localPort, &localAddress); // Determine protocol family switch (addr.Family()) { @@ -616,7 +575,7 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters() // Determine the remote address nativeSocket.RemoteName(addr); - qt_socket_getPortAndAddress(addr, &peerPort, &peerAddress); + getPortAndAddress(addr, &peerPort, &peerAddress); // Determine the socket type (UDP/TCP) TProtocolDesc protocol; @@ -662,6 +621,7 @@ void QNativeSocketEnginePrivate::nativeClose() //TODO: call nativeSocket.Shutdown(EImmediate) in some cases? nativeSocket.Close(); + QSymbianSocketManager::instance().removeSocket(&nativeSocket); } qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len) @@ -744,13 +704,68 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize) int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const { -//TODO: implement + 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; } QT_END_NAMESPACE -- cgit v0.12 From de55502a960a1044770aa840d7e443343b3c436b Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 6 Dec 2010 12:36:13 +0000 Subject: Add socket manager to corelib This class stores socket handles so they can be passed around as integers. Also, it owns the global RSocketServ used throughout the application. Reason for this not being in QtNetwork is that QtCore exports some socket related classes. Reviewed-by: Markus Goetz --- src/corelib/kernel/qcore_symbian_p.cpp | 27 +++++++++++++++++++++------ src/corelib/kernel/qcore_symbian_p.h | 34 +++++++++++++++++++++++++++------- 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/src/corelib/kernel/qcore_symbian_p.cpp b/src/corelib/kernel/qcore_symbian_p.cpp index 29996a4..809dc30 100644 --- a/src/corelib/kernel/qcore_symbian_p.cpp +++ b/src/corelib/kernel/qcore_symbian_p.cpp @@ -203,6 +203,11 @@ private: RFs iFs; }; +uint qHash(const RSubSessionBase& key) +{ + return qHash(key.SubSessionHandle()); +} + Q_GLOBAL_STATIC(QS60RFsSession, qt_s60_RFsSession); Q_CORE_EXPORT RFs& qt_s60GetRFs() @@ -229,7 +234,8 @@ RSocketServ& QSymbianSocketManager::getSocketServer() { return iSocketServ; } -int QSymbianSocketManager::addSocket(RSocket* sock) { +int QSymbianSocketManager::addSocket(const RSocket& socket) { + QHashableSocket sock(static_cast(socket)); QMutexLocker l(&iMutex); Q_ASSERT(!socketMap.contains(sock)); if(socketMap.contains(sock)) @@ -250,7 +256,8 @@ int QSymbianSocketManager::addSocket(RSocket* sock) { return id + socket_offset; } -bool QSymbianSocketManager::removeSocket(RSocket* sock) { +bool QSymbianSocketManager::removeSocket(const RSocket &socket) { + QHashableSocket sock(static_cast(socket)); QMutexLocker l(&iMutex); if(!socketMap.contains(sock)) return false; @@ -260,7 +267,8 @@ bool QSymbianSocketManager::removeSocket(RSocket* sock) { return true; } -int QSymbianSocketManager::lookupSocket(RSocket* sock) const { +int QSymbianSocketManager::lookupSocket(const RSocket& socket) const { + QHashableSocket sock(static_cast(socket)); QMutexLocker l(&iMutex); if(!socketMap.contains(sock)) return -1; @@ -268,12 +276,13 @@ int QSymbianSocketManager::lookupSocket(RSocket* sock) const { return id + socket_offset; } -RSocket* QSymbianSocketManager::lookupSocket(int fd) const { +bool QSymbianSocketManager::lookupSocket(int fd, RSocket& socket) const { QMutexLocker l(&iMutex); int id = fd + socket_offset; if(!reverseSocketMap.contains(id)) - return 0; - return reverseSocketMap.value(id); + return false; + socket = reverseSocketMap.value(id); + return true; } Q_GLOBAL_STATIC(QSymbianSocketManager, qt_symbianSocketManager); @@ -282,4 +291,10 @@ QSymbianSocketManager& QSymbianSocketManager::instance() { return *(qt_symbianSocketManager()); } + +Q_CORE_EXPORT RSocketServ& qt_symbianGetSocketServer() +{ + return QSymbianSocketManager::instance().getSocketServer(); +} + QT_END_NAMESPACE diff --git a/src/corelib/kernel/qcore_symbian_p.h b/src/corelib/kernel/qcore_symbian_p.h index b6cba6e..8ffa247 100644 --- a/src/corelib/kernel/qcore_symbian_p.h +++ b/src/corelib/kernel/qcore_symbian_p.h @@ -161,6 +161,25 @@ Q_CORE_EXPORT RSocketServ& qt_symbianGetSocketServer(); // Defined in qlocale_symbian.cpp. Q_CORE_EXPORT QByteArray qt_symbianLocaleName(int code); +//Wrapper for RSocket so it can be used as a key in QHash or QMap +class QHashableSocket : public RSocket +{ +public: + bool operator==(const QHashableSocket &other) const + { + return SubSessionHandle() == other.SubSessionHandle() + && Session().Handle() == other.Session().Handle(); + } + bool operator<(const QHashableSocket &other) const + { + if(Session().Handle() == other.Session().Handle()) + return SubSessionHandle() < other.SubSessionHandle(); + return Session().Handle() < other.Session().Handle(); + } +}; + +uint qHash(const RSubSessionBase& key); + /*! \internal This class exists in QtCore for the benefit of QSocketNotifier, which uses integer @@ -185,28 +204,29 @@ public: \param an open socket \return pseudo file descriptor, -1 if out of resources */ - int addSocket(RSocket *sock); + int addSocket(const RSocket &sock); /*! \internal Removes a symbian socket from the global map \param an open socket \return true if the socket was in the map */ - bool removeSocket(RSocket *sock); + bool removeSocket(const RSocket &sock); /*! \internal Get pseudo file descriptor for a socket \param an open socket \return integer handle, or -1 if not in map */ - int lookupSocket(RSocket *sock) const; + int lookupSocket(const RSocket &sock) const; /*! \internal Get socket for a pseudo file descriptor \param an open socket fd - \return socket handle or NULL if not in map + \param sock (out) socket handle + \return true on success or false if not in map */ - RSocket *lookupSocket(int fd) const; + bool lookupSocket(int fd, RSocket& sock) const; /*! \internal @@ -219,8 +239,8 @@ private: const static int max_sockets = 0x20000; //covers all TCP and UDP ports, probably run out of memory first const static int socket_offset = 0x40000000; //hacky way of separating sockets from file descriptors int iNextSocket; - QHash socketMap; - QHash reverseSocketMap; + QHash socketMap; + QHash reverseSocketMap; mutable QMutex iMutex; RSocketServ iSocketServ; }; -- cgit v0.12 From 7ec11a51d564c85d46ddee270cf7c743a2cbd320 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 6 Dec 2010 14:02:02 +0000 Subject: Use socket manager in QtNetwork Store/Retrieve sockets in the socket manager Use the shared socket server instance from QtCore Also, add 4 stub functions for multicast groups (new in master) to fix link error Reviewed-by: Markus Goetz --- src/network/socket/qnativesocketengine.cpp | 17 +++++++---- src/network/socket/qnativesocketengine_p.h | 2 +- src/network/socket/qnativesocketengine_symbian.cpp | 35 ++++++++++++++++++---- 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/src/network/socket/qnativesocketengine.cpp b/src/network/socket/qnativesocketengine.cpp index df73b9c..00d36b4 100644 --- a/src/network/socket/qnativesocketengine.cpp +++ b/src/network/socket/qnativesocketengine.cpp @@ -110,6 +110,10 @@ # include "qtcpserver.h" #endif +#ifdef Q_OS_SYMBIAN +# include +#endif + QT_BEGIN_NAMESPACE //#define QNATIVESOCKETENGINE_DEBUG @@ -158,12 +162,15 @@ QT_BEGIN_NAMESPACE concurrent QNativeSocketEngine. This is safe, because WSAStartup and WSACleanup are reference counted. */ -QNativeSocketEnginePrivate::QNativeSocketEnginePrivate() +QNativeSocketEnginePrivate::QNativeSocketEnginePrivate() : + socketDescriptor(-1), +#ifdef Q_OS_SYMBIAN + socketServer(qt_symbianGetSocketServer()), +#endif + readNotifier(0), + writeNotifier(0), + exceptNotifier(0) { - socketDescriptor = -1; - readNotifier = 0; - writeNotifier = 0; - exceptNotifier = 0; } /*! \internal diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h index ceecfeb..c017065 100644 --- a/src/network/socket/qnativesocketengine_p.h +++ b/src/network/socket/qnativesocketengine_p.h @@ -200,7 +200,7 @@ public: int socketDescriptor; #ifdef Q_OS_SYMBIAN mutable RSocket nativeSocket; - RSocketServ socketServer; //TODO: shared ref + RSocketServ& socketServer; RConnection connection; //TODO: shared ref mutable RTimer selectTimer; #endif diff --git a/src/network/socket/qnativesocketengine_symbian.cpp b/src/network/socket/qnativesocketengine_symbian.cpp index 788e58a..d1a0819 100644 --- a/src/network/socket/qnativesocketengine_symbian.cpp +++ b/src/network/socket/qnativesocketengine_symbian.cpp @@ -46,6 +46,7 @@ #include "qhostaddress.h" #include "qelapsedtimer.h" #include "qvarlengtharray.h" +#include "qnetworkinterface.h" #include #include #include @@ -165,7 +166,7 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc return false; } - socketDescriptor = QSymbianSocketManager::instance().addSocket(&nativeSocket); + socketDescriptor = QSymbianSocketManager::instance().addSocket(nativeSocket); return true; } @@ -547,10 +548,8 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters() return false; if (!nativeSocket.SubSessionHandle()) { - RSocket *s = QSymbianSocketManager::instance().lookupSocket(socketDescriptor); - if (!s) + if (!QSymbianSocketManager::instance().lookupSocket(socketDescriptor, nativeSocket)) return false; - nativeSocket = *s; //TODO: badwrongfun (address is different, so this is broken) } // Determine local address @@ -621,7 +620,7 @@ void QNativeSocketEnginePrivate::nativeClose() //TODO: call nativeSocket.Shutdown(EImmediate) in some cases? nativeSocket.Close(); - QSymbianSocketManager::instance().removeSocket(&nativeSocket); + QSymbianSocketManager::instance().removeSocket(nativeSocket); } qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len) @@ -768,4 +767,30 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c 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 -- cgit v0.12 From 8dacbccfd89006d1571b3b6ab6e96ea13e74f455 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 6 Dec 2010 15:47:40 +0000 Subject: Set preferences in socket server Connect() Tell the socket server we intend to use this session mainly for IP This allows the socket server to optimise this session for IP usage. Reviewed-by: Markus Goetz --- src/corelib/kernel/qcore_symbian_p.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/corelib/kernel/qcore_symbian_p.cpp b/src/corelib/kernel/qcore_symbian_p.cpp index 809dc30..b6688f7 100644 --- a/src/corelib/kernel/qcore_symbian_p.cpp +++ b/src/corelib/kernel/qcore_symbian_p.cpp @@ -44,6 +44,7 @@ #include #include "qcore_symbian_p.h" #include +#include QT_BEGIN_NAMESPACE @@ -218,7 +219,11 @@ Q_CORE_EXPORT RFs& qt_s60GetRFs() QSymbianSocketManager::QSymbianSocketManager() : iNextSocket(0) { - qt_symbian_throwIfError(iSocketServ.Connect()); + TSessionPref preferences; + // ### In future this could be changed to KAfInet6 when that is more common than IPv4 + preferences.iAddrFamily = KAfInet; + preferences.iProtocol = KProtocolInetIp; + qt_symbian_throwIfError(iSocketServ.Connect(preferences)); qt_symbian_throwIfError(iSocketServ.ShareAuto()); } -- cgit v0.12 From 5ef1fb5823a25cd4b27029701f7d707c82750acb Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 6 Dec 2010 15:57:59 +0000 Subject: Use shared socket server session everywhere Converted uses of RSocketServ in QtNetwork and the symbian bearer plugin to use the shared session from QtCore instead of creating their own Reviewed-by: Markus Goetz --- src/network/kernel/qnetworkinterface_symbian.cpp | 13 ++----------- src/plugins/bearer/symbian/qnetworksession_impl.cpp | 18 +++--------------- src/plugins/bearer/symbian/qnetworksession_impl.h | 2 +- 3 files changed, 6 insertions(+), 27 deletions(-) diff --git a/src/network/kernel/qnetworkinterface_symbian.cpp b/src/network/kernel/qnetworkinterface_symbian.cpp index 7942461..751664e 100644 --- a/src/network/kernel/qnetworkinterface_symbian.cpp +++ b/src/network/kernel/qnetworkinterface_symbian.cpp @@ -44,6 +44,7 @@ #include "qnetworkinterface.h" #include "qnetworkinterface_p.h" #include "../corelib/kernel/qcore_symbian_p.h" +#include #ifndef QT_NO_NETWORKINTERFACE @@ -72,17 +73,10 @@ static QList interfaceListing() TInt err(KErrNone); QList interfaces; - // Connect to Native socket server - RSocketServ socketServ; - err = socketServ.Connect(); - if (err) - return interfaces; - // Open dummy socket for interface queries RSocket socket; - err = socket.Open(socketServ, _L("udp")); + err = socket.Open(qt_symbianGetSocketServer(), _L("udp")); if (err) { - socketServ.Close(); return interfaces; } @@ -90,7 +84,6 @@ static QList interfaceListing() err = socket.SetOpt(KSoInetEnumInterfaces, KSolInetIfCtrl); if (err) { socket.Close(); - socketServ.Close(); return interfaces; } @@ -176,7 +169,6 @@ static QList interfaceListing() err = socket.SetOpt(KSoInetEnumRoutes, KSolInetRtCtrl); if (err) { socket.Close(); - socketServ.Close(); // return what we have // up to this moment return interfaces; @@ -223,7 +215,6 @@ static QList interfaceListing() } socket.Close(); - socketServ.Close(); return interfaces; } diff --git a/src/plugins/bearer/symbian/qnetworksession_impl.cpp b/src/plugins/bearer/symbian/qnetworksession_impl.cpp index 53a5b4d..cfb55bf 100644 --- a/src/plugins/bearer/symbian/qnetworksession_impl.cpp +++ b/src/plugins/bearer/symbian/qnetworksession_impl.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #ifdef SNAP_FUNCTIONALITY_AVAILABLE #include @@ -65,7 +66,7 @@ QNetworkSessionPrivateImpl::QNetworkSessionPrivateImpl(SymbianEngine *engine) iDynamicUnSetdefaultif(0), ipConnectionNotifier(0), iHandleStateNotificationsFromManager(false), iFirstSync(true), iStoppedByUser(false), iClosedByUser(false), iError(QNetworkSession::UnknownSessionError), iALREnabled(0), - iConnectInBackground(false), isOpening(false) + iConnectInBackground(false), isOpening(false), iSocketServ(qt_symbianGetSocketServer()) { CActiveScheduler::Add(this); @@ -109,7 +110,6 @@ QNetworkSessionPrivateImpl::~QNetworkSessionPrivateImpl() // Cancel possible RConnection::Start() Cancel(); - iSocketServ.Close(); // Close global 'Open C' RConnection // Clears also possible unsetdefaultif() flags. @@ -363,20 +363,9 @@ void QNetworkSessionPrivateImpl::open() iStoppedByUser = false; iClosedByUser = false; - TInt error = iSocketServ.Connect(); - if (error != KErrNone) { - // Could not open RSocketServ - newState(QNetworkSession::Invalid); - iError = QNetworkSession::UnknownSessionError; - emit QNetworkSessionPrivate::error(iError); - syncStateWithInterface(); - return; - } - - error = iConnection.Open(iSocketServ); + TInt error = iConnection.Open(iSocketServ); if (error != KErrNone) { // Could not open RConnection - iSocketServ.Close(); newState(QNetworkSession::Invalid); iError = QNetworkSession::UnknownSessionError; emit QNetworkSessionPrivate::error(iError); @@ -533,7 +522,6 @@ void QNetworkSessionPrivateImpl::close(bool allowSignals) } Cancel(); // closes iConnection - iSocketServ.Close(); // Close global 'Open C' RConnection. If OpenC supports, // close the defaultif for good to avoid difficult timing diff --git a/src/plugins/bearer/symbian/qnetworksession_impl.h b/src/plugins/bearer/symbian/qnetworksession_impl.h index 8e3e997..1101d1e 100644 --- a/src/plugins/bearer/symbian/qnetworksession_impl.h +++ b/src/plugins/bearer/symbian/qnetworksession_impl.h @@ -162,7 +162,7 @@ private: // data RLibrary iOpenCLibrary; TOpenCUnSetdefaultifFunction iDynamicUnSetdefaultif; - mutable RSocketServ iSocketServ; + mutable RSocketServ &iSocketServ; //not owned, shared from QtCore mutable RConnection iConnection; mutable RConnectionMonitor iConnectionMonitor; ConnectionProgressNotifier* ipConnectionNotifier; -- cgit v0.12 From 3a53b2853c0f1d4ace0eaf73f8c5ca5ded172345 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Tue, 7 Dec 2010 09:23:04 +0100 Subject: Symbian socket engine: Some more comments --- src/network/socket/qnativesocketengine_symbian.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/network/socket/qnativesocketengine_symbian.cpp b/src/network/socket/qnativesocketengine_symbian.cpp index d1a0819..cfaee03 100644 --- a/src/network/socket/qnativesocketengine_symbian.cpp +++ b/src/network/socket/qnativesocketengine_symbian.cpp @@ -165,6 +165,9 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc return false; } + // FIXME Set socket to nonblocking. While we are still a QNativeSocketEngine this is done already. + // Uncomment the following when we switch to QSymbianSocketEngine. + // setOption(NonBlockingSocketOption, 1) socketDescriptor = QSymbianSocketManager::instance().addSocket(nativeSocket); return true; @@ -444,7 +447,8 @@ int QNativeSocketEnginePrivate::nativeAccept() qWarning("QNativeSocketEnginePrivate::nativeAccept() - error %d", status.Int()); return 0; } - + // FIXME Qt Handle of new socket must be retrieved from QSymbianSocketManager + // and then returned. Not the SubSessionHandle! Also set the socket to nonblocking. return blankSocket.SubSessionHandle(); } @@ -452,6 +456,8 @@ qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const { int nbytes = 0; qint64 available = 0; + // FIXME is this the right thing also for UDP? + // What is expected for UDP, the length for the next packet I guess? TInt err = nativeSocket.GetOpt(KSOReadBytesPending, KSOLSocket, nbytes); if(err) return 0; @@ -476,6 +482,8 @@ 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)? + // Why = Could it be that this is about header lengths etc? if yes + // this could be pretty broken, especially for IPv6 } qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxSize, @@ -744,6 +752,8 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c //writeStat = ? array[count++] = writeStat; } + // TODO: for selecting, we can use getOpt(KSOSelectPoll) to get the select result + // and KIOCtlSelect for the selecting. User::WaitForNRequest(array, count); //IMPORTANT - WaitForNRequest only decrements the thread semaphore once, although more than one status may have completed. -- cgit v0.12 From fcb60092c90934df77f1441df7ab2a14fc5edf32 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Tue, 7 Dec 2010 09:43:07 +0100 Subject: Copy qhostinfo_unix.cpp to qhostinfo_symbian.cpp --- src/network/kernel/kernel.pri | 2 +- src/network/kernel/qhostinfo_symbian.cpp | 407 +++++++++++++++++++++++++++++++ 2 files changed, 408 insertions(+), 1 deletion(-) create mode 100644 src/network/kernel/qhostinfo_symbian.cpp diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri index 6145c43..ccc113c 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..5ca15a3 --- /dev/null +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -0,0 +1,407 @@ +/**************************************************************************** +** +** 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 + +#include "qplatformdefs.h" + +#include "qhostinfo_p.h" +#include "private/qnativesocketengine_p.h" +#include "qiodevice.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#if defined(Q_OS_VXWORKS) +# include +#else +# include +#endif + +#if defined (QT_NO_GETADDRINFO) +#include +QT_BEGIN_NAMESPACE +Q_GLOBAL_STATIC(QMutex, getHostByNameMutex) +QT_END_NAMESPACE +#endif + +QT_BEGIN_NAMESPACE + +// Almost always the same. If not, specify in qplatformdefs.h. +#if !defined(QT_SOCKOPTLEN_T) +# define QT_SOCKOPTLEN_T QT_SOCKLEN_T +#endif + +// HP-UXi has a bug in getaddrinfo(3) that makes it thread-unsafe +// with this flag. So disable it in that platform. +#if defined(AI_ADDRCONFIG) && !defined(Q_OS_HPUX) +# define Q_ADDRCONFIG AI_ADDRCONFIG +#endif + +typedef struct __res_state *res_state_ptr; + +typedef int (*res_init_proto)(void); +static res_init_proto local_res_init = 0; +typedef int (*res_ninit_proto)(res_state_ptr); +static res_ninit_proto local_res_ninit = 0; +typedef void (*res_nclose_proto)(res_state_ptr); +static res_nclose_proto local_res_nclose = 0; +static res_state_ptr local_res = 0; + +static void resolveLibrary() +{ +#ifndef QT_NO_LIBRARY + QLibrary lib(QLatin1String("resolv")); + if (!lib.load()) + return; + + local_res_init = res_init_proto(lib.resolve("__res_init")); + if (!local_res_init) + local_res_init = res_init_proto(lib.resolve("res_init")); + + local_res_ninit = res_ninit_proto(lib.resolve("__res_ninit")); + if (!local_res_ninit) + local_res_ninit = res_ninit_proto(lib.resolve("res_ninit")); + + if (!local_res_ninit) { + // if we can't get a thread-safe context, we have to use the global _res state + local_res = res_state_ptr(lib.resolve("_res")); + } else { + local_res_nclose = res_nclose_proto(lib.resolve("res_nclose")); + if (!local_res_nclose) + local_res_nclose = res_nclose_proto(lib.resolve("__res_nclose")); + if (!local_res_nclose) + local_res_ninit = 0; + } +#endif +} + +QHostInfo QHostInfoAgent::fromName(const QString &hostName) +{ + QHostInfo results; + +#if defined(QHOSTINFO_DEBUG) + qDebug("QHostInfoAgent::fromName(%s) looking up...", + hostName.toLatin1().constData()); +#endif + + // Load res_init on demand. + static volatile bool triedResolve = false; + if (!triedResolve) { + QMutexLocker locker(QMutexPool::globalInstanceGet(&local_res_init)); + if (!triedResolve) { + resolveLibrary(); + triedResolve = true; + } + } + + // If res_init is available, poll it. + if (local_res_init) + local_res_init(); + + QHostAddress address; + if (address.setAddress(hostName)) { + // Reverse lookup +// Reverse lookups using getnameinfo are broken on darwin, use gethostbyaddr instead. +#if !defined (QT_NO_GETADDRINFO) && !defined (Q_OS_DARWIN) && !defined (Q_OS_SYMBIAN) + sockaddr_in sa4; +#ifndef QT_NO_IPV6 + sockaddr_in6 sa6; +#endif + sockaddr *sa = 0; + QT_SOCKLEN_T saSize = 0; + if (address.protocol() == QAbstractSocket::IPv4Protocol) { + sa = (sockaddr *)&sa4; + saSize = sizeof(sa4); + memset(&sa4, 0, sizeof(sa4)); + sa4.sin_family = AF_INET; + sa4.sin_addr.s_addr = htonl(address.toIPv4Address()); + } +#ifndef QT_NO_IPV6 + else { + sa = (sockaddr *)&sa6; + saSize = sizeof(sa6); + memset(&sa6, 0, sizeof(sa6)); + sa6.sin6_family = AF_INET6; + memcpy(sa6.sin6_addr.s6_addr, address.toIPv6Address().c, sizeof(sa6.sin6_addr.s6_addr)); + } +#endif + + char hbuf[NI_MAXHOST]; + if (sa && getnameinfo(sa, saSize, hbuf, sizeof(hbuf), 0, 0, 0) == 0) + results.setHostName(QString::fromLatin1(hbuf)); +#else + in_addr_t inetaddr = qt_safe_inet_addr(hostName.toLatin1().constData()); + struct hostent *ent = gethostbyaddr((const char *)&inetaddr, sizeof(inetaddr), AF_INET); + if (ent) + results.setHostName(QString::fromLatin1(ent->h_name)); +#endif + + if (results.hostName().isEmpty()) + results.setHostName(address.toString()); + results.setAddresses(QList() << address); + return results; + } + + // IDN support + QByteArray aceHostname = QUrl::toAce(hostName); + results.setHostName(hostName); + if (aceHostname.isEmpty()) { + results.setError(QHostInfo::HostNotFound); + results.setErrorString(hostName.isEmpty() ? + QCoreApplication::translate("QHostInfoAgent", "No host name given") : + QCoreApplication::translate("QHostInfoAgent", "Invalid hostname")); + return results; + } + +#if !defined (QT_NO_GETADDRINFO) + // Call getaddrinfo, and place all IPv4 addresses at the start and + // the IPv6 addresses at the end of the address list in results. + addrinfo *res = 0; + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; +#ifdef Q_ADDRCONFIG + hints.ai_flags = Q_ADDRCONFIG; +#endif +#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 + + if (result == 0) { + addrinfo *node = res; + QList addresses; + while (node) { +#ifdef QHOSTINFO_DEBUG + qDebug() << "getaddrinfo node: flags:" << node->ai_flags << "family:" << node->ai_family << "ai_socktype:" << node->ai_socktype << "ai_protocol:" << node->ai_protocol << "ai_addrlen:" << node->ai_addrlen; +#endif + if (node->ai_family == AF_INET) { + QHostAddress addr; + addr.setAddress(ntohl(((sockaddr_in *) node->ai_addr)->sin_addr.s_addr)); + if (!addresses.contains(addr)) + addresses.append(addr); + } +#ifndef QT_NO_IPV6 + else if (node->ai_family == AF_INET6) { + QHostAddress addr; + sockaddr_in6 *sa6 = (sockaddr_in6 *) node->ai_addr; + addr.setAddress(sa6->sin6_addr.s6_addr); + if (sa6->sin6_scope_id) + addr.setScopeId(QString::number(sa6->sin6_scope_id)); + if (!addresses.contains(addr)) + addresses.append(addr); + } +#endif + node = node->ai_next; + } + if (addresses.isEmpty() && node == 0) { + // Reached the end of the list, but no addresses were found; this + // means the list contains one or more unknown address types. + results.setError(QHostInfo::UnknownError); + results.setErrorString(tr("Unknown address type")); + } + + results.setAddresses(addresses); + freeaddrinfo(res); + } else if (result == EAI_NONAME + || result == EAI_FAIL +#ifdef EAI_NODATA + // EAI_NODATA is deprecated in RFC 3493 + || result == EAI_NODATA +#endif + ) { + results.setError(QHostInfo::HostNotFound); + results.setErrorString(tr("Host not found")); + } else { + results.setError(QHostInfo::UnknownError); + results.setErrorString(QString::fromLocal8Bit(gai_strerror(result))); + } + +#else + // Fall back to gethostbyname for platforms that don't define + // getaddrinfo. gethostbyname does not support IPv6, and it's not + // reentrant on all platforms. For now this is okay since we only + // use one QHostInfoAgent, but if more agents are introduced, locking + // must be provided. + QMutexLocker locker(::getHostByNameMutex()); + hostent *result = gethostbyname(aceHostname.constData()); + if (result) { + if (result->h_addrtype == AF_INET) { + QList addresses; + for (char **p = result->h_addr_list; *p != 0; p++) { + QHostAddress addr; + addr.setAddress(ntohl(*((quint32 *)*p))); + if (!addresses.contains(addr)) + addresses.prepend(addr); + } + results.setAddresses(addresses); + } else { + results.setError(QHostInfo::UnknownError); + results.setErrorString(tr("Unknown address type")); + } +#if !defined(Q_OS_VXWORKS) + } else if (h_errno == HOST_NOT_FOUND || h_errno == NO_DATA + || h_errno == NO_ADDRESS) { + results.setError(QHostInfo::HostNotFound); + results.setErrorString(tr("Host not found")); +#endif + } else { + results.setError(QHostInfo::UnknownError); + results.setErrorString(tr("Unknown error")); + } +#endif // !defined (QT_NO_GETADDRINFO) + +#if defined(QHOSTINFO_DEBUG) + if (results.error() != QHostInfo::NoError) { + qDebug("QHostInfoAgent::fromName(): error #%d %s", + h_errno, results.errorString().toLatin1().constData()); + } else { + QString tmp; + QList addresses = results.addresses(); + for (int i = 0; i < addresses.count(); ++i) { + if (i != 0) tmp += ", "; + tmp += addresses.at(i).toString(); + } + qDebug("QHostInfoAgent::fromName(): found %i entries for \"%s\": {%s}", + addresses.count(), hostName.toLatin1().constData(), + tmp.toLatin1().constData()); + } +#endif + return results; +} + +QString QHostInfo::localHostName() +{ + char hostName[512]; + if (gethostname(hostName, sizeof(hostName)) == -1) + return QString(); + hostName[sizeof(hostName) - 1] = '\0'; + return QString::fromLocal8Bit(hostName); +} + +QString QHostInfo::localDomainName() +{ +#if !defined(Q_OS_VXWORKS) + resolveLibrary(); + if (local_res_ninit) { + // using thread-safe version + res_state_ptr state = res_state_ptr(qMalloc(sizeof(*state))); + Q_CHECK_PTR(state); + memset(state, 0, sizeof(*state)); + local_res_ninit(state); + QString domainName = QUrl::fromAce(state->defdname); + if (domainName.isEmpty()) + domainName = QUrl::fromAce(state->dnsrch[0]); + local_res_nclose(state); + qFree(state); + + return domainName; + } + + if (local_res_init && local_res) { + // using thread-unsafe version + +#if defined(QT_NO_GETADDRINFO) + // We have to call res_init to be sure that _res was initialized + // So, for systems without getaddrinfo (which is thread-safe), we lock the mutex too + QMutexLocker locker(::getHostByNameMutex()); +#endif + local_res_init(); + QString domainName = QUrl::fromAce(local_res->defdname); + if (domainName.isEmpty()) + domainName = QUrl::fromAce(local_res->dnsrch[0]); + return domainName; + } +#endif + // nothing worked, try doing it by ourselves: + QFile resolvconf; +#if defined(_PATH_RESCONF) + resolvconf.setFileName(QFile::decodeName(_PATH_RESCONF)); +#else + resolvconf.setFileName(QLatin1String("/etc/resolv.conf")); +#endif + if (!resolvconf.open(QIODevice::ReadOnly)) + return QString(); // failure + + QString domainName; + while (!resolvconf.atEnd()) { + QByteArray line = resolvconf.readLine().trimmed(); + if (line.startsWith("domain ")) + return QUrl::fromAce(line.mid(sizeof "domain " - 1).trimmed()); + + // in case there's no "domain" line, fall back to the first "search" entry + if (domainName.isEmpty() && line.startsWith("search ")) { + QByteArray searchDomain = line.mid(sizeof "search " - 1).trimmed(); + int pos = searchDomain.indexOf(' '); + if (pos != -1) + searchDomain.truncate(pos); + domainName = QUrl::fromAce(searchDomain); + } + } + + // return the fallen-back-to searched domain + return domainName; +} + +QT_END_NAMESPACE -- cgit v0.12 From 5c75d5bed133a4cd77329b5e90d1f47f86f92a17 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Tue, 7 Dec 2010 10:01:08 +0100 Subject: Weed out old unix code from qhostinfo_symbian.cpp --- src/network/kernel/qhostinfo_symbian.cpp | 322 +------------------------------ 1 file changed, 9 insertions(+), 313 deletions(-) diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp index 5ca15a3..2e1e6ca 100644 --- a/src/network/kernel/qhostinfo_symbian.cpp +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -44,82 +44,9 @@ #include "qplatformdefs.h" #include "qhostinfo_p.h" -#include "private/qnativesocketengine_p.h" -#include "qiodevice.h" -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#if defined(Q_OS_VXWORKS) -# include -#else -# include -#endif - -#if defined (QT_NO_GETADDRINFO) -#include -QT_BEGIN_NAMESPACE -Q_GLOBAL_STATIC(QMutex, getHostByNameMutex) -QT_END_NAMESPACE -#endif QT_BEGIN_NAMESPACE -// Almost always the same. If not, specify in qplatformdefs.h. -#if !defined(QT_SOCKOPTLEN_T) -# define QT_SOCKOPTLEN_T QT_SOCKLEN_T -#endif - -// HP-UXi has a bug in getaddrinfo(3) that makes it thread-unsafe -// with this flag. So disable it in that platform. -#if defined(AI_ADDRCONFIG) && !defined(Q_OS_HPUX) -# define Q_ADDRCONFIG AI_ADDRCONFIG -#endif - -typedef struct __res_state *res_state_ptr; - -typedef int (*res_init_proto)(void); -static res_init_proto local_res_init = 0; -typedef int (*res_ninit_proto)(res_state_ptr); -static res_ninit_proto local_res_ninit = 0; -typedef void (*res_nclose_proto)(res_state_ptr); -static res_nclose_proto local_res_nclose = 0; -static res_state_ptr local_res = 0; - -static void resolveLibrary() -{ -#ifndef QT_NO_LIBRARY - QLibrary lib(QLatin1String("resolv")); - if (!lib.load()) - return; - - local_res_init = res_init_proto(lib.resolve("__res_init")); - if (!local_res_init) - local_res_init = res_init_proto(lib.resolve("res_init")); - - local_res_ninit = res_ninit_proto(lib.resolve("__res_ninit")); - if (!local_res_ninit) - local_res_ninit = res_ninit_proto(lib.resolve("res_ninit")); - - if (!local_res_ninit) { - // if we can't get a thread-safe context, we have to use the global _res state - local_res = res_state_ptr(lib.resolve("_res")); - } else { - local_res_nclose = res_nclose_proto(lib.resolve("res_nclose")); - if (!local_res_nclose) - local_res_nclose = res_nclose_proto(lib.resolve("__res_nclose")); - if (!local_res_nclose) - local_res_ninit = 0; - } -#endif -} - QHostInfo QHostInfoAgent::fromName(const QString &hostName) { QHostInfo results; @@ -129,60 +56,11 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) hostName.toLatin1().constData()); #endif - // Load res_init on demand. - static volatile bool triedResolve = false; - if (!triedResolve) { - QMutexLocker locker(QMutexPool::globalInstanceGet(&local_res_init)); - if (!triedResolve) { - resolveLibrary(); - triedResolve = true; - } - } - - // If res_init is available, poll it. - if (local_res_init) - local_res_init(); - QHostAddress address; if (address.setAddress(hostName)) { // Reverse lookup -// Reverse lookups using getnameinfo are broken on darwin, use gethostbyaddr instead. -#if !defined (QT_NO_GETADDRINFO) && !defined (Q_OS_DARWIN) && !defined (Q_OS_SYMBIAN) - sockaddr_in sa4; -#ifndef QT_NO_IPV6 - sockaddr_in6 sa6; -#endif - sockaddr *sa = 0; - QT_SOCKLEN_T saSize = 0; - if (address.protocol() == QAbstractSocket::IPv4Protocol) { - sa = (sockaddr *)&sa4; - saSize = sizeof(sa4); - memset(&sa4, 0, sizeof(sa4)); - sa4.sin_family = AF_INET; - sa4.sin_addr.s_addr = htonl(address.toIPv4Address()); - } -#ifndef QT_NO_IPV6 - else { - sa = (sockaddr *)&sa6; - saSize = sizeof(sa6); - memset(&sa6, 0, sizeof(sa6)); - sa6.sin6_family = AF_INET6; - memcpy(sa6.sin6_addr.s6_addr, address.toIPv6Address().c, sizeof(sa6.sin6_addr.s6_addr)); - } -#endif - - char hbuf[NI_MAXHOST]; - if (sa && getnameinfo(sa, saSize, hbuf, sizeof(hbuf), 0, 0, 0) == 0) - results.setHostName(QString::fromLatin1(hbuf)); -#else - in_addr_t inetaddr = qt_safe_inet_addr(hostName.toLatin1().constData()); - struct hostent *ent = gethostbyaddr((const char *)&inetaddr, sizeof(inetaddr), AF_INET); - if (ent) - results.setHostName(QString::fromLatin1(ent->h_name)); -#endif - - if (results.hostName().isEmpty()) - results.setHostName(address.toString()); + // TODO + results.setHostName("assume.it.works"); results.setAddresses(QList() << address); return results; } @@ -198,210 +76,28 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) return results; } -#if !defined (QT_NO_GETADDRINFO) // Call getaddrinfo, and place all IPv4 addresses at the start and // the IPv6 addresses at the end of the address list in results. - addrinfo *res = 0; - struct addrinfo hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; -#ifdef Q_ADDRCONFIG - hints.ai_flags = Q_ADDRCONFIG; -#endif -#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 - - if (result == 0) { - addrinfo *node = res; - QList addresses; - while (node) { -#ifdef QHOSTINFO_DEBUG - qDebug() << "getaddrinfo node: flags:" << node->ai_flags << "family:" << node->ai_family << "ai_socktype:" << node->ai_socktype << "ai_protocol:" << node->ai_protocol << "ai_addrlen:" << node->ai_addrlen; -#endif - if (node->ai_family == AF_INET) { - QHostAddress addr; - addr.setAddress(ntohl(((sockaddr_in *) node->ai_addr)->sin_addr.s_addr)); - if (!addresses.contains(addr)) - addresses.append(addr); - } -#ifndef QT_NO_IPV6 - else if (node->ai_family == AF_INET6) { - QHostAddress addr; - sockaddr_in6 *sa6 = (sockaddr_in6 *) node->ai_addr; - addr.setAddress(sa6->sin6_addr.s6_addr); - if (sa6->sin6_scope_id) - addr.setScopeId(QString::number(sa6->sin6_scope_id)); - if (!addresses.contains(addr)) - addresses.append(addr); - } -#endif - node = node->ai_next; - } - if (addresses.isEmpty() && node == 0) { - // Reached the end of the list, but no addresses were found; this - // means the list contains one or more unknown address types. - results.setError(QHostInfo::UnknownError); - results.setErrorString(tr("Unknown address type")); - } - - results.setAddresses(addresses); - freeaddrinfo(res); - } else if (result == EAI_NONAME - || result == EAI_FAIL -#ifdef EAI_NODATA - // EAI_NODATA is deprecated in RFC 3493 - || result == EAI_NODATA -#endif - ) { - results.setError(QHostInfo::HostNotFound); - results.setErrorString(tr("Host not found")); + /* + results.setError(QHostInfo::HostNotFound); + results.setErrorString(tr("Host not found")); } else { results.setError(QHostInfo::UnknownError); results.setErrorString(QString::fromLocal8Bit(gai_strerror(result))); } - -#else - // Fall back to gethostbyname for platforms that don't define - // getaddrinfo. gethostbyname does not support IPv6, and it's not - // reentrant on all platforms. For now this is okay since we only - // use one QHostInfoAgent, but if more agents are introduced, locking - // must be provided. - QMutexLocker locker(::getHostByNameMutex()); - hostent *result = gethostbyname(aceHostname.constData()); - if (result) { - if (result->h_addrtype == AF_INET) { - QList addresses; - for (char **p = result->h_addr_list; *p != 0; p++) { - QHostAddress addr; - addr.setAddress(ntohl(*((quint32 *)*p))); - if (!addresses.contains(addr)) - addresses.prepend(addr); - } - results.setAddresses(addresses); - } else { - results.setError(QHostInfo::UnknownError); - results.setErrorString(tr("Unknown address type")); - } -#if !defined(Q_OS_VXWORKS) - } else if (h_errno == HOST_NOT_FOUND || h_errno == NO_DATA - || h_errno == NO_ADDRESS) { - results.setError(QHostInfo::HostNotFound); - results.setErrorString(tr("Host not found")); -#endif - } else { - results.setError(QHostInfo::UnknownError); - results.setErrorString(tr("Unknown error")); - } -#endif // !defined (QT_NO_GETADDRINFO) - -#if defined(QHOSTINFO_DEBUG) - if (results.error() != QHostInfo::NoError) { - qDebug("QHostInfoAgent::fromName(): error #%d %s", - h_errno, results.errorString().toLatin1().constData()); - } else { - QString tmp; - QList addresses = results.addresses(); - for (int i = 0; i < addresses.count(); ++i) { - if (i != 0) tmp += ", "; - tmp += addresses.at(i).toString(); - } - qDebug("QHostInfoAgent::fromName(): found %i entries for \"%s\": {%s}", - addresses.count(), hostName.toLatin1().constData(), - tmp.toLatin1().constData()); - } -#endif + */ + return results; } QString QHostInfo::localHostName() { - char hostName[512]; - if (gethostname(hostName, sizeof(hostName)) == -1) - return QString(); - hostName[sizeof(hostName) - 1] = '\0'; - return QString::fromLocal8Bit(hostName); + return QString() } QString QHostInfo::localDomainName() { -#if !defined(Q_OS_VXWORKS) - resolveLibrary(); - if (local_res_ninit) { - // using thread-safe version - res_state_ptr state = res_state_ptr(qMalloc(sizeof(*state))); - Q_CHECK_PTR(state); - memset(state, 0, sizeof(*state)); - local_res_ninit(state); - QString domainName = QUrl::fromAce(state->defdname); - if (domainName.isEmpty()) - domainName = QUrl::fromAce(state->dnsrch[0]); - local_res_nclose(state); - qFree(state); - - return domainName; - } - - if (local_res_init && local_res) { - // using thread-unsafe version - -#if defined(QT_NO_GETADDRINFO) - // We have to call res_init to be sure that _res was initialized - // So, for systems without getaddrinfo (which is thread-safe), we lock the mutex too - QMutexLocker locker(::getHostByNameMutex()); -#endif - local_res_init(); - QString domainName = QUrl::fromAce(local_res->defdname); - if (domainName.isEmpty()) - domainName = QUrl::fromAce(local_res->dnsrch[0]); - return domainName; - } -#endif - // nothing worked, try doing it by ourselves: - QFile resolvconf; -#if defined(_PATH_RESCONF) - resolvconf.setFileName(QFile::decodeName(_PATH_RESCONF)); -#else - resolvconf.setFileName(QLatin1String("/etc/resolv.conf")); -#endif - if (!resolvconf.open(QIODevice::ReadOnly)) - return QString(); // failure - - QString domainName; - while (!resolvconf.atEnd()) { - QByteArray line = resolvconf.readLine().trimmed(); - if (line.startsWith("domain ")) - return QUrl::fromAce(line.mid(sizeof "domain " - 1).trimmed()); - - // in case there's no "domain" line, fall back to the first "search" entry - if (domainName.isEmpty() && line.startsWith("search ")) { - QByteArray searchDomain = line.mid(sizeof "search " - 1).trimmed(); - int pos = searchDomain.indexOf(' '); - if (pos != -1) - searchDomain.truncate(pos); - domainName = QUrl::fromAce(searchDomain); - } - } - - // return the fallen-back-to searched domain - return domainName; + return QString(); } QT_END_NAMESPACE -- cgit v0.12 From 2533c00db1851e712b036329d6cc7562fe106da1 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Tue, 7 Dec 2010 10:50:45 +0100 Subject: Added qnetworkproxy_symbian.cpp --- src/network/kernel/kernel.pri | 1 + src/network/kernel/qnetworkproxy_symbian.cpp | 61 ++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 src/network/kernel/qnetworkproxy_symbian.cpp diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri index ccc113c..8aeb5c2 100644 --- a/src/network/kernel/kernel.pri +++ b/src/network/kernel/kernel.pri @@ -27,5 +27,6 @@ win32:SOURCES += kernel/qhostinfo_win.cpp kernel/qnetworkinterface_win.cpp mac:LIBS_PRIVATE += -framework SystemConfiguration -framework CoreFoundation mac:SOURCES += kernel/qnetworkproxy_mac.cpp else:win32:SOURCES += kernel/qnetworkproxy_win.cpp +else:symbian:SOURCES += kernel/qnetworkproxy_symbian.cpp else:SOURCES += kernel/qnetworkproxy_generic.cpp diff --git a/src/network/kernel/qnetworkproxy_symbian.cpp b/src/network/kernel/qnetworkproxy_symbian.cpp new file mode 100644 index 0000000..7eba2c2 --- /dev/null +++ b/src/network/kernel/qnetworkproxy_symbian.cpp @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#include "qnetworkproxy.h" + +#ifndef QT_NO_NETWORKPROXY + +QT_BEGIN_NAMESPACE + +QList QNetworkProxyFactory::systemProxyForQuery(const QNetworkProxyQuery &) +{ + // TODO: Get the current QNetworkSession which has the Symbian RConnection we use + + // TODO: Get the proxy from that RConnection + + + // Default case: No network proxy found/needed + return QList() << QNetworkProxy::NoProxy; +} + +QT_END_NAMESPACE + +#endif -- cgit v0.12 From 0ce754850de6473bc0df1918d76a9b127b445260 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Tue, 7 Dec 2010 11:01:30 +0100 Subject: Some more qnetworkproxy_symbian information --- src/network/kernel/qnetworkproxy_symbian.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/network/kernel/qnetworkproxy_symbian.cpp b/src/network/kernel/qnetworkproxy_symbian.cpp index 7eba2c2..62266d1 100644 --- a/src/network/kernel/qnetworkproxy_symbian.cpp +++ b/src/network/kernel/qnetworkproxy_symbian.cpp @@ -48,9 +48,14 @@ QT_BEGIN_NAMESPACE QList QNetworkProxyFactory::systemProxyForQuery(const QNetworkProxyQuery &) { // TODO: Get the current QNetworkSession which has the Symbian RConnection we use + // I am wondering if we already have a connected QNetworkSession when the code + // is run that retrieves the proxy (for QNetworkAccessManager it's somewhere called + // from createRequest() which might be too early...) // TODO: Get the proxy from that RConnection + // See http://bugreports.qt.nokia.com/browse/QTBUG-13857 and http://bugreports.qt.nokia.com/browse/QTBUG-11016 + // and the mails we have received. // Default case: No network proxy found/needed return QList() << QNetworkProxy::NoProxy; -- cgit v0.12 From 7dce8f9b28288b95daf0e8fd1016b8b75bccc61c Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Tue, 7 Dec 2010 12:12:48 +0100 Subject: QTestLib: Wait a bit on Symbian at exit Reviewed-by: Shane Kearns --- src/testlib/qabstracttestlogger.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/testlib/qabstracttestlogger.cpp b/src/testlib/qabstracttestlogger.cpp index f7269d6..a23638e 100644 --- a/src/testlib/qabstracttestlogger.cpp +++ b/src/testlib/qabstracttestlogger.cpp @@ -104,8 +104,16 @@ void QAbstractTestLogger::startLogging() void QAbstractTestLogger::stopLogging() { QTEST_ASSERT(QTest::stream); - if (QTest::stream != stdout) + if (QTest::stream != stdout) { fclose(QTest::stream); + } else { +#ifdef Q_OS_SYMBIAN + // Convenience sleep for Symbian and TRK. Without this sleep depending on the timing the + // user would not see the complete output because it is still pending in any of the buffers + // before arriving via the USB port on the development PC + User::AfterHighRes(2*1000*1000); +#endif + } QTest::stream = 0; } -- cgit v0.12 From 2b60cdf7b0c17372cbeb32e3eac1e18c0baea0e4 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Tue, 7 Dec 2010 15:50:05 +0100 Subject: Move qnativesocketengine_symbian* to QSymbianSocketEngine Reviewed-By: Shane Kearns --- src/network/socket/qnativesocketengine_symbian.cpp | 806 --------------------- src/network/socket/qsymbiansocketengine.cpp | 806 +++++++++++++++++++++ src/network/socket/qsymbiansocketengine_p.h | 289 ++++++++ src/network/socket/socket.pri | 5 +- 4 files changed, 1099 insertions(+), 807 deletions(-) delete mode 100644 src/network/socket/qnativesocketengine_symbian.cpp create mode 100644 src/network/socket/qsymbiansocketengine.cpp create mode 100644 src/network/socket/qsymbiansocketengine_p.h diff --git a/src/network/socket/qnativesocketengine_symbian.cpp b/src/network/socket/qnativesocketengine_symbian.cpp deleted file mode 100644 index cfaee03..0000000 --- a/src/network/socket/qnativesocketengine_symbian.cpp +++ /dev/null @@ -1,806 +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 -#include -#include -#ifndef QT_NO_IPV6IFNAME -#include -#endif - -#define QNATIVESOCKETENGINE_DEBUG - -#if defined QNATIVESOCKETENGINE_DEBUG -#include -#include -#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 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; - } - // FIXME Set socket to nonblocking. While we are still a QNativeSocketEngine this is done already. - // Uncomment the following when we switch to QSymbianSocketEngine. - // setOption(NonBlockingSocketOption, 1) - - 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 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; - } - // FIXME Qt Handle of new socket must be retrieved from QSymbianSocketManager - // and then returned. Not the SubSessionHandle! Also set the socket to nonblocking. - return blankSocket.SubSessionHandle(); -} - -qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const -{ - int nbytes = 0; - qint64 available = 0; - // FIXME is this the right thing also for UDP? - // What is expected for UDP, the length for the next packet I guess? - 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)? - // Why = Could it be that this is about header lengths etc? if yes - // this could be pretty broken, especially for IPv6 -} - -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(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; - } - // TODO: for selecting, we can use getOpt(KSOSelectPoll) to get the select result - // and KIOCtlSelect for the selecting. - - 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/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp new file mode 100644 index 0000000..cfaee03 --- /dev/null +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -0,0 +1,806 @@ +/**************************************************************************** +** +** 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 +#include +#include +#ifndef QT_NO_IPV6IFNAME +#include +#endif + +#define QNATIVESOCKETENGINE_DEBUG + +#if defined QNATIVESOCKETENGINE_DEBUG +#include +#include +#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 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; + } + // FIXME Set socket to nonblocking. While we are still a QNativeSocketEngine this is done already. + // Uncomment the following when we switch to QSymbianSocketEngine. + // setOption(NonBlockingSocketOption, 1) + + 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 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; + } + // FIXME Qt Handle of new socket must be retrieved from QSymbianSocketManager + // and then returned. Not the SubSessionHandle! Also set the socket to nonblocking. + return blankSocket.SubSessionHandle(); +} + +qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const +{ + int nbytes = 0; + qint64 available = 0; + // FIXME is this the right thing also for UDP? + // What is expected for UDP, the length for the next packet I guess? + 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)? + // Why = Could it be that this is about header lengths etc? if yes + // this could be pretty broken, especially for IPv6 +} + +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(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; + } + // TODO: for selecting, we can use getOpt(KSOSelectPoll) to get the select result + // and KIOCtlSelect for the selecting. + + 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::nativeJoinMulticast