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);
41 lifetime_token m_lifetime;
43 explicit decoder(Socket& socket)
46 if constexpr(HeaderBytes == 1)
49 m_data.reserve(65535);
55 boost::asio::async_read(
56 socket, boost::asio::mutable_buffer(&m_header,
sizeof(header_type)),
57 boost::asio::transfer_exactly(
sizeof(header_type)),
58 [
this, alive = m_lifetime.watch(),
59 f = std::move(f)](boost::system::error_code ec, std::size_t sz)
mutable {
64 read_size(std::move(f), ec, sz);
69 void read_size(F&& f, boost::system::error_code ec, std::size_t sz)
71 if(!f.validate_stream(ec))
74 if constexpr(HeaderBytes > 1)
76 if constexpr(Order == byte_order::big_endian)
77 boost::endian::big_to_native_inplace(m_header);
79 boost::endian::little_to_native_inplace(m_header);
82 auto packet_size =
static_cast<std::size_t
>(m_header);
83 if(packet_size == 0 || packet_size > max_frame_size)
86 m_data.resize(packet_size, boost::container::default_init);
87 boost::asio::async_read(
88 socket, boost::asio::mutable_buffer(m_data.data(), packet_size),
89 boost::asio::transfer_exactly(packet_size),
90 [
this, alive = m_lifetime.watch(),
91 f = std::move(f)](boost::system::error_code ec, std::size_t sz)
mutable {
96 read_data(std::move(f), ec, sz);
100 template <
typename F>
101 void read_data(F&& f, boost::system::error_code ec, std::size_t sz)
103 if(!f.validate_stream(ec))
110 f((
const unsigned char*)m_data.data(), sz);
117 this->receive(std::move(f));
121 template <
typename Socket>
126 void write(
const char* data, std::size_t sz)
128 header_type header =
static_cast<header_type
>(sz);
129 if constexpr(HeaderBytes > 1)
131 if constexpr(Order == byte_order::big_endian)
132 boost::endian::native_to_big_inplace(header);
134 boost::endian::native_to_little_inplace(header);
137 std::array<boost::asio::const_buffer, 2> bufs = {
139 reinterpret_cast<const char*
>(&header),
sizeof(header_type)),
140 boost::asio::buffer(data, sz)};
141 this->do_write(socket, bufs);
144 template <
typename T, std::
size_t N>
145 void do_write(T& sock,
const std::array<boost::asio::const_buffer, N>& bufs)
147 boost::asio::write(sock, bufs);
150 template <
typename T, std::
size_t N>
152 multi_socket_writer<T>& sock,
153 const std::array<boost::asio::const_buffer, N>& bufs)
155 for(
const auto& buf : bufs)
162using size_prefix_1byte_framing = var_size_prefix_framing<1>;
163using size_prefix_2byte_be_framing = var_size_prefix_framing<2, byte_order::big_endian>;
164using size_prefix_2byte_le_framing = var_size_prefix_framing<2, byte_order::little_endian>;
165using size_prefix_4byte_be_framing = var_size_prefix_framing<4, byte_order::big_endian>;
166using size_prefix_4byte_le_framing = var_size_prefix_framing<4, byte_order::little_endian>;