Joedb 10.4.6
The Journal-Only Embedded Database
Loading...
Searching...
No Matches
Server.h
Go to the documentation of this file.
1#ifndef joedb_rpc_Server_declared
2#define joedb_rpc_Server_declared
3
7#include "joedb/asio/Server.h"
9
10#include <algorithm>
11
12namespace joedb::rpc
13{
14 /// RPC Server
15 ///
16 /// @ingroup rpc
18 {
19 private:
20 const std::vector<Signature> &signatures;
21 const std::vector<Procedure *> &procedures;
22 const int64_t max_message_size;
23
24 protected:
26 {
27 private:
28 Server &get_server() {return *(Server *)&server;}
29
30 ////////////////////////////////////////////////////////////////////////
31 boost::asio::awaitable<bool> handshake()
32 ////////////////////////////////////////////////////////////////////////
33 {
34 co_await read_buffer(0, 32);
35
36 const SHA_256::Hash hash = buffer.read<SHA_256::Hash>();
37 const bool correct_hash = hash == get_hash(get_server().signatures);
38
39 buffer.index = 0;
40 buffer.write<char>(correct_hash ? 'H': 'h');
41 buffer.write<int64_t>(id);
42
43 if (get_server().log_level > 2)
44 log(correct_hash ? "correct hash" : "incorrect hash");
45
46 co_await write_buffer();
47 co_return correct_hash;
48 }
49
50 ////////////////////////////////////////////////////////////////////////
51 boost::asio::awaitable<void> call()
52 ////////////////////////////////////////////////////////////////////////
53 {
54 co_await read_buffer(1, 16);
55
56 const size_t id = static_cast<size_t>(buffer.read<int64_t>());
57 const int64_t until = buffer.read<int64_t>();
58
59 //
60 // Get procedure from id
61 //
62 if (id >= get_server().procedures.size())
63 throw Exception("bad procedure id");
64
65 auto &signature = get_server().signatures[id];
66 auto &procedure = *get_server().procedures[id];
67
68 if (get_server().log_level > 2)
69 log("procedure[" + std::to_string(id) + "]: " + signature.name);
70
71 //
72 // Read input message into a Memory_File
73 //
74 Memory_File file;
75
76 if (until < int64_t(signature.prolog.size()) || until > get_server().max_message_size)
77 throw Exception("invalid size");
78
79 {
80 std::string &data = file.get_data();
81 data.reserve(size_t(until));
82 data = signature.prolog;
83
84 int64_t remaining = until - file.get_size();
85 while (remaining > 0)
86 {
87 const size_t n = co_await read_buffer
88 (
89 0,
90 std::min(remaining, int64_t(buffer.size))
91 );
92 data.append(buffer.data, n);
93 remaining -= n;
94 }
95 }
96
97 //
98 // Execute procedure
99 //
100 buffer.index = 0;
101
102 try
103 {
104 procedure.execute(file);
105 }
106 catch (const std::exception &e)
107 {
108 const std::string_view message(e.what());
109
110 if (get_server().log_level > 2)
111 log("error: " + std::string(message));
112
113 const size_t n = std::min(message.size(), buffer.size - 9);
114 buffer.write<char>('c');
115 buffer.write<int64_t>(int64_t(n));
116 std::strncpy(buffer.data + buffer.index, message.data(), n);
117 buffer.index += n;
118 }
119
120 //
121 // Return either an error message or the procedure output
122 //
123 if (buffer.index > 0)
124 co_await write_buffer();
125 else
126 {
127 buffer.index = 0;
128 buffer.write<char>('C');
129 buffer.write<int64_t>(file.get_size());
130
131 size_t offset = size_t(until);
132 size_t remaining = file.get_data().size() - offset;
133 while (remaining + buffer.index > 0)
134 {
135 const size_t n = std::min(remaining, buffer.size - buffer.index);
136 file.pread(buffer.data + buffer.index, n, offset);
137 buffer.index += n;
138 offset += n;
139 remaining -= n;
140 co_await write_buffer();
141 buffer.index = 0;
142 }
143 }
144 }
145
146 public:
147 ////////////////////////////////////////////////////////////////////////
149 ////////////////////////////////////////////////////////////////////////
150 (
151 Server &server,
152 boost::asio::local::stream_protocol::socket &&socket
153 ):
154 joedb::asio::Server::Session(server, std::move(socket))
155 {
156 }
157
158 ////////////////////////////////////////////////////////////////////////
159 boost::asio::awaitable<void> run() override
160 ////////////////////////////////////////////////////////////////////////
161 {
162 if (!co_await handshake())
163 co_return;
164
165 while (true)
166 {
167 co_await read_buffer(0, 1);
168
169 if (server.get_log_level() > 2)
170 log(std::string("received command: ") + buffer.data[0]);
171
172 switch (buffer.data[0])
173 {
174 case 'C':
175 co_await call();
176 break;
177
178 case 'P':
179 buffer.index = 1;
180 co_await write_buffer();
181 break;
182
183 default:
184 co_return;
185 break;
186 }
187 }
188 }
189 };
190
191 //////////////////////////////////////////////////////////////////////////
192 std::unique_ptr<joedb::asio::Server::Session> new_session
193 //////////////////////////////////////////////////////////////////////////
194 (
195 boost::asio::local::stream_protocol::socket &&socket
196 ) override
197 {
198 return std::make_unique<Session>(*this, std::move(socket));
199 }
200
201 public:
202 //////////////////////////////////////////////////////////////////////////
204 //////////////////////////////////////////////////////////////////////////
205 (
206 Logger &logger,
207 int log_level,
208 int thread_count,
209 std::string endpoint_path,
210 const std::vector<Signature> &signatures,
211 const std::vector<Procedure *> &procedures,
212 int64_t max_message_size = 1 << 24
213 ):
214 joedb::asio::Server
215 (
216 logger,
217 log_level,
219 std::move(endpoint_path)
220 ),
221 signatures(signatures),
222 procedures(procedures),
223 max_message_size(max_message_size)
224 {
225 }
226 };
227}
228
229#endif
size_t index
Definition Buffer.h:20
void write(T x)
Definition Buffer.h:23
char data[size+extra_size]
Definition Buffer.h:19
static constexpr size_t size
Definition Buffer.h:15
std::string & get_data()
Definition Memory_File.h:23
size_t pread(char *buffer, size_t size, int64_t offset) const override
Read a range of bytes.
int64_t get_size() const override
Get the size of the file, or -1 if it is unknown.
Definition Memory_File.h:27
std::array< uint32_t, 8 > Hash
Definition SHA_256.h:59
boost::asio::awaitable< void > write_buffer()
Definition Server.cpp:56
boost::asio::awaitable< size_t > read_buffer(size_t offset, size_t size)
Definition Server.cpp:39
void log(beman::cstring_view message) noexcept override
Definition Server.cpp:66
boost::asio::local::stream_protocol::socket socket
Definition Server.h:39
Superclass for asio servers.
Definition Server.h:19
const std::string endpoint_path
Definition Server.h:29
Logger & logger
Definition Server.h:21
int get_log_level() const
Definition Server.h:81
const int thread_count
Definition Server.h:25
const int log_level
Definition Server.h:22
boost::asio::awaitable< void > run() override
Definition Server.h:159
RPC Server.
Definition Server.h:18
std::unique_ptr< joedb::asio::Server::Session > new_session(boost::asio::local::stream_protocol::socket &&socket) override
Definition Server.h:194
SHA_256::Hash get_hash(const std::vector< Signature > &signatures)
Compute hash code for a collection of procedure signatures.
Definition get_hash.cpp:9
Definition ids.h:50