Files
UnrealEngine/Engine/Source/Runtime/Sockets/Private/NetworkMessage.cpp
2025-05-18 13:04:45 +08:00

160 lines
3.8 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "NetworkMessage.h"
#include "SocketSubsystem.h"
#include "Sockets.h"
#include "MultichannelTcpSocket.h"
bool FSimpleAbstractSocket_FSocket::Receive(uint8 *Results, int32 Size) const
{
int32 Offset = 0;
if (Size < 0)
{
return false;
}
while (Size > 0)
{
int32 NumRead = 0;
Socket->Recv(Results + Offset, Size, NumRead);
check(NumRead <= Size);
// make sure we were able to read at least something (and not too much)
if (NumRead <= 0)
{
return false;
}
// if we read a partial block, move along
Offset += NumRead;
Size -= NumRead;
}
return true;
}
bool FSimpleAbstractSocket_FSocket::Send(const uint8 *Buffer, int32 Size) const
{
while (Size > 0)
{
int32 BytesSent = 0;
if (!Socket->Send(Buffer, Size, BytesSent))
{
return false;
}
Size -= BytesSent;
Buffer += BytesSent;
}
return true;
}
bool FSimpleAbstractSocket_FMultichannelTCPSocket::Receive(uint8 *Results, int32 Size) const
{
int32 NumRead = Socket->BlockingReceive(Results, Size, ReceiveChannel);
// make sure we were able to read at least something (and not too much)
check(NumRead <= Size);
if (NumRead <= 0)
{
return false;
}
return true;
}
bool FSimpleAbstractSocket_FMultichannelTCPSocket::Send(const uint8 *Buffer, int32 Size) const
{
Socket->Send(Buffer, Size, SendChannel);
return true;
}
bool FNFSMessageHeader::WrapAndSendPayload(const TArray<uint8>& Payload, const FSimpleAbstractSocket& Socket)
{
// make a header for the payload
FNFSMessageHeader Header(Socket, Payload);
// serialize out the header
FBufferArchive Ar;
Ar << Header;
// append the payload bytes to send it in one network packet
Ar.Append(Payload);
// Send it, and make sure it sent it all
if (!Socket.Send(Ar.GetData(), Ar.Num()))
{
UE_LOG(LogSockets, Error, TEXT("Unable to send."));
return false;
}
return true;
}
bool FNFSMessageHeader::ReceivePayload(FArrayReader& OutPayload, const FSimpleAbstractSocket& Socket)
{
// make room to receive a header
TArray<uint8> HeaderBytes;
int32 Size = sizeof(FNFSMessageHeader);
HeaderBytes.AddZeroed(Size);
if (!Socket.Receive(HeaderBytes.GetData(), Size))
{
UE_LOG(LogSockets, Error, TEXT("Unable to read full network header"));
return false;
}
// parse it as a header (doing any byte swapping as needed)
FMemoryReader Reader(HeaderBytes);
FNFSMessageHeader Header(Socket);
Reader << Header;
// make sure it's valid
if (Header.Magic != Socket.GetMagic())
{
UE_LOG(LogSockets, Error, TEXT("Bad network header magic"));
return false;
}
if (!Header.PayloadSize)
{
UE_LOG(LogSockets, Error, TEXT("Empty payload"));
return false;
}
// was the header byteswapped? If so, make the archive byteswapped
OutPayload.SetByteSwapping(Reader.ForceByteSwapping());
// we are going to append to the payload, so note how much data is in it now
int32 PayloadOffset = OutPayload.AddUninitialized(Header.PayloadSize);
// put the read head at the start of the new data
OutPayload.Seek(PayloadOffset);
// receive the payload
if (!Socket.Receive(OutPayload.GetData() + PayloadOffset, Header.PayloadSize))
{
UE_LOG(LogSockets, Error, TEXT("Unable to read full payload"));
return false;
}
// make sure it's valid
uint32 ActualPayloadCrc = FCrc::MemCrc_DEPRECATED(OutPayload.GetData() + PayloadOffset, Header.PayloadSize);
if (Header.PayloadCrc != ActualPayloadCrc)
{
UE_LOG(LogSockets, Error, TEXT("Payload Crc failure."));
return false;
}
// success!
return true;
}
bool FNFSMessageHeader::SendPayloadAndReceiveResponse(const TArray<uint8>& Payload, FArrayReader& Response, const FSimpleAbstractSocket& Socket)
{
// send payload
if (WrapAndSendPayload(Payload, Socket) == false)
{
return false;
}
// wait for response and get it
return ReceivePayload(Response, Socket);
}