Added a way for partial sends over non-blocking TcpSockets to be handled properly.

This commit is contained in:
binary1248 2015-02-06 19:37:53 +01:00 committed by Lukas Dürrenberger
parent 67c7663c80
commit d790114df8
5 changed files with 66 additions and 9 deletions

View file

@ -37,6 +37,7 @@ namespace sf
////////////////////////////////////////////////////////////
Packet::Packet() :
m_readPos(0),
m_sendPos(0),
m_isValid(true)
{

View file

@ -218,6 +218,18 @@ void TcpSocket::disconnect()
////////////////////////////////////////////////////////////
Socket::Status TcpSocket::send(const void* data, std::size_t size)
{
if (!isBlocking())
err() << "Warning: Partial sends might not be handled properly." << std::endl;
std::size_t sent;
return send(data, size, sent);
}
////////////////////////////////////////////////////////////
Socket::Status TcpSocket::send(const void* data, std::size_t size, std::size_t& sent)
{
// Check the parameters
if (!data || (size == 0))
@ -227,16 +239,22 @@ Socket::Status TcpSocket::send(const void* data, std::size_t size)
}
// Loop until every byte has been sent
int sent = 0;
int sizeToSend = static_cast<int>(size);
for (int length = 0; length < sizeToSend; length += sent)
int result = 0;
for (sent = 0; sent < size; sent += result)
{
// Send a chunk of data
sent = ::send(getHandle(), static_cast<const char*>(data) + length, sizeToSend - length, flags);
result = ::send(getHandle(), static_cast<const char*>(data) + sent, size - sent, flags);
// Check for errors
if (sent < 0)
return priv::SocketImpl::getErrorStatus();
if (result < 0)
{
Status status = priv::SocketImpl::getErrorStatus();
if ((status == NotReady) && sent)
return Partial;
return status;
}
}
return Done;
@ -294,17 +312,30 @@ Socket::Status TcpSocket::send(Packet& packet)
// First convert the packet size to network byte order
Uint32 packetSize = htonl(static_cast<Uint32>(size));
// Allocate memory for the data block to send
std::vector<char> 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);
// Send the data block
return send(&blockToSend[0], blockToSend.size());
std::size_t sent;
Status status = send(&blockToSend[0] + packet.m_sendPos, blockToSend.size() - packet.m_sendPos, sent);
// In the case of a partial send, record the location to resume from
if (status == Partial)
{
packet.m_sendPos += sent;
}
else if (status == Done)
{
packet.m_sendPos = 0;
}
return status;
}