summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/network/socket/qnativesocketengine_p.h35
-rw-r--r--src/network/socket/qnativesocketengine_unix.cpp86
-rw-r--r--src/network/socket/qnativesocketengine_win.cpp82
-rw-r--r--src/network/socket/qnet_unix_p.h27
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