Home | History | Annotate | Download | only in pairing
      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