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;