e83e9b7479fcb2f96d0d95b171739e1a5b6d2772
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / easy_unlock_private / easy_unlock_private_bluetooth_util_chromeos.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 "chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_bluetooth_util.h"
6
7 #include <stdint.h>
8 #include <bluetooth/bluetooth.h>
9 #include <bluetooth/l2cap.h>
10 #include <bluetooth/sdp.h>
11 #include <sys/socket.h>
12 #include <algorithm>
13 #include <vector>
14
15 #include "base/bind.h"
16 #include "base/callback.h"
17 #include "base/numerics/safe_conversions.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/string_split.h"
20 #include "base/task_runner_util.h"
21 #include "base/threading/sequenced_worker_pool.h"
22 #include "base/time/time.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "device/bluetooth/bluetooth_device.h"
25 #include "net/socket/socket_descriptor.h"
26
27 namespace extensions {
28 namespace api {
29 namespace easy_unlock {
30 namespace {
31
32 using device::BluetoothDevice;
33
34 const char kInvalidDeviceAddress[] =
35     "Given address is not a valid Bluetooth device.";
36 const char kUnableToConnectToDevice[] =
37     "Unable to connect to the remote device.";
38
39 // Delay prior to closing an SDP connection opened to register a Bluetooth
40 // device with the system BlueZ daemon.
41 const int kCloseSDPConnectionDelaySec = 5;
42
43 // Writes |address| into the |result|. Return true on success, false if the
44 // |address| is not a valid Bluetooth address.
45 bool BluetoothAddressToBdaddr(const std::string& address,
46                               bdaddr_t* result) {
47   std::string canonical_address = BluetoothDevice::CanonicalizeAddress(address);
48   if (canonical_address.empty())
49     return false;
50
51   std::vector<std::string> octets;
52   base::SplitString(canonical_address, ':', &octets);
53   DCHECK_EQ(octets.size(), 6U);
54
55   // BlueZ expects the octets in the reverse order.
56   std::reverse(octets.begin(), octets.end());
57   for (size_t i = 0; i < octets.size(); ++i) {
58     uint32_t octet;
59     bool success = base::HexStringToUInt(octets[i], &octet);
60     DCHECK(success);
61     result->b[i] = base::checked_cast<uint8_t>(octet);
62   }
63
64   return true;
65 }
66
67 // Closes the socket with the given |socket_descriptor|.
68 void CloseSocket(net::SocketDescriptor socket_descriptor) {
69   int result = close(socket_descriptor);
70   DCHECK_EQ(result, 0);
71 }
72
73 // Connects to the SDP service on the Bluetooth device with the given
74 // |device_address|, if possible. Returns an indicator of success or an error
75 // message on failure.
76 SeekDeviceResult SeekBluetoothDeviceByAddressImpl(
77     const std::string& device_address) {
78   base::TaskRunner* blocking_pool = content::BrowserThread::GetBlockingPool();
79   DCHECK(blocking_pool->RunsTasksOnCurrentThread());
80
81   SeekDeviceResult seek_result;
82   seek_result.success = false;
83
84   struct sockaddr_l2 addr;
85   memset(&addr, 0, sizeof(addr));
86   addr.l2_family = AF_BLUETOOTH;
87   addr.l2_psm = htobs(SDP_PSM);
88   if (!BluetoothAddressToBdaddr(device_address, &addr.l2_bdaddr)) {
89     seek_result.error_message = kInvalidDeviceAddress;
90     return seek_result;
91   }
92
93   net::SocketDescriptor socket_descriptor =
94       socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
95   int result = connect(socket_descriptor,
96                        reinterpret_cast<struct sockaddr *>(&addr),
97                        sizeof(addr));
98   if (result == 0) {
99     seek_result.success = true;
100     blocking_pool->PostDelayedTask(
101         FROM_HERE,
102         base::Bind(&CloseSocket, socket_descriptor),
103         base::TimeDelta::FromSeconds(kCloseSDPConnectionDelaySec));
104   } else {
105     // TODO(isherman): Pass a better message based on the errno?
106     seek_result.error_message = kUnableToConnectToDevice;
107   }
108   return seek_result;
109 }
110
111 }  // namespace
112
113 void SeekBluetoothDeviceByAddress(const std::string& device_address,
114                                   const SeekDeviceCallback& callback) {
115   base::PostTaskAndReplyWithResult(
116       content::BrowserThread::GetBlockingPool(),
117       FROM_HERE,
118       base::Bind(&SeekBluetoothDeviceByAddressImpl, device_address),
119       callback);
120 }
121
122 }  // namespace easy_unlock
123 }  // namespace api
124 }  // namespace extensions