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