Goby3  3.1.4
2024.02.22
dccl.h
Go to the documentation of this file.
1 // Copyright 2009-2023:
2 // GobySoft, LLC (2013-)
3 // Massachusetts Institute of Technology (2007-2014)
4 // Community contributors (see AUTHORS file)
5 // File authors:
6 // Toby Schneider <toby@gobysoft.org>
7 //
8 //
9 // This file is part of the Goby Underwater Autonomy Project Libraries
10 // ("The Goby Libraries").
11 //
12 // The Goby Libraries are free software: you can redistribute them and/or modify
13 // them under the terms of the GNU Lesser General Public License as published by
14 // the Free Software Foundation, either version 2.1 of the License, or
15 // (at your option) any later version.
16 //
17 // The Goby Libraries are distributed in the hope that they will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU Lesser General Public License for more details.
21 //
22 // You should have received a copy of the GNU Lesser General Public License
23 // along with Goby. If not, see <http://www.gnu.org/licenses/>.
24 
25 #ifndef GOBY_ACOMMS_DCCL_DCCL_H
26 #define GOBY_ACOMMS_DCCL_DCCL_H
27 
28 #include <list> // for list
29 #include <memory> // for shared_ptr
30 #include <ostream> // for endl, ostream
31 #include <set> // for set
32 #include <string> // for string, oper...
33 
34 #include <dccl/bitset.h> // for Bitset
35 #include <dccl/codecs2/field_codec_default_message.h> // for DefaultMessa...
36 #include <dccl/common.h> // for int64, uint64
37 #include <dccl/exception.h> // for Exception
38 #include <dccl/field_codec.h> // for FieldCodecBase
39 #include <dccl/field_codec_fixed.h> // for TypedFixedFi...
40 #include <dccl/field_codec_manager.h> // for FieldCodecMa...
41 #include <dccl/field_codec_typed.h> // for RepeatedType...
42 #include <dccl/logger.h> // for DECODE, ENCODE
43 #include <dccl/option_extensions.pb.h> // for DCCLMessageO...
44 #include <google/protobuf/descriptor.h> // for Descriptor
45 #include <google/protobuf/descriptor.pb.h> // for MessageOptions
46 
47 #include "dccl/codec.h" // for Codec
48 #include "dccl/codecs2/field_codec_default.h" // for DefaultBoolC...
49 #include "dccl/field_codec_id.h" // for DefaultIdent...
50 #include "goby/acomms/protobuf/dccl.pb.h" // for DCCLConfig
51 #include "goby/util/binary.h" // for hex_encode
52 #include "goby/util/debug_logger/flex_ostream.h" // for operator<<
53 #include "goby/util/debug_logger/flex_ostreambuf.h" // for WARN, DEBUG1
54 #include "goby/util/debug_logger/logger_manipulators.h" // for operator<<
55 #include "goby/util/dccl_compat.h"
56 
57 namespace google
58 {
59 namespace protobuf
60 {
61 class Message;
62 } // namespace protobuf
63 } // namespace google
64 
65 namespace goby
66 {
67 namespace acomms
68 {
69 typedef dccl::Exception DCCLException;
70 using DCCLNullValueException = dccl::NullValueException;
71 
72 using DCCLDefaultIdentifierCodec = dccl::DefaultIdentifierCodec;
73 template <typename WireType, typename FieldType = WireType>
75 {
76 };
77 
78 using DCCLDefaultBoolCodec = dccl::v2::DefaultBoolCodec;
79 using DCCLDefaultStringCodec = dccl::v2::DefaultStringCodec;
80 using DCCLDefaultBytesCodec = dccl::v2::DefaultBytesCodec;
81 using DCCLDefaultEnumCodec = dccl::v2::DefaultEnumCodec;
82 
83 template <typename TimeType> class TimeCodec : public dccl::v2::TimeCodecBase<TimeType, 0>
84 {
85  static_assert(sizeof(TimeCodec) == 0, "TimeCodec must be specialized");
86 };
87 
88 template <> class TimeCodec<dccl::uint64> : public dccl::v2::TimeCodecBase<dccl::uint64, 1000000>
89 {
90 };
91 template <> class TimeCodec<dccl::int64> : public dccl::v2::TimeCodecBase<dccl::int64, 1000000>
92 {
93 };
94 template <> class TimeCodec<double> : public dccl::v2::TimeCodecBase<double, 1>
95 {
96 };
97 
98 template <typename T> class StaticCodec : public dccl::v2::StaticCodec<T>
99 {
100 };
101 
102 using DCCLDefaultMessageCodec = dccl::v2::DefaultMessageCodec;
103 
104 using DCCLFieldCodecBase = dccl::FieldCodecBase;
105 
106 template <typename WireType, typename FieldType = WireType>
107 struct DCCLTypedFieldCodec : public dccl::TypedFieldCodec<WireType, FieldType>
108 {
109  using DCCLFieldCodecBase = dccl::FieldCodecBase;
110 };
111 
112 template <typename WireType, typename FieldType = WireType>
113 struct DCCLTypedFixedFieldCodec : public dccl::TypedFixedFieldCodec<WireType, FieldType>
114 {
115  using DCCLFieldCodecBase = dccl::FieldCodecBase;
116 };
117 
118 template <typename WireType, typename FieldType = WireType>
119 struct DCCLRepeatedTypedFieldCodec : public dccl::RepeatedTypedFieldCodec<WireType, FieldType>
120 {
121  using DCCLFieldCodecBase = dccl::FieldCodecBase;
122 };
123 
124 using DCCLFieldCodecManager = dccl::FieldCodecManager;
125 using DCCLFieldCodecManager = dccl::FieldCodecManager;
127 
129 {
130  public:
132  static DCCLCodec* get()
133  {
134  static DCCLCodec d;
135  return &d;
136  }
137 
139  std::shared_ptr<dccl::Codec> codec() { return codec_; }
140 
141  void set_cfg(const protobuf::DCCLConfig& cfg)
142  {
143  cfg_.CopyFrom(cfg);
144  process_cfg(true);
145  }
146 
148  {
149  bool new_id_codec = (cfg_.id_codec() != cfg.id_codec());
150  cfg_.MergeFrom(cfg);
151  process_cfg(new_id_codec);
152  }
153 
154  void load_shared_library_codecs(void* dl_handle)
155  {
156  codec_->load_library(dl_handle);
157  loaded_libs_.insert(dl_handle);
158  }
159 
160  template <typename ProtobufMessage> void validate() { validate(ProtobufMessage::descriptor()); }
161 
162  template <typename ProtobufMessage> void info(std::ostream* os) const
163  {
164  info(ProtobufMessage::descriptor(), os);
165  }
166 
167  void info_all(std::ostream* os) const { codec_->info_all(os); }
168 
169  template <typename ProtobufMessage> unsigned id() const
170  {
171  return id(ProtobufMessage::descriptor());
172  }
173 
174  unsigned size(const google::protobuf::Message& msg) { return codec_->size(msg); }
175 
176  static const std::string& glog_encode_group() { return glog_encode_group_; }
177  static const std::string& glog_decode_group() { return glog_decode_group_; }
178 
179  void encode(std::string* bytes, const google::protobuf::Message& msg, bool header_only = false)
180  {
181  bytes->clear();
182  codec_->encode(bytes, msg, header_only);
183  }
184 
185  void decode(const std::string& bytes, google::protobuf::Message* msg, bool header_only = false)
186  {
187  codec_->decode(bytes, msg, header_only);
188  }
189 
190  unsigned id_from_encoded(const std::string& bytes) { return codec_->id(bytes); }
191 
192  void validate(const google::protobuf::Descriptor* desc)
193  {
194  codec_->load(desc);
195  loaded_msgs_.insert(desc);
196  }
197 
198  void validate_repeated(const std::list<const google::protobuf::Descriptor*>& descs)
199  {
200  for (const google::protobuf::Descriptor* p : descs) validate(p);
201  }
202 
203  void info(const google::protobuf::Descriptor* desc, std::ostream* os) const
204  {
205  codec_->info(desc, os);
206  }
207 
208  void info_repeated(const std::list<const google::protobuf::Descriptor*>& desc,
209  std::ostream* os) const
210  {
211  for (const google::protobuf::Descriptor* p : desc) info(p, os);
212  }
213 
214  unsigned id(const google::protobuf::Descriptor* desc) const
215  {
216  return desc->options().GetExtension(dccl::msg).id();
217  }
218 
219  template <typename GoogleProtobufMessagePointer>
220  unsigned size_repeated(const std::list<GoogleProtobufMessagePointer>& msgs)
221  {
222  unsigned out = 0;
223  for (const GoogleProtobufMessagePointer& msg : msgs) out += size(*msg);
224  return out;
225  }
226 
227  template <typename GoogleProtobufMessagePointer>
228  GoogleProtobufMessagePointer decode(const std::string& bytes, bool header_only = false)
229  {
230  return codec_->decode<GoogleProtobufMessagePointer>(bytes, header_only);
231  }
232 
233  template <typename GoogleProtobufMessagePointer>
234  std::string encode_repeated(const std::list<GoogleProtobufMessagePointer>& msgs)
235  {
236  std::string out;
237  for (const GoogleProtobufMessagePointer& msg : msgs)
238  {
239  std::string piece;
240  encode(&piece, *msg);
241  out += piece;
242  }
243 
244  return out;
245  }
246 
247  template <typename GoogleProtobufMessagePointer>
248  std::list<GoogleProtobufMessagePointer> decode_repeated(const std::string& orig_bytes)
249  {
250  std::string bytes = orig_bytes;
251  std::list<GoogleProtobufMessagePointer> out;
252  while (!bytes.empty())
253  {
254  try
255  {
256  out.push_back(decode<GoogleProtobufMessagePointer>(bytes));
257  unsigned last_size = size(*out.back());
258  glog.is(util::logger::DEBUG1) && glog << "last message size was: " << last_size
259  << std::endl;
260  bytes.erase(0, last_size);
261  }
262  catch (dccl::Exception& e)
263  {
264  if (out.empty())
265  throw(e);
266  else
267  {
269  glog << "failed to decode " << goby::util::hex_encode(bytes)
270  << " but returning parts already decoded" << std::endl;
271  return out;
272  }
273  }
274  }
275  return out;
276  }
277 
278  template <typename DCCLTypedFieldCodecUint32> void add_id_codec(const std::string& identifier)
279  {
280 #ifdef DCCL_VERSION_4_1_OR_NEWER
281  codec()->manager().add<DCCLTypedFieldCodecUint32>(identifier);
282 #else
283  dccl::FieldCodecManager::add<DCCLTypedFieldCodecUint32>(identifier);
284 #endif
285  }
286 
287  void set_id_codec(const std::string& identifier)
288  {
289  codec_.reset(new dccl::Codec(identifier));
290 
291  for (auto loaded_lib : loaded_libs_) load_shared_library_codecs(loaded_lib);
292 
293  for (auto loaded_msg : loaded_msgs_)
294  {
295  try
296  {
297  validate(loaded_msg);
298  }
299  catch (dccl::Exception& e)
300  {
302  glog << "Failed to reload " << loaded_msg->full_name()
303  << " after ID codec change: " << e.what() << std::endl;
304  }
305  }
306  }
307 
308  void reset_id_codec() { set_id_codec(dccl::Codec::default_id_codec_name()); }
309 
311 
312  private:
313  DCCLCodec();
314 
315  ~DCCLCodec() = default;
316  DCCLCodec(const DCCLCodec&) = delete;
317  DCCLCodec& operator=(const DCCLCodec&) = delete;
318 
319  void process_cfg(bool new_id_codec)
320  {
321  if (cfg_.has_crypto_passphrase())
322  {
323  std::set<unsigned> skip_crypto_ids;
324  for (int i = 0, n = cfg_.skip_crypto_for_id_size(); i < n; ++i)
325  skip_crypto_ids.insert(cfg_.skip_crypto_for_id(i));
326  codec_->set_crypto_passphrase(cfg_.crypto_passphrase(), skip_crypto_ids);
327  }
328 
329  if (new_id_codec && cfg_.has_id_codec())
330  {
331  set_id_codec(cfg_.id_codec());
332  }
333  }
334 
335  void dlog_message(const std::string& msg, dccl::logger::Verbosity vrb, dccl::logger::Group grp)
336  {
337  std::string glog_group =
338  (grp == dccl::logger::DECODE) ? glog_decode_group_ : glog_encode_group_;
339  std::string prefix = (grp == dccl::logger::SIZE) ? " {size} " : "";
340  auto glog_vrb = goby::util::logger::VERBOSE;
341  switch (vrb)
342  {
343  case dccl::logger::WARN_PLUS:
344  case dccl::logger::WARN: glog_vrb = goby::util::logger::WARN; break;
345  default:
346  case dccl::logger::INFO_PLUS:
347  case dccl::logger::INFO: glog_vrb = goby::util::logger::VERBOSE; break;
348  case dccl::logger::DEBUG1_PLUS:
349  case dccl::logger::DEBUG1: glog_vrb = goby::util::logger::DEBUG1; break;
350  case dccl::logger::DEBUG2_PLUS:
351  case dccl::logger::DEBUG2: glog_vrb = goby::util::logger::DEBUG2; break;
352  case dccl::logger::DEBUG3_PLUS:
353  case dccl::logger::DEBUG3: glog_vrb = goby::util::logger::DEBUG3; break;
354  }
355 
356  goby::glog.is(glog_vrb) && goby::glog << group(glog_group) << prefix << msg << std::endl;
357  }
358 
359  private:
360  static std::string glog_encode_group_;
361  static std::string glog_decode_group_;
362 
363  protobuf::DCCLConfig cfg_;
364 
365  std::shared_ptr<dccl::Codec> codec_;
366 
367  std::set<void*> loaded_libs_;
368  std::set<const google::protobuf::Descriptor*> loaded_msgs_;
369 };
370 
371 inline std::ostream& operator<<(std::ostream& os, const DCCLCodec& codec)
372 {
373  codec.info_all(&os);
374  return os;
375 }
376 } // namespace acomms
377 } // namespace goby
378 
379 #endif
goby::acomms::TimeCodec
Definition: dccl.h:83
goby::acomms::DCCLCodec::glog_encode_group
static const std::string & glog_encode_group()
Definition: dccl.h:176
goby::acomms::DCCLCodec::size_repeated
unsigned size_repeated(const std::list< GoogleProtobufMessagePointer > &msgs)
Definition: dccl.h:220
StaticCodec
goby::acomms::Bitset
dccl::Bitset Bitset
Definition: dccl.h:126
goby::acomms::DCCLDefaultIdentifierCodec
dccl::DefaultIdentifierCodec DCCLDefaultIdentifierCodec
Definition: dccl.h:72
goby::acomms::DCCLTypedFixedFieldCodec
Definition: dccl.h:113
goby::acomms::DCCLDefaultEnumCodec
dccl::v2::DefaultEnumCodec DCCLDefaultEnumCodec
Definition: dccl.h:81
goby::acomms::DCCLCodec::merge_cfg
void merge_cfg(const protobuf::DCCLConfig &cfg)
Definition: dccl.h:147
goby::acomms::DCCLCodec::reset_id_codec
void reset_id_codec()
Definition: dccl.h:308
goby::util::FlexOstream::is
bool is(goby::util::logger::Verbosity verbosity)
goby::acomms::DCCLDefaultBoolCodec
dccl::v2::DefaultBoolCodec DCCLDefaultBoolCodec
Definition: dccl.h:78
goby::acomms::DCCLCodec::info
void info(const google::protobuf::Descriptor *desc, std::ostream *os) const
Definition: dccl.h:203
goby
The global namespace for the Goby project.
Definition: acomms_constants.h:33
goby::util::logger::DEBUG2
@ DEBUG2
Definition: flex_ostreambuf.h:78
dccl
Definition: mm_driver.h:44
dccl_compat.h
goby::acomms::DCCLCodec::id
unsigned id() const
Definition: dccl.h:169
goby::acomms::DCCLFieldCodecManager
dccl::FieldCodecManager DCCLFieldCodecManager
Definition: dccl.h:124
goby::acomms::DCCLRepeatedTypedFieldCodec
Definition: dccl.h:119
goby::acomms::protobuf::DCCLConfig
Definition: dccl.pb.h:77
goby::uint64
std::uint64_t uint64
Definition: primitive_types.h:34
goby::acomms::protobuf::DCCLConfig::has_id_codec
bool has_id_codec() const
Definition: dccl.pb.h:514
goby::util::logger::WARN
@ WARN
Definition: flex_ostreambuf.h:74
goby::util::e
constexpr T e
Definition: constants.h:35
goby::acomms::DCCLCodec::decode
void decode(const std::string &bytes, google::protobuf::Message *msg, bool header_only=false)
Definition: dccl.h:185
goby::acomms::DCCLCodec::validate_repeated
void validate_repeated(const std::list< const google::protobuf::Descriptor * > &descs)
Definition: dccl.h:198
group
goby::util::logger::GroupSetter group(std::string n)
Definition: logger_manipulators.h:134
goby::acomms::DefaultNumericFieldCodec
Definition: dccl.h:74
goby::acomms::StaticCodec
Definition: dccl.h:98
goby::acomms::DCCLCodec::codec
std::shared_ptr< dccl::Codec > codec()
Return the underlying dccl::Codec that is used by this wrapper.
Definition: dccl.h:139
TimeCodecBase
flex_ostreambuf.h
goby::acomms::protobuf::DCCLConfig::skip_crypto_for_id
::google::protobuf::uint32 skip_crypto_for_id(int index) const
Definition: dccl.pb.h:490
goby::acomms::DCCLTypedFieldCodec::DCCLFieldCodecBase
dccl::FieldCodecBase DCCLFieldCodecBase
Definition: dccl.h:109
goby::util::logger::VERBOSE
@ VERBOSE
Definition: flex_ostreambuf.h:75
goby::acomms::DCCLCodec::validate
void validate(const google::protobuf::Descriptor *desc)
Definition: dccl.h:192
goby::acomms::DCCLCodec::set_id_codec
void set_id_codec(const std::string &identifier)
Definition: dccl.h:287
goby::acomms::DCCLCodec::decode_repeated
std::list< GoogleProtobufMessagePointer > decode_repeated(const std::string &orig_bytes)
Definition: dccl.h:248
goby::acomms::DCCLCodec::get
static DCCLCodec * get()
DCCLCodec is a singleton class; use this to get a pointer to the class.
Definition: dccl.h:132
goby::acomms::DCCLCodec::info_all
void info_all(std::ostream *os) const
Definition: dccl.h:167
goby::acomms::DCCLDefaultStringCodec
dccl::v2::DefaultStringCodec DCCLDefaultStringCodec
Definition: dccl.h:79
goby::acomms::operator<<
std::ostream & operator<<(std::ostream &os, const MACManager &mac)
goby::acomms::DCCLCodec::size
unsigned size(const google::protobuf::Message &msg)
Definition: dccl.h:174
goby::acomms::DCCLCodec
Definition: dccl.h:128
double
goby::acomms::DCCLCodec::info_repeated
void info_repeated(const std::list< const google::protobuf::Descriptor * > &desc, std::ostream *os) const
Definition: dccl.h:208
goby::acomms::DCCLCodec::set_cfg
void set_cfg(const protobuf::DCCLConfig &cfg)
Definition: dccl.h:141
goby::acomms::DCCLCodec::add_id_codec
void add_id_codec(const std::string &identifier)
Definition: dccl.h:278
goby::acomms::DCCLDefaultMessageCodec
dccl::v2::DefaultMessageCodec DCCLDefaultMessageCodec
Definition: dccl.h:102
goby::acomms::DCCLCodec::encode
void encode(std::string *bytes, const google::protobuf::Message &msg, bool header_only=false)
Definition: dccl.h:179
goby::acomms::protobuf::DCCLConfig::crypto_passphrase
const ::std::string & crypto_passphrase() const
Definition: dccl.pb.h:431
goby::acomms::DCCLTypedFieldCodec
Definition: dccl.h:107
goby::util::logger::DEBUG3
@ DEBUG3
Definition: flex_ostreambuf.h:79
goby::util::logger::Verbosity
Verbosity
Definition: flex_ostreambuf.h:70
flex_ostream.h
goby::msg
extern ::google::protobuf::internal::ExtensionIdentifier< ::google::protobuf::MessageOptions, ::google::protobuf::internal::MessageTypeTraits< ::goby::GobyMessageOptions >, 11, false > msg
Definition: option_extensions.pb.h:1327
goby::int64
std::int64_t int64
Definition: primitive_types.h:35
goby::acomms::DCCLCodec::id_from_encoded
unsigned id_from_encoded(const std::string &bytes)
Definition: dccl.h:190
goby::acomms::DCCLCodec::glog_decode_group
static const std::string & glog_decode_group()
Definition: dccl.h:177
goby::acomms::DCCLCodec::id
unsigned id(const google::protobuf::Descriptor *desc) const
Definition: dccl.h:214
google::protobuf::Message
Definition: message.h:189
binary.h
logger_manipulators.h
goby::acomms::protobuf::DCCLConfig::CopyFrom
void CopyFrom(const ::google::protobuf::Message &from) final
goby::acomms::DCCLRepeatedTypedFieldCodec::DCCLFieldCodecBase
dccl::FieldCodecBase DCCLFieldCodecBase
Definition: dccl.h:121
goby::acomms::DCCLTypedFixedFieldCodec::DCCLFieldCodecBase
dccl::FieldCodecBase DCCLFieldCodecBase
Definition: dccl.h:115
goby::acomms::DCCLCodec::decode
GoogleProtobufMessagePointer decode(const std::string &bytes, bool header_only=false)
Definition: dccl.h:228
goby::acomms::protobuf::DCCLConfig::skip_crypto_for_id_size
int skip_crypto_for_id_size() const
Definition: dccl.pb.h:484
goby::acomms::DCCLNullValueException
dccl::NullValueException DCCLNullValueException
Definition: dccl.h:70
goby::acomms::DCCLFieldCodecBase
dccl::FieldCodecBase DCCLFieldCodecBase
Definition: dccl.h:104
goby::util::logger::DEBUG1
@ DEBUG1
Definition: flex_ostreambuf.h:77
goby::util::hex_encode
void hex_encode(const std::string &in, std::string *out, bool upper_case=false)
Encodes a (little-endian) hexadecimal string from a byte string. Index 0 of in is written to index 0 ...
Definition: binary.h:94
goby::acomms::DCCLCodec::validate
void validate()
Definition: dccl.h:160
goby::acomms::DCCLDefaultBytesCodec
dccl::v2::DefaultBytesCodec DCCLDefaultBytesCodec
Definition: dccl.h:80
goby::glog
util::FlexOstream glog
Access the Goby logger through this object.
goby::acomms::DCCLCodec::encode_repeated
std::string encode_repeated(const std::list< GoogleProtobufMessagePointer > &msgs)
Definition: dccl.h:234
DefaultNumericFieldCodec
goby::acomms::DCCLCodec::info
void info(std::ostream *os) const
Definition: dccl.h:162
goby::acomms::protobuf::DCCLConfig::id_codec
const ::std::string & id_codec() const
Definition: dccl.pb.h:527
goby::acomms::DCCLCodec::load_shared_library_codecs
void load_shared_library_codecs(void *dl_handle)
Definition: dccl.h:154
goby::acomms::protobuf::DCCLConfig::has_crypto_passphrase
bool has_crypto_passphrase() const
Definition: dccl.pb.h:418
goby::acomms::protobuf::DCCLConfig::MergeFrom
void MergeFrom(const ::google::protobuf::Message &from) final
goby::acomms::DCCLException
dccl::Exception DCCLException
Definition: dccl.h:69
dccl.pb.h
google
Definition: dccl.h:57