• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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