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 
134  boost::shared_ptr<dccl::Codec> codec() { return codec_; }
135 
136  void set_cfg(const protobuf::DCCLConfig& cfg)
137  {
138  cfg_.CopyFrom(cfg);
139  process_cfg(true);
140  }
141 
142  void merge_cfg(const protobuf::DCCLConfig& cfg)
143  {
144  bool new_id_codec = (cfg_.id_codec() != cfg.id_codec());
145  cfg_.MergeFrom(cfg);
146  process_cfg(new_id_codec);
147  }
148 
149  void load_shared_library_codecs(void* dl_handle)
150  {
151  codec_->load_library(dl_handle);
152  loaded_libs_.insert(dl_handle);
153  }
154 
155  template <typename ProtobufMessage> void validate() { validate(ProtobufMessage::descriptor()); }
156 
157  template <typename ProtobufMessage> void info(std::ostream* os) const
158  {
159  info(ProtobufMessage::descriptor(), os);
160  }
161 
162  void info_all(std::ostream* os) const { codec_->info_all(os); }
163 
164  template <typename ProtobufMessage> unsigned id() const
165  {
166  return id(ProtobufMessage::descriptor());
167  }
168 
169  unsigned size(const google::protobuf::Message& msg) { return codec_->size(msg); }
170 
171  static const std::string& glog_encode_group() { return glog_encode_group_; }
172  static const std::string& glog_decode_group() { return glog_decode_group_; }
173 
174  void encode(std::string* bytes, const google::protobuf::Message& msg, bool header_only = false)
175  {
176  bytes->clear();
177  codec_->encode(bytes, msg, header_only);
178  }
179 
180  void decode(const std::string& bytes, google::protobuf::Message* msg, bool header_only = false)
181  {
182  codec_->decode(bytes, msg, header_only);
183  }
184 
185  unsigned id_from_encoded(const std::string& bytes) { return codec_->id(bytes); }
186 
187  void validate(const google::protobuf::Descriptor* desc)
188  {
189  codec_->load(desc);
190  loaded_msgs_.insert(desc);
191  }
192 
193  void validate_repeated(const std::list<const google::protobuf::Descriptor*>& descs)
194  {
195  BOOST_FOREACH (const google::protobuf::Descriptor* p, descs)
196  validate(p);
197  }
198 
199  void info(const google::protobuf::Descriptor* desc, std::ostream* os) const
200  {
201  codec_->info(desc, os);
202  }
203 
204  void info_repeated(const std::list<const google::protobuf::Descriptor*>& desc,
205  std::ostream* os) const
206  {
207  BOOST_FOREACH (const google::protobuf::Descriptor* p, desc)
208  info(p, os);
209  }
210 
211  unsigned id(const google::protobuf::Descriptor* desc) const
212  {
213  return desc->options().GetExtension(dccl::msg).id();
214  }
215 
216  template <typename GoogleProtobufMessagePointer>
217  unsigned size_repeated(const std::list<GoogleProtobufMessagePointer>& msgs)
218  {
219  unsigned out = 0;
220  BOOST_FOREACH (const GoogleProtobufMessagePointer& msg, msgs)
221  out += size(*msg);
222  return out;
223  }
224 
225  template <typename GoogleProtobufMessagePointer>
226  GoogleProtobufMessagePointer decode(const std::string& bytes, bool header_only = false)
227  {
228  return codec_->decode<GoogleProtobufMessagePointer>(bytes, header_only);
229  }
230 
231  template <typename GoogleProtobufMessagePointer>
232  std::string encode_repeated(const std::list<GoogleProtobufMessagePointer>& msgs)
233  {
234  std::string out;
235  BOOST_FOREACH (const GoogleProtobufMessagePointer& msg, msgs)
236  {
237  std::string piece;
238  encode(&piece, *msg);
239  out += piece;
240  }
241 
242  return out;
243  }
244 
245  template <typename GoogleProtobufMessagePointer>
246  std::list<GoogleProtobufMessagePointer> decode_repeated(const std::string& orig_bytes)
247  {
248  std::string bytes = orig_bytes;
249  std::list<GoogleProtobufMessagePointer> out;
250  while (!bytes.empty())
251  {
252  try
253  {
254  out.push_back(decode<GoogleProtobufMessagePointer>(bytes));
255  unsigned last_size = size(*out.back());
256  glog.is(common::logger::DEBUG1) && glog << "last message size was: " << last_size
257  << std::endl;
258  bytes.erase(0, last_size);
259  }
260  catch (dccl::Exception& e)
261  {
262  if (out.empty())
263  throw(e);
264  else
265  {
266  glog.is(common::logger::WARN) &&
267  glog << "failed to decode " << goby::util::hex_encode(bytes)
268  << " but returning parts already decoded" << std::endl;
269  return out;
270  }
271  }
272  }
273  return out;
274  }
275 
276  template <typename DCCLTypedFieldCodecUint32> void add_id_codec(const std::string& identifier)
277  {
278  dccl::FieldCodecManager::add<DCCLTypedFieldCodecUint32>(identifier);
279  }
280 
281  void set_id_codec(const std::string& identifier)
282  {
283  codec_.reset(new dccl::Codec(identifier));
284 
285  for (std::set<void*>::const_iterator it = loaded_libs_.begin(), end = loaded_libs_.end();
286  it != end; ++it)
287  load_shared_library_codecs(*it);
288 
289  for (std::set<const google::protobuf::Descriptor*>::const_iterator
290  it = loaded_msgs_.begin(),
291  end = loaded_msgs_.end();
292  it != end; ++it)
293  {
294  try
295  {
296  validate(*it);
297  }
298  catch (dccl::Exception& e)
299  {
300  glog.is(common::logger::WARN) && glog << "Failed to reload " << (*it)->full_name()
301  << " after ID codec change: " << e.what()
302  << std::endl;
303  }
304  }
305  }
306 
307  void reset_id_codec() { set_id_codec(dccl::Codec::default_id_codec_name()); }
308 
310 
311  private:
312  // so we can use shared_ptr to hold the singleton
313  template <typename T> friend void boost::checked_delete(T*);
314 
315  DCCLCodec();
316 
317  ~DCCLCodec() {}
318  DCCLCodec(const DCCLCodec&);
319  DCCLCodec& operator=(const DCCLCodec&);
320 
321  void process_cfg(bool new_id_codec)
322  {
323  if (cfg_.has_crypto_passphrase())
324  {
325  std::set<unsigned> skip_crypto_ids;
326  for (int i = 0, n = cfg_.skip_crypto_for_id_size(); i < n; ++i)
327  skip_crypto_ids.insert(cfg_.skip_crypto_for_id(i));
328  codec_->set_crypto_passphrase(cfg_.crypto_passphrase(), skip_crypto_ids);
329  }
330 
331  if (new_id_codec && cfg_.has_id_codec())
332  {
333  set_id_codec(cfg_.id_codec());
334  }
335  }
336 
337  void dlog_message(const std::string& msg, dccl::logger::Verbosity vrb, dccl::logger::Group grp)
338  {
339  if (grp == dccl::logger::DECODE)
340  goby::glog << group(glog_decode_group_) << msg << std::endl;
341  else if (grp == dccl::logger::ENCODE)
342  goby::glog << group(glog_encode_group_) << msg << std::endl;
343  else if (grp == dccl::logger::SIZE)
344  goby::glog << group(glog_encode_group_) << " {size} " << msg << std::endl;
345  else
346  goby::glog << group(glog_encode_group_) << msg << std::endl;
347  }
348 
349  private:
350  static boost::shared_ptr<DCCLCodec> inst_;
351 
352  static std::string glog_encode_group_;
353  static std::string glog_decode_group_;
354 
356 
357  boost::shared_ptr<dccl::Codec> codec_;
358 
359  std::set<void*> loaded_libs_;
360  std::set<const google::protobuf::Descriptor*> loaded_msgs_;
361 };
362 
363 inline std::ostream& operator<<(std::ostream& os, const DCCLCodec& codec)
364 {
365  codec.info_all(&os);
366  return os;
367 }
368 } // namespace acomms
369 } // namespace goby
370 
371 #endif
static DCCLCodec * get()
DCCLCodec is a singleton class; use this to get a pointer to the class.
Definition: dccl.h:124
boost::shared_ptr< dccl::Codec > codec()
Return the underlying dccl::Codec that is used by this wrapper.
Definition: dccl.h:134
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