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/bluetooth_host_pairing_controller.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/hash.h"
      9 #include "base/logging.h"
     10 #include "base/strings/stringprintf.h"
     11 #include "components/pairing/bluetooth_pairing_constants.h"
     12 #include "components/pairing/pairing_api.pb.h"
     13 #include "components/pairing/proto_decoder.h"
     14 #include "device/bluetooth/bluetooth_adapter_factory.h"
     15 #include "net/base/io_buffer.h"
     16 
     17 namespace {
     18 const int kReceiveSize = 16384;
     19 }
     20 
     21 namespace pairing_chromeos {
     22 
     23 BluetoothHostPairingController::BluetoothHostPairingController()
     24     : current_stage_(STAGE_NONE),
     25       device_(NULL),
     26       proto_decoder_(new ProtoDecoder(this)),
     27       ptr_factory_(this) {
     28 }
     29 
     30 BluetoothHostPairingController::~BluetoothHostPairingController() {
     31   if (adapter_.get()) {
     32     if (adapter_->IsDiscoverable()) {
     33       adapter_->SetDiscoverable(false, base::Closure(), base::Closure());
     34     }
     35     adapter_->RemoveObserver(this);
     36     adapter_ = NULL;
     37   }
     38 }
     39 
     40 void BluetoothHostPairingController::ChangeStage(Stage new_stage) {
     41   if (current_stage_ == new_stage)
     42     return;
     43   current_stage_ = new_stage;
     44   FOR_EACH_OBSERVER(Observer, observers_, PairingStageChanged(new_stage));
     45 }
     46 
     47 void BluetoothHostPairingController::SendHostStatus() {
     48   pairing_api::HostStatus host_status;
     49 
     50   host_status.set_api_version(kPairingAPIVersion);
     51   if (!enrollment_domain_.empty())
     52     host_status.mutable_parameters()->set_domain(enrollment_domain_);
     53 
     54   // TODO(zork): Get these values from the UI. (http://crbug.com/405744)
     55   host_status.mutable_parameters()->set_connectivity(
     56       pairing_api::HostStatusParameters::CONNECTIVITY_CONNECTED);
     57   host_status.mutable_parameters()->set_update_status(
     58       pairing_api::HostStatusParameters::UPDATE_STATUS_UPDATED);
     59 
     60   // TODO(zork): Get a list of other paired controllers.
     61   // (http://crbug.com/405757)
     62 
     63   int size = 0;
     64   scoped_refptr<net::IOBuffer> io_buffer(
     65       ProtoDecoder::SendHostStatus(host_status, &size));
     66 
     67   controller_socket_->Send(
     68       io_buffer, size,
     69       base::Bind(&BluetoothHostPairingController::OnSendComplete,
     70                  ptr_factory_.GetWeakPtr()),
     71       base::Bind(&BluetoothHostPairingController::OnSendError,
     72                  ptr_factory_.GetWeakPtr()));
     73 }
     74 
     75 void BluetoothHostPairingController::AbortWithError(
     76     int code,
     77     const std::string& message) {
     78   if (controller_socket_.get()) {
     79     pairing_api::Error error;
     80 
     81     error.set_api_version(kPairingAPIVersion);
     82     error.mutable_parameters()->set_code(PAIRING_ERROR_PAIRING_OR_ENROLLMENT);
     83     error.mutable_parameters()->set_description(message);
     84 
     85     int size = 0;
     86     scoped_refptr<net::IOBuffer> io_buffer(
     87         ProtoDecoder::SendError(error, &size));
     88 
     89     controller_socket_->Send(
     90         io_buffer, size,
     91         base::Bind(&BluetoothHostPairingController::OnSendComplete,
     92                    ptr_factory_.GetWeakPtr()),
     93         base::Bind(&BluetoothHostPairingController::OnSendError,
     94                    ptr_factory_.GetWeakPtr()));
     95   }
     96   Reset();
     97 }
     98 
     99 void BluetoothHostPairingController::Reset() {
    100   if (controller_socket_.get()) {
    101     controller_socket_->Close();
    102     controller_socket_ = NULL;
    103   }
    104 
    105   if (service_socket_.get()) {
    106     service_socket_->Close();
    107     service_socket_ = NULL;
    108   }
    109   ChangeStage(STAGE_NONE);
    110 }
    111 
    112 void BluetoothHostPairingController::OnGetAdapter(
    113     scoped_refptr<device::BluetoothAdapter> adapter) {
    114   DCHECK(thread_checker_.CalledOnValidThread());
    115   DCHECK(!adapter_.get());
    116   adapter_ = adapter;
    117 
    118   if (adapter_->IsPresent()) {
    119     SetName();
    120   } else {
    121     // Set the name once the adapter is present.
    122     adapter_->AddObserver(this);
    123   }
    124 }
    125 
    126 void BluetoothHostPairingController::SetName() {
    127   // Hash the bluetooth address and take the lower 2 bytes to create a human
    128   // readable device name.
    129   const uint32 device_id = base::Hash(adapter_->GetAddress()) & 0xFFFF;
    130   device_name_ = base::StringPrintf("%s%04X", kDeviceNamePrefix, device_id);
    131 
    132   adapter_->SetName(
    133       device_name_,
    134       base::Bind(&BluetoothHostPairingController::OnSetName,
    135                  ptr_factory_.GetWeakPtr()),
    136       base::Bind(&BluetoothHostPairingController::OnSetError,
    137                  ptr_factory_.GetWeakPtr()));
    138 }
    139 
    140 void BluetoothHostPairingController::OnSetName() {
    141   DCHECK(thread_checker_.CalledOnValidThread());
    142   if (adapter_->IsPowered()) {
    143     OnSetPowered();
    144   } else {
    145     adapter_->SetPowered(
    146         true,
    147         base::Bind(&BluetoothHostPairingController::OnSetPowered,
    148                    ptr_factory_.GetWeakPtr()),
    149         base::Bind(&BluetoothHostPairingController::OnSetError,
    150                    ptr_factory_.GetWeakPtr()));
    151   }
    152 }
    153 
    154 void BluetoothHostPairingController::OnSetPowered() {
    155   DCHECK(thread_checker_.CalledOnValidThread());
    156   adapter_->AddPairingDelegate(
    157       this, device::BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH);
    158 
    159   device::BluetoothAdapter::ServiceOptions options;
    160   options.name.reset(new std::string(kPairingServiceName));
    161 
    162   adapter_->CreateRfcommService(
    163       device::BluetoothUUID(kPairingServiceUUID), options,
    164       base::Bind(&BluetoothHostPairingController::OnCreateService,
    165                  ptr_factory_.GetWeakPtr()),
    166       base::Bind(&BluetoothHostPairingController::OnCreateServiceError,
    167                  ptr_factory_.GetWeakPtr()));
    168 }
    169 
    170 void BluetoothHostPairingController::OnCreateService(
    171     scoped_refptr<device::BluetoothSocket> socket) {
    172   DCHECK(thread_checker_.CalledOnValidThread());
    173   service_socket_ = socket;
    174 
    175   service_socket_->Accept(
    176       base::Bind(&BluetoothHostPairingController::OnAccept,
    177                  ptr_factory_.GetWeakPtr()),
    178       base::Bind(&BluetoothHostPairingController::OnAcceptError,
    179                  ptr_factory_.GetWeakPtr()));
    180 
    181   adapter_->SetDiscoverable(
    182       true,
    183       base::Bind(&BluetoothHostPairingController::OnSetDiscoverable,
    184                  ptr_factory_.GetWeakPtr(), true),
    185       base::Bind(&BluetoothHostPairingController::OnSetError,
    186                  ptr_factory_.GetWeakPtr()));
    187 }
    188 
    189 void BluetoothHostPairingController::OnAccept(
    190     const device::BluetoothDevice* device,
    191     scoped_refptr<device::BluetoothSocket> socket) {
    192   DCHECK(thread_checker_.CalledOnValidThread());
    193   adapter_->SetDiscoverable(
    194       false,
    195       base::Bind(&BluetoothHostPairingController::OnSetDiscoverable,
    196                  ptr_factory_.GetWeakPtr(), false),
    197       base::Bind(&BluetoothHostPairingController::OnSetError,
    198                  ptr_factory_.GetWeakPtr()));
    199 
    200   controller_socket_ = socket;
    201   service_socket_ = NULL;
    202 
    203   // TODO: Update Host. (http://crbug.com/405754)
    204   SendHostStatus();
    205 
    206   controller_socket_->Receive(
    207       kReceiveSize,
    208       base::Bind(&BluetoothHostPairingController::OnReceiveComplete,
    209                  ptr_factory_.GetWeakPtr()),
    210       base::Bind(&BluetoothHostPairingController::OnReceiveError,
    211                  ptr_factory_.GetWeakPtr()));
    212 
    213   ChangeStage(STAGE_WAITING_FOR_CREDENTIALS);
    214 }
    215 
    216 void BluetoothHostPairingController::OnSetDiscoverable(bool change_stage) {
    217   DCHECK(thread_checker_.CalledOnValidThread());
    218   if (change_stage) {
    219     DCHECK_EQ(current_stage_, STAGE_NONE);
    220     ChangeStage(STAGE_WAITING_FOR_CONTROLLER);
    221   }
    222 }
    223 
    224 void BluetoothHostPairingController::OnSendComplete(int bytes_sent) {}
    225 
    226 void BluetoothHostPairingController::OnReceiveComplete(
    227     int bytes, scoped_refptr<net::IOBuffer> io_buffer) {
    228   DCHECK(thread_checker_.CalledOnValidThread());
    229   proto_decoder_->DecodeIOBuffer(bytes, io_buffer);
    230 
    231   controller_socket_->Receive(
    232       kReceiveSize,
    233       base::Bind(&BluetoothHostPairingController::OnReceiveComplete,
    234                  ptr_factory_.GetWeakPtr()),
    235       base::Bind(&BluetoothHostPairingController::OnReceiveError,
    236                  ptr_factory_.GetWeakPtr()));
    237 }
    238 
    239 void BluetoothHostPairingController::OnCreateServiceError(
    240     const std::string& message) {
    241   LOG(ERROR) << message;
    242   ChangeStage(STAGE_INITIALIZATION_ERROR);
    243 }
    244 
    245 void BluetoothHostPairingController::OnSetError() {
    246   adapter_->RemovePairingDelegate(this);
    247   ChangeStage(STAGE_INITIALIZATION_ERROR);
    248 }
    249 
    250 void BluetoothHostPairingController::OnAcceptError(
    251     const std::string& error_message) {
    252   LOG(ERROR) << error_message;
    253 }
    254 
    255 void BluetoothHostPairingController::OnSendError(
    256     const std::string& error_message) {
    257   LOG(ERROR) << error_message;
    258 }
    259 
    260 void BluetoothHostPairingController::OnReceiveError(
    261     device::BluetoothSocket::ErrorReason reason,
    262     const std::string& error_message) {
    263   LOG(ERROR) << reason << ", " << error_message;
    264 }
    265 
    266 void BluetoothHostPairingController::OnHostStatusMessage(
    267     const pairing_api::HostStatus& message) {
    268   NOTREACHED();
    269 }
    270 
    271 void BluetoothHostPairingController::OnConfigureHostMessage(
    272     const pairing_api::ConfigureHost& message) {
    273   FOR_EACH_OBSERVER(Observer, observers_,
    274                     ConfigureHost(message.parameters().accepted_eula(),
    275                                   message.parameters().lang(),
    276                                   message.parameters().timezone(),
    277                                   message.parameters().send_reports(),
    278                                   message.parameters().keyboard_layout()));
    279 }
    280 
    281 void BluetoothHostPairingController::OnPairDevicesMessage(
    282     const pairing_api::PairDevices& message) {
    283   DCHECK(thread_checker_.CalledOnValidThread());
    284   if (current_stage_ != STAGE_WAITING_FOR_CREDENTIALS) {
    285     AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT, kErrorInvalidProtocol);
    286     return;
    287   }
    288 
    289   ChangeStage(STAGE_ENROLLING);
    290   FOR_EACH_OBSERVER(Observer, observers_,
    291                     EnrollHost(message.parameters().admin_access_token()));
    292 }
    293 
    294 void BluetoothHostPairingController::SetEnrollmentComplete(bool success) {
    295   DCHECK_EQ(current_stage_, STAGE_ENROLLING);
    296   DCHECK(thread_checker_.CalledOnValidThread());
    297   if (success) {
    298     ChangeStage(STAGE_PAIRING_DONE);
    299     SendHostStatus();
    300   } else {
    301     AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT, kErrorEnrollmentFailed);
    302   }
    303 }
    304 
    305 void BluetoothHostPairingController::OnCompleteSetupMessage(
    306     const pairing_api::CompleteSetup& message) {
    307   DCHECK(thread_checker_.CalledOnValidThread());
    308   if (current_stage_ != STAGE_PAIRING_DONE) {
    309     AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT, kErrorInvalidProtocol);
    310     return;
    311   }
    312 
    313   // TODO(zork): Handle adding another controller. (http://crbug.com/405757)
    314   ChangeStage(STAGE_FINISHED);
    315 }
    316 
    317 void BluetoothHostPairingController::OnErrorMessage(
    318     const pairing_api::Error& message) {
    319   NOTREACHED();
    320 }
    321 
    322 void BluetoothHostPairingController::AdapterPresentChanged(
    323     device::BluetoothAdapter* adapter,
    324     bool present) {
    325   DCHECK_EQ(adapter, adapter_.get());
    326   if (present) {
    327     adapter_->RemoveObserver(this);
    328     SetName();
    329   }
    330 }
    331 
    332 void BluetoothHostPairingController::AddObserver(Observer* observer) {
    333   observers_.AddObserver(observer);
    334 }
    335 
    336 void BluetoothHostPairingController::RemoveObserver(Observer* observer) {
    337   observers_.RemoveObserver(observer);
    338 }
    339 
    340 HostPairingController::Stage BluetoothHostPairingController::GetCurrentStage() {
    341   return current_stage_;
    342 }
    343 
    344 void BluetoothHostPairingController::StartPairing() {
    345   DCHECK_EQ(current_stage_, STAGE_NONE);
    346   bool bluetooth_available =
    347       device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable();
    348   if (!bluetooth_available) {
    349     ChangeStage(STAGE_INITIALIZATION_ERROR);
    350     return;
    351   }
    352 
    353   device::BluetoothAdapterFactory::GetAdapter(
    354       base::Bind(&BluetoothHostPairingController::OnGetAdapter,
    355                  ptr_factory_.GetWeakPtr()));
    356 }
    357 
    358 std::string BluetoothHostPairingController::GetDeviceName() {
    359   return device_name_;
    360 }
    361 
    362 std::string BluetoothHostPairingController::GetConfirmationCode() {
    363   DCHECK_EQ(current_stage_, STAGE_WAITING_FOR_CODE_CONFIRMATION);
    364   return confirmation_code_;
    365 }
    366 
    367 std::string BluetoothHostPairingController::GetEnrollmentDomain() {
    368   return enrollment_domain_;
    369 }
    370 
    371 void BluetoothHostPairingController::OnUpdateStatusChanged(
    372     UpdateStatus update_status) {
    373   // TODO(zork): Handling updating stages (http://crbug.com/405754).
    374 }
    375 
    376 void BluetoothHostPairingController::RequestPinCode(
    377     device::BluetoothDevice* device) {
    378   // Disallow unknown device.
    379   device->RejectPairing();
    380 }
    381 
    382 void BluetoothHostPairingController::RequestPasskey(
    383     device::BluetoothDevice* device) {
    384   // Disallow unknown device.
    385   device->RejectPairing();
    386 }
    387 
    388 void BluetoothHostPairingController::DisplayPinCode(
    389     device::BluetoothDevice* device,
    390     const std::string& pincode) {
    391   // Disallow unknown device.
    392   device->RejectPairing();
    393 }
    394 
    395 void BluetoothHostPairingController::DisplayPasskey(
    396     device::BluetoothDevice* device,
    397     uint32 passkey) {
    398   // Disallow unknown device.
    399   device->RejectPairing();
    400 }
    401 
    402 void BluetoothHostPairingController::KeysEntered(
    403     device::BluetoothDevice* device,
    404     uint32 entered) {
    405   // Disallow unknown device.
    406   device->RejectPairing();
    407 }
    408 
    409 void BluetoothHostPairingController::ConfirmPasskey(
    410     device::BluetoothDevice* device,
    411     uint32 passkey) {
    412   confirmation_code_ = base::StringPrintf("%06d", passkey);
    413   device->ConfirmPairing();
    414   ChangeStage(STAGE_WAITING_FOR_CODE_CONFIRMATION);
    415 }
    416 
    417 void BluetoothHostPairingController::AuthorizePairing(
    418     device::BluetoothDevice* device) {
    419   // Disallow unknown device.
    420   device->RejectPairing();
    421 }
    422 
    423 }  // namespace pairing_chromeos
    424