// // 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