// Copyright 2022 Google LLC // // 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 // // https://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. #ifndef THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_IOS_BLE_H_ #define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_IOS_BLE_H_ #import #import #include #include "absl/types/optional.h" #include "internal/platform/cancellation_flag.h" #include "internal/platform/implementation/ble_v2.h" #include "internal/platform/implementation/bluetooth_adapter.h" #import "internal/platform/implementation/ios/Mediums/GNCMConnection.h" #include "internal/platform/implementation/ios/bluetooth_adapter.h" @class GNCMBlePeripheral, GNCMBleCentral; namespace location { namespace nearby { namespace ios { /** InputStream that reads from GNCMConnection. */ class BleInputStream : public InputStream { public: BleInputStream(); ~BleInputStream() override; ExceptionOr Read(std::int64_t size) override; Exception Close() override; GNCMConnectionHandlers *GetConnectionHandlers() { return connectionHandlers_; } private: GNCMConnectionHandlers *connectionHandlers_; NSMutableArray *newDataPackets_; NSMutableData *accumulatedData_; NSCondition *condition_; }; /** OutputStream that writes to GNCMConnection. */ class BleOutputStream : public OutputStream { public: explicit BleOutputStream(id connection) : connection_(connection), condition_([[NSCondition alloc] init]) {} ~BleOutputStream() override; Exception Write(const ByteArray &data) override; Exception Flush() override; Exception Close() override; private: id connection_; NSCondition *condition_; }; /** Concrete BleSocket implementation. */ class BleSocket : public api::ble_v2::BleSocket { public: BleSocket() = default; explicit BleSocket(id connection); ~BleSocket() override; InputStream &GetInputStream() override { return *input_stream_; } OutputStream &GetOutputStream() override { return *output_stream_; } Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_); BlePeripheral *GetRemotePeripheral() override { return nullptr; } bool IsClosed() const ABSL_LOCKS_EXCLUDED(mutex_); private: void DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); mutable absl::Mutex mutex_; bool closed_ ABSL_GUARDED_BY(mutex_) = false; std::unique_ptr input_stream_; std::unique_ptr output_stream_; }; /** Concrete BleServerSocket implementation. */ class BleServerSocket : public api::ble_v2::BleServerSocket { public: ~BleServerSocket() override; std::unique_ptr Accept() override ABSL_LOCKS_EXCLUDED(mutex_); Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_); bool Connect(std::unique_ptr socket) ABSL_LOCKS_EXCLUDED(mutex_); void SetCloseNotifier(std::function notifier) ABSL_LOCKS_EXCLUDED(mutex_); private: Exception DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); mutable absl::Mutex mutex_; absl::CondVar cond_; absl::flat_hash_set> pending_sockets_ ABSL_GUARDED_BY(mutex_); std::function close_notifier_ ABSL_GUARDED_BY(mutex_); bool closed_ ABSL_GUARDED_BY(mutex_) = false; }; /** Concrete BleMedium implementation. */ class BleMedium : public api::ble_v2::BleMedium { public: explicit BleMedium(api::BluetoothAdapter &adapter); // api::BleMedium: bool StartAdvertising(const api::ble_v2::BleAdvertisementData &advertising_data, api::ble_v2::AdvertiseParameters advertise_set_parameters) override; bool StopAdvertising() override; bool StartScanning(const Uuid &service_uuid, api::ble_v2::TxPowerLevel tx_power_level, api::ble_v2::BleMedium::ScanCallback scan_callback) override; bool StopScanning() override; std::unique_ptr StartGattServer( api::ble_v2::ServerGattConnectionCallback callback) override; std::unique_ptr ConnectToGattServer( api::ble_v2::BlePeripheral &peripheral, api::ble_v2::TxPowerLevel tx_power_level, api::ble_v2::ClientGattConnectionCallback callback) override; std::unique_ptr OpenServerSocket( const std::string &service_id) override; std::unique_ptr Connect(const std::string &service_id, api::ble_v2::TxPowerLevel tx_power_level, api::ble_v2::BlePeripheral &peripheral, CancellationFlag *cancellation_flag) override; bool IsExtendedAdvertisementsAvailable() override; private: // A concrete implemenation for GattServer. class GattServer : public api::ble_v2::GattServer { public: GattServer() = default; explicit GattServer(GNCMBlePeripheral *peripheral) : peripheral_(peripheral) {} absl::optional CreateCharacteristic( const Uuid &service_uuid, const Uuid &characteristic_uuid, const std::vector &permissions, const std::vector &properties) override; bool UpdateCharacteristic(const api::ble_v2::GattCharacteristic &characteristic, const location::nearby::ByteArray &value) override; void Stop() override; private: GNCMBlePeripheral *peripheral_; }; // A concrete implemenation for GattClient. class GattClient : public api::ble_v2::GattClient { public: GattClient() = default; explicit GattClient(GNCMBleCentral *central, const std::string &peripheral_id) : central_(central), peripheral_id_(peripheral_id) {} bool DiscoverServiceAndCharacteristics(const Uuid &service_uuid, const std::vector &characteristic_uuids) override; // NOLINTNEXTLINE absl::optional GetCharacteristic( const Uuid &service_uuid, const Uuid &characteristic_uuid) override; // NOLINTNEXTLINE absl::optional ReadCharacteristic( const api::ble_v2::GattCharacteristic &characteristic) override; bool WriteCharacteristic(const api::ble_v2::GattCharacteristic &characteristic, const ByteArray &value) override; void Disconnect() override; private: GNCMBleCentral *central_; std::string peripheral_id_; absl::flat_hash_map gatt_characteristic_values_; }; absl::Mutex mutex_; BluetoothAdapter *adapter_; GNCMBlePeripheral *peripheral_; GNCMBleCentral *central_; absl::flat_hash_map server_sockets_ ABSL_GUARDED_BY(mutex_); absl::flat_hash_map connection_requesters_ ABSL_GUARDED_BY(mutex_); }; } // namespace ios } // namespace nearby } // namespace location #endif // THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_IOS_BLE_H_