OSSIA
Open Scenario System for Interactive Application
Loading...
Searching...
No Matches
size_prefix_framing.hpp
1#pragma once
2#include <ossia/detail/pod_vector.hpp>
3#include <ossia/network/sockets/writers.hpp>
4
5#include <boost/asio/buffer.hpp>
6#include <boost/asio/error.hpp>
7#include <boost/asio/read.hpp>
8#include <boost/asio/streambuf.hpp>
9#include <boost/asio/write.hpp>
10#include <boost/endian/conversion.hpp>
11
12namespace ossia::net
13{
14
15template <typename Socket>
16struct size_prefix_decoder
17{
18 Socket& socket;
19 int32_t m_next_packet_size{};
20 ossia::pod_vector<char> m_data;
21
22 explicit size_prefix_decoder(Socket& socket)
23 : socket{socket}
24 {
25 m_data.reserve(65535);
26 }
27
28 template <typename F>
29 void receive(F f)
30 {
31 // Receive the size prefix
32 socket.async_read_some(
33 boost::asio::mutable_buffer(&m_next_packet_size, sizeof(int32_t)),
34 [this, f = std::move(f)](boost::system::error_code ec, std::size_t sz) mutable {
35 read_size(std::move(f), ec, sz);
36 });
37 }
38
39 template <typename F>
40 void read_size(F&& f, boost::system::error_code ec, std::size_t sz)
41 {
42 if(!f.validate_stream(ec))
43 return;
44
45 boost::endian::big_to_native_inplace(m_next_packet_size);
46 if(m_next_packet_size <= 0)
47 return;
48
49 m_data.resize(m_next_packet_size);
50 boost::asio::async_read(
51 socket, boost::asio::mutable_buffer(m_data.data(), m_next_packet_size),
52 boost::asio::transfer_exactly(m_next_packet_size),
53 [this, f = std::move(f)](boost::system::error_code ec, std::size_t sz) mutable {
54 read_data(std::move(f), ec, sz);
55 });
56 }
57
58 template <typename F>
59 void read_data(F&& f, boost::system::error_code ec, std::size_t sz)
60 {
61 if(!f.validate_stream(ec))
62 return;
63
64 if(!ec && sz > 0)
65 {
66 try
67 {
68 f((const unsigned char*)m_data.data(), sz);
69 }
70 catch(...)
71 {
72 }
73 }
74
75 this->receive(std::move(f));
76 }
77};
78
79template <typename Socket>
80struct size_prefix_encoder
81{
82 Socket& socket;
83
84 void write(const char* data, std::size_t sz)
85 {
86 int32_t packet_size = sz;
87 boost::endian::native_to_big_inplace(packet_size);
88 this->write(
89 socket, boost::asio::buffer(
90 reinterpret_cast<const char*>(&packet_size), sizeof(int32_t)));
91 this->write(socket, boost::asio::buffer(data, sz));
92 }
93
94 template <typename T>
95 void write(T& sock, const boost::asio::const_buffer& buf)
96 {
97 boost::asio::write(sock, buf);
98 }
99
100 template <typename T>
101 void write(multi_socket_writer<T>& sock, const boost::asio::const_buffer& buf)
102 {
103 sock.write(buf);
104 }
105};
106
107struct size_prefix_framing
108{
109 template <typename Socket>
110 using encoder = size_prefix_encoder<Socket>;
111 template <typename Socket>
112 using decoder = size_prefix_decoder<Socket>;
113};
114
115}