diff options
-rw-r--r-- | src/network/socket/qnativesocketengine_p.h | 35 | ||||
-rw-r--r-- | src/network/socket/qnativesocketengine_unix.cpp | 86 | ||||
-rw-r--r-- | src/network/socket/qnativesocketengine_win.cpp | 82 | ||||
-rw-r--r-- | src/network/socket/qnet_unix_p.h | 27 |
4 files changed, 142 insertions, 88 deletions
diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h index fb36ce6204..29063b3a85 100644 --- a/src/network/socket/qnativesocketengine_p.h +++ b/src/network/socket/qnativesocketengine_p.h @@ -51,6 +51,7 @@ # include <netinet/in.h> #else # include <winsock2.h> +# include <mswsock.h> #endif QT_BEGIN_NAMESPACE @@ -70,6 +71,36 @@ struct qt_sockaddr_storage { #ifdef Q_OS_WIN #define QT_SOCKLEN_T int #define QT_SOCKOPTLEN_T int + +// The following definitions are copied from the MinGW header mswsock.h which +// was placed in the public domain. The WSASendMsg and WSARecvMsg functions +// were introduced with Windows Vista, so some Win32 headers are lacking them. +// There are no known versions of Windows CE or Embedded that contain them. +#ifndef Q_OS_WINCE +# ifndef WSAID_WSARECVMSG +typedef INT (WINAPI *LPFN_WSARECVMSG)(SOCKET s, LPWSAMSG lpMsg, + LPDWORD lpdwNumberOfBytesRecvd, + LPWSAOVERLAPPED lpOverlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); +# define WSAID_WSARECVMSG {0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}} +# endif +# ifndef WSAID_WSASENDMSG +typedef struct { + LPWSAMSG lpMsg; + DWORD dwFlags; + LPDWORD lpNumberOfBytesSent; + LPWSAOVERLAPPED lpOverlapped; + LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine; +} WSASENDMSG, *LPWSASENDMSG; + +typedef INT (WSAAPI *LPFN_WSASENDMSG)(SOCKET s, LPWSAMSG lpMsg, DWORD dwFlags, + LPDWORD lpNumberOfBytesSent, + LPWSAOVERLAPPED lpOverlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + +# define WSAID_WSASENDMSG {0xa441e712,0x754f,0x43ca,{0x84,0xa7,0x0d,0xee,0x44,0xcf,0x60,0x6d}} +# endif +#endif #endif // sockaddr_in6 size changed between old and new SDK @@ -185,6 +216,10 @@ public: QSocketNotifier *readNotifier, *writeNotifier, *exceptNotifier; +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + LPFN_WSASENDMSG sendmsg; + LPFN_WSARECVMSG recvmsg; +# endif enum ErrorString { NonBlockingInitFailedErrorString, BroadcastingInitFailedErrorString, diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp index 0e04096296..37651dcbc3 100644 --- a/src/network/socket/qnativesocketengine_unix.cpp +++ b/src/network/socket/qnativesocketengine_unix.cpp @@ -847,19 +847,29 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxSize, QIpPacketHeader *header, QAbstractSocketEngine::PacketHeaderOptions options) { + struct msghdr msg; + struct iovec vec; qt_sockaddr aa; + char c; + memset(&msg, 0, sizeof(msg)); memset(&aa, 0, sizeof(aa)); - QT_SOCKLEN_T sz; - sz = sizeof(aa); - ssize_t recvFromResult = 0; + // we need to receive at least one byte, even if our user isn't interested in it + vec.iov_base = maxSize ? data : &c; + vec.iov_len = maxSize ? maxSize : 1; + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + if (options & QAbstractSocketEngine::WantDatagramSender) { + msg.msg_name = &aa; + msg.msg_namelen = sizeof(aa); + } + + ssize_t recvResult = 0; do { - char c; - recvFromResult = ::recvfrom(socketDescriptor, maxSize ? data : &c, maxSize ? maxSize : 1, - 0, &aa.a, &sz); - } while (recvFromResult == -1 && errno == EINTR); + recvResult = ::recvmsg(socketDescriptor, &msg, 0); + } while (recvResult == -1 && errno == EINTR); - if (recvFromResult == -1) { + if (recvResult == -1) { setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString); if (header) header->clear(); @@ -870,46 +880,50 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS #if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEnginePrivate::nativeReceiveDatagram(%p \"%s\", %lli, %s, %i) == %lli", - data, qt_prettyDebug(data, qMin(recvFromResult, ssize_t(16)), recvFromResult).data(), maxSize, + data, qt_prettyDebug(data, qMin(recvResult, ssize_t(16)), recvResult).data(), maxSize, address ? address->toString().toLatin1().constData() : "(nil)", - port ? *port : 0, (qint64) recvFromResult); + port ? *port : 0, (qint64) recvResult); #endif - return qint64(maxSize ? recvFromResult : recvFromResult == -1 ? -1 : 0); + return qint64(maxSize ? recvResult : recvResult == -1 ? -1 : 0); } qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 len, const QIpPacketHeader &header) { - struct sockaddr_in sockAddrIPv4; - struct sockaddr *sockAddrPtr = 0; - QT_SOCKLEN_T sockAddrSize = 0; + struct msghdr msg; + struct iovec vec; + qt_sockaddr aa; - struct sockaddr_in6 sockAddrIPv6; - const QHostAddress &host = header.destinationAddress; - quint16 port = header.destinationPort; - if (host.protocol() == QAbstractSocket::IPv6Protocol + memset(&msg, 0, sizeof(msg)); + memset(&aa, 0, sizeof(aa)); + vec.iov_base = const_cast<char *>(data); + vec.iov_len = len; + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + msg.msg_name = &aa.a; + + if (header.destinationAddress.protocol() == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) { - memset(&sockAddrIPv6, 0, sizeof(sockAddrIPv6)); - sockAddrIPv6.sin6_family = AF_INET6; - sockAddrIPv6.sin6_port = htons(port); - sockAddrIPv6.sin6_scope_id = makeScopeId(host); - - Q_IPV6ADDR tmp = host.toIPv6Address(); - memcpy(&sockAddrIPv6.sin6_addr.s6_addr, &tmp, sizeof(tmp)); - sockAddrSize = sizeof(sockAddrIPv6); - sockAddrPtr = (struct sockaddr *)&sockAddrIPv6; - } else 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; + aa.a6.sin6_family = AF_INET6; + aa.a6.sin6_port = htons(header.destinationPort); + aa.a6.sin6_scope_id = makeScopeId(header.destinationAddress); + + Q_IPV6ADDR tmp = header.destinationAddress.toIPv6Address(); + memcpy(&aa.a6.sin6_addr, &tmp, sizeof(tmp)); + msg.msg_namelen = sizeof(aa.a6); + } else if (header.destinationAddress.protocol() == QAbstractSocket::IPv4Protocol) { + aa.a4.sin_family = AF_INET; + aa.a4.sin_port = htons(header.destinationPort); + aa.a4.sin_addr.s_addr = htonl(header.destinationAddress.toIPv4Address()); + msg.msg_namelen = sizeof(aa.a4); + } else { + // Don't know what IP type this is, let's hope it sends + msg.msg_name = 0; + msg.msg_namelen = 0; } - ssize_t sentBytes = qt_safe_sendto(socketDescriptor, data, len, - 0, sockAddrPtr, sockAddrSize); + ssize_t sentBytes = qt_safe_sendmsg(socketDescriptor, &msg, 0); if (sentBytes < 0) { switch (errno) { diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp index ed376eed95..9171ee36e0 100644 --- a/src/network/socket/qnativesocketengine_win.cpp +++ b/src/network/socket/qnativesocketengine_win.cpp @@ -420,6 +420,20 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc WS_ERROR_DEBUG(err); } } + + // get the pointer to sendmsg and recvmsg + DWORD bytesReturned; + GUID recvmsgguid = WSAID_WSARECVMSG; + if (WSAIoctl(socketDescriptor, SIO_GET_EXTENSION_FUNCTION_POINTER, + &recvmsgguid, sizeof(recvmsgguid), + &recvmsg, sizeof(recvmsg), &bytesReturned, NULL, NULL) == SOCKET_ERROR) + recvmsg = 0; + + GUID sendmsgguid = WSAID_WSASENDMSG; + if (WSAIoctl(socketDescriptor, SIO_GET_EXTENSION_FUNCTION_POINTER, + &sendmsgguid, sizeof(sendmsgguid), + &sendmsg, sizeof(sendmsg), &bytesReturned, NULL, NULL) == SOCKET_ERROR) + sendmsg = 0; #endif socketDescriptor = socket; @@ -1196,33 +1210,39 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const return ret; } +#ifdef Q_OS_WINCE +// Windows CE has no support for sendmsg or recvmsg. We set it to null here to simplify the code below. +static int (*const recvmsg)(...) = 0; +static int (*const sendmsg)(...) = 0; +#endif qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxLength, QIpPacketHeader *header, QAbstractSocketEngine::PacketHeaderOptions options) { - qint64 ret = 0; - + WSAMSG msg; + WSABUF buf; qt_sockaddr aa; + char c; + memset(&msg, 0, sizeof(msg)); memset(&aa, 0, sizeof(aa)); - QT_SOCKLEN_T sz; - sz = sizeof(aa); - WSABUF buf; - buf.buf = data; - buf.len = maxLength; -#if !defined(Q_OS_WINCE) - buf.buf = data; - buf.len = maxLength; -#else - char tmpChar; - buf.buf = data ? data : &tmpChar; - buf.len = maxLength; -#endif + // we need to receive at least one byte, even if our user isn't interested in it + buf.buf = maxLength ? data : &c; + buf.len = maxLength ? maxLength : 1; + msg.lpBuffers = &buf; + msg.dwBufferCount = 1; + msg.name = reinterpret_cast<LPSOCKADDR>(&aa); + msg.namelen = sizeof(aa); DWORD flags = 0; DWORD bytesRead = 0; - int wsaRet = ::WSARecvFrom(socketDescriptor, &buf, 1, &bytesRead, &flags, &aa.a, &sz,0,0); - if (wsaRet == SOCKET_ERROR) { + qint64 ret; + + if (recvmsg) + ret = recvmsg(socketDescriptor, &msg, &bytesRead, 0,0); + else + ret = ::WSARecvFrom(socketDescriptor, &buf, 1, &bytesRead, &flags, msg.name, &msg.namelen,0,0); + if (ret == SOCKET_ERROR) { int err = WSAGetLastError(); if (err == WSAEMSGSIZE) { // it is ok the buffer was to small if bytesRead is larger than @@ -1256,26 +1276,34 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxL qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 len, const QIpPacketHeader &header) { - qint64 ret = -1; - struct sockaddr_in sockAddrIPv4; - qt_sockaddr_in6 sockAddrIPv6; - struct sockaddr *sockAddrPtr = 0; - QT_SOCKLEN_T sockAddrSize = 0; - - setPortAndAddress(&sockAddrIPv4, &sockAddrIPv6, header.destinationPort, - header.destinationAddress, &sockAddrPtr, &sockAddrSize); - + WSAMSG msg; WSABUF buf; + qt_sockaddr aa; + + memset(&msg, 0, sizeof(msg)); + memset(&aa, 0, sizeof(aa)); #if !defined(Q_OS_WINCE) buf.buf = len ? (char*)data : 0; #else char tmp; buf.buf = len ? (char*)data : &tmp; #endif + msg.lpBuffers = &buf; + msg.dwBufferCount = 1; buf.len = len; + + setPortAndAddress(&aa.a4, &aa.a6, header.destinationPort, + header.destinationAddress, &msg.name, &msg.namelen); + DWORD flags = 0; DWORD bytesSent = 0; - if (::WSASendTo(socketDescriptor, &buf, 1, &bytesSent, flags, sockAddrPtr, sockAddrSize, 0,0) == SOCKET_ERROR) { + qint64 ret = -1; + if (sendmsg) { + ret = sendmsg(socketDescriptor, &msg, flags, &bytesSent, 0,0); + } else { + ret = ::WSASendTo(socketDescriptor, &buf, 1, &bytesSent, flags, msg.name, msg.namelen, 0,0); + } + if (ret == SOCKET_ERROR) { int err = WSAGetLastError(); WS_ERROR_DEBUG(err); switch (err) { diff --git a/src/network/socket/qnet_unix_p.h b/src/network/socket/qnet_unix_p.h index a5a87fc7c1..9626c53711 100644 --- a/src/network/socket/qnet_unix_p.h +++ b/src/network/socket/qnet_unix_p.h @@ -173,8 +173,7 @@ static inline in_addr_t qt_safe_inet_addr(const char *cp) #endif } -// VxWorks' headers do not specify any const modifiers -static inline int qt_safe_sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *to, QT_SOCKLEN_T tolen) +static inline int qt_safe_sendmsg(int sockfd, const struct msghdr *msg, int flags) { #ifdef MSG_NOSIGNAL flags |= MSG_NOSIGNAL; @@ -183,11 +182,7 @@ static inline int qt_safe_sendto(int sockfd, const void *buf, size_t len, int fl #endif int ret; -#ifdef Q_OS_VXWORKS - EINTR_LOOP(ret, ::sendto(sockfd, (char *) buf, len, flags, (struct sockaddr *) to, tolen)); -#else - EINTR_LOOP(ret, ::sendto(sockfd, buf, len, flags, to, tolen)); -#endif + EINTR_LOOP(ret, ::sendmsg(sockfd, msg, flags)); return ret; } @@ -199,24 +194,6 @@ static inline int qt_safe_recvmsg(int sockfd, struct msghdr *msg, int flags) return ret; } -// VxWorks' headers do not specify any const modifiers -static inline int qt_safe_sendmsg(int sockfd, const struct msghdr *msg, int flags) -{ -#ifdef MSG_NOSIGNAL - flags |= MSG_NOSIGNAL; -#else - qt_ignore_sigpipe(); -#endif - - int ret; -#ifdef Q_OS_VXWORKS - EINTR_LOOP(ret, ::sendmsg(sockfd, (struct msghdr *) msg, flags); -#else - EINTR_LOOP(ret, ::sendmsg(sockfd, msg, flags)); -#endif - return ret; -} - QT_END_NAMESPACE #endif // QNET_UNIX_P_H |