From 4d78d02b5c97f48826e9caba6bab9d22249def37 Mon Sep 17 00:00:00 2001 From: Laurent Gomila Date: Mon, 17 Jun 2013 18:47:16 +0200 Subject: [PATCH] Fixed TCP packet data corruption in non-blocking mode (#402, #119) --- src/SFML/Network/TcpSocket.cpp | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/SFML/Network/TcpSocket.cpp b/src/SFML/Network/TcpSocket.cpp index 62761c28a..c7eb6ec8b 100644 --- a/src/SFML/Network/TcpSocket.cpp +++ b/src/SFML/Network/TcpSocket.cpp @@ -282,27 +282,28 @@ Socket::Status TcpSocket::send(Packet& packet) // This means that we have to send the packet size first, so that the // receiver knows the actual end of the packet in the data stream. + // We allocate an extra memory block so that the size can be sent + // together with the data in a single call. This may seem inefficient, + // but it is actually required to avoid partial send, which could cause + // data corruption on the receiving end. + // Get the data to send from the packet std::size_t size = 0; const void* data = packet.onSend(size); - // First send the packet size + // First convert the packet size to network byte order Uint32 packetSize = htonl(static_cast(size)); - Status status = send(reinterpret_cast(&packetSize), sizeof(packetSize)); + + // Allocate memory for the data block to send + std::vector blockToSend(sizeof(packetSize) + size); + + // Copy the packet size and data into the block to send + std::memcpy(&blockToSend[0], &packetSize, sizeof(packetSize)); + if (size > 0) + std::memcpy(&blockToSend[0] + sizeof(packetSize), data, size); - // Make sure that the size was properly sent - if (status != Done) - return status; - - // Send the packet data - if (packetSize > 0) - { - return send(data, size); - } - else - { - return Done; - } + // Send the data block + return send(&blockToSend[0], blockToSend.size()); }