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