diff options
Diffstat (limited to 'src/network/socket/qnativesocketengine_unix.cpp')
-rw-r--r-- | src/network/socket/qnativesocketengine_unix.cpp | 330 |
1 files changed, 290 insertions, 40 deletions
diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp index 0a7c6a1aee..cf31832f12 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" @@ -60,15 +59,150 @@ #include <arpa/inet.h> #endif +#ifdef Q_OS_SYMBIAN +#include <private/qeventdispatcher_symbian_p.h> +#endif + #if defined QNATIVESOCKETENGINE_DEBUG #include <qstring.h> #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 +static inline int qt_socket_connect(int s, const struct sockaddr * addrptr, socklen_t namelen) +{ + return ::connect(s, addrptr, namelen); +} +#if defined(connect) +# undef connect +#endif + +static inline int qt_socket_bind(int s, const struct sockaddr * addrptr, socklen_t namelen) +{ + return ::bind(s, addrptr, namelen); +} +#if defined(bind) +# undef bind +#endif + +static inline int qt_socket_write(int socket, const char *data, qint64 len) +{ + return ::write(socket, data, len); +} +#if defined(write) +# undef write +#endif + +static inline int qt_socket_read(int socket, char *data, qint64 len) +{ + return ::read(socket, data, len); +} +#if defined(read) +# undef read +#endif + +static inline int qt_socket_recv(int socket, void *data, size_t length, int flags) +{ + return ::recv(socket, data, length, flags); +} +#if defined(recv) +# undef recv +#endif + +static inline int qt_socket_recvfrom(int socket, void *data, size_t length, + int flags, struct sockaddr *address, + socklen_t *address_length) +{ + return ::recvfrom(socket, data, length, flags, address, address_length); +} +#if defined(recvfrom) +# undef recvfrom +#endif + +static inline int qt_socket_sendto(int socket, const void *data, size_t length, + int flags, const struct sockaddr *dest_addr, + socklen_t dest_length) +{ + return ::sendto(socket, data, length, flags, dest_addr, dest_length); +} +#if defined(sendto) +# undef sendto +#endif +static inline int qt_socket_close(int socket) +{ + return ::close(socket); +} +#if defined(close) +# undef close +#endif + +static inline int qt_socket_fcntl(int socket, int command, int option) +{ + return ::fcntl(socket, command, option); +} +#if defined(fcntl) +# undef fcntl +#endif + +static inline int qt_socket_ioctl(int socket, int command, char *option) +{ + return ::ioctl(socket, command, option); +} +#if defined(ioctl) +# undef ioctl +#endif + +static inline int qt_socket_getsockname(int socket, struct sockaddr *address, socklen_t *address_len) +{ + return ::getsockname(socket, address, address_len); +} +#if defined(getsockname) +# undef getsockname +#endif + +static inline int qt_socket_getpeername(int socket, struct sockaddr *address, socklen_t *address_len) +{ + return ::getpeername(socket, address, address_len); +} +#if defined(getpeername) +# undef getpeername +#endif + +static inline int qt_socket_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) +{ + return ::select(nfds, readfds, writefds, exceptfds, timeout); +} + +#if defined(select) +# undef select +#endif + +static inline int qt_socket_getsockopt(int socket, int level, int optname, void *optval, socklen_t *optlen) +{ + return ::getsockopt(socket, level, optname, optval, optlen); +} + +#if defined(getsockopt) +# undef getsockopt +#endif + +static inline int qt_socket_setsockopt(int socket, int level, int optname, void *optval, socklen_t optlen) +{ + return ::setsockopt(socket, level, optname, optval, optlen); +} + +#if defined(setsockopt) +# undef setsockopt +#endif + #if defined QNATIVESOCKETENGINE_DEBUG /* @@ -103,6 +237,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 +246,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 +268,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 @@ -190,7 +329,8 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc } // Ensure that the socket is closed on exec*(). - ::fcntl(socket, F_SETFD, FD_CLOEXEC); + qt_socket_fcntl(socket, F_SETFD, FD_CLOEXEC); + socketDescriptor = socket; return true; } @@ -237,8 +377,9 @@ int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) co int v = -1; QT_SOCKOPTLEN_T len = sizeof(v); - if (::getsockopt(socketDescriptor, level, n, (char *) &v, &len) != -1) + if (qt_socket_getsockopt(socketDescriptor, level, n, (char *) &v, &len) != -1) return v; + return -1; } @@ -268,14 +409,14 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt case QNativeSocketEngine::NonBlockingSocketOption: { // Make the socket nonblocking. #if !defined(Q_OS_VXWORKS) - int flags = ::fcntl(socketDescriptor, F_GETFL, 0); + int flags = qt_socket_fcntl(socketDescriptor, F_GETFL, 0); if (flags == -1) { #ifdef QNATIVESOCKETENGINE_DEBUG perror("QNativeSocketEnginePrivate::setOption(): fcntl(F_GETFL) failed"); #endif return false; } - if (::fcntl(socketDescriptor, F_SETFL, flags | O_NONBLOCK) == -1) { + if (qt_socket_fcntl(socketDescriptor, F_SETFL, flags | O_NONBLOCK) == -1) { #ifdef QNATIVESOCKETENGINE_DEBUG perror("QNativeSocketEnginePrivate::setOption(): fcntl(F_SETFL) failed"); #endif @@ -293,7 +434,9 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt return true; } case QNativeSocketEngine::AddressReusable: -#ifdef SO_REUSEPORT +#ifdef Q_OS_SYMBIAN + n = SO_REUSEADDR; +#elif SO_REUSEPORT n = SO_REUSEPORT; #else n = SO_REUSEADDR; @@ -313,11 +456,15 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt break; } - return ::setsockopt(socketDescriptor, level, n, (char *) &v, sizeof(v)) == 0; + return qt_socket_setsockopt(socketDescriptor, level, n, (char *) &v, sizeof(v)) == 0; } 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 +503,8 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 // unreachable } - int connectResult = QT_SOCKET_CONNECT(socketDescriptor, sockAddrPtr, sockAddrSize); + int connectResult = qt_socket_connect(socketDescriptor, sockAddrPtr, sockAddrSize); + if (connectResult == -1) { switch (errno) { case EISCONN: @@ -459,7 +607,8 @@ bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16 // unreachable } - int bindResult = QT_SOCKET_BIND(socketDescriptor, sockAddrPtr, sockAddrSize); + int bindResult = qt_socket_bind(socketDescriptor, sockAddrPtr, sockAddrSize); + if (bindResult < 0) { switch(errno) { case EADDRINUSE: @@ -527,8 +676,15 @@ int QNativeSocketEnginePrivate::nativeAccept() #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*() + qt_socket_fcntl(acceptedDescriptor, F_SETFD, FD_CLOEXEC); + } else { + qWarning("QNativeSocketEnginePrivate::nativeAccept() - acceptedDescriptor <= 0"); + } + return acceptedDescriptor; } @@ -558,7 +714,7 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const ssize_t readBytes; do { char c; - readBytes = ::recvfrom(socketDescriptor, &c, 1, MSG_PEEK, &storage.a, &storageSize); + readBytes = qt_socket_recvfrom(socketDescriptor, &c, 1, MSG_PEEK, &storage.a, &storageSize); } while (readBytes == -1 && errno == EINTR); // If there's no error, or if our buffer was too small, there must be a @@ -572,16 +728,25 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const return result; } +#ifdef Q_OS_SYMBIAN +qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const +{ + size_t nbytes = 0; + qt_socket_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); + recvResult = qt_socket_recv(socketDescriptor, udpMessagePeekBuffer.data(), + udpMessagePeekBuffer.size(), MSG_PEEK); if (recvResult == -1 && errno == EINTR) continue; @@ -597,7 +762,7 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const return qint64(recvResult); } - +#endif qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxSize, QHostAddress *address, quint16 *port) { @@ -609,7 +774,7 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS ssize_t recvFromResult = 0; do { char c; - recvFromResult = ::recvfrom(socketDescriptor, maxSize ? data : &c, maxSize ? maxSize : 1, + recvFromResult = qt_socket_recvfrom(socketDescriptor, maxSize ? data : &c, maxSize ? maxSize : 1, 0, &aa.a, &sz); } while (recvFromResult == -1 && errno == EINTR); @@ -639,28 +804,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); @@ -698,7 +862,7 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters() // Determine local address memset(&sa, 0, sizeof(sa)); - if (::getsockname(socketDescriptor, &sa.a, &sockAddrSize) == 0) { + if (qt_socket_getsockname(socketDescriptor, &sa.a, &sockAddrSize) == 0) { qt_socket_getPortAndAddress(&sa, &localPort, &localAddress); // Determine protocol family @@ -722,13 +886,13 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters() } // Determine the remote address - if (!::getpeername(socketDescriptor, &sa.a, &sockAddrSize)) + if (!qt_socket_getpeername(socketDescriptor, &sa.a, &sockAddrSize)) qt_socket_getPortAndAddress(&sa, &peerPort, &peerAddress); // 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 (qt_socket_getsockopt(socketDescriptor, SOL_SOCKET, SO_TYPE, &value, &valueSize) == 0) { if (value == SOCK_STREAM) socketType = QAbstractSocket::TcpSocket; else if (value == SOCK_DGRAM) @@ -759,7 +923,7 @@ void QNativeSocketEnginePrivate::nativeClose() #if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEngine::nativeClose()"); #endif - ::close(socketDescriptor); + qt_socket_close(socketDescriptor); } qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len) @@ -773,7 +937,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_socket_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 +980,7 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize) ssize_t r = 0; do { - r = ::read(socketDescriptor, data, maxSize); + r = qt_socket_read(socketDescriptor, data, maxSize); } while (r == -1 && errno == EINTR); if (r < 0) { @@ -833,6 +998,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 +1031,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 fdexec; + FD_ZERO(&fdexec); + FD_SET(socketDescriptor, &fdexec); +#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_socket_select(socketDescriptor + 1, &fds, 0, &fdexec, 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_socket_select(socketDescriptor + 1, 0, &fds, &fdexec, 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, &fdexec); + } + if(selectForExec) { + qWarning("nativeSelect (selectForRead %d, retVal %d, errno %d) Unexpected expectfds ready in 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 +1082,69 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c if (checkWrite) FD_SET(socketDescriptor, &fdwrite); +#ifdef Q_OS_SYMBIAN + fd_set fdexec; + FD_ZERO(&fdexec); + FD_SET(socketDescriptor, &fdexec); +#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_socket_select(socketDescriptor + 1, &fdread, &fdwrite, &fdexec, 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, &fdexec); + } + 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; } |