35 #include <type_traits>
38 #include <google/protobuf/descriptor.h>
43 #include "dynamic_protobuf_manager.h"
44 #include "exception.h"
45 #include "field_codec.h"
46 #include "field_codec_fixed.h"
49 #include "codecs2/field_codec_default_message.h"
50 #include "codecs3/field_codec_default_message.h"
52 #include "field_codec_manager.h"
69 Codec(std::string dccl_id_codec_name = default_id_codec_name(),
70 const std::string& library_path =
"");
78 template <
class IDFieldCodec,
79 typename std::enable_if<std::is_base_of<FieldCodecBase, IDFieldCodec>::value,
81 Codec(
const std::string& dccl_id_codec_name,
const IDFieldCodec& dccl_id_codec)
82 : id_codec_(dccl_id_codec_name)
85 manager_.
add<IDFieldCodec>(dccl_id_codec_name);
119 template <
typename ProtobufMessage>
void load() {
load(ProtobufMessage::descriptor()); }
124 template <
typename ProtobufMessage>
void unload() {
unload(ProtobufMessage::descriptor()); }
126 void unload_all() { id2desc_.clear(); }
134 void load(
const google::protobuf::Descriptor* desc,
int user_id = -1);
140 void unload(
const google::protobuf::Descriptor* desc);
146 void unload(
size_t dccl_id);
150 std::string get_id_codec() {
return id_codec_; }
159 const std::set<unsigned>& do_not_encrypt_ids_ = std::set<unsigned>());
184 template <
typename ProtobufMessage>
185 void info(std::ostream* os =
nullptr,
int user_id = -1)
const
187 info(ProtobufMessage::descriptor(), os, user_id);
195 void info(
const google::protobuf::Descriptor* desc, std::ostream* os =
nullptr,
196 int user_id = -1)
const;
201 void info_all(std::ostream* os =
nullptr)
const;
206 template <
typename ProtobufMessage>
unsigned id()
const
208 return id(ProtobufMessage::descriptor());
230 unsigned id(
const std::string& bytes)
const;
233 template <
typename CharIterator>
unsigned id(CharIterator begin, CharIterator end)
const;
236 unsigned id(
const google::protobuf::Descriptor* desc)
const
239 dccl::uint32 hardcoded_id = desc->options().GetExtension(dccl::msg).id();
243 id_codec()->field_encode(&id_bits, hardcoded_id,
nullptr);
249 const std::map<int32, const google::protobuf::Descriptor*>&
loaded()
const {
return id2desc_; }
280 bool header_only =
false,
int user_id = -1);
290 template <
typename CharIterator>
292 bool header_only =
false);
316 template <
typename GoogleProtobufMessagePo
inter>
317 GoogleProtobufMessagePointer
decode(
const std::string& bytes,
bool header_only =
false);
325 template <
typename GoogleProtobufMessagePo
inter>
326 GoogleProtobufMessagePointer
decode(std::string* bytes);
340 template <
typename ProtobufMessage>
unsigned max_size()
342 return max_size(ProtobufMessage::descriptor());
346 unsigned max_size(
const google::protobuf::Descriptor* desc)
const;
352 template <
typename ProtobufMessage>
unsigned min_size()
354 return min_size(ProtobufMessage::descriptor());
358 unsigned min_size(
const google::protobuf::Descriptor* desc)
const;
362 static std::string default_id_codec_name() {
return "dccl.default.id"; }
364 static std::string default_codec_name(
int version = 2)
369 return dccl::DCCLFieldOptions::descriptor()
370 ->FindFieldByName(
"codec")
371 ->default_value_string();
372 default:
return "dccl.default" + std::to_string(version);
376 FieldCodecManagerLocal& manager() {
return manager_; }
380 Bitset& header_bits, Bitset& body_bits,
int user_id);
384 void encrypt(std::string* s,
const std::string& nonce);
385 void decrypt(std::string* s,
const std::string& nonce);
387 void set_default_codecs();
389 std::shared_ptr<FieldCodecBase> id_codec()
const
391 return manager_.
find(google::protobuf::FieldDescriptor::TYPE_UINT32, id_codec_);
396 std::string crypto_key_;
402 unsigned console_width_{60};
405 std::set<unsigned> skip_crypto_ids_;
408 std::map<int32, const google::protobuf::Descriptor*> id2desc_;
409 std::string id_codec_;
411 std::vector<void*> dl_handles_;
413 std::string build_guard_for_console_output(std::string& base,
char guard_char)
const;
415 FieldCodecManagerLocal manager_;
418 inline std::ostream& operator<<(std::ostream& os,
const Codec& codec)
425 template <
typename GoogleProtobufMessagePo
inter>
429 unsigned this_id =
id(bytes);
431 if (!id2desc_.count(this_id))
432 throw(
Exception(
"Message id " + std::to_string(this_id) +
433 " has not been loaded. Call load() before decoding this type."));
436 auto msg = dccl::DynamicProtobufManager::new_protobuf_message<GoogleProtobufMessagePointer>(
437 id2desc_.find(this_id)->second);
438 decode(bytes, &(*msg), header_only);
442 template <
typename GoogleProtobufMessagePo
inter>
445 unsigned this_id = id(*bytes);
447 if (!id2desc_.count(this_id))
448 throw(
Exception(
"Message id " + std::to_string(this_id) +
449 " has not been loaded. Call load() before decoding this type."));
451 GoogleProtobufMessagePointer msg =
452 dccl::DynamicProtobufManager::new_protobuf_message<GoogleProtobufMessagePointer>(
453 id2desc_.find(this_id)->second);
454 std::string::iterator new_begin = decode(bytes->begin(), bytes->end(), &(*msg));
455 bytes->erase(bytes->begin(), new_begin);
459 template <
typename CharIterator>
462 unsigned id_min_size = 0, id_max_size = 0;
463 id_codec()->field_min_size(&id_min_size,
nullptr);
464 id_codec()->field_max_size(&id_max_size,
nullptr);
466 if (std::distance(begin, end) < (id_min_size / BITS_IN_BYTE))
468 ") is too small to be a valid DCCL message"));
472 begin, begin + (
size_t)std::ceil(
double(id_max_size) / BITS_IN_BYTE));
474 Bitset these_bits(&fixed_header_bits);
477 dccl::any return_value;
478 id_codec()->field_decode(&these_bits, &return_value,
nullptr);
480 return dccl::any_cast<uint32>(return_value);
483 template <
typename CharIterator>
489 unsigned this_id = id(begin, end);
491 dlog.
is(logger::DEBUG1, logger::DECODE) &&
492 dlog <<
"Began decoding message of id: " << this_id << std::endl;
494 if (!id2desc_.count(this_id))
495 throw(
Exception(
"Message id " + std::to_string(this_id) +
496 " has not been loaded. Call load() before decoding this type."));
498 const google::protobuf::Descriptor* desc = msg->GetDescriptor();
500 dlog.
is(logger::DEBUG1, logger::DECODE) && dlog <<
"Type name: " << desc->full_name()
503 std::shared_ptr<FieldCodecBase> codec = manager_.find(desc);
504 std::shared_ptr<internal::FromProtoCppTypeBase> helper = manager_.type_helper().find(desc);
506 CharIterator actual_end = end;
509 unsigned head_size_bits;
510 unsigned body_size_bits;
511 codec->base_max_size(&head_size_bits, desc, HEAD);
512 codec->base_max_size(&body_size_bits, desc, BODY);
513 unsigned id_size = 0;
514 id_codec()->field_size(&id_size, this_id,
nullptr);
515 head_size_bits += id_size;
517 unsigned head_size_bytes = ceil_bits2bytes(head_size_bits);
518 unsigned body_size_bytes = ceil_bits2bytes(body_size_bits);
520 dlog.
is(logger::DEBUG2, logger::DECODE) &&
521 dlog <<
"Head bytes (bits): " << head_size_bytes <<
"(" << head_size_bits
522 <<
"), max body bytes (bits): " << body_size_bytes <<
"(" << body_size_bits
525 CharIterator head_bytes_end = begin + head_size_bytes;
526 dlog.
is(logger::DEBUG3, logger::DECODE) &&
527 dlog <<
"Unencrypted Head (hex): " <<
hex_encode(begin, head_bytes_end)
532 dlog.
is(logger::DEBUG3, logger::DECODE) &&
533 dlog <<
"Unencrypted Head (bin): " << head_bits << std::endl;
536 head_bits >>= id_size;
538 dlog.
is(logger::DEBUG3, logger::DECODE) &&
539 dlog <<
"Unencrypted Head after ID bits removal (bin): " << head_bits << std::endl;
542 manager_.codec_data().message_data_);
543 msg_stack.push(msg->GetDescriptor());
545 codec->base_decode(&head_bits, msg, HEAD);
546 dlog.
is(logger::DEBUG2, logger::DECODE) &&
547 dlog <<
"after header decode, message is: " << *msg << std::endl;
551 dlog.
is(logger::DEBUG2, logger::DECODE) &&
552 dlog <<
"as requested, skipping decrypting and decoding body." << std::endl;
553 actual_end = head_bytes_end;
557 dlog.
is(logger::DEBUG3, logger::DECODE) &&
558 dlog <<
"Encrypted Body (hex): " <<
hex_encode(head_bytes_end, end)
562 if (!crypto_key_.empty() && !skip_crypto_ids_.count(this_id))
564 std::string head_bytes(begin, head_bytes_end);
565 std::string body_bytes(head_bytes_end, end);
566 decrypt(&body_bytes, head_bytes);
567 dlog.
is(logger::DEBUG3, logger::DECODE) &&
568 dlog <<
"Unencrypted Body (hex): " <<
hex_encode(body_bytes) << std::endl;
573 dlog.
is(logger::DEBUG3, logger::DECODE) &&
574 dlog <<
"Unencrypted Body (hex): " <<
hex_encode(head_bytes_end, end)
579 dlog.
is(logger::DEBUG3, logger::DECODE) &&
580 dlog <<
"Unencrypted Body (bin): " << body_bits << std::endl;
582 codec->base_decode(&body_bits, msg, BODY);
583 dlog.
is(logger::DEBUG2, logger::DECODE) &&
584 dlog <<
"after header & body decode, message is: " << *msg << std::endl;
586 actual_end = end - body_bits.size() / BITS_IN_BYTE;
591 throw(
Exception(
"Failed to find (dccl.msg).codec `" +
592 desc->options().GetExtension(dccl::msg).codec() +
"`"),
596 dlog.
is(logger::DEBUG1, logger::DECODE) &&
597 dlog <<
"Successfully decoded message of type: " << desc->full_name() << std::endl;
600 catch (std::exception& e)
602 std::stringstream ss;
604 ss <<
"Message " <<
hex_encode(begin, end) <<
" failed to decode. Reason: " << e.what()
607 dlog.
is(logger::DEBUG1, logger::DECODE) && dlog << ss.str() << std::endl;