diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2015-03-10 15:09:29 -0700 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2015-08-22 22:26:30 +0000 |
commit | ef05ad0ac500c10b1a3ae254d8a07968d6cf0c9e (patch) | |
tree | f2545760293240883c22bffe71d4fab48484dfc5 /src/network/socket/qnativesocketengine_unix.cpp | |
parent | 5b38454714fdbf8d4acffe482aaa32b91a4b5d98 (diff) |
QNativeSocketEngine: use sendmsg/recvmsg instead of sendto/recvfrom
We'll need to use these functions instead of the ones we're currently
using in order to access the ancillary data.
Note that on Windows the two functions aren't globals, but must be
obtained via ioctl, which means they can fail. If they do, we fall back
to using WSARecvFrom/WSASendTo
Change-Id: Iee8cbc07c4434ce9b560ffff13ca4284acd24132
Reviewed-by: Richard J. Moore <rich@kde.org>
Diffstat (limited to 'src/network/socket/qnativesocketengine_unix.cpp')
-rw-r--r-- | src/network/socket/qnativesocketengine_unix.cpp | 86 |
1 files changed, 50 insertions, 36 deletions
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) { |