Use multiline attribute to check for IA2_STATE_MULTILINE.
[chromium-blink-merge.git] / components / proximity_auth / bluetooth_util_chromeos.cc
blob86a0758fc913580f2287e14bcca444c9a842cb59
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.
5 #include "components/proximity_auth/bluetooth_util.h"
7 #include <stdint.h>
8 #include <sys/socket.h>
9 #include <algorithm>
10 #include <vector>
12 #include "base/bind.h"
13 #include "base/callback.h"
14 #include "base/location.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/numerics/safe_conversions.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/string_split.h"
19 #include "base/sys_byteorder.h"
20 #include "base/task_runner_util.h"
21 #include "base/threading/sequenced_worker_pool.h"
22 #include "base/time/time.h"
23 #include "device/bluetooth/bluetooth_device.h"
24 #include "net/socket/socket_descriptor.h"
26 // The bluez headers are (intentionally) not available within the Chromium
27 // repository, so several definitions from these headers are replicated below.
29 // From <bluetooth/bluetooth.h>:
30 #define BTPROTO_L2CAP 0
31 struct bdaddr_t {
32 uint8_t b[6];
33 } __attribute__((packed));
35 // From <bluetooth/l2cap.h>:
36 struct sockaddr_l2 {
37 sa_family_t l2_family;
38 unsigned short l2_psm;
39 bdaddr_t l2_bdaddr;
40 unsigned short l2_cid;
43 // From <bluetooth/sdp.h>:
44 #define SDP_PSM 0x0001
46 namespace proximity_auth {
47 namespace bluetooth_util {
48 namespace {
50 using device::BluetoothDevice;
52 const char kInvalidDeviceAddress[] =
53 "Given address is not a valid Bluetooth device.";
54 const char kUnableToConnectToDevice[] =
55 "Unable to connect to the remote device.";
57 // Delay prior to closing an SDP connection opened to register a Bluetooth
58 // device with the system BlueZ daemon.
59 const int kCloseSDPConnectionDelaySec = 5;
61 struct SeekDeviceResult {
62 // Whether the connection to the device succeeded.
63 bool success;
65 // If the connection failed, an error message describing the failure.
66 std::string error_message;
69 // Writes |address| into the |result|. Return true on success, false if the
70 // |address| is not a valid Bluetooth address.
71 bool BluetoothAddressToBdaddr(const std::string& address, bdaddr_t* result) {
72 std::string canonical_address = BluetoothDevice::CanonicalizeAddress(address);
73 if (canonical_address.empty())
74 return false;
76 std::vector<std::string> octets;
77 base::SplitString(canonical_address, ':', &octets);
78 DCHECK_EQ(octets.size(), 6U);
80 // BlueZ expects the octets in the reverse order.
81 std::reverse(octets.begin(), octets.end());
82 for (size_t i = 0; i < octets.size(); ++i) {
83 uint32_t octet;
84 bool success = base::HexStringToUInt(octets[i], &octet);
85 DCHECK(success);
86 result->b[i] = base::checked_cast<uint8_t>(octet);
89 return true;
92 // Closes the socket with the given |socket_descriptor|.
93 void CloseSocket(net::SocketDescriptor socket_descriptor) {
94 int result = close(socket_descriptor);
95 DCHECK_EQ(result, 0);
98 // Connects to the SDP service on the Bluetooth device with the given
99 // |device_address|, if possible. Returns an indicator of success or an error
100 // message on failure.
101 SeekDeviceResult SeekDeviceByAddressImpl(
102 const std::string& device_address,
103 scoped_refptr<base::TaskRunner> task_runner) {
104 SeekDeviceResult seek_result;
105 seek_result.success = false;
107 struct sockaddr_l2 addr;
108 memset(&addr, 0, sizeof(addr));
109 addr.l2_family = AF_BLUETOOTH;
110 addr.l2_psm = base::ByteSwapToLE16(SDP_PSM);
111 if (!BluetoothAddressToBdaddr(device_address, &addr.l2_bdaddr)) {
112 seek_result.error_message = kInvalidDeviceAddress;
113 return seek_result;
116 net::SocketDescriptor socket_descriptor =
117 socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
118 int result = connect(socket_descriptor,
119 reinterpret_cast<struct sockaddr*>(&addr),
120 sizeof(addr));
121 if (result == 0) {
122 seek_result.success = true;
123 task_runner->PostDelayedTask(
124 FROM_HERE,
125 base::Bind(&CloseSocket, socket_descriptor),
126 base::TimeDelta::FromSeconds(kCloseSDPConnectionDelaySec));
127 } else {
128 // TODO(isherman): Pass a better message based on the errno?
129 seek_result.error_message = kUnableToConnectToDevice;
131 return seek_result;
134 void OnSeekDeviceResult(const base::Closure& callback,
135 const ErrorCallback& error_callback,
136 const SeekDeviceResult& result) {
137 if (result.success)
138 callback.Run();
139 else
140 error_callback.Run(result.error_message);
143 } // namespace
145 void SeekDeviceByAddress(const std::string& device_address,
146 const base::Closure& callback,
147 const ErrorCallback& error_callback,
148 base::TaskRunner* task_runner) {
149 base::PostTaskAndReplyWithResult(
150 task_runner,
151 FROM_HERE,
152 base::Bind(&SeekDeviceByAddressImpl,
153 device_address,
154 make_scoped_refptr(task_runner)),
155 base::Bind(&OnSeekDeviceResult, callback, error_callback));
158 } // namespace bluetooth_util
159 } // namespace proximity_auth