Electroneum
transport.cpp
Go to the documentation of this file.
1 // Copyright (c) 2017-Present, Electroneum
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 #ifdef WITH_DEVICE_TREZOR_WEBUSB
31 #include <libusb.h>
32 #endif
33 
34 #include <algorithm>
35 #include <functional>
36 #include <boost/endian/conversion.hpp>
37 #include <boost/asio/io_service.hpp>
38 #include <boost/asio/ip/udp.hpp>
39 #include <boost/date_time/posix_time/posix_time_types.hpp>
40 #include <boost/format.hpp>
42 #include "transport.hpp"
43 #include "messages/messages-common.pb.h"
44 
45 #undef ELECTRONEUM_DEFAULT_LOG_CATEGORY
46 #define ELECTRONEUM_DEFAULT_LOG_CATEGORY "device.trezor.transport"
47 
48 using namespace std;
50 
51 
52 namespace hw{
53 namespace trezor{
54 
55  bool t_serialize(const std::string & in, std::string & out){
56  out = in;
57  return true;
58  }
59 
60  bool t_serialize(const json_val & in, std::string & out){
62  rapidjson::Writer<rapidjson::StringBuffer> writer(sb);
63  in.Accept(writer);
64  out = sb.GetString();
65  return true;
66  }
67 
69  std::string ret;
70  t_serialize(in, ret);
71  return ret;
72  }
73 
74  bool t_deserialize(const std::string & in, std::string & out){
75  out = in;
76  return true;
77  }
78 
79  bool t_deserialize(const std::string & in, json & out){
80  if (out.Parse(in.c_str()).HasParseError()) {
81  throw exc::CommunicationException("JSON parse error");
82  }
83  return true;
84  }
85 
86  static std::string json_get_string(const rapidjson::Value & in){
87  return std::string(in.GetString());
88  }
89 
91  {
92  // packing (major, minor, patch) to 64 B: 16 B | 24 B | 24 B
93  const unsigned bits_1 = 16;
94  const unsigned bits_2 = 24;
95  const uint32_t mask_1 = (1 << bits_1) - 1;
96  const uint32_t mask_2 = (1 << bits_2) - 1;
97  CHECK_AND_ASSERT_THROW_MES(major <= mask_1 && minor <= mask_2 && patch <= mask_2, "Version numbers overflow packing scheme");
98  return patch | (((uint64_t)minor) << bits_2) | (((uint64_t)major) << (bits_1 + bits_2));
99  }
100 
101  typedef struct {
106 
107  static trezor_usb_desc_t TREZOR_DESC_T1 = {1, 0x534C, 0x0001};
108  static trezor_usb_desc_t TREZOR_DESC_T2 = {2, 0x1209, 0x53C1};
109  static trezor_usb_desc_t TREZOR_DESC_T2_BL = {3, 0x1209, 0x53C0};
110 
111  static trezor_usb_desc_t TREZOR_DESCS[] = {
112  TREZOR_DESC_T1,
113  TREZOR_DESC_T2,
114  TREZOR_DESC_T2_BL,
115  };
116 
117  static size_t TREZOR_DESCS_LEN = sizeof(TREZOR_DESCS)/sizeof(TREZOR_DESCS[0]);
118 
119  static ssize_t get_device_idx(uint16_t id_vendor, uint16_t id_product){
120  for(size_t i = 0; i < TREZOR_DESCS_LEN; ++i){
121  if (TREZOR_DESCS[i].id_vendor == id_vendor && TREZOR_DESCS[i].id_product == id_product){
122  return i;
123  }
124  }
125 
126  return -1;
127  }
128 
129  static bool is_device_supported(ssize_t device_idx){
130  CHECK_AND_ASSERT_THROW_MES(device_idx < (ssize_t)TREZOR_DESCS_LEN, "Device desc idx too big");
131  if (device_idx < 0){
132  return false;
133  }
134 
135 #ifdef TREZOR_1_SUPPORTED
136  return true;
137 #else
138  return TREZOR_DESCS[device_idx].trezor_type != 1;
139 #endif
140  }
141 
142  //
143  // Helpers
144  //
145 
146 #define PROTO_HEADER_SIZE 6
147 
148  static size_t message_size(const google::protobuf::Message &req){
149  return static_cast<size_t>(req.ByteSize());
150  }
151 
152  static size_t serialize_message_buffer_size(size_t msg_size) {
153  return PROTO_HEADER_SIZE + msg_size; // tag 2B + len 4B
154  }
155 
156  static void serialize_message_header(void * buff, uint16_t tag, uint32_t len){
157  uint16_t wire_tag = boost::endian::native_to_big(static_cast<uint16_t>(tag));
158  uint32_t wire_len = boost::endian::native_to_big(static_cast<uint32_t>(len));
159  memcpy(buff, (void *) &wire_tag, 2);
160  memcpy((uint8_t*)buff + 2, (void *) &wire_len, 4);
161  }
162 
163  static void deserialize_message_header(const void * buff, uint16_t & tag, uint32_t & len){
164  uint16_t wire_tag;
165  uint32_t wire_len;
166  memcpy(&wire_tag, buff, 2);
167  memcpy(&wire_len, (uint8_t*)buff + 2, 4);
168 
169  tag = boost::endian::big_to_native(wire_tag);
170  len = boost::endian::big_to_native(wire_len);
171  }
172 
173  static void serialize_message(const google::protobuf::Message &req, size_t msg_size, uint8_t * buff, size_t buff_size) {
174  auto msg_wire_num = MessageMapper::get_message_wire_number(req);
175  const auto req_buffer_size = serialize_message_buffer_size(msg_size);
176  if (req_buffer_size > buff_size){
177  throw std::invalid_argument("Buffer too small");
178  }
179 
180  serialize_message_header(buff, msg_wire_num, msg_size);
181  if (!req.SerializeToArray(buff + 6, msg_size)){
182  throw exc::EncodingException("Message serialization error");
183  }
184  }
185 
186  //
187  // Communication protocol
188  //
189 
190 #define REPLEN 64
191 
192  void ProtocolV1::write(Transport & transport, const google::protobuf::Message & req){
193  const auto msg_size = message_size(req);
194  const auto buff_size = serialize_message_buffer_size(msg_size) + 2;
195 
196  std::unique_ptr<uint8_t[]> req_buff(new uint8_t[buff_size]);
197  uint8_t * req_buff_raw = req_buff.get();
198  req_buff_raw[0] = '#';
199  req_buff_raw[1] = '#';
200 
201  serialize_message(req, msg_size, req_buff_raw + 2, buff_size - 2);
202 
203  size_t offset = 0;
204  uint8_t chunk_buff[REPLEN];
205 
206  // Chunk by chunk upload
207  while(offset < buff_size){
208  auto to_copy = std::min((size_t)(buff_size - offset), (size_t)(REPLEN - 1));
209 
210  chunk_buff[0] = '?';
211  memcpy(chunk_buff + 1, req_buff_raw + offset, to_copy);
212 
213  // Pad with zeros
214  if (to_copy < REPLEN - 1){
215  memset(chunk_buff + 1 + to_copy, 0, REPLEN - 1 - to_copy);
216  }
217 
218  transport.write_chunk(chunk_buff, REPLEN);
219  offset += REPLEN - 1;
220  }
221  }
222 
223  void ProtocolV1::read(Transport & transport, std::shared_ptr<google::protobuf::Message> & msg, messages::MessageType * msg_type){
224  char chunk[REPLEN];
225 
226  // Initial chunk read
227  size_t nread = transport.read_chunk(chunk, REPLEN);
228  if (nread != REPLEN){
229  throw exc::CommunicationException("Read chunk has invalid size");
230  }
231 
232  if (strncmp(chunk, "?##", 3) != 0){
233  throw exc::CommunicationException("Malformed chunk");
234  }
235 
236  uint16_t tag;
237  uint32_t len;
238  nread -= 3 + 6;
239  deserialize_message_header(chunk + 3, tag, len);
240 
241  std::string data_acc(chunk + 3 + 6, nread);
242  data_acc.reserve(len);
243 
244  while(nread < len){
245  const size_t cur = transport.read_chunk(chunk, REPLEN);
246  if (chunk[0] != '?'){
247  throw exc::CommunicationException("Chunk malformed");
248  }
249 
250  data_acc.append(chunk + 1, cur - 1);
251  nread += cur - 1;
252  }
253 
254  if (msg_type){
255  *msg_type = static_cast<messages::MessageType>(tag);
256  }
257 
258  if (nread < len){
259  throw exc::CommunicationException("Response incomplete");
260  }
261 
262  std::shared_ptr<google::protobuf::Message> msg_wrap(MessageMapper::get_message(tag));
263  if (!msg_wrap->ParseFromArray(data_acc.c_str(), len)){
264  throw exc::CommunicationException("Message could not be parsed");
265  }
266 
267  msg = msg_wrap;
268  }
269 
270  static void assert_port_number(uint32_t port)
271  {
272  CHECK_AND_ASSERT_THROW_MES(port >= 1024 && port < 65535, "Invalid port number: " << port);
273  }
274 
275  Transport::Transport(): m_open_counter(0) {
276 
277  }
278 
280  if (m_open_counter > 0){
281  MTRACE("Already opened, count: " << m_open_counter);
282  m_open_counter += 1;
283  return false;
284 
285  } else if (m_open_counter < 0){
286  MTRACE("Negative open value: " << m_open_counter);
287 
288  }
289 
290  // Caller should set m_open_counter to 1 after open
291  m_open_counter = 0;
292  return true;
293  }
294 
296  m_open_counter -= 1;
297 
298  if (m_open_counter < 0){
299  MDEBUG("Already closed. Counter " << m_open_counter);
300 
301  } else if (m_open_counter == 0) {
302  return true;
303 
304  }
305 
306  return false;
307  }
308 
309  //
310  // Bridge transport
311  //
312 
313  const char * BridgeTransport::PATH_PREFIX = "bridge:";
314 
316  boost::optional<std::string> device_path,
317  boost::optional<std::string> bridge_host):
318  m_device_path(device_path),
319  m_bridge_host(bridge_host ? bridge_host.get() : DEFAULT_BRIDGE),
320  m_response(boost::none),
321  m_session(boost::none),
322  m_device_info(boost::none)
323  {
324  const char *env_bridge_port = nullptr;
325  if (!bridge_host && (env_bridge_port = getenv("TREZOR_BRIDGE_PORT")) != nullptr)
326  {
327  uint16_t bridge_port;
328  CHECK_AND_ASSERT_THROW_MES(epee::string_tools::get_xtype_from_string(bridge_port, env_bridge_port), "Invalid bridge port: " << env_bridge_port);
329  assert_port_number(bridge_port);
330 
331  m_bridge_host = std::string("127.0.0.1:") + boost::lexical_cast<std::string>(env_bridge_port);
332  MDEBUG("Bridge host: " << m_bridge_host);
333  }
334 
335  m_http_client.set_server(m_bridge_host, boost::none, epee::net_utils::ssl_support_t::e_ssl_support_disabled);
336  }
337 
339  if (!m_device_path){
340  return "";
341  }
342 
343  std::string path(PATH_PREFIX);
344  return path + m_device_path.get();
345  }
346 
348  json bridge_res;
349  std::string req;
350 
351  bool req_status = invoke_bridge_http("/enumerate", req, bridge_res, m_http_client);
352  if (!req_status){
353  throw exc::CommunicationException("Bridge enumeration failed");
354  }
355 
356  for(rapidjson::Value::ConstValueIterator itr = bridge_res.Begin(); itr != bridge_res.End(); ++itr){
357  auto element = itr->GetObject();
358  auto t = std::make_shared<BridgeTransport>(boost::make_optional(json_get_string(element["path"])));
359 
360  auto itr_vendor = element.FindMember("vendor");
361  auto itr_product = element.FindMember("product");
362  if (itr_vendor != element.MemberEnd() && itr_product != element.MemberEnd()
363  && itr_vendor->value.IsNumber() && itr_product->value.IsNumber()){
364  try {
365  const auto id_vendor = (uint16_t) itr_vendor->value.GetUint64();
366  const auto id_product = (uint16_t) itr_product->value.GetUint64();
367  const auto device_idx = get_device_idx(id_vendor, id_product);
368  if (!is_device_supported(device_idx)){
369  MDEBUG("Device with idx " << device_idx << " is not supported. Vendor: " << id_vendor << ", product: " << id_product);
370  continue;
371  }
372  } catch(const std::exception &e){
373  MERROR("Could not detect vendor & product: " << e.what());
374  }
375  }
376 
377  t->m_device_info.emplace();
378  t->m_device_info->CopyFrom(*itr, t->m_device_info->GetAllocator());
379  res.push_back(t);
380  }
381  }
382 
384  if (!pre_open()){
385  return;
386  }
387 
388  if (!m_device_path){
389  throw exc::CommunicationException("Coud not open, empty device path");
390  }
391 
392  std::string uri = "/acquire/" + m_device_path.get() + "/null";
393  std::string req;
394  json bridge_res;
395  bool req_status = invoke_bridge_http(uri, req, bridge_res, m_http_client);
396  if (!req_status){
397  throw exc::CommunicationException("Failed to acquire device");
398  }
399 
400  m_session = boost::make_optional(json_get_string(bridge_res["session"]));
401  m_open_counter = 1;
402  }
403 
405  if (!pre_close()){
406  return;
407  }
408 
409  MTRACE("Closing Trezor:BridgeTransport");
410  if (!m_device_path || !m_session){
411  throw exc::CommunicationException("Device not open");
412  }
413 
414  std::string uri = "/release/" + m_session.get();
415  std::string req;
416  json bridge_res;
417  bool req_status = invoke_bridge_http(uri, req, bridge_res, m_http_client);
418  if (!req_status){
419  throw exc::CommunicationException("Failed to release device");
420  }
421 
422  m_session = boost::none;
423  }
424 
425  void BridgeTransport::write(const google::protobuf::Message &req) {
426  m_response = boost::none;
427 
428  const auto msg_size = message_size(req);
429  const auto buff_size = serialize_message_buffer_size(msg_size);
430 
431  std::unique_ptr<uint8_t[]> req_buff(new uint8_t[buff_size]);
432  uint8_t * req_buff_raw = req_buff.get();
433 
434  serialize_message(req, msg_size, req_buff_raw, buff_size);
435 
436  std::string uri = "/call/" + m_session.get();
437  std::string req_hex = epee::to_hex::string(epee::span<const std::uint8_t>(req_buff_raw, buff_size));
438  std::string res_hex;
439 
440  bool req_status = invoke_bridge_http(uri, req_hex, res_hex, m_http_client);
441  if (!req_status){
442  throw exc::CommunicationException("Call method failed");
443  }
444 
445  m_response = res_hex;
446  }
447 
448  void BridgeTransport::read(std::shared_ptr<google::protobuf::Message> & msg, messages::MessageType * msg_type) {
449  if (!m_response){
450  throw exc::CommunicationException("Could not read, no response stored");
451  }
452 
453  std::string bin_data;
454  if (!epee::string_tools::parse_hexstr_to_binbuff(m_response.get(), bin_data)){
455  throw exc::CommunicationException("Response is not well hexcoded");
456  }
457 
458  uint16_t msg_tag;
459  uint32_t msg_len;
460  deserialize_message_header(bin_data.c_str(), msg_tag, msg_len);
461  if (bin_data.size() != msg_len + 6){
462  throw exc::CommunicationException("Response is not well hexcoded");
463  }
464 
465  if (msg_type){
466  *msg_type = static_cast<messages::MessageType>(msg_tag);
467  }
468 
469  std::shared_ptr<google::protobuf::Message> msg_wrap(MessageMapper::get_message(msg_tag));
470  if (!msg_wrap->ParseFromArray(bin_data.c_str() + 6, msg_len)){
471  throw exc::EncodingException("Response is not well hexcoded");
472  }
473  msg = msg_wrap;
474  }
475 
476  const boost::optional<json> & BridgeTransport::device_info() const {
477  return m_device_info;
478  }
479 
480  std::ostream& BridgeTransport::dump(std::ostream& o) const {
481  return o << "BridgeTransport<path=" << (m_device_path ? get_path() : "None")
482  << ", info=" << (m_device_info ? t_serialize(m_device_info.get()) : "None")
483  << ", session=" << (m_session ? m_session.get() : "None")
484  << ">";
485  }
486 
487  //
488  // UdpTransport
489  //
490  const char * UdpTransport::PATH_PREFIX = "udp:";
491  const char * UdpTransport::DEFAULT_HOST = "127.0.0.1";
492  const int UdpTransport::DEFAULT_PORT = 21324;
493 
494  static void parse_udp_path(std::string &host, int &port, std::string path)
495  {
496  if (boost::starts_with(path, UdpTransport::PATH_PREFIX))
497  {
498  path = path.substr(strlen(UdpTransport::PATH_PREFIX));
499  }
500 
501  auto delim = path.find(':');
502  if (delim == std::string::npos) {
503  host = path;
504  } else {
505  host = path.substr(0, delim);
506  port = std::stoi(path.substr(delim + 1));
507  }
508  }
509 
510  UdpTransport::UdpTransport(boost::optional<std::string> device_path,
511  boost::optional<std::shared_ptr<Protocol>> proto) :
512  m_io_service(), m_deadline(m_io_service)
513  {
514  m_device_host = DEFAULT_HOST;
515  m_device_port = DEFAULT_PORT;
516  const char *env_trezor_path = nullptr;
517 
518  if (device_path) {
519  parse_udp_path(m_device_host, m_device_port, device_path.get());
520  } else if ((env_trezor_path = getenv("TREZOR_PATH")) != nullptr && boost::starts_with(env_trezor_path, UdpTransport::PATH_PREFIX)){
521  parse_udp_path(m_device_host, m_device_port, std::string(env_trezor_path));
522  MDEBUG("Applied TREZOR_PATH: " << m_device_host << ":" << m_device_port);
523  } else {
524  m_device_host = DEFAULT_HOST;
525  }
526 
527  assert_port_number((uint32_t)m_device_port);
528  if (m_device_host != "localhost" && m_device_host != DEFAULT_HOST){
529  throw std::invalid_argument("Local endpoint allowed only");
530  }
531 
532  m_proto = proto ? proto.get() : std::make_shared<ProtocolV1>();
533  }
534 
536  std::string path(PATH_PREFIX);
537  return path + m_device_host + ":" + std::to_string(m_device_port);
538  }
539 
540  void UdpTransport::require_socket(){
541  if (!m_socket){
542  throw exc::NotConnectedException("Socket not connected");
543  }
544  }
545 
547  return ping_int();
548  }
549 
550  bool UdpTransport::ping_int(boost::posix_time::time_duration timeout){
551  require_socket();
552  try {
553  std::string req = "PINGPING";
554  char res[8];
555 
556  m_socket->send_to(boost::asio::buffer(req.c_str(), req.size()), m_endpoint);
557  receive(res, 8, nullptr, false, timeout);
558 
559  return memcmp(res, "PONGPONG", 8) == 0;
560 
561  } catch(...){
562  return false;
563  }
564  }
565 
567  std::shared_ptr<UdpTransport> t = std::make_shared<UdpTransport>();
568  bool t_works = false;
569 
570  try{
571  t->open();
572  t_works = t->ping();
573  } catch(...) {
574 
575  }
576  t->close();
577  if (t_works){
578  res.push_back(t);
579  }
580  }
581 
583  if (!pre_open()){
584  return;
585  }
586 
587  udp::resolver resolver(m_io_service);
588  udp::resolver::query query(udp::v4(), m_device_host, std::to_string(m_device_port));
589  m_endpoint = *resolver.resolve(query);
590 
591  m_socket.reset(new udp::socket(m_io_service));
592  m_socket->open(udp::v4());
593 
594  m_deadline.expires_at(boost::posix_time::pos_infin);
595  check_deadline();
596 
597  m_proto->session_begin(*this);
598  m_open_counter = 1;
599  }
600 
602  if (!pre_close()){
603  return;
604  }
605 
606  MTRACE("Closing Trezor:UdpTransport");
607  if (!m_socket) {
608  throw exc::CommunicationException("Socket is already closed");
609  }
610 
611  m_proto->session_end(*this);
612  m_socket->close();
613  m_socket = nullptr;
614  }
615 
616  std::shared_ptr<Transport> UdpTransport::find_debug() {
617 #ifdef WITH_TREZOR_DEBUGGING
618  std::shared_ptr<UdpTransport> t = std::make_shared<UdpTransport>();
619  t->m_proto = std::make_shared<ProtocolV1>();
620  t->m_device_host = m_device_host;
621  t->m_device_port = m_device_port + 1;
622  return t;
623 #else
624  MINFO("Debug link is disabled in production");
625  return nullptr;
626 #endif
627  }
628 
629  void UdpTransport::write_chunk(const void * buff, size_t size){
630  require_socket();
631 
632  if (size != 64){
633  throw exc::CommunicationException("Invalid chunk size");
634  }
635 
636  auto written = m_socket->send_to(boost::asio::buffer(buff, size), m_endpoint);
637  if (size != written){
638  throw exc::CommunicationException("Could not send the whole chunk");
639  }
640  }
641 
642  size_t UdpTransport::read_chunk(void * buff, size_t size){
643  require_socket();
644  if (size < 64){
645  throw std::invalid_argument("Buffer too small");
646  }
647 
648  ssize_t len;
649  while(true) {
650  try {
651  boost::system::error_code ec;
652  len = receive(buff, size, &ec, true);
653  if (ec == boost::asio::error::operation_aborted) {
654  continue;
655  } else if (ec) {
656  throw exc::CommunicationException(std::string("Comm error: ") + ec.message());
657  }
658 
659  if (len != 64) {
660  throw exc::CommunicationException("Invalid chunk size");
661  }
662 
663  break;
664 
665  } catch(exc::CommunicationException const& e){
666  throw;
667  } catch(std::exception const& e){
668  MWARNING("Error reading chunk, reason: " << e.what());
669  throw exc::CommunicationException(std::string("Chunk read error: ") + std::string(e.what()));
670  }
671  }
672 
673  return static_cast<size_t>(len);
674  }
675 
676  ssize_t UdpTransport::receive(void * buff, size_t size, boost::system::error_code * error_code, bool no_throw, boost::posix_time::time_duration timeout){
677  boost::system::error_code ec;
678  boost::asio::mutable_buffer buffer = boost::asio::buffer(buff, size);
679 
680  require_socket();
681 
682  // Set a deadline for the asynchronous operation.
683  m_deadline.expires_from_now(timeout);
684 
685  // Set up the variables that receive the result of the asynchronous
686  // operation. The error code is set to would_block to signal that the
687  // operation is incomplete. Asio guarantees that its asynchronous
688  // operations will never fail with would_block, so any other value in
689  // ec indicates completion.
690  ec = boost::asio::error::would_block;
691  std::size_t length = 0;
692 
693  // Start the asynchronous operation itself. The handle_receive function
694  // used as a callback will update the ec and length variables.
695  m_socket->async_receive_from(boost::asio::buffer(buffer), m_endpoint,
696  std::bind(&UdpTransport::handle_receive, std::placeholders::_1, std::placeholders::_2, &ec, &length));
697 
698  // Block until the asynchronous operation has completed.
699  do {
700  m_io_service.run_one();
701  }
702  while (ec == boost::asio::error::would_block);
703 
704  if (error_code){
705  *error_code = ec;
706  }
707 
708  if (no_throw){
709  return length;
710  }
711 
712  // Operation result
713  if (ec == boost::asio::error::operation_aborted){
714  throw exc::TimeoutException();
715 
716  } else if (ec) {
717  MWARNING("Reading from UDP socket failed: " << ec.message());
718  throw exc::CommunicationException();
719 
720  }
721 
722  return length;
723  }
724 
725  void UdpTransport::write(const google::protobuf::Message &req) {
726  m_proto->write(*this, req);
727  }
728 
729  void UdpTransport::read(std::shared_ptr<google::protobuf::Message> & msg, messages::MessageType * msg_type) {
730  m_proto->read(*this, msg, msg_type);
731  }
732 
733  void UdpTransport::check_deadline(){
734  if (!m_socket){
735  return; // no active socket.
736  }
737 
738  // Check whether the deadline has passed. We compare the deadline against
739  // the current time since a new asynchronous operation may have moved the
740  // deadline before this actor had a chance to run.
741  if (m_deadline.expires_at() <= boost::asio::deadline_timer::traits_type::now())
742  {
743  // The deadline has passed. The outstanding asynchronous operation needs
744  // to be cancelled so that the blocked receive() function will return.
745  //
746  // Please note that cancel() has portability issues on some versions of
747  // Microsoft Windows, and it may be necessary to use close() instead.
748  // Consult the documentation for cancel() for further information.
749  m_socket->cancel();
750 
751  // There is no longer an active deadline. The expiry is set to positive
752  // infinity so that the actor takes no action until a new deadline is set.
753  m_deadline.expires_at(boost::posix_time::pos_infin);
754  }
755 
756  // Put the actor back to sleep.
757  m_deadline.async_wait(boost::bind(&UdpTransport::check_deadline, this));
758  }
759 
760  void UdpTransport::handle_receive(const boost::system::error_code &ec, std::size_t length,
761  boost::system::error_code *out_ec, std::size_t *out_length) {
762  *out_ec = ec;
763  *out_length = length;
764  }
765 
766  std::ostream& UdpTransport::dump(std::ostream& o) const {
767  return o << "UdpTransport<path=" << get_path()
768  << ", socket_alive=" << (m_socket ? "true" : "false")
769  << ">";
770  }
771 
772 #ifdef WITH_DEVICE_TREZOR_WEBUSB
773 
774  static bool is_trezor1(libusb_device_descriptor * info){
775  return info->idVendor == TREZOR_DESC_T1.id_vendor && info->idProduct == TREZOR_DESC_T1.id_product;
776  }
777 
778  static bool is_trezor2(libusb_device_descriptor * info){
779  return info->idVendor == TREZOR_DESC_T2.id_vendor && info->idProduct == TREZOR_DESC_T2.id_product;
780  }
781 
782  static bool is_trezor2_bl(libusb_device_descriptor * info){
783  return info->idVendor == TREZOR_DESC_T2_BL.id_vendor && info->idProduct == TREZOR_DESC_T2_BL.id_product;
784  }
785 
786  static ssize_t get_trezor_dev_id(libusb_device_descriptor *info){
787  CHECK_AND_ASSERT_THROW_MES(info, "Empty device descriptor");
788  return get_device_idx(info->idVendor, info->idProduct);
789  }
790 
791  static void set_libusb_log(libusb_context *ctx){
792  CHECK_AND_ASSERT_THROW_MES(ctx, "Null libusb context");
793 
794  // http://libusb.sourceforge.net/api-1.0/group__libusb__lib.html
795 #if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01000106)
796 # define TREZOR_LIBUSB_SET_DEBUG(ctx, level) libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, level)
797 #else
798 # define TREZOR_LIBUSB_SET_DEBUG(ctx, level) libusb_set_debug(ctx, level)
799 #endif
800 
801  if (ELPP->vRegistry()->allowed(el::Level::Debug, ELECTRONEUM_DEFAULT_LOG_CATEGORY))
802  TREZOR_LIBUSB_SET_DEBUG(ctx, 3);
803  else if (ELPP->vRegistry()->allowed(el::Level::Warning, ELECTRONEUM_DEFAULT_LOG_CATEGORY))
804  TREZOR_LIBUSB_SET_DEBUG(ctx, 2);
805  else if (ELPP->vRegistry()->allowed(el::Level::Error, ELECTRONEUM_DEFAULT_LOG_CATEGORY))
806  TREZOR_LIBUSB_SET_DEBUG(ctx, 1);
807 
808 #undef TREZOR_LIBUSB_SET_DEBUG
809  }
810 
811  static int get_libusb_ports(libusb_device *dev, std::vector<uint8_t> &path){
812  uint8_t tmp_path[16];
813  int r = libusb_get_port_numbers(dev, tmp_path, sizeof(tmp_path));
814  CHECK_AND_ASSERT_MES(r != LIBUSB_ERROR_OVERFLOW, -1, "Libusb path array too small");
815  CHECK_AND_ASSERT_MES(r >= 0, -1, "Libusb path array error");
816 
817  path.resize(r);
818  for (int i = 0; i < r; i++){
819  path[i] = tmp_path[i];
820  }
821 
822  return 0;
823  }
824 
825  static std::string get_usb_path(uint8_t bus_id, const std::vector<uint8_t> &path){
826  std::stringstream ss;
827  ss << WebUsbTransport::PATH_PREFIX << (boost::format("%03d") % ((int)bus_id));
828  for(uint8_t port : path){
829  ss << ":" << ((int) port);
830  }
831  return ss.str();
832  }
833 
834  const char * WebUsbTransport::PATH_PREFIX = "webusb:";
835 
836  WebUsbTransport::WebUsbTransport(
837  boost::optional<libusb_device_descriptor*> descriptor,
838  boost::optional<std::shared_ptr<Protocol>> proto
839  ): m_usb_session(nullptr), m_usb_device(nullptr), m_usb_device_handle(nullptr),
840  m_bus_id(-1), m_device_addr(-1)
841  {
842  if (descriptor){
843  libusb_device_descriptor * desc = new libusb_device_descriptor;
844  memcpy(desc, descriptor.get(), sizeof(libusb_device_descriptor));
845  this->m_usb_device_desc.reset(desc);
846  }
847 
848  m_proto = proto ? proto.get() : std::make_shared<ProtocolV1>();
849 
850 #ifdef WITH_TREZOR_DEBUGGING
851  m_debug_mode = false;
852 #endif
853  }
854 
855  WebUsbTransport::~WebUsbTransport(){
856  if (m_usb_device){
857  close();
858  }
859 
860  if (m_usb_session) {
861  libusb_exit(m_usb_session);
862  m_usb_session = nullptr;
863  }
864  }
865 
866  void WebUsbTransport::require_device() const{
867  if (!m_usb_device_desc){
868  throw std::runtime_error("No USB device specified");
869  }
870  }
871 
872  void WebUsbTransport::require_connected() const{
873  require_device();
874  if (!m_usb_device_handle){
875  throw std::runtime_error("USB Device not opened");
876  }
877  }
878 
880  int r;
881  libusb_device **devs;
882  libusb_context *ctx = nullptr;
883 
884  r = libusb_init(&ctx);
885  CHECK_AND_ASSERT_THROW_MES(r >= 0, "Unable to init libusb");
886 
887  set_libusb_log(ctx);
888 
889  ssize_t cnt = libusb_get_device_list(ctx, &devs);
890  if (cnt < 0){
891  libusb_exit(ctx);
892  throw std::runtime_error("Unable to enumerate libusb devices");
893  }
894 
895  MTRACE("Libusb devices: " << cnt);
896 
897  for(ssize_t i = 0; i < cnt; i++) {
898  libusb_device_descriptor desc{};
899  r = libusb_get_device_descriptor(devs[i], &desc);
900  if (r < 0){
901  MERROR("Unable to get libusb device descriptor " << i);
902  continue;
903  }
904 
905  const auto trezor_dev_idx = get_trezor_dev_id(&desc);
906  if (!is_device_supported(trezor_dev_idx)){
907  continue;
908  }
909 
910  MTRACE("Found Trezor device: " << desc.idVendor << ":" << desc.idProduct << " dev_idx " << (int)trezor_dev_idx);
911 
912  auto t = std::make_shared<WebUsbTransport>(boost::make_optional(&desc));
913  t->m_bus_id = libusb_get_bus_number(devs[i]);
914  t->m_device_addr = libusb_get_device_address(devs[i]);
915 
916  // Port resolution may fail. Non-critical error, just addressing precision is decreased.
917  get_libusb_ports(devs[i], t->m_port_numbers);
918 
919  res.push_back(t);
920  }
921 
922  libusb_free_device_list(devs, 1);
923  libusb_exit(ctx);
924  }
925 
926  std::string WebUsbTransport::get_path() const {
927  if (!m_usb_device_desc){
928  return "";
929  }
930 
931  return get_usb_path(static_cast<uint8_t>(m_bus_id), m_port_numbers);
932  };
933 
934  void WebUsbTransport::open() {
935  if (!pre_open()){
936  return;
937  }
938  const int interface = get_interface();
939 
940 #define TREZOR_DESTROY_SESSION() do { libusb_exit(m_usb_session); m_usb_session = nullptr; } while(0)
941 
942  int r;
943  libusb_device **devs = nullptr;
944 
945  if (m_usb_session) {
946  TREZOR_DESTROY_SESSION();
947  }
948 
949  r = libusb_init(&m_usb_session);
950  CHECK_AND_ASSERT_THROW_MES(r >= 0, "Unable to init libusb");
951  set_libusb_log(m_usb_session);
952 
953  bool found = false;
954  int open_res = 0;
955 
956  ssize_t cnt = libusb_get_device_list(m_usb_session, &devs);
957  if (cnt < 0){
958  TREZOR_DESTROY_SESSION();
959  throw std::runtime_error("Unable to enumerate libusb devices");
960  }
961 
962  for (ssize_t i = 0; i < cnt; i++) {
963  libusb_device_descriptor desc{};
964  r = libusb_get_device_descriptor(devs[i], &desc);
965  if (r < 0){
966  MERROR("Unable to get libusb device descriptor " << i);
967  continue;
968  }
969 
970  const auto trezor_dev_idx = get_trezor_dev_id(&desc);
971  if (!is_device_supported(trezor_dev_idx)){
972  continue;
973  }
974 
975  auto bus_id = libusb_get_bus_number(devs[i]);
976  std::vector<uint8_t> path;
977 
978  // Port resolution may fail. Non-critical error, just addressing precision is decreased.
979  get_libusb_ports(devs[i], path);
980 
981  MTRACE("Found Trezor device: " << desc.idVendor << ":" << desc.idProduct
982  << ", dev_idx: " << (int)trezor_dev_idx
983  << ". path: " << get_usb_path(bus_id, path));
984 
985  if (bus_id == m_bus_id && path == m_port_numbers) {
986  found = true;
987  m_usb_device = devs[i];
988  open_res = libusb_open(m_usb_device, &m_usb_device_handle);
989  break;
990  }
991  }
992 
993  libusb_free_device_list(devs, 1);
994 
995  if (!found){
996  TREZOR_DESTROY_SESSION();
997  throw exc::DeviceAcquireException("Device not found");
998 
999  } else if (found && open_res != 0) {
1000  m_usb_device_handle = nullptr;
1001  m_usb_device = nullptr;
1002  TREZOR_DESTROY_SESSION();
1003  throw exc::DeviceAcquireException("Unable to open libusb device");
1004  }
1005 
1006  r = libusb_claim_interface(m_usb_device_handle, interface);
1007 
1008  if (r != 0){
1009  libusb_close(m_usb_device_handle);
1010  m_usb_device_handle = nullptr;
1011  m_usb_device = nullptr;
1012  TREZOR_DESTROY_SESSION();
1013  throw exc::DeviceAcquireException("Unable to claim libusb device");
1014  }
1015 
1016  m_open_counter = 1;
1017  m_proto->session_begin(*this);
1018 
1019 #undef TREZOR_DESTROY_SESSION
1020  };
1021 
1022  void WebUsbTransport::close() {
1023  if (!pre_close()){
1024  return;
1025  }
1026 
1027  MTRACE("Closing Trezor:WebUsbTransport");
1028  m_proto->session_end(*this);
1029 
1030  int r = libusb_release_interface(m_usb_device_handle, get_interface());
1031  if (r != 0){
1032  MERROR("Could not release libusb interface: " << r);
1033  }
1034 
1035  m_usb_device = nullptr;
1036  if (m_usb_device_handle) {
1037  libusb_close(m_usb_device_handle);
1038  m_usb_device_handle = nullptr;
1039  }
1040 
1041  if (m_usb_session) {
1042  libusb_exit(m_usb_session);
1043  m_usb_session = nullptr;
1044  }
1045  };
1046 
1047  std::shared_ptr<Transport> WebUsbTransport::find_debug() {
1048 #ifdef WITH_TREZOR_DEBUGGING
1049  require_device();
1050  auto t = std::make_shared<WebUsbTransport>(boost::make_optional(m_usb_device_desc.get()));
1051  t->m_bus_id = m_bus_id;
1052  t->m_device_addr = m_device_addr;
1053  t->m_port_numbers = m_port_numbers;
1054  t->m_debug_mode = true;
1055  return t;
1056 #else
1057  MINFO("Debug link is disabled in production");
1058  return nullptr;
1059 #endif
1060  }
1061 
1062  int WebUsbTransport::get_interface() const{
1063  const int INTERFACE_NORMAL = 0;
1064 #ifdef WITH_TREZOR_DEBUGGING
1065  const int INTERFACE_DEBUG = 1;
1066  return m_debug_mode ? INTERFACE_DEBUG : INTERFACE_NORMAL;
1067 #else
1068  return INTERFACE_NORMAL;
1069 #endif
1070  }
1071 
1072  unsigned char WebUsbTransport::get_endpoint() const{
1073  const unsigned char ENDPOINT_NORMAL = 1;
1074 #ifdef WITH_TREZOR_DEBUGGING
1075  const unsigned char ENDPOINT_DEBUG = 2;
1076  return m_debug_mode ? ENDPOINT_DEBUG : ENDPOINT_NORMAL;
1077 #else
1078  return ENDPOINT_NORMAL;
1079 #endif
1080  }
1081 
1082  void WebUsbTransport::write(const google::protobuf::Message &req) {
1083  m_proto->write(*this, req);
1084  };
1085 
1086  void WebUsbTransport::read(std::shared_ptr<google::protobuf::Message> & msg, messages::MessageType * msg_type) {
1087  m_proto->read(*this, msg, msg_type);
1088  };
1089 
1090  void WebUsbTransport::write_chunk(const void * buff, size_t size) {
1091  require_connected();
1092  if (size != REPLEN){
1093  throw exc::CommunicationException("Invalid chunk size: ");
1094  }
1095 
1096  unsigned char endpoint = get_endpoint();
1097  endpoint = (endpoint & ~LIBUSB_ENDPOINT_DIR_MASK) | LIBUSB_ENDPOINT_OUT;
1098 
1099  int transferred = 0;
1100  int r = libusb_interrupt_transfer(m_usb_device_handle, endpoint, (unsigned char*)buff, (int)size, &transferred, 0);
1101  CHECK_AND_ASSERT_THROW_MES(r == 0, "Unable to transfer, r: " << r);
1102  if (transferred != (int)size){
1103  throw exc::CommunicationException("Could not transfer chunk");
1104  }
1105  };
1106 
1107  size_t WebUsbTransport::read_chunk(void * buff, size_t size) {
1108  require_connected();
1109  unsigned char endpoint = get_endpoint();
1110  endpoint = (endpoint & ~LIBUSB_ENDPOINT_DIR_MASK) | LIBUSB_ENDPOINT_IN;
1111 
1112  int transferred = 0;
1113  int r = libusb_interrupt_transfer(m_usb_device_handle, endpoint, (unsigned char*)buff, (int)size, &transferred, 0);
1114  CHECK_AND_ASSERT_THROW_MES(r == 0, "Unable to transfer, r: " << r);
1115  if (transferred != (int)size){
1116  throw exc::CommunicationException("Could not read the chunk");
1117  }
1118 
1119  return transferred;
1120  };
1121 
1122  std::ostream& WebUsbTransport::dump(std::ostream& o) const {
1123  o << "WebUsbTransport<path=" << get_path()
1124  << ", vendorId=" << (m_usb_device_desc ? std::to_string(m_usb_device_desc->idVendor) : "?")
1125  << ", productId=" << (m_usb_device_desc ? std::to_string(m_usb_device_desc->idProduct) : "?")
1126  << ", deviceType=";
1127 
1128  if (m_usb_device_desc){
1129  if (is_trezor1(m_usb_device_desc.get()))
1130  o << "TrezorOne";
1131  else if (is_trezor2(m_usb_device_desc.get()))
1132  o << "TrezorT";
1133  else if (is_trezor2_bl(m_usb_device_desc.get()))
1134  o << "TrezorT BL";
1135  } else {
1136  o << "?";
1137  }
1138 
1139  return o << ">";
1140  };
1141 
1142 #endif // WITH_DEVICE_TREZOR_WEBUSB
1143 
1145  BridgeTransport bt;
1146  try{
1147  bt.enumerate(res);
1148  } catch (const std::exception & e){
1149  MERROR("BridgeTransport enumeration failed:" << e.what());
1150  }
1151 
1152 #ifdef WITH_DEVICE_TREZOR_WEBUSB
1153  hw::trezor::WebUsbTransport btw;
1154  try{
1155  btw.enumerate(res);
1156  } catch (const std::exception & e){
1157  MERROR("WebUsbTransport enumeration failed:" << e.what());
1158  }
1159 #endif
1160 
1161 #ifdef WITH_DEVICE_TREZOR_UDP
1163  try{
1164  btu.enumerate(res);
1165  } catch (const std::exception & e){
1166  MERROR("UdpTransport enumeration failed:" << e.what());
1167  }
1168 #endif
1169  }
1170 
1172  const char *env_trezor_path = getenv("TREZOR_PATH");
1173  if (!env_trezor_path){
1174  return;
1175  }
1176 
1177  // Sort transports by the longest matching prefix with TREZOR_PATH
1178  std::string trezor_path(env_trezor_path);
1179  std::vector<size_t> match_idx(res.size());
1180  std::vector<size_t> path_permutation(res.size());
1181 
1182  for(size_t i = 0; i < res.size(); ++i){
1183  auto cpath = res[i]->get_path();
1184  std::string * s1 = &trezor_path;
1185  std::string * s2 = &cpath;
1186 
1187  // first has to be shorter in std::mismatch(). Returns first non-matching iterators.
1188  if (s1->size() >= s2->size()){
1189  std::swap(s1, s2);
1190  }
1191 
1192  const auto mism = std::mismatch(s1->begin(), s1->end(), s2->begin());
1193  match_idx[i] = mism.first - s1->begin();
1194  path_permutation[i] = i;
1195  }
1196 
1197  std::sort(path_permutation.begin(), path_permutation.end(), [&](const size_t i0, const size_t i1) {
1198  return match_idx[i0] > match_idx[i1];
1199  });
1200 
1201  tools::apply_permutation(path_permutation, res);
1202  }
1203 
1204  std::shared_ptr<Transport> transport(const std::string & path){
1205  if (boost::starts_with(path, BridgeTransport::PATH_PREFIX)){
1206  return std::make_shared<BridgeTransport>(path.substr(strlen(BridgeTransport::PATH_PREFIX)));
1207 
1208  } else if (boost::starts_with(path, UdpTransport::PATH_PREFIX)){
1209  return std::make_shared<UdpTransport>(path.substr(strlen(UdpTransport::PATH_PREFIX)));
1210 
1211  } else {
1212  throw std::invalid_argument("Unknown Trezor device path: " + path);
1213 
1214  }
1215  }
1216 
1217  void throw_failure_exception(const messages::common::Failure * failure) {
1218  if (failure == nullptr){
1219  throw std::invalid_argument("Failure message cannot be null");
1220  }
1221 
1222  boost::optional<std::string> message = failure->has_message() ? boost::make_optional(failure->message()) : boost::none;
1223  boost::optional<uint32_t> code = failure->has_code() ? boost::make_optional(static_cast<uint32_t>(failure->code())) : boost::none;
1224  if (!code){
1226  }
1227 
1228  auto ecode = failure->code();
1229  if (ecode == messages::common::Failure_FailureType_Failure_UnexpectedMessage){
1231  } else if (ecode == messages::common::Failure_FailureType_Failure_ActionCancelled){
1233  } else if (ecode == messages::common::Failure_FailureType_Failure_PinExpected){
1235  } else if (ecode == messages::common::Failure_FailureType_Failure_PinInvalid){
1237  } else if (ecode == messages::common::Failure_FailureType_Failure_NotEnoughFunds){
1239  } else if (ecode == messages::common::Failure_FailureType_Failure_NotInitialized){
1241  } else if (ecode == messages::common::Failure_FailureType_Failure_FirmwareError){
1243  } else {
1245  }
1246  }
1247 
1248  GenericMessage::GenericMessage(messages::MessageType m_type, const shared_ptr<google::protobuf::Message> &m_msg)
1249  : m_type(m_type), m_msg(m_msg), m_empty(false) {}
1250 
1251  std::ostream& operator<<(std::ostream& o, hw::trezor::Transport const& t){
1252  return t.dump(o);
1253  }
1254 
1255  std::ostream& operator<<(std::ostream& o, std::shared_ptr<hw::trezor::Transport> const& t){
1256  if (!t){
1257  return o << "None";
1258  }
1259 
1260  return t->dump(o);
1261  }
1262 
1263 }
1264 }
1265 
virtual bool pre_open()
Definition: transport.cpp:279
const char * res
Definition: hmac_keccak.cpp:41
#define MERROR(x)
Definition: misc_log_ex.h:73
bool ping() override
Definition: transport.cpp:546
const std::string DEFAULT_BRIDGE
Definition: transport.hpp:63
#define CHECK_AND_ASSERT_THROW_MES(expr, message)
Definition: misc_log_ex.h:173
bool set_server(const std::string &address, boost::optional< login > user, ssl_options_t ssl_options=ssl_support_t::e_ssl_support_autodetect)
Definition: http_client.h:302
void enumerate(t_transport_vect &res)
Definition: transport.cpp:1144
void open() override
Definition: transport.cpp:582
void read(std::shared_ptr< google::protobuf::Message > &msg, messages::MessageType *msg_type=nullptr) override
Definition: transport.cpp:448
void read(std::shared_ptr< google::protobuf::Message > &msg, messages::MessageType *msg_type=nullptr) override
Definition: transport.cpp:729
rapidjson::Value json_val
Definition: transport.hpp:60
#define MTRACE(x)
Definition: misc_log_ex.h:77
#define MINFO(x)
Definition: misc_log_ex.h:75
void apply_permutation(std::vector< size_t > permutation, const F &swap)
Information representing errors in application but application will keep running. ...
rapidjson::Document json
Definition: transport.hpp:59
bool t_serialize(const std::string &in, std::string &out)
Definition: transport.cpp:55
::std::string string
Definition: gtest-port.h:1097
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
Definition: misc_log_ex.h:181
#define ELPP
Informational events most useful for developers to debug application.
Represents a JSON value. Use Value for UTF8 encoding and default allocator.
Definition: document.h:57
std::unique_ptr< void, close > socket
Unique ZMQ socket handle, calls zmq_close on destruction.
Definition: zmq.h:101
STL namespace.
unsigned short uint16_t
Definition: stdint.h:125
unsigned char uint8_t
Definition: stdint.h:124
#define ELECTRONEUM_DEFAULT_LOG_CATEGORY
Definition: transport.cpp:46
#define MDEBUG(x)
Definition: misc_log_ex.h:76
const boost::optional< json > & device_info() const
Definition: transport.cpp:476
void close() override
Definition: transport.cpp:601
static const char * PATH_PREFIX
Definition: transport.hpp:170
GenericValue< UTF8<> > Value
GenericValue with UTF8 encoding.
Definition: document.h:2116
unsigned int uint32_t
Definition: stdint.h:126
std::ostream & dump(std::ostream &o) const override
Definition: transport.cpp:480
size_t read_chunk(void *buff, size_t size) override
Definition: transport.cpp:642
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:77
unsigned __int64 uint64_t
Definition: stdint.h:136
GenericDocument< UTF8<> > Document
GenericDocument with UTF8 encoding.
Definition: document.h:2512
Definition: device.cpp:38
void enumerate(t_transport_vect &res) override
Definition: transport.cpp:347
::google::protobuf::Message * get_message(int wire_number)
#define false
Definition: stdbool.h:38
GenericStringBuffer< UTF8< char >, CrtAllocator > StringBuffer
Definition: fwd.h:59
void throw_failure_exception(const messages::common::Failure *failure)
Definition: transport.cpp:1217
void sort_transports_by_env(t_transport_vect &res)
Definition: transport.cpp:1171
Useful when application has potentially harmful situtaions.
#define MWARNING(x)
Definition: misc_log_ex.h:74
void write_chunk(const void *buff, size_t size) override
Definition: transport.cpp:629
virtual std::ostream & dump(std::ostream &o) const
Definition: transport.hpp:153
std::string message("Message requiring signing")
boost::endian::big_uint16_t port
Definition: socks.cpp:60
uint64_t pack_version(uint32_t major, uint32_t minor, uint32_t patch)
Definition: transport.cpp:90
CXA_THROW_INFO_T * info
Definition: stack_trace.cpp:91
bool t_deserialize(const std::string &in, json &out)
Definition: transport.cpp:79
virtual bool pre_close()
Definition: transport.cpp:295
std::string get_path() const override
Definition: transport.cpp:535
std::shared_ptr< Transport > find_debug() override
Definition: transport.cpp:616
void write(const google::protobuf::Message &req) override
Definition: transport.cpp:425
void enumerate(t_transport_vect &res) override
Definition: transport.cpp:566
void * memcpy(void *a, const void *b, size_t c)
void write(const google::protobuf::Message &req) override
Definition: transport.cpp:725
BridgeTransport(boost::optional< std::string > device_path=boost::none, boost::optional< std::string > bridge_host=boost::none)
Definition: transport.cpp:315
std::string t_serialize(const json_val &in)
Definition: transport.cpp:68
static std::string string(const span< const std::uint8_t > src)
Definition: hex.cpp:68
#define PROTO_HEADER_SIZE
Definition: transport.cpp:146
static const int DEFAULT_PORT
Definition: transport.hpp:207
#define REPLEN
Definition: transport.cpp:190
std::ostream & operator<<(std::ostream &o, std::shared_ptr< hw::trezor::Transport > const &t)
Definition: transport.cpp:1255
std::ostream & dump(std::ostream &o) const override
Definition: transport.cpp:766
std::string to_string(t_connection_type type)
std::vector< std::shared_ptr< Transport > > t_transport_vect
Definition: transport.hpp:135
static const char * PATH_PREFIX
Definition: transport.hpp:205
PUSH_WARNINGS bool get_xtype_from_string(OUT XType &val, const std::string &str_id)
Definition: string_tools.h:125
void get(std::istream &input, bool &res)
Definition: io.h:62
std::string get_path() const override
Definition: transport.cpp:338
static const char * DEFAULT_HOST
Definition: transport.hpp:206
bool parse_hexstr_to_binbuff(const epee::span< const char > s, epee::span< char > &res)
Definition: string_tools.h:92
std::shared_ptr< Transport > transport(const std::string &path)
Definition: transport.cpp:1204
rapidjson::Document json
Definition: transport.cpp:49
UdpTransport(boost::optional< std::string > device_path=boost::none, boost::optional< std::shared_ptr< Protocol >> proto=boost::none)
Definition: transport.cpp:510