| Index: components/proximity_auth/ble/bluetooth_low_energy_weave_client_connection.cc
|
| diff --git a/components/proximity_auth/ble/bluetooth_low_energy_weave_client_connection.cc b/components/proximity_auth/ble/bluetooth_low_energy_weave_client_connection.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..3fde2722609660df66b3ee9544bea3494e224ec2
|
| --- /dev/null
|
| +++ b/components/proximity_auth/ble/bluetooth_low_energy_weave_client_connection.cc
|
| @@ -0,0 +1,639 @@
|
| +// Copyright 2016 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/ble/bluetooth_low_energy_weave_client_connection.h"
|
| +
|
| +#include <utility>
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/location.h"
|
| +#include "base/task_runner.h"
|
| +#include "base/threading/thread_task_runner_handle.h"
|
| +#include "components/proximity_auth/bluetooth_throttler.h"
|
| +#include "components/proximity_auth/connection_finder.h"
|
| +#include "components/proximity_auth/logging/logging.h"
|
| +#include "components/proximity_auth/wire_message.h"
|
| +#include "device/bluetooth/bluetooth_gatt_connection.h"
|
| +
|
| +using device::BluetoothAdapter;
|
| +using device::BluetoothDevice;
|
| +using device::BluetoothGattConnection;
|
| +using device::BluetoothRemoteGattService;
|
| +using device::BluetoothRemoteGattCharacteristic;
|
| +using device::BluetoothGattNotifySession;
|
| +using device::BluetoothUUID;
|
| +
|
| +namespace proximity_auth {
|
| +namespace weave {
|
| +namespace {
|
| +
|
| +typedef BluetoothLowEnergyWeavePacketReceiver::State ReceiverState;
|
| +
|
| +// The UUID of the TX characteristic used to transmit data to the server.
|
| +const char kTXCharacteristicUUID[] = "00000100-0004-1000-8000-001A11000101";
|
| +
|
| +// The UUID of the RX characteristic used to receive data from the server.
|
| +const char kRXCharacteristicUUID[] = "00000100-0004-1000-8000-001A11000102";
|
| +
|
| +} // namespace
|
| +
|
| +BluetoothLowEnergyWeaveClientConnection::
|
| + BluetoothLowEnergyWeaveClientConnection(
|
| + const RemoteDevice& device,
|
| + scoped_refptr<device::BluetoothAdapter> adapter,
|
| + const BluetoothUUID remote_service_uuid,
|
| + BluetoothThrottler* bluetooth_throttler,
|
| + int max_number_of_write_attempts)
|
| + : Connection(device),
|
| + adapter_(adapter),
|
| + remote_service_({remote_service_uuid, ""}),
|
| + packet_generator_(
|
| + BluetoothLowEnergyWeavePacketGenerator::Factory::NewInstance()),
|
| + packet_receiver_(
|
| + BluetoothLowEnergyWeavePacketReceiver::Factory::NewInstance(
|
| + BluetoothLowEnergyWeavePacketReceiver::ReceiverType::CLIENT)),
|
| + tx_characteristic_({BluetoothUUID(kTXCharacteristicUUID), ""}),
|
| + rx_characteristic_({BluetoothUUID(kRXCharacteristicUUID), ""}),
|
| + bluetooth_throttler_(bluetooth_throttler),
|
| + task_runner_(base::ThreadTaskRunnerHandle::Get()),
|
| + sub_status_(SubStatus::DISCONNECTED),
|
| + write_remote_characteristic_pending_(false),
|
| + max_number_of_write_attempts_(max_number_of_write_attempts),
|
| + weak_ptr_factory_(this) {
|
| + DCHECK(adapter_);
|
| + DCHECK(adapter_->IsInitialized());
|
| +
|
| + adapter_->AddObserver(this);
|
| +}
|
| +
|
| +BluetoothLowEnergyWeaveClientConnection::
|
| + ~BluetoothLowEnergyWeaveClientConnection() {
|
| + // Since the destructor can be called at anytime, it would be unwise to send a
|
| + // connection close since we might not be connected at all.
|
| + DestroyConnection();
|
| +
|
| + if (adapter_) {
|
| + adapter_->RemoveObserver(this);
|
| + adapter_ = NULL;
|
| + }
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveClientConnection::Connect() {
|
| + DCHECK(sub_status() == SubStatus::DISCONNECTED);
|
| +
|
| + SetSubStatus(SubStatus::WAITING_GATT_CONNECTION);
|
| + base::TimeDelta throttler_delay = bluetooth_throttler_->GetDelay();
|
| + PA_LOG(INFO) << "Connecting in " << throttler_delay;
|
| +
|
| + start_time_ = base::TimeTicks::Now();
|
| +
|
| + // If necessary, wait to create a new GATT connection.
|
| + //
|
| + // Avoid creating a new GATT connection immediately after a given device was
|
| + // disconnected. This is a workaround for crbug.com/508919.
|
| + if (!throttler_delay.is_zero()) {
|
| + task_runner_->PostDelayedTask(
|
| + FROM_HERE,
|
| + base::Bind(
|
| + &BluetoothLowEnergyWeaveClientConnection::CreateGattConnection,
|
| + weak_ptr_factory_.GetWeakPtr()),
|
| + throttler_delay);
|
| + return;
|
| + }
|
| +
|
| + CreateGattConnection();
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveClientConnection::CreateGattConnection() {
|
| + DCHECK(sub_status() == SubStatus::WAITING_GATT_CONNECTION);
|
| +
|
| + BluetoothDevice* remote_device = GetRemoteDevice();
|
| + if (remote_device) {
|
| + PA_LOG(INFO) << "Creating GATT connection with "
|
| + << remote_device->GetAddress();
|
| +
|
| + remote_device->CreateGattConnection(
|
| + base::Bind(
|
| + &BluetoothLowEnergyWeaveClientConnection::OnGattConnectionCreated,
|
| + weak_ptr_factory_.GetWeakPtr()),
|
| + base::Bind(&BluetoothLowEnergyWeaveClientConnection::
|
| + OnCreateGattConnectionError,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| + } else {
|
| + SetSubStatus(SubStatus::DISCONNECTED);
|
| + }
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveClientConnection::Disconnect() {
|
| + if (sub_status_ == SubStatus::CONNECTED) {
|
| + // Friendly disconnect by sending a connection close and then destroy the
|
| + // the connection once the connection close has been sent.
|
| + WriteRequest request(packet_generator_->CreateConnectionClose(
|
| + ReasonForClose::CLOSE_WITHOUT_ERROR),
|
| + WriteRequestType::CONNECTION_CLOSE);
|
| + WriteRemoteCharacteristic(request);
|
| + } else {
|
| + DestroyConnection();
|
| + }
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveClientConnection::DestroyConnection() {
|
| + if (sub_status() != SubStatus::DISCONNECTED) {
|
| + weak_ptr_factory_.InvalidateWeakPtrs();
|
| + StopNotifySession();
|
| + characteristic_finder_.reset();
|
| + if (gatt_connection_) {
|
| + PA_LOG(INFO) << "Disconnect from device "
|
| + << gatt_connection_->GetDeviceAddress();
|
| +
|
| + // Destroying BluetoothGattConnection also disconnects it.
|
| + gatt_connection_.reset();
|
| + }
|
| +
|
| + // Only transition to the DISCONNECTED state after perfoming all necessary
|
| + // operations. Otherwise, it'll trigger observers that can pontentially
|
| + // destroy the current instance (causing a crash).
|
| + SetSubStatus(SubStatus::DISCONNECTED);
|
| + }
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveClientConnection::SetSubStatus(
|
| + SubStatus new_sub_status) {
|
| + sub_status_ = new_sub_status;
|
| +
|
| + // Sets the status of parent class proximity_auth::Connection accordingly.
|
| + if (new_sub_status == SubStatus::CONNECTED) {
|
| + SetStatus(Status::CONNECTED);
|
| + } else if (new_sub_status == SubStatus::DISCONNECTED) {
|
| + SetStatus(Status::DISCONNECTED);
|
| + } else {
|
| + SetStatus(Status::IN_PROGRESS);
|
| + }
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveClientConnection::SetTaskRunnerForTesting(
|
| + scoped_refptr<base::TaskRunner> task_runner) {
|
| + task_runner_ = task_runner;
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveClientConnection::SendMessageImpl(
|
| + std::unique_ptr<WireMessage> message) {
|
| + PA_LOG(INFO) << "Sending message " << message->Serialize();
|
| + std::string serialized_msg = message->Serialize();
|
| +
|
| + std::vector<Packet> packets =
|
| + packet_generator_->EncodeDataMessage(serialized_msg);
|
| +
|
| + std::shared_ptr<WireMessage> request_message(message.release());
|
| +
|
| + for (uint32_t i = 0; i < packets.size(); ++i) {
|
| + WriteRequestType request_type = (i == packets.size() - 1)
|
| + ? WriteRequestType::MESSAGE_COMPLETE
|
| + : WriteRequestType::REGULAR;
|
| + WriteRequest request(packets[i], request_type, request_message);
|
| + WriteRemoteCharacteristic(request);
|
| + }
|
| +}
|
| +
|
| +// Changes in the GATT connection with the remote device should be observed
|
| +// here. If the GATT connection is dropped, we should call DestroyConnection()
|
| +// anyway, so the object can notify its observers.
|
| +void BluetoothLowEnergyWeaveClientConnection::DeviceChanged(
|
| + BluetoothAdapter* adapter,
|
| + BluetoothDevice* device) {
|
| + DCHECK(device);
|
| + if (sub_status() == SubStatus::DISCONNECTED ||
|
| + device->GetAddress() != GetDeviceAddress())
|
| + return;
|
| +
|
| + if (sub_status() != SubStatus::WAITING_GATT_CONNECTION &&
|
| + !device->IsConnected()) {
|
| + PA_LOG(INFO) << "GATT connection dropped " << GetDeviceAddress()
|
| + << "\ndevice connected: " << device->IsConnected()
|
| + << "\ngatt connection: "
|
| + << (gatt_connection_ ? gatt_connection_->IsConnected()
|
| + : false);
|
| + DestroyConnection();
|
| + }
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveClientConnection::DeviceRemoved(
|
| + BluetoothAdapter* adapter,
|
| + BluetoothDevice* device) {
|
| + DCHECK(device);
|
| + if (sub_status_ == SubStatus::DISCONNECTED ||
|
| + device->GetAddress() != GetDeviceAddress())
|
| + return;
|
| +
|
| + PA_LOG(INFO) << "Device removed " << GetDeviceAddress();
|
| + DestroyConnection();
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveClientConnection::GattCharacteristicValueChanged(
|
| + BluetoothAdapter* adapter,
|
| + BluetoothRemoteGattCharacteristic* characteristic,
|
| + const Packet& value) {
|
| + DCHECK_EQ(adapter, adapter_.get());
|
| + if (sub_status() != SubStatus::WAITING_CONNECTION_RESPONSE &&
|
| + sub_status() != SubStatus::CONNECTED)
|
| + return;
|
| +
|
| + PA_LOG(INFO) << "Characteristic value changed: "
|
| + << characteristic->GetUUID().canonical_value();
|
| +
|
| + if (characteristic->GetIdentifier() == rx_characteristic_.id) {
|
| + ReceiverState state = packet_receiver_->ReceivePacket(value);
|
| +
|
| + PA_LOG(INFO) << "\nReceiver State: " << state;
|
| + switch (state) {
|
| + case ReceiverState::DATA_READY:
|
| + OnBytesReceived(packet_receiver_->GetDataMessage());
|
| + break;
|
| + case ReceiverState::CONNECTION_CLOSED:
|
| + PA_LOG(ERROR) << "Connection closed due to: " << GetReasonForClose();
|
| + DestroyConnection();
|
| + break;
|
| + case ReceiverState::ERROR_DETECTED:
|
| + OnPacketReceiverError();
|
| + break;
|
| + case ReceiverState::WAITING:
|
| + // Receiver state should have changed from CONNECTING to WAITING if
|
| + // a proper connection response had been received.
|
| + // The max packet size selected from the connection response will be
|
| + // used to generate future data packets.
|
| + packet_generator_->SetMaxPacketSize(
|
| + packet_receiver_->GetMaxPacketSize());
|
| + DCHECK(sub_status() == SubStatus::WAITING_CONNECTION_RESPONSE);
|
| + CompleteConnection();
|
| + break;
|
| + case ReceiverState::RECEIVING_DATA:
|
| + // Normal in between states, so do nothing.
|
| + break;
|
| + default:
|
| + NOTREACHED();
|
| + }
|
| + }
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveClientConnection::CompleteConnection() {
|
| + PA_LOG(INFO) << "Connection completed. Time elapsed: "
|
| + << base::TimeTicks::Now() - start_time_;
|
| + SetSubStatus(SubStatus::CONNECTED);
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveClientConnection::OnCreateGattConnectionError(
|
| + device::BluetoothDevice::ConnectErrorCode error_code) {
|
| + DCHECK(sub_status_ == SubStatus::WAITING_GATT_CONNECTION);
|
| + PA_LOG(WARNING) << "Error creating GATT connection to "
|
| + << remote_device().bluetooth_address
|
| + << " error code: " << error_code;
|
| + DestroyConnection();
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveClientConnection::OnGattConnectionCreated(
|
| + std::unique_ptr<device::BluetoothGattConnection> gatt_connection) {
|
| + DCHECK(sub_status() == SubStatus::WAITING_GATT_CONNECTION);
|
| + PA_LOG(INFO) << "GATT connection with " << gatt_connection->GetDeviceAddress()
|
| + << " created.";
|
| + PrintTimeElapsed();
|
| +
|
| + // Informing |bluetooth_trottler_| a new connection was established.
|
| + bluetooth_throttler_->OnConnection(this);
|
| +
|
| + gatt_connection_ = std::move(gatt_connection);
|
| + SetSubStatus(SubStatus::WAITING_CHARACTERISTICS);
|
| + characteristic_finder_.reset(CreateCharacteristicsFinder(
|
| + base::Bind(
|
| + &BluetoothLowEnergyWeaveClientConnection::OnCharacteristicsFound,
|
| + weak_ptr_factory_.GetWeakPtr()),
|
| + base::Bind(&BluetoothLowEnergyWeaveClientConnection::
|
| + OnCharacteristicsFinderError,
|
| + weak_ptr_factory_.GetWeakPtr())));
|
| +}
|
| +
|
| +BluetoothLowEnergyCharacteristicsFinder*
|
| +BluetoothLowEnergyWeaveClientConnection::CreateCharacteristicsFinder(
|
| + const BluetoothLowEnergyCharacteristicsFinder::SuccessCallback&
|
| + success_callback,
|
| + const BluetoothLowEnergyCharacteristicsFinder::ErrorCallback&
|
| + error_callback) {
|
| + return new BluetoothLowEnergyCharacteristicsFinder(
|
| + adapter_, GetRemoteDevice(), remote_service_, tx_characteristic_,
|
| + rx_characteristic_, success_callback, error_callback);
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveClientConnection::OnCharacteristicsFound(
|
| + const RemoteAttribute& service,
|
| + const RemoteAttribute& tx_characteristic,
|
| + const RemoteAttribute& rx_characteristic) {
|
| + PA_LOG(INFO) << "Remote chacteristics found.";
|
| + PrintTimeElapsed();
|
| +
|
| + DCHECK(sub_status() == SubStatus::WAITING_CHARACTERISTICS);
|
| + remote_service_ = service;
|
| + tx_characteristic_ = tx_characteristic;
|
| + rx_characteristic_ = rx_characteristic;
|
| +
|
| + SetSubStatus(SubStatus::CHARACTERISTICS_FOUND);
|
| + StartNotifySession();
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveClientConnection::OnCharacteristicsFinderError(
|
| + const RemoteAttribute& tx_characteristic,
|
| + const RemoteAttribute& rx_characteristic) {
|
| + DCHECK(sub_status() == SubStatus::WAITING_CHARACTERISTICS);
|
| + PA_LOG(WARNING) << "Connection error, missing characteristics for SmartLock "
|
| + "service.\n"
|
| + << (tx_characteristic.id.empty()
|
| + ? tx_characteristic.uuid.canonical_value()
|
| + : "")
|
| + << ", "
|
| + << (rx_characteristic.id.empty()
|
| + ? ", " + rx_characteristic.uuid.canonical_value()
|
| + : "")
|
| + << " not found.";
|
| +
|
| + DestroyConnection();
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveClientConnection::StartNotifySession() {
|
| + DCHECK(sub_status() == SubStatus::CHARACTERISTICS_FOUND);
|
| + BluetoothRemoteGattCharacteristic* characteristic =
|
| + GetGattCharacteristic(rx_characteristic_.id);
|
| + CHECK(characteristic);
|
| +
|
| + // This is a workaround for crbug.com/507325. If |characteristic| is already
|
| + // notifying |characteristic->StartNotifySession()| will fail with
|
| + // GATT_ERROR_FAILED.
|
| + if (characteristic->IsNotifying()) {
|
| + PA_LOG(INFO) << characteristic->GetUUID().canonical_value()
|
| + << " already notifying.";
|
| + SetSubStatus(SubStatus::NOTIFY_SESSION_READY);
|
| + SendConnectionRequest();
|
| + return;
|
| + }
|
| +
|
| + SetSubStatus(SubStatus::WAITING_NOTIFY_SESSION);
|
| + characteristic->StartNotifySession(
|
| + base::Bind(
|
| + &BluetoothLowEnergyWeaveClientConnection::OnNotifySessionStarted,
|
| + weak_ptr_factory_.GetWeakPtr()),
|
| + base::Bind(&BluetoothLowEnergyWeaveClientConnection::OnNotifySessionError,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveClientConnection::OnNotifySessionStarted(
|
| + std::unique_ptr<BluetoothGattNotifySession> notify_session) {
|
| + DCHECK(sub_status() == SubStatus::WAITING_NOTIFY_SESSION);
|
| + PA_LOG(INFO) << "Notification session started "
|
| + << notify_session->GetCharacteristicIdentifier();
|
| + PrintTimeElapsed();
|
| +
|
| + SetSubStatus(SubStatus::NOTIFY_SESSION_READY);
|
| + notify_session_ = std::move(notify_session);
|
| +
|
| + SendConnectionRequest();
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveClientConnection::OnNotifySessionError(
|
| + BluetoothRemoteGattService::GattErrorCode error) {
|
| + DCHECK(sub_status() == SubStatus::WAITING_NOTIFY_SESSION);
|
| + PA_LOG(WARNING) << "Error starting notification session: " << error;
|
| + DestroyConnection();
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveClientConnection::StopNotifySession() {
|
| + if (notify_session_) {
|
| + notify_session_->Stop(base::Bind(&base::DoNothing));
|
| + notify_session_.reset();
|
| + }
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveClientConnection::SendConnectionRequest() {
|
| + if (sub_status() == SubStatus::NOTIFY_SESSION_READY) {
|
| + PA_LOG(INFO) << "Sending connection request to the server";
|
| + SetSubStatus(SubStatus::WAITING_CONNECTION_RESPONSE);
|
| +
|
| + WriteRequest write_request(packet_generator_->CreateConnectionRequest(),
|
| + WriteRequestType::CONNECTION_REQUEST);
|
| +
|
| + WriteRemoteCharacteristic(write_request);
|
| + }
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveClientConnection::WriteRemoteCharacteristic(
|
| + const WriteRequest& request) {
|
| + write_requests_queue_.push(request);
|
| + PA_LOG(ERROR) << "you got " << request.message.get();
|
| + ProcessNextWriteRequest();
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveClientConnection::ProcessNextWriteRequest() {
|
| + BluetoothRemoteGattCharacteristic* characteristic =
|
| + GetGattCharacteristic(tx_characteristic_.id);
|
| + if (!write_requests_queue_.empty() && !write_remote_characteristic_pending_ &&
|
| + characteristic) {
|
| + write_remote_characteristic_pending_ = true;
|
| + const WriteRequest& next_request = write_requests_queue_.front();
|
| +
|
| + PA_LOG(INFO) << "Writing to characteristic " << next_request.value.size()
|
| + << " bytes";
|
| + characteristic->WriteRemoteCharacteristic(
|
| + next_request.value,
|
| + base::Bind(&BluetoothLowEnergyWeaveClientConnection::
|
| + OnRemoteCharacteristicWritten,
|
| + weak_ptr_factory_.GetWeakPtr()),
|
| + base::Bind(&BluetoothLowEnergyWeaveClientConnection::
|
| + OnWriteRemoteCharacteristicError,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| + }
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveClientConnection::OnRemoteCharacteristicWritten() {
|
| + PA_LOG(INFO) << "Characteristic written.";
|
| +
|
| + DCHECK(!write_requests_queue_.empty());
|
| +
|
| + const WriteRequest& request = write_requests_queue_.front();
|
| +
|
| + switch (request.request_type) {
|
| + case WriteRequestType::REGULAR:
|
| + case WriteRequestType::CONNECTION_REQUEST:
|
| + break;
|
| + case WriteRequestType::MESSAGE_COMPLETE:
|
| + OnDidSendMessage(*request.message, true);
|
| + break;
|
| + case WriteRequestType::CONNECTION_CLOSE:
|
| + DestroyConnection();
|
| + break;
|
| + default:
|
| + NOTREACHED();
|
| + }
|
| +
|
| + // Removes the top of queue (already processed) and process the next request.
|
| + write_requests_queue_.pop();
|
| + write_remote_characteristic_pending_ = false;
|
| + ProcessNextWriteRequest();
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveClientConnection::OnWriteRemoteCharacteristicError(
|
| + BluetoothRemoteGattService::GattErrorCode error) {
|
| + PA_LOG(WARNING) << "Error " << error << " writing characteristic: "
|
| + << tx_characteristic_.uuid.canonical_value();
|
| +
|
| + write_remote_characteristic_pending_ = false;
|
| +
|
| + DCHECK(!write_requests_queue_.empty());
|
| + WriteRequest* request = &write_requests_queue_.front();
|
| +
|
| + // Increases the number of failed attempts and retry.
|
| +
|
| + if (++request->number_of_failed_attempts >= max_number_of_write_attempts_) {
|
| + switch (request->request_type) {
|
| + case WriteRequestType::REGULAR:
|
| + case WriteRequestType::MESSAGE_COMPLETE:
|
| + OnDidSendMessage(*request->message, false);
|
| + break;
|
| + case WriteRequestType::CONNECTION_CLOSE:
|
| + case WriteRequestType::CONNECTION_REQUEST:
|
| + break;
|
| + default:
|
| + NOTREACHED();
|
| + }
|
| +
|
| + // If the previous write failed that many times, probably can't write a
|
| + // connection close either, so just destroy the connection.
|
| + DestroyConnection();
|
| + } else {
|
| + ProcessNextWriteRequest();
|
| + }
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveClientConnection::OnPacketReceiverError() {
|
| + PA_LOG(ERROR) << "Received erroneous packet. Closing connection.";
|
| +
|
| + WriteRequest request(packet_generator_->CreateConnectionClose(
|
| + packet_receiver_->GetReasonToClose()),
|
| + WriteRequestType::CONNECTION_CLOSE);
|
| +
|
| + // Skip all other writes that's not in progress.
|
| +
|
| + // C++ queue does not have a clear method.
|
| + // According to stackoverflow
|
| + // "http://stackoverflow.com/questions/709146/how-do-i-clear-the-stdqueue-
|
| + // efficiently"
|
| + std::queue<WriteRequest> empty;
|
| + std::swap(write_requests_queue_, empty);
|
| +
|
| + if (write_remote_characteristic_pending_) {
|
| + // Add the in progress write back to the queue.
|
| + write_requests_queue_.push(empty.front());
|
| + }
|
| +
|
| + WriteRemoteCharacteristic(request);
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveClientConnection::PrintTimeElapsed() {
|
| + PA_LOG(INFO) << "Time elapsed: " << base::TimeTicks::Now() - start_time_;
|
| +}
|
| +
|
| +std::string BluetoothLowEnergyWeaveClientConnection::GetDeviceAddress() {
|
| + // When the remote device is connected we should rely on the address given by
|
| + // |gatt_connection_|. As the device address may change if the device is
|
| + // paired. The address in |gatt_connection_| is automatically updated in this
|
| + // case.
|
| + return gatt_connection_ ? gatt_connection_->GetDeviceAddress()
|
| + : remote_device().bluetooth_address;
|
| +}
|
| +
|
| +BluetoothDevice* BluetoothLowEnergyWeaveClientConnection::GetRemoteDevice() {
|
| + // It's not possible to simply use
|
| + // |adapter_->GetDevice(GetDeviceAddress())| to find the device with MAC
|
| + // address |GetDeviceAddress()|. For paired devices,
|
| + // BluetoothAdapter::GetDevice(XXX) searches for the temporary MAC address
|
| + // XXX, whereas |GetDeviceAddress()| is the real MAC address. This is a
|
| + // bug in the way device::BluetoothAdapter is storing the devices (see
|
| + // crbug.com/497841).
|
| + std::vector<BluetoothDevice*> devices = adapter_->GetDevices();
|
| + for (const auto& device : devices) {
|
| + if (device->GetAddress() == GetDeviceAddress())
|
| + return device;
|
| + }
|
| +
|
| + return nullptr;
|
| +}
|
| +
|
| +BluetoothRemoteGattService*
|
| +BluetoothLowEnergyWeaveClientConnection::GetRemoteService() {
|
| + BluetoothDevice* remote_device = GetRemoteDevice();
|
| + if (!remote_device) {
|
| + PA_LOG(WARNING) << "Remote device not found.";
|
| + return NULL;
|
| + }
|
| + if (remote_service_.id.empty()) {
|
| + std::vector<BluetoothRemoteGattService*> services =
|
| + remote_device->GetGattServices();
|
| + for (const auto& service : services)
|
| + if (service->GetUUID() == remote_service_.uuid) {
|
| + remote_service_.id = service->GetIdentifier();
|
| + break;
|
| + }
|
| + }
|
| + return remote_device->GetGattService(remote_service_.id);
|
| +}
|
| +
|
| +BluetoothRemoteGattCharacteristic*
|
| +BluetoothLowEnergyWeaveClientConnection::GetGattCharacteristic(
|
| + const std::string& gatt_characteristic) {
|
| + BluetoothRemoteGattService* remote_service = GetRemoteService();
|
| + if (!remote_service) {
|
| + PA_LOG(WARNING) << "Remote service not found.";
|
| + return NULL;
|
| + }
|
| + return remote_service->GetCharacteristic(gatt_characteristic);
|
| +}
|
| +
|
| +std::string BluetoothLowEnergyWeaveClientConnection::GetReasonForClose() {
|
| + switch (packet_receiver_->GetReasonForClose()) {
|
| + case ReasonForClose::CLOSE_WITHOUT_ERROR:
|
| + return "CLOSE_WITHOUT_ERROR";
|
| + case ReasonForClose::UNKNOWN_ERROR:
|
| + return "UNKNOWN_ERROR";
|
| + case ReasonForClose::NO_COMMON_VERSION_SUPPORTED:
|
| + return "NO_COMMON_VERSION_SUPPORTED";
|
| + case ReasonForClose::RECEIVED_PACKET_OUT_OF_SEQUENCE:
|
| + return "RECEIVED_PACKET_OUT_OF_SEQUENCE";
|
| + case ReasonForClose::APPLICATION_ERROR:
|
| + return "APPLICATION_ERROR";
|
| + default:
|
| + NOTREACHED();
|
| + return "";
|
| + }
|
| +}
|
| +
|
| +BluetoothLowEnergyWeaveClientConnection::WriteRequest::WriteRequest(
|
| + const Packet& val,
|
| + WriteRequestType request_type,
|
| + std::shared_ptr<WireMessage> message)
|
| + : value(val),
|
| + request_type(request_type),
|
| + message(message),
|
| + number_of_failed_attempts(0) {}
|
| +
|
| +BluetoothLowEnergyWeaveClientConnection::WriteRequest::WriteRequest(
|
| + const Packet& val,
|
| + WriteRequestType request_type)
|
| + : value(val),
|
| + request_type(request_type),
|
| + message(nullptr),
|
| + number_of_failed_attempts(0) {}
|
| +
|
| +BluetoothLowEnergyWeaveClientConnection::WriteRequest::WriteRequest(
|
| + const WriteRequest& other) = default;
|
| +
|
| +BluetoothLowEnergyWeaveClientConnection::WriteRequest::~WriteRequest() {}
|
| +
|
| +} // namespace weave
|
| +
|
| +} // namespace proximity_auth
|
|
|