/** This function loads a protobuf object from a file using the assumption that it is proceeded with a 64 bit Poco::Int64 in network byte order that holds the size of the object to be loaded and deserialized. @param inputPath: The path to the file to load from @param inputMessageBuffer: The protobuf object to deserialize to @return: true if the message could be loaded and deserialized and false otherwise */ bool pylongps::loadProtobufObjectFromFile(const std::string &inputPath, google::protobuf::Message &inputMessageBuffer) { //Read size of object in file std::string sizeString; if(readStringFromFile(sizeString, sizeof(Poco::Int64), inputPath) == false) { return false; } Poco::Int64 objectSizeNetworkOrder = *((Poco::Int64 *) sizeString.c_str()); Poco::Int64 objectSize = Poco::ByteOrder::fromNetwork(objectSizeNetworkOrder); //Read size+object std::string sizeAndObjectString; if(readStringFromFile(sizeAndObjectString, sizeof(Poco::Int64)+objectSize, inputPath) == false) { return false; } //Clip off size std::string objectString = sizeAndObjectString.substr(sizeof(Poco::Int64)); //Deserialize the protobuf object inputMessageBuffer.ParseFromString(objectString); if(!inputMessageBuffer.IsInitialized()) { printf("Message not initialized\n"); return false; } return true; }
// Write out the given protobuf to the specified file descriptor by // first writing out the length of the protobuf followed by the contents. // NOTE: On error, this may have written partial data to the file. inline Try<Nothing> write(int fd, const google::protobuf::Message& message) { if (!message.IsInitialized()) { return Error("Uninitialized protocol buffer"); } // First write the size of the protobuf. uint32_t size = message.ByteSize(); std::string bytes = std::string((char*) &size, sizeof(size)); Try<Nothing> result = os::write(fd, bytes); if (result.isError()) { return Error("Failed to write size: " + result.error()); } if (!message.SerializeToFileDescriptor(fd)) { return Error("Failed to write/serialize message"); } return Nothing(); }
// Write out the given protobuf to the specified file descriptor by // first writing out the length of the protobuf followed by the // contents. inline Result<bool> write(int fd, const google::protobuf::Message& message) { if (!message.IsInitialized()) { LOG(ERROR) << "Failed to write protocol buffer to file, " << "protocol buffer is not initialized!"; return false; } uint32_t size = message.ByteSize(); ssize_t length = ::write(fd, (void*) &size, sizeof(size)); if (length == -1) { std::string error = strerror(errno); error = error + " (" + __FILE__ + ":" + utils::stringify(__LINE__) + ")"; return Result<bool>::error(error); } CHECK(length != 0); CHECK(length == sizeof(size)); // TODO(benh): Handle a non-blocking fd? return message.SerializeToFileDescriptor(fd); }
/** This function is used to receive and deserialize a protobuf object from a ZMQ socket. @param inputSocketToReceiveFrom: This is the socket to receive the object from @param inputMessageBuffer: This is the buffer to place the received object in @param inputFlags: The flags to pass to the ZMQ socket @param inputPreappendedDataBuffer: The buffer to place x bytes before the message in @param inputPreappendedDataSize: How much data to expect to be preappended @param inputPostappendedDataBuffer: The buffer to place x bytes before the message in @param inputPostappendedDataSize: How much data to expect to be postappended @return: <true if message received, true if message deserialized correctly> @throws: This function can throw exceptions */ std::tuple<bool, bool> pylongps::receiveProtobufMessage(zmq::socket_t &inputSocketToReceiveFrom, google::protobuf::Message &inputMessageBuffer, int inputFlags, char *inputPreappendedDataBuffer, int inputPreappendedDataSize, char *inputPostappendedDataBuffer, int inputPostappendedDataSize) { if(inputPreappendedDataSize < 0 || inputPostappendedDataSize < 0) { throw SOMException("Negative data size\n", INVALID_FUNCTION_INPUT, __FILE__, __LINE__); } if((inputPreappendedDataSize > 0 && inputPreappendedDataBuffer == nullptr) || (inputPostappendedDataSize < 0 && inputPostappendedDataBuffer == nullptr)) { throw SOMException("Data size > 0 but buffer is nullptr\n", INVALID_FUNCTION_INPUT, __FILE__, __LINE__); } bool messageReceived = false; bool messageDeserialized = false; std::unique_ptr<zmq::message_t> messageBuffer; SOM_TRY messageBuffer.reset(new zmq::message_t); SOM_CATCH("Error initializing ZMQ message") SOM_TRY messageReceived = inputSocketToReceiveFrom.recv(messageBuffer.get(), inputFlags); SOM_CATCH("Error, unable to receive message\n") if(messageReceived == false) { //Didn't get a message return std::tuple<bool, bool>(messageReceived, messageDeserialized); } //Attempt to retrieve any preappended data if(messageBuffer->size() < inputPreappendedDataSize) { //Message isn't valid (smaller than expected preappended data) return std::tuple<bool, bool>(messageReceived, messageDeserialized); } else if(inputPreappendedDataSize > 0) { //Preappended data is expected and the message is large enough to get it memcpy((void *) inputPreappendedDataBuffer, messageBuffer->data(), inputPreappendedDataSize); } //Deserialize message inputMessageBuffer.ParseFromArray(((char *) messageBuffer->data())+inputPreappendedDataSize, messageBuffer->size()-inputPreappendedDataSize); if(!inputMessageBuffer.IsInitialized()) { return std::tuple<bool, bool>(messageReceived, messageDeserialized); } if(inputPostappendedDataSize > 0) { int protobufMessageSize = inputMessageBuffer.ByteSize(); if((protobufMessageSize+inputPreappendedDataSize+inputPostappendedDataSize) > messageBuffer->size()) { return std::tuple<bool, bool>(messageReceived, messageDeserialized); } else { memcpy((void *) inputPostappendedDataBuffer, (void *) (((char *) messageBuffer->data()) + protobufMessageSize + inputPreappendedDataSize), inputPostappendedDataSize); messageDeserialized = true; } } else { messageDeserialized = true; } return std::tuple<bool, bool>(messageReceived, messageDeserialized); }
mori::TcpConnBuffer Codec::Encode( const google::protobuf::Message& msg, const SEncodeContext& context ) { assert(msg.IsInitialized()); CodecProtocol::Codec encodeMsg; encodeMsg.set_msgname(msg.GetDescriptor()->full_name()); encodeMsg.set_clienttype(context.ClientType_); if ( context.UserID_ ) { encodeMsg.set_userid(*context.UserID_); } if ( context.VerifyCode_ ) { encodeMsg.set_verifycode(*context.VerifyCode_); } std::string msgBuf; msg.SerializeToString(&msgBuf); auto bContinue = true; auto step = 0; while ( bContinue ) { switch (step) { case 0: { if ( !context.AESKey_.empty() ) { msgBuf = FastEncrypt::AES_CBCEncrypt(context.AESKey_, msgBuf); encodeMsg.set_aeskey(context.AESKey_); } ++step; }break; case 1: { if ( !context.RSAKey_.empty() && !context.AESKey_.empty() ) { auto EncryptAESKey = FastEncrypt::RSA_PubEncrypt(context.RSAKey_, context.AESKey_); encodeMsg.mutable_aeskey()->swap(EncryptAESKey); encodeMsg.set_rsaencode(true); } ++step; } break; case 2: { if ( context.Compress_ ) { auto compSize = compressBound(msgBuf.size()); std::string tmpbuf; tmpbuf.resize(compSize); auto err = compress(reinterpret_cast<Bytef*>(&tmpbuf[0]), &compSize, reinterpret_cast<const Bytef*>(msgBuf.data()), msgBuf.size()); if ( Z_OK != err ) { assert(0); bContinue = false; } else { encodeMsg.set_rawsize(msgBuf.size()); msgBuf.clear(); tmpbuf.resize(compSize); msgBuf.swap(tmpbuf); } } ++step; } break; default: { bContinue = false; } break; } } mori::TcpConnBuffer ret(sizeof(uint32_t)+encodeMsg.ByteSize()); encodeMsg.SerializeToArray(ret.data()+sizeof(uint32_t), ret.size()-sizeof(uint32_t)); uint32_t* pSize = reinterpret_cast<uint32_t*>(ret.data()); *pSize = boost::asio::detail::socket_ops::host_to_network_long(encodeMsg.ByteSize()); ret.reserve(ret.size()+msgBuf.size()); std::copy(msgBuf.begin(), msgBuf.end(), std::back_inserter(ret)); return std::move(ret); }