// Copyright 2021 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 CORE_INTERNAL_SIMULATION_USER_H_ #define CORE_INTERNAL_SIMULATION_USER_H_ #include #include #include #include "absl/functional/any_invocable.h" #include "absl/strings/string_view.h" #include "absl/time/time.h" #include "connections/advertising_options.h" #include "connections/connection_options.h" #include "connections/discovery_options.h" #include "connections/implementation/bwu_manager.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel_manager.h" #include "connections/implementation/endpoint_manager.h" #include "connections/implementation/flags/nearby_connections_feature_flags.h" #include "connections/implementation/injected_bluetooth_device_store.h" #include "connections/implementation/mediums/mediums.h" #include "connections/implementation/payload_manager.h" #include "connections/implementation/pcp_manager.h" #include "connections/listeners.h" #include "connections/medium_selector.h" #include "connections/out_of_band_connection_metadata.h" #include "connections/payload.h" #include "connections/status.h" #include "connections/strategy.h" #include "connections/v3/connection_listening_options.h" #include "internal/flags/nearby_flags.h" #include "internal/interop/device.h" #include "internal/platform/byte_array.h" #include "internal/platform/condition_variable.h" #include "internal/platform/count_down_latch.h" #include "internal/platform/feature_flags.h" #include "internal/platform/future.h" #include "internal/platform/mutex.h" // Test-only class to help run end-to-end simulations for nearby connections // protocol. // // This is a "standalone" version of PcpManager. It can run independently, // provided MediumEnvironment has adequate support for all medium types in use. namespace nearby { namespace connections { class SetSafeToDisconnect { public: explicit SetSafeToDisconnect(bool safe_to_disconnect, bool auto_reconnect, std::int32_t safe_to_disconnect_version) { NearbyFlags::GetInstance().OverrideBoolFlagValue( config_package_nearby::nearby_connections_feature:: kEnableSafeToDisconnect, safe_to_disconnect); NearbyFlags::GetInstance().OverrideBoolFlagValue( config_package_nearby::nearby_connections_feature::kEnableAutoReconnect, auto_reconnect); NearbyFlags::GetInstance().OverrideInt64FlagValue( config_package_nearby::nearby_connections_feature:: kSafeToDisconnectVersion, safe_to_disconnect_version); } }; class SimulationUser { public: struct DiscoveredInfo { std::string endpoint_id; ByteArray endpoint_info; std::string service_id; bool Empty() const { return endpoint_id.empty(); } void Clear() { endpoint_id.clear(); } }; explicit SimulationUser( const std::string& device_name, BooleanMediumSelector allowed = BooleanMediumSelector(), SetSafeToDisconnect set_safe_to_disconnect = SetSafeToDisconnect(/*safe_to_disconnect=*/true, /*auto_reconnect=*/false, /*safe_to_disconnect_version=*/5)) : info_{ByteArray{device_name}}, advertising_options_{ { Strategy::kP2pCluster, allowed, }, }, connection_options_{ .keep_alive_interval_millis = FeatureFlags::GetInstance() .GetFlags() .keep_alive_interval_millis, .keep_alive_timeout_millis = FeatureFlags::GetInstance() .GetFlags() .keep_alive_timeout_millis, }, discovery_options_{ { Strategy::kP2pCluster, allowed, }, }, set_safe_to_disconnect_(set_safe_to_disconnect) {} virtual ~SimulationUser() { Stop(); } void Stop() { pm_.DisconnectFromEndpointManager(); mgr_.DisconnectFromEndpointManager(); bwu_.Shutdown(); } // Calls PcpManager::StartAdvertising. // If latch is provided, will call latch->CountDown() in the initiated_cb // callback. void StartAdvertising(const std::string& service_id, CountDownLatch* latch); // Calls PcpManager::StartDiscovery. // If latch is provided, will call latch->CountDown() in the endpoint_found_cb // callback. void StartDiscovery(const std::string& service_id, CountDownLatch* latch); void StopDiscovery(); // Calls PcpManager::UpdateDiscoveryOptions. Status UpdateDiscoveryOptions(absl::string_view service_id); // Calls PcpManager::InjectEndpoint. void InjectEndpoint(const std::string& service_id, const OutOfBandConnectionMetadata& metadata); // Calls PcpManager::RequestConnection. // If latch is provided, latch->CountDown() will be called in the initiated_cb // callback. void RequestConnection(CountDownLatch* latch); // Calls PcpManager::RequestConnectionV3. // If latch is provided, latch->CountDown() will be called in the initiated_cb // callback. void RequestConnectionV3(CountDownLatch* latch, const NearbyDevice& remote_device); // Calls PcpManager::AcceptConnection. // If latch is provided, latch->CountDown() will be called in the accepted_cb // callback. void AcceptConnection(CountDownLatch* latch); // Calls PcpManager::RejectConnection. // If latch is provided, latch->CountDown() will be called in the rejected_cb // callback. void RejectConnection(CountDownLatch* latch); // Calls PcpManager::StartListeningForIncomingConnections. // If latch is provided, latch->CountDown() will be called on call completion. void StartListeningForIncomingConnections( CountDownLatch* latch, absl::string_view service_id, const v3::ConnectionListeningOptions& options, Status expected_status); // Unlike acceptance, rejection does not have to be mutual, in order to work. // This method will allow to synchronize on the remote rejection, without // performing a local rejection. // latch.CountDown() will be called in the rejected_cb callback. void ExpectRejectedConnection(CountDownLatch& latch) { reject_latch_ = &latch; } void ExpectPayload(CountDownLatch& latch) { payload_latch_ = &latch; } const DiscoveredInfo& GetDiscovered() const { return discovered_; } ByteArray GetInfo() const { return info_; } bool WaitForProgress( absl::AnyInvocable pred, absl::Duration timeout); ClientProxy& GetClient() { return client_; } EndpointChannelManager& GetEndpointChannelManager() { return ecm_; } protected: // ConnectionListener callbacks void OnConnectionInitiated(const std::string& endpoint_id, const ConnectionResponseInfo& info, bool is_outgoing); void OnConnectionAccepted(const std::string& endpoint_id); void OnConnectionRejected(const std::string& endpoint_id, Status status); // DiscoveryListener callbacks void OnEndpointFound(const std::string& endpoint_id, const ByteArray& endpoint_info, const std::string& service_id); void OnEndpointLost(const std::string& endpoint_id); // PayloadListener callbacks void OnPayload(absl::string_view, Payload payload); void OnPayloadProgress(absl::string_view endpoint_id, const PayloadProgressInfo& info); std::string service_id_; DiscoveredInfo discovered_; Mutex progress_mutex_; ConditionVariable progress_sync_{&progress_mutex_}; PayloadProgressInfo progress_info_; Payload payload_; CountDownLatch* initiated_latch_ = nullptr; CountDownLatch* accept_latch_ = nullptr; CountDownLatch* reject_latch_ = nullptr; CountDownLatch* found_latch_ = nullptr; CountDownLatch* lost_latch_ = nullptr; CountDownLatch* payload_latch_ = nullptr; Future* future_ = nullptr; absl::AnyInvocable predicate_; ByteArray info_; Mediums mediums_; AdvertisingOptions advertising_options_; ConnectionOptions connection_options_; DiscoveryOptions discovery_options_; SetSafeToDisconnect set_safe_to_disconnect_; ClientProxy client_; EndpointChannelManager ecm_; EndpointManager em_{&ecm_}; BwuManager bwu_{mediums_, em_, ecm_, {}, {}}; InjectedBluetoothDeviceStore injected_bluetooth_device_store_; PcpManager mgr_{mediums_, ecm_, em_, bwu_, injected_bluetooth_device_store_}; PayloadManager pm_{em_}; }; } // namespace connections } // namespace nearby #endif // CORE_INTERNAL_SIMULATION_USER_H_