From 786408c5bcc4261f22db04932c21bcfb20be8807 Mon Sep 17 00:00:00 2001 From: LaurentGom Date: Tue, 2 Mar 2010 12:00:12 +0000 Subject: [PATCH] Sockets can now handle properly the situation where the packet size is received in multiple chunks git-svn-id: https://sfml.svn.sourceforge.net/svnroot/sfml/trunk@1433 4e206d99-4929-0410-ac5d-dfc041789085 --- include/SFML/Network/SocketTCP.hpp | 6 ++++-- include/SFML/Network/SocketUDP.hpp | 6 ++++-- src/SFML/Network/SocketTCP.cpp | 18 ++++++++++++++---- src/SFML/Network/SocketUDP.cpp | 25 ++++++++++++++----------- 4 files changed, 36 insertions(+), 19 deletions(-) diff --git a/include/SFML/Network/SocketTCP.hpp b/include/SFML/Network/SocketTCP.hpp index 964686a5..8929dc95 100644 --- a/include/SFML/Network/SocketTCP.hpp +++ b/include/SFML/Network/SocketTCP.hpp @@ -214,8 +214,10 @@ private : // Member data //////////////////////////////////////////////////////////// SocketHelper::SocketType mySocket; ///< Socket descriptor - std::vector myPendingPacket; ///< Data of the current pending packet, if any (in non-blocking mode) - Int32 myPendingPacketSize; ///< Size of the current pending packet, if any (in non-blocking mode) + Uint32 myPendingHeader; ///< Data of the current pending packet header, if any + Uint32 myPendingHeaderSize; ///< Size of the current pending packet header, if any + std::vector myPendingPacket; ///< Data of the current pending packet, if any + Int32 myPendingPacketSize; ///< Size of the current pending packet, if any bool myIsBlocking; ///< Is the socket blocking or non-blocking ? }; diff --git a/include/SFML/Network/SocketUDP.hpp b/include/SFML/Network/SocketUDP.hpp index 37df3f7d..7cb6b19d 100644 --- a/include/SFML/Network/SocketUDP.hpp +++ b/include/SFML/Network/SocketUDP.hpp @@ -215,8 +215,10 @@ private : //////////////////////////////////////////////////////////// SocketHelper::SocketType mySocket; ///< Socket identifier unsigned short myPort; ///< Port to which the socket is bound - std::vector myPendingPacket; ///< Data of the current pending packet, if any (in non-blocking mode) - Int32 myPendingPacketSize; ///< Size of the current pending packet, if any (in non-blocking mode) + Uint32 myPendingHeader; ///< Data of the current pending packet header, if any + Uint32 myPendingHeaderSize; ///< Size of the current pending packet header, if any + std::vector myPendingPacket; ///< Data of the current pending packet, if any + Int32 myPendingPacketSize; ///< Size of the current pending packet, if any bool myIsBlocking; ///< Is the socket blocking or non-blocking ? }; diff --git a/src/SFML/Network/SocketTCP.cpp b/src/SFML/Network/SocketTCP.cpp index 61a01bc2..6a200fce 100644 --- a/src/SFML/Network/SocketTCP.cpp +++ b/src/SFML/Network/SocketTCP.cpp @@ -344,11 +344,20 @@ Socket::Status SocketTCP::Receive(Packet& PacketToReceive) std::size_t Received = 0; if (myPendingPacketSize < 0) { - Socket::Status Status = Receive(reinterpret_cast(&PacketSize), sizeof(PacketSize), Received); - if (Status != Socket::Done) - return Status; + // Loop until we've received the entire size of the packet + // (even a 4 bytes variable may be received in more than one call) + while (myPendingHeaderSize < sizeof(myPendingHeader)) + { + char* Data = reinterpret_cast(&myPendingHeader) + myPendingHeaderSize; + Socket::Status Status = Receive(Data, sizeof(myPendingHeader) - myPendingHeaderSize, Received); + myPendingHeaderSize += Received; - PacketSize = ntohl(PacketSize); + if (Status != Socket::Done) + return Status; + } + + PacketSize = ntohl(myPendingHeader); + myPendingHeaderSize = 0; } else { @@ -472,6 +481,7 @@ void SocketTCP::Create(SocketHelper::SocketType Descriptor) myIsBlocking = true; // Reset the pending packet + myPendingHeaderSize = 0; myPendingPacket.clear(); myPendingPacketSize = -1; diff --git a/src/SFML/Network/SocketUDP.cpp b/src/SFML/Network/SocketUDP.cpp index 0c977cdc..c1fbc7b7 100644 --- a/src/SFML/Network/SocketUDP.cpp +++ b/src/SFML/Network/SocketUDP.cpp @@ -244,20 +244,25 @@ Socket::Status SocketUDP::Send(Packet& PacketToSend, const IPAddress& Address, u //////////////////////////////////////////////////////////// Socket::Status SocketUDP::Receive(Packet& PacketToReceive, IPAddress& Address, unsigned short& Port) { - // This is not safe at all, as data can be lost, duplicated, or arrive in a different order. - // So if a packet is split into more than one chunk, nobody knows what could happen... - // Conclusion : we shouldn't use packets with UDP, unless we build a more complex protocol on top of it. - // We start by getting the size of the incoming packet Uint32 PacketSize = 0; std::size_t Received = 0; if (myPendingPacketSize < 0) { - Socket::Status Status = Receive(reinterpret_cast(&PacketSize), sizeof(PacketSize), Received, Address, Port); - if (Status != Socket::Done) - return Status; + // Loop until we've received the entire size of the packet + // (even a 4 bytes variable may be received in more than one call) + while (myPendingHeaderSize < sizeof(myPendingHeader)) + { + char* Data = reinterpret_cast(&myPendingHeader) + myPendingHeaderSize; + Socket::Status Status = Receive(Data, sizeof(myPendingHeader) - myPendingHeaderSize, Received, Address, Port); + myPendingHeaderSize += Received; - PacketSize = ntohl(PacketSize); + if (Status != Socket::Done) + return Status; + } + + PacketSize = ntohl(myPendingHeader); + myPendingHeaderSize = 0; } else { @@ -265,9 +270,6 @@ Socket::Status SocketUDP::Receive(Packet& PacketToReceive, IPAddress& Address, u PacketSize = myPendingPacketSize; } - // Clear the user packet - PacketToReceive.Clear(); - // Use another address instance for receiving the packet data ; // chunks of data coming from a different sender will be discarded (and lost...) IPAddress Sender; @@ -402,6 +404,7 @@ void SocketUDP::Create(SocketHelper::SocketType Descriptor) myPort = 0; // Reset the pending packet + myPendingHeaderSize = 0; myPendingPacket.clear(); myPendingPacketSize = -1;