diff options
Diffstat (limited to 'src/network/socket/qnativesocketengine_unix.cpp')
-rw-r--r-- | src/network/socket/qnativesocketengine_unix.cpp | 177 |
1 files changed, 146 insertions, 31 deletions
diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp index 0a7c6a1..4388382 100644 --- a/src/network/socket/qnativesocketengine_unix.cpp +++ b/src/network/socket/qnativesocketengine_unix.cpp @@ -40,7 +40,6 @@ ****************************************************************************/ //#define QNATIVESOCKETENGINE_DEBUG - #include "qnativesocketengine_p.h" #include "private/qnet_unix_p.h" #include "qiodevice.h" @@ -65,7 +64,12 @@ #include <ctype.h> #endif +#ifdef Q_OS_SYMBIAN // ### TODO: Are these headers right? +#include <sys/socket.h> +#include <netinet/in.h> +#else #include <netinet/tcp.h> +#endif QT_BEGIN_NAMESPACE @@ -103,6 +107,7 @@ static QByteArray qt_prettyDebug(const char *data, int len, int maxSize) 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)) { @@ -111,6 +116,10 @@ static void qt_ignore_sigpipe() 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 } /* @@ -129,7 +138,7 @@ static inline void qt_socket_getPortAndAddress(const qt_sockaddr *s, quint16 *po *addr = tmpAddress; #ifndef QT_NO_IPV6IFNAME char scopeid[IFNAMSIZ]; - if (::if_indextoname(s->a6.sin6_scope_id, scopeid) > 0) { + if (::if_indextoname(s->a6.sin6_scope_id, scopeid)) { addr->setScopeId(QLatin1String(scopeid)); } else #endif @@ -191,6 +200,7 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc // Ensure that the socket is closed on exec*(). ::fcntl(socket, F_SETFD, FD_CLOEXEC); + socketDescriptor = socket; return true; } @@ -239,6 +249,7 @@ int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) co QT_SOCKOPTLEN_T len = sizeof(v); if (::getsockopt(socketDescriptor, level, n, (char *) &v, &len) != -1) return v; + return -1; } @@ -318,6 +329,10 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 port) { +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug("QNativeSocketEnginePrivate::nativeConnect() : %d ", socketDescriptor); +#endif + struct sockaddr_in sockAddrIPv4; struct sockaddr *sockAddrPtr = 0; QT_SOCKLEN_T sockAddrSize = 0; @@ -356,7 +371,8 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 // unreachable } - int connectResult = QT_SOCKET_CONNECT(socketDescriptor, sockAddrPtr, sockAddrSize); + int connectResult = qt_safe_connect(socketDescriptor, sockAddrPtr, sockAddrSize); + if (connectResult == -1) { switch (errno) { case EISCONN: @@ -460,6 +476,7 @@ bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16 } int bindResult = QT_SOCKET_BIND(socketDescriptor, sockAddrPtr, sockAddrSize); + if (bindResult < 0) { switch(errno) { case EADDRINUSE: @@ -524,11 +541,15 @@ bool QNativeSocketEnginePrivate::nativeListen(int backlog) int QNativeSocketEnginePrivate::nativeAccept() { int acceptedDescriptor = qt_safe_accept(socketDescriptor, 0, 0); -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeAccept() == %i", acceptedDescriptor); -#endif - // Ensure that the socket is closed on exec*() - ::fcntl(acceptedDescriptor, F_SETFD, FD_CLOEXEC); + + //check if we have vaild descriptor at all + if(acceptedDescriptor > 0) { + // Ensure that the socket is closed on exec*() + ::fcntl(acceptedDescriptor, F_SETFD, FD_CLOEXEC); + } else { + qWarning("QNativeSocketEnginePrivate::nativeAccept() - acceptedDescriptor <= 0"); + } + return acceptedDescriptor; } @@ -572,16 +593,25 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const return result; } +#ifdef Q_OS_SYMBIAN +qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const +{ + size_t nbytes = 0; + ::ioctl(socketDescriptor, E32IONREAD, (char *) &nbytes); + return qint64(nbytes-28); +} +#else qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const { QVarLengthArray<char, 8192> udpMessagePeekBuffer(8192); ssize_t recvResult = -1; + for (;;) { // the data written to udpMessagePeekBuffer is discarded, so // this function is still reentrant although it might not look // so. recvResult = ::recv(socketDescriptor, udpMessagePeekBuffer.data(), - udpMessagePeekBuffer.size(), MSG_PEEK); + udpMessagePeekBuffer.size(), MSG_PEEK); if (recvResult == -1 && errno == EINTR) continue; @@ -597,7 +627,7 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const return qint64(recvResult); } - +#endif qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxSize, QHostAddress *address, quint16 *port) { @@ -639,28 +669,27 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l #if !defined(QT_NO_IPV6) struct sockaddr_in6 sockAddrIPv6; if (host.protocol() == QAbstractSocket::IPv6Protocol) { - memset(&sockAddrIPv6, 0, sizeof(sockAddrIPv6)); - sockAddrIPv6.sin6_family = AF_INET6; - sockAddrIPv6.sin6_port = htons(port); - - Q_IPV6ADDR tmp = host.toIPv6Address(); - memcpy(&sockAddrIPv6.sin6_addr.s6_addr, &tmp, sizeof(tmp)); - sockAddrSize = sizeof(sockAddrIPv6); - sockAddrPtr = (struct sockaddr *)&sockAddrIPv6; + memset(&sockAddrIPv6, 0, sizeof(sockAddrIPv6)); + sockAddrIPv6.sin6_family = AF_INET6; + sockAddrIPv6.sin6_port = htons(port); + + Q_IPV6ADDR tmp = host.toIPv6Address(); + memcpy(&sockAddrIPv6.sin6_addr.s6_addr, &tmp, sizeof(tmp)); + sockAddrSize = sizeof(sockAddrIPv6); + sockAddrPtr = (struct sockaddr *)&sockAddrIPv6; } else #endif if (host.protocol() == QAbstractSocket::IPv4Protocol) { - memset(&sockAddrIPv4, 0, sizeof(sockAddrIPv4)); - sockAddrIPv4.sin_family = AF_INET; - sockAddrIPv4.sin_port = htons(port); - sockAddrIPv4.sin_addr.s_addr = htonl(host.toIPv4Address()); - sockAddrSize = sizeof(sockAddrIPv4); - sockAddrPtr = (struct sockaddr *)&sockAddrIPv4; + memset(&sockAddrIPv4, 0, sizeof(sockAddrIPv4)); + sockAddrIPv4.sin_family = AF_INET; + sockAddrIPv4.sin_port = htons(port); + sockAddrIPv4.sin_addr.s_addr = htonl(host.toIPv4Address()); + sockAddrSize = sizeof(sockAddrIPv4); + sockAddrPtr = (struct sockaddr *)&sockAddrIPv4; } // ignore the SIGPIPE signal qt_ignore_sigpipe(); - ssize_t sentBytes = qt_safe_sendto(socketDescriptor, data, len, 0, sockAddrPtr, sockAddrSize); @@ -728,7 +757,7 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters() // Determine the socket type (UDP/TCP) int value = 0; QT_SOCKOPTLEN_T valueSize = sizeof(int); - if (::getsockopt(socketDescriptor, SOL_SOCKET, SO_TYPE, (char *) &value, &valueSize) == 0) { + if (::getsockopt(socketDescriptor, SOL_SOCKET, SO_TYPE, &value, &valueSize) == 0) { if (value == SOCK_STREAM) socketType = QAbstractSocket::TcpSocket; else if (value == SOCK_DGRAM) @@ -759,7 +788,7 @@ void QNativeSocketEnginePrivate::nativeClose() #if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEngine::nativeClose()"); #endif - ::close(socketDescriptor); + qt_safe_close(socketDescriptor); } qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len) @@ -773,7 +802,8 @@ qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len) // of an interrupting signal. ssize_t writtenBytes; do { - writtenBytes = QT_WRITE(socketDescriptor, data, len); + writtenBytes = qt_safe_write(socketDescriptor, data, len); + // writtenBytes = QT_WRITE(socketDescriptor, data, len); ### TODO S60: Should this line be removed or the one above it? } while (writtenBytes < 0 && errno == EINTR); if (writtenBytes < 0) { @@ -815,7 +845,7 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize) ssize_t r = 0; do { - r = ::read(socketDescriptor, data, maxSize); + r = qt_safe_read(socketDescriptor, data, maxSize); } while (r == -1 && errno == EINTR); if (r < 0) { @@ -833,6 +863,9 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize) case EIO: setError(QAbstractSocket::NetworkError, ReadErrorString); break; +#ifdef Q_OS_SYMBIAN + case EPIPE: +#endif case ECONNRESET: #if defined(Q_OS_VXWORKS) case ESHUTDOWN: @@ -863,16 +896,46 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) co tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; +#ifdef Q_OS_SYMBIAN + fd_set fdexception; + FD_ZERO(&fdexception); + FD_SET(socketDescriptor, &fdexception); +#endif + int retval; if (selectForRead) +#ifndef Q_OS_SYMBIAN retval = qt_safe_select(socketDescriptor + 1, &fds, 0, 0, timeout < 0 ? 0 : &tv); +#else + retval = qt_safe_select(socketDescriptor + 1, &fds, 0, &fdexception, timeout < 0 ? 0 : &tv); +#endif else +#ifndef Q_OS_SYMBIAN retval = qt_safe_select(socketDescriptor + 1, 0, &fds, 0, timeout < 0 ? 0 : &tv); +#else + retval = qt_safe_select(socketDescriptor + 1, 0, &fds, &fdexception, timeout < 0 ? 0 : &tv); +#endif + + +#ifdef Q_OS_SYMBIAN + bool selectForExec = false; + if(retval != 0) { + if(retval < 0) { + qWarning("nativeSelect(....) returned < 0 for socket %d", socketDescriptor); + } + selectForExec = FD_ISSET(socketDescriptor, &fdexception); + } + if(selectForExec) { + qWarning("nativeSelect (selectForRead %d, retVal %d, errno %d) Unexpected exception for fd %d", + selectForRead, retval, errno, socketDescriptor); + } +#endif + return retval; } int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite, - bool *selectForRead, bool *selectForWrite) const + bool *selectForRead, bool *selectForWrite) const { fd_set fdread; FD_ZERO(&fdread); @@ -884,17 +947,69 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c if (checkWrite) FD_SET(socketDescriptor, &fdwrite); +#ifdef Q_OS_SYMBIAN + fd_set fdexception; + FD_ZERO(&fdexception); + FD_SET(socketDescriptor, &fdexception); +#endif + struct timeval tv; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; int ret; +#ifndef Q_OS_SYMBIAN ret = qt_safe_select(socketDescriptor + 1, &fdread, &fdwrite, 0, timeout < 0 ? 0 : &tv); +#else + QTime timer; + timer.start(); + + do { + ret = qt_safe_select(socketDescriptor + 1, &fdread, &fdwrite, &fdexception, timeout < 0 ? 0 : &tv); + bool selectForExec = false; + if(ret != 0) { + if(ret < 0) { + qWarning("nativeSelect(....) returned < 0 for socket %d", socketDescriptor); + } + selectForExec = FD_ISSET(socketDescriptor, &fdexception); + } + if(selectForExec) { + qWarning("nativeSelect (checkRead %d, checkWrite %d, ret %d, errno %d): Unexpected expectfds ready in fd %d", + checkRead, checkWrite, ret, errno, socketDescriptor); + if (checkRead) + FD_SET(socketDescriptor, &fdread); + if (checkWrite) + FD_SET(socketDescriptor, &fdwrite); + + if ((ret == -1) && ( errno == ECONNREFUSED || errno == EPIPE )) + ret = 1; + + } + + if (ret != -1 || errno != EINTR) { + break; + } + + if (timeout > 0) { + // recalculate the timeout + int t = timeout - timer.elapsed(); + if (t < 0) { + // oops, timeout turned negative? + ret = -1; + break; + } + + tv.tv_sec = t / 1000; + tv.tv_usec = (t % 1000) * 1000; + } + } while (true); +#endif + if (ret <= 0) return ret; - *selectForRead = FD_ISSET(socketDescriptor, &fdread); *selectForWrite = FD_ISSET(socketDescriptor, &fdwrite); + return ret; } |