summaryrefslogtreecommitdiffstats
path: root/src/network/socket/qnativesocketengine_unix.cpp
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2015-03-10 15:09:29 -0700
committerThiago Macieira <thiago.macieira@intel.com>2015-08-22 22:26:30 +0000
commitef05ad0ac500c10b1a3ae254d8a07968d6cf0c9e (patch)
treef2545760293240883c22bffe71d4fab48484dfc5 /src/network/socket/qnativesocketengine_unix.cpp
parent5b38454714fdbf8d4acffe482aaa32b91a4b5d98 (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.cpp86
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) {