32 #include <google/protobuf/descriptor.h>
34 #include <boost/shared_ptr.hpp>
37 #include "dynamic_protobuf_manager.h"
39 #include "exception.h"
40 #include "field_codec.h"
41 #include "field_codec_fixed.h"
43 #include "codecs2/field_codec_default_message.h"
44 #include "codecs3/field_codec_default_message.h"
45 #include "field_codec_manager.h"
47 #define DCCL_HAS_CRYPTOPP 1
64 Codec(
const std::string& dccl_id_codec = default_id_codec_name(),
65 const std::string& library_path =
"");
95 template<
typename ProtobufMessage>
97 {
load(ProtobufMessage::descriptor()); }
102 template<
typename ProtobufMessage>
104 {
unload(ProtobufMessage::descriptor()); }
108 { id2desc_.clear(); }
116 void load(
const google::protobuf::Descriptor* desc,
int user_id = - 1);
122 void unload(
const google::protobuf::Descriptor* desc);
128 void unload(
size_t dccl_id);
132 std::string get_id_codec() {
return id_codec_; }
141 const std::set<unsigned>& do_not_encrypt_ids_ = std::set<unsigned>());
169 template<
typename ProtobufMessage>
170 void info(std::ostream* os = 0,
int user_id = -1)
const
171 {
info(ProtobufMessage::descriptor(), os, user_id); }
178 void info(
const google::protobuf::Descriptor* desc, std::ostream* os = 0,
int user_id = - 1)
const;
183 void info_all(std::ostream* os = 0)
const;
188 template <
typename ProtobufMessage>
190 {
return id(ProtobufMessage::descriptor()); }
211 unsigned id(
const std::string& bytes)
const;
214 template<
typename CharIterator>
215 unsigned id(CharIterator begin, CharIterator end)
const;
218 unsigned id(
const google::protobuf::Descriptor* desc)
const {
220 dccl::uint32 hardcoded_id = desc->options().GetExtension(dccl::msg).id();
224 id_codec()->field_encode(&id_bits, hardcoded_id, 0);
230 const std::map<int32, const google::protobuf::Descriptor*>&
loaded()
const {
return id2desc_; }
270 template <
typename CharIterator>
295 template<
typename GoogleProtobufMessagePo
inter>
296 GoogleProtobufMessagePointer
decode(
const std::string& bytes,
bool header_only =
false);
304 template<
typename GoogleProtobufMessagePo
inter>
305 GoogleProtobufMessagePointer
decode(std::string* bytes);
319 template<
typename ProtobufMessage>
321 {
return max_size(ProtobufMessage::descriptor()); }
324 unsigned max_size(
const google::protobuf::Descriptor* desc)
const;
330 template<
typename ProtobufMessage>
332 {
return min_size(ProtobufMessage::descriptor()); }
335 unsigned min_size(
const google::protobuf::Descriptor* desc)
const;
341 static std::string default_id_codec_name()
342 {
return "dccl.default.id"; }
345 static std::string default_codec_name(
int version = 2)
350 return dccl::DCCLFieldOptions::descriptor()->FindFieldByName(
"codec")->default_value_string();
352 return "dccl.default" + boost::lexical_cast<std::string>(version);
359 friend class v2::DefaultMessageCodec;
363 void encode_internal(
const google::protobuf::Message& msg,
bool header_only, Bitset& header_bits, Bitset& body_bits,
int user_id);
364 std::string get_all_error_fields_in_message(
368 void encrypt(std::string* s,
const std::string& nonce);
369 void decrypt(std::string* s,
const std::string& nonce);
371 void set_default_codecs();
373 boost::shared_ptr<FieldCodecBase> id_codec()
const
382 std::string crypto_key_;
388 unsigned console_width_;
391 std::set<unsigned> skip_crypto_ids_;
394 std::map<int32, const google::protobuf::Descriptor*> id2desc_;
395 std::string id_codec_;
397 std::vector<void *> dl_handles_;
399 std::string build_guard_for_console_output(std::string& base,
char guard_char)
const;
402 inline std::ostream& operator<<(std::ostream& os,
const Codec& codec)
409 template<
typename GoogleProtobufMessagePo
inter>
412 unsigned this_id =
id(bytes);
414 if(!id2desc_.count(this_id))
415 throw(
Exception(
"Message id " + boost::lexical_cast<std::string>(this_id) +
" has not been loaded. Call load() before decoding this type."));
418 GoogleProtobufMessagePointer msg =
419 dccl::DynamicProtobufManager::new_protobuf_message<GoogleProtobufMessagePointer>(id2desc_.find(this_id)->second);
420 decode(bytes, &(*msg), header_only);
424 template<
typename GoogleProtobufMessagePo
inter>
427 unsigned this_id = id(*bytes);
429 if(!id2desc_.count(this_id))
430 throw(
Exception(
"Message id " + boost::lexical_cast<std::string>(this_id) +
" has not been loaded. Call load() before decoding this type."));
432 GoogleProtobufMessagePointer msg =
433 dccl::DynamicProtobufManager::new_protobuf_message<GoogleProtobufMessagePointer>(id2desc_.find(this_id)->second);
434 std::string::iterator new_begin = decode(bytes->begin(), bytes->end(), &(*msg));
435 bytes->erase(bytes->begin(), new_begin);
439 template<
typename CharIterator>
442 unsigned id_min_size = 0, id_max_size = 0;
443 id_codec()->field_min_size(&id_min_size, 0);
444 id_codec()->field_max_size(&id_max_size, 0);
446 if(std::distance(begin, end) < (id_min_size / BITS_IN_BYTE))
447 throw(
Exception(
"Bytes passed (hex: " +
hex_encode(begin, end) +
") is too small to be a valid DCCL message"));
450 fixed_header_bits.
from_byte_stream(begin, begin+(
size_t)std::ceil(
double(id_max_size) / BITS_IN_BYTE));
452 Bitset these_bits(&fixed_header_bits);
455 boost::any return_value;
456 id_codec()->field_decode(&these_bits, &return_value, 0);
458 return boost::any_cast<uint32>(return_value);
461 template <
typename CharIterator>
466 unsigned this_id = id(begin, end);
468 dlog.
is(logger::DEBUG1, logger::DECODE) && dlog <<
"Began decoding message of id: " << this_id << std::endl;
470 if(!id2desc_.count(this_id))
471 throw(
Exception(
"Message id " + boost::lexical_cast<std::string>(this_id) +
" has not been loaded. Call load() before decoding this type."));
473 const google::protobuf::Descriptor* desc = msg->GetDescriptor();
475 dlog.
is(logger::DEBUG1, logger::DECODE) && dlog <<
"Type name: " << desc->full_name() << std::endl;
478 boost::shared_ptr<internal::FromProtoCppTypeBase> helper = internal::TypeHelper::find(desc);
480 CharIterator actual_end = end;
483 unsigned head_size_bits;
484 unsigned body_size_bits;
485 codec->base_max_size(&head_size_bits, desc, HEAD);
486 codec->base_max_size(&body_size_bits, desc, BODY);
487 unsigned id_size = 0;
488 id_codec()->field_size(&id_size, this_id, 0);
489 head_size_bits += id_size;
491 unsigned head_size_bytes = ceil_bits2bytes(head_size_bits);
492 unsigned body_size_bytes = ceil_bits2bytes(body_size_bits);
494 dlog.
is(logger::DEBUG2, logger::DECODE) && dlog <<
"Head bytes (bits): " << head_size_bytes <<
"(" << head_size_bits
495 <<
"), max body bytes (bits): " << body_size_bytes <<
"(" << body_size_bits <<
")" << std::endl;
497 CharIterator head_bytes_end = begin + head_size_bytes;
498 dlog.
is(logger::DEBUG3, logger::DECODE) && dlog <<
"Unencrypted Head (hex): " <<
hex_encode(begin, head_bytes_end) << std::endl;
502 dlog.
is(logger::DEBUG3, logger::DECODE) && dlog <<
"Unencrypted Head (bin): " << head_bits << std::endl;
505 head_bits >>= id_size;
507 dlog.
is(logger::DEBUG3, logger::DECODE) && dlog <<
"Unencrypted Head after ID bits removal (bin): " << head_bits << std::endl;
510 msg_stack.push(msg->GetDescriptor());
512 codec->base_decode(&head_bits, msg, HEAD);
513 dlog.
is(logger::DEBUG2, logger::DECODE) && dlog <<
"after header decode, message is: " << *msg << std::endl;
518 dlog.
is(logger::DEBUG2, logger::DECODE) && dlog <<
"as requested, skipping decrypting and decoding body." << std::endl;
519 actual_end = head_bytes_end;
523 dlog.
is(logger::DEBUG3, logger::DECODE) && dlog <<
"Encrypted Body (hex): " <<
hex_encode(head_bytes_end, end) << std::endl;
526 if(!crypto_key_.empty() && !skip_crypto_ids_.count(this_id))
528 std::string head_bytes(begin, head_bytes_end);
529 std::string body_bytes(head_bytes_end, end);
530 decrypt(&body_bytes, head_bytes);
531 dlog.
is(logger::DEBUG3, logger::DECODE) && dlog <<
"Unencrypted Body (hex): " <<
hex_encode(body_bytes) << std::endl;
536 dlog.
is(logger::DEBUG3, logger::DECODE) && dlog <<
"Unencrypted Body (hex): " <<
hex_encode(head_bytes_end, end) << std::endl;
540 dlog.
is(logger::DEBUG3, logger::DECODE) && dlog <<
"Unencrypted Body (bin): " << body_bits << std::endl;
542 codec->base_decode(&body_bits, msg, BODY);
543 dlog.
is(logger::DEBUG2, logger::DECODE) && dlog <<
"after header & body decode, message is: " << *msg << std::endl;
545 actual_end = end - body_bits.size()/BITS_IN_BYTE;
550 throw(
Exception(
"Failed to find (dccl.msg).codec `" + desc->options().GetExtension(dccl::msg).codec() +
"`"));
553 dlog.
is(logger::DEBUG1, logger::DECODE) && dlog <<
"Successfully decoded message of type: " << desc->full_name() << std::endl;
556 catch(std::exception& e)
558 std::stringstream ss;
560 ss <<
"Message " <<
hex_encode(begin, end) <<
" failed to decode. Reason: " << e.what() << std::endl;
562 dlog.
is(logger::DEBUG1, logger::DECODE) && dlog << ss.str() << std::endl;