Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
asn1_message.cc
1 #include <arpa/inet.h>
2 #include <netinet/tcp.h>
3 #include <sys/socket.h>
4 #include <sys/types.h>
5 
6 #include "asn1_message.h"
7 #include "logging/logging.h"
8 #include "utilities/dequeue_buffer.h"
9 #include "utilities/utils.h"
10 
11 #ifndef MSG_NOSIGNAL
12 #define MSG_NOSIGNAL 0
13 #endif
14 
15 int Asn1StringAppendCallback(const void* buffer, size_t size, void* priv) {
16  auto* out_str = static_cast<std::string*>(priv);
17  out_str->append(std::string(static_cast<const char*>(buffer), size));
18  return 0;
19 }
20 
21 /**
22  * Adaptor to write output of der_encode to a socket
23  * priv is a SocketHandle
24  */
25 int Asn1SocketWriteCallback(const void* buffer, size_t size, void* priv) {
26  auto sock = reinterpret_cast<int*>(priv); // NOLINT
27  assert(sock != nullptr);
28  assert(-1 < *sock);
29 
30  const auto* b = static_cast<const char*>(buffer);
31  size_t len = size;
32  size_t pos = 0;
33 
34  while (len > 0) {
35  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
36  ssize_t written = send(*sock, b + pos, len, MSG_NOSIGNAL);
37  if (written < 0) {
38  LOG_ERROR << "write: " << std::strerror(errno);
39  return 1;
40  }
41  len -= static_cast<size_t>(written);
42  pos += static_cast<size_t>(written);
43  }
44  return 0;
45 }
46 
47 std::string ToString(const OCTET_STRING_t& octet_str) {
48  return std::string(reinterpret_cast<const char*>(octet_str.buf), static_cast<size_t>(octet_str.size));
49 }
50 
51 void SetString(OCTET_STRING_t* dest, const std::string& str) {
52  OCTET_STRING_fromBuf(dest, str.c_str(), static_cast<int>(str.size()));
53 }
54 
55 Asn1Message::Ptr Asn1Rpc(const Asn1Message::Ptr& tx, int con_fd) {
56  der_encode(&asn_DEF_AKIpUptaneMes, &tx->msg_, Asn1SocketWriteCallback, &con_fd);
57 
58  // Bounce TCP_NODELAY to flush the TCP send buffer
59  int no_delay = 1;
60  setsockopt(con_fd, IPPROTO_TCP, TCP_NODELAY, &no_delay, sizeof(int));
61  no_delay = 0;
62  setsockopt(con_fd, IPPROTO_TCP, TCP_NODELAY, &no_delay, sizeof(int));
63 
64  AKIpUptaneMes_t* m = nullptr;
65  asn_dec_rval_t res;
66  asn_codec_ctx_s context{};
67  DequeueBuffer buffer;
68  ssize_t received;
69  do {
70  res.code = RC_FAIL;
71  received = recv(con_fd, buffer.Tail(), buffer.TailSpace(), 0);
72  if (received < 0) {
73  LOG_ERROR << "Failed to read data from a coonnection socket: " << strerror(errno);
74  break;
75  }
76  LOG_TRACE << "Asn1Rpc read " << Utils::toBase64(std::string(buffer.Tail(), static_cast<size_t>(received)));
77  buffer.HaveEnqueued(static_cast<size_t>(received));
78  res = ber_decode(&context, &asn_DEF_AKIpUptaneMes, reinterpret_cast<void**>(&m), buffer.Head(), buffer.Size());
79  buffer.Consume(res.consumed);
80  } while (res.code == RC_WMORE && received > 0);
81  // Note that ber_decode allocates *m even on failure, so this must always be done
82  Asn1Message::Ptr msg = Asn1Message::FromRaw(&m);
83 
84  if (res.code != RC_OK) {
85  LOG_DEBUG << "Asn1Rpc decoding failed";
86  msg->present(AKIpUptaneMes_PR_NOTHING);
87  }
88 
89  return msg;
90 }
91 
92 Asn1Message::Ptr Asn1Rpc(const Asn1Message::Ptr& tx, const std::pair<std::string, uint16_t>& addr) {
93  ConnectionSocket connection(addr.first, addr.second);
94 
95  if (connection.connect() < 0) {
96  LOG_ERROR << "Failed to connect to the Secondary ( " << addr.first << ":" << addr.second
97  << "): " << std::strerror(errno);
98  return Asn1Message::Empty();
99  }
100  return Asn1Rpc(tx, *connection);
101 }
Asn1Message::Empty
static Asn1Message::Ptr Empty()
Create a new Asn1Message, in order to fill it with data and send it.
Definition: asn1_message.h:46
DequeueBuffer::Tail
char * Tail()
A pointer to the next place to write data to.
Definition: dequeue_buffer.cc:32
DequeueBuffer::Consume
void Consume(size_t bytes)
Called after bytes have been read from Head().
Definition: dequeue_buffer.cc:16
ConnectionSocket
Definition: utils.h:124
DequeueBuffer::Size
size_t Size() const
The number of elements that are valid (have been written) after Head()
Definition: dequeue_buffer.cc:11
DequeueBuffer::TailSpace
size_t TailSpace()
The number of bytes beyond Tail() that are allocated and may be written to.
Definition: dequeue_buffer.cc:38
Asn1Message::FromRaw
static Asn1Message::Ptr FromRaw(AKIpUptaneMes_t **msg)
Destructively copy from a raw msg pointer created by parsing an incomming message.
Definition: asn1_message.h:53
DequeueBuffer
A dequeue based on a contiguous buffer in memory.
Definition: dequeue_buffer.h:11
DequeueBuffer::Head
char * Head()
A pointer to the first element that has not been Consumed().
Definition: dequeue_buffer.cc:6
DequeueBuffer::HaveEnqueued
void HaveEnqueued(size_t bytes)
Call to indicate that bytes have been written in the range Tail() ...
Definition: dequeue_buffer.cc:43