2#include <ossia/detail/pod_vector.hpp>
3#include <ossia/network/sockets/writers.hpp>
5#include <boost/asio/buffer.hpp>
6#include <boost/asio/error.hpp>
7#include <boost/asio/read.hpp>
8#include <boost/asio/write.hpp>
9#include <boost/endian/conversion.hpp>
23template <
int HeaderBytes,
byte_order Order =
byte_order::big_endian>
24struct var_size_prefix_framing
26 static_assert(HeaderBytes == 1 || HeaderBytes == 2 || HeaderBytes == 4);
28 using header_type = std::conditional_t<
29 HeaderBytes == 1, uint8_t, std::conditional_t<HeaderBytes == 2, uint16_t, uint32_t>>;
31 template <
typename Socket>
35 header_type m_header{};
36 ossia::pod_vector<char> m_data;
37 std::size_t max_frame_size
38 = HeaderBytes == 1 ? std::size_t(255)
39 : HeaderBytes == 2 ? std::size_t(65535)
40 : std::size_t(0x7FFFFFFF);
42 explicit decoder(Socket& socket)
45 if constexpr(HeaderBytes == 1)
48 m_data.reserve(65535);
54 boost::asio::async_read(
55 socket, boost::asio::mutable_buffer(&m_header,
sizeof(header_type)),
56 boost::asio::transfer_exactly(
sizeof(header_type)),
58 f = std::move(f)](boost::system::error_code ec, std::size_t sz)
mutable {
59 read_size(std::move(f), ec, sz);
64 void read_size(F&& f, boost::system::error_code ec, std::size_t sz)
66 if(!f.validate_stream(ec))
69 if constexpr(HeaderBytes > 1)
71 if constexpr(Order == byte_order::big_endian)
72 boost::endian::big_to_native_inplace(m_header);
74 boost::endian::little_to_native_inplace(m_header);
77 auto packet_size =
static_cast<std::size_t
>(m_header);
78 if(packet_size == 0 || packet_size > max_frame_size)
81 m_data.resize(packet_size, boost::container::default_init);
82 boost::asio::async_read(
83 socket, boost::asio::mutable_buffer(m_data.data(), packet_size),
84 boost::asio::transfer_exactly(packet_size),
86 f = std::move(f)](boost::system::error_code ec, std::size_t sz)
mutable {
87 read_data(std::move(f), ec, sz);
92 void read_data(F&& f, boost::system::error_code ec, std::size_t sz)
94 if(!f.validate_stream(ec))
101 f((
const unsigned char*)m_data.data(), sz);
108 this->receive(std::move(f));
112 template <
typename Socket>
117 void write(
const char* data, std::size_t sz)
119 header_type header =
static_cast<header_type
>(sz);
120 if constexpr(HeaderBytes > 1)
122 if constexpr(Order == byte_order::big_endian)
123 boost::endian::native_to_big_inplace(header);
125 boost::endian::native_to_little_inplace(header);
128 std::array<boost::asio::const_buffer, 2> bufs = {
130 reinterpret_cast<const char*
>(&header),
sizeof(header_type)),
131 boost::asio::buffer(data, sz)};
132 this->do_write(socket, bufs);
135 template <
typename T, std::
size_t N>
136 void do_write(T& sock,
const std::array<boost::asio::const_buffer, N>& bufs)
138 boost::asio::write(sock, bufs);
141 template <
typename T, std::
size_t N>
143 multi_socket_writer<T>& sock,
144 const std::array<boost::asio::const_buffer, N>& bufs)
146 for(
const auto& buf : bufs)
153using size_prefix_1byte_framing = var_size_prefix_framing<1>;
154using size_prefix_2byte_be_framing = var_size_prefix_framing<2, byte_order::big_endian>;
155using size_prefix_2byte_le_framing = var_size_prefix_framing<2, byte_order::little_endian>;
156using size_prefix_4byte_be_framing = var_size_prefix_framing<4, byte_order::big_endian>;
157using size_prefix_4byte_le_framing = var_size_prefix_framing<4, byte_order::little_endian>;