Monero
Loading...
Searching...
No Matches
levin_abstract_invoke2.h
Go to the documentation of this file.
1// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are met:
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above copyright
9// notice, this list of conditions and the following disclaimer in the
10// documentation and/or other materials provided with the distribution.
11// * Neither the name of the Andrey N. Sabelnikov nor the
12// names of its contributors may be used to endorse or promote products
13// derived from this software without specific prior written permission.
14//
15// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
19// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25//
26
27#pragma once
28
30#include <boost/utility/string_ref.hpp>
31#include <boost/utility/value_init.hpp>
32#include <functional>
33#include "byte_slice.h"
34#include "span.h"
35#include "net/levin_base.h"
36
37#undef MONERO_DEFAULT_LOG_CATEGORY
38#define MONERO_DEFAULT_LOG_CATEGORY "net"
39
40template<typename context_t>
41void on_levin_traffic(const context_t &context, bool initiator, bool sent, bool error, size_t bytes, const char *category);
42
43template<typename context_t>
44void on_levin_traffic(const context_t &context, bool initiator, bool sent, bool error, size_t bytes, int command);
45
46namespace
47{
48 static const constexpr epee::serialization::portable_storage::limits_t default_levin_limits = {
49 8192, // objects
50 16384, // fields
51 16384, // strings
52 };
53}
54
55namespace epee
56{
57 namespace net_utils
58 {
59 template<class t_arg, class t_result, class t_transport>
60 bool invoke_remote_command2(const epee::net_utils::connection_context_base context, int command, const t_arg& out_struct, t_result& result_struct, t_transport& transport)
61 {
62 const boost::uuids::uuid &conn_id = context.m_connection_id;
64 out_struct.store(stg);
65 levin::message_writer to_send{16 * 1024};
66 std::string buff_to_recv;
67 stg.store_to_binary(to_send.buffer);
68
69 int res = transport.invoke(command, std::move(to_send), buff_to_recv, conn_id);
70 if( res <=0 )
71 {
72 LOG_PRINT_L1("Failed to invoke command " << command << " return code " << res);
73 return false;
74 }
75 typename serialization::portable_storage stg_ret;
76 if(!stg_ret.load_from_binary(buff_to_recv, &default_levin_limits))
77 {
78 on_levin_traffic(context, true, false, true, buff_to_recv.size(), command);
79 LOG_ERROR("Failed to load_from_binary on command " << command);
80 return false;
81 }
82 on_levin_traffic(context, true, false, false, buff_to_recv.size(), command);
83 return result_struct.load(stg_ret);
84 }
85
86 template<class t_result, class t_arg, class callback_t, class t_transport>
87 bool async_invoke_remote_command2(const epee::net_utils::connection_context_base &context, int command, const t_arg& out_struct, t_transport& transport, const callback_t &cb, size_t inv_timeout = LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED)
88 {
89 const boost::uuids::uuid &conn_id = context.m_connection_id;
91 const_cast<t_arg&>(out_struct).store(stg);//TODO: add true const support to searilzation
92 levin::message_writer to_send{16 * 1024};
93 stg.store_to_binary(to_send.buffer);
94 int res = transport.invoke_async(command, std::move(to_send), conn_id, [cb, command](int code, const epee::span<const uint8_t> buff, typename t_transport::connection_context& context)->bool
95 {
96 t_result result_struct = AUTO_VAL_INIT(result_struct);
97 if( code <=0 )
98 {
99 if (!buff.empty())
100 on_levin_traffic(context, true, false, true, buff.size(), command);
101 LOG_PRINT_L1("Failed to invoke command " << command << " return code " << code);
102 cb(code, result_struct, context);
103 return false;
104 }
106 if(!stg_ret.load_from_binary(buff, &default_levin_limits))
107 {
108 on_levin_traffic(context, true, false, true, buff.size(), command);
109 LOG_ERROR("Failed to load_from_binary on command " << command);
110 cb(LEVIN_ERROR_FORMAT, result_struct, context);
111 return false;
112 }
113 if (!result_struct.load(stg_ret))
114 {
115 on_levin_traffic(context, true, false, true, buff.size(), command);
116 LOG_ERROR("Failed to load result struct on command " << command);
117 cb(LEVIN_ERROR_FORMAT, result_struct, context);
118 return false;
119 }
120 on_levin_traffic(context, true, false, false, buff.size(), command);
121 cb(code, result_struct, context);
122 return true;
123 }, inv_timeout);
124 if( res <=0 )
125 {
126 LOG_PRINT_L1("Failed to invoke command " << command << " return code " << res);
127 return false;
128 }
129 return true;
130 }
131
132 template<class t_arg, class t_transport>
133 bool notify_remote_command2(const typename t_transport::connection_context &context, int command, const t_arg& out_struct, t_transport& transport)
134 {
135 const boost::uuids::uuid &conn_id = context.m_connection_id;
137 out_struct.store(stg);
138 levin::message_writer to_send;
139 stg.store_to_binary(to_send.buffer);
140
141 int res = transport.send(to_send.finalize_notify(command), conn_id);
142 if(res <=0 )
143 {
144 MERROR("Failed to notify command " << command << " return code " << res);
145 return false;
146 }
147 return true;
148 }
149 //----------------------------------------------------------------------------------------------------
150 //----------------------------------------------------------------------------------------------------
151 template<class t_owner, class t_in_type, class t_out_type, class t_context, class callback_t>
152 int buff_to_t_adapter(int command, const epee::span<const uint8_t> in_buff, byte_stream& buff_out, callback_t cb, t_context& context )
153 {
155 if(!strg.load_from_binary(in_buff, &default_levin_limits))
156 {
157 on_levin_traffic(context, false, false, true, in_buff.size(), command);
158 LOG_ERROR("Failed to load_from_binary in command " << command);
159 return -1;
160 }
161 boost::value_initialized<t_in_type> in_struct;
162 boost::value_initialized<t_out_type> out_struct;
163
164 if (!static_cast<t_in_type&>(in_struct).load(strg))
165 {
166 on_levin_traffic(context, false, false, true, in_buff.size(), command);
167 LOG_ERROR("Failed to load in_struct in command " << command);
168 return -1;
169 }
170 on_levin_traffic(context, false, false, false, in_buff.size(), command);
171 int res = cb(command, static_cast<t_in_type&>(in_struct), static_cast<t_out_type&>(out_struct), context);
173 static_cast<t_out_type&>(out_struct).store(strg_out);
174
175 if(!strg_out.store_to_binary(buff_out))
176 {
177 LOG_ERROR("Failed to store_to_binary in command" << command);
178 return -1;
179 }
180
181 return res;
182 }
183
184 template<class t_owner, class t_in_type, class t_context, class callback_t>
185 int buff_to_t_adapter(t_owner* powner, int command, const epee::span<const uint8_t> in_buff, callback_t cb, t_context& context)
186 {
188 if(!strg.load_from_binary(in_buff, &default_levin_limits))
189 {
190 on_levin_traffic(context, false, false, true, in_buff.size(), command);
191 LOG_ERROR("Failed to load_from_binary in notify " << command);
192 return -1;
193 }
194 boost::value_initialized<t_in_type> in_struct;
195 if (!static_cast<t_in_type&>(in_struct).load(strg))
196 {
197 on_levin_traffic(context, false, false, true, in_buff.size(), command);
198 LOG_ERROR("Failed to load in_struct in notify " << command);
199 return -1;
200 }
201 on_levin_traffic(context, false, false, false, in_buff.size(), command);
202 return cb(command, in_struct, context);
203 }
204
205#define CHAIN_LEVIN_INVOKE_MAP2(context_type) \
206 int invoke(int command, const epee::span<const uint8_t> in_buff, epee::byte_stream& buff_out, context_type& context) \
207 { \
208 bool handled = false; \
209 return handle_invoke_map(false, command, in_buff, buff_out, context, handled); \
210 }
211
212#define CHAIN_LEVIN_NOTIFY_MAP2(context_type) \
213 int notify(int command, const epee::span<const uint8_t> in_buff, context_type& context) \
214 { \
215 bool handled = false; epee::byte_stream fake_str; \
216 return handle_invoke_map(true, command, in_buff, fake_str, context, handled); \
217 }
218
219
220#define CHAIN_LEVIN_INVOKE_MAP() \
221 int invoke(int command, const epee::span<const uint8_t> in_buff, epee::byte_stream& buff_out, epee::net_utils::connection_context_base& context) \
222 { \
223 bool handled = false; \
224 return handle_invoke_map(false, command, in_buff, buff_out, context, handled); \
225 }
226
227#define CHAIN_LEVIN_NOTIFY_MAP() \
228 int notify(int command, const epee::span<const uint8_t> in_buff, epee::net_utils::connection_context_base& context) \
229 { \
230 bool handled = false; std::string fake_str;\
231 return handle_invoke_map(true, command, in_buff, fake_str, context, handled); \
232 }
233
234#define CHAIN_LEVIN_NOTIFY_STUB() \
235 int notify(int command, const epee::span<const uint8_t> in_buff, epee::net_utils::connection_context_base& context) \
236 { \
237 return -1; \
238 }
239
240#define BEGIN_INVOKE_MAP2(owner_type) \
241 template <class t_context> int handle_invoke_map(bool is_notify, int command, const epee::span<const uint8_t> in_buff, epee::byte_stream& buff_out, t_context& context, bool& handled) \
242 { \
243 try { \
244 typedef owner_type internal_owner_type_name;
245
246#define HANDLE_INVOKE2(command_id, func, type_name_in, typename_out) \
247 if(!is_notify && command_id == command) \
248 {handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, type_name_in, typename_out>(this, command, in_buff, buff_out, std::bind(func, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4), context);}
249
250#define HANDLE_INVOKE_T2(COMMAND, func) \
251 if(!is_notify && COMMAND::ID == command) \
252 {handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, typename COMMAND::request, typename COMMAND::response>(command, in_buff, buff_out, std::bind(func, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4), context);}
253
254
255#define HANDLE_NOTIFY2(command_id, func, type_name_in) \
256 if(is_notify && command_id == command) \
257 {handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, type_name_in>(this, command, in_buff, std::bind(func, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), context);}
258
259#define HANDLE_NOTIFY_T2(NOTIFY, func) \
260 if(is_notify && NOTIFY::ID == command) \
261 {handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, typename NOTIFY::request>(this, command, in_buff, std::bind(func, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), context);}
262
263
264#define CHAIN_INVOKE_MAP2(func) \
265 { \
266 int res = func(is_notify, command, in_buff, buff_out, context, handled); \
267 if(handled) \
268 return res; \
269 }
270
271#define CHAIN_INVOKE_MAP_TO_OBJ2(obj) \
272 { \
273 int res = obj.handle_invoke_map(is_notify, command, in_buff, buff_out, context, handled); \
274 if(handled) \
275 return res; \
276 }
277
278#define CHAIN_INVOKE_MAP_TO_OBJ_FORCE_CONTEXT(obj, context_type) \
279 { \
280 int res = obj.handle_invoke_map(is_notify, command, in_buff, buff_out, static_cast<context_type>(context), handled); \
281 if(handled) return res; \
282 }
283
284
285#define END_INVOKE_MAP2() \
286 LOG_ERROR("Unknown command:" << command); \
287 on_levin_traffic(context, false, false, true, in_buff.size(), "invalid-command"); \
288 return LEVIN_ERROR_CONNECTION_HANDLER_NOT_DEFINED; \
289 } \
290 catch (const std::exception &e) { \
291 MERROR("Error in handle_invoke_map: " << e.what()); \
292 return LEVIN_ERROR_CONNECTION_TIMEDOUT; /* seems kinda appropriate */ \
293 } \
294 }
295
296 }
297}
298
A partial drop-in replacement for std::ostream.
Definition byte_stream.h:58
Provides space for levin (p2p) header, so that payload can be sent without copy.
Definition levin_base.h:132
byte_stream buffer
Has space for levin header until a finalize method is used.
Definition levin_base.h:159
byte_slice finalize_notify(uint32_t command)
Definition levin_base.h:152
Definition portable_storage.h:46
bool load_from_binary(const epee::span< const uint8_t > target, const limits_t *limits=nullptr)
Definition portable_storage.cpp:87
bool store_to_binary(byte_slice &target, std::size_t initial_buffer_size=8192)
Definition portable_storage.cpp:46
Non-owning sequence of data. Does not deep copy.
Definition span.h:55
constexpr std::size_t size() const noexcept
Definition span.h:109
constexpr bool empty() const noexcept
Definition span.h:107
const char * res
Definition hmac_keccak.cpp:42
void on_levin_traffic(const context_t &context, bool initiator, bool sent, bool error, size_t bytes, const char *category)
Definition levin_protocol_handler_async.h:54
#define LEVIN_ERROR_FORMAT
Definition levin_base.h:109
#define LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED
Definition levin_base.h:75
void on_levin_traffic(const context_t &context, bool initiator, bool sent, bool error, size_t bytes, const char *category)
Definition levin_protocol_handler_async.h:54
#define AUTO_VAL_INIT(v)
Definition misc_language.h:36
Definition abstract_http_client.h:36
bool invoke_remote_command2(const epee::net_utils::connection_context_base context, int command, const t_arg &out_struct, t_result &result_struct, t_transport &transport)
Definition levin_abstract_invoke2.h:60
bool notify_remote_command2(const typename t_transport::connection_context &context, int command, const t_arg &out_struct, t_transport &transport)
Definition levin_abstract_invoke2.h:133
int buff_to_t_adapter(int command, const epee::span< const uint8_t > in_buff, byte_stream &buff_out, callback_t cb, t_context &context)
Definition levin_abstract_invoke2.h:152
bool async_invoke_remote_command2(const epee::net_utils::connection_context_base &context, int command, const t_arg &out_struct, t_transport &transport, const callback_t &cb, size_t inv_timeout=LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED)
Definition levin_abstract_invoke2.h:87
TODO: (mj-xmr) This will be reduced in an another PR.
Definition byte_slice.h:40
const portMappingElt code
Definition portlistingparse.c:22
Definition net_utils_base.h:367
Definition portable_storage.h:53