Network: Add support for sending/receiving NetPacket over UDP/TCP

Former-commit-id: 5c09a5fa8b499e4204d2312f6d04d8554093a5a4
This commit is contained in:
Lynix
2016-02-04 14:51:26 +01:00
parent 6c0215952d
commit 08caff5ea3
4 changed files with 149 additions and 3 deletions

View File

@@ -6,7 +6,7 @@
#include <Nazara/Core/CallOnExit.hpp>
#include <Nazara/Core/Error.hpp>
#include <limits>
#include <Nazara/Network/Debug.hpp>
#include <Nazara/Network/NetPacket.hpp>
#if defined(NAZARA_PLATFORM_WINDOWS)
#include <Nazara/Network/Win32/SocketImpl.hpp>
@@ -16,6 +16,8 @@
#error Missing implementation: Socket
#endif
#include <Nazara/Network/Debug.hpp>
namespace Nz
{
SocketState TcpClient::Connect(const IpAddress& remoteAddress)
@@ -141,6 +143,66 @@ namespace Nz
return true;
}
bool TcpClient::ReceivePacket(NetPacket* packet)
{
//TODO: Every packet requires at least two Receive call, using an internal buffer of a fixed size would prevent this
NazaraAssert(packet, "Invalid packet");
if (!m_pendingPacket.headerReceived)
{
m_pendingPacket.data.Resize(NetPacket::HeaderSize);
std::size_t received;
if (!Receive(&m_pendingPacket.data[m_pendingPacket.received], NetPacket::HeaderSize - m_pendingPacket.received, &received))
return false;
m_pendingPacket.received += received;
NazaraAssert(m_pendingPacket.received <= NetPacket::HeaderSize, "Received more data than header size");
if (m_pendingPacket.received >= NetPacket::HeaderSize)
{
UInt16 size;
if (!NetPacket::DecodeHeader(m_pendingPacket.data.GetConstBuffer(), &size, &m_pendingPacket.netcode))
{
m_lastError = SocketError_Packet;
NazaraWarning("Invalid header data");
return false;
}
m_pendingPacket.data.Resize(size - NetPacket::HeaderSize);
m_pendingPacket.headerReceived = true;
m_pendingPacket.received = 0;
}
}
// We may have just received the header now
if (m_pendingPacket.headerReceived)
{
UInt16 packetSize = static_cast<UInt16>(m_pendingPacket.data.GetSize()); //< Total packet size
std::size_t received;
if (!Receive(&m_pendingPacket.data[m_pendingPacket.received], packetSize - m_pendingPacket.received, &received))
return false;
m_pendingPacket.received += received;
NazaraAssert(m_pendingPacket.received <= packetSize, "Received more data than packet size");
if (m_pendingPacket.received >= packetSize)
{
// Okay we received the whole packet, copy it
packet->Reset(m_pendingPacket.netcode, m_pendingPacket.data.GetConstBuffer(), m_pendingPacket.data.GetSize());
// And reset every state
m_pendingPacket.data.Clear();
m_pendingPacket.headerReceived = false;
m_pendingPacket.received = 0;
return true;
}
}
return false;
}
bool TcpClient::Send(const void* buffer, std::size_t size, std::size_t* sent)
{
NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Invalid handle");
@@ -183,6 +245,20 @@ namespace Nz
return true;
}
bool TcpClient::SendPacket(const NetPacket& packet)
{
std::size_t size = 0;
const UInt8* ptr = static_cast<const UInt8*>(packet.OnSend(&size));
if (!ptr)
{
m_lastError = SocketError_Packet;
NazaraError("Failed to prepare packet");
return false;
}
return Send(ptr, size, nullptr);
}
bool TcpClient::SetCursorPos(UInt64 offset)
{
NazaraError("SetCursorPos() cannot be used on sequential streams");
@@ -215,7 +291,7 @@ namespace Nz
}
SocketState newState = SocketImpl::Connect(m_handle, m_peerAddress, msTimeout, &m_lastError);
NazaraAssert(newState != SocketState_Connecting, "Invalid internal return");
NazaraAssert(newState != SocketState_Connecting, "Invalid internal return"); //< Connect cannot return Connecting is a timeout was specified
// Prevent valid peer address in non-connected state
if (newState == SocketState_NotConnected)

View File

@@ -3,6 +3,7 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Network/UdpSocket.hpp>
#include <Nazara/Network/NetPacket.hpp>
#if defined(NAZARA_PLATFORM_WINDOWS)
#include <Nazara/Network/Win32/SocketImpl.hpp>
@@ -61,6 +62,43 @@ namespace Nz
return true;
}
bool UdpSocket::ReceivePacket(NetPacket* packet, IpAddress* from)
{
// I'm not sure what's the best between having a 65k bytes buffer ready for any datagram size
// or querying the next datagram size every time, for now I'll leave it as is
packet->Reset(NetCode_Invalid, std::numeric_limits<UInt16>::max());
std::size_t received;
if (!Receive(packet->GetData(), static_cast<std::size_t>(packet->GetSize()), from, &received))
{
NazaraError("Failed to receive packet");
return false;
}
if (received == 0)
return false; //< No datagram received
Nz::UInt16 netCode;
Nz::UInt16 packetSize;
if (!NetPacket::DecodeHeader(packet->GetConstData(), &packetSize, &netCode))
{
m_lastError = SocketError_Packet;
NazaraWarning("Invalid header data");
return false;
}
if (packetSize != received)
{
m_lastError = SocketError_Packet;
NazaraWarning("Invalid packet size (packet size is " + String::Number(packetSize) + " bytes, received " + Nz::String::Number(received) + " bytes)");
return false;
}
packet->Resize(received);
packet->SetNetCode(netCode);
return true;
}
bool UdpSocket::Send(const IpAddress& to, const void* buffer, std::size_t size, std::size_t* sent)
{
NazaraAssert(to.IsValid(), "Invalid ip address");
@@ -77,6 +115,20 @@ namespace Nz
return true;
}
bool UdpSocket::SendPacket(const IpAddress& to, const NetPacket& packet)
{
std::size_t size = 0;
const UInt8* ptr = static_cast<const UInt8*>(packet.OnSend(&size));
if (!ptr)
{
m_lastError = SocketError_Packet;
NazaraError("Failed to prepare packet");
return false;
}
return Send(to, ptr, size, nullptr);
}
void UdpSocket::OnClose()
{
AbstractSocket::OnClose();