summaryrefslogtreecommitdiffstats
path: root/src/network/socket
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2017-08-23 13:11:34 -0700
committerThiago Macieira <thiago.macieira@intel.com>2017-09-13 16:19:54 +0000
commita9ff368ac7244009b7a961388fe95372fbd7179c (patch)
treeecffd0cb4921ae95133bd8a8468ee985804a0d9c /src/network/socket
parent3b61cd6ad738b8479bf216dcf736bb935e8812df (diff)
QNativeSocketEngine: reduce memory usage in nativePendingDatagramSize()
The Windows implementation had the right idea: by using a chunked read, we can tell the OS to reuse the same buffer over and over, so we don't need to grow a buffer to the size of the datagram when peeking. This commit implements that strategy on Unix and changes both implementations to start at 1500 bytes instead of 8192 (1500 is more than enough for almost all datagrams we're going to receive). Let's also not use a static buffer, but a stack-based one. No need to dedicate 1500 (or, worse, 8192) bytes for something that is only seldom called. Change-Id: I320d9d2f42284a69a4cbfffd14dd92a6775bf28b Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Diffstat (limited to 'src/network/socket')
-rw-r--r--src/network/socket/qnativesocketengine_unix.cpp30
-rw-r--r--src/network/socket/qnativesocketengine_win.cpp8
2 files changed, 29 insertions, 9 deletions
diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp
index a8f756dc31..bf94f6f606 100644
--- a/src/network/socket/qnativesocketengine_unix.cpp
+++ b/src/network/socket/qnativesocketengine_unix.cpp
@@ -868,22 +868,42 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const
if (recvResult != -1)
recvResult = value;
#else
- QVarLengthArray<char, 8192> udpMessagePeekBuffer(8192);
+ // We need to grow the buffer to fit the entire datagram.
+ // We start at 1500 bytes (the MTU for Ethernet V2), which should catch
+ // almost all uses (effective MTU for UDP under IPv4 is 1468), except
+ // for localhost datagrams and those reassembled by the IP layer.
+ char udpMessagePeekBuffer[1500];
+ struct msghdr msg;
+ struct iovec vec;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = &vec;
+ msg.msg_iovlen = 1;
+ vec.iov_base = udpMessagePeekBuffer;
+ vec.iov_len = sizeof(udpMessagePeekBuffer);
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 = ::recvmsg(socketDescriptor, &msg, MSG_PEEK);
if (recvResult == -1 && errno == EINTR)
continue;
- if (recvResult != (ssize_t) udpMessagePeekBuffer.size())
+ // was the result truncated?
+ if ((msg.msg_flags & MSG_TRUNC) == 0)
break;
- udpMessagePeekBuffer.resize(udpMessagePeekBuffer.size() * 2);
+ // grow by 16 times
+ msg.msg_iovlen *= 16;
+ if (msg.msg_iov != &vec)
+ delete[] msg.msg_iov;
+ msg.msg_iov = new struct iovec[msg.msg_iovlen];
+ std::fill_n(msg.msg_iov, msg.msg_iovlen, vec);
}
+
+ if (msg.msg_iov != &vec)
+ delete[] msg.msg_iov;
#endif
#if defined (QNATIVESOCKETENGINE_DEBUG)
diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp
index e21bf29d4b..7556bb98f4 100644
--- a/src/network/socket/qnativesocketengine_win.cpp
+++ b/src/network/socket/qnativesocketengine_win.cpp
@@ -1146,10 +1146,10 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const
DWORD bufferCount = 5;
WSABUF * buf = 0;
for (;;) {
- // the data written to udpMessagePeekBuffer is discarded, so
- // this function is still reentrant although it might not look
- // so.
- static char udpMessagePeekBuffer[8192];
+ // We start at 1500 bytes (the MTU for Ethernet V2), which should catch
+ // almost all uses (effective MTU for UDP under IPv4 is 1468), except
+ // for localhost datagrams and those reassembled by the IP layer.
+ char udpMessagePeekBuffer[1500];
buf = new WSABUF[bufferCount];
for (DWORD i=0; i<bufferCount; i++) {