Network: Add support for sending/receiving NetPacket over UDP/TCP
Former-commit-id: 5c09a5fa8b499e4204d2312f6d04d8554093a5a4
This commit is contained in:
parent
6c0215952d
commit
08caff5ea3
|
|
@ -8,6 +8,7 @@
|
|||
#define NAZARA_TCPCLIENT_HPP
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Core/ByteArray.hpp>
|
||||
#include <Nazara/Core/Signal.hpp>
|
||||
#include <Nazara/Core/Stream.hpp>
|
||||
#include <Nazara/Network/AbstractSocket.hpp>
|
||||
|
|
@ -15,6 +16,8 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
class NetPacket;
|
||||
|
||||
class NAZARA_NETWORK_API TcpClient : public AbstractSocket, public Stream
|
||||
{
|
||||
friend class TcpServer;
|
||||
|
|
@ -43,8 +46,10 @@ namespace Nz
|
|||
inline bool IsKeepAliveEnabled() const;
|
||||
|
||||
bool Receive(void* buffer, std::size_t size, std::size_t* received);
|
||||
bool ReceivePacket(NetPacket* packet);
|
||||
|
||||
bool Send(const void* buffer, std::size_t size, std::size_t* sent);
|
||||
bool SendPacket(const NetPacket& packet);
|
||||
|
||||
bool SetCursorPos(UInt64 offset) override;
|
||||
|
||||
|
|
@ -62,7 +67,16 @@ namespace Nz
|
|||
void Reset(SocketHandle handle, const IpAddress& peerAddress);
|
||||
std::size_t WriteBlock(const void* buffer, std::size_t size) override;
|
||||
|
||||
struct PendingPacket
|
||||
{
|
||||
std::size_t received = 0;
|
||||
ByteArray data;
|
||||
UInt16 netcode;
|
||||
bool headerReceived = false;
|
||||
};
|
||||
|
||||
IpAddress m_peerAddress;
|
||||
PendingPacket m_pendingPacket;
|
||||
UInt64 m_keepAliveInterval;
|
||||
UInt64 m_keepAliveTime;
|
||||
bool m_isLowDelayEnabled;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
class NetPacket;
|
||||
|
||||
class NAZARA_NETWORK_API UdpSocket : public AbstractSocket
|
||||
{
|
||||
public:
|
||||
|
|
@ -37,8 +39,10 @@ namespace Nz
|
|||
std::size_t QueryMaxDatagramSize();
|
||||
|
||||
bool Receive(void* buffer, std::size_t size, IpAddress* from, std::size_t* received);
|
||||
bool ReceivePacket(NetPacket* packet, IpAddress* from);
|
||||
|
||||
bool Send(const IpAddress& to, const void* buffer, std::size_t size, std::size_t* sent);
|
||||
bool SendPacket(const IpAddress& to, const NetPacket& packet);
|
||||
|
||||
private:
|
||||
void OnClose() override;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Reference in New Issue