1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/pairing/proto_decoder.h"
6
7 #include "components/pairing/pairing_api.pb.h"
8 #include "net/base/io_buffer.h"
9
10 namespace {
11 enum {
12 MESSAGE_NONE,
13 MESSAGE_HOST_STATUS,
14 MESSAGE_CONFIGURE_HOST,
15 MESSAGE_PAIR_DEVICES,
16 MESSAGE_COMPLETE_SETUP,
17 MESSAGE_ERROR,
18 NUM_MESSAGES,
19 };
20 }
21
22 namespace pairing_chromeos {
23
ProtoDecoder(Observer * observer)24 ProtoDecoder::ProtoDecoder(Observer* observer)
25 : observer_(observer),
26 next_message_type_(MESSAGE_NONE),
27 next_message_size_(0) {
28 DCHECK(observer_);
29 }
30
~ProtoDecoder()31 ProtoDecoder::~ProtoDecoder() {}
32
DecodeIOBuffer(int size,ProtoDecoder::IOBufferRefPtr io_buffer)33 bool ProtoDecoder::DecodeIOBuffer(int size,
34 ProtoDecoder::IOBufferRefPtr io_buffer) {
35 // Update the message buffer.
36 message_buffer_.AddIOBuffer(io_buffer, size);
37
38 // If there is no current message, the next byte is the message type.
39 if (next_message_type_ == MESSAGE_NONE) {
40 if (message_buffer_.AvailableBytes() < static_cast<int>(sizeof(uint8_t)))
41 return true;
42
43 uint8_t message_type = MESSAGE_NONE;
44 message_buffer_.ReadBytes(reinterpret_cast<char*>(&message_type),
45 sizeof(message_type));
46
47 if (message_type == MESSAGE_NONE || message_type >= NUM_MESSAGES) {
48 LOG(ERROR) << "Unknown message type received: " << message_type;
49 return false;
50 }
51 next_message_type_ = message_type;
52 }
53
54 // If the message size isn't set, the next two bytes are the message size.
55 if (next_message_size_ == 0) {
56 if (message_buffer_.AvailableBytes() < static_cast<int>(sizeof(uint16_t)))
57 return true;
58
59 // The size is sent in network byte order.
60 uint8_t high_byte = 0;
61 message_buffer_.ReadBytes(reinterpret_cast<char*>(&high_byte),
62 sizeof(high_byte));
63 uint8_t low_byte = 0;
64 message_buffer_.ReadBytes(reinterpret_cast<char*>(&low_byte),
65 sizeof(low_byte));
66
67 next_message_size_ = (high_byte << 8) + low_byte;
68 }
69
70 // If the whole proto buffer is not yet available, return early.
71 if (message_buffer_.AvailableBytes() < next_message_size_)
72 return true;
73
74 std::vector<char> buffer(next_message_size_);
75 message_buffer_.ReadBytes(&buffer[0], next_message_size_);
76
77 switch (next_message_type_) {
78 case MESSAGE_HOST_STATUS: {
79 pairing_api::HostStatus message;
80 message.ParseFromArray(&buffer[0], buffer.size());
81 observer_->OnHostStatusMessage(message);
82 }
83 break;
84 case MESSAGE_CONFIGURE_HOST: {
85 pairing_api::ConfigureHost message;
86 message.ParseFromArray(&buffer[0], buffer.size());
87 observer_->OnConfigureHostMessage(message);
88 }
89 break;
90 case MESSAGE_PAIR_DEVICES: {
91 pairing_api::PairDevices message;
92 message.ParseFromArray(&buffer[0], buffer.size());
93 observer_->OnPairDevicesMessage(message);
94 }
95 break;
96 case MESSAGE_COMPLETE_SETUP: {
97 pairing_api::CompleteSetup message;
98 message.ParseFromArray(&buffer[0], buffer.size());
99 observer_->OnCompleteSetupMessage(message);
100 }
101 break;
102 case MESSAGE_ERROR: {
103 pairing_api::Error message;
104 message.ParseFromArray(&buffer[0], buffer.size());
105 observer_->OnErrorMessage(message);
106 }
107 break;
108
109 default:
110 NOTREACHED();
111 break;
112 }
113
114 // Reset the message data.
115 next_message_type_ = MESSAGE_NONE;
116 next_message_size_ = 0;
117
118 return true;
119 }
120
SendHostStatus(const pairing_api::HostStatus & message,int * size)121 ProtoDecoder::IOBufferRefPtr ProtoDecoder::SendHostStatus(
122 const pairing_api::HostStatus& message, int* size) {
123 std::string serialized_proto;
124 if (!message.SerializeToString(&serialized_proto)) {
125 NOTREACHED();
126 }
127
128 return SendMessage(MESSAGE_HOST_STATUS, serialized_proto, size);
129 }
130
SendConfigureHost(const pairing_api::ConfigureHost & message,int * size)131 ProtoDecoder::IOBufferRefPtr ProtoDecoder::SendConfigureHost(
132 const pairing_api::ConfigureHost& message, int* size) {
133 std::string serialized_proto;
134 if (!message.SerializeToString(&serialized_proto)) {
135 NOTREACHED();
136 }
137
138 return SendMessage(MESSAGE_CONFIGURE_HOST, serialized_proto, size);
139 }
140
SendPairDevices(const pairing_api::PairDevices & message,int * size)141 ProtoDecoder::IOBufferRefPtr ProtoDecoder::SendPairDevices(
142 const pairing_api::PairDevices& message, int* size) {
143 std::string serialized_proto;
144 if (!message.SerializeToString(&serialized_proto)) {
145 NOTREACHED();
146 }
147
148 return SendMessage(MESSAGE_PAIR_DEVICES, serialized_proto, size);
149 }
150
SendCompleteSetup(const pairing_api::CompleteSetup & message,int * size)151 ProtoDecoder::IOBufferRefPtr ProtoDecoder::SendCompleteSetup(
152 const pairing_api::CompleteSetup& message, int* size) {
153 std::string serialized_proto;
154 if (!message.SerializeToString(&serialized_proto)) {
155 NOTREACHED();
156 }
157
158 return SendMessage(MESSAGE_COMPLETE_SETUP, serialized_proto, size);
159 }
160
SendError(const pairing_api::Error & message,int * size)161 ProtoDecoder::IOBufferRefPtr ProtoDecoder::SendError(
162 const pairing_api::Error& message, int* size) {
163 std::string serialized_proto;
164 if (!message.SerializeToString(&serialized_proto)) {
165 NOTREACHED();
166 }
167
168 return SendMessage(MESSAGE_ERROR, serialized_proto, size);
169 }
170
SendMessage(uint8_t message_type,const std::string & message,int * size)171 ProtoDecoder::IOBufferRefPtr ProtoDecoder::SendMessage(
172 uint8_t message_type,
173 const std::string& message,
174 int* size) {
175 uint16_t message_size = message.size();
176
177 *size = sizeof(message_type) + sizeof(message_size) + message.size();
178 IOBufferRefPtr io_buffer(new net::IOBuffer(*size));
179
180 // Write the message type.
181 int offset = 0;
182 memcpy(&io_buffer->data()[offset], &message_type, sizeof(message_type));
183 offset += sizeof(message_type);
184
185 // Network byte order.
186 // Write the high byte of the size.
187 uint8_t data = (message_size >> 8) & 0xFF;
188 memcpy(&io_buffer->data()[offset], &data, sizeof(data));
189 offset += sizeof(data);
190 // Write the low byte of the size.
191 data = message_size & 0xFF;
192 memcpy(&io_buffer->data()[offset], &data, sizeof(data));
193 offset += sizeof(data);
194
195 // Write the actual message.
196 memcpy(&io_buffer->data()[offset], message.data(), message.size());
197
198 return io_buffer;
199 }
200
201 } // namespace pairing_chromeos
202