diff options
Diffstat (limited to 'components')
-rw-r--r-- | components/pairing.gypi | 2 | ||||
-rw-r--r-- | components/pairing/BUILD.gn | 2 | ||||
-rw-r--r-- | components/pairing/proto_decoder.cc | 201 | ||||
-rw-r--r-- | components/pairing/proto_decoder.h | 91 |
4 files changed, 296 insertions, 0 deletions
diff --git a/components/pairing.gypi b/components/pairing.gypi index 35f13c9..4dd03d1 100644 --- a/components/pairing.gypi +++ b/components/pairing.gypi @@ -27,6 +27,8 @@ 'pairing/host_pairing_controller.h', 'pairing/message_buffer.cc', 'pairing/message_buffer.h', + 'pairing/proto_decoder.cc', + 'pairing/proto_decoder.h', ], }, { diff --git a/components/pairing/BUILD.gn b/components/pairing/BUILD.gn index 55f29ed..d017ec4 100644 --- a/components/pairing/BUILD.gn +++ b/components/pairing/BUILD.gn @@ -16,6 +16,8 @@ source_set("pairing") { "pairing/host_pairing_controller.h", "pairing/message_buffer.cc", "pairing/message_buffer.h", + "pairing/proto_decoder.cc", + "pairing/proto_decoder.h", ] deps = [ 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 diff --git a/components/pairing/proto_decoder.h b/components/pairing/proto_decoder.h new file mode 100644 index 0000000..e36eb7f --- /dev/null +++ b/components/pairing/proto_decoder.h @@ -0,0 +1,91 @@ +// 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. + +#ifndef COMPONENTS_PAIRING_PROTO_DECODER_H_ +#define COMPONENTS_PAIRING_PROTO_DECODER_H_ + +#include <deque> + +#include "base/logging.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "components/pairing/message_buffer.h" + +namespace net { +class IOBuffer; +} + +namespace pairing_api { +class CompleteSetup; +class ConfigureHost; +class Error; +class HostStatus; +class PairDevices; +} // namespace pairing_api + +namespace pairing_chromeos { + +// A ProtoDecoder collects data from a series of IOBuffers and decodes Proto +// buffers from the data. The decoded messages are then forwarded to an +// observer. +class ProtoDecoder { + public: + typedef scoped_refptr<net::IOBuffer> IOBufferRefPtr; + class Observer { + public: + virtual ~Observer() {} + + virtual void OnHostStatusMessage( + const pairing_api::HostStatus& message) = 0; + virtual void OnConfigureHostMessage( + const pairing_api::ConfigureHost& message) = 0; + virtual void OnPairDevicesMessage( + const pairing_api::PairDevices& message) = 0; + virtual void OnCompleteSetupMessage( + const pairing_api::CompleteSetup& message) = 0; + virtual void OnErrorMessage( + const pairing_api::Error& message) = 0; + + protected: + Observer() {} + + private: + DISALLOW_COPY_AND_ASSIGN(Observer); + }; + + explicit ProtoDecoder(Observer* observer); + ~ProtoDecoder(); + + // Decodes the data from an io_buffer, and sends out events for any complete + // messages. + bool DecodeIOBuffer(int size, IOBufferRefPtr io_buffer); + + // Convenience functions for serializing messages into an IOBuffer. + static IOBufferRefPtr SendHostStatus(const pairing_api::HostStatus& message, + int* size); + static IOBufferRefPtr SendConfigureHost( + const pairing_api::ConfigureHost& message, int* size); + static IOBufferRefPtr SendPairDevices(const pairing_api::PairDevices& message, + int* size); + static IOBufferRefPtr SendCompleteSetup( + const pairing_api::CompleteSetup& message, int* size); + static IOBufferRefPtr SendError(const pairing_api::Error& message, int* size); + + private: + static IOBufferRefPtr SendMessage(uint8_t message_type, + const std::string& message, + int* size); + + Observer* observer_; + MessageBuffer message_buffer_; + int next_message_type_; + int next_message_size_; + + DISALLOW_COPY_AND_ASSIGN(ProtoDecoder); +}; + +} // namespace pairing_chromeos + +#endif // COMPONENTS_PAIRING_PROTO_DECODER_H_ |