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 24 ProtoDecoder::ProtoDecoder(Observer* observer) 25 : observer_(observer), 26 next_message_type_(MESSAGE_NONE), 27 next_message_size_(0) { 28 DCHECK(observer_); 29 } 30 31 ProtoDecoder::~ProtoDecoder() {} 32 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 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 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 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 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 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 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