Goby3 3.2.3
2025.05.13
Loading...
Searching...
No Matches
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<<
56
57namespace google
58{
59namespace protobuf
60{
61class Message;
62} // namespace protobuf
63} // namespace google
64
65namespace goby
66{
67namespace acomms
68{
69typedef dccl::Exception DCCLException;
70using DCCLNullValueException = dccl::NullValueException;
71
72using DCCLDefaultIdentifierCodec = dccl::DefaultIdentifierCodec;
73template <typename WireType, typename FieldType = WireType>
75{
76};
77
78using DCCLDefaultBoolCodec = dccl::v2::DefaultBoolCodec;
79using DCCLDefaultStringCodec = dccl::v2::DefaultStringCodec;
80using DCCLDefaultBytesCodec = dccl::v2::DefaultBytesCodec;
81using DCCLDefaultEnumCodec = dccl::v2::DefaultEnumCodec;
82
83template <typename TimeType> class TimeCodec : public dccl::v2::TimeCodecBase<TimeType, 0>
84{
85 static_assert(sizeof(TimeCodec) == 0, "TimeCodec must be specialized");
86};
87
88template <> class TimeCodec<dccl::uint64> : public dccl::v2::TimeCodecBase<dccl::uint64, 1000000>
89{
90};
91template <> class TimeCodec<dccl::int64> : public dccl::v2::TimeCodecBase<dccl::int64, 1000000>
92{
93};
94template <> class TimeCodec<double> : public dccl::v2::TimeCodecBase<double, 1>
95{
96};
97
98template <typename T> class StaticCodec : public dccl::v2::StaticCodec<T>
99{
100};
101
102using DCCLDefaultMessageCodec = dccl::v2::DefaultMessageCodec;
103
104using DCCLFieldCodecBase = dccl::FieldCodecBase;
105
106template <typename WireType, typename FieldType = WireType>
107struct DCCLTypedFieldCodec : public dccl::TypedFieldCodec<WireType, FieldType>
108{
109 using DCCLFieldCodecBase = dccl::FieldCodecBase;
110};
111
112template <typename WireType, typename FieldType = WireType>
113struct DCCLTypedFixedFieldCodec : public dccl::TypedFixedFieldCodec<WireType, FieldType>
114{
115 using DCCLFieldCodecBase = dccl::FieldCodecBase;
116};
117
118template <typename WireType, typename FieldType = WireType>
119struct DCCLRepeatedTypedFieldCodec : public dccl::RepeatedTypedFieldCodec<WireType, FieldType>
120{
121 using DCCLFieldCodecBase = dccl::FieldCodecBase;
122};
123
124using DCCLFieldCodecManager = dccl::FieldCodecManager;
125using DCCLFieldCodecManager = dccl::FieldCodecManager;
126using Bitset = dccl::Bitset;
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
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
371inline 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
std::shared_ptr< dccl::Codec > codec()
Return the underlying dccl::Codec that is used by this wrapper.
Definition dccl.h:139
static DCCLCodec * get()
DCCLCodec is a singleton class; use this to get a pointer to the class.
Definition dccl.h:132
std::string encode_repeated(const std::list< GoogleProtobufMessagePointer > &msgs)
Definition dccl.h:234
void encode(std::string *bytes, const google::protobuf::Message &msg, bool header_only=false)
Definition dccl.h:179
void info(const google::protobuf::Descriptor *desc, std::ostream *os) const
Definition dccl.h:203
unsigned id(const google::protobuf::Descriptor *desc) const
Definition dccl.h:214
unsigned size(const google::protobuf::Message &msg)
Definition dccl.h:174
void load_shared_library_codecs(void *dl_handle)
Definition dccl.h:154
void set_cfg(const protobuf::DCCLConfig &cfg)
Definition dccl.h:141
void info_repeated(const std::list< const google::protobuf::Descriptor * > &desc, std::ostream *os) const
Definition dccl.h:208
void info_all(std::ostream *os) const
Definition dccl.h:167
static const std::string & glog_decode_group()
Definition dccl.h:177
unsigned id_from_encoded(const std::string &bytes)
Definition dccl.h:190
void merge_cfg(const protobuf::DCCLConfig &cfg)
Definition dccl.h:147
void validate_repeated(const std::list< const google::protobuf::Descriptor * > &descs)
Definition dccl.h:198
void add_id_codec(const std::string &identifier)
Definition dccl.h:278
unsigned id() const
Definition dccl.h:169
void info(std::ostream *os) const
Definition dccl.h:162
unsigned size_repeated(const std::list< GoogleProtobufMessagePointer > &msgs)
Definition dccl.h:220
void set_id_codec(const std::string &identifier)
Definition dccl.h:287
static const std::string & glog_encode_group()
Definition dccl.h:176
void decode(const std::string &bytes, google::protobuf::Message *msg, bool header_only=false)
Definition dccl.h:185
void validate(const google::protobuf::Descriptor *desc)
Definition dccl.h:192
GoogleProtobufMessagePointer decode(const std::string &bytes, bool header_only=false)
Definition dccl.h:228
std::list< GoogleProtobufMessagePointer > decode_repeated(const std::string &orig_bytes)
Definition dccl.h:248
const std::string & id_codec() const
Definition dccl.pb.h:677
uint32_t skip_crypto_for_id(int index) const
Definition dccl.pb.h:631
void MergeFrom(const DCCLConfig &from)
Definition dccl.pb.h:161
void CopyFrom(const DCCLConfig &from)
const std::string & crypto_passphrase() const
Definition dccl.pb.h:562
bool is(goby::util::logger::Verbosity verbosity)
goby::util::logger::GroupSetter group(std::string n)
dccl::v2::DefaultBoolCodec DCCLDefaultBoolCodec
Definition dccl.h:78
dccl::Bitset Bitset
Definition dccl.h:126
dccl::FieldCodecBase DCCLFieldCodecBase
Definition dccl.h:104
dccl::FieldCodecManager DCCLFieldCodecManager
Definition dccl.h:124
dccl::v2::DefaultBytesCodec DCCLDefaultBytesCodec
Definition dccl.h:80
std::ostream & operator<<(std::ostream &os, const MACManager &mac)
dccl::DefaultIdentifierCodec DCCLDefaultIdentifierCodec
Definition dccl.h:72
dccl::v2::DefaultEnumCodec DCCLDefaultEnumCodec
Definition dccl.h:81
dccl::NullValueException DCCLNullValueException
Definition dccl.h:70
dccl::Exception DCCLException
Definition dccl.h:69
dccl::v2::DefaultStringCodec DCCLDefaultStringCodec
Definition dccl.h:79
dccl::v2::DefaultMessageCodec DCCLDefaultMessageCodec
Definition dccl.h:102
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
The global namespace for the Goby project.
std::int64_t int64
std::uint64_t uint64
extern ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< ::PROTOBUF_NAMESPACE_ID::MessageOptions, ::PROTOBUF_NAMESPACE_ID::internal::MessageTypeTraits< ::goby::GobyMessageOptions >, 11, false > msg
util::FlexOstream glog
Access the Goby logger through this object.
Definition dccl.h:58
dccl::FieldCodecBase DCCLFieldCodecBase
Definition dccl.h:121
dccl::FieldCodecBase DCCLFieldCodecBase
Definition dccl.h:109
dccl::FieldCodecBase DCCLFieldCodecBase
Definition dccl.h:115