Aktualizr
C++ SOTA Client
common.cc
1 #include "configuration.h"
2 #include "currenttime.h"
3 #include "ecuversionmanifest.h"
4 #include "ecuversionmanifestsigned.h"
5 #include "filedata.h"
6 #include "filelist.h"
7 #include "hash.h"
8 #include "image.h"
9 #include "imageblock.h"
10 #include "imagefile.h"
11 #include "imagerequest.h"
12 #include "metadatafile.h"
13 #include "metadatafiles.h"
14 #include "originalmanifest.h"
15 #include "signature.h"
16 #include "signed.h"
17 #include "versionreport.h"
18 
19 #include "logging/logging.h"
20 
21 #include <boost/filesystem.hpp>
22 #include <boost/iostreams/device/mapped_file.hpp>
23 
24 #include <fstream>
25 
26 namespace fs = boost::filesystem;
27 
28 namespace opcuabridge {
29 const UA_UInt16 kNSindex = 1;
30 const char *kLocale = "en-US";
31 
32 const char *VersionReport::node_id_ = "VersionReport";
33 const char *Configuration::node_id_ = "Configuration";
34 const char *CurrentTime::node_id_ = "CurrentTime";
35 const char *MetadataFiles::node_id_ = "MetadataFiles";
36 const char *MetadataFile::node_id_ = "MetadataFile";
37 const char *MetadataFile::bin_node_id_ = "MetadataFile_BinaryData";
38 const char *ImageRequest::node_id_ = "ImageRequest";
39 const char *ImageFile::node_id_ = "ImageFile";
40 const char *ImageBlock::node_id_ = "ImageBlock";
41 const char *ImageBlock::bin_node_id_ = "ImageBlock_BinaryData";
42 const char *FileData::node_id_ = "FileData";
43 const char *FileData::bin_node_id_ = "FileData_BinaryData";
44 const char *FileList::node_id_ = "FileList";
45 const char *FileList::bin_node_id_ = "FileList_BinaryData";
46 const char *OriginalManifest::node_id_ = "OriginalManifest";
47 const char *OriginalManifest::bin_node_id_ = "OriginalManifest_BinaryData";
48 } // namespace opcuabridge
49 
50 namespace opcuabridge {
51 
52 const std::size_t kLogMsgBuffSize = 256;
53 
54 void BoostLogOpcua(UA_LogLevel level, UA_LogCategory category, const char *msg, va_list args) {
55  char msg_buff[kLogMsgBuffSize];
56  vsnprintf(msg_buff, kLogMsgBuffSize, msg, args);
57  BOOST_LOG_STREAM_WITH_PARAMS(
58  boost::log::trivial::logger::get(),
59  (boost::log::keywords::severity = static_cast<boost::log::trivial::severity_level>(level)))
60  << "OPC-UA " << msg_buff;
61 }
62 
63 template <>
64 UA_StatusCode read<MessageBinaryData>(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
65  const UA_NodeId *nodeId, void *nodeContext, UA_Boolean sourceTimeStamp,
66  const UA_NumericRange *range, UA_DataValue *dataValue) {
67  const BinaryDataType &bin_data = *static_cast<BinaryDataType *>(nodeContext);
68 
69  UA_Variant_setArrayCopy(&dataValue->value, &bin_data[0], bin_data.size(), &UA_TYPES[UA_TYPES_BYTE]);
70  dataValue->hasValue = !bin_data.empty();
71 
72  return UA_STATUSCODE_GOOD;
73 }
74 
75 template <>
76 UA_StatusCode write<MessageBinaryData>(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
77  const UA_NodeId *nodeId, void *nodeContext, const UA_NumericRange *range,
78  const UA_DataValue *data) {
79  if (!UA_Variant_isEmpty(&data->value) && UA_Variant_hasArrayType(&data->value, &UA_TYPES[UA_TYPES_BYTE])) {
80  auto *bin_data = static_cast<BinaryDataType *>(nodeContext);
81  bin_data->resize(data->value.arrayLength);
82  const auto *src = static_cast<const unsigned char *>(data->value.data);
83  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
84  std::copy(src, src + data->value.arrayLength, bin_data->begin());
85  }
86  return UA_STATUSCODE_GOOD;
87 }
88 
89 template <>
90 UA_StatusCode read<MessageFileData>(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
91  const UA_NodeId *nodeId, void *nodeContext, UA_Boolean sourceTimeStamp,
92  const UA_NumericRange *range, UA_DataValue *dataValue) {
93  return UA_STATUSCODE_GOOD;
94 }
95 
96 template <>
97 UA_StatusCode write<MessageFileData>(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
98  const UA_NodeId *nodeId, void *nodeContext, const UA_NumericRange *range,
99  const UA_DataValue *data) {
100  if (!UA_Variant_isEmpty(&data->value) && UA_Variant_hasArrayType(&data->value, &UA_TYPES[UA_TYPES_BYTE])) {
101  auto *mfd = static_cast<MessageFileData *>(nodeContext);
102 
103  fs::path full_file_path = mfd->getFullFilePath();
104  if (!fs::exists(full_file_path)) {
105  fs::create_directories(full_file_path.parent_path());
106  }
107  std::ofstream ofs(full_file_path.c_str(), std::ios::binary | std::ios::app);
108  if (ofs) {
109  ofs.write(static_cast<const char *>(data->value.data), static_cast<long>(data->value.arrayLength));
110  if (!ofs) {
111  LOG_ERROR << "File write error: " << full_file_path.native();
112  }
113  } else {
114  LOG_ERROR << "File open error: " << full_file_path.native();
115  }
116  }
117  return UA_STATUSCODE_GOOD;
118 }
119 
120 namespace internal {
121 
122 UA_StatusCode ClientWriteFile(UA_Client *client, const char *node_id, const boost::filesystem::path &file_path,
123  const std::size_t block_size) {
124  UA_StatusCode retval;
125 
126  boost::iostreams::mapped_file_source file(file_path.native());
127  boost::iostreams::mapped_file_source::iterator f_it = file.begin();
128 
129  const std::size_t total_size = file.size();
130  std::size_t written_size = 0;
131  UA_Variant *val = UA_Variant_new();
132  while (f_it != file.end()) {
133  std::size_t current_block_size = std::min(block_size, (total_size - written_size));
134  UA_Variant_setArray(val, const_cast<char *>(&(*f_it)), current_block_size, &UA_TYPES[UA_TYPES_BYTE]);
135  val->storageType = UA_VARIANT_DATA_NODELETE;
136  retval = UA_Client_writeValueAttribute(client, UA_NODEID_STRING(kNSindex, const_cast<char *>(node_id)), val);
137  if (retval != UA_STATUSCODE_GOOD) {
138  return retval;
139  }
140  std::advance(f_it, current_block_size);
141  written_size += current_block_size;
142  }
143  UA_Variant_delete(val);
144 
145  return UA_STATUSCODE_GOOD;
146 }
147 
148 /**
149  * Workaround for cppcoreguidelines-pro-bounds-pointer-arithmetic
150  * TODO: Replace with something that is memory-safe
151  */
152 void parseJson(const char *msg, size_t len, Json::Value *value) {
153  Json::Reader rd;
154  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
155  rd.parse(msg, msg + len, *value);
156 }
157 
158 } // namespace internal
159 
160 } // namespace opcuabridge
General data structures.
Definition: types.cc:6