blob: fc0e4b35e26184efd1f33e1192cd44023d4dd346 [file] [log] [blame]
// Copyright 2017 The Fuchsia 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 SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_FIDL_LOW_ENERGY_PERIPHERAL_SERVER_H_
#define SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_FIDL_LOW_ENERGY_PERIPHERAL_SERVER_H_
#include <fuchsia/bluetooth/le/cpp/fidl.h>
#include <lib/async/cpp/wait.h>
#include <lib/fidl/cpp/binding.h>
#include <memory>
#include <unordered_map>
#include "src/connectivity/bluetooth/core/bt-host/fidl/low_energy_connection_server.h"
#include "src/connectivity/bluetooth/core/bt-host/fidl/server_base.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/macros.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/weak_self.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/gap/adapter.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/gap/low_energy_advertising_manager.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/gap/low_energy_connection_manager.h"
namespace bthost {
// Implements the low_energy::Peripheral FIDL interface.
class LowEnergyPeripheralServer : public AdapterServerBase<fuchsia::bluetooth::le::Peripheral> {
public:
LowEnergyPeripheralServer(bt::gap::Adapter::WeakPtr adapter, bt::gatt::GATT::WeakPtr gatt,
fidl::InterfaceRequest<fuchsia::bluetooth::le::Peripheral> request);
~LowEnergyPeripheralServer() override;
// fuchsia::bluetooth::le::Peripheral overrides:
void Advertise(
fuchsia::bluetooth::le::AdvertisingParameters parameters,
fidl::InterfaceHandle<fuchsia::bluetooth::le::AdvertisedPeripheral> advertised_peripheral,
AdvertiseCallback callback) override;
void StartAdvertising(fuchsia::bluetooth::le::AdvertisingParameters parameters,
::fidl::InterfaceRequest<fuchsia::bluetooth::le::AdvertisingHandle> token,
StartAdvertisingCallback callback) override;
// Returns the connection handle associated with the given |id|, or nullptr if the peer with
// |id| is no longer connected. Should only be used for testing.
const bt::gap::LowEnergyConnectionHandle* FindConnectionForTesting(bt::PeerId id) const;
private:
using ConnectionRefPtr = std::unique_ptr<bt::gap::LowEnergyConnectionHandle>;
using AdvertisementInstanceId = uint64_t;
using ConnectionServerId = uint64_t;
// Manages state associated with a single invocation of the `Peripheral.Advertise` method.
class AdvertisementInstance final {
public:
using AdvertiseCompleteCallback =
fit::callback<void(fuchsia::bluetooth::le::Peripheral_Advertise_Result)>;
// |complete_cb| will be called to send a Peripheral.Advertise response to the client when an
// error occurs or this AdvertisementInstance is destroyed. This is done so that the FIDL client
// can determine when the server has terminated this AdvertisementInstance (this is useful for
// reconfiguring an advertisement).
AdvertisementInstance(
LowEnergyPeripheralServer* peripheral_server, AdvertisementInstanceId id,
fuchsia::bluetooth::le::AdvertisingParameters parameters,
fidl::InterfaceHandle<fuchsia::bluetooth::le::AdvertisedPeripheral> handle,
AdvertiseCompleteCallback complete_cb);
~AdvertisementInstance();
// This method is separate from the constructor because HCI-level advertising may be
// started many times over the life of this object.
void StartAdvertising();
// Called when a central connects to us. When this is called, the
// advertisement in |advertisement_id| has been stopped.
void OnConnected(bt::gap::AdvertisementId advertisement_id,
bt::gap::Adapter::LowEnergy::ConnectionResult result);
private:
// After advertising successfully starts, the advertisement instance must be registered to tie
// advertising to the lifetime of this object.
void Register(bt::gap::AdvertisementInstance instance);
// End the advertisement with a result. Idempotent.
// This object should be destroyed immediately after calling this method.
void CloseWith(fpromise::result<void, fuchsia::bluetooth::le::PeripheralError> result);
LowEnergyPeripheralServer* peripheral_server_;
AdvertisementInstanceId id_;
fuchsia::bluetooth::le::AdvertisingParameters parameters_;
// The advertising handle set by Register. When destroyed, advertising will be stopped.
std::optional<bt::gap::AdvertisementInstance> instance_;
// The AdvertisedPeripheral protocol representing this advertisement.
fidl::InterfacePtr<fuchsia::bluetooth::le::AdvertisedPeripheral> advertised_peripheral_;
// Callback used to send a response to the Advertise request that started this advertisement.
AdvertiseCompleteCallback advertise_complete_cb_;
WeakSelf<AdvertisementInstance> weak_self_;
BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(AdvertisementInstance);
};
class AdvertisementInstanceDeprecated final {
public:
explicit AdvertisementInstanceDeprecated(
fidl::InterfaceRequest<fuchsia::bluetooth::le::AdvertisingHandle> handle);
~AdvertisementInstanceDeprecated();
// Begin watching for ZX_CHANNEL_PEER_CLOSED events on the AdvertisingHandle this was
// initialized with. The returned status will indicate an error if wait cannot be initiated
// (e.g. because the peer closed its end of the channel).
zx_status_t Register(bt::gap::AdvertisementInstance instance);
// Returns the ID assigned to this instance, or bt::gap::kInvalidAdvertisementId if one wasn't
// assigned.
bt::gap::AdvertisementId id() const {
return instance_ ? instance_->id() : bt::gap::kInvalidAdvertisementId;
}
private:
std::optional<bt::gap::AdvertisementInstance> instance_;
fidl::InterfaceRequest<fuchsia::bluetooth::le::AdvertisingHandle> handle_;
async::Wait handle_closed_wait_;
BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(AdvertisementInstanceDeprecated);
};
// Called when a central connects to us. When this is called, the
// advertisement in |advertisement_id| has been stopped.
void OnConnectedDeprecated(bt::gap::AdvertisementId advertisement_id,
bt::gap::Adapter::LowEnergy::ConnectionResult result);
// Sets up a Connection server and returns the client end.
fidl::InterfaceHandle<fuchsia::bluetooth::le::Connection> CreateConnectionServer(
std::unique_ptr<bt::gap::LowEnergyConnectionHandle> connection);
// Common advertising initiation code shared by Peripheral.{Advertise, StartAdvertising}.
// If advertising was initiated by `Advertise`, `advertisement_instance` must be set to the
// identifier of the `AdvertisementInstance` that connections to this advertisement should be
// routed to. Otherwise, connections will be sent in a `Peripheral.OnConnected` event.
void StartAdvertisingInternal(
fuchsia::bluetooth::le::AdvertisingParameters& parameters,
bt::gap::Adapter::LowEnergy::AdvertisingStatusCallback status_cb,
std::optional<AdvertisementInstanceId> advertisement_instance = std::nullopt);
void RemoveAdvertisingInstance(AdvertisementInstanceId id) { advertisements_.erase(id); }
// Represents the current advertising instance:
// - Contains no value if advertising was never requested.
// - Contains a value while advertising is being (re)enabled and during advertising.
// - May correspond to an invalidated advertising instance if advertising is stopped by closing
// the AdvertisingHandle.
std::optional<AdvertisementInstanceDeprecated> advertisement_deprecated_;
// Map of all active advertisement instances associated with a call to `Advertise`.
// bt::gap::AdvertisementId cannot be used as a map key because it is received asynchronously, and
// we need an advertisement ID to refer to before advertising starts.
// TODO(https://fxbug.dev/42157682): Support AdvertisedPeripheral protocols that outlive this
// Peripheral protocol. This may require passing AdvertisementInstances to HostServer.
AdvertisementInstanceId next_advertisement_instance_id_ = 0u;
std::unordered_map<AdvertisementInstanceId, AdvertisementInstance> advertisements_;
// Connections that were initiated to this peripheral. A single Peripheral instance can hold
// many connections across numerous advertisements that it initiates during its lifetime.
ConnectionServerId next_connection_server_id_ = 0u;
std::unordered_map<ConnectionServerId, std::unique_ptr<LowEnergyConnectionServer>> connections_;
bt::gatt::GATT::WeakPtr gatt_;
// Keep this as the last member to make sure that all weak pointers are
// invalidated before other members get destroyed.
WeakSelf<LowEnergyPeripheralServer> weak_self_;
BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(LowEnergyPeripheralServer);
};
} // namespace bthost
#endif // SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_FIDL_LOW_ENERGY_PERIPHERAL_SERVER_H_