Monero
Loading...
Searching...
No Matches
transport.hpp
Go to the documentation of this file.
1// Copyright (c) 2017-2022, The Monero Project
2//
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without modification, are
6// permitted provided that the following conditions are met:
7//
8// 1. Redistributions of source code must retain the above copyright notice, this list of
9// conditions and the following disclaimer.
10//
11// 2. Redistributions in binary form must reproduce the above copyright notice, this list
12// of conditions and the following disclaimer in the documentation and/or other
13// materials provided with the distribution.
14//
15// 3. Neither the name of the copyright holder nor the names of its contributors may be
16// used to endorse or promote products derived from this software without specific
17// prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
20// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
22// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
27// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28//
29
30#ifndef MONERO_TRANSPORT_H
31#define MONERO_TRANSPORT_H
32
33
34#include <boost/asio.hpp>
35#include <boost/asio/deadline_timer.hpp>
36#include <boost/array.hpp>
37#include <boost/utility/string_ref.hpp>
38
39#include <typeinfo>
40#include <type_traits>
41#include "net/http_client.h"
42
43#include "rapidjson/document.h"
44#include "rapidjson/writer.h"
46
47#include "exceptions.hpp"
48#include "trezor_defs.hpp"
49#include "messages_map.hpp"
50
51#include "messages/messages.pb.h"
52#include "messages/messages-common.pb.h"
53#include "messages/messages-management.pb.h"
54#include "messages/messages-monero.pb.h"
55
56namespace hw {
57namespace trezor {
58
59 using json = rapidjson::Document;
60 using json_val = rapidjson::Value;
61 namespace http = epee::net_utils::http;
62
63 const std::string DEFAULT_BRIDGE = "127.0.0.1:21325";
64
65 uint64_t pack_version(uint32_t major, uint32_t minor=0, uint32_t patch=0);
66
67 // Base HTTP comm serialization.
68 bool t_serialize(const std::string & in, std::string & out);
69 bool t_serialize(const epee::wipeable_string & in, std::string & out);
70 bool t_serialize(const json_val & in, std::string & out);
71 std::string t_serialize(const json_val & in);
72
73 bool t_deserialize(const std::string & in, std::string & out);
74 bool t_deserialize(std::string & in, epee::wipeable_string & out);
75 bool t_deserialize(const std::string & in, json & out);
76
77 // Flexible json serialization. HTTP client tailored for bridge API
78 template<class t_req, class t_res, class t_transport>
79 bool invoke_bridge_http(const boost::string_ref uri, const t_req & out_struct, t_res & result_struct, t_transport& transport, const boost::string_ref method = "POST", std::chrono::milliseconds timeout = std::chrono::seconds(180))
80 {
81 std::string req_param;
82 t_serialize(out_struct, req_param);
83
84 http::fields_list additional_params;
85 additional_params.push_back(std::make_pair("Origin","https://monero.trezor.io"));
86 additional_params.push_back(std::make_pair("Content-Type","application/json; charset=utf-8"));
87
88 const http::http_response_info* pri = nullptr;
89 const auto data_cleaner = epee::misc_utils::create_scope_leave_handler([&]() {
90 if (!req_param.empty()) {
91 memwipe(&req_param[0], req_param.size());
92 }
93 transport.wipe_response();
94 });
95
96 if(!transport.invoke(uri, method, req_param, timeout, &pri, std::move(additional_params)))
97 {
98 MERROR("Failed to invoke http request to " << uri);
99 return false;
100 }
101
102 if(!pri)
103 {
104 MERROR("Failed to invoke http request to " << uri << ", internal error (null response ptr)");
105 return false;
106 }
107
108 if(pri->m_response_code != 200)
109 {
110 MERROR("Failed to invoke http request to " << uri << ", wrong response code: " << pri->m_response_code
111 << " Response Body: " << pri->m_body);
112 return false;
113 }
114
115 return t_deserialize(const_cast<http::http_response_info*>(pri)->m_body, result_struct);
116 }
117
118 // Forward decl
119 class Transport;
120 class Protocol;
121
122 // Communication protocol
123 class Protocol {
124 public:
125 Protocol() = default;
126 virtual ~Protocol() = default;
128 virtual void session_end(Transport & transport){ };
129 virtual void write(Transport & transport, const google::protobuf::Message & req)= 0;
130 virtual void read(Transport & transport, std::shared_ptr<google::protobuf::Message> & msg, messages::MessageType * msg_type=nullptr)= 0;
131 };
132
133 class ProtocolV1 : public Protocol {
134 public:
135 ProtocolV1() = default;
136 virtual ~ProtocolV1() = default;
137
138 void write(Transport & transport, const google::protobuf::Message & req) override;
139 void read(Transport & transport, std::shared_ptr<google::protobuf::Message> & msg, messages::MessageType * msg_type=nullptr) override;
140 };
141
142
143 // Base transport
144 typedef std::vector<std::shared_ptr<Transport>> t_transport_vect;
145
146 class Transport {
147 public:
148 Transport();
149 virtual ~Transport() = default;
150
151 virtual bool ping() { return false; };
152 virtual std::string get_path() const { return ""; };
153 virtual void enumerate(t_transport_vect & res){};
154 virtual void open(){};
155 virtual void close(){};
156 virtual void write(const google::protobuf::Message & req) =0;
157 virtual void read(std::shared_ptr<google::protobuf::Message> & msg, messages::MessageType * msg_type=nullptr) =0;
158 virtual std::shared_ptr<Transport> find_debug() { return nullptr; };
159
160 virtual void write_chunk(const void * buff, size_t size) { };
161 virtual size_t read_chunk(void * buff, size_t size) { return 0; };
162 virtual std::ostream& dump(std::ostream& o) const { return o << "Transport<>"; }
163 protected:
165
166 virtual bool pre_open();
167 virtual bool pre_close();
168 };
169
170 // Bridge transport
171 class BridgeTransport : public Transport {
172 public:
174 boost::optional<std::string> device_path = boost::none,
175 boost::optional<std::string> bridge_host = boost::none);
176
177 virtual ~BridgeTransport() = default;
178
179 static const char * PATH_PREFIX;
180
181 std::string get_path() const override;
182 void enumerate(t_transport_vect & res) override;
183
184 void open() override;
185 void close() override;
186
187 void write(const google::protobuf::Message &req) override;
188 void read(std::shared_ptr<google::protobuf::Message> & msg, messages::MessageType * msg_type=nullptr) override;
189
190 const boost::optional<json> & device_info() const;
191 std::ostream& dump(std::ostream& o) const override;
192
193 private:
195 std::string m_bridge_host;
196 boost::optional<std::string> m_device_path;
197 boost::optional<std::string> m_session;
198 boost::optional<epee::wipeable_string> m_response;
199 boost::optional<json> m_device_info;
200 };
201
202 // UdpTransport transport
203 using boost::asio::ip::udp;
204
205 class UdpTransport : public Transport {
206 public:
207
208 explicit UdpTransport(
209 boost::optional<std::string> device_path=boost::none,
210 boost::optional<std::shared_ptr<Protocol>> proto=boost::none);
211
212 virtual ~UdpTransport() = default;
213
214 static const char * PATH_PREFIX;
215 static const char * DEFAULT_HOST;
216 static const int DEFAULT_PORT;
217
218 bool ping() override;
219 std::string get_path() const override;
220 void enumerate(t_transport_vect & res) override;
221
222 void open() override;
223 void close() override;
224 std::shared_ptr<Transport> find_debug() override;
225
226 void write(const google::protobuf::Message &req) override;
227 void read(std::shared_ptr<google::protobuf::Message> & msg, messages::MessageType * msg_type=nullptr) override;
228
229 void write_chunk(const void * buff, size_t size) override;
230 size_t read_chunk(void * buff, size_t size) override;
231
232 std::ostream& dump(std::ostream& o) const override;
233
234 private:
235 void require_socket();
236 ssize_t receive(void * buff, size_t size, boost::system::error_code * error_code=nullptr, bool no_throw=false, boost::posix_time::time_duration timeout=boost::posix_time::seconds(10));
237 void check_deadline();
238 static void handle_receive(const boost::system::error_code& ec, std::size_t length,
239 boost::system::error_code* out_ec, std::size_t* out_length);
240 bool ping_int(boost::posix_time::time_duration timeout=boost::posix_time::milliseconds(1500));
241
242 std::shared_ptr<Protocol> m_proto;
243 std::string m_device_host;
245
246 std::unique_ptr<udp::socket> m_socket;
247 boost::asio::io_context m_io_service;
248 boost::asio::deadline_timer m_deadline;
249 udp::endpoint m_endpoint;
250 };
251
252#ifdef WITH_DEVICE_TREZOR_WEBUSB
253#include <libusb.h>
254
255 class WebUsbTransport : public Transport {
256 public:
257
258 explicit WebUsbTransport(
259 boost::optional<libusb_device_descriptor*> descriptor = boost::none,
260 boost::optional<std::shared_ptr<Protocol>> proto = boost::none
261 );
262
263 virtual ~WebUsbTransport();
264
265 static const char * PATH_PREFIX;
266
267 std::string get_path() const override;
268 void enumerate(t_transport_vect & res) override;
269
270 void open() override;
271 void close() override;
272 std::shared_ptr<Transport> find_debug() override;
273
274 void write(const google::protobuf::Message &req) override;
275 void read(std::shared_ptr<google::protobuf::Message> & msg, messages::MessageType * msg_type=nullptr) override;
276
277 void write_chunk(const void * buff, size_t size) override;
278 size_t read_chunk(void * buff, size_t size) override;
279
280 std::ostream& dump(std::ostream& o) const override;
281
282 private:
283 void require_device() const;
284 void require_connected() const;
285 int get_interface() const;
286 unsigned char get_endpoint() const;
287
288 std::shared_ptr<Protocol> m_proto;
289
290 libusb_context *m_usb_session;
291 libusb_device *m_usb_device;
292 libusb_device_handle *m_usb_device_handle;
293 std::unique_ptr<libusb_device_descriptor> m_usb_device_desc;
294 std::vector<uint8_t> m_port_numbers;
295 int m_bus_id;
296 int m_device_addr;
297
298#ifdef WITH_TREZOR_DEBUGGING
299 bool m_debug_mode;
300#endif
301 };
302
303#endif
304
305 //
306 // General helpers
307 //
308
313
318
322 std::shared_ptr<Transport> transport(const std::string & path);
323
327 template<class t_transport=Transport>
328 std::shared_ptr<t_transport> transport_typed(const std::string & path){
329 auto t = transport(path);
330 if (!t){
331 return nullptr;
332 }
333
334 return std::dynamic_pointer_cast<t_transport>(t);
335 }
336
337 // Exception carries unexpected message being received
338 namespace exc {
340 protected:
341 hw::trezor::messages::MessageType recvType;
342 std::shared_ptr<google::protobuf::Message> recvMsg;
343
344 public:
346 UnexpectedMessageException(): ProtocolException("Trezor returned unexpected message") {};
347 UnexpectedMessageException(hw::trezor::messages::MessageType recvType,
348 const std::shared_ptr<google::protobuf::Message> & recvMsg)
350 reason = std::string("Trezor returned unexpected message: ") + std::to_string(recvType);
351 }
352 };
353 }
354
358 [[ noreturn ]] void throw_failure_exception(const messages::common::Failure * failure);
359
364 public:
366 GenericMessage(messages::MessageType m_type, const std::shared_ptr<google::protobuf::Message> &m_msg);
367 bool empty() const { return m_empty; }
368
369 hw::trezor::messages::MessageType m_type;
370 std::shared_ptr<google::protobuf::Message> m_msg;
372 };
373
380 template<class t_message=google::protobuf::Message>
381 std::shared_ptr<t_message>
382 exchange_message(Transport & transport, const google::protobuf::Message & req,
383 boost::optional<messages::MessageType> resp_type = boost::none)
384 {
385 // Require strictly protocol buffers response in the template.
386 BOOST_STATIC_ASSERT(boost::is_base_of<google::protobuf::Message, t_message>::value);
387
388 // Write the request
389 transport.write(req);
390
391 // Read the response
392 std::shared_ptr<google::protobuf::Message> msg_resp;
393 hw::trezor::messages::MessageType msg_resp_type;
394 transport.read(msg_resp, &msg_resp_type);
395
396 // Determine type of expected message response
397 messages::MessageType required_type = resp_type ? resp_type.get() : MessageMapper::get_message_wire_number<t_message>();
398
399 if (msg_resp_type == required_type) {
400 return message_ptr_retype<t_message>(msg_resp);
401 } else if (msg_resp_type == messages::MessageType_Failure){
402 throw_failure_exception(dynamic_cast<messages::common::Failure*>(msg_resp.get()));
403 } else {
404 throw exc::UnexpectedMessageException(msg_resp_type, msg_resp);
405 }
406 }
407
408 std::ostream& operator<<(std::ostream& o, hw::trezor::Transport const& t);
409 std::ostream& operator<<(std::ostream& o, std::shared_ptr<hw::trezor::Transport> const& t);
410}}
411
412
413#endif //MONERO_TRANSPORT_H
static void close()
Definition blockchain_blackball.cpp:279
static void open(MDB_env *&env, const boost::filesystem::path &path, uint64_t db_flags, bool readonly)
Definition blockchain_prune.cpp:66
Definition wipeable_string.h:41
std::string m_bridge_host
Definition transport.hpp:195
virtual ~BridgeTransport()=default
static const char * PATH_PREFIX
Definition transport.hpp:179
void close() override
Definition transport.cpp:426
void write(const google::protobuf::Message &req) override
Definition transport.cpp:447
BridgeTransport(boost::optional< std::string > device_path=boost::none, boost::optional< std::string > bridge_host=boost::none)
Definition transport.cpp:337
boost::optional< std::string > m_session
Definition transport.hpp:197
const boost::optional< json > & device_info() const
Definition transport.cpp:499
boost::optional< json > m_device_info
Definition transport.hpp:199
boost::optional< std::string > m_device_path
Definition transport.hpp:196
std::string get_path() const override
Definition transport.cpp:360
boost::optional< epee::wipeable_string > m_response
Definition transport.hpp:198
void enumerate(t_transport_vect &res) override
Definition transport.cpp:369
void read(std::shared_ptr< google::protobuf::Message > &msg, messages::MessageType *msg_type=nullptr) override
Definition transport.cpp:471
std::ostream & dump(std::ostream &o) const override
Definition transport.cpp:503
epee::net_utils::http::http_simple_client m_http_client
Definition transport.hpp:194
void open() override
Definition transport.cpp:405
bool m_empty
Definition transport.hpp:371
std::shared_ptr< google::protobuf::Message > m_msg
Definition transport.hpp:370
GenericMessage()
Definition transport.hpp:365
bool empty() const
Definition transport.hpp:367
GenericMessage(messages::MessageType m_type, const std::shared_ptr< google::protobuf::Message > &m_msg)
hw::trezor::messages::MessageType m_type
Definition transport.hpp:369
static messages::MessageType get_message_wire_number()
Definition messages_map.hpp:74
void write(Transport &transport, const google::protobuf::Message &req) override
Definition transport.cpp:206
void read(Transport &transport, std::shared_ptr< google::protobuf::Message > &msg, messages::MessageType *msg_type=nullptr) override
Definition transport.cpp:243
virtual ~ProtocolV1()=default
virtual void session_end(Transport &transport)
Definition transport.hpp:128
virtual void session_begin(Transport &transport)
Definition transport.hpp:127
virtual ~Protocol()=default
virtual void read(Transport &transport, std::shared_ptr< google::protobuf::Message > &msg, messages::MessageType *msg_type=nullptr)=0
virtual void write(Transport &transport, const google::protobuf::Message &req)=0
Definition transport.hpp:146
virtual void close()
Definition transport.hpp:155
virtual void enumerate(t_transport_vect &res)
Definition transport.hpp:153
virtual void read(std::shared_ptr< google::protobuf::Message > &msg, messages::MessageType *msg_type=nullptr)=0
Transport()
Definition transport.cpp:297
virtual void write_chunk(const void *buff, size_t size)
Definition transport.hpp:160
virtual size_t read_chunk(void *buff, size_t size)
Definition transport.hpp:161
virtual bool pre_open()
Definition transport.cpp:301
virtual std::ostream & dump(std::ostream &o) const
Definition transport.hpp:162
virtual std::string get_path() const
Definition transport.hpp:152
virtual bool pre_close()
Definition transport.cpp:317
virtual void open()
Definition transport.hpp:154
virtual bool ping()
Definition transport.hpp:151
virtual void write(const google::protobuf::Message &req)=0
long m_open_counter
Definition transport.hpp:164
virtual std::shared_ptr< Transport > find_debug()
Definition transport.hpp:158
virtual ~Transport()=default
int m_device_port
Definition transport.hpp:244
bool ping() override
Definition transport.cpp:569
void write(const google::protobuf::Message &req) override
Definition transport.cpp:752
std::shared_ptr< Protocol > m_proto
Definition transport.hpp:242
udp::endpoint m_endpoint
Definition transport.hpp:249
static const char * PATH_PREFIX
Definition transport.hpp:214
void enumerate(t_transport_vect &res) override
Definition transport.cpp:594
std::ostream & dump(std::ostream &o) const override
Definition transport.cpp:793
void check_deadline()
Definition transport.cpp:760
void open() override
Definition transport.cpp:610
void write_chunk(const void *buff, size_t size) override
Definition transport.cpp:656
static const char * DEFAULT_HOST
Definition transport.hpp:215
size_t read_chunk(void *buff, size_t size) override
Definition transport.cpp:669
void require_socket()
Definition transport.cpp:563
bool ping_int(boost::posix_time::time_duration timeout=boost::posix_time::milliseconds(1500))
Definition transport.cpp:573
void close() override
Definition transport.cpp:628
virtual ~UdpTransport()=default
std::string m_device_host
Definition transport.hpp:243
std::unique_ptr< udp::socket > m_socket
Definition transport.hpp:246
static const int DEFAULT_PORT
Definition transport.hpp:216
ssize_t receive(void *buff, size_t size, boost::system::error_code *error_code=nullptr, bool no_throw=false, boost::posix_time::time_duration timeout=boost::posix_time::seconds(10))
Definition transport.cpp:703
std::string get_path() const override
Definition transport.cpp:558
std::shared_ptr< Transport > find_debug() override
Definition transport.cpp:643
boost::asio::deadline_timer m_deadline
Definition transport.hpp:248
UdpTransport(boost::optional< std::string > device_path=boost::none, boost::optional< std::shared_ptr< Protocol > > proto=boost::none)
Definition transport.cpp:533
boost::asio::io_context m_io_service
Definition transport.hpp:247
static void handle_receive(const boost::system::error_code &ec, std::size_t length, boost::system::error_code *out_ec, std::size_t *out_length)
Definition transport.cpp:787
void read(std::shared_ptr< google::protobuf::Message > &msg, messages::MessageType *msg_type=nullptr) override
Definition transport.cpp:756
ProtocolException()
Definition exceptions.hpp:118
boost::optional< std::string > reason
Definition exceptions.hpp:62
UnexpectedMessageException()
Definition transport.hpp:346
hw::trezor::messages::MessageType recvType
Definition transport.hpp:341
std::shared_ptr< google::protobuf::Message > recvMsg
Definition transport.hpp:342
UnexpectedMessageException(hw::trezor::messages::MessageType recvType, const std::shared_ptr< google::protobuf::Message > &recvMsg)
Definition transport.hpp:347
ProtocolException()
Definition exceptions.hpp:118
#define true
const char * res
Definition hmac_keccak.cpp:42
void * memwipe(void *src, size_t n)
Definition memwipe.c:107
auto_scope_leave_caller create_scope_leave_handler(t_scope_leave_handler f)
Definition misc_language.h:97
Definition abstract_http_client.h:60
http_simple_client_template< blocked_mode_client > http_simple_client
Definition http_client.h:877
Definition device_trezor.cpp:35
void sort_transports_by_env(t_transport_vect &res)
Definition transport.cpp:1198
std::ostream & operator<<(std::ostream &o, hw::trezor::Transport const &t)
Definition transport.cpp:1278
void throw_failure_exception(const messages::common::Failure *failure)
Definition transport.cpp:1244
std::shared_ptr< t_message > message_ptr_retype(std::shared_ptr< google::protobuf::Message > &in)
Definition messages_map.hpp:81
bool t_serialize(const std::string &in, std::string &out)
Definition transport.cpp:55
bool t_deserialize(const std::string &in, std::string &out)
Definition transport.cpp:79
std::shared_ptr< t_message > exchange_message(Transport &transport, const google::protobuf::Message &req, boost::optional< messages::MessageType > resp_type=boost::none)
Definition transport.hpp:382
const std::string DEFAULT_BRIDGE
Definition transport.hpp:63
std::shared_ptr< t_transport > transport_typed(const std::string &path)
Definition transport.hpp:328
std::shared_ptr< Transport > transport(const std::string &path)
Definition transport.cpp:1231
uint64_t pack_version(uint32_t major, uint32_t minor, uint32_t patch)
Definition transport.cpp:100
bool invoke_bridge_http(const boost::string_ref uri, const t_req &out_struct, t_res &result_struct, t_transport &transport, const boost::string_ref method="POST", std::chrono::milliseconds timeout=std::chrono::seconds(180))
Definition transport.hpp:79
rapidjson::Document json
Definition transport.hpp:59
rapidjson::Value json_val
Definition transport.hpp:60
std::vector< std::shared_ptr< Transport > > t_transport_vect
Definition transport.hpp:144
void enumerate(t_transport_vect &res)
Definition transport.cpp:1171
Definition device.cpp:38
Definition uri.py:1
unsigned int uint32_t
Definition stdint.h:126
unsigned __int64 uint64_t
Definition stdint.h:136
void dump(const char *buffer, uint64_t count, const char *name)
Definition utility.hpp:75