390 lines
16 KiB
C++
390 lines
16 KiB
C++
//
|
|
// Copyright (C) 2015 Google, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at:
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
|
|
#pragma once
|
|
|
|
#include <deque>
|
|
#include <functional>
|
|
#include <mutex>
|
|
#include <unordered_map>
|
|
#include <unordered_set>
|
|
#include <vector>
|
|
|
|
#include <base/macros.h>
|
|
|
|
#include "service/bluetooth_instance.h"
|
|
#include "service/common/bluetooth/gatt_identifier.h"
|
|
#include "service/common/bluetooth/uuid.h"
|
|
#include "service/hal/bluetooth_gatt_interface.h"
|
|
|
|
namespace bluetooth {
|
|
|
|
// A GattServer instance represents an application's handle to perform GATT
|
|
// server-role operations. Instances cannot be created directly and should be
|
|
// obtained through the factory.
|
|
class GattServer : public BluetoothInstance,
|
|
private hal::BluetoothGattInterface::ServerObserver {
|
|
public:
|
|
// Delegate interface is used to handle incoming requests and confirmations
|
|
// for a GATT service.
|
|
class Delegate {
|
|
public:
|
|
Delegate() = default;
|
|
virtual ~Delegate() = default;
|
|
|
|
// Called when there is an incoming read request for the characteristic with
|
|
// ID |characteristic_id| from a remote device with address
|
|
// |device_address|. |request_id| can be used to respond to this request by
|
|
// calling SendResponse below.
|
|
virtual void OnCharacteristicReadRequest(
|
|
GattServer* gatt_server,
|
|
const std::string& device_address,
|
|
int request_id, int offset, bool is_long,
|
|
const bluetooth::GattIdentifier& characteristic_id) = 0;
|
|
|
|
// Called when there is an incoming read request for the descriptor with
|
|
// ID |descriptor_id| from a remote device with address |device_address|.
|
|
// |request_id| can be used to respond to this request by
|
|
// calling SendResponse below.
|
|
virtual void OnDescriptorReadRequest(
|
|
GattServer* gatt_server,
|
|
const std::string& device_address,
|
|
int request_id, int offset, bool is_long,
|
|
const bluetooth::GattIdentifier& descriptor_id) = 0;
|
|
|
|
// Called when there is an incoming write request for the characteristic
|
|
// with ID |characteristic_id| from a remote device with address
|
|
// |device_address|. |request_id| can be used to respond to this request by
|
|
// calling SendResponse, if the |need_response| parameter is true. Otherwise
|
|
// this is a "Write Without Reponse" procedure and SendResponse will fail.
|
|
// If |is_prepare_write| is true, then the write should not be committed
|
|
// immediately as this is a "Prepared Write Request". Instead, the Delegate
|
|
// should hold on to the value and either discard it or complete the write
|
|
// when it receives the OnExecuteWriteRequest event.
|
|
virtual void OnCharacteristicWriteRequest(
|
|
GattServer* gatt_server,
|
|
const std::string& device_address,
|
|
int request_id, int offset, bool is_prepare_write, bool need_response,
|
|
const std::vector<uint8_t>& value,
|
|
const bluetooth::GattIdentifier& characteristic_id) = 0;
|
|
|
|
// Called when there is an incoming write request for the descriptor
|
|
// with ID |descriptor_id| from a remote device with address
|
|
// |device_address|. |request_id| can be used to respond to this request by
|
|
// calling SendResponse, if the |need_response| parameter is true. Otherwise
|
|
// this is a "Write Without Response" procedure and SendResponse will fail.
|
|
// If |is_prepare_write| is true, then the write should not be committed
|
|
// immediately as this is a "Prepared Write Request". Instead, the Delegate
|
|
// should hold on to the value and either discard it or complete the write
|
|
// when it receives the OnExecuteWriteRequest event.
|
|
virtual void OnDescriptorWriteRequest(
|
|
GattServer* gatt_server,
|
|
const std::string& device_address,
|
|
int request_id, int offset, bool is_prepare_write, bool need_response,
|
|
const std::vector<uint8_t>& value,
|
|
const bluetooth::GattIdentifier& descriptor_id) = 0;
|
|
|
|
// Called when there is an incoming "Execute Write Request". If |is_execute|
|
|
// is true, then the Delegate should commit all previously prepared writes.
|
|
// Otherwise, all prepared writes should be aborted. The Delegate should
|
|
// call "SendResponse" to complete the procedure.
|
|
virtual void OnExecuteWriteRequest(
|
|
GattServer* gatt_server,
|
|
const std::string& device_address,
|
|
int request_id, bool is_execute) = 0;
|
|
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(Delegate);
|
|
};
|
|
|
|
// The desctructor automatically unregisters this instance from the stack.
|
|
~GattServer() override;
|
|
|
|
// Assigns a delegate to this instance. |delegate| must out-live this
|
|
// GattServer instance.
|
|
void SetDelegate(Delegate* delegate);
|
|
|
|
// BluetoothClientInstace overrides:
|
|
const UUID& GetAppIdentifier() const override;
|
|
int GetInstanceId() const override;
|
|
|
|
// Callback type used to report the status of an asynchronous GATT server
|
|
// operation.
|
|
using ResultCallback =
|
|
std::function<void(BLEStatus status, const GattIdentifier& id)>;
|
|
using GattCallback = std::function<void(GATTError error)>;
|
|
|
|
// Starts a new GATT service declaration for the service with the given
|
|
// parameters. In the case of an error, for example If a service declaration
|
|
// is already in progress, then this method returns a NULL pointer. Otherwise,
|
|
// this returns an identifier that uniquely identifies the added service.
|
|
//
|
|
// TODO(armansito): In the framework code, the "min_handles" parameter is
|
|
// annotated to be used for "conformance testing only". I don't fully see the
|
|
// point of this and suggest getting rid of this parameter entirely. For now
|
|
// this code doesn't declare or use it.
|
|
std::unique_ptr<GattIdentifier> BeginServiceDeclaration(
|
|
const UUID& uuid, bool is_primary);
|
|
|
|
// Inserts a new characteristic definition into a previously begun service
|
|
// declaration. Returns the assigned identifier for the characteristic, or
|
|
// nullptr if a service declaration wasn't begun or a call to
|
|
// EndServiceDeclaration is still in progress.
|
|
std::unique_ptr<GattIdentifier> AddCharacteristic(
|
|
const UUID& uuid, int properties, int permissions);
|
|
|
|
// Inserts a new descriptor definition into a previous begun service
|
|
// declaration. Returns the assigned identifier for the descriptor, or
|
|
// nullptr if a service declaration wasn't begun, a call to
|
|
// EndServiceDeclaration is still in progress, or a characteristic definition
|
|
// doesn't properly precede this definition.
|
|
std::unique_ptr<GattIdentifier> AddDescriptor(
|
|
const UUID& uuid, int permissions);
|
|
|
|
// Ends a previously started service declaration. This method immediately
|
|
// returns false if a service declaration hasn't been started. Otherwise,
|
|
// |callback| will be called asynchronously with the result of the operation.
|
|
//
|
|
// TODO(armansito): It is unclear to me what it means for this function to
|
|
// fail. What is the state that we're in? Is the service declaration over so
|
|
// we can add other services to this server instance? Do we need to clean up
|
|
// all the entries or does the upper-layer need to remove the service? Or are
|
|
// we in a stuck-state where the service declaration hasn't ended?
|
|
bool EndServiceDeclaration(const ResultCallback& callback);
|
|
|
|
// Sends a response for a pending notification. |request_id| and
|
|
// |device_address| should match those that were received through one of the
|
|
// Delegate callbacks. |value| and |offset| are used for read requests and
|
|
// prepare write requests and should match the value of the attribute. Returns
|
|
// false if the pending request could not be resolved using the given
|
|
// parameters or if the call to the underlying stack fails.
|
|
bool SendResponse(const std::string& device_address, int request_id,
|
|
GATTError error, int offset,
|
|
const std::vector<uint8_t>& value);
|
|
|
|
// Sends an ATT Handle-Value Notification to the device with BD_ADDR
|
|
// |device_address| for the characteristic with ID |characteristic_id| and
|
|
// value |value|. If |confirm| is true, then an ATT Handle-Value Indication
|
|
// will be sent instead, which requires the remote to confirm receipt. Returns
|
|
// false if there was an immediate error in initiating the notification
|
|
// procedure. Otherwise, returns true and reports the asynchronous result of
|
|
// the operation in |callback|.
|
|
//
|
|
// If |confirm| is true, then |callback| will be run when the remote device
|
|
// sends a ATT Handle-Value Confirmation packet. Otherwise, it will be run as
|
|
// soon as the notification has been sent out.
|
|
bool SendNotification(const std::string& device_address,
|
|
const GattIdentifier& characteristic_id,
|
|
bool confirm, const std::vector<uint8_t>& value,
|
|
const GattCallback& callback);
|
|
|
|
private:
|
|
friend class GattServerFactory;
|
|
|
|
// Internal representation of an attribute entry as part of a service
|
|
// declaration.
|
|
struct AttributeEntry {
|
|
AttributeEntry(const GattIdentifier& id,
|
|
int char_properties,
|
|
int permissions)
|
|
: id(id), char_properties(char_properties), permissions(permissions) {}
|
|
|
|
GattIdentifier id;
|
|
int char_properties;
|
|
int permissions;
|
|
};
|
|
|
|
// Internal representation of a GATT service declaration before it has been
|
|
// sent to the stack.
|
|
struct ServiceDeclaration {
|
|
ServiceDeclaration() : num_handles(0), service_handle(-1) {}
|
|
|
|
size_t num_handles;
|
|
GattIdentifier service_id;
|
|
int service_handle;
|
|
std::deque<AttributeEntry> attributes;
|
|
};
|
|
|
|
// Used for the internal remote connection tracking. Keeps track of the
|
|
// request ID and the device address for the connection. If |request_id| is -1
|
|
// then no ATT read/write request is currently pending.
|
|
struct Connection {
|
|
Connection(int conn_id, const bt_bdaddr_t& bdaddr)
|
|
: conn_id(conn_id), bdaddr(bdaddr) {}
|
|
Connection() : conn_id(-1) {
|
|
memset(&bdaddr, 0, sizeof(bdaddr));
|
|
}
|
|
|
|
int conn_id;
|
|
std::unordered_map<int, int> request_id_to_handle;
|
|
bt_bdaddr_t bdaddr;
|
|
};
|
|
|
|
// Used to keep track of a pending Handle-Value indication.
|
|
struct PendingIndication {
|
|
PendingIndication(const GattCallback& callback)
|
|
: has_success(false), callback(callback) {}
|
|
|
|
bool has_success;
|
|
GattCallback callback;
|
|
};
|
|
|
|
// Constructor shouldn't be called directly as instances are meant to be
|
|
// obtained from the factory.
|
|
GattServer(const UUID& uuid, int server_id);
|
|
|
|
// Returns a GattIdentifier for the attribute with the given UUID within the
|
|
// current pending service declaration.
|
|
std::unique_ptr<GattIdentifier> GetIdForService(const UUID& uuid,
|
|
bool is_primary);
|
|
std::unique_ptr<GattIdentifier> GetIdForCharacteristic(const UUID& uuid);
|
|
std::unique_ptr<GattIdentifier> GetIdForDescriptor(const UUID& uuid);
|
|
|
|
// hal::BluetoothGattInterface::ServerObserver overrides:
|
|
void ConnectionCallback(
|
|
hal::BluetoothGattInterface* gatt_iface,
|
|
int conn_id, int server_id,
|
|
int connected,
|
|
const bt_bdaddr_t& bda) override;
|
|
void ServiceAddedCallback(
|
|
hal::BluetoothGattInterface* gatt_iface,
|
|
int status, int server_id,
|
|
const btgatt_srvc_id_t& srvc_id,
|
|
int service_handle) override;
|
|
void CharacteristicAddedCallback(
|
|
hal::BluetoothGattInterface* gatt_iface,
|
|
int status, int server_id,
|
|
const bt_uuid_t& uuid,
|
|
int service_handle,
|
|
int char_handle) override;
|
|
void DescriptorAddedCallback(
|
|
hal::BluetoothGattInterface* gatt_iface,
|
|
int status, int server_id,
|
|
const bt_uuid_t& uuid,
|
|
int service_handle,
|
|
int desc_handle) override;
|
|
void ServiceStartedCallback(
|
|
hal::BluetoothGattInterface* gatt_iface,
|
|
int status, int server_id,
|
|
int service_handle) override;
|
|
void ServiceStoppedCallback(
|
|
hal::BluetoothGattInterface* gatt_iface,
|
|
int status, int server_id,
|
|
int service_handle) override;
|
|
void RequestReadCallback(
|
|
hal::BluetoothGattInterface* gatt_iface,
|
|
int conn_id, int trans_id,
|
|
const bt_bdaddr_t& bda,
|
|
int attribute_handle, int offset,
|
|
bool is_long) override;
|
|
void RequestWriteCallback(
|
|
hal::BluetoothGattInterface* gatt_iface,
|
|
int conn_id, int trans_id,
|
|
const bt_bdaddr_t& bda,
|
|
int attr_handle, int offset, int length,
|
|
bool need_rsp, bool is_prep, uint8_t* value) override;
|
|
void RequestExecWriteCallback(
|
|
hal::BluetoothGattInterface* gatt_iface,
|
|
int conn_id, int trans_id,
|
|
const bt_bdaddr_t& bda, int exec_write) override;
|
|
void IndicationSentCallback(
|
|
hal::BluetoothGattInterface* gatt_iface,
|
|
int conn_id, int status) override;
|
|
|
|
// Helper function that notifies and clears the pending callback.
|
|
void NotifyEndCallbackAndClearData(BLEStatus status,
|
|
const GattIdentifier& id);
|
|
void CleanUpPendingData();
|
|
|
|
// Handles the next attribute entry in the pending service declaration.
|
|
void HandleNextEntry(hal::BluetoothGattInterface* gatt_iface);
|
|
|
|
// Helper method that returns a pointer to an internal Connection instance
|
|
// that matches the given parameters.
|
|
std::shared_ptr<Connection> GetConnection(int conn_id, const bt_bdaddr_t& bda,
|
|
int request_id);
|
|
|
|
// Pops the next GATT ID or entry from the pending service declaration's
|
|
// attribute list.
|
|
std::unique_ptr<AttributeEntry> PopNextEntry();
|
|
std::unique_ptr<GattIdentifier> PopNextId();
|
|
|
|
// See getters for documentation.
|
|
UUID app_identifier_;
|
|
int server_id_;
|
|
|
|
// Mutex that synchronizes access to the entries below.
|
|
std::mutex mutex_;
|
|
std::unique_ptr<GattIdentifier> pending_id_;
|
|
std::unique_ptr<ServiceDeclaration> pending_decl_;
|
|
ResultCallback pending_end_decl_cb_;
|
|
std::unordered_map<GattIdentifier, int> pending_handle_map_;
|
|
|
|
// Mapping of handles and GATT identifiers for started services.
|
|
std::unordered_map<GattIdentifier, int> id_to_handle_map_;
|
|
std::unordered_map<int, GattIdentifier> handle_to_id_map_;
|
|
|
|
// GATT connection mappings from stack-provided "conn_id" IDs and remote
|
|
// device addresses to Connection structures. The conn_id map is one-to-one
|
|
// while the conn_addr map is one to many, as a remote device may support
|
|
// multiple transports (BR/EDR & LE) and use the same device address for both.
|
|
std::unordered_map<int, std::shared_ptr<Connection>> conn_id_map_;
|
|
std::unordered_map<std::string, std::vector<std::shared_ptr<Connection>>>
|
|
conn_addr_map_;
|
|
|
|
// Connections for which a Handle-Value indication is pending. Since there can
|
|
// be multiple indications to the same device (in the case of a dual-mode
|
|
// device with simulatenous BR/EDR & LE GATT connections), we also keep track
|
|
// of whether there has been at least one successful confirmation.
|
|
std::unordered_map<int, std::shared_ptr<PendingIndication>>
|
|
pending_indications_;
|
|
|
|
// Raw handle to the Delegate, which must outlive this GattServer instance.
|
|
Delegate* delegate_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(GattServer);
|
|
};
|
|
|
|
// GattServerFactory is used to register and obtain a per-application GattServer
|
|
// instance. Users should call RegisterClient to obtain their own unique
|
|
// GattServer instance that has been registered with the Bluetooth stack.
|
|
class GattServerFactory : public BluetoothInstanceFactory,
|
|
private hal::BluetoothGattInterface::ServerObserver {
|
|
public:
|
|
// Don't construct/destruct directly except in tests. Instead, obtain a handle
|
|
// from an Adapter instance.
|
|
GattServerFactory();
|
|
~GattServerFactory() override;
|
|
|
|
// BluetoothInstanceFactory override:
|
|
bool RegisterInstance(const UUID& uuid,
|
|
const RegisterCallback& callback) override;
|
|
|
|
private:
|
|
// hal::BluetoothGattInterface::ServerObserver override:
|
|
void RegisterServerCallback(
|
|
hal::BluetoothGattInterface* gatt_iface,
|
|
int status, int server_id,
|
|
const bt_uuid_t& app_uuid) override;
|
|
|
|
// Map of pending calls to register.
|
|
std::mutex pending_calls_lock_;
|
|
std::unordered_map<UUID, RegisterCallback> pending_calls_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(GattServerFactory);
|
|
};
|
|
|
|
} // namespace bluetooth
|