2026-05-20 12:12:39 -07:00
|
|
|
/* Copyright (C) 2026 Wildfire Games.
|
2023-12-02 16:30:12 -08:00
|
|
|
* This file is part of 0 A.D.
|
2010-06-07 15:19:05 -07:00
|
|
|
*
|
2023-12-02 16:30:12 -08:00
|
|
|
* 0 A.D. is free software: you can redistribute it and/or modify
|
2010-06-07 15:19:05 -07:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation, either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
2023-12-02 16:30:12 -08:00
|
|
|
* 0 A.D. is distributed in the hope that it will be useful,
|
2010-06-07 15:19:05 -07:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
2023-12-02 16:30:12 -08:00
|
|
|
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
2010-06-07 15:19:05 -07:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "precompiled.h"
|
2010-06-30 14:41:04 -07:00
|
|
|
|
2010-06-07 15:19:05 -07:00
|
|
|
#include "NetHost.h"
|
|
|
|
|
|
2025-07-06 11:15:27 -07:00
|
|
|
#include "lib/debug.h"
|
2010-08-10 14:49:33 -07:00
|
|
|
#include "lib/external_libraries/enet.h"
|
2010-06-30 14:41:04 -07:00
|
|
|
#include "network/NetMessage.h"
|
2010-06-07 15:19:05 -07:00
|
|
|
#include "ps/CLogger.h"
|
|
|
|
|
|
2025-07-06 11:15:27 -07:00
|
|
|
#include <cstddef>
|
2026-05-20 12:12:39 -07:00
|
|
|
#include <numeric>
|
2025-07-06 11:15:27 -07:00
|
|
|
#include <vector>
|
|
|
|
|
|
2026-05-20 12:12:39 -07:00
|
|
|
std::vector<std::uint8_t> CNetHost::CreatePacket(const CNetMessage* message)
|
2010-06-07 15:19:05 -07:00
|
|
|
{
|
2010-06-30 14:41:04 -07:00
|
|
|
size_t size = message->GetSerializedLength();
|
2010-06-07 15:19:05 -07:00
|
|
|
|
2011-04-30 06:01:45 -07:00
|
|
|
ENSURE(size); // else we'll fail when accessing the 0th element
|
2010-06-07 15:19:05 -07:00
|
|
|
|
|
|
|
|
// Adjust buffer for message
|
|
|
|
|
std::vector<u8> buffer;
|
|
|
|
|
buffer.resize(size);
|
|
|
|
|
|
|
|
|
|
// Save message to internal buffer
|
2010-06-30 14:41:04 -07:00
|
|
|
message->Serialize(&buffer[0]);
|
2010-06-07 15:19:05 -07:00
|
|
|
|
2026-05-20 12:12:39 -07:00
|
|
|
return buffer;
|
2010-06-07 15:19:05 -07:00
|
|
|
}
|
2010-07-03 12:31:14 -07:00
|
|
|
|
|
|
|
|
void CNetHost::Initialize()
|
|
|
|
|
{
|
|
|
|
|
int ret = enet_initialize();
|
2011-04-30 06:01:45 -07:00
|
|
|
ENSURE(ret == 0);
|
2010-07-03 12:31:14 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CNetHost::Deinitialize()
|
|
|
|
|
{
|
|
|
|
|
enet_deinitialize();
|
2010-08-10 14:49:33 -07:00
|
|
|
}
|
2026-05-20 12:12:39 -07:00
|
|
|
|
|
|
|
|
|
|
|
|
|
Stream::Stream(const std::int64_t streamId):
|
|
|
|
|
m_Id{streamId}
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
void Stream::PushData(std::vector<std::uint8_t> data)
|
|
|
|
|
{
|
|
|
|
|
m_SendBuffer.push_back(std::move(data));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Stream::PushMessage(const CNetMessage* message)
|
|
|
|
|
{
|
|
|
|
|
m_SendBuffer.push_back(CNetHost::CreatePacket(message));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<std::span<const std::uint8_t>> Stream::PeekData()
|
|
|
|
|
{
|
|
|
|
|
const std::size_t startOffset{m_SentOffset - m_AckedOffset};
|
|
|
|
|
std::size_t offset{0};
|
|
|
|
|
|
|
|
|
|
for (std::vector<std::uint8_t>& bytes : m_SendBuffer)
|
|
|
|
|
{
|
|
|
|
|
if (startOffset - offset < bytes.size())
|
|
|
|
|
{
|
|
|
|
|
const std::size_t temp{startOffset - offset};
|
|
|
|
|
return std::span{bytes.data() + temp, bytes.size() - temp};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
offset += bytes.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Stream::MarkSent(const std::size_t offset)
|
|
|
|
|
{
|
|
|
|
|
m_SentOffset += offset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Stream::MarkAcknowledged(const std::size_t offset)
|
|
|
|
|
{
|
|
|
|
|
while (!m_SendBuffer.empty())
|
|
|
|
|
{
|
|
|
|
|
std::vector<uint8_t>& head{m_SendBuffer.front()};
|
|
|
|
|
if (m_AckedOffset + head.size() > offset)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
m_AckedOffset += head.size();
|
|
|
|
|
m_SendBuffer.pop_front();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<std::vector<std::uint8_t>> Stream::Receive(const std::span<const std::uint8_t> data)
|
|
|
|
|
{
|
|
|
|
|
m_ReceiveBuffer.emplace_back(data.begin(), data.end());
|
|
|
|
|
const std::size_t bufferSize{std::transform_reduce(m_ReceiveBuffer.begin(), m_ReceiveBuffer.end(),
|
|
|
|
|
static_cast<std::size_t>(0), std::plus<>{}, std::mem_fn(&std::vector<std::uint8_t>::size))};
|
|
|
|
|
if (bufferSize < 3)
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
const auto& message = m_ReceiveBuffer.front();
|
|
|
|
|
|
|
|
|
|
auto bufferIter = message.begin();
|
|
|
|
|
std::size_t messageSize;
|
|
|
|
|
Deserialize_int_1(bufferIter, std::ignore);
|
|
|
|
|
Deserialize_int_2(bufferIter, messageSize);
|
|
|
|
|
if (messageSize > bufferSize)
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
|
|
|
|
|
std::vector<std::uint8_t> messageCopy;
|
|
|
|
|
while (messageCopy.size() < messageSize)
|
|
|
|
|
{
|
|
|
|
|
messageCopy.insert(messageCopy.end(), m_ReceiveBuffer.front().begin(),
|
|
|
|
|
m_ReceiveBuffer.front().end());
|
|
|
|
|
m_ReceiveBuffer.pop_front();
|
|
|
|
|
}
|
|
|
|
|
return messageCopy;
|
|
|
|
|
}
|