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>());
162 template<
typename ProtobufMessage>
163 void info(std::ostream* os = 0,
int user_id = -1)
const
164 {
info(ProtobufMessage::descriptor(), os, user_id); }
171 void info(
const google::protobuf::Descriptor* desc, std::ostream* os = 0,
int user_id = - 1)
const;
176 void info_all(std::ostream* os = 0)
const;
181 template <
typename ProtobufMessage>
183 {
return id(ProtobufMessage::descriptor()); }
204 unsigned id(
const std::string& bytes)
const;
207 template<
typename CharIterator>
208 unsigned id(CharIterator begin, CharIterator end)
const;
211 unsigned id(
const google::protobuf::Descriptor* desc)
const {
213 dccl::uint32 hardcoded_id = desc->options().GetExtension(dccl::msg).id();
217 id_codec()->field_encode(&id_bits, hardcoded_id, 0);
223 const std::map<int32, const google::protobuf::Descriptor*>&
loaded()
const {
return id2desc_; }
263 template <
typename CharIterator>
288 template<
typename GoogleProtobufMessagePo
inter>
289 GoogleProtobufMessagePointer
decode(
const std::string& bytes,
bool header_only =
false);
297 template<
typename GoogleProtobufMessagePo
inter>
298 GoogleProtobufMessagePointer
decode(std::string* bytes);
312 template<
typename ProtobufMessage>
314 {
return max_size(ProtobufMessage::descriptor()); }
317 unsigned max_size(
const google::protobuf::Descriptor* desc)
const;
323 template<
typename ProtobufMessage>
325 {
return min_size(ProtobufMessage::descriptor()); }
328 unsigned min_size(
const google::protobuf::Descriptor* desc)
const;
334 static std::string default_id_codec_name()
335 {
return "dccl.default.id"; }
338 static std::string default_codec_name(
int version = 2)
343 return dccl::DCCLFieldOptions::descriptor()->FindFieldByName(
"codec")->default_value_string();
345 return "dccl.default" + boost::lexical_cast<std::string>(version);
352 friend class v2::DefaultMessageCodec;
356 void encode_internal(
const google::protobuf::Message& msg,
bool header_only, Bitset& header_bits, Bitset& body_bits,
int user_id);
358 void encrypt(std::string* s,
const std::string& nonce);
359 void decrypt(std::string* s,
const std::string& nonce);
361 void set_default_codecs();
363 boost::shared_ptr<FieldCodecBase> id_codec()
const
371 std::string crypto_key_;
377 std::set<unsigned> skip_crypto_ids_;
380 std::map<int32, const google::protobuf::Descriptor*> id2desc_;
381 std::string id_codec_;
383 std::vector<void *> dl_handles_;
387 inline std::ostream& operator<<(std::ostream& os,
const Codec& codec)
394 template<
typename GoogleProtobufMessagePo
inter>
397 unsigned this_id =
id(bytes);
399 if(!id2desc_.count(this_id))
400 throw(
Exception(
"Message id " + boost::lexical_cast<std::string>(this_id) +
" has not been loaded. Call load() before decoding this type."));
403 GoogleProtobufMessagePointer msg =
404 dccl::DynamicProtobufManager::new_protobuf_message<GoogleProtobufMessagePointer>(id2desc_.find(this_id)->second);
405 decode(bytes, &(*msg), header_only);
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."));
417 GoogleProtobufMessagePointer msg =
418 dccl::DynamicProtobufManager::new_protobuf_message<GoogleProtobufMessagePointer>(id2desc_.find(this_id)->second);
419 std::string::iterator new_begin = decode(bytes->begin(), bytes->end(), &(*msg));
420 bytes->erase(bytes->begin(), new_begin);
424 template<
typename CharIterator>
427 unsigned id_min_size = 0, id_max_size = 0;
428 id_codec()->field_min_size(&id_min_size, 0);
429 id_codec()->field_max_size(&id_max_size, 0);
431 if(std::distance(begin, end) < (id_min_size / BITS_IN_BYTE))
432 throw(
Exception(
"Bytes passed (hex: " +
hex_encode(begin, end) +
") is too small to be a valid DCCL message"));
435 fixed_header_bits.
from_byte_stream(begin, begin+(
size_t)std::ceil(
double(id_max_size) / BITS_IN_BYTE));
437 Bitset these_bits(&fixed_header_bits);
440 boost::any return_value;
441 id_codec()->field_decode(&these_bits, &return_value, 0);
443 return boost::any_cast<uint32>(return_value);
446 template <
typename CharIterator>
451 unsigned this_id = id(begin, end);
453 dlog.
is(logger::DEBUG1, logger::DECODE) && dlog <<
"Began decoding message of id: " << this_id << std::endl;
455 if(!id2desc_.count(this_id))
456 throw(
Exception(
"Message id " + boost::lexical_cast<std::string>(this_id) +
" has not been loaded. Call load() before decoding this type."));
458 const google::protobuf::Descriptor* desc = msg->GetDescriptor();
460 dlog.
is(logger::DEBUG1, logger::DECODE) && dlog <<
"Type name: " << desc->full_name() << std::endl;
463 boost::shared_ptr<internal::FromProtoCppTypeBase> helper = internal::TypeHelper::find(desc);
465 CharIterator actual_end = end;
468 unsigned head_size_bits;
469 unsigned body_size_bits;
470 codec->base_max_size(&head_size_bits, desc, HEAD);
471 codec->base_max_size(&body_size_bits, desc, BODY);
472 unsigned id_size = 0;
473 id_codec()->field_size(&id_size, this_id, 0);
474 head_size_bits += id_size;
476 unsigned head_size_bytes = ceil_bits2bytes(head_size_bits);
477 unsigned body_size_bytes = ceil_bits2bytes(body_size_bits);
479 dlog.
is(logger::DEBUG2, logger::DECODE) && dlog <<
"Head bytes (bits): " << head_size_bytes <<
"(" << head_size_bits
480 <<
"), max body bytes (bits): " << body_size_bytes <<
"(" << body_size_bits <<
")" << std::endl;
482 CharIterator head_bytes_end = begin + head_size_bytes;
483 dlog.
is(logger::DEBUG3, logger::DECODE) && dlog <<
"Unencrypted Head (hex): " <<
hex_encode(begin, head_bytes_end) << std::endl;
487 dlog.
is(logger::DEBUG3, logger::DECODE) && dlog <<
"Unencrypted Head (bin): " << head_bits << std::endl;
490 head_bits >>= id_size;
492 dlog.
is(logger::DEBUG3, logger::DECODE) && dlog <<
"Unencrypted Head after ID bits removal (bin): " << head_bits << std::endl;
495 msg_stack.push(msg->GetDescriptor());
497 codec->base_decode(&head_bits, msg, HEAD);
498 dlog.
is(logger::DEBUG2, logger::DECODE) && dlog <<
"after header decode, message is: " << *msg << std::endl;
503 dlog.
is(logger::DEBUG2, logger::DECODE) && dlog <<
"as requested, skipping decrypting and decoding body." << std::endl;
504 actual_end = head_bytes_end;
508 dlog.
is(logger::DEBUG3, logger::DECODE) && dlog <<
"Encrypted Body (hex): " <<
hex_encode(head_bytes_end, end) << std::endl;
511 if(!crypto_key_.empty() && !skip_crypto_ids_.count(this_id))
513 std::string head_bytes(begin, head_bytes_end);
514 std::string body_bytes(head_bytes_end, end);
515 decrypt(&body_bytes, head_bytes);
516 dlog.
is(logger::DEBUG3, logger::DECODE) && dlog <<
"Unencrypted Body (hex): " <<
hex_encode(body_bytes) << std::endl;
521 dlog.
is(logger::DEBUG3, logger::DECODE) && dlog <<
"Unencrypted Body (hex): " <<
hex_encode(head_bytes_end, end) << std::endl;
525 dlog.
is(logger::DEBUG3, logger::DECODE) && dlog <<
"Unencrypted Body (bin): " << body_bits << std::endl;
527 codec->base_decode(&body_bits, msg, BODY);
528 dlog.
is(logger::DEBUG2, logger::DECODE) && dlog <<
"after header & body decode, message is: " << *msg << std::endl;
530 actual_end = end - body_bits.size()/BITS_IN_BYTE;
535 throw(
Exception(
"Failed to find (dccl.msg).codec `" + desc->options().GetExtension(dccl::msg).codec() +
"`"));
538 dlog.
is(logger::DEBUG1, logger::DECODE) && dlog <<
"Successfully decoded message of type: " << desc->full_name() << std::endl;
541 catch(std::exception& e)
543 std::stringstream ss;
545 ss <<
"Message " <<
hex_encode(begin, end) <<
" failed to decode. Reason: " << e.what() << std::endl;
547 dlog.
is(logger::DEBUG1, logger::DECODE) && dlog << ss.str() << std::endl;