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"
8 #include <sys/socket.h>
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
33 } __attribute__((packed
));
35 // From <bluetooth/l2cap.h>:
37 sa_family_t l2_family
;
38 unsigned short l2_psm
;
40 unsigned short l2_cid
;
43 // From <bluetooth/sdp.h>:
44 #define SDP_PSM 0x0001
46 namespace proximity_auth
{
47 namespace bluetooth_util
{
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.
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())
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
) {
84 bool success
= base::HexStringToUInt(octets
[i
], &octet
);
86 result
->b
[i
] = base::checked_cast
<uint8_t>(octet
);
92 // Closes the socket with the given |socket_descriptor|.
93 void CloseSocket(net::SocketDescriptor socket_descriptor
) {
94 int result
= close(socket_descriptor
);
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
;
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
),
122 seek_result
.success
= true;
123 task_runner
->PostDelayedTask(
125 base::Bind(&CloseSocket
, socket_descriptor
),
126 base::TimeDelta::FromSeconds(kCloseSDPConnectionDelaySec
));
128 // TODO(isherman): Pass a better message based on the errno?
129 seek_result
.error_message
= kUnableToConnectToDevice
;
134 void OnSeekDeviceResult(const base::Closure
& callback
,
135 const ErrorCallback
& error_callback
,
136 const SeekDeviceResult
& result
) {
140 error_callback
.Run(result
.error_message
);
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(
152 base::Bind(&SeekDeviceByAddressImpl
,
154 make_scoped_refptr(task_runner
)),
155 base::Bind(&OnSeekDeviceResult
, callback
, error_callback
));
158 } // namespace bluetooth_util
159 } // namespace proximity_auth