2024-03-20 23:09:58 -04:00
|
|
|
#include <aries/Message.hpp>
|
|
|
|
#include <aries/Tags.hpp>
|
|
|
|
#include <base/types.hpp>
|
|
|
|
#include <boost/asio/read.hpp>
|
|
|
|
#include <boost/asio/write.hpp>
|
|
|
|
#include <exception>
|
|
|
|
#include <impl/asio_config.hpp>
|
|
|
|
|
2024-03-20 23:32:03 -04:00
|
|
|
#include "boost/asio/buffer.hpp"
|
|
|
|
|
2024-03-20 23:09:58 -04:00
|
|
|
namespace ls::aries {
|
|
|
|
|
2024-03-20 23:32:03 -04:00
|
|
|
// Mostly to be conservative. I don't think the game will really care but bleh
|
|
|
|
constexpr static auto MAX_TAGFIELD_SIZE_IN_MB = 1;
|
|
|
|
constexpr static auto MAX_TAGFIELD_SIZE_IN_BYTES = MAX_TAGFIELD_SIZE_IN_MB * (1024 * 1024);
|
2024-03-20 23:09:58 -04:00
|
|
|
|
|
|
|
|
|
|
|
namespace errors {
|
|
|
|
|
|
|
|
struct TagPayloadTooLarge : std::exception {
|
|
|
|
TagPayloadTooLarge(u32 size)
|
|
|
|
: payloadSize(size) {
|
2024-03-20 23:32:03 -04:00
|
|
|
whatStr = std::format("Tag field data size is over {} MB (Max is {}MB).", (static_cast<u32>(payloadSize) / 1024 / 1024), MAX_TAGFIELD_SIZE_IN_MB);
|
2024-03-20 23:09:58 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
const char* what() const noexcept override {
|
|
|
|
return whatStr.c_str();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
u32 payloadSize;
|
|
|
|
std::string whatStr;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace errors
|
|
|
|
|
2024-03-20 23:32:03 -04:00
|
|
|
/// Reads an Aries message from an Boost.Asio async read stream.
|
|
|
|
/// Returns the raw Aries message header and the tag field buffer.
|
2024-03-20 23:09:58 -04:00
|
|
|
template <class AsyncReadStream>
|
|
|
|
base::Awaitable<RawAriesMessage> AsyncReadAriesMessage(AsyncReadStream& stream) {
|
|
|
|
RawAriesMessage res;
|
|
|
|
|
|
|
|
// Read the header first
|
|
|
|
co_await asio::async_read(stream, asio::buffer(&res.header, sizeof(res.header)), asio::deferred);
|
|
|
|
|
|
|
|
auto realPayloadSize = res.header.messageSize - sizeof(res.header);
|
|
|
|
|
2024-03-20 23:32:03 -04:00
|
|
|
// Read tag payload (if there is one)
|
2024-03-20 23:09:58 -04:00
|
|
|
if(res.header.messageSize != sizeof(res.header)) {
|
|
|
|
// Sanity check. I don't expect game payloads to ever reach this large, but who knows.
|
2024-03-20 23:32:03 -04:00
|
|
|
if(realPayloadSize > MAX_TAGFIELD_SIZE_IN_BYTES)
|
2024-03-20 23:09:58 -04:00
|
|
|
throw errors::TagPayloadTooLarge(realPayloadSize);
|
|
|
|
|
2024-03-20 23:32:03 -04:00
|
|
|
res.tagFields.resize(realPayloadSize);
|
2024-03-20 23:09:58 -04:00
|
|
|
|
2024-03-20 23:32:03 -04:00
|
|
|
co_await asio::async_read(stream, asio::buffer(res.tagFields), asio::deferred);
|
2024-03-20 23:09:58 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
co_return res;
|
|
|
|
}
|
|
|
|
|
2024-03-20 23:32:03 -04:00
|
|
|
template <class AsyncReadStream>
|
|
|
|
base::Awaitable<void> AsyncWriteAriesMessage(AsyncReadStream& stream, const RawAriesMessage& message) {
|
|
|
|
auto realTagFieldSize = message.header.messageSize - sizeof(message.header);
|
|
|
|
|
|
|
|
// Make sure *we* won't write a message the official Aries protocol
|
|
|
|
// won't like (even though it'd probably just crash, it's nice for us to do this.)
|
|
|
|
if(message.header.messageSize != sizeof(message.header)) {
|
|
|
|
// Sanity check. I don't expect game payloads to ever reach this large, but who knows.
|
|
|
|
if(realTagFieldSize > MAX_TAGFIELD_SIZE_IN_BYTES)
|
|
|
|
throw errors::TagPayloadTooLarge(realTagFieldSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Our buffer list. We pass this to asio::async_write so we only actually have to perform
|
|
|
|
// one (scatter-gather) I/O operation in this function
|
|
|
|
std::array<asio::const_buffer, 2> buffers = {
|
|
|
|
asio::buffer(&message.header, sizeof(message.header)),
|
|
|
|
asio::buffer(message.tagFields, realTagFieldSize)
|
|
|
|
};
|
|
|
|
|
|
|
|
co_await asio::async_write(stream, buffers, asio::deferred);
|
|
|
|
co_return;
|
|
|
|
}
|
|
|
|
|
2024-03-20 23:09:58 -04:00
|
|
|
} // namespace ls::aries
|