Commit c40cd06b authored by Lan Wei's avatar Lan Wei Committed by Commit Bot

Revert "[Nearby] Create concrete BluetoothSocket and implement ConnectToService."

This reverts commit 261661bb.

Reason for revert:
BluetoothSocketTest.TestInputStream/TestOutputStream fails on Linux TSan Tests
https://ci.chromium.org/p/chromium/builders/ci/Linux%20TSan%20Tests/57982

Original change's description:
> [Nearby] Create concrete BluetoothSocket and implement ConnectToService.
> 
> Implement a concrete location::nearby::api::BluetoothSocket, created via
> a bluetooth::mojom::Socket and Mojo DataPipes supplied by the newly
> implemented BluetoothClassicMedium::ConnectToService().
> 
> Nearby Connections uses this BluetoothSocket to communicate with a
> remote device. At a high-level, it first exchanges frames to encrypt
> the connection, then delegates to its caller (e.g., Nearby Share)
> to authenticate the connection, and finally expects its caller to
> send and receive application-level messages. The following precautions
> are taken to handle untrusted bytes received from remote devices:
>   * Nearby Connections (including the code being added in this CL) is
>     hosted in a Nearby utility process.
>   * Whenever Nearby Connections provides bytes received from a remote
>     device to its caller, even after it has been authenticated, the
>     caller must not trust those bytes, and is responsible for first
>     passing those bytes through the trusted NearbyDecoder interface
>     (see go/nearby-chrome-mojo). NearbyDecoder is hosted in the same
>     Nearby utility process.
> 
> api::BluetoothSocket is a synchronous interface, so this
> implementation consumes the synchronous signatures of
> bluetooth::mojom::Socket methods.
> 
> api::BluetoothSocket's subclasses are also synchronous interfaces,
> but the Mojo DataPipes they consume only provide asynchronous
> interfaces. This is reconciled by blocking on the caller thread when
> waiting (via a mojo::SimpleWatcher) for the DataPipes to become
> readable or writable (this is expected by the callers of
> api::BluetoothSocket's subclasses). Mojo DataPipe operations are
> handled on a separate task runner so that blocking on the calling
> thread will not deadlock.
> 
> Please see design doc go/nearby-chrome-bt for more details.
> 
> Bug: b:154849033, b:158848873
> Change-Id: I2e945277aa1f75b4ca378d0b961f7682ff25d812
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2322166
> Commit-Queue: Ryan Hansberry <hansberry@chromium.org>
> Reviewed-by: Alex Chau <alexchau@chromium.org>
> Reviewed-by: James Vecore <vecore@google.com>
> Reviewed-by: Reilly Grant <reillyg@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#797758}

TBR=reillyg@chromium.org,hansberry@chromium.org,alexchau@chromium.org,vecore@google.com

Change-Id: Ia33d32ae93a8900032e81f77d298553c5de82874
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: b:154849033
Bug: b:158848873
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2355253Reviewed-by: default avatarLan Wei <lanwei@chromium.org>
Commit-Queue: Lan Wei <lanwei@chromium.org>
Cr-Commit-Position: refs/heads/master@{#797966}
parent 5aeb6a42
...@@ -14,8 +14,6 @@ source_set("platform_v2") { ...@@ -14,8 +14,6 @@ source_set("platform_v2") {
"bluetooth_classic_medium.h", "bluetooth_classic_medium.h",
"bluetooth_device.cc", "bluetooth_device.cc",
"bluetooth_device.h", "bluetooth_device.h",
"bluetooth_socket.cc",
"bluetooth_socket.h",
"condition_variable.cc", "condition_variable.cc",
"condition_variable.h", "condition_variable.h",
"count_down_latch.cc", "count_down_latch.cc",
...@@ -63,7 +61,6 @@ source_set("unit_tests") { ...@@ -63,7 +61,6 @@ source_set("unit_tests") {
"atomic_uint32_unittest.cc", "atomic_uint32_unittest.cc",
"bluetooth_adapter_unittest.cc", "bluetooth_adapter_unittest.cc",
"bluetooth_classic_medium_unittest.cc", "bluetooth_classic_medium_unittest.cc",
"bluetooth_socket_unittest.cc",
"condition_variable_unittest.cc", "condition_variable_unittest.cc",
"count_down_latch_unittest.cc", "count_down_latch_unittest.cc",
"crypto_unittest.cc", "crypto_unittest.cc",
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
# found in the LICENSE file. # found in the LICENSE file.
include_rules = [ include_rules = [
'+device/bluetooth/public',
'+third_party/abseil-cpp/absl/strings/string_view.h', '+third_party/abseil-cpp/absl/strings/string_view.h',
'+third_party/abseil-cpp/absl/time/time.h', '+third_party/abseil-cpp/absl/time/time.h',
] ]
...@@ -15,7 +15,7 @@ namespace nearby { ...@@ -15,7 +15,7 @@ namespace nearby {
namespace chrome { namespace chrome {
// Concrete BluetoothAdapter implementation. // Concrete BluetoothAdapter implementation.
// api::BluetoothAdapter is a synchronous interface, so this implementation // api::BluetoothAdapter is a synchronous interface, so this implementation of
// consumes the synchronous signatures of bluetooth::mojom::Adapter methods. // consumes the synchronous signatures of bluetooth::mojom::Adapter methods.
class BluetoothAdapter : public api::BluetoothAdapter { class BluetoothAdapter : public api::BluetoothAdapter {
public: public:
......
...@@ -4,9 +4,6 @@ ...@@ -4,9 +4,6 @@
#include "chrome/services/sharing/nearby/platform_v2/bluetooth_classic_medium.h" #include "chrome/services/sharing/nearby/platform_v2/bluetooth_classic_medium.h"
#include "chrome/services/sharing/nearby/platform_v2/bluetooth_socket.h"
#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
namespace location { namespace location {
namespace nearby { namespace nearby {
namespace chrome { namespace chrome {
...@@ -72,26 +69,8 @@ bool BluetoothClassicMedium::StopDiscovery() { ...@@ -72,26 +69,8 @@ bool BluetoothClassicMedium::StopDiscovery() {
std::unique_ptr<api::BluetoothSocket> BluetoothClassicMedium::ConnectToService( std::unique_ptr<api::BluetoothSocket> BluetoothClassicMedium::ConnectToService(
api::BluetoothDevice& remote_device, api::BluetoothDevice& remote_device,
const std::string& service_uuid) { const std::string& service_uuid) {
// TODO(hansberry): This currently assumes that the device was discovered via // TODO(b/154849933): Implement this in a subsequent CL.
// Bluetooth Classic (the remote device is in high visibility mode), meaning NOTIMPLEMENTED();
// this address is the expected permanent BT MAC address. Once an
// implementation is in place to scan for devices over BLE, a new mechanism
// to query for the remote device's permanent BT MAC address from stored
// certificates.
// We provided this |remote_device|, so we can safely downcast it.
const std::string& address =
static_cast<chrome::BluetoothDevice&>(remote_device).GetAddress();
bluetooth::mojom::ConnectToServiceResultPtr result;
bool success = adapter_->ConnectToServiceInsecurely(
address, device::BluetoothUUID(service_uuid), &result);
if (success && result) {
return std::make_unique<chrome::BluetoothSocket>(
remote_device, std::move(result->socket),
std::move(result->receive_stream), std::move(result->send_stream));
}
return nullptr; return nullptr;
} }
......
...@@ -25,8 +25,6 @@ const char kDeviceAddress1[] = "DeviceAddress1"; ...@@ -25,8 +25,6 @@ const char kDeviceAddress1[] = "DeviceAddress1";
const char kDeviceAddress2[] = "DeviceAddress2"; const char kDeviceAddress2[] = "DeviceAddress2";
const char kDeviceName1[] = "DeviceName1"; const char kDeviceName1[] = "DeviceName1";
const char kDeviceName2[] = "DeviceName2"; const char kDeviceName2[] = "DeviceName2";
const device::BluetoothUUID kNearbySharingServiceUuid =
device::BluetoothUUID("a82efa21-ae5c-3dde-9bbc-f16da7b16c5a");
} // namespace } // namespace
class BluetoothClassicMediumTest : public testing::Test { class BluetoothClassicMediumTest : public testing::Test {
...@@ -195,35 +193,6 @@ TEST_F(BluetoothClassicMediumTest, TestDiscovery_DeviceLost) { ...@@ -195,35 +193,6 @@ TEST_F(BluetoothClassicMediumTest, TestDiscovery_DeviceLost) {
StopDiscovery(); StopDiscovery();
} }
TEST_F(BluetoothClassicMediumTest, TestConnectToService_Success) {
StartDiscovery();
NotifyDeviceAdded(kDeviceAddress1, kDeviceName1);
StopDiscovery();
fake_adapter_->AllowConnectionForAddressAndUuidPair(
kDeviceAddress1, kNearbySharingServiceUuid);
auto bluetooth_socket = bluetooth_classic_medium_->ConnectToService(
*last_device_discovered_, kNearbySharingServiceUuid.value());
EXPECT_EQ(last_device_discovered_, bluetooth_socket->GetRemoteDevice());
EXPECT_TRUE(bluetooth_socket->Close().Ok());
}
TEST_F(BluetoothClassicMediumTest, TestConnectToService_ConnectionFailure) {
StartDiscovery();
NotifyDeviceAdded(kDeviceAddress1, kDeviceName1);
NotifyDeviceAdded(kDeviceAddress2, kDeviceName2);
StopDiscovery();
// Do not allow "Device 2".
fake_adapter_->AllowConnectionForAddressAndUuidPair(
kDeviceAddress1, kNearbySharingServiceUuid);
EXPECT_FALSE(bluetooth_classic_medium_->ConnectToService(
*last_device_discovered_, kNearbySharingServiceUuid.value()));
}
} // namespace chrome } // namespace chrome
} // namespace nearby } // namespace nearby
} // namespace location } // namespace location
// Copyright 2020 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 "chrome/services/sharing/nearby/platform_v2/bluetooth_socket.h"
#include <limits>
#include "base/synchronization/waitable_event.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "third_party/nearby/src/cpp/platform_v2/public/count_down_latch.h"
namespace location {
namespace nearby {
namespace chrome {
namespace {
// Concrete InputStream implementation, tightly coupled to BluetoothSocket.
class InputStreamImpl : public InputStream {
public:
InputStreamImpl(scoped_refptr<base::SequencedTaskRunner> task_runner,
mojo::ScopedDataPipeConsumerHandle receive_stream)
: task_runner_(std::move(task_runner)),
receive_stream_(std::move(receive_stream)),
receive_stream_watcher_(FROM_HERE,
mojo::SimpleWatcher::ArmingPolicy::MANUAL,
task_runner_) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
receive_stream_watcher_.Watch(
receive_stream_.get(),
MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
base::BindRepeating(&InputStreamImpl::ReceiveMore,
base::Unretained(this)));
}
~InputStreamImpl() override = default;
InputStreamImpl(const InputStreamImpl&) = delete;
InputStreamImpl& operator=(const InputStreamImpl&) = delete;
// InputStream:
ExceptionOr<ByteArray> Read(std::int64_t size) override {
if (size <= 0 || size > std::numeric_limits<uint32_t>::max())
return {Exception::kIo};
task_run_.emplace();
read_size_ = static_cast<uint32_t>(size);
task_runner_->PostTask(
FROM_HERE, base::BindOnce(&mojo::SimpleWatcher::ArmOrNotify,
base::Unretained(&receive_stream_watcher_)));
task_run_->Wait();
task_run_.reset();
return exception_or_received_byte_array_;
}
Exception Close() override {
receive_stream_.reset();
return {Exception::kSuccess};
}
private:
void ReceiveMore(MojoResult result, const mojo::HandleSignalsState& state) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
DCHECK_NE(result, MOJO_RESULT_SHOULD_WAIT);
if (!receive_stream_.is_valid()) {
read_size_ = 0;
exception_or_received_byte_array_ =
ExceptionOr<ByteArray>(Exception::kIo);
if (task_run_)
task_run_->Signal();
return;
}
DCHECK_NE(read_size_, 0u);
DCHECK(task_run_);
std::vector<char> buf(read_size_);
uint32_t num_bytes = read_size_;
if (result == MOJO_RESULT_OK) {
// Pass MOJO_READ_DATA_FLAG_ALL_OR_NONE to ensure the exact number of
// bytes requested is read.
result = receive_stream_->ReadData(buf.data(), &num_bytes,
MOJO_READ_DATA_FLAG_ALL_OR_NONE);
}
read_size_ = 0;
if (result == MOJO_RESULT_OK) {
exception_or_received_byte_array_ =
ExceptionOr<ByteArray>(ByteArray(buf.data(), num_bytes));
} else {
exception_or_received_byte_array_ =
ExceptionOr<ByteArray>(Exception::kIo);
}
task_run_->Signal();
}
scoped_refptr<base::SequencedTaskRunner> task_runner_;
mojo::ScopedDataPipeConsumerHandle receive_stream_;
mojo::SimpleWatcher receive_stream_watcher_;
uint32_t read_size_ = 0;
ExceptionOr<ByteArray> exception_or_received_byte_array_;
base::Optional<base::WaitableEvent> task_run_;
};
// Concrete OutputStream implementation, tightly coupled to BluetoothSocket.
class OutputStreamImpl : public OutputStream {
public:
OutputStreamImpl(scoped_refptr<base::SequencedTaskRunner> task_runner,
mojo::ScopedDataPipeProducerHandle send_stream)
: task_runner_(std::move(task_runner)),
send_stream_(std::move(send_stream)),
send_stream_watcher_(FROM_HERE,
mojo::SimpleWatcher::ArmingPolicy::MANUAL,
task_runner_) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
send_stream_watcher_.Watch(
send_stream_.get(),
MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
base::BindRepeating(&OutputStreamImpl::SendMore,
base::Unretained(this)));
}
~OutputStreamImpl() override = default;
OutputStreamImpl(const OutputStreamImpl&) = delete;
OutputStreamImpl& operator=(const OutputStreamImpl&) = delete;
// OutputStream:
Exception Write(const ByteArray& data) override {
DCHECK(!write_success_);
pending_write_buffer_ = std::make_unique<ByteArray>(data);
task_run_.emplace();
task_runner_->PostTask(
FROM_HERE, base::BindOnce(&mojo::SimpleWatcher::ArmOrNotify,
base::Unretained(&send_stream_watcher_)));
task_run_->Wait();
Exception result = {write_success_ ? Exception::kSuccess : Exception::kIo};
write_success_ = false;
pending_write_buffer_.reset();
task_run_.reset();
return result;
}
Exception Flush() override {
// TODO(hansberry): Unsure if anything can reasonably be done here. Need to
// ask a reviewer from the Nearby team.
return {Exception::kSuccess};
}
Exception Close() override {
send_stream_.reset();
return {Exception::kSuccess};
}
private:
void SendMore(MojoResult result, const mojo::HandleSignalsState& state) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
DCHECK_NE(result, MOJO_RESULT_SHOULD_WAIT);
if (!send_stream_.is_valid()) {
write_success_ = false;
if (task_run_)
task_run_->Signal();
return;
}
DCHECK(pending_write_buffer_);
DCHECK(task_run_);
if (result == MOJO_RESULT_OK) {
uint32_t num_bytes = static_cast<uint32_t>(pending_write_buffer_->size());
// Pass MOJO_WRITE_DATA_FLAG_ALL_OR_NONE to ensure the exact number of
// bytes requested is written.
result =
send_stream_->WriteData(pending_write_buffer_->data(), &num_bytes,
MOJO_WRITE_DATA_FLAG_ALL_OR_NONE);
}
write_success_ = (result == MOJO_RESULT_OK);
task_run_->Signal();
}
scoped_refptr<base::SequencedTaskRunner> task_runner_;
mojo::ScopedDataPipeProducerHandle send_stream_;
mojo::SimpleWatcher send_stream_watcher_;
std::unique_ptr<ByteArray> pending_write_buffer_;
bool write_success_ = false;
base::Optional<base::WaitableEvent> task_run_;
};
} // namespace
BluetoothSocket::BluetoothSocket(
api::BluetoothDevice& remote_device,
mojo::PendingRemote<bluetooth::mojom::Socket> socket,
mojo::ScopedDataPipeConsumerHandle receive_stream,
mojo::ScopedDataPipeProducerHandle send_stream)
: remote_device_(remote_device),
task_runner_(base::ThreadPool::CreateSequencedTaskRunner({})) {
socket_.Bind(std::move(socket));
// These properties must be created on the same sequence they are later run
// on. See |task_runner_|.
CountDownLatch latch(2);
auto count_down_latch_callback = base::BindRepeating(
[](CountDownLatch* latch) { latch->CountDown(); }, &latch);
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&BluetoothSocket::CreateInputStream,
base::Unretained(this), std::move(receive_stream),
count_down_latch_callback));
task_runner_->PostTask(
FROM_HERE, base::BindOnce(&BluetoothSocket::CreateOutputStream,
base::Unretained(this), std::move(send_stream),
count_down_latch_callback));
latch.Await();
}
BluetoothSocket::~BluetoothSocket() {
if (socket_)
Close();
}
InputStream& BluetoothSocket::GetInputStream() {
DCHECK(input_stream_);
return *input_stream_;
}
OutputStream& BluetoothSocket::GetOutputStream() {
DCHECK(output_stream_);
return *output_stream_;
}
Exception BluetoothSocket::Close() {
socket_->Disconnect();
socket_.reset();
// These properties must be destroyed on the same sequence they are later run
// on. See |task_runner_|.
CountDownLatch latch(2);
auto count_down_latch_callback = base::BindRepeating(
[](CountDownLatch* latch) { latch->CountDown(); }, &latch);
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&BluetoothSocket::DestroyInputStream,
base::Unretained(this), count_down_latch_callback));
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&BluetoothSocket::DestroyOutputStream,
base::Unretained(this), count_down_latch_callback));
return latch.Await();
}
api::BluetoothDevice* BluetoothSocket::GetRemoteDevice() {
return &remote_device_;
}
void BluetoothSocket::CreateInputStream(
mojo::ScopedDataPipeConsumerHandle receive_stream,
base::OnceClosure callback) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
input_stream_ = std::make_unique<InputStreamImpl>(task_runner_,
std::move(receive_stream));
std::move(callback).Run();
}
void BluetoothSocket::DestroyInputStream(base::OnceClosure callback) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
input_stream_.reset();
std::move(callback).Run();
}
void BluetoothSocket::CreateOutputStream(
mojo::ScopedDataPipeProducerHandle send_stream,
base::OnceClosure callback) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
output_stream_ =
std::make_unique<OutputStreamImpl>(task_runner_, std::move(send_stream));
std::move(callback).Run();
}
void BluetoothSocket::DestroyOutputStream(base::OnceClosure callback) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
output_stream_.reset();
std::move(callback).Run();
}
} // namespace chrome
} // namespace nearby
} // namespace location
// Copyright 2020 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.
#ifndef CHROME_SERVICES_SHARING_NEARBY_PLATFORM_V2_BLUETOOTH_SOCKET_H_
#define CHROME_SERVICES_SHARING_NEARBY_PLATFORM_V2_BLUETOOTH_SOCKET_H_
#include <string>
#include "device/bluetooth/public/mojom/adapter.mojom.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "third_party/nearby/src/cpp/platform_v2/api/bluetooth_classic.h"
#include "third_party/nearby/src/cpp/platform_v2/base/input_stream.h"
#include "third_party/nearby/src/cpp/platform_v2/base/output_stream.h"
namespace base {
class SequencedTaskRunner;
} // namespace base
namespace location {
namespace nearby {
namespace chrome {
// Concrete BluetoothSocket implementation.
//
// Nearby Connections uses this BluetoothSocket to communicate with a remote
// device. At a high-level, it first exchanges frames to encrypt the connection,
// then delegates to its caller (e.g., Nearby Share) to authenticate the
// connection, and finally expects its caller to send and receive
// application-level messages. The following precautions are taken to handle
// untrusted bytes received from remote devices:
// * Nearby Connections (which this class is a piece of) is hosted in a
// Nearby utility process.
// * Whenever Nearby Connections provides bytes received from a remote device
// to its caller, even after it has been authenticated, the caller must not
// trust those bytes, and is responsible for first passing those bytes
// through the trusted NearbyDecoder interface (see go/nearby-chrome-mojo).
// NearbyDecoder is hosted in the same Nearby utility process.
//
// api::BluetoothSocket is a synchronous interface, so this implementation
// consumes the synchronous signatures of bluetooth::mojom::Socket methods.
//
// api::BluetoothSocket's subclasses are also synchronous interfaces, but the
// Mojo DataPipes they consume only provide asynchronous interfaces. This is
// reconciled by blocking on the caller thread when waiting (via a
// mojo::SimpleWatcher) for the DataPipes to become readable or writable (this
// is expected by the callers of api::BluetoothSocket's subclasses). Mojo
// DataPipe operations are handled on a separate task runner (see
// |task_runner_|) so that blocking on the calling thread will not deadlock.
class BluetoothSocket : public api::BluetoothSocket {
public:
BluetoothSocket(api::BluetoothDevice& remote_device,
mojo::PendingRemote<bluetooth::mojom::Socket> socket,
mojo::ScopedDataPipeConsumerHandle receive_stream,
mojo::ScopedDataPipeProducerHandle send_stream);
~BluetoothSocket() override;
BluetoothSocket(const BluetoothSocket&) = delete;
BluetoothSocket& operator=(const BluetoothSocket&) = delete;
// api::BluetoothSocket:
InputStream& GetInputStream() override;
OutputStream& GetOutputStream() override;
Exception Close() override;
api::BluetoothDevice* GetRemoteDevice() override;
private:
// These methods must be run on |task_runner_|, because the
// mojo::SimpleWatcher members of |input_stream_| and |output_stream_| expect
// to be created on the same sequence they are later run on. See
// |task_runner_|.
void CreateInputStream(mojo::ScopedDataPipeConsumerHandle receive_stream,
base::OnceClosure callback);
void DestroyInputStream(base::OnceClosure callback);
void CreateOutputStream(mojo::ScopedDataPipeProducerHandle send_stream,
base::OnceClosure callback);
void DestroyOutputStream(base::OnceClosure callback);
api::BluetoothDevice& remote_device_;
// The public methods which are overridden by BluetoothSocket's subclasses
// InputStreamImpl and OutputStreamImpl are expected to block the caller
// thread. While that thread is blocked, |task_runner_| handles read and write
// operations on |input_stream_| and |output_stream_|. Because of that,
// |input_stream_| (and its mojo::SimpleWatcher) and |output_stream_| (and
// its mojo::SimpleWatcher), must be created and destroyed on |task_runner_|
// (see respective helper Create* and Destroy* methods).
scoped_refptr<base::SequencedTaskRunner> task_runner_;
// These properties must be created on |task_runner_|. See |task_runner_|.
mojo::Remote<bluetooth::mojom::Socket> socket_;
std::unique_ptr<InputStream> input_stream_;
std::unique_ptr<OutputStream> output_stream_;
};
} // namespace chrome
} // namespace nearby
} // namespace location
#endif // CHROME_SERVICES_SHARING_NEARBY_PLATFORM_V2_BLUETOOTH_SOCKET_H_
// Copyright 2020 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 "chrome/services/sharing/nearby/platform_v2/bluetooth_socket.h"
#include <memory>
#include "base/bind.h"
#include "base/run_loop.h"
#include "base/test/bind_test_util.h"
#include "base/test/task_environment.h"
#include "chrome/services/sharing/nearby/platform_v2/bluetooth_device.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace location {
namespace nearby {
namespace chrome {
namespace {
const char kDeviceAddress1[] = "DeviceAddress1";
const char kDeviceName1[] = "DeviceName1";
class FakeSocket : public bluetooth::mojom::Socket {
public:
FakeSocket() = default;
~FakeSocket() override {
EXPECT_TRUE(called_disconnect_);
if (on_destroy_callback_)
std::move(on_destroy_callback_).Run();
}
void SetOnDestroyCallback(base::OnceClosure callback) {
on_destroy_callback_ = std::move(callback);
}
private:
// bluetooth::mojom::Socket:
void Disconnect(DisconnectCallback callback) override {
called_disconnect_ = true;
std::move(callback).Run();
}
bool called_disconnect_ = false;
base::OnceClosure on_destroy_callback_;
};
} // namespace
class BluetoothSocketTest : public testing::Test {
public:
BluetoothSocketTest() = default;
~BluetoothSocketTest() override = default;
BluetoothSocketTest(const BluetoothSocketTest&) = delete;
BluetoothSocketTest& operator=(const BluetoothSocketTest&) = delete;
void SetUp() override {
bluetooth_device_ = std::make_unique<chrome::BluetoothDevice>(
CreateDeviceInfo(kDeviceAddress1, kDeviceName1));
mojo::ScopedDataPipeProducerHandle receive_pipe_producer_handle;
mojo::ScopedDataPipeConsumerHandle receive_pipe_consumer_handle;
ASSERT_EQ(
MOJO_RESULT_OK,
mojo::CreateDataPipe(/*options=*/nullptr, &receive_pipe_producer_handle,
&receive_pipe_consumer_handle));
mojo::ScopedDataPipeProducerHandle send_pipe_producer_handle;
mojo::ScopedDataPipeConsumerHandle send_pipe_consumer_handle;
ASSERT_EQ(MOJO_RESULT_OK, mojo::CreateDataPipe(/*options=*/nullptr,
&send_pipe_producer_handle,
&send_pipe_consumer_handle));
auto fake_socket = std::make_unique<FakeSocket>();
fake_socket_ = fake_socket.get();
mojo::PendingRemote<bluetooth::mojom::Socket> pending_socket;
mojo::MakeSelfOwnedReceiver(
std::move(fake_socket),
pending_socket.InitWithNewPipeAndPassReceiver());
bluetooth_socket_ = std::make_unique<BluetoothSocket>(
*bluetooth_device_, std::move(pending_socket),
std::move(receive_pipe_consumer_handle),
std::move(send_pipe_producer_handle));
receive_stream_ = std::move(receive_pipe_producer_handle);
send_stream_ = std::move(send_pipe_consumer_handle);
}
void TearDown() override {
// Destroy here, not in BluetoothSocketTest's destructor, because this is
// blocking.
bluetooth_socket_.reset();
}
protected:
std::unique_ptr<chrome::BluetoothDevice> bluetooth_device_;
FakeSocket* fake_socket_ = nullptr;
std::unique_ptr<BluetoothSocket> bluetooth_socket_;
mojo::ScopedDataPipeProducerHandle receive_stream_;
mojo::ScopedDataPipeConsumerHandle send_stream_;
private:
bluetooth::mojom::DeviceInfoPtr CreateDeviceInfo(const std::string& address,
const std::string& name) {
auto device_info = bluetooth::mojom::DeviceInfo::New();
device_info->address = address;
device_info->name = name;
device_info->name_for_display = name;
return device_info;
}
base::test::TaskEnvironment task_environment_;
};
TEST_F(BluetoothSocketTest, TestGetRemoteDevice) {
EXPECT_EQ(bluetooth_device_.get(), bluetooth_socket_->GetRemoteDevice());
}
TEST_F(BluetoothSocketTest, TestClose) {
ASSERT_TRUE(fake_socket_);
base::RunLoop run_loop;
fake_socket_->SetOnDestroyCallback(run_loop.QuitClosure());
EXPECT_TRUE(bluetooth_socket_->Close().Ok());
run_loop.Run();
}
TEST_F(BluetoothSocketTest, TestDestroy) {
ASSERT_TRUE(fake_socket_);
base::RunLoop run_loop;
fake_socket_->SetOnDestroyCallback(run_loop.QuitClosure());
bluetooth_socket_.reset();
run_loop.Run();
}
TEST_F(BluetoothSocketTest, TestInputStream) {
InputStream& input_stream = bluetooth_socket_->GetInputStream();
std::string message = "ReceivedMessage";
uint32_t message_size = message.size();
EXPECT_EQ(MOJO_RESULT_OK,
receive_stream_->WriteData(message.data(), &message_size,
MOJO_WRITE_DATA_FLAG_NONE));
EXPECT_EQ(message.size(), message_size);
ExceptionOr<ByteArray> exception_or_byte_array =
input_stream.Read(message_size);
ASSERT_TRUE(exception_or_byte_array.ok());
ByteArray& byte_array = exception_or_byte_array.result();
std::string received_string(byte_array);
EXPECT_EQ(message, received_string);
EXPECT_EQ(Exception::kSuccess, input_stream.Close().value);
}
TEST_F(BluetoothSocketTest, TestOutputStream) {
OutputStream& output_stream = bluetooth_socket_->GetOutputStream();
std::string message = "SentMessage";
ByteArray byte_array(message);
EXPECT_EQ(Exception::kSuccess, output_stream.Write(byte_array).value);
const uint32_t max_buffer_size = 1024;
uint32_t buffer_size = max_buffer_size;
std::vector<char> buffer(max_buffer_size);
EXPECT_EQ(MOJO_RESULT_OK, send_stream_->ReadData(buffer.data(), &buffer_size,
MOJO_READ_DATA_FLAG_NONE));
std::string sent_string(buffer.data(), buffer_size);
EXPECT_EQ(message, sent_string);
EXPECT_EQ(Exception::kSuccess, output_stream.Flush().value);
EXPECT_EQ(Exception::kSuccess, output_stream.Close().value);
}
} // namespace chrome
} // namespace nearby
} // namespace location
include_rules = [
"+device/bluetooth/public",
]
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace bluetooth { namespace bluetooth {
...@@ -21,7 +20,7 @@ class FakeDiscoverySession : public mojom::DiscoverySession { ...@@ -21,7 +20,7 @@ class FakeDiscoverySession : public mojom::DiscoverySession {
~FakeDiscoverySession() override { std::move(on_destroy_callback_).Run(); } ~FakeDiscoverySession() override { std::move(on_destroy_callback_).Run(); }
private: private:
// mojom::DiscoverySession: // mojom::FakeDiscoverySession:
void IsActive(IsActiveCallback callback) override { void IsActive(IsActiveCallback callback) override {
std::move(callback).Run(true); std::move(callback).Run(true);
} }
...@@ -30,24 +29,6 @@ class FakeDiscoverySession : public mojom::DiscoverySession { ...@@ -30,24 +29,6 @@ class FakeDiscoverySession : public mojom::DiscoverySession {
base::OnceClosure on_destroy_callback_; base::OnceClosure on_destroy_callback_;
}; };
class FakeSocket : public mojom::Socket {
public:
FakeSocket(mojo::ScopedDataPipeProducerHandle receive_stream,
mojo::ScopedDataPipeConsumerHandle send_stream)
: receive_stream_(std::move(receive_stream)),
send_stream_(std::move(send_stream)) {}
~FakeSocket() override = default;
private:
// mojom::Socket:
void Disconnect(DisconnectCallback callback) override {
std::move(callback).Run();
}
mojo::ScopedDataPipeProducerHandle receive_stream_;
mojo::ScopedDataPipeConsumerHandle send_stream_;
};
} // namespace } // namespace
FakeAdapter::FakeAdapter() = default; FakeAdapter::FakeAdapter() = default;
...@@ -96,45 +77,6 @@ void FakeAdapter::StartDiscoverySession( ...@@ -96,45 +77,6 @@ void FakeAdapter::StartDiscoverySession(
std::move(callback).Run(std::move(pending_session)); std::move(callback).Run(std::move(pending_session));
} }
void FakeAdapter::ConnectToServiceInsecurely(
const std::string& address,
const device::BluetoothUUID& service_uuid,
ConnectToServiceInsecurelyCallback callback) {
if (!base::Contains(allowed_connections_for_address_and_uuid_pair_,
std::make_pair(address, service_uuid))) {
std::move(callback).Run(/*result=*/nullptr);
return;
}
mojo::ScopedDataPipeProducerHandle receive_pipe_producer_handle;
mojo::ScopedDataPipeConsumerHandle receive_pipe_consumer_handle;
ASSERT_EQ(
MOJO_RESULT_OK,
mojo::CreateDataPipe(/*options=*/nullptr, &receive_pipe_producer_handle,
&receive_pipe_consumer_handle));
mojo::ScopedDataPipeProducerHandle send_pipe_producer_handle;
mojo::ScopedDataPipeConsumerHandle send_pipe_consumer_handle;
ASSERT_EQ(MOJO_RESULT_OK, mojo::CreateDataPipe(/*options=*/nullptr,
&send_pipe_producer_handle,
&send_pipe_consumer_handle));
mojo::PendingRemote<mojom::Socket> pending_socket;
mojo::MakeSelfOwnedReceiver(
std::make_unique<FakeSocket>(std::move(receive_pipe_producer_handle),
std::move(send_pipe_consumer_handle)),
pending_socket.InitWithNewPipeAndPassReceiver());
mojom::ConnectToServiceResultPtr connect_to_service_result =
mojom::ConnectToServiceResult::New();
connect_to_service_result->socket = std::move(pending_socket);
connect_to_service_result->receive_stream =
std::move(receive_pipe_consumer_handle);
connect_to_service_result->send_stream = std::move(send_pipe_producer_handle);
std::move(callback).Run(std::move(connect_to_service_result));
}
void FakeAdapter::SetShouldDiscoverySucceed(bool should_discovery_succeed) { void FakeAdapter::SetShouldDiscoverySucceed(bool should_discovery_succeed) {
should_discovery_succeed_ = should_discovery_succeed; should_discovery_succeed_ = should_discovery_succeed;
} }
...@@ -160,12 +102,6 @@ void FakeAdapter::NotifyDeviceRemoved(mojom::DeviceInfoPtr device_info) { ...@@ -160,12 +102,6 @@ void FakeAdapter::NotifyDeviceRemoved(mojom::DeviceInfoPtr device_info) {
client_->DeviceRemoved(std::move(device_info)); client_->DeviceRemoved(std::move(device_info));
} }
void FakeAdapter::AllowConnectionForAddressAndUuidPair(
const std::string& address,
const device::BluetoothUUID& service_uuid) {
allowed_connections_for_address_and_uuid_pair_.emplace(address, service_uuid);
}
void FakeAdapter::OnDiscoverySessionDestroyed() { void FakeAdapter::OnDiscoverySessionDestroyed() {
DCHECK(discovery_session_); DCHECK(discovery_session_);
discovery_session_ = nullptr; discovery_session_ = nullptr;
...@@ -173,4 +109,9 @@ void FakeAdapter::OnDiscoverySessionDestroyed() { ...@@ -173,4 +109,9 @@ void FakeAdapter::OnDiscoverySessionDestroyed() {
std::move(on_discovery_session_destroyed_callback_).Run(); std::move(on_discovery_session_destroyed_callback_).Run();
} }
void FakeAdapter::ConnectToServiceInsecurely(
const std::string& address,
const device::BluetoothUUID& service_uuid,
ConnectToServiceInsecurelyCallback callback) {}
} // namespace bluetooth } // namespace bluetooth
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
#ifndef CHROME_SERVICES_SHARING_NEARBY_TEST_SUPPORT_FAKE_ADAPTER_H_ #ifndef CHROME_SERVICES_SHARING_NEARBY_TEST_SUPPORT_FAKE_ADAPTER_H_
#define CHROME_SERVICES_SHARING_NEARBY_TEST_SUPPORT_FAKE_ADAPTER_H_ #define CHROME_SERVICES_SHARING_NEARBY_TEST_SUPPORT_FAKE_ADAPTER_H_
#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
#include "device/bluetooth/public/mojom/adapter.mojom.h" #include "device/bluetooth/public/mojom/adapter.mojom.h"
#include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote_set.h" #include "mojo/public/cpp/bindings/remote_set.h"
...@@ -38,9 +37,6 @@ class FakeAdapter : public mojom::Adapter { ...@@ -38,9 +37,6 @@ class FakeAdapter : public mojom::Adapter {
void NotifyDeviceAdded(mojom::DeviceInfoPtr device_info); void NotifyDeviceAdded(mojom::DeviceInfoPtr device_info);
void NotifyDeviceChanged(mojom::DeviceInfoPtr device_info); void NotifyDeviceChanged(mojom::DeviceInfoPtr device_info);
void NotifyDeviceRemoved(mojom::DeviceInfoPtr device_info); void NotifyDeviceRemoved(mojom::DeviceInfoPtr device_info);
void AllowConnectionForAddressAndUuidPair(
const std::string& address,
const device::BluetoothUUID& service_uuid);
mojo::Receiver<mojom::Adapter> adapter_{this}; mojo::Receiver<mojom::Adapter> adapter_{this};
std::string name_ = "AdapterName"; std::string name_ = "AdapterName";
...@@ -55,8 +51,6 @@ class FakeAdapter : public mojom::Adapter { ...@@ -55,8 +51,6 @@ class FakeAdapter : public mojom::Adapter {
mojom::DiscoverySession* discovery_session_ = nullptr; mojom::DiscoverySession* discovery_session_ = nullptr;
bool should_discovery_succeed_ = true; bool should_discovery_succeed_ = true;
base::OnceClosure on_discovery_session_destroyed_callback_; base::OnceClosure on_discovery_session_destroyed_callback_;
std::set<std::pair<std::string, device::BluetoothUUID>>
allowed_connections_for_address_and_uuid_pair_;
mojo::Remote<mojom::AdapterClient> client_; mojo::Remote<mojom::AdapterClient> client_;
}; };
......
...@@ -38,8 +38,6 @@ class Adapter : public mojom::Adapter, ...@@ -38,8 +38,6 @@ class Adapter : public mojom::Adapter,
void SetClient(mojo::PendingRemote<mojom::AdapterClient> client, void SetClient(mojo::PendingRemote<mojom::AdapterClient> client,
SetClientCallback callback) override; SetClientCallback callback) override;
void StartDiscoverySession(StartDiscoverySessionCallback callback) override; void StartDiscoverySession(StartDiscoverySessionCallback callback) override;
// TODO(b/162975217): Add a mechanism to allowlist which address and UUID
// pairs clients are allowed to create a connection to.
void ConnectToServiceInsecurely( void ConnectToServiceInsecurely(
const std::string& address, const std::string& address,
const device::BluetoothUUID& service_uuid, const device::BluetoothUUID& service_uuid,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment