Upstream version 11.39.250.0
[platform/framework/web/crosswalk.git] / src / components / pairing / bluetooth_host_pairing_controller.cc
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