| Index: components/proximity_auth/ble/bluetooth_low_energy_weave_server.cc
|
| diff --git a/components/proximity_auth/ble/bluetooth_low_energy_weave_server.cc b/components/proximity_auth/ble/bluetooth_low_energy_weave_server.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..4cefd6bc1c6e3e11e81f265f3fc65884c0edc674
|
| --- /dev/null
|
| +++ b/components/proximity_auth/ble/bluetooth_low_energy_weave_server.cc
|
| @@ -0,0 +1,298 @@
|
| +// 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 "base/bind.h"
|
| +#include "base/threading/thread_task_runner_handle.h"
|
| +#include "base/time/time.h"
|
| +#include "components/proximity_auth/ble/bluetooth_low_energy_weave_server.h"
|
| +#include "device/bluetooth/bluetooth_adapter_factory.h"
|
| +#include "device/bluetooth/bluetooth_uuid.h"
|
| +
|
| +namespace proximity_auth {
|
| +namespace weave {
|
| +namespace {
|
| +
|
| +using Property = BluetoothLocalGattCharacteristic::Property;
|
| +using BluetoothUUID = device::BluetoothUUID;
|
| +
|
| +const uint32_t kAdvertisementRotationPeriodInSecs = 5;
|
| +
|
| +// TODO(jingxuy): find out the right UUID
|
| +const char kWeaveServiceUUID[] = "00000100-0004-1000-8000-001A11000100";
|
| +
|
| +// The UUID of the BLE service that host the RX and TX characteristics.
|
| +const char kRXCharacteristicUUID[] = "00000100-0004-1000-8000-001A11000101";
|
| +const char kTXCharacteristicUUID[] = "00000100-0004-1000-8000-001A11000102";
|
| +
|
| +// TODO(jingxuy): verify these properties, currently just a draft version.
|
| +const uint32_t kRXCharacteristicProperties =
|
| + Property::PROPERTY_NOTIFY | Property::PROPERTY_READ;
|
| +
|
| +const uint32_t kTXCharacteristicProperties = Property::PROPERTY_WRITE;
|
| +
|
| +const uint32_t kCharacteristicPermissions =
|
| + BluetoothLocalGattCharacteristic::Permission::PERMISSION_NONE;
|
| +
|
| +} // namespace
|
| +
|
| +// static.
|
| +BluetoothLowEnergyWeaveServer::Factory*
|
| + BluetoothLowEnergyWeaveServer::Factory::factory_instance_ = nullptr;
|
| +
|
| +// static.
|
| +std::unique_ptr<BluetoothLowEnergyWeaveServer>
|
| +BluetoothLowEnergyWeaveServer::Factory::NewInstance() {
|
| + if (factory_instance_ == nullptr) {
|
| + factory_instance_ = new Factory();
|
| + }
|
| + return factory_instance_->BuildInstance();
|
| +}
|
| +
|
| +// static.
|
| +void BluetoothLowEnergyWeaveServer::Factory::SetInstanceForTesting(
|
| + Factory* factory) {
|
| + factory_instance_ = factory;
|
| +}
|
| +
|
| +std::unique_ptr<BluetoothLowEnergyWeaveServer>
|
| +BluetoothLowEnergyWeaveServer::Factory::BuildInstance() {
|
| + return std::unique_ptr<BluetoothLowEnergyWeaveServer>(
|
| + new BluetoothLowEnergyWeaveServer());
|
| +}
|
| +
|
| +BluetoothLowEnergyWeaveServer::BluetoothLowEnergyWeaveServer()
|
| + : task_runner_(base::ThreadTaskRunnerHandle::Get()),
|
| + ad_rotator_(BluetoothLowEnergyAdvertisementRotator::Factory::NewInstance(
|
| + kWeaveServiceUUID)),
|
| + weak_ptr_factory_(this) {
|
| + adapter_ =
|
| + BluetoothAdapter::CreateAdapter(
|
| + base::Bind(&BluetoothLowEnergyWeaveServer::CreateAdapterCallback,
|
| + weak_ptr_factory_.GetWeakPtr()))
|
| + .get();
|
| + service_ = BluetoothLocalGattService::Create(
|
| + adapter_.get(), BluetoothUUID(kWeaveServiceUUID), true, nullptr, this);
|
| + rx_characteristic_ = BluetoothLocalGattCharacteristic::Create(
|
| + BluetoothUUID(kRXCharacteristicUUID), kRXCharacteristicProperties,
|
| + kCharacteristicPermissions, service_.get());
|
| + tx_characteristic_ = BluetoothLocalGattCharacteristic::Create(
|
| + BluetoothUUID(kTXCharacteristicUUID), kTXCharacteristicProperties,
|
| + kCharacteristicPermissions, service_.get());
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveServer::OnCharacteristicReadRequest(
|
| + const BluetoothDevice* bluetooth_device,
|
| + const BluetoothLocalGattCharacteristic* characteristic,
|
| + int offset,
|
| + const ValueCallback& callback,
|
| + const ErrorCallback& error_callback) {
|
| + // Only care about the read on the rx_characteristic from registered devices.
|
| + // TODO(jingxuy): Do we even need to support this function?
|
| + // I thought the client only gets informed of rx_characteristics changes and
|
| + // wont't starting actively reading the value.
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveServer::OnCharacteristicWriteRequest(
|
| + const BluetoothDevice* bluetooth_device,
|
| + const BluetoothLocalGattCharacteristic* characteristic,
|
| + const Packet& value,
|
| + int offset,
|
| + const base::Closure& callback,
|
| + const ErrorCallback& error_callback) {
|
| + // Only care about the writes on the tx_characteristic from registered
|
| + // devices.
|
| + if (characteristic != tx_characteristic_.get() ||
|
| + !HasChannel(bluetooth_device)) {
|
| + return;
|
| + }
|
| +
|
| + map_to_channel_[bluetooth_device]->ReceivePacket(value);
|
| +
|
| + // TODO(jingxuy): do I need to care about offset?
|
| + // TODO(jingxuy): what do I do with the error_callback?
|
| + callback.Run();
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveServer::OnNotificationsStart(
|
| + const BluetoothDevice* bluetooth_device,
|
| + const BluetoothLocalGattCharacteristic* characteristic) {
|
| + if (characteristic != rx_characteristic_.get() ||
|
| + HasChannel(bluetooth_device)) {
|
| + return;
|
| + }
|
| +
|
| + std::unique_ptr<BluetoothLowEnergyWeaveChannel> channel(
|
| + new BluetoothLowEnergyWeaveChannel(bluetooth_device, rx_characteristic_));
|
| +
|
| + map_to_channel_.insert(std::make_pair(bluetooth_device, std::move(channel)));
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveServer::OnNotificationsStop(
|
| + const BluetoothDevice* bluetooth_device,
|
| + const BluetoothLocalGattCharacteristic* characteristic) {
|
| + if (characteristic != rx_characteristic_.get() ||
|
| + !HasChannel(bluetooth_device)) {
|
| + return;
|
| + }
|
| +
|
| + map_to_channel_[bluetooth_device]->GetServerConnection()->Disconnect();
|
| +
|
| + map_to_channel_.erase(bluetooth_device);
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveServer::OnChannelAuthenticated(
|
| + std::string device_id,
|
| + const BluetoothDevice* bluetooth_device) {
|
| + DCHECK(HasDevice(device_id));
|
| + DCHECK(HasChannel(bluetooth_device));
|
| +
|
| + DisableAdvertising(device_id);
|
| +
|
| + for (const auto& observer : observers_) {
|
| + observer->OnConnectionEstablished(
|
| + map_to_channel_[bluetooth_device]->GetServerConnection());
|
| + }
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveServer::OnChannelDisconnected(
|
| + std::string device_id,
|
| + const BluetoothDevice* bluetooth_device) {
|
| + DCHECK(HasDevice(device_id));
|
| + DCHECK(HasChannel(bluetooth_device));
|
| +
|
| + EnableAdvertising(device_id);
|
| +
|
| + for (const auto& observer : observers_) {
|
| + observer->OnConnectionClosed();
|
| + }
|
| +
|
| + map_to_channel_.erase(bluetooth_device);
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveServer::RegisterDevice(
|
| + const RemoteDevice& remote_device) {
|
| + DCHECK(!HasDevice(remote_device.user_id));
|
| +
|
| + map_to_remote_device_[remote_device.user_id] = remote_device;
|
| + ad_rotator_->AddDevice(remote_device);
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveServer::UnregisterDevice(
|
| + const RemoteDevice& remote_device) {
|
| + std::string device_id = remote_device.user_id;
|
| + DCHECK(HasDevice(device_id));
|
| +
|
| + if (IsAdvertising(device_id)) {
|
| + UnregisterAdvertisement(device_id);
|
| + }
|
| +
|
| + // TODO(jingxuy): remove current connected channels.
|
| +
|
| + ad_rotator_->RemoveDevice(remote_device);
|
| + map_to_remote_device_.erase(remote_device.user_id);
|
| +}
|
| +
|
| +bool BluetoothLowEnergyWeaveServer::HasDevice(std::string device_address) {
|
| + return map_to_remote_device_.find(device_address) !=
|
| + map_to_remote_device_.end();
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveServer::EnableAdvertising(std::string device_id) {
|
| + DCHECK(HasDevice(device_id) || !ad_rotator_->HasDeviceWithId(device_id));
|
| +
|
| + ad_rotator_->AddDevice(map_to_remote_device_[device_id]);
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveServer::DisableAdvertising(std::string device_id) {
|
| + DCHECK(HasDevice(device_id) || ad_rotator_->HasDeviceWithId(device_id));
|
| +
|
| + const RemoteDevice& remote_device = map_to_remote_device_[device_id];
|
| +
|
| + ad_rotator_->RemoveDevice(remote_device);
|
| +
|
| + if (map_to_advertisement_.find(device_id) != map_to_advertisement_.end()) {
|
| + UnregisterAdvertisement(device_id);
|
| + }
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveServer::SetTaskRunnerForTesting(
|
| + scoped_refptr<base::TaskRunner> task_runner) {
|
| + task_runner_ = task_runner;
|
| +}
|
| +
|
| +bool BluetoothLowEnergyWeaveServer::IsAdvertising(
|
| + std::string bluetooth_address) {
|
| + return map_to_advertisement_.find(bluetooth_address) !=
|
| + map_to_advertisement_.end();
|
| +}
|
| +
|
| +bool BluetoothLowEnergyWeaveServer::HasChannel(
|
| + const BluetoothDevice* bluetooth_device) {
|
| + return map_to_channel_.find(bluetooth_device) != map_to_channel_.end();
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveServer::RotateAdvertisement() {
|
| + for (auto const& it : map_to_advertisement_) {
|
| + UnregisterAdvertisement(it.first);
|
| + }
|
| +
|
| + Advertise();
|
| + base::TimeDelta wait_time =
|
| + base::TimeDelta::FromSeconds(kAdvertisementRotationPeriodInSecs);
|
| +
|
| + task_runner_->PostDelayedTask(
|
| + FROM_HERE, base::Bind(&BluetoothLowEnergyWeaveServer::RotateAdvertisement,
|
| + weak_ptr_factory_.GetWeakPtr()),
|
| + wait_time);
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveServer::Advertise() {
|
| + std::pair<std::string, std::unique_ptr<Advertisement>> ad =
|
| + ad_rotator_->GetNextAdvertisement();
|
| + adapter_->RegisterAdvertisement(
|
| + std::move(ad.second),
|
| + base::Bind(&BluetoothLowEnergyWeaveServer::RegisterAdvertisementSuccess,
|
| + weak_ptr_factory_.GetWeakPtr(), ad.first),
|
| + base::Bind(&BluetoothLowEnergyWeaveServer::RegisterAdvertisementError,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveServer::UnregisterAdvertisement(
|
| + std::string bluetooth_address) {
|
| + DCHECK(IsAdvertising(bluetooth_address));
|
| + map_to_advertisement_[bluetooth_address]->Unregister(
|
| + base::Bind(&BluetoothLowEnergyWeaveServer::UnregisterAdvertisementSuccess,
|
| + weak_ptr_factory_.GetWeakPtr(), bluetooth_address),
|
| + base::Bind(&BluetoothLowEnergyWeaveServer::UnregisterAdvertisementError,
|
| + weak_ptr_factory_.GetWeakPtr(), bluetooth_address));
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveServer::UnregisterAdvertisementSuccess(
|
| + std::string bluetooth_address) {
|
| + map_to_advertisement_.erase(bluetooth_address);
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveServer::UnregisterAdvertisementError(
|
| + std::string bluetooth_address,
|
| + BluetoothAdvertisement::ErrorCode error) {
|
| + DCHECK(error ==
|
| + BluetoothAdvertisement::ErrorCode::ERROR_ADVERTISEMENT_DOES_NOT_EXIST);
|
| + // The only way the unregister could fail is if the advertisement is not
|
| + // registered to begin with. Which means in our use case it should never fail.
|
| + // Hence remove the advertisement from the map.
|
| + map_to_advertisement_.erase(bluetooth_address);
|
| +}
|
| +
|
| +void BluetoothLowEnergyWeaveServer::RegisterAdvertisementSuccess(
|
| + std::string bluetooth_address,
|
| + scoped_refptr<BluetoothAdvertisement> advertisement) {
|
| + map_to_advertisement_[bluetooth_address] = advertisement;
|
| + ad_rotator_->RotateAdvertisement();
|
| + // Keep trying to advertise until failures.
|
| + Advertise();
|
| +}
|
| +
|
| +} // namespace weave
|
| +
|
| +} // namespace
|
|
|