Commit f33c8675 authored by zork@chromium.org's avatar zork@chromium.org

Add ProtoDecoder for sending messages between Host and Controller when pairing

BUG=380961, 380962

Review URL: https://codereview.chromium.org/448273002

Cr-Commit-Position: refs/heads/master@{#289097}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@289097 0039d316-1c4b-4281-b951-d872f2087c98
parent f34acc69
......@@ -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',
],
},
{
......
......@@ -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 = [
......
// 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
// 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_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment