diff options
Diffstat (limited to 'components/pairing/proto_decoder.cc')
-rw-r--r-- | components/pairing/proto_decoder.cc | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/components/pairing/proto_decoder.cc b/components/pairing/proto_decoder.cc new file mode 100644 index 0000000..96b3c24 --- /dev/null +++ b/components/pairing/proto_decoder.cc @@ -0,0 +1,201 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/pairing/proto_decoder.h" + +#include "components/pairing/pairing_api.pb.h" +#include "net/base/io_buffer.h" + +namespace { +enum { + MESSAGE_NONE, + MESSAGE_HOST_STATUS, + MESSAGE_CONFIGURE_HOST, + MESSAGE_PAIR_DEVICES, + MESSAGE_COMPLETE_SETUP, + MESSAGE_ERROR, + NUM_MESSAGES, +}; +} + +namespace pairing_chromeos { + +ProtoDecoder::ProtoDecoder(Observer* observer) + : observer_(observer), + next_message_type_(MESSAGE_NONE), + next_message_size_(0) { + DCHECK(observer_); +} + +ProtoDecoder::~ProtoDecoder() {} + +bool ProtoDecoder::DecodeIOBuffer(int size, + ProtoDecoder::IOBufferRefPtr io_buffer) { + // Update the message buffer. + message_buffer_.AddIOBuffer(io_buffer, size); + + // If there is no current message, the next byte is the message type. + if (next_message_type_ == MESSAGE_NONE) { + if (message_buffer_.AvailableBytes() < static_cast<int>(sizeof(uint8_t))) + return true; + + uint8_t message_type = MESSAGE_NONE; + message_buffer_.ReadBytes(reinterpret_cast<char*>(&message_type), + sizeof(message_type)); + + if (message_type == MESSAGE_NONE || message_type >= NUM_MESSAGES) { + LOG(ERROR) << "Unknown message type received: " << message_type; + return false; + } + next_message_type_ = message_type; + } + + // If the message size isn't set, the next two bytes are the message size. + if (next_message_size_ == 0) { + if (message_buffer_.AvailableBytes() < static_cast<int>(sizeof(uint16_t))) + return true; + + // The size is sent in network byte order. + uint8_t high_byte = 0; + message_buffer_.ReadBytes(reinterpret_cast<char*>(&high_byte), + sizeof(high_byte)); + uint8_t low_byte = 0; + message_buffer_.ReadBytes(reinterpret_cast<char*>(&low_byte), + sizeof(low_byte)); + + next_message_size_ = (high_byte << 8) + low_byte; + } + + // If the whole proto buffer is not yet available, return early. + if (message_buffer_.AvailableBytes() < next_message_size_) + return true; + + std::vector<char> buffer(next_message_size_); + message_buffer_.ReadBytes(&buffer[0], next_message_size_); + + switch (next_message_type_) { + case MESSAGE_HOST_STATUS: { + pairing_api::HostStatus message; + message.ParseFromArray(&buffer[0], buffer.size()); + observer_->OnHostStatusMessage(message); + } + break; + case MESSAGE_CONFIGURE_HOST: { + pairing_api::ConfigureHost message; + message.ParseFromArray(&buffer[0], buffer.size()); + observer_->OnConfigureHostMessage(message); + } + break; + case MESSAGE_PAIR_DEVICES: { + pairing_api::PairDevices message; + message.ParseFromArray(&buffer[0], buffer.size()); + observer_->OnPairDevicesMessage(message); + } + break; + case MESSAGE_COMPLETE_SETUP: { + pairing_api::CompleteSetup message; + message.ParseFromArray(&buffer[0], buffer.size()); + observer_->OnCompleteSetupMessage(message); + } + break; + case MESSAGE_ERROR: { + pairing_api::Error message; + message.ParseFromArray(&buffer[0], buffer.size()); + observer_->OnErrorMessage(message); + } + break; + + default: + NOTREACHED(); + break; + } + + // Reset the message data. + next_message_type_ = MESSAGE_NONE; + next_message_size_ = 0; + + return true; +} + +ProtoDecoder::IOBufferRefPtr ProtoDecoder::SendHostStatus( + const pairing_api::HostStatus& message, int* size) { + std::string serialized_proto; + if (!message.SerializeToString(&serialized_proto)) { + NOTREACHED(); + } + + return SendMessage(MESSAGE_HOST_STATUS, serialized_proto, size); +} + +ProtoDecoder::IOBufferRefPtr ProtoDecoder::SendConfigureHost( + const pairing_api::ConfigureHost& message, int* size) { + std::string serialized_proto; + if (!message.SerializeToString(&serialized_proto)) { + NOTREACHED(); + } + + return SendMessage(MESSAGE_CONFIGURE_HOST, serialized_proto, size); +} + +ProtoDecoder::IOBufferRefPtr ProtoDecoder::SendPairDevices( + const pairing_api::PairDevices& message, int* size) { + std::string serialized_proto; + if (!message.SerializeToString(&serialized_proto)) { + NOTREACHED(); + } + + return SendMessage(MESSAGE_PAIR_DEVICES, serialized_proto, size); +} + +ProtoDecoder::IOBufferRefPtr ProtoDecoder::SendCompleteSetup( + const pairing_api::CompleteSetup& message, int* size) { + std::string serialized_proto; + if (!message.SerializeToString(&serialized_proto)) { + NOTREACHED(); + } + + return SendMessage(MESSAGE_COMPLETE_SETUP, serialized_proto, size); +} + +ProtoDecoder::IOBufferRefPtr ProtoDecoder::SendError( + const pairing_api::Error& message, int* size) { + std::string serialized_proto; + if (!message.SerializeToString(&serialized_proto)) { + NOTREACHED(); + } + + return SendMessage(MESSAGE_ERROR, serialized_proto, size); +} + +ProtoDecoder::IOBufferRefPtr ProtoDecoder::SendMessage( + uint8_t message_type, + const std::string& message, + int* size) { + uint16_t message_size = message.size(); + + *size = sizeof(message_type) + sizeof(message_size) + message.size(); + IOBufferRefPtr io_buffer(new net::IOBuffer(*size)); + + // Write the message type. + int offset = 0; + memcpy(&io_buffer->data()[offset], &message_type, sizeof(message_type)); + offset += sizeof(message_type); + + // Network byte order. + // Write the high byte of the size. + uint8_t data = (message_size >> 8) & 0xFF; + memcpy(&io_buffer->data()[offset], &data, sizeof(data)); + offset += sizeof(data); + // Write the low byte of the size. + data = message_size & 0xFF; + memcpy(&io_buffer->data()[offset], &data, sizeof(data)); + offset += sizeof(data); + + // Write the actual message. + memcpy(&io_buffer->data()[offset], message.data(), message.size()); + + return io_buffer; +} + +} // namespace pairing_chromeos |